emdash 0.37.0 → 0.39.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 (1445) hide show
  1. package/dist/action-token-On1sot_c.mjs +26 -0
  2. package/dist/action-token-On1sot_c.mjs.map +1 -0
  3. package/dist/activation-CaMfdBt1.mjs +382 -0
  4. package/dist/activation-CaMfdBt1.mjs.map +1 -0
  5. package/dist/adapters-Cq10K4_c.d.mts +171 -0
  6. package/dist/adapters-Cq10K4_c.d.mts.map +1 -0
  7. package/dist/after-PcEvMY_6.mjs +96 -0
  8. package/dist/after-PcEvMY_6.mjs.map +1 -0
  9. package/dist/allowed-origins-1Sa-2wZK.mjs +116 -0
  10. package/dist/allowed-origins-1Sa-2wZK.mjs.map +1 -0
  11. package/dist/api/route-utils.d.mts +4 -3
  12. package/dist/api/route-utils.d.mts.map +1 -1
  13. package/dist/api/route-utils.mjs +45 -29
  14. package/dist/api/route-utils.mjs.map +1 -1
  15. package/dist/api/schemas/index.d.mts +2 -2
  16. package/dist/api/schemas/index.mjs +7 -6
  17. package/dist/api-DmjKxPCY.mjs +4831 -0
  18. package/dist/api-DmjKxPCY.mjs.map +1 -0
  19. package/dist/api-tokens-BIXItFKV.mjs +163 -0
  20. package/dist/api-tokens-BIXItFKV.mjs.map +1 -0
  21. package/dist/apply-drpfmqrR.mjs +1005 -0
  22. package/dist/apply-drpfmqrR.mjs.map +1 -0
  23. package/dist/artifact-fetch-COiMhVgk.mjs +813 -0
  24. package/dist/artifact-fetch-COiMhVgk.mjs.map +1 -0
  25. package/dist/astro/index.d.mts +14 -12
  26. package/dist/astro/index.d.mts.map +1 -1
  27. package/dist/astro/index.mjs +123 -13
  28. package/dist/astro/index.mjs.map +1 -1
  29. package/dist/astro/middleware/auth.d.mts +12 -10
  30. package/dist/astro/middleware/auth.d.mts.map +1 -1
  31. package/dist/astro/middleware/auth.mjs +20 -11
  32. package/dist/astro/middleware/auth.mjs.map +1 -1
  33. package/dist/astro/middleware/media-usage-write-fence.mjs +5 -5
  34. package/dist/astro/middleware/redirect.mjs +11 -9
  35. package/dist/astro/middleware/redirect.mjs.map +1 -1
  36. package/dist/astro/middleware/request-context.d.mts +1 -1
  37. package/dist/astro/middleware/request-context.d.mts.map +1 -1
  38. package/dist/astro/middleware/request-context.mjs +154 -28
  39. package/dist/astro/middleware/request-context.mjs.map +1 -1
  40. package/dist/astro/middleware/setup.mjs +1 -1
  41. package/dist/astro/middleware.d.mts +13 -10
  42. package/dist/astro/middleware.d.mts.map +1 -1
  43. package/dist/astro/middleware.mjs +122 -3041
  44. package/dist/astro/middleware.mjs.map +1 -1
  45. package/dist/astro/routes/api/admin/allowed-domains/_domain_.mjs +10 -9
  46. package/dist/astro/routes/api/admin/allowed-domains/_domain_.mjs.map +1 -1
  47. package/dist/astro/routes/api/admin/allowed-domains/index.mjs +10 -9
  48. package/dist/astro/routes/api/admin/allowed-domains/index.mjs.map +1 -1
  49. package/dist/astro/routes/api/admin/api-tokens/_id_.mjs +5 -5
  50. package/dist/astro/routes/api/admin/api-tokens/index.mjs +6 -6
  51. package/dist/astro/routes/api/admin/byline-fields/_slug_/usage.mjs +6 -6
  52. package/dist/astro/routes/api/admin/byline-fields/_slug_.mjs +13 -12
  53. package/dist/astro/routes/api/admin/byline-fields/_slug_.mjs.map +1 -1
  54. package/dist/astro/routes/api/admin/byline-fields/index.mjs +13 -12
  55. package/dist/astro/routes/api/admin/byline-fields/index.mjs.map +1 -1
  56. package/dist/astro/routes/api/admin/byline-fields/reorder.mjs +13 -12
  57. package/dist/astro/routes/api/admin/byline-fields/reorder.mjs.map +1 -1
  58. package/dist/astro/routes/api/admin/bylines/_id_/index.mjs +22 -21
  59. package/dist/astro/routes/api/admin/bylines/_id_/index.mjs.map +1 -1
  60. package/dist/astro/routes/api/admin/bylines/_id_/translations.mjs +22 -21
  61. package/dist/astro/routes/api/admin/bylines/_id_/translations.mjs.map +1 -1
  62. package/dist/astro/routes/api/admin/bylines/index.mjs +22 -21
  63. package/dist/astro/routes/api/admin/bylines/index.mjs.map +1 -1
  64. package/dist/astro/routes/api/admin/comments/_id_/status.d.mts.map +1 -1
  65. package/dist/astro/routes/api/admin/comments/_id_/status.mjs +21 -54
  66. package/dist/astro/routes/api/admin/comments/_id_/status.mjs.map +1 -1
  67. package/dist/astro/routes/api/admin/comments/_id_.mjs +8 -8
  68. package/dist/astro/routes/api/admin/comments/bulk.mjs +15 -14
  69. package/dist/astro/routes/api/admin/comments/bulk.mjs.map +1 -1
  70. package/dist/astro/routes/api/admin/comments/counts.mjs +8 -8
  71. package/dist/astro/routes/api/admin/comments/index.mjs +15 -14
  72. package/dist/astro/routes/api/admin/comments/index.mjs.map +1 -1
  73. package/dist/astro/routes/api/admin/hooks/exclusive/_hookName_.mjs +6 -6
  74. package/dist/astro/routes/api/admin/hooks/exclusive/index.mjs +5 -5
  75. package/dist/astro/routes/api/admin/media-usage/activation.mjs +17 -16
  76. package/dist/astro/routes/api/admin/media-usage/activation.mjs.map +1 -1
  77. package/dist/astro/routes/api/admin/media-usage/collection-deletions/index.mjs +19 -18
  78. package/dist/astro/routes/api/admin/media-usage/collection-deletions/index.mjs.map +1 -1
  79. package/dist/astro/routes/api/admin/media-usage/collection-deletions/retry.mjs +19 -18
  80. package/dist/astro/routes/api/admin/media-usage/collection-deletions/retry.mjs.map +1 -1
  81. package/dist/astro/routes/api/admin/media-usage/progress.mjs +17 -17
  82. package/dist/astro/routes/api/admin/media-usage/repair.mjs +21 -20
  83. package/dist/astro/routes/api/admin/media-usage/repair.mjs.map +1 -1
  84. package/dist/astro/routes/api/admin/media-usage/work/index.mjs +19 -18
  85. package/dist/astro/routes/api/admin/media-usage/work/index.mjs.map +1 -1
  86. package/dist/astro/routes/api/admin/media-usage/work/retry.mjs +19 -18
  87. package/dist/astro/routes/api/admin/media-usage/work/retry.mjs.map +1 -1
  88. package/dist/astro/routes/api/admin/oauth-clients/_id_.mjs +5 -5
  89. package/dist/astro/routes/api/admin/oauth-clients/index.mjs +5 -5
  90. package/dist/astro/routes/api/admin/plugins/_id_/disable.d.mts.map +1 -1
  91. package/dist/astro/routes/api/admin/plugins/_id_/disable.mjs +9 -66
  92. package/dist/astro/routes/api/admin/plugins/_id_/disable.mjs.map +1 -1
  93. package/dist/astro/routes/api/admin/plugins/_id_/enable.d.mts.map +1 -1
  94. package/dist/astro/routes/api/admin/plugins/_id_/enable.mjs +9 -69
  95. package/dist/astro/routes/api/admin/plugins/_id_/enable.mjs.map +1 -1
  96. package/dist/astro/routes/api/admin/plugins/_id_/index.mjs +66 -59
  97. package/dist/astro/routes/api/admin/plugins/_id_/index.mjs.map +1 -1
  98. package/dist/astro/routes/api/admin/plugins/_id_/mcp.mjs +6 -6
  99. package/dist/astro/routes/api/admin/plugins/_id_/settings.mjs +65 -59
  100. package/dist/astro/routes/api/admin/plugins/_id_/settings.mjs.map +1 -1
  101. package/dist/astro/routes/api/admin/plugins/_id_/uninstall.mjs +70 -61
  102. package/dist/astro/routes/api/admin/plugins/_id_/uninstall.mjs.map +1 -1
  103. package/dist/astro/routes/api/admin/plugins/_id_/update.d.mts.map +1 -1
  104. package/dist/astro/routes/api/admin/plugins/_id_/update.mjs +87 -63
  105. package/dist/astro/routes/api/admin/plugins/_id_/update.mjs.map +1 -1
  106. package/dist/astro/routes/api/admin/plugins/index.mjs +66 -59
  107. package/dist/astro/routes/api/admin/plugins/index.mjs.map +1 -1
  108. package/dist/astro/routes/api/admin/plugins/marketplace/_id_/icon.mjs +4 -4
  109. package/dist/astro/routes/api/admin/plugins/marketplace/_id_/index.mjs +65 -59
  110. package/dist/astro/routes/api/admin/plugins/marketplace/_id_/index.mjs.map +1 -1
  111. package/dist/astro/routes/api/admin/plugins/marketplace/_id_/install.d.mts.map +1 -1
  112. package/dist/astro/routes/api/admin/plugins/marketplace/_id_/install.mjs +85 -63
  113. package/dist/astro/routes/api/admin/plugins/marketplace/_id_/install.mjs.map +1 -1
  114. package/dist/astro/routes/api/admin/plugins/marketplace/index.mjs +65 -59
  115. package/dist/astro/routes/api/admin/plugins/marketplace/index.mjs.map +1 -1
  116. package/dist/astro/routes/api/admin/plugins/registry/_id_/uninstall.mjs +70 -61
  117. package/dist/astro/routes/api/admin/plugins/registry/_id_/uninstall.mjs.map +1 -1
  118. package/dist/astro/routes/api/admin/plugins/registry/_id_/update.d.mts.map +1 -1
  119. package/dist/astro/routes/api/admin/plugins/registry/_id_/update.mjs +90 -66
  120. package/dist/astro/routes/api/admin/plugins/registry/_id_/update.mjs.map +1 -1
  121. package/dist/astro/routes/api/admin/plugins/registry/artifact.d.mts.map +1 -1
  122. package/dist/astro/routes/api/admin/plugins/registry/artifact.mjs +9 -7
  123. package/dist/astro/routes/api/admin/plugins/registry/artifact.mjs.map +1 -1
  124. package/dist/astro/routes/api/admin/plugins/registry/install.d.mts.map +1 -1
  125. package/dist/astro/routes/api/admin/plugins/registry/install.mjs +77 -63
  126. package/dist/astro/routes/api/admin/plugins/registry/install.mjs.map +1 -1
  127. package/dist/astro/routes/api/admin/plugins/registry/verify.d.mts.map +1 -1
  128. package/dist/astro/routes/api/admin/plugins/registry/verify.mjs +67 -61
  129. package/dist/astro/routes/api/admin/plugins/registry/verify.mjs.map +1 -1
  130. package/dist/astro/routes/api/admin/plugins/updates.d.mts.map +1 -1
  131. package/dist/astro/routes/api/admin/plugins/updates.mjs +66 -60
  132. package/dist/astro/routes/api/admin/plugins/updates.mjs.map +1 -1
  133. package/dist/astro/routes/api/admin/scheduled-policy-rejections/_collection_/_id_.d.mts +8 -0
  134. package/dist/astro/routes/api/admin/scheduled-policy-rejections/_collection_/_id_.d.mts.map +1 -0
  135. package/dist/astro/routes/api/admin/scheduled-policy-rejections/_collection_/_id_.mjs +27 -0
  136. package/dist/astro/routes/api/admin/scheduled-policy-rejections/_collection_/_id_.mjs.map +1 -0
  137. package/dist/astro/routes/api/admin/themes/marketplace/_id_/index.mjs +65 -59
  138. package/dist/astro/routes/api/admin/themes/marketplace/_id_/index.mjs.map +1 -1
  139. package/dist/astro/routes/api/admin/themes/marketplace/_id_/thumbnail.mjs +4 -4
  140. package/dist/astro/routes/api/admin/themes/marketplace/index.mjs +65 -59
  141. package/dist/astro/routes/api/admin/themes/marketplace/index.mjs.map +1 -1
  142. package/dist/astro/routes/api/admin/users/_id_/disable.mjs +4 -4
  143. package/dist/astro/routes/api/admin/users/_id_/enable.mjs +3 -3
  144. package/dist/astro/routes/api/admin/users/_id_/index.mjs +11 -10
  145. package/dist/astro/routes/api/admin/users/_id_/index.mjs.map +1 -1
  146. package/dist/astro/routes/api/admin/users/_id_/send-recovery.mjs +5 -5
  147. package/dist/astro/routes/api/admin/users/index.mjs +10 -9
  148. package/dist/astro/routes/api/admin/users/index.mjs.map +1 -1
  149. package/dist/astro/routes/api/auth/dev-bypass.mjs +5 -5
  150. package/dist/astro/routes/api/auth/invite/accept.mjs +3 -3
  151. package/dist/astro/routes/api/auth/invite/complete.mjs +15 -14
  152. package/dist/astro/routes/api/auth/invite/complete.mjs.map +1 -1
  153. package/dist/astro/routes/api/auth/invite/index.mjs +12 -11
  154. package/dist/astro/routes/api/auth/invite/index.mjs.map +1 -1
  155. package/dist/astro/routes/api/auth/invite/register-options.mjs +14 -13
  156. package/dist/astro/routes/api/auth/invite/register-options.mjs.map +1 -1
  157. package/dist/astro/routes/api/auth/logout.mjs +4 -4
  158. package/dist/astro/routes/api/auth/magic-link/send.mjs +14 -13
  159. package/dist/astro/routes/api/auth/magic-link/send.mjs.map +1 -1
  160. package/dist/astro/routes/api/auth/magic-link/verify.mjs +4 -4
  161. package/dist/astro/routes/api/auth/me.mjs +11 -10
  162. package/dist/astro/routes/api/auth/me.mjs.map +1 -1
  163. package/dist/astro/routes/api/auth/mode.mjs +4 -4
  164. package/dist/astro/routes/api/auth/oauth/_provider_/callback.mjs +4 -4
  165. package/dist/astro/routes/api/auth/oauth/_provider_.mjs +2 -2
  166. package/dist/astro/routes/api/auth/passkey/_id_.mjs +10 -9
  167. package/dist/astro/routes/api/auth/passkey/_id_.mjs.map +1 -1
  168. package/dist/astro/routes/api/auth/passkey/index.mjs +3 -3
  169. package/dist/astro/routes/api/auth/passkey/options.mjs +16 -15
  170. package/dist/astro/routes/api/auth/passkey/options.mjs.map +1 -1
  171. package/dist/astro/routes/api/auth/passkey/register/options.mjs +14 -13
  172. package/dist/astro/routes/api/auth/passkey/register/options.mjs.map +1 -1
  173. package/dist/astro/routes/api/auth/passkey/register/verify.mjs +15 -14
  174. package/dist/astro/routes/api/auth/passkey/register/verify.mjs.map +1 -1
  175. package/dist/astro/routes/api/auth/passkey/verify.mjs +15 -14
  176. package/dist/astro/routes/api/auth/passkey/verify.mjs.map +1 -1
  177. package/dist/astro/routes/api/auth/signup/complete.mjs +15 -14
  178. package/dist/astro/routes/api/auth/signup/complete.mjs.map +1 -1
  179. package/dist/astro/routes/api/auth/signup/request.mjs +14 -13
  180. package/dist/astro/routes/api/auth/signup/request.mjs.map +1 -1
  181. package/dist/astro/routes/api/auth/signup/verify.mjs +3 -3
  182. package/dist/astro/routes/api/comments/_collection_/_contentId_/index.d.mts.map +1 -1
  183. package/dist/astro/routes/api/comments/_collection_/_contentId_/index.mjs +15 -211
  184. package/dist/astro/routes/api/comments/_collection_/_contentId_/index.mjs.map +1 -1
  185. package/dist/astro/routes/api/comments/_collection_/_contentId_/reactions.mjs +18 -17
  186. package/dist/astro/routes/api/comments/_collection_/_contentId_/reactions.mjs.map +1 -1
  187. package/dist/astro/routes/api/content/_collection_/_id_/compare.mjs +4 -4
  188. package/dist/astro/routes/api/content/_collection_/_id_/discard-draft.d.mts.map +1 -1
  189. package/dist/astro/routes/api/content/_collection_/_id_/discard-draft.mjs +17 -11
  190. package/dist/astro/routes/api/content/_collection_/_id_/discard-draft.mjs.map +1 -1
  191. package/dist/astro/routes/api/content/_collection_/_id_/duplicate.mjs +5 -5
  192. package/dist/astro/routes/api/content/_collection_/_id_/lock.d.mts +10 -0
  193. package/dist/astro/routes/api/content/_collection_/_id_/lock.d.mts.map +1 -0
  194. package/dist/astro/routes/api/content/_collection_/_id_/lock.mjs +67 -0
  195. package/dist/astro/routes/api/content/_collection_/_id_/lock.mjs.map +1 -0
  196. package/dist/astro/routes/api/content/_collection_/_id_/permanent.mjs +4 -4
  197. package/dist/astro/routes/api/content/_collection_/_id_/plugin-extensions/_pluginId_/_kind_/_extensionId_.d.mts +8 -0
  198. package/dist/astro/routes/api/content/_collection_/_id_/plugin-extensions/_pluginId_/_kind_/_extensionId_.d.mts.map +1 -0
  199. package/dist/astro/routes/api/content/_collection_/_id_/plugin-extensions/_pluginId_/_kind_/_extensionId_.mjs +35 -0
  200. package/dist/astro/routes/api/content/_collection_/_id_/plugin-extensions/_pluginId_/_kind_/_extensionId_.mjs.map +1 -0
  201. package/dist/astro/routes/api/content/_collection_/_id_/preview-url.mjs +16 -15
  202. package/dist/astro/routes/api/content/_collection_/_id_/preview-url.mjs.map +1 -1
  203. package/dist/astro/routes/api/content/_collection_/_id_/publish.d.mts +9 -2
  204. package/dist/astro/routes/api/content/_collection_/_id_/publish.d.mts.map +1 -1
  205. package/dist/astro/routes/api/content/_collection_/_id_/publish.mjs +28 -16
  206. package/dist/astro/routes/api/content/_collection_/_id_/publish.mjs.map +1 -1
  207. package/dist/astro/routes/api/content/_collection_/_id_/references/_relation_/children.mjs +27 -23
  208. package/dist/astro/routes/api/content/_collection_/_id_/references/_relation_/children.mjs.map +1 -1
  209. package/dist/astro/routes/api/content/_collection_/_id_/references/_relation_/parents.mjs +27 -23
  210. package/dist/astro/routes/api/content/_collection_/_id_/references/_relation_/parents.mjs.map +1 -1
  211. package/dist/astro/routes/api/content/_collection_/_id_/restore.mjs +5 -5
  212. package/dist/astro/routes/api/content/_collection_/_id_/revisions.mjs +4 -4
  213. package/dist/astro/routes/api/content/_collection_/_id_/schedule.d.mts.map +1 -1
  214. package/dist/astro/routes/api/content/_collection_/_id_/schedule.mjs +27 -12
  215. package/dist/astro/routes/api/content/_collection_/_id_/schedule.mjs.map +1 -1
  216. package/dist/astro/routes/api/content/_collection_/_id_/terms/_taxonomy_.mjs +23 -20
  217. package/dist/astro/routes/api/content/_collection_/_id_/terms/_taxonomy_.mjs.map +1 -1
  218. package/dist/astro/routes/api/content/_collection_/_id_/translations.mjs +4 -4
  219. package/dist/astro/routes/api/content/_collection_/_id_/unpublish.d.mts.map +1 -1
  220. package/dist/astro/routes/api/content/_collection_/_id_/unpublish.mjs +25 -12
  221. package/dist/astro/routes/api/content/_collection_/_id_/unpublish.mjs.map +1 -1
  222. package/dist/astro/routes/api/content/_collection_/_id_.d.mts.map +1 -1
  223. package/dist/astro/routes/api/content/_collection_/_id_.mjs +27 -14
  224. package/dist/astro/routes/api/content/_collection_/_id_.mjs.map +1 -1
  225. package/dist/astro/routes/api/content/_collection_/authors.mjs +4 -4
  226. package/dist/astro/routes/api/content/_collection_/index.mjs +18 -12
  227. package/dist/astro/routes/api/content/_collection_/index.mjs.map +1 -1
  228. package/dist/astro/routes/api/content/_collection_/trash.mjs +11 -10
  229. package/dist/astro/routes/api/content/_collection_/trash.mjs.map +1 -1
  230. package/dist/astro/routes/api/dashboard.mjs +14 -12
  231. package/dist/astro/routes/api/dashboard.mjs.map +1 -1
  232. package/dist/astro/routes/api/dev/emails.mjs +4 -4
  233. package/dist/astro/routes/api/health.d.mts +8 -0
  234. package/dist/astro/routes/api/health.d.mts.map +1 -0
  235. package/dist/astro/routes/api/health.mjs +21 -0
  236. package/dist/astro/routes/api/health.mjs.map +1 -0
  237. package/dist/astro/routes/api/import/probe.d.mts +3 -3
  238. package/dist/astro/routes/api/import/probe.mjs +25 -23
  239. package/dist/astro/routes/api/import/probe.mjs.map +1 -1
  240. package/dist/astro/routes/api/import/wordpress/analyze.mjs +5 -5
  241. package/dist/astro/routes/api/import/wordpress/execute.d.mts +13 -11
  242. package/dist/astro/routes/api/import/wordpress/execute.d.mts.map +1 -1
  243. package/dist/astro/routes/api/import/wordpress/execute.mjs +20 -19
  244. package/dist/astro/routes/api/import/wordpress/execute.mjs.map +1 -1
  245. package/dist/astro/routes/api/import/wordpress/media.d.mts +12 -10
  246. package/dist/astro/routes/api/import/wordpress/media.d.mts.map +1 -1
  247. package/dist/astro/routes/api/import/wordpress/media.mjs +15 -14
  248. package/dist/astro/routes/api/import/wordpress/media.mjs.map +1 -1
  249. package/dist/astro/routes/api/import/wordpress/prepare.mjs +14 -13
  250. package/dist/astro/routes/api/import/wordpress/prepare.mjs.map +1 -1
  251. package/dist/astro/routes/api/import/wordpress/rewrite-urls.d.mts +13 -11
  252. package/dist/astro/routes/api/import/wordpress/rewrite-urls.d.mts.map +1 -1
  253. package/dist/astro/routes/api/import/wordpress/rewrite-urls.mjs +18 -17
  254. package/dist/astro/routes/api/import/wordpress/rewrite-urls.mjs.map +1 -1
  255. package/dist/astro/routes/api/import/wordpress-plugin/analyze.d.mts +1 -1
  256. package/dist/astro/routes/api/import/wordpress-plugin/analyze.mjs +25 -23
  257. package/dist/astro/routes/api/import/wordpress-plugin/analyze.mjs.map +1 -1
  258. package/dist/astro/routes/api/import/wordpress-plugin/callback.mjs +1 -1
  259. package/dist/astro/routes/api/import/wordpress-plugin/execute.d.mts +13 -11
  260. package/dist/astro/routes/api/import/wordpress-plugin/execute.d.mts.map +1 -1
  261. package/dist/astro/routes/api/import/wordpress-plugin/execute.mjs +36 -33
  262. package/dist/astro/routes/api/import/wordpress-plugin/execute.mjs.map +1 -1
  263. package/dist/astro/routes/api/manifest.mjs +17 -9
  264. package/dist/astro/routes/api/manifest.mjs.map +1 -1
  265. package/dist/astro/routes/api/mcp.d.mts.map +1 -1
  266. package/dist/astro/routes/api/mcp.mjs +192 -110
  267. package/dist/astro/routes/api/mcp.mjs.map +1 -1
  268. package/dist/astro/routes/api/media/_id_/confirm.mjs +15 -14
  269. package/dist/astro/routes/api/media/_id_/confirm.mjs.map +1 -1
  270. package/dist/astro/routes/api/media/_id_/replace.mjs +12 -11
  271. package/dist/astro/routes/api/media/_id_/replace.mjs.map +1 -1
  272. package/dist/astro/routes/api/media/_id_/upload.mjs +8 -8
  273. package/dist/astro/routes/api/media/_id_/usage.mjs +23 -22
  274. package/dist/astro/routes/api/media/_id_/usage.mjs.map +1 -1
  275. package/dist/astro/routes/api/media/_id_.mjs +22 -21
  276. package/dist/astro/routes/api/media/_id_.mjs.map +1 -1
  277. package/dist/astro/routes/api/media/asset/_id_/_filename_.d.mts +8 -0
  278. package/dist/astro/routes/api/media/asset/_id_/_filename_.d.mts.map +1 -0
  279. package/dist/astro/routes/api/media/asset/_id_/_filename_.mjs +52 -0
  280. package/dist/astro/routes/api/media/asset/_id_/_filename_.mjs.map +1 -0
  281. package/dist/astro/routes/api/media/file/_...key_.mjs +3 -3
  282. package/dist/astro/routes/api/media/folders/_id_.mjs +12 -11
  283. package/dist/astro/routes/api/media/folders/_id_.mjs.map +1 -1
  284. package/dist/astro/routes/api/media/folders/index.mjs +12 -11
  285. package/dist/astro/routes/api/media/folders/index.mjs.map +1 -1
  286. package/dist/astro/routes/api/media/providers/_providerId_/_itemId_.mjs +4 -4
  287. package/dist/astro/routes/api/media/providers/_providerId_/index.mjs +4 -4
  288. package/dist/astro/routes/api/media/providers/index.mjs +4 -4
  289. package/dist/astro/routes/api/media/upload-url.mjs +14 -13
  290. package/dist/astro/routes/api/media/upload-url.mjs.map +1 -1
  291. package/dist/astro/routes/api/media.mjs +26 -25
  292. package/dist/astro/routes/api/media.mjs.map +1 -1
  293. package/dist/astro/routes/api/menus/_name_/items/_id_.mjs +15 -14
  294. package/dist/astro/routes/api/menus/_name_/items/_id_.mjs.map +1 -1
  295. package/dist/astro/routes/api/menus/_name_/items.mjs +15 -14
  296. package/dist/astro/routes/api/menus/_name_/items.mjs.map +1 -1
  297. package/dist/astro/routes/api/menus/_name_/reorder.mjs +15 -14
  298. package/dist/astro/routes/api/menus/_name_/reorder.mjs.map +1 -1
  299. package/dist/astro/routes/api/menus/_name_/translations.mjs +15 -14
  300. package/dist/astro/routes/api/menus/_name_/translations.mjs.map +1 -1
  301. package/dist/astro/routes/api/menus/_name_.mjs +15 -14
  302. package/dist/astro/routes/api/menus/_name_.mjs.map +1 -1
  303. package/dist/astro/routes/api/menus/index.mjs +15 -14
  304. package/dist/astro/routes/api/menus/index.mjs.map +1 -1
  305. package/dist/astro/routes/api/oauth/authorize.mjs +6 -6
  306. package/dist/astro/routes/api/oauth/device/authorize.mjs +7 -7
  307. package/dist/astro/routes/api/oauth/device/code.mjs +10 -10
  308. package/dist/astro/routes/api/oauth/device/token.mjs +9 -9
  309. package/dist/astro/routes/api/oauth/register.mjs +4 -4
  310. package/dist/astro/routes/api/oauth/token/refresh.mjs +7 -7
  311. package/dist/astro/routes/api/oauth/token/revoke.mjs +7 -7
  312. package/dist/astro/routes/api/oauth/token.mjs +7 -7
  313. package/dist/astro/routes/api/openapi.json.mjs +95 -24
  314. package/dist/astro/routes/api/openapi.json.mjs.map +1 -1
  315. package/dist/astro/routes/api/plugins/_pluginId_/_...path_.d.mts +2 -1
  316. package/dist/astro/routes/api/plugins/_pluginId_/_...path_.d.mts.map +1 -1
  317. package/dist/astro/routes/api/plugins/_pluginId_/_...path_.mjs +22 -40
  318. package/dist/astro/routes/api/plugins/_pluginId_/_...path_.mjs.map +1 -1
  319. package/dist/astro/routes/api/redirects/404s/index.mjs +18 -14
  320. package/dist/astro/routes/api/redirects/404s/index.mjs.map +1 -1
  321. package/dist/astro/routes/api/redirects/404s/summary.mjs +18 -14
  322. package/dist/astro/routes/api/redirects/404s/summary.mjs.map +1 -1
  323. package/dist/astro/routes/api/redirects/_id_.d.mts.map +1 -1
  324. package/dist/astro/routes/api/redirects/_id_.mjs +20 -22
  325. package/dist/astro/routes/api/redirects/_id_.mjs.map +1 -1
  326. package/dist/astro/routes/api/redirects/index.d.mts.map +1 -1
  327. package/dist/astro/routes/api/redirects/index.mjs +19 -19
  328. package/dist/astro/routes/api/redirects/index.mjs.map +1 -1
  329. package/dist/astro/routes/api/relations/_id_/index.mjs +27 -23
  330. package/dist/astro/routes/api/relations/_id_/index.mjs.map +1 -1
  331. package/dist/astro/routes/api/relations/_id_/translations.mjs +21 -18
  332. package/dist/astro/routes/api/relations/_id_/translations.mjs.map +1 -1
  333. package/dist/astro/routes/api/relations/index.mjs +27 -23
  334. package/dist/astro/routes/api/relations/index.mjs.map +1 -1
  335. package/dist/astro/routes/api/revisions/_revisionId_/index.mjs +4 -4
  336. package/dist/astro/routes/api/revisions/_revisionId_/restore.mjs +5 -5
  337. package/dist/astro/routes/api/schema/collections/_slug_/fields/_fieldSlug_.mjs +65 -59
  338. package/dist/astro/routes/api/schema/collections/_slug_/fields/_fieldSlug_.mjs.map +1 -1
  339. package/dist/astro/routes/api/schema/collections/_slug_/fields/index.mjs +65 -59
  340. package/dist/astro/routes/api/schema/collections/_slug_/fields/index.mjs.map +1 -1
  341. package/dist/astro/routes/api/schema/collections/_slug_/fields/reorder.mjs +65 -59
  342. package/dist/astro/routes/api/schema/collections/_slug_/fields/reorder.mjs.map +1 -1
  343. package/dist/astro/routes/api/schema/collections/_slug_/index.mjs +65 -59
  344. package/dist/astro/routes/api/schema/collections/_slug_/index.mjs.map +1 -1
  345. package/dist/astro/routes/api/schema/collections/index.mjs +65 -59
  346. package/dist/astro/routes/api/schema/collections/index.mjs.map +1 -1
  347. package/dist/astro/routes/api/schema/collections/reorder.mjs +65 -59
  348. package/dist/astro/routes/api/schema/collections/reorder.mjs.map +1 -1
  349. package/dist/astro/routes/api/schema/index.mjs +16 -14
  350. package/dist/astro/routes/api/schema/index.mjs.map +1 -1
  351. package/dist/astro/routes/api/schema/orphans/_slug_.mjs +65 -59
  352. package/dist/astro/routes/api/schema/orphans/_slug_.mjs.map +1 -1
  353. package/dist/astro/routes/api/schema/orphans/index.mjs +65 -59
  354. package/dist/astro/routes/api/schema/orphans/index.mjs.map +1 -1
  355. package/dist/astro/routes/api/search/enable.mjs +16 -14
  356. package/dist/astro/routes/api/search/enable.mjs.map +1 -1
  357. package/dist/astro/routes/api/search/index.mjs +17 -14
  358. package/dist/astro/routes/api/search/index.mjs.map +1 -1
  359. package/dist/astro/routes/api/search/rebuild.mjs +16 -14
  360. package/dist/astro/routes/api/search/rebuild.mjs.map +1 -1
  361. package/dist/astro/routes/api/search/stats.mjs +10 -9
  362. package/dist/astro/routes/api/search/stats.mjs.map +1 -1
  363. package/dist/astro/routes/api/search/suggest.mjs +15 -13
  364. package/dist/astro/routes/api/search/suggest.mjs.map +1 -1
  365. package/dist/astro/routes/api/sections/_slug_.mjs +15 -13
  366. package/dist/astro/routes/api/sections/_slug_.mjs.map +1 -1
  367. package/dist/astro/routes/api/sections/index.mjs +15 -13
  368. package/dist/astro/routes/api/sections/index.mjs.map +1 -1
  369. package/dist/astro/routes/api/settings/backups/archives/_name_.mjs +9 -8
  370. package/dist/astro/routes/api/settings/backups/archives/_name_.mjs.map +1 -1
  371. package/dist/astro/routes/api/settings/backups/archives/index.mjs +8 -7
  372. package/dist/astro/routes/api/settings/backups/archives/index.mjs.map +1 -1
  373. package/dist/astro/routes/api/settings/backups/export.mjs +9 -8
  374. package/dist/astro/routes/api/settings/backups/export.mjs.map +1 -1
  375. package/dist/astro/routes/api/settings/backups/index.mjs +10 -9
  376. package/dist/astro/routes/api/settings/backups/index.mjs.map +1 -1
  377. package/dist/astro/routes/api/settings/email.mjs +6 -6
  378. package/dist/astro/routes/api/settings.mjs +22 -20
  379. package/dist/astro/routes/api/settings.mjs.map +1 -1
  380. package/dist/astro/routes/api/setup/admin-verify.mjs +16 -15
  381. package/dist/astro/routes/api/setup/admin-verify.mjs.map +1 -1
  382. package/dist/astro/routes/api/setup/admin.mjs +15 -14
  383. package/dist/astro/routes/api/setup/admin.mjs.map +1 -1
  384. package/dist/astro/routes/api/setup/dev-bypass.mjs +42 -38
  385. package/dist/astro/routes/api/setup/dev-bypass.mjs.map +1 -1
  386. package/dist/astro/routes/api/setup/dev-reset.mjs +4 -4
  387. package/dist/astro/routes/api/setup/index.mjs +43 -38
  388. package/dist/astro/routes/api/setup/index.mjs.map +1 -1
  389. package/dist/astro/routes/api/setup/status.mjs +5 -5
  390. package/dist/astro/routes/api/snapshot.mjs +11 -10
  391. package/dist/astro/routes/api/snapshot.mjs.map +1 -1
  392. package/dist/astro/routes/api/taxonomies/_name_/reorder.mjs +23 -21
  393. package/dist/astro/routes/api/taxonomies/_name_/reorder.mjs.map +1 -1
  394. package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_/translations.mjs +23 -21
  395. package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_/translations.mjs.map +1 -1
  396. package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_.mjs +23 -21
  397. package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_.mjs.map +1 -1
  398. package/dist/astro/routes/api/taxonomies/_name_/terms/index.mjs +23 -21
  399. package/dist/astro/routes/api/taxonomies/_name_/terms/index.mjs.map +1 -1
  400. package/dist/astro/routes/api/taxonomies/_name_/translations.mjs +22 -20
  401. package/dist/astro/routes/api/taxonomies/_name_/translations.mjs.map +1 -1
  402. package/dist/astro/routes/api/taxonomies/_name_.mjs +23 -21
  403. package/dist/astro/routes/api/taxonomies/_name_.mjs.map +1 -1
  404. package/dist/astro/routes/api/taxonomies/index.mjs +23 -21
  405. package/dist/astro/routes/api/taxonomies/index.mjs.map +1 -1
  406. package/dist/astro/routes/api/themes/preview.mjs +8 -8
  407. package/dist/astro/routes/api/typegen.mjs +6 -6
  408. package/dist/astro/routes/api/visual-editing/action-token.d.mts +8 -0
  409. package/dist/astro/routes/api/visual-editing/action-token.d.mts.map +1 -0
  410. package/dist/astro/routes/api/visual-editing/action-token.mjs +25 -0
  411. package/dist/astro/routes/api/visual-editing/action-token.mjs.map +1 -0
  412. package/dist/astro/routes/api/visual-editing/content/_collection_/_id_/publish.d.mts +8 -0
  413. package/dist/astro/routes/api/visual-editing/content/_collection_/_id_/publish.d.mts.map +1 -0
  414. package/dist/astro/routes/api/visual-editing/content/_collection_/_id_/publish.mjs +37 -0
  415. package/dist/astro/routes/api/visual-editing/content/_collection_/_id_/publish.mjs.map +1 -0
  416. package/dist/astro/routes/api/visual-editing/toolbar-labels.d.mts +8 -0
  417. package/dist/astro/routes/api/visual-editing/toolbar-labels.d.mts.map +1 -0
  418. package/dist/astro/routes/api/visual-editing/toolbar-labels.mjs +20 -0
  419. package/dist/astro/routes/api/visual-editing/toolbar-labels.mjs.map +1 -0
  420. package/dist/astro/routes/api/well-known/auth.mjs +2 -2
  421. package/dist/astro/routes/api/well-known/oauth-authorization-server.mjs +2 -2
  422. package/dist/astro/routes/api/well-known/oauth-protected-resource.mjs +2 -2
  423. package/dist/astro/routes/api/widget-areas/_name_/reorder.mjs +12 -11
  424. package/dist/astro/routes/api/widget-areas/_name_/reorder.mjs.map +1 -1
  425. package/dist/astro/routes/api/widget-areas/_name_/widgets/_id_.mjs +16 -15
  426. package/dist/astro/routes/api/widget-areas/_name_/widgets/_id_.mjs.map +1 -1
  427. package/dist/astro/routes/api/widget-areas/_name_/widgets.mjs +16 -15
  428. package/dist/astro/routes/api/widget-areas/_name_/widgets.mjs.map +1 -1
  429. package/dist/astro/routes/api/widget-areas/_name_.mjs +10 -10
  430. package/dist/astro/routes/api/widget-areas/index.mjs +16 -15
  431. package/dist/astro/routes/api/widget-areas/index.mjs.map +1 -1
  432. package/dist/astro/routes/api/widget-components.mjs +4 -4
  433. package/dist/astro/routes/robots.txt.mjs +13 -12
  434. package/dist/astro/routes/robots.txt.mjs.map +1 -1
  435. package/dist/astro/routes/sitemap-_collection_.xml.d.mts.map +1 -1
  436. package/dist/astro/routes/sitemap-_collection_.xml.mjs +24 -19
  437. package/dist/astro/routes/sitemap-_collection_.xml.mjs.map +1 -1
  438. package/dist/astro/routes/sitemap.xml.mjs +14 -13
  439. package/dist/astro/routes/sitemap.xml.mjs.map +1 -1
  440. package/dist/astro/types.d.mts +79 -26
  441. package/dist/astro/types.d.mts.map +1 -1
  442. package/dist/auth/providers/github.d.mts +1 -1
  443. package/dist/auth/providers/google.d.mts +1 -1
  444. package/dist/authoritative-records-DbqshfKD.mjs +5172 -0
  445. package/dist/authoritative-records-DbqshfKD.mjs.map +1 -0
  446. package/dist/authorize-BXpfMpp0.mjs +40 -0
  447. package/dist/authorize-BXpfMpp0.mjs.map +1 -0
  448. package/dist/backup-BsPQdwnS.mjs +246 -0
  449. package/dist/backup-BsPQdwnS.mjs.map +1 -0
  450. package/dist/base64-DvnNgP7e.mjs +63 -0
  451. package/dist/base64-DvnNgP7e.mjs.map +1 -0
  452. package/dist/byline-Doh-wt99.mjs +906 -0
  453. package/dist/byline-Doh-wt99.mjs.map +1 -0
  454. package/dist/byline-fields-CsrdvaLV.mjs +123 -0
  455. package/dist/byline-fields-CsrdvaLV.mjs.map +1 -0
  456. package/dist/byline-registry-D6lWzXk6.mjs +406 -0
  457. package/dist/byline-registry-D6lWzXk6.mjs.map +1 -0
  458. package/dist/bylines-Cop0hkoy.mjs +214 -0
  459. package/dist/bylines-Cop0hkoy.mjs.map +1 -0
  460. package/dist/bylines-kpBzHPr8.mjs +232 -0
  461. package/dist/bylines-kpBzHPr8.mjs.map +1 -0
  462. package/dist/cache-B0pOlXdM.mjs +108 -0
  463. package/dist/cache-B0pOlXdM.mjs.map +1 -0
  464. package/dist/capture-triggers-gxQxnxrJ.mjs +362 -0
  465. package/dist/capture-triggers-gxQxnxrJ.mjs.map +1 -0
  466. package/dist/challenge-store-CkRdSdd8.mjs +51 -0
  467. package/dist/challenge-store-CkRdSdd8.mjs.map +1 -0
  468. package/dist/checksum-Bsi2D9M1.mjs +162 -0
  469. package/dist/checksum-Bsi2D9M1.mjs.map +1 -0
  470. package/dist/chrome-tags-D7LGB91U.mjs +24 -0
  471. package/dist/chrome-tags-D7LGB91U.mjs.map +1 -0
  472. package/dist/chunks-BmWyou79.mjs +25 -0
  473. package/dist/chunks-BmWyou79.mjs.map +1 -0
  474. package/dist/cli/index.mjs +921 -106
  475. package/dist/cli/index.mjs.map +1 -1
  476. package/dist/client/cf-access.d.mts +1 -1
  477. package/dist/client/index.d.mts +17 -7
  478. package/dist/client/index.d.mts.map +1 -1
  479. package/dist/client/index.mjs +17 -12
  480. package/dist/client/index.mjs.map +1 -1
  481. package/dist/collection-deletion-C3Xixmkx.mjs +436 -0
  482. package/dist/collection-deletion-C3Xixmkx.mjs.map +1 -0
  483. package/dist/collection-slugs-cache-D9auiKmI.mjs +85 -0
  484. package/dist/collection-slugs-cache-D9auiKmI.mjs.map +1 -0
  485. package/dist/comment-DcT8qdPK.mjs +313 -0
  486. package/dist/comment-DcT8qdPK.mjs.map +1 -0
  487. package/dist/comment-reaction-DY5-y8Y5.mjs +85 -0
  488. package/dist/comment-reaction-DY5-y8Y5.mjs.map +1 -0
  489. package/dist/comments-B67VRNGw.mjs +204 -0
  490. package/dist/comments-B67VRNGw.mjs.map +1 -0
  491. package/dist/comments-BVzzt6x5.mjs +99 -0
  492. package/dist/comments-BVzzt6x5.mjs.map +1 -0
  493. package/dist/components-DIl9Qzh6.mjs +108 -0
  494. package/dist/components-DIl9Qzh6.mjs.map +1 -0
  495. package/dist/config-B2acLeC5.mjs +242 -0
  496. package/dist/config-B2acLeC5.mjs.map +1 -0
  497. package/dist/config-CGVeT8Hc.mjs +73 -0
  498. package/dist/config-CGVeT8Hc.mjs.map +1 -0
  499. package/dist/config-D3HhLON3.d.mts +39 -0
  500. package/dist/config-D3HhLON3.d.mts.map +1 -0
  501. package/dist/config-DS7e4EZ9.d.mts +6387 -0
  502. package/dist/config-DS7e4EZ9.d.mts.map +1 -0
  503. package/dist/content-DZ3B5qtA.mjs +2216 -0
  504. package/dist/content-DZ3B5qtA.mjs.map +1 -0
  505. package/dist/content-list-query-CbPdzsna.d.mts +26 -0
  506. package/dist/content-list-query-CbPdzsna.d.mts.map +1 -0
  507. package/dist/content-policy-CM4skrNi.mjs +46 -0
  508. package/dist/content-policy-CM4skrNi.mjs.map +1 -0
  509. package/dist/content-refresh-BHLHJgyt.mjs +3599 -0
  510. package/dist/content-refresh-BHLHJgyt.mjs.map +1 -0
  511. package/dist/content-repair-BVll5WNl.mjs +440 -0
  512. package/dist/content-repair-BVll5WNl.mjs.map +1 -0
  513. package/dist/context-B195kjqZ.mjs +1835 -0
  514. package/dist/context-B195kjqZ.mjs.map +1 -0
  515. package/dist/cron-BcR3RN4K.mjs +282 -0
  516. package/dist/cron-BcR3RN4K.mjs.map +1 -0
  517. package/dist/dashboard-CZD4G7k_.mjs +151 -0
  518. package/dist/dashboard-CZD4G7k_.mjs.map +1 -0
  519. package/dist/database/migration-lock.d.mts +37 -0
  520. package/dist/database/migration-lock.d.mts.map +1 -0
  521. package/dist/database/migration-lock.mjs +76 -0
  522. package/dist/database/migration-lock.mjs.map +1 -0
  523. package/dist/database/pg-migration-lock.d.mts +1 -1
  524. package/dist/database/pg-migration-lock.mjs +1 -1
  525. package/dist/database/pg-migration-lock.mjs.map +1 -1
  526. package/dist/datetime-normalization-PeiEdcRY.mjs +187 -0
  527. package/dist/datetime-normalization-PeiEdcRY.mjs.map +1 -0
  528. package/dist/db/index.d.mts +3 -3
  529. package/dist/db/index.mjs +4 -3
  530. package/dist/db/index.mjs.map +1 -1
  531. package/dist/db/libsql-migrations.d.mts +1 -1
  532. package/dist/db/libsql-migrations.mjs +7 -6
  533. package/dist/db/libsql-migrations.mjs.map +1 -1
  534. package/dist/db/libsql.d.mts +1 -1
  535. package/dist/db/postgres-migrations.d.mts +1 -1
  536. package/dist/db/postgres-migrations.mjs +7 -6
  537. package/dist/db/postgres-migrations.mjs.map +1 -1
  538. package/dist/db/postgres.d.mts +1 -1
  539. package/dist/db/sqlite-migrations.d.mts +1 -1
  540. package/dist/db/sqlite-migrations.mjs +7 -6
  541. package/dist/db/sqlite-migrations.mjs.map +1 -1
  542. package/dist/db/sqlite.d.mts +1 -1
  543. package/dist/db/sqlite.mjs +1 -1
  544. package/dist/db-errors-CBD5yMro.mjs +55 -0
  545. package/dist/db-errors-CBD5yMro.mjs.map +1 -0
  546. package/dist/default-BtlxWgh9.mjs +81 -0
  547. package/dist/default-BtlxWgh9.mjs.map +1 -0
  548. package/dist/deferred-tasks-Ba9fphlE.d.mts +9 -0
  549. package/dist/deferred-tasks-Ba9fphlE.d.mts.map +1 -0
  550. package/dist/dev-typegen-CZaPLl3V.mjs +29 -0
  551. package/dist/dev-typegen-CZaPLl3V.mjs.map +1 -0
  552. package/dist/device-flow-3E5l0fpH.mjs +466 -0
  553. package/dist/device-flow-3E5l0fpH.mjs.map +1 -0
  554. package/dist/dialect-helpers-CtYdsX4W.mjs +307 -0
  555. package/dist/dialect-helpers-CtYdsX4W.mjs.map +1 -0
  556. package/dist/direct-executor-ZI8E01Yt.mjs +104 -0
  557. package/dist/direct-executor-ZI8E01Yt.mjs.map +1 -0
  558. package/dist/dist-2hDLsLeq.mjs +810 -0
  559. package/dist/dist-2hDLsLeq.mjs.map +1 -0
  560. package/dist/email-console-gc-E3Eqj.mjs +50 -0
  561. package/dist/email-console-gc-E3Eqj.mjs.map +1 -0
  562. package/dist/emdash-runtime-DZGinqTL.mjs +4041 -0
  563. package/dist/emdash-runtime-DZGinqTL.mjs.map +1 -0
  564. package/dist/enrich-C2Mk0lwE.mjs +194 -0
  565. package/dist/enrich-C2Mk0lwE.mjs.map +1 -0
  566. package/dist/entry-lock-D3C99MXS.mjs +1520 -0
  567. package/dist/entry-lock-D3C99MXS.mjs.map +1 -0
  568. package/dist/entry-lock-D9rnj2Lu.mjs +163 -0
  569. package/dist/entry-lock-D9rnj2Lu.mjs.map +1 -0
  570. package/dist/entry-lock-DX7QkqEg.d.mts +3503 -0
  571. package/dist/entry-lock-DX7QkqEg.d.mts.map +1 -0
  572. package/dist/entry-locks-CO_KaoU5.mjs +167 -0
  573. package/dist/entry-locks-CO_KaoU5.mjs.map +1 -0
  574. package/dist/error-CCTCskie.mjs +90 -0
  575. package/dist/error-CCTCskie.mjs.map +1 -0
  576. package/dist/errors-W3PA8HqB.mjs +447 -0
  577. package/dist/errors-W3PA8HqB.mjs.map +1 -0
  578. package/dist/escape-DN4Qmjsl.mjs +9 -0
  579. package/dist/escape-DN4Qmjsl.mjs.map +1 -0
  580. package/dist/field-defs-cache-B337z8UJ.mjs +77 -0
  581. package/dist/field-defs-cache-B337z8UJ.mjs.map +1 -0
  582. package/dist/focal-point-Gr34o-4o.mjs +23 -0
  583. package/dist/focal-point-Gr34o-4o.mjs.map +1 -0
  584. package/dist/fts-manager-DMb0sbIQ.mjs +413 -0
  585. package/dist/fts-manager-DMb0sbIQ.mjs.map +1 -0
  586. package/dist/hash-CLVFzWvx.mjs +37 -0
  587. package/dist/hash-CLVFzWvx.mjs.map +1 -0
  588. package/dist/hook-result-KY1jq21o.d.mts +31 -0
  589. package/dist/hook-result-KY1jq21o.d.mts.map +1 -0
  590. package/dist/hreflang-BgS2FqhH.d.mts +50 -0
  591. package/dist/hreflang-BgS2FqhH.d.mts.map +1 -0
  592. package/dist/hreflang-CrJwqoeb.mjs +105 -0
  593. package/dist/hreflang-CrJwqoeb.mjs.map +1 -0
  594. package/dist/http-route-dispatch-DAKlanXb.mjs +339 -0
  595. package/dist/http-route-dispatch-DAKlanXb.mjs.map +1 -0
  596. package/dist/identity-DRGSHEEr.mjs +35 -0
  597. package/dist/identity-DRGSHEEr.mjs.map +1 -0
  598. package/dist/import-DFr5B_hC.mjs +2020 -0
  599. package/dist/import-DFr5B_hC.mjs.map +1 -0
  600. package/dist/index-CDwKDkTq.d.mts +623 -0
  601. package/dist/index-CDwKDkTq.d.mts.map +1 -0
  602. package/dist/index.d.mts +27 -22
  603. package/dist/index.mjs +101 -86
  604. package/dist/init-lock-4eRRB4Le.mjs +56 -0
  605. package/dist/init-lock-4eRRB4Le.mjs.map +1 -0
  606. package/dist/install-finalization-5Os-QZ-2.mjs +58 -0
  607. package/dist/install-finalization-5Os-QZ-2.mjs.map +1 -0
  608. package/dist/lifecycle-7e-Lt_kX.mjs +25 -0
  609. package/dist/lifecycle-7e-Lt_kX.mjs.map +1 -0
  610. package/dist/load-Cu5bvCZh.mjs +28 -0
  611. package/dist/load-Cu5bvCZh.mjs.map +1 -0
  612. package/dist/loader-t4TxaFiQ.mjs +1004 -0
  613. package/dist/loader-t4TxaFiQ.mjs.map +1 -0
  614. package/dist/manifest-builder-D31UoJCu.mjs +189 -0
  615. package/dist/manifest-builder-D31UoJCu.mjs.map +1 -0
  616. package/dist/manifest-schema-Bkh8SeHd.mjs +491 -0
  617. package/dist/manifest-schema-Bkh8SeHd.mjs.map +1 -0
  618. package/dist/media/image-endpoint.mjs +1 -1
  619. package/dist/media/index.d.mts +1 -1
  620. package/dist/media/index.mjs +4 -4
  621. package/dist/media/local-runtime.d.mts +14 -12
  622. package/dist/media/local-runtime.d.mts.map +1 -1
  623. package/dist/media/local-runtime.mjs +12 -11
  624. package/dist/media/local-runtime.mjs.map +1 -1
  625. package/dist/media-TBlKCwo7.mjs +334 -0
  626. package/dist/media-TBlKCwo7.mjs.map +1 -0
  627. package/dist/media-allowlist-s60eAIf6.mjs +44 -0
  628. package/dist/media-allowlist-s60eAIf6.mjs.map +1 -0
  629. package/dist/media-folders-ClIRLUQv.mjs +210 -0
  630. package/dist/media-folders-ClIRLUQv.mjs.map +1 -0
  631. package/dist/media-url-DY_ijO3B.mjs +43 -0
  632. package/dist/media-url-DY_ijO3B.mjs.map +1 -0
  633. package/dist/media-usage-C4NolTpQ.mjs +1833 -0
  634. package/dist/media-usage-C4NolTpQ.mjs.map +1 -0
  635. package/dist/media-usage-activation-CAhmb14O.mjs +78 -0
  636. package/dist/media-usage-activation-CAhmb14O.mjs.map +1 -0
  637. package/dist/media-usage-work-Cu5DqewW.mjs +586 -0
  638. package/dist/media-usage-work-Cu5DqewW.mjs.map +1 -0
  639. package/dist/media-usage-work-DJr3rOEN.mjs +152 -0
  640. package/dist/media-usage-work-DJr3rOEN.mjs.map +1 -0
  641. package/dist/media-usage-write-fence-DW5oHT7q.mjs +42 -0
  642. package/dist/media-usage-write-fence-DW5oHT7q.mjs.map +1 -0
  643. package/dist/menus-DbgU9z5Q.mjs +3732 -0
  644. package/dist/menus-DbgU9z5Q.mjs.map +1 -0
  645. package/dist/menus-Wy8m5NcH.mjs +753 -0
  646. package/dist/menus-Wy8m5NcH.mjs.map +1 -0
  647. package/dist/migrations/index.d.mts +2 -2
  648. package/dist/migrations/index.d.mts.map +1 -1
  649. package/dist/migrations/index.mjs +6 -5
  650. package/dist/mime-CCYRC4r1.mjs +36 -0
  651. package/dist/mime-CCYRC4r1.mjs.map +1 -0
  652. package/dist/mode-CkmOhFqj.mjs +23 -0
  653. package/dist/mode-CkmOhFqj.mjs.map +1 -0
  654. package/dist/node-sqlite-compat-vpVaILnb.mjs +46 -0
  655. package/dist/node-sqlite-compat-vpVaILnb.mjs.map +1 -0
  656. package/dist/normalize-dChXQjwS.mjs +191 -0
  657. package/dist/normalize-dChXQjwS.mjs.map +1 -0
  658. package/dist/oauth-authorization-DZ-R-hmx.mjs +274 -0
  659. package/dist/oauth-authorization-DZ-R-hmx.mjs.map +1 -0
  660. package/dist/oauth-clients-BMPA8vjl.mjs +266 -0
  661. package/dist/oauth-clients-BMPA8vjl.mjs.map +1 -0
  662. package/dist/oauth-state-store-0gIdb48-.mjs +50 -0
  663. package/dist/oauth-state-store-0gIdb48-.mjs.map +1 -0
  664. package/dist/oauth-user-lookup-ChVW4UWu.mjs +26 -0
  665. package/dist/oauth-user-lookup-ChVW4UWu.mjs.map +1 -0
  666. package/dist/object-cache/memory.d.mts +1 -1
  667. package/dist/object-cache-DlSVbn5Y.mjs +534 -0
  668. package/dist/object-cache-DlSVbn5Y.mjs.map +1 -0
  669. package/dist/options-D5WcorD5.mjs +200 -0
  670. package/dist/options-D5WcorD5.mjs.map +1 -0
  671. package/dist/options-DAknChnw.d.mts +77 -0
  672. package/dist/options-DAknChnw.d.mts.map +1 -0
  673. package/dist/page/index.d.mts +2 -2
  674. package/dist/page/index.d.mts.map +1 -1
  675. package/dist/page/index.mjs +13 -0
  676. package/dist/page/index.mjs.map +1 -1
  677. package/dist/parse-Cr379Av9.mjs +81 -0
  678. package/dist/parse-Cr379Av9.mjs.map +1 -0
  679. package/dist/parse-tj9XLNO_.d.mts +165 -0
  680. package/dist/parse-tj9XLNO_.d.mts.map +1 -0
  681. package/dist/passkey-config-BD-wMaCf.mjs +46 -0
  682. package/dist/passkey-config-BD-wMaCf.mjs.map +1 -0
  683. package/dist/patterns-Do3iqi7N.mjs +145 -0
  684. package/dist/patterns-Do3iqi7N.mjs.map +1 -0
  685. package/dist/placeholder-CubPFn_L.d.mts +306 -0
  686. package/dist/placeholder-CubPFn_L.d.mts.map +1 -0
  687. package/dist/plugin-test-runtime.d.mts +97 -0
  688. package/dist/plugin-test-runtime.d.mts.map +1 -0
  689. package/dist/plugin-test-runtime.mjs +105 -0
  690. package/dist/plugin-types.d.mts +53 -15
  691. package/dist/plugin-types.d.mts.map +1 -1
  692. package/dist/plugin-types.mjs +18 -1
  693. package/dist/plugin-types.mjs.map +1 -0
  694. package/dist/plugin-utils.d.mts +12 -10
  695. package/dist/plugin-utils.d.mts.map +1 -1
  696. package/dist/plugins/adapt-sandbox-entry.d.mts +12 -10
  697. package/dist/plugins/adapt-sandbox-entry.d.mts.map +1 -1
  698. package/dist/plugins/adapt-sandbox-entry.mjs +18 -13
  699. package/dist/plugins/adapt-sandbox-entry.mjs.map +1 -1
  700. package/dist/plugins/host.d.mts +7 -0
  701. package/dist/plugins/host.mjs +45 -0
  702. package/dist/plugins/http-wire.d.mts +25 -0
  703. package/dist/plugins/http-wire.d.mts.map +1 -0
  704. package/dist/plugins/http-wire.mjs +148 -0
  705. package/dist/plugins/http-wire.mjs.map +1 -0
  706. package/dist/plugins/secret-redactor.d.mts +9 -0
  707. package/dist/plugins/secret-redactor.d.mts.map +1 -0
  708. package/dist/plugins/secret-redactor.mjs +51 -0
  709. package/dist/plugins/secret-redactor.mjs.map +1 -0
  710. package/dist/plugins-DHurtdXQ.mjs +277 -0
  711. package/dist/plugins-DHurtdXQ.mjs.map +1 -0
  712. package/dist/policy-lyZnjpwz.mjs +45 -0
  713. package/dist/policy-lyZnjpwz.mjs.map +1 -0
  714. package/dist/portable-text-oAwodbPS.mjs +286 -0
  715. package/dist/portable-text-oAwodbPS.mjs.map +1 -0
  716. package/dist/preview-Cup2bj8c.mjs +107 -0
  717. package/dist/preview-Cup2bj8c.mjs.map +1 -0
  718. package/dist/protocol-C1CNiKX4.d.mts +61 -0
  719. package/dist/protocol-C1CNiKX4.d.mts.map +1 -0
  720. package/dist/public-submission-Cs-pFMQK.mjs +245 -0
  721. package/dist/public-submission-Cs-pFMQK.mjs.map +1 -0
  722. package/dist/public-url-BWVHsfQv.mjs +101 -0
  723. package/dist/public-url-BWVHsfQv.mjs.map +1 -0
  724. package/dist/query-D-lxiOgn.mjs +890 -0
  725. package/dist/query-D-lxiOgn.mjs.map +1 -0
  726. package/dist/query-D7kHKOws.mjs +41 -0
  727. package/dist/query-D7kHKOws.mjs.map +1 -0
  728. package/dist/rate-limit-CqJn-w4h.mjs +120 -0
  729. package/dist/rate-limit-CqJn-w4h.mjs.map +1 -0
  730. package/dist/redirect-BrChFPIu.mjs +17 -0
  731. package/dist/redirect-BrChFPIu.mjs.map +1 -0
  732. package/dist/redirect-D2Yo-b6S.mjs +415 -0
  733. package/dist/redirect-D2Yo-b6S.mjs.map +1 -0
  734. package/dist/redirects-BCiTaIQ-.mjs +146 -0
  735. package/dist/redirects-BCiTaIQ-.mjs.map +1 -0
  736. package/dist/redirects-ByItliuu.mjs +644 -0
  737. package/dist/redirects-ByItliuu.mjs.map +1 -0
  738. package/dist/registry/testing.d.mts +14 -0
  739. package/dist/registry/testing.d.mts.map +1 -0
  740. package/dist/registry/testing.mjs +255 -0
  741. package/dist/registry/testing.mjs.map +1 -0
  742. package/dist/registry-CkuPoZs7.mjs +1222 -0
  743. package/dist/registry-CkuPoZs7.mjs.map +1 -0
  744. package/dist/relation-XTAtOpJO.mjs +334 -0
  745. package/dist/relation-XTAtOpJO.mjs.map +1 -0
  746. package/dist/relations-B4w-G5U9.mjs +309 -0
  747. package/dist/relations-B4w-G5U9.mjs.map +1 -0
  748. package/dist/relations-O63JWBRj.mjs +403 -0
  749. package/dist/relations-O63JWBRj.mjs.map +1 -0
  750. package/dist/request-cache-DaMhSQdx.mjs +104 -0
  751. package/dist/request-cache-DaMhSQdx.mjs.map +1 -0
  752. package/dist/request-context.d.mts +1 -1
  753. package/dist/request-meta-C8yl_sIs.mjs +141 -0
  754. package/dist/request-meta-C8yl_sIs.mjs.map +1 -0
  755. package/dist/resolve-BJIS8wKr.mjs +199 -0
  756. package/dist/resolve-BJIS8wKr.mjs.map +1 -0
  757. package/dist/route-wire-D66L2oaZ.mjs +197 -0
  758. package/dist/route-wire-D66L2oaZ.mjs.map +1 -0
  759. package/dist/routes-DYsTe-oR.mjs +321 -0
  760. package/dist/routes-DYsTe-oR.mjs.map +1 -0
  761. package/dist/runner-3gfxRsJG.d.mts +68 -0
  762. package/dist/runner-3gfxRsJG.d.mts.map +1 -0
  763. package/dist/runner-ClrleR8A.mjs +5502 -0
  764. package/dist/runner-ClrleR8A.mjs.map +1 -0
  765. package/dist/runtime.d.mts +13 -11
  766. package/dist/runtime.d.mts.map +1 -1
  767. package/dist/runtime.mjs +6 -5
  768. package/dist/runtime.mjs.map +1 -1
  769. package/dist/schema-CPhPM9Do.mjs +420 -0
  770. package/dist/schema-CPhPM9Do.mjs.map +1 -0
  771. package/dist/schema-DEERRrKS.mjs +9 -0
  772. package/dist/schema-DEERRrKS.mjs.map +1 -0
  773. package/dist/scopes-Bn8_rCSt.mjs +27 -0
  774. package/dist/scopes-Bn8_rCSt.mjs.map +1 -0
  775. package/dist/search-lami_Ota.mjs +448 -0
  776. package/dist/search-lami_Ota.mjs.map +1 -0
  777. package/dist/secrets-DNgVgz_e.mjs +341 -0
  778. package/dist/secrets-DNgVgz_e.mjs.map +1 -0
  779. package/dist/sections-BIpd4Cxf.mjs +346 -0
  780. package/dist/sections-BIpd4Cxf.mjs.map +1 -0
  781. package/dist/seed/index.d.mts +2 -2
  782. package/dist/seed/index.mjs +35 -31
  783. package/dist/seo/index.d.mts +3 -3
  784. package/dist/seo/index.d.mts.map +1 -1
  785. package/dist/seo/index.mjs +27 -26
  786. package/dist/seo/index.mjs.map +1 -1
  787. package/dist/seo-BtU70b7l.mjs +114 -0
  788. package/dist/seo-BtU70b7l.mjs.map +1 -0
  789. package/dist/seo-_4qmazxz.mjs +133 -0
  790. package/dist/seo-_4qmazxz.mjs.map +1 -0
  791. package/dist/service-Bpy5iTX0.mjs +150 -0
  792. package/dist/service-Bpy5iTX0.mjs.map +1 -0
  793. package/dist/session-user-BQeS2Mrb.mjs +51 -0
  794. package/dist/session-user-BQeS2Mrb.mjs.map +1 -0
  795. package/dist/settings-DmroR53o.mjs +420 -0
  796. package/dist/settings-DmroR53o.mjs.map +1 -0
  797. package/dist/settings-g2F2a3Ub.mjs +51 -0
  798. package/dist/settings-g2F2a3Ub.mjs.map +1 -0
  799. package/dist/setup-complete-BrZaXpVV.mjs +26 -0
  800. package/dist/setup-complete-BrZaXpVV.mjs.map +1 -0
  801. package/dist/setup-nonce-Cb9-884O.mjs +25 -0
  802. package/dist/setup-nonce-Cb9-884O.mjs.map +1 -0
  803. package/dist/single-flight-cache-B5O2qhO1.mjs +104 -0
  804. package/dist/single-flight-cache-B5O2qhO1.mjs.map +1 -0
  805. package/dist/site-url-DjhYCaep.mjs +16 -0
  806. package/dist/site-url-DjhYCaep.mjs.map +1 -0
  807. package/dist/slugify-T5GHH42D.mjs +17 -0
  808. package/dist/slugify-T5GHH42D.mjs.map +1 -0
  809. package/dist/snapshot-C32Xuv3o.mjs +233 -0
  810. package/dist/snapshot-C32Xuv3o.mjs.map +1 -0
  811. package/dist/ssrf-Co1GGFZz.mjs +406 -0
  812. package/dist/ssrf-Co1GGFZz.mjs.map +1 -0
  813. package/dist/state-C7gCoiHr.mjs +153 -0
  814. package/dist/state-C7gCoiHr.mjs.map +1 -0
  815. package/dist/status-DLoBmcDz.mjs +30 -0
  816. package/dist/status-DLoBmcDz.mjs.map +1 -0
  817. package/dist/storage/local.d.mts +1 -1
  818. package/dist/storage/local.mjs +1 -1
  819. package/dist/storage/s3.d.mts +1 -1
  820. package/dist/storage/s3.mjs +1 -1
  821. package/dist/storage-query-CPctdMKX.d.mts +1519 -0
  822. package/dist/storage-query-CPctdMKX.d.mts.map +1 -0
  823. package/dist/target-CUKlGrXb.mjs +27 -0
  824. package/dist/target-CUKlGrXb.mjs.map +1 -0
  825. package/dist/taxonomies-BpqpXJUE.mjs +707 -0
  826. package/dist/taxonomies-BpqpXJUE.mjs.map +1 -0
  827. package/dist/taxonomies-ClCo4IGO.mjs +899 -0
  828. package/dist/taxonomies-ClCo4IGO.mjs.map +1 -0
  829. package/dist/taxonomy-Dj1vpw5E.mjs +508 -0
  830. package/dist/taxonomy-Dj1vpw5E.mjs.map +1 -0
  831. package/dist/tokens-Ns02GAma.mjs +171 -0
  832. package/dist/tokens-Ns02GAma.mjs.map +1 -0
  833. package/dist/transaction-BcJO4Tmc.mjs +29 -0
  834. package/dist/transaction-BcJO4Tmc.mjs.map +1 -0
  835. package/dist/transport-B8P1xsqk.mjs +136 -0
  836. package/dist/transport-B8P1xsqk.mjs.map +1 -0
  837. package/dist/transport-BLHZZcD_.d.mts +42 -0
  838. package/dist/transport-BLHZZcD_.d.mts.map +1 -0
  839. package/dist/trusted-proxy-Cg7SuD15.mjs +51 -0
  840. package/dist/trusted-proxy-Cg7SuD15.mjs.map +1 -0
  841. package/dist/turnstile-DWCSh_Qc.mjs +53 -0
  842. package/dist/turnstile-DWCSh_Qc.mjs.map +1 -0
  843. package/dist/types-B3RkqvDW.mjs +156 -0
  844. package/dist/types-B3RkqvDW.mjs.map +1 -0
  845. package/dist/types-BkUg2yHx.mjs +92 -0
  846. package/dist/types-BkUg2yHx.mjs.map +1 -0
  847. package/dist/types-BtuppOTV.mjs +16 -0
  848. package/dist/types-BtuppOTV.mjs.map +1 -0
  849. package/dist/types-CCR3ivXE.d.mts +363 -0
  850. package/dist/types-CCR3ivXE.d.mts.map +1 -0
  851. package/dist/types-CSHgU_-_.mjs +18 -0
  852. package/dist/types-CSHgU_-_.mjs.map +1 -0
  853. package/dist/types-CbwqGOXm.d.mts +766 -0
  854. package/dist/types-CbwqGOXm.d.mts.map +1 -0
  855. package/dist/types-D4RGIc2I.d.mts +198 -0
  856. package/dist/types-D4RGIc2I.d.mts.map +1 -0
  857. package/dist/types-DEHidMEk.d.mts +1637 -0
  858. package/dist/types-DEHidMEk.d.mts.map +1 -0
  859. package/dist/types-DQeU2SR7.d.mts +279 -0
  860. package/dist/types-DQeU2SR7.d.mts.map +1 -0
  861. package/dist/types-DxQWoQLA.d.mts +264 -0
  862. package/dist/types-DxQWoQLA.d.mts.map +1 -0
  863. package/dist/types-FBBnGZ2Y.d.mts +198 -0
  864. package/dist/types-FBBnGZ2Y.d.mts.map +1 -0
  865. package/dist/types-ZCnlropY.mjs +69 -0
  866. package/dist/types-ZCnlropY.mjs.map +1 -0
  867. package/dist/types-_Qtyawiy.d.mts +124 -0
  868. package/dist/types-_Qtyawiy.d.mts.map +1 -0
  869. package/dist/types-gC6FAoa_.d.mts +75 -0
  870. package/dist/types-gC6FAoa_.d.mts.map +1 -0
  871. package/dist/types-k--LneIF.mjs +22 -0
  872. package/dist/types-k--LneIF.mjs.map +1 -0
  873. package/dist/upload-attempts-2xdnoKGe.mjs +27 -0
  874. package/dist/upload-attempts-2xdnoKGe.mjs.map +1 -0
  875. package/dist/url-pattern-3m3reMzr.mjs +33 -0
  876. package/dist/url-pattern-3m3reMzr.mjs.map +1 -0
  877. package/dist/user-DroRntkx.mjs +171 -0
  878. package/dist/user-DroRntkx.mjs.map +1 -0
  879. package/dist/utils-CC2oNGV8.mjs +435 -0
  880. package/dist/utils-CC2oNGV8.mjs.map +1 -0
  881. package/dist/validate-BCP9HNDn.mjs +384 -0
  882. package/dist/validate-BCP9HNDn.mjs.map +1 -0
  883. package/dist/validate-CyQ7I3xF.d.mts +410 -0
  884. package/dist/validate-CyQ7I3xF.d.mts.map +1 -0
  885. package/dist/validate-DANX1-Qi.mjs +120 -0
  886. package/dist/validate-DANX1-Qi.mjs.map +1 -0
  887. package/dist/validation-DBy6WF94.mjs +216 -0
  888. package/dist/validation-DBy6WF94.mjs.map +1 -0
  889. package/dist/version-B57E4Uo7.mjs +7 -0
  890. package/dist/version-B57E4Uo7.mjs.map +1 -0
  891. package/dist/widgets-wQ7Xcgq8.mjs +126 -0
  892. package/dist/widgets-wQ7Xcgq8.mjs.map +1 -0
  893. package/dist/wxr-taxonomies-DIHfvEDt.mjs +406 -0
  894. package/dist/wxr-taxonomies-DIHfvEDt.mjs.map +1 -0
  895. package/dist/wxr-taxonomies-DU2ZSiGc.d.mts +34 -0
  896. package/dist/wxr-taxonomies-DU2ZSiGc.d.mts.map +1 -0
  897. package/dist/zod-generator-D_yHIWfs.mjs +329 -0
  898. package/dist/zod-generator-D_yHIWfs.mjs.map +1 -0
  899. package/package.json +39 -12
  900. package/src/api/errors.ts +23 -0
  901. package/src/api/handlers/backup.ts +11 -5
  902. package/src/api/handlers/content.ts +226 -85
  903. package/src/api/handlers/dashboard.ts +31 -1
  904. package/src/api/handlers/entry-lock.ts +206 -0
  905. package/src/api/handlers/index.ts +3 -0
  906. package/src/api/handlers/manifest.ts +5 -6
  907. package/src/api/handlers/marketplace.ts +126 -34
  908. package/src/api/handlers/media-upload.ts +31 -4
  909. package/src/api/handlers/menus.ts +9 -0
  910. package/src/api/handlers/plugin-settings.ts +35 -3
  911. package/src/api/handlers/redirects.ts +221 -138
  912. package/src/api/handlers/registry.ts +75 -29
  913. package/src/api/handlers/revision.ts +16 -27
  914. package/src/api/handlers/seo.ts +10 -1
  915. package/src/api/handlers/snapshot.ts +87 -72
  916. package/src/api/handlers/taxonomies.ts +79 -5
  917. package/src/api/handlers/validation.ts +120 -19
  918. package/src/api/openapi/document.ts +133 -11
  919. package/src/api/schemas/content.ts +32 -12
  920. package/src/api/schemas/entry-lock.ts +57 -0
  921. package/src/api/schemas/index.ts +1 -0
  922. package/src/api/schemas/schema.ts +10 -1
  923. package/src/api/schemas/search.ts +4 -0
  924. package/src/api/types.ts +4 -0
  925. package/src/astro/integration/index.ts +22 -6
  926. package/src/astro/integration/routes.ts +89 -0
  927. package/src/astro/integration/runtime.ts +40 -24
  928. package/src/astro/integration/virtual-modules.ts +4 -0
  929. package/src/astro/integration/vite-config.ts +31 -0
  930. package/src/astro/middleware/auth.ts +25 -4
  931. package/src/astro/middleware/request-context.ts +28 -10
  932. package/src/astro/middleware.ts +33 -1
  933. package/src/astro/prefetch.ts +2 -2
  934. package/src/astro/routes/api/admin/comments/[id]/status.ts +22 -58
  935. package/src/astro/routes/api/admin/plugins/[id]/disable.ts +2 -15
  936. package/src/astro/routes/api/admin/plugins/[id]/enable.ts +2 -25
  937. package/src/astro/routes/api/admin/plugins/[id]/uninstall.ts +1 -0
  938. package/src/astro/routes/api/admin/plugins/[id]/update.ts +23 -4
  939. package/src/astro/routes/api/admin/plugins/marketplace/[id]/install.ts +12 -2
  940. package/src/astro/routes/api/admin/plugins/registry/[id]/uninstall.ts +1 -0
  941. package/src/astro/routes/api/admin/plugins/registry/[id]/update.ts +29 -10
  942. package/src/astro/routes/api/admin/plugins/registry/artifact.ts +8 -2
  943. package/src/astro/routes/api/admin/plugins/registry/install.ts +15 -4
  944. package/src/astro/routes/api/admin/plugins/registry/verify.ts +2 -1
  945. package/src/astro/routes/api/admin/plugins/updates.ts +6 -1
  946. package/src/astro/routes/api/admin/scheduled-policy-rejections/[collection]/[id].ts +34 -0
  947. package/src/astro/routes/api/comments/[collection]/[contentId]/index.ts +4 -259
  948. package/src/astro/routes/api/content/[collection]/[id]/discard-draft.ts +10 -0
  949. package/src/astro/routes/api/content/[collection]/[id]/lock.ts +133 -0
  950. package/src/astro/routes/api/content/[collection]/[id]/plugin-extensions/[pluginId]/[kind]/[extensionId].ts +29 -0
  951. package/src/astro/routes/api/content/[collection]/[id]/publish.ts +21 -4
  952. package/src/astro/routes/api/content/[collection]/[id]/schedule.ts +30 -1
  953. package/src/astro/routes/api/content/[collection]/[id]/unpublish.ts +15 -1
  954. package/src/astro/routes/api/content/[collection]/[id].ts +27 -2
  955. package/src/astro/routes/api/content/[collection]/index.ts +3 -0
  956. package/src/astro/routes/api/health.ts +23 -0
  957. package/src/astro/routes/api/manifest.ts +14 -4
  958. package/src/astro/routes/api/mcp.ts +2 -1
  959. package/src/astro/routes/api/media/asset/[id]/[filename].ts +50 -0
  960. package/src/astro/routes/api/plugins/[pluginId]/[...path].ts +13 -81
  961. package/src/astro/routes/api/redirects/[id].ts +0 -3
  962. package/src/astro/routes/api/redirects/index.ts +0 -2
  963. package/src/astro/routes/api/search/index.ts +1 -0
  964. package/src/astro/routes/api/visual-editing/action-token.ts +36 -0
  965. package/src/astro/routes/api/visual-editing/content/[collection]/[id]/publish.ts +32 -0
  966. package/src/astro/routes/api/visual-editing/toolbar-labels.ts +16 -0
  967. package/src/astro/routes/sitemap-[collection].xml.ts +11 -4
  968. package/src/astro/types.ts +83 -12
  969. package/src/cli/commands/bundle-utils.ts +19 -19
  970. package/src/cli/commands/bundle.ts +9 -6
  971. package/src/cli/commands/content.ts +32 -6
  972. package/src/cli/commands/doctor.ts +25 -0
  973. package/src/cli/commands/export-seed.ts +195 -56
  974. package/src/cli/commands/migrate.ts +71 -23
  975. package/src/cli/commands/publish.ts +2 -2
  976. package/src/client/index.ts +34 -7
  977. package/src/comments/public-submission.ts +246 -0
  978. package/src/comments/service.ts +59 -12
  979. package/src/components/EmDashBodyEnd.astro +4 -1
  980. package/src/components/EmDashBodyStart.astro +4 -1
  981. package/src/components/EmDashHead.astro +36 -16
  982. package/src/components/Gallery.astro +18 -4
  983. package/src/components/InlineEditor.astro +3 -1
  984. package/src/components/InlinePortableTextEditor.tsx +106 -11
  985. package/src/components/PortableText.astro +4 -0
  986. package/src/components/Table.astro +147 -62
  987. package/src/components/widgets/Archives.astro +6 -5
  988. package/src/config/errors.ts +13 -0
  989. package/src/config/secrets.ts +25 -11
  990. package/src/content/converters/portable-text-to-prosemirror.ts +26 -2
  991. package/src/content/converters/prosemirror-to-portable-text.ts +35 -6
  992. package/src/content/converters/types.ts +10 -0
  993. package/src/content/known-fields.ts +44 -0
  994. package/src/database/connection.ts +5 -1
  995. package/src/database/content-datetime.ts +123 -0
  996. package/src/database/datetime-storage.ts +452 -0
  997. package/src/database/dialect-helpers.ts +161 -1
  998. package/src/database/migration-lock.ts +140 -0
  999. package/src/database/migrations/075_entry_edit_locks.ts +44 -0
  1000. package/src/database/migrations/076_collection_nav_group.ts +22 -0
  1001. package/src/database/migrations/077_plugin_storage_revisions.ts +89 -0
  1002. package/src/database/migrations/078_menu_item_translation_groups.ts +15 -0
  1003. package/src/database/migrations/079_datetime_normalization.ts +13 -0
  1004. package/src/database/migrations/080_content_translation_locale_unique.ts +88 -0
  1005. package/src/database/migrations/081_redirect_write_guards.ts +257 -0
  1006. package/src/database/migrations/082_taxonomy_translation_locale_unique.ts +49 -0
  1007. package/src/database/migrations/runner.ts +63 -15
  1008. package/src/database/pg-migration-lock.ts +2 -2
  1009. package/src/database/repositories/byline.ts +9 -0
  1010. package/src/database/repositories/comment.ts +86 -0
  1011. package/src/database/repositories/content.ts +560 -69
  1012. package/src/database/repositories/entry-locks.ts +257 -0
  1013. package/src/database/repositories/media.ts +35 -4
  1014. package/src/database/repositories/menu.ts +1 -0
  1015. package/src/database/repositories/options.ts +113 -7
  1016. package/src/database/repositories/plugin-storage.ts +159 -0
  1017. package/src/database/repositories/redirect.ts +262 -56
  1018. package/src/database/repositories/revision.ts +116 -17
  1019. package/src/database/repositories/taxonomy.ts +42 -0
  1020. package/src/database/repositories/types.ts +5 -0
  1021. package/src/database/types.ts +26 -1
  1022. package/src/datetime-normalization.ts +311 -0
  1023. package/src/db/node-sqlite-compat.ts +3 -2
  1024. package/src/emdash-runtime.ts +1994 -424
  1025. package/src/fields/image.ts +2 -0
  1026. package/src/i18n/config.ts +6 -6
  1027. package/src/i18n/resolve.ts +98 -15
  1028. package/src/index.ts +101 -0
  1029. package/src/loader.ts +49 -4
  1030. package/src/mcp/server.ts +216 -68
  1031. package/src/media/responsive.ts +23 -0
  1032. package/src/media/usage/content-refresh.ts +2 -1
  1033. package/src/media/usage/extractor.ts +50 -15
  1034. package/src/media/usage/types.ts +1 -1
  1035. package/src/menus/index.ts +64 -35
  1036. package/src/migrations/direct-executor.ts +40 -2
  1037. package/src/migrations/index.ts +1 -0
  1038. package/src/migrations/protocol.ts +11 -1
  1039. package/src/page/seo-contributions.ts +78 -1
  1040. package/src/page/seo-panel.ts +47 -0
  1041. package/src/plugin-test-runtime.ts +17 -0
  1042. package/src/plugin-types.ts +128 -21
  1043. package/src/plugins/adapt-sandbox-entry.ts +34 -27
  1044. package/src/plugins/conditional-storage.ts +30 -0
  1045. package/src/plugins/content-access.ts +170 -0
  1046. package/src/plugins/content-policy.ts +74 -0
  1047. package/src/plugins/context.ts +790 -166
  1048. package/src/plugins/cron.ts +18 -10
  1049. package/src/plugins/define-plugin.ts +55 -54
  1050. package/src/plugins/editor-draft.ts +257 -0
  1051. package/src/plugins/hooks.ts +136 -3
  1052. package/src/plugins/host.ts +29 -0
  1053. package/src/plugins/http-route-dispatch.ts +389 -0
  1054. package/src/plugins/http-wire.ts +180 -0
  1055. package/src/plugins/index.ts +97 -3
  1056. package/src/plugins/install-finalization.ts +77 -0
  1057. package/src/plugins/lifecycle.ts +47 -0
  1058. package/src/plugins/manager.ts +5 -2
  1059. package/src/plugins/manifest-schema.ts +314 -58
  1060. package/src/plugins/media.ts +166 -0
  1061. package/src/plugins/request-meta.ts +12 -2
  1062. package/src/plugins/route-wire.ts +304 -0
  1063. package/src/plugins/routes.ts +38 -5
  1064. package/src/plugins/sandbox/index.ts +4 -0
  1065. package/src/plugins/sandbox/proxy.ts +129 -0
  1066. package/src/plugins/sandbox/types.ts +83 -7
  1067. package/src/plugins/secret-redactor.ts +65 -0
  1068. package/src/plugins/settings.ts +303 -0
  1069. package/src/plugins/state.ts +26 -0
  1070. package/src/plugins/storage-query.ts +45 -0
  1071. package/src/plugins/storage-update.ts +96 -0
  1072. package/src/plugins/types.ts +602 -15
  1073. package/src/query.ts +84 -4
  1074. package/src/registry/authoritative-records.ts +26 -0
  1075. package/src/registry/config.ts +182 -31
  1076. package/src/registry/testing.ts +100 -0
  1077. package/src/registry/types.ts +12 -70
  1078. package/src/scheduled-publish.ts +70 -3
  1079. package/src/schema/collection-slugs-cache.ts +157 -0
  1080. package/src/schema/index.ts +1 -0
  1081. package/src/schema/registry.ts +64 -1
  1082. package/src/schema/types.ts +32 -6
  1083. package/src/schema/zod-generator.ts +5 -13
  1084. package/src/search/fts-manager.ts +3 -3
  1085. package/src/search/query.ts +32 -5
  1086. package/src/search/types.ts +8 -0
  1087. package/src/security/ssrf.ts +167 -141
  1088. package/src/seed/apply.ts +41 -3
  1089. package/src/seed/types.ts +13 -3
  1090. package/src/seed/validate.ts +18 -1
  1091. package/src/seo/hreflang.ts +10 -6
  1092. package/src/seo/index.ts +5 -10
  1093. package/src/seo/media-url.ts +26 -0
  1094. package/src/settings/index.ts +53 -11
  1095. package/src/taxonomies/term-counts.ts +22 -5
  1096. package/src/visual-editing/action-token.ts +31 -0
  1097. package/src/visual-editing/toolbar-bootstrap.ts +31 -6
  1098. package/src/visual-editing/toolbar.ts +103 -12
  1099. package/src/widgets/archives.ts +10 -9
  1100. package/src/widgets/index.ts +11 -1
  1101. package/dist/activation-K0kGBWuJ.mjs +0 -382
  1102. package/dist/activation-K0kGBWuJ.mjs.map +0 -1
  1103. package/dist/adapters-BDQwg236.d.mts +0 -171
  1104. package/dist/adapters-BDQwg236.d.mts.map +0 -1
  1105. package/dist/after-CBU2vkoO.mjs +0 -96
  1106. package/dist/after-CBU2vkoO.mjs.map +0 -1
  1107. package/dist/allowed-origins-BGglilcs.mjs +0 -116
  1108. package/dist/allowed-origins-BGglilcs.mjs.map +0 -1
  1109. package/dist/api-Dz6rgoa3.mjs +0 -10040
  1110. package/dist/api-Dz6rgoa3.mjs.map +0 -1
  1111. package/dist/api-tokens-BSsQACNe.mjs +0 -163
  1112. package/dist/api-tokens-BSsQACNe.mjs.map +0 -1
  1113. package/dist/apply-B4SIOxR1.mjs +0 -980
  1114. package/dist/apply-B4SIOxR1.mjs.map +0 -1
  1115. package/dist/authorize-Bkf_UHhD.mjs +0 -40
  1116. package/dist/authorize-Bkf_UHhD.mjs.map +0 -1
  1117. package/dist/backup-rwVAl9NI.mjs +0 -241
  1118. package/dist/backup-rwVAl9NI.mjs.map +0 -1
  1119. package/dist/base64-CvLhUKQv.mjs +0 -63
  1120. package/dist/base64-CvLhUKQv.mjs.map +0 -1
  1121. package/dist/bundle-C8S2Zl6U.mjs +0 -663
  1122. package/dist/bundle-C8S2Zl6U.mjs.map +0 -1
  1123. package/dist/byline-DuhF7NWl.mjs +0 -902
  1124. package/dist/byline-DuhF7NWl.mjs.map +0 -1
  1125. package/dist/byline-fields-BovY4KYM.mjs +0 -123
  1126. package/dist/byline-fields-BovY4KYM.mjs.map +0 -1
  1127. package/dist/byline-registry-Bpu9-MVs.mjs +0 -406
  1128. package/dist/byline-registry-Bpu9-MVs.mjs.map +0 -1
  1129. package/dist/bylines-CJ5nd6Lw.mjs +0 -232
  1130. package/dist/bylines-CJ5nd6Lw.mjs.map +0 -1
  1131. package/dist/bylines-RwBAeOF1.mjs +0 -214
  1132. package/dist/bylines-RwBAeOF1.mjs.map +0 -1
  1133. package/dist/cache-BF5Kvn59.mjs +0 -108
  1134. package/dist/cache-BF5Kvn59.mjs.map +0 -1
  1135. package/dist/capture-triggers-CNW1q3HK.mjs +0 -362
  1136. package/dist/capture-triggers-CNW1q3HK.mjs.map +0 -1
  1137. package/dist/challenge-store-DQN_Yrck.mjs +0 -51
  1138. package/dist/challenge-store-DQN_Yrck.mjs.map +0 -1
  1139. package/dist/chrome-tags-D8fiZG94.mjs +0 -24
  1140. package/dist/chrome-tags-D8fiZG94.mjs.map +0 -1
  1141. package/dist/chunks-C4szrD8o.mjs +0 -25
  1142. package/dist/chunks-C4szrD8o.mjs.map +0 -1
  1143. package/dist/collection-deletion-Bj07NHbj.mjs +0 -436
  1144. package/dist/collection-deletion-Bj07NHbj.mjs.map +0 -1
  1145. package/dist/comment-reaction-BhrvSHml.mjs +0 -85
  1146. package/dist/comment-reaction-BhrvSHml.mjs.map +0 -1
  1147. package/dist/comment-vxOzWbZN.mjs +0 -255
  1148. package/dist/comment-vxOzWbZN.mjs.map +0 -1
  1149. package/dist/comments-Ct4ensnf.mjs +0 -204
  1150. package/dist/comments-Ct4ensnf.mjs.map +0 -1
  1151. package/dist/components-DJbo1z0S.mjs +0 -108
  1152. package/dist/components-DJbo1z0S.mjs.map +0 -1
  1153. package/dist/config-B9eZ340f.d.mts +0 -34
  1154. package/dist/config-B9eZ340f.d.mts.map +0 -1
  1155. package/dist/config-C3EBstHi.mjs +0 -72
  1156. package/dist/config-C3EBstHi.mjs.map +0 -1
  1157. package/dist/config-it29yDLA.mjs +0 -1163
  1158. package/dist/config-it29yDLA.mjs.map +0 -1
  1159. package/dist/content-DjvM0T92.mjs +0 -1725
  1160. package/dist/content-DjvM0T92.mjs.map +0 -1
  1161. package/dist/content-list-query-Btqd4uV2.d.mts +0 -26
  1162. package/dist/content-list-query-Btqd4uV2.d.mts.map +0 -1
  1163. package/dist/content-refresh-Bwp-8yGy.mjs +0 -3588
  1164. package/dist/content-refresh-Bwp-8yGy.mjs.map +0 -1
  1165. package/dist/content-repair-Czdp7jz5.mjs +0 -440
  1166. package/dist/content-repair-Czdp7jz5.mjs.map +0 -1
  1167. package/dist/context-CX6gxOLW.mjs +0 -1068
  1168. package/dist/context-CX6gxOLW.mjs.map +0 -1
  1169. package/dist/cron-C6o7VppJ.mjs +0 -277
  1170. package/dist/cron-C6o7VppJ.mjs.map +0 -1
  1171. package/dist/dashboard-C2kTeeRI.mjs +0 -140
  1172. package/dist/dashboard-C2kTeeRI.mjs.map +0 -1
  1173. package/dist/db-errors-Cl-sKYTm.mjs +0 -55
  1174. package/dist/db-errors-Cl-sKYTm.mjs.map +0 -1
  1175. package/dist/default-Clra32mw.mjs +0 -81
  1176. package/dist/default-Clra32mw.mjs.map +0 -1
  1177. package/dist/deferred-tasks-CvDETTJO.d.mts +0 -9
  1178. package/dist/deferred-tasks-CvDETTJO.d.mts.map +0 -1
  1179. package/dist/dev-typegen-DzOPfsNj.mjs +0 -29
  1180. package/dist/dev-typegen-DzOPfsNj.mjs.map +0 -1
  1181. package/dist/device-flow-D2oCWvLJ.mjs +0 -466
  1182. package/dist/device-flow-D2oCWvLJ.mjs.map +0 -1
  1183. package/dist/dialect-helpers-BSbfaO3F.mjs +0 -202
  1184. package/dist/dialect-helpers-BSbfaO3F.mjs.map +0 -1
  1185. package/dist/direct-executor-Bfa5_ToE.mjs +0 -85
  1186. package/dist/direct-executor-Bfa5_ToE.mjs.map +0 -1
  1187. package/dist/dist-89xCrGqi.mjs +0 -810
  1188. package/dist/dist-89xCrGqi.mjs.map +0 -1
  1189. package/dist/email-console-Dzb6uGYa.mjs +0 -50
  1190. package/dist/email-console-Dzb6uGYa.mjs.map +0 -1
  1191. package/dist/enrich-BX0IDp4z.mjs +0 -194
  1192. package/dist/enrich-BX0IDp4z.mjs.map +0 -1
  1193. package/dist/error-DFrQjppn.mjs +0 -90
  1194. package/dist/error-DFrQjppn.mjs.map +0 -1
  1195. package/dist/errors-DsVoDUjJ.mjs +0 -427
  1196. package/dist/errors-DsVoDUjJ.mjs.map +0 -1
  1197. package/dist/escape-HmHTC1Is.mjs +0 -9
  1198. package/dist/escape-HmHTC1Is.mjs.map +0 -1
  1199. package/dist/field-defs-cache-BM4SIRqH.mjs +0 -77
  1200. package/dist/field-defs-cache-BM4SIRqH.mjs.map +0 -1
  1201. package/dist/focal-point-BeWFo6Xx.mjs +0 -23
  1202. package/dist/focal-point-BeWFo6Xx.mjs.map +0 -1
  1203. package/dist/fts-manager-Do1BlW2r.mjs +0 -413
  1204. package/dist/fts-manager-Do1BlW2r.mjs.map +0 -1
  1205. package/dist/hash-3JJPlHF2.mjs +0 -37
  1206. package/dist/hash-3JJPlHF2.mjs.map +0 -1
  1207. package/dist/hook-result-DCh2WUpe.d.mts +0 -31
  1208. package/dist/hook-result-DCh2WUpe.d.mts.map +0 -1
  1209. package/dist/hreflang-B6hbAuuO.d.mts +0 -48
  1210. package/dist/hreflang-B6hbAuuO.d.mts.map +0 -1
  1211. package/dist/hreflang-DQbPZliA.mjs +0 -102
  1212. package/dist/hreflang-DQbPZliA.mjs.map +0 -1
  1213. package/dist/identity-DksvEazf.mjs +0 -35
  1214. package/dist/identity-DksvEazf.mjs.map +0 -1
  1215. package/dist/import-CJpaBBBT.mjs +0 -2020
  1216. package/dist/import-CJpaBBBT.mjs.map +0 -1
  1217. package/dist/index-BJNMCWmu.d.mts +0 -6562
  1218. package/dist/index-BJNMCWmu.d.mts.map +0 -1
  1219. package/dist/index-Du8K7bWa.d.mts +0 -278
  1220. package/dist/index-Du8K7bWa.d.mts.map +0 -1
  1221. package/dist/init-lock-DJkX6Hto.mjs +0 -56
  1222. package/dist/init-lock-DJkX6Hto.mjs.map +0 -1
  1223. package/dist/load-CawHjTOH.mjs +0 -28
  1224. package/dist/load-CawHjTOH.mjs.map +0 -1
  1225. package/dist/loader-Z8vl7zTq.mjs +0 -966
  1226. package/dist/loader-Z8vl7zTq.mjs.map +0 -1
  1227. package/dist/manifest-builder-COtzuca2.mjs +0 -189
  1228. package/dist/manifest-builder-COtzuca2.mjs.map +0 -1
  1229. package/dist/manifest-schema-BNWwR8Vd.mjs +0 -301
  1230. package/dist/manifest-schema-BNWwR8Vd.mjs.map +0 -1
  1231. package/dist/media-BBm8Wg3f.mjs +0 -318
  1232. package/dist/media-BBm8Wg3f.mjs.map +0 -1
  1233. package/dist/media-BHjus86Y.mjs +0 -464
  1234. package/dist/media-BHjus86Y.mjs.map +0 -1
  1235. package/dist/media-allowlist-CoTBWoDp.mjs +0 -44
  1236. package/dist/media-allowlist-CoTBWoDp.mjs.map +0 -1
  1237. package/dist/media-folders-BGkATs8n.mjs +0 -210
  1238. package/dist/media-folders-BGkATs8n.mjs.map +0 -1
  1239. package/dist/media-upload-BCidR-EY.mjs +0 -147
  1240. package/dist/media-upload-BCidR-EY.mjs.map +0 -1
  1241. package/dist/media-url-DHoPr0hq.mjs +0 -26
  1242. package/dist/media-url-DHoPr0hq.mjs.map +0 -1
  1243. package/dist/media-usage-CdY5jhSR.mjs +0 -1833
  1244. package/dist/media-usage-CdY5jhSR.mjs.map +0 -1
  1245. package/dist/media-usage-activation-BgeMtK5C.mjs +0 -78
  1246. package/dist/media-usage-activation-BgeMtK5C.mjs.map +0 -1
  1247. package/dist/media-usage-work-CnGCdHxx.mjs +0 -152
  1248. package/dist/media-usage-work-CnGCdHxx.mjs.map +0 -1
  1249. package/dist/media-usage-work-D6D9sMCA.mjs +0 -586
  1250. package/dist/media-usage-work-D6D9sMCA.mjs.map +0 -1
  1251. package/dist/media-usage-write-fence-hjeD4u7s.mjs +0 -42
  1252. package/dist/media-usage-write-fence-hjeD4u7s.mjs.map +0 -1
  1253. package/dist/menus-6qSwTNxG.mjs +0 -4010
  1254. package/dist/menus-6qSwTNxG.mjs.map +0 -1
  1255. package/dist/menus-uvPLXMZf.mjs +0 -744
  1256. package/dist/menus-uvPLXMZf.mjs.map +0 -1
  1257. package/dist/mime-CUIG6x84.mjs +0 -36
  1258. package/dist/mime-CUIG6x84.mjs.map +0 -1
  1259. package/dist/mode-DN_WneRx.mjs +0 -23
  1260. package/dist/mode-DN_WneRx.mjs.map +0 -1
  1261. package/dist/node-sqlite-compat-BuJXIeMz.mjs +0 -46
  1262. package/dist/node-sqlite-compat-BuJXIeMz.mjs.map +0 -1
  1263. package/dist/normalize-C2xNjTSG.mjs +0 -191
  1264. package/dist/normalize-C2xNjTSG.mjs.map +0 -1
  1265. package/dist/oauth-authorization-Dj6Kwc21.mjs +0 -274
  1266. package/dist/oauth-authorization-Dj6Kwc21.mjs.map +0 -1
  1267. package/dist/oauth-clients-FD7I0J8m.mjs +0 -266
  1268. package/dist/oauth-clients-FD7I0J8m.mjs.map +0 -1
  1269. package/dist/oauth-state-store-DkmDOmHs.mjs +0 -50
  1270. package/dist/oauth-state-store-DkmDOmHs.mjs.map +0 -1
  1271. package/dist/oauth-user-lookup-CvIwGpYd.mjs +0 -26
  1272. package/dist/oauth-user-lookup-CvIwGpYd.mjs.map +0 -1
  1273. package/dist/object-cache-DVKnyOfy.mjs +0 -534
  1274. package/dist/object-cache-DVKnyOfy.mjs.map +0 -1
  1275. package/dist/options-BHPeIbBd.mjs +0 -117
  1276. package/dist/options-BHPeIbBd.mjs.map +0 -1
  1277. package/dist/options-CYb4y7hM.d.mts +0 -221
  1278. package/dist/options-CYb4y7hM.d.mts.map +0 -1
  1279. package/dist/parse-Ckpg-Qfp.mjs +0 -81
  1280. package/dist/parse-Ckpg-Qfp.mjs.map +0 -1
  1281. package/dist/passkey-config-O_lj3y0k.mjs +0 -46
  1282. package/dist/passkey-config-O_lj3y0k.mjs.map +0 -1
  1283. package/dist/patterns-D9iDO3j8.mjs +0 -145
  1284. package/dist/patterns-D9iDO3j8.mjs.map +0 -1
  1285. package/dist/placeholder-4X9BrRrp.d.mts +0 -306
  1286. package/dist/placeholder-4X9BrRrp.d.mts.map +0 -1
  1287. package/dist/policy-Dhtwntrt.mjs +0 -45
  1288. package/dist/policy-Dhtwntrt.mjs.map +0 -1
  1289. package/dist/portable-text-U85hOafW.mjs +0 -286
  1290. package/dist/portable-text-U85hOafW.mjs.map +0 -1
  1291. package/dist/preview-B_vJLvf8.mjs +0 -107
  1292. package/dist/preview-B_vJLvf8.mjs.map +0 -1
  1293. package/dist/protocol-JdD2YhY9.d.mts +0 -52
  1294. package/dist/protocol-JdD2YhY9.d.mts.map +0 -1
  1295. package/dist/public-url-CarhZJgf.mjs +0 -101
  1296. package/dist/public-url-CarhZJgf.mjs.map +0 -1
  1297. package/dist/query-BZKZcG5b.mjs +0 -881
  1298. package/dist/query-BZKZcG5b.mjs.map +0 -1
  1299. package/dist/query-BndaFxxp.mjs +0 -41
  1300. package/dist/query-BndaFxxp.mjs.map +0 -1
  1301. package/dist/rate-limit-BZmATC6W.mjs +0 -120
  1302. package/dist/rate-limit-BZmATC6W.mjs.map +0 -1
  1303. package/dist/redirect-CZkbozu9.mjs +0 -313
  1304. package/dist/redirect-CZkbozu9.mjs.map +0 -1
  1305. package/dist/redirect-CzqnLxK-.mjs +0 -17
  1306. package/dist/redirect-CzqnLxK-.mjs.map +0 -1
  1307. package/dist/redirects-BLNOWQTn.mjs +0 -1238
  1308. package/dist/redirects-BLNOWQTn.mjs.map +0 -1
  1309. package/dist/redirects-CqzNM0KM.mjs +0 -579
  1310. package/dist/redirects-CqzNM0KM.mjs.map +0 -1
  1311. package/dist/registry-AZAsRsor.mjs +0 -1179
  1312. package/dist/registry-AZAsRsor.mjs.map +0 -1
  1313. package/dist/relation-04DfKRTO.mjs +0 -334
  1314. package/dist/relation-04DfKRTO.mjs.map +0 -1
  1315. package/dist/relations-C4htk5sb.mjs +0 -309
  1316. package/dist/relations-C4htk5sb.mjs.map +0 -1
  1317. package/dist/relations-CcFwDJdJ.mjs +0 -403
  1318. package/dist/relations-CcFwDJdJ.mjs.map +0 -1
  1319. package/dist/relations-DnRK4YIT.d.mts +0 -3354
  1320. package/dist/relations-DnRK4YIT.d.mts.map +0 -1
  1321. package/dist/request-cache-DH9zdCOD.mjs +0 -104
  1322. package/dist/request-cache-DH9zdCOD.mjs.map +0 -1
  1323. package/dist/request-meta-DYxLlnmz.mjs +0 -140
  1324. package/dist/request-meta-DYxLlnmz.mjs.map +0 -1
  1325. package/dist/resolve-prZ3mP7l.mjs +0 -143
  1326. package/dist/resolve-prZ3mP7l.mjs.map +0 -1
  1327. package/dist/runner-BLIDKpmA.mjs +0 -4676
  1328. package/dist/runner-BLIDKpmA.mjs.map +0 -1
  1329. package/dist/runner-YKfIMnaF.d.mts +0 -67
  1330. package/dist/runner-YKfIMnaF.d.mts.map +0 -1
  1331. package/dist/schema-CGnBeLiW.mjs +0 -9
  1332. package/dist/schema-CGnBeLiW.mjs.map +0 -1
  1333. package/dist/schema-DYr-Vd-L.mjs +0 -420
  1334. package/dist/schema-DYr-Vd-L.mjs.map +0 -1
  1335. package/dist/scopes-BhWvBavj.mjs +0 -27
  1336. package/dist/scopes-BhWvBavj.mjs.map +0 -1
  1337. package/dist/search-C-qDk4kx.mjs +0 -439
  1338. package/dist/search-C-qDk4kx.mjs.map +0 -1
  1339. package/dist/secrets-rEtHt-6z.mjs +0 -330
  1340. package/dist/secrets-rEtHt-6z.mjs.map +0 -1
  1341. package/dist/sections-B_nYvlwn.mjs +0 -346
  1342. package/dist/sections-B_nYvlwn.mjs.map +0 -1
  1343. package/dist/seo-926NRIgt.mjs +0 -133
  1344. package/dist/seo-926NRIgt.mjs.map +0 -1
  1345. package/dist/seo-CVWkdv6x.mjs +0 -113
  1346. package/dist/seo-CVWkdv6x.mjs.map +0 -1
  1347. package/dist/service-CJl3ZAYs.mjs +0 -195
  1348. package/dist/service-CJl3ZAYs.mjs.map +0 -1
  1349. package/dist/session-user-BlMgqCHS.mjs +0 -51
  1350. package/dist/session-user-BlMgqCHS.mjs.map +0 -1
  1351. package/dist/settings--wobrkkC.mjs +0 -258
  1352. package/dist/settings--wobrkkC.mjs.map +0 -1
  1353. package/dist/settings-Cwm6o2jY.mjs +0 -51
  1354. package/dist/settings-Cwm6o2jY.mjs.map +0 -1
  1355. package/dist/setup-complete-DQbClIN2.mjs +0 -26
  1356. package/dist/setup-complete-DQbClIN2.mjs.map +0 -1
  1357. package/dist/setup-nonce-DZCFS2sn.mjs +0 -25
  1358. package/dist/setup-nonce-DZCFS2sn.mjs.map +0 -1
  1359. package/dist/single-flight-cache-BPuGPdcN.mjs +0 -104
  1360. package/dist/single-flight-cache-BPuGPdcN.mjs.map +0 -1
  1361. package/dist/site-url-BrxA_E9H.mjs +0 -16
  1362. package/dist/site-url-BrxA_E9H.mjs.map +0 -1
  1363. package/dist/slugify-B994zkXC.mjs +0 -17
  1364. package/dist/slugify-B994zkXC.mjs.map +0 -1
  1365. package/dist/snapshot--OCDTqdb.mjs +0 -216
  1366. package/dist/snapshot--OCDTqdb.mjs.map +0 -1
  1367. package/dist/ssrf-5sIM5jzl.mjs +0 -349
  1368. package/dist/ssrf-5sIM5jzl.mjs.map +0 -1
  1369. package/dist/state-BpFVsJZB.mjs +0 -136
  1370. package/dist/state-BpFVsJZB.mjs.map +0 -1
  1371. package/dist/status-B777-dXz.mjs +0 -30
  1372. package/dist/status-B777-dXz.mjs.map +0 -1
  1373. package/dist/target-BmR0iTwz.mjs +0 -27
  1374. package/dist/target-BmR0iTwz.mjs.map +0 -1
  1375. package/dist/taxonomies-DkAkMupr.mjs +0 -837
  1376. package/dist/taxonomies-DkAkMupr.mjs.map +0 -1
  1377. package/dist/taxonomies-Wfy_Lg12.mjs +0 -698
  1378. package/dist/taxonomies-Wfy_Lg12.mjs.map +0 -1
  1379. package/dist/taxonomy-tJepplLL.mjs +0 -484
  1380. package/dist/taxonomy-tJepplLL.mjs.map +0 -1
  1381. package/dist/tokens-BCO1oruF.mjs +0 -171
  1382. package/dist/tokens-BCO1oruF.mjs.map +0 -1
  1383. package/dist/transaction-0KOpOyMu.mjs +0 -29
  1384. package/dist/transaction-0KOpOyMu.mjs.map +0 -1
  1385. package/dist/transport-Dr3qtwXC.mjs +0 -136
  1386. package/dist/transport-Dr3qtwXC.mjs.map +0 -1
  1387. package/dist/transport-xh6YKW2G.d.mts +0 -42
  1388. package/dist/transport-xh6YKW2G.d.mts.map +0 -1
  1389. package/dist/trusted-proxy-BR5F1Otp.mjs +0 -51
  1390. package/dist/trusted-proxy-BR5F1Otp.mjs.map +0 -1
  1391. package/dist/types-3qNFPlci.mjs +0 -16
  1392. package/dist/types-3qNFPlci.mjs.map +0 -1
  1393. package/dist/types-75KIqzL9.mjs +0 -142
  1394. package/dist/types-75KIqzL9.mjs.map +0 -1
  1395. package/dist/types-B6GrPic4.d.mts +0 -1335
  1396. package/dist/types-B6GrPic4.d.mts.map +0 -1
  1397. package/dist/types-BuHW4xDE.d.mts +0 -259
  1398. package/dist/types-BuHW4xDE.d.mts.map +0 -1
  1399. package/dist/types-C00oyCZp.d.mts +0 -198
  1400. package/dist/types-C00oyCZp.d.mts.map +0 -1
  1401. package/dist/types-CDtkNSFQ.d.mts +0 -75
  1402. package/dist/types-CDtkNSFQ.d.mts.map +0 -1
  1403. package/dist/types-CPeXo1wF.d.mts +0 -124
  1404. package/dist/types-CPeXo1wF.d.mts.map +0 -1
  1405. package/dist/types-CQPWhPxE.mjs +0 -92
  1406. package/dist/types-CQPWhPxE.mjs.map +0 -1
  1407. package/dist/types-CXFkwEGC.d.mts +0 -198
  1408. package/dist/types-CXFkwEGC.d.mts.map +0 -1
  1409. package/dist/types-DM3vioBY.mjs +0 -18
  1410. package/dist/types-DM3vioBY.mjs.map +0 -1
  1411. package/dist/types-DczELMop.d.mts +0 -363
  1412. package/dist/types-DczELMop.d.mts.map +0 -1
  1413. package/dist/types-DfuTR6dL.mjs +0 -3
  1414. package/dist/types-FV23hEoW.d.mts +0 -743
  1415. package/dist/types-FV23hEoW.d.mts.map +0 -1
  1416. package/dist/types-xDMtUFnO.d.mts +0 -257
  1417. package/dist/types-xDMtUFnO.d.mts.map +0 -1
  1418. package/dist/upload-attempts-BsqoQ1fn.mjs +0 -27
  1419. package/dist/upload-attempts-BsqoQ1fn.mjs.map +0 -1
  1420. package/dist/url-pattern-D4c2czpJ.mjs +0 -33
  1421. package/dist/url-pattern-D4c2czpJ.mjs.map +0 -1
  1422. package/dist/user-BTZ40aq6.mjs +0 -171
  1423. package/dist/user-BTZ40aq6.mjs.map +0 -1
  1424. package/dist/utils-BKvNjjhY.mjs +0 -435
  1425. package/dist/utils-BKvNjjhY.mjs.map +0 -1
  1426. package/dist/validate-BpwoDOgt.mjs +0 -120
  1427. package/dist/validate-BpwoDOgt.mjs.map +0 -1
  1428. package/dist/validate-DE_LRwo9.mjs +0 -379
  1429. package/dist/validate-DE_LRwo9.mjs.map +0 -1
  1430. package/dist/validate-DUP27OYD.d.mts +0 -400
  1431. package/dist/validate-DUP27OYD.d.mts.map +0 -1
  1432. package/dist/validation-BMImFJ11.mjs +0 -153
  1433. package/dist/validation-BMImFJ11.mjs.map +0 -1
  1434. package/dist/version-Bii3suaO.mjs +0 -7
  1435. package/dist/version-Bii3suaO.mjs.map +0 -1
  1436. package/dist/widgets-D3gJ10xU.mjs +0 -122
  1437. package/dist/widgets-D3gJ10xU.mjs.map +0 -1
  1438. package/dist/wxr-taxonomies-B2Og_6rU.d.mts +0 -34
  1439. package/dist/wxr-taxonomies-B2Og_6rU.d.mts.map +0 -1
  1440. package/dist/wxr-taxonomies-Cxngsjwo.mjs +0 -406
  1441. package/dist/wxr-taxonomies-Cxngsjwo.mjs.map +0 -1
  1442. package/dist/zod-generator-BuYSQJB7.mjs +0 -331
  1443. package/dist/zod-generator-BuYSQJB7.mjs.map +0 -1
  1444. /package/dist/{api-tokens-BfYts-sq.mjs → api-tokens-DS1VzN7_.mjs} +0 -0
  1445. /package/dist/{ssrf-Dg3cIT-b.mjs → ssrf-BRpTDMV6.mjs} +0 -0
@@ -1,1725 +0,0 @@
1
- import { c as __exportAll } from "./runner-BLIDKpmA.mjs";
2
- import { t as validateIdentifier } from "./validate-BpwoDOgt.mjs";
3
- import { c as invalidateCollectionCache } from "./object-cache-DVKnyOfy.mjs";
4
- import { c as isIndexableFieldType } from "./types-75KIqzL9.mjs";
5
- import { n as chunks, t as SQL_BATCH_SIZE } from "./chunks-C4szrD8o.mjs";
6
- import { n as isMissingTableError } from "./db-errors-Cl-sKYTm.mjs";
7
- import { n as slugify } from "./slugify-B994zkXC.mjs";
8
- import { a as ScheduledNotDueError, i as InvalidCursorError, n as ContentMutationConflictError, o as decodeCursor, r as EmDashValidationError, s as encodeCursor, t as ContentCollectionNotFoundError } from "./types-CQPWhPxE.mjs";
9
- import { sql } from "kysely";
10
- import { monotonicFactory, ulid } from "ulidx";
11
-
12
- //#region src/search/match.ts
13
- /**
14
- * FTS5 match-expression builder for structured (non-user-syntax) queries.
15
- *
16
- * Unlike `escapeQuery` in `query.ts` (which powers the public search API and
17
- * deliberately passes through FTS5 operators like AND/OR/NOT), this builder
18
- * treats the input as plain words: every term is double-quoted with interior
19
- * quotes escaped, so the result can never produce an FTS5 syntax error. Used
20
- * by the admin content-list filter, where the input is a filter box, not a
21
- * search-syntax field.
22
- */
23
- const WHITESPACE_RE = /\s+/;
24
- const DOUBLE_QUOTE_RE = /"/g;
25
- const GLOB_SPECIAL_RE = /[[\]*?]/g;
26
- /**
27
- * Build a prefix-matching FTS5 MATCH expression from free-form input.
28
- *
29
- * `hello wor` becomes `"hello"* "wor"*` — implicit AND with per-term prefix
30
- * matching. Returns `""` when the input contains no usable terms; callers
31
- * must fall back to their non-FTS path in that case.
32
- */
33
- function buildFtsPrefixMatch(input) {
34
- const terms = input.trim().split(WHITESPACE_RE).map((term) => term.replace(DOUBLE_QUOTE_RE, "\"\"")).filter((term) => term.length > 0);
35
- if (terms.length === 0) return "";
36
- return terms.map((term) => `"${term}"*`).join(" ");
37
- }
38
- /**
39
- * Build a GLOB prefix pattern from free-form input, treating GLOB
40
- * metacharacters (`* ? [ ]`) literally by wrapping each in a character
41
- * class (GLOB has no ESCAPE clause).
42
- *
43
- * GLOB (unlike default LIKE) is case-sensitive, so with a lowercased
44
- * pattern it matches slugs (lowercase by construction) while staying
45
- * servable by the ordinary BINARY-collated slug index — SQLite's GLOB
46
- * optimization turns a `prefix*` pattern into an index range scan.
47
- */
48
- function buildSlugGlobPrefix(input) {
49
- return `${input.trim().toLowerCase().replace(GLOB_SPECIAL_RE, (c) => `[${c}]`)}*`;
50
- }
51
-
52
- //#endregion
53
- //#region src/database/repositories/revision.ts
54
- const monotonic = monotonicFactory();
55
- /**
56
- * Revision repository for version history
57
- *
58
- * Each revision stores a JSON snapshot of the content at a point in time.
59
- * Used when collection has `supports: ["revisions"]` enabled.
60
- */
61
- var RevisionRepository = class {
62
- constructor(db) {
63
- this.db = db;
64
- }
65
- /**
66
- * Create a new revision
67
- */
68
- async create(input) {
69
- const id = monotonic();
70
- const row = {
71
- id,
72
- collection: input.collection,
73
- entry_id: input.entryId,
74
- data: JSON.stringify(input.data),
75
- author_id: input.authorId ?? null
76
- };
77
- await this.db.insertInto("revisions").values(row).execute();
78
- const revision = await this.findById(id);
79
- if (!revision) throw new Error("Failed to create revision");
80
- try {
81
- await this.db.insertInto("_emdash_revision_prune_queue").values({
82
- collection: input.collection,
83
- entry_id: input.entryId,
84
- revision_id: id
85
- }).onConflict((conflict) => conflict.columns(["collection", "entry_id"]).doUpdateSet({ revision_id: id })).execute();
86
- } catch (error) {
87
- console.error(`[revisions] Failed to queue revision pruning for ${input.collection}/${input.entryId}:`, error);
88
- }
89
- return revision;
90
- }
91
- /**
92
- * Find revision by ID
93
- */
94
- async findById(id) {
95
- const row = await this.db.selectFrom("revisions").selectAll().where("id", "=", id).executeTakeFirst();
96
- return row ? this.rowToRevision(row) : null;
97
- }
98
- /**
99
- * Get all revisions for an entry (newest first)
100
- *
101
- * Orders by monotonic ULID (descending). The monotonic factory
102
- * guarantees strictly increasing IDs even within the same millisecond.
103
- */
104
- async findByEntry(collection, entryId, options = {}) {
105
- let query = this.db.selectFrom("revisions").selectAll().where("collection", "=", collection).where("entry_id", "=", entryId).orderBy("id", "desc");
106
- if (options.limit) query = query.limit(options.limit);
107
- return (await query.execute()).map((row) => this.rowToRevision(row));
108
- }
109
- /**
110
- * Get the most recent revision for an entry
111
- */
112
- async findLatest(collection, entryId) {
113
- const row = await this.db.selectFrom("revisions").selectAll().where("collection", "=", collection).where("entry_id", "=", entryId).orderBy("id", "desc").limit(1).executeTakeFirst();
114
- return row ? this.rowToRevision(row) : null;
115
- }
116
- /**
117
- * Count revisions for an entry
118
- */
119
- async countByEntry(collection, entryId) {
120
- const result = await this.db.selectFrom("revisions").select((eb) => eb.fn.count("id").as("count")).where("collection", "=", collection).where("entry_id", "=", entryId).executeTakeFirst();
121
- return Number(result?.count || 0);
122
- }
123
- /**
124
- * Delete all revisions for an entry (use when entry is deleted)
125
- */
126
- async deleteByEntry(collection, entryId) {
127
- const result = await this.db.deleteFrom("revisions").where("collection", "=", collection).where("entry_id", "=", entryId).executeTakeFirst();
128
- try {
129
- await this.db.deleteFrom("_emdash_revision_prune_queue").where("collection", "=", collection).where("entry_id", "=", entryId).execute();
130
- } catch (error) {
131
- console.error(`[revisions] Failed to clear queued revision pruning for ${collection}/${entryId}:`, error);
132
- }
133
- return Number(result.numDeletedRows ?? 0);
134
- }
135
- /**
136
- * Delete old revisions, keeping the most recent N
137
- */
138
- async pruneOldRevisions(collection, entryId, keepCount, throughRevisionId) {
139
- validateIdentifier(collection, "collection");
140
- const tableName = `ec_${collection}`;
141
- let keepQuery = this.db.selectFrom("revisions").select("id").where("collection", "=", collection).where("entry_id", "=", entryId).orderBy("created_at", "desc").orderBy("id", "desc").limit(keepCount);
142
- if (throughRevisionId) keepQuery = keepQuery.where("id", "<=", throughRevisionId);
143
- const keepIds = (await keepQuery.execute()).map((r) => r.id);
144
- if (keepIds.length === 0) return 0;
145
- const result = await sql`
146
- DELETE FROM revisions
147
- WHERE collection = ${collection}
148
- AND entry_id = ${entryId}
149
- ${throughRevisionId ? sql`AND id <= ${throughRevisionId}` : sql``}
150
- AND id NOT IN (${sql.join(keepIds.map((id) => sql`${id}`))})
151
- AND NOT EXISTS (
152
- SELECT 1 FROM ${sql.ref(tableName)} AS content
153
- WHERE content.live_revision_id = revisions.id
154
- OR content.draft_revision_id = revisions.id
155
- )
156
- `.execute(this.db);
157
- return Number(result.numAffectedRows ?? 0);
158
- }
159
- async pruneQueuedEntry(collection, entryId, queuedRevisionId, keepCount) {
160
- const pruned = await this.pruneOldRevisions(collection, entryId, keepCount, queuedRevisionId);
161
- await this.db.deleteFrom("_emdash_revision_prune_queue").where("collection", "=", collection).where("entry_id", "=", entryId).where("revision_id", "=", queuedRevisionId).execute();
162
- return pruned;
163
- }
164
- async deleteIfUnreferenced(collection, entryId, revisionId) {
165
- validateIdentifier(collection, "collection");
166
- const tableName = `ec_${collection}`;
167
- return ((await sql`
168
- DELETE FROM revisions
169
- WHERE id = ${revisionId}
170
- AND collection = ${collection}
171
- AND entry_id = ${entryId}
172
- AND NOT EXISTS (
173
- SELECT 1 FROM ${sql.ref(tableName)} AS content
174
- WHERE content.live_revision_id = revisions.id
175
- OR content.draft_revision_id = revisions.id
176
- )
177
- `.execute(this.db)).numAffectedRows ?? 0n) > 0n;
178
- }
179
- /**
180
- * Convert database row to Revision object
181
- */
182
- rowToRevision(row) {
183
- return {
184
- id: row.id,
185
- collection: row.collection,
186
- entryId: row.entry_id,
187
- data: JSON.parse(row.data),
188
- authorId: row.author_id,
189
- createdAt: row.created_at
190
- };
191
- }
192
- };
193
-
194
- //#endregion
195
- //#region src/database/repositories/content.ts
196
- var content_exports = /* @__PURE__ */ __exportAll({
197
- ContentRepository: () => ContentRepository,
198
- isConfirmedStatementFailure: () => isConfirmedStatementFailure,
199
- isSystemOrderField: () => isSystemOrderField
200
- });
201
- const ULID_PATTERN = /^[0-9A-Z]{26}$/;
202
- const SQLSTATE_PATTERN = /^[0-9A-Z]{5}$/;
203
- const MAX_DRAFT_STAGE_ATTEMPTS = 32;
204
- const LIKE_WILDCARD_RE = /[\\%_]/g;
205
- const MAX_INDEXED_FIELD_FILTERS = 20;
206
- const MAX_IN_FILTER_VALUES = SQL_BATCH_SIZE;
207
- const MAX_FILTER_STRING_LENGTH = 2048;
208
- function assertRevisionPrecondition(item, expected) {
209
- if (expected && (item.version !== expected.version || item.updatedAt !== expected.updatedAt)) throw new ContentMutationConflictError();
210
- }
211
- function nullableColumnMatch(column, value) {
212
- validateIdentifier(column, "content column");
213
- return value === null ? sql`${sql.ref(column)} IS NULL` : sql`${sql.ref(column)} = ${value}`;
214
- }
215
- function sameStoredValue(left, right) {
216
- return Object.is(serializeValue(left), serializeValue(right));
217
- }
218
- function matchesPublication(observed, existing, revision, revisionId, slug, publishedAt, updatedAt) {
219
- if (observed.version !== existing.version + 1 || observed.status !== "published" || observed.slug !== slug || observed.liveRevisionId !== revisionId || observed.draftRevisionId !== null || observed.scheduledAt !== null || observed.publishedAt !== publishedAt || observed.updatedAt !== updatedAt) return false;
220
- return Object.entries(revision.data).every(([key, value]) => SYSTEM_COLUMNS.has(key) || key.startsWith("_") || sameStoredValue(observed.data[key], value));
221
- }
222
- function matchesLifecyclePublication(observed, existing, liveRevisionId, publishedAt, updatedAt) {
223
- if (observed.version !== existing.version + 1 || observed.status !== "published" || observed.slug !== existing.slug || observed.liveRevisionId !== liveRevisionId || observed.draftRevisionId !== null || observed.scheduledAt !== null || observed.publishedAt !== publishedAt || observed.updatedAt !== updatedAt) return false;
224
- return Object.entries(existing.data).every(([key, value]) => sameStoredValue(observed.data[key], value));
225
- }
226
- function matchesPublicationFence(observed, existing) {
227
- return observed.version === existing.version && observed.status === existing.status && observed.liveRevisionId === existing.liveRevisionId && observed.draftRevisionId === existing.draftRevisionId && observed.scheduledAt === existing.scheduledAt;
228
- }
229
- function isConfirmedStatementFailure(error) {
230
- if (typeof error !== "object" || error === null || !("code" in error)) return false;
231
- const code = error.code;
232
- return typeof code === "string" && (code === "ERR_SQLITE_ERROR" || code.startsWith("SQLITE_") || SQLSTATE_PATTERN.test(code));
233
- }
234
- function encodeIndexedFieldCursor(field, value, id) {
235
- const payload = {
236
- version: 1,
237
- field,
238
- value
239
- };
240
- return encodeCursor(JSON.stringify(payload), id);
241
- }
242
- function decodeIndexedFieldCursor(cursor, field) {
243
- const { orderValue, id } = decodeCursor(cursor);
244
- let payload;
245
- try {
246
- payload = JSON.parse(orderValue);
247
- } catch {
248
- throw new InvalidCursorError(cursor);
249
- }
250
- if (payload === null || typeof payload !== "object") throw new InvalidCursorError(cursor);
251
- const candidate = payload;
252
- const validValue = candidate.value === null || typeof candidate.value === "string" || typeof candidate.value === "number";
253
- if (candidate.version !== 1 || candidate.field !== field || !validValue) throw new InvalidCursorError(cursor);
254
- return {
255
- value: candidate.value,
256
- id
257
- };
258
- }
259
- /**
260
- * Whitelist mapping a public date-filter field to its physical column. Keeping
261
- * this separate from `mapOrderField` makes the filterable set explicit and
262
- * prevents filtering on arbitrary columns.
263
- */
264
- const DATE_FILTER_COLUMNS = {
265
- createdAt: "created_at",
266
- updatedAt: "updated_at",
267
- publishedAt: "published_at"
268
- };
269
- /**
270
- * Built-in sort fields → their physical columns. A closed set that blocks
271
- * sorting by arbitrary columns; per-collection fields are allowed
272
- * separately via `mapOrderField`'s `sortableExtras`.
273
- */
274
- const ORDER_FIELD_COLUMNS = {
275
- createdAt: "created_at",
276
- updatedAt: "updated_at",
277
- publishedAt: "published_at",
278
- scheduledAt: "scheduled_at",
279
- deletedAt: "deleted_at",
280
- title: "title",
281
- name: "name",
282
- slug: "slug",
283
- status: "status",
284
- locale: "locale"
285
- };
286
- /** True when `field` maps to a system column and needs no per-collection resolution. */
287
- function isSystemOrderField(field) {
288
- return field in ORDER_FIELD_COLUMNS;
289
- }
290
- /**
291
- * System columns that exist in every ec_* table
292
- */
293
- const SYSTEM_COLUMNS = new Set([
294
- "id",
295
- "slug",
296
- "status",
297
- "author_id",
298
- "primary_byline_id",
299
- "created_at",
300
- "updated_at",
301
- "published_at",
302
- "scheduled_at",
303
- "deleted_at",
304
- "version",
305
- "live_revision_id",
306
- "draft_revision_id",
307
- "locale",
308
- "translation_group"
309
- ]);
310
- /**
311
- * Get the table name for a collection type
312
- */
313
- function getTableName(type) {
314
- validateIdentifier(type, "collection type");
315
- return `ec_${type}`;
316
- }
317
- /**
318
- * Serialize a value for database storage
319
- * Objects/arrays are JSON-stringified
320
- * Booleans are converted to 0/1 for SQLite
321
- */
322
- function serializeValue(value) {
323
- if (value === null || value === void 0) return null;
324
- if (typeof value === "boolean") return value ? 1 : 0;
325
- if (typeof value === "object") return JSON.stringify(value);
326
- return value;
327
- }
328
- function writableContentData(data) {
329
- const writable = {};
330
- for (const [key, value] of Object.entries(data)) {
331
- if (SYSTEM_COLUMNS.has(key)) continue;
332
- validateIdentifier(key, "content field name");
333
- writable[key] = value;
334
- }
335
- return writable;
336
- }
337
- /**
338
- * Deserialize a value from database storage
339
- * Attempts to parse JSON strings that look like objects/arrays
340
- */
341
- function deserializeValue(value) {
342
- if (typeof value === "string") {
343
- if (value.startsWith("{") || value.startsWith("[")) try {
344
- return JSON.parse(value);
345
- } catch {
346
- return value;
347
- }
348
- }
349
- return value;
350
- }
351
- /** Pattern for escaping special regex characters */
352
- const REGEX_ESCAPE_PATTERN = /[.*+?^${}()|[\]\\]/g;
353
- /**
354
- * Escape special regex characters in a string for use in `new RegExp()`
355
- */
356
- function escapeRegExp(s) {
357
- return s.replace(REGEX_ESCAPE_PATTERN, "\\$&");
358
- }
359
- /**
360
- * Repository for content CRUD operations
361
- *
362
- * Content is stored in per-collection tables (ec_posts, ec_pages, etc.)
363
- * Each field becomes a real column in the table.
364
- */
365
- var ContentRepository = class {
366
- constructor(db) {
367
- this.db = db;
368
- }
369
- /**
370
- * Create a new content item
371
- */
372
- async create(input) {
373
- const id = input.id ?? ulid();
374
- const now = (/* @__PURE__ */ new Date()).toISOString();
375
- const { type, slug, data, status = "draft", authorId, primaryBylineId, locale, translationOf, publishedAt, createdAt } = input;
376
- if (!type) throw new EmDashValidationError("Content type is required");
377
- const tableName = getTableName(type);
378
- let translationGroup = id;
379
- if (translationOf) {
380
- const source = await this.findById(type, translationOf);
381
- if (!source) throw new EmDashValidationError("Translation source content not found");
382
- translationGroup = source.translationGroup || source.id;
383
- }
384
- const columns = [
385
- "id",
386
- "slug",
387
- "status",
388
- "author_id",
389
- "primary_byline_id",
390
- "created_at",
391
- "updated_at",
392
- "published_at",
393
- "version",
394
- "locale",
395
- "translation_group"
396
- ];
397
- const values = [
398
- id,
399
- slug || null,
400
- status,
401
- authorId || null,
402
- primaryBylineId ?? null,
403
- createdAt || now,
404
- now,
405
- publishedAt || null,
406
- 1,
407
- locale || "en",
408
- translationGroup
409
- ];
410
- if (data && typeof data === "object") {
411
- for (const [key, value] of Object.entries(data)) if (!SYSTEM_COLUMNS.has(key)) {
412
- validateIdentifier(key, "content field name");
413
- columns.push(key);
414
- values.push(serializeValue(value));
415
- }
416
- }
417
- const columnRefs = columns.map((c) => sql.ref(c));
418
- const valuePlaceholders = values.map((v) => v === null ? sql`NULL` : sql`${v}`);
419
- await sql`
420
- INSERT INTO ${sql.ref(tableName)} (${sql.join(columnRefs, sql`, `)})
421
- VALUES (${sql.join(valuePlaceholders, sql`, `)})
422
- `.execute(this.db);
423
- invalidateCollectionCache(type);
424
- const item = await this.findById(type, id);
425
- if (!item) throw new Error("Failed to create content");
426
- return item;
427
- }
428
- /**
429
- * Generate a unique slug for a content item within a collection.
430
- *
431
- * Checks the collection table for existing slugs that match `baseSlug`
432
- * (optionally scoped to a locale) and appends a numeric suffix (`-1`,
433
- * `-2`, etc.) on collision to guarantee uniqueness.
434
- *
435
- * Returns null when slug normalization cannot produce a value.
436
- */
437
- async generateUniqueSlug(type, text, locale) {
438
- const baseSlug = slugify(text);
439
- if (!baseSlug) return null;
440
- const tableName = getTableName(type);
441
- if ((locale ? await sql`
442
- SELECT slug FROM ${sql.ref(tableName)}
443
- WHERE slug = ${baseSlug}
444
- AND locale = ${locale}
445
- LIMIT 1
446
- `.execute(this.db) : await sql`
447
- SELECT slug FROM ${sql.ref(tableName)}
448
- WHERE slug = ${baseSlug}
449
- LIMIT 1
450
- `.execute(this.db)).rows.length === 0) return baseSlug;
451
- const pattern = `${baseSlug}-%`;
452
- const candidates = locale ? await sql`
453
- SELECT slug FROM ${sql.ref(tableName)}
454
- WHERE (slug = ${baseSlug} OR slug LIKE ${pattern})
455
- AND locale = ${locale}
456
- `.execute(this.db) : await sql`
457
- SELECT slug FROM ${sql.ref(tableName)}
458
- WHERE slug = ${baseSlug} OR slug LIKE ${pattern}
459
- `.execute(this.db);
460
- let maxSuffix = 0;
461
- const suffixPattern = new RegExp(`^${escapeRegExp(baseSlug)}-(\\d+)$`);
462
- for (const row of candidates.rows) {
463
- const match = suffixPattern.exec(row.slug);
464
- if (match) {
465
- const n = parseInt(match[1], 10);
466
- if (n > maxSuffix) maxSuffix = n;
467
- }
468
- }
469
- return `${baseSlug}-${maxSuffix + 1}`;
470
- }
471
- /**
472
- * Duplicate a content item
473
- * Creates a new draft copy with "(Copy)" appended to the title.
474
- * A slug is auto-generated from the new title by the handler layer.
475
- */
476
- async duplicate(type, id, authorId) {
477
- const original = await this.findById(type, id);
478
- if (!original) throw new EmDashValidationError("Content item not found");
479
- const newData = { ...original.data };
480
- if (typeof newData.title === "string") newData.title = `${newData.title} (Copy)`;
481
- else if (typeof newData.name === "string") newData.name = `${newData.name} (Copy)`;
482
- const slugSource = typeof newData.title === "string" ? newData.title : typeof newData.name === "string" ? newData.name : null;
483
- const slug = slugSource ? await this.generateUniqueSlug(type, slugSource, original.locale ?? void 0) : null;
484
- return this.create({
485
- type,
486
- slug,
487
- data: newData,
488
- status: "draft",
489
- authorId: authorId || original.authorId || void 0,
490
- locale: original.locale ?? void 0
491
- });
492
- }
493
- /**
494
- * Find content by ID
495
- */
496
- async findById(type, id) {
497
- const tableName = getTableName(type);
498
- const row = (await sql`
499
- SELECT * FROM ${sql.ref(tableName)}
500
- WHERE id = ${id}
501
- AND deleted_at IS NULL
502
- `.execute(this.db)).rows[0];
503
- if (!row) return null;
504
- return this.mapRow(type, row);
505
- }
506
- /**
507
- * Find content by id, including trashed (soft-deleted) items.
508
- * Used by restore endpoint for ownership checks.
509
- */
510
- async findByIdIncludingTrashed(type, id) {
511
- const tableName = getTableName(type);
512
- const row = (await sql`
513
- SELECT * FROM ${sql.ref(tableName)}
514
- WHERE id = ${id}
515
- `.execute(this.db)).rows[0];
516
- if (!row) return null;
517
- return this.mapRow(type, row);
518
- }
519
- /**
520
- * Find content by ID or slug. Tries ID first if it looks like a ULID,
521
- * otherwise tries slug. Falls back to the other if the first lookup misses.
522
- */
523
- async findByIdOrSlug(type, identifier, locale) {
524
- return this._findByIdOrSlug(type, identifier, false, locale);
525
- }
526
- /**
527
- * Find content by ID or slug, including trashed (soft-deleted) items.
528
- * Used by restore/permanent-delete endpoints.
529
- */
530
- async findByIdOrSlugIncludingTrashed(type, identifier, locale) {
531
- return this._findByIdOrSlug(type, identifier, true, locale);
532
- }
533
- async _findByIdOrSlug(type, identifier, includeTrashed, locale) {
534
- const looksLikeUlid = ULID_PATTERN.test(identifier);
535
- const findById = includeTrashed ? (t, id) => this.findByIdIncludingTrashed(t, id) : (t, id) => this.findById(t, id);
536
- const findBySlug = includeTrashed ? (t, s) => this.findBySlugIncludingTrashed(t, s, locale) : (t, s) => this.findBySlug(t, s, locale);
537
- try {
538
- if (looksLikeUlid) {
539
- const byId = await findById(type, identifier);
540
- if (byId) return byId;
541
- return await findBySlug(type, identifier);
542
- }
543
- const bySlug = await findBySlug(type, identifier);
544
- if (bySlug) return bySlug;
545
- return await findById(type, identifier);
546
- } catch (error) {
547
- if (isMissingTableError(error)) return null;
548
- throw error;
549
- }
550
- }
551
- /**
552
- * Find content by slug
553
- */
554
- async findBySlug(type, slug, locale) {
555
- const tableName = getTableName(type);
556
- const row = (locale ? await sql`
557
- SELECT * FROM ${sql.ref(tableName)}
558
- WHERE slug = ${slug}
559
- AND locale = ${locale}
560
- AND deleted_at IS NULL
561
- `.execute(this.db) : await sql`
562
- SELECT * FROM ${sql.ref(tableName)}
563
- WHERE slug = ${slug}
564
- AND deleted_at IS NULL
565
- ORDER BY locale ASC
566
- LIMIT 1
567
- `.execute(this.db)).rows[0];
568
- if (!row) return null;
569
- return this.mapRow(type, row);
570
- }
571
- /**
572
- * Find content by slug, including trashed (soft-deleted) items.
573
- * Used by restore/permanent-delete endpoints.
574
- */
575
- async findBySlugIncludingTrashed(type, slug, locale) {
576
- const tableName = getTableName(type);
577
- const row = (locale ? await sql`
578
- SELECT * FROM ${sql.ref(tableName)}
579
- WHERE slug = ${slug}
580
- AND locale = ${locale}
581
- `.execute(this.db) : await sql`
582
- SELECT * FROM ${sql.ref(tableName)}
583
- WHERE slug = ${slug}
584
- ORDER BY locale ASC
585
- LIMIT 1
586
- `.execute(this.db)).rows[0];
587
- if (!row) return null;
588
- return this.mapRow(type, row);
589
- }
590
- /**
591
- * Find many content items with filtering and pagination
592
- */
593
- async findMany(type, options = {}) {
594
- const tableName = getTableName(type);
595
- const limit = Math.min(options.limit || 50, 100);
596
- const orderField = options.orderBy?.field || "createdAt";
597
- const orderDirection = options.orderBy?.direction || "desc";
598
- const resolvedOrderField = await this.resolveOrderField(type, orderField, options.sortableExtras);
599
- const dbField = resolvedOrderField.column;
600
- const resolvedFieldFilters = await this.resolveFieldFilters(type, options.where?.fieldFilters);
601
- const safeOrderDirection = orderDirection.toLowerCase() === "asc" ? "ASC" : "DESC";
602
- let query = this.db.selectFrom(tableName).selectAll().where("deleted_at", "is", null);
603
- if (options.where?.status) query = query.where("status", "=", options.where.status);
604
- if (options.where?.authorId) query = query.where("author_id", "=", options.where.authorId);
605
- if (options.where?.locale) query = query.where("locale", "=", options.where.locale);
606
- query = this.applySearchFilter(query, options.where, type);
607
- query = this.applyDateFilter(query, options.where);
608
- query = this.applyBylineFilter(query, options.where, type);
609
- query = this.applyFieldFilters(query, resolvedFieldFilters);
610
- if (options.cursor) if (resolvedOrderField.indexedCustomField) {
611
- const { value, id: cursorId } = decodeIndexedFieldCursor(options.cursor, orderField);
612
- const isPresent = sql`${sql.ref(dbField)} IS NOT NULL`;
613
- const falseLiteral = sql`FALSE`;
614
- const trueLiteral = sql`TRUE`;
615
- if (safeOrderDirection === "ASC" && value === null) query = query.where(sql`
616
- (${isPresent}) > ${falseLiteral}
617
- OR ((${isPresent}) = ${falseLiteral} AND ${sql.ref("id")} > ${cursorId})
618
- `);
619
- else if (safeOrderDirection === "DESC" && value === null) query = query.where(sql`
620
- (${isPresent}) = ${falseLiteral} AND ${sql.ref("id")} < ${cursorId}
621
- `);
622
- else if (safeOrderDirection === "ASC") query = query.where(sql`
623
- (${isPresent}, ${sql.ref(dbField)}, ${sql.ref("id")})
624
- > (${trueLiteral}, ${value}, ${cursorId})
625
- `);
626
- else query = query.where(sql`
627
- (${isPresent}, ${sql.ref(dbField)}, ${sql.ref("id")})
628
- < (${trueLiteral}, ${value}, ${cursorId})
629
- `);
630
- } else {
631
- const { orderValue, id: cursorId } = decodeCursor(options.cursor);
632
- if (safeOrderDirection === "DESC") query = query.where((eb) => eb.or([eb(dbField, "<", orderValue), eb.and([eb(dbField, "=", orderValue), eb("id", "<", cursorId)])]));
633
- else query = query.where((eb) => eb.or([eb(dbField, ">", orderValue), eb.and([eb(dbField, "=", orderValue), eb("id", ">", cursorId)])]));
634
- }
635
- const indexedOrderFilter = resolvedOrderField.indexedCustomField ? resolvedFieldFilters.find((filter) => filter.column === dbField) : void 0;
636
- if (resolvedOrderField.indexedCustomField && !indexedOrderFilter) query = query.orderBy(sql`${sql.ref(dbField)} IS NOT NULL`, safeOrderDirection === "ASC" ? "asc" : "desc");
637
- if (indexedOrderFilter?.kind !== "null") query = query.orderBy(dbField, safeOrderDirection === "ASC" ? "asc" : "desc");
638
- query = query.orderBy("id", safeOrderDirection === "ASC" ? "asc" : "desc").limit(limit + 1);
639
- const [rowsResult, countResult] = await Promise.allSettled([query.execute(), this.countWithResolvedFilters(type, options.where, resolvedFieldFilters)]);
640
- if (rowsResult.status === "rejected") throw rowsResult.reason;
641
- if (countResult.status === "rejected") throw countResult.reason;
642
- const rows = rowsResult.value;
643
- const total = countResult.value;
644
- const hasMore = rows.length > limit;
645
- const items = rows.slice(0, limit);
646
- const mappedResult = {
647
- items: items.map((row) => this.mapRow(type, row)),
648
- total
649
- };
650
- if (hasMore && items.length > 0) {
651
- const lastRow = items.at(-1);
652
- const lastOrderValue = lastRow[dbField];
653
- if (resolvedOrderField.indexedCustomField) {
654
- if (lastOrderValue !== null && typeof lastOrderValue !== "string" && typeof lastOrderValue !== "number") throw new EmDashValidationError(`Invalid indexed value for order field: ${orderField}`);
655
- mappedResult.nextCursor = encodeIndexedFieldCursor(orderField, lastOrderValue, String(lastRow.id));
656
- } else mappedResult.nextCursor = encodeCursor(typeof lastOrderValue === "string" || typeof lastOrderValue === "number" ? String(lastOrderValue) : "", String(lastRow.id));
657
- }
658
- return mappedResult;
659
- }
660
- normalizeScheduledAt(value) {
661
- if (value === null) return null;
662
- const scheduledDate = new Date(value);
663
- if (isNaN(scheduledDate.getTime())) throw new EmDashValidationError("Invalid scheduled date");
664
- return scheduledDate.toISOString();
665
- }
666
- /**
667
- * Update content
668
- */
669
- async update(type, id, input) {
670
- const tableName = getTableName(type);
671
- const now = (/* @__PURE__ */ new Date()).toISOString();
672
- const updates = {};
673
- if (input.status !== void 0) updates.status = input.status;
674
- if (input.slug !== void 0) updates.slug = input.slug;
675
- if (input.publishedAt !== void 0) updates.published_at = input.publishedAt;
676
- if (input.scheduledAt !== void 0) updates.scheduled_at = this.normalizeScheduledAt(input.scheduledAt);
677
- if (input.authorId !== void 0) updates.author_id = input.authorId;
678
- if (input.primaryBylineId !== void 0) updates.primary_byline_id = input.primaryBylineId;
679
- if (input.data !== void 0 && typeof input.data === "object") for (const [key, value] of Object.entries(writableContentData(input.data))) updates[key] = serializeValue(value);
680
- const hasColumnWrites = Object.keys(updates).length > 0;
681
- if (hasColumnWrites) updates.updated_at = now;
682
- updates.version = sql`version + 1`;
683
- await this.db.updateTable(tableName).set(updates).where("id", "=", id).where("deleted_at", "is", null).execute();
684
- if (hasColumnWrites) invalidateCollectionCache(type);
685
- const updated = await this.findById(type, id);
686
- if (!updated) throw new Error("Content not found");
687
- return updated;
688
- }
689
- /**
690
- * Update plugin-authored fields without letting content columns diverge
691
- * from the revision pointers that publication promotes.
692
- */
693
- async updateDraftAware(type, id, input) {
694
- const data = input.data ? writableContentData(input.data) : {};
695
- const stagedSlug = typeof input.slug === "string" ? input.slug : void 0;
696
- if (!(Object.keys(data).length > 0 || stagedSlug !== void 0)) return this.update(type, id, {
697
- ...input,
698
- data
699
- });
700
- const collectionRows = await this.db.selectFrom("_emdash_collections as collection").leftJoin("_emdash_fields as field", "field.collection_id", "collection.id").select(["collection.supports", "field.slug as fieldSlug"]).where("collection.slug", "=", type).execute();
701
- const supportsRaw = collectionRows[0]?.supports;
702
- const supports = supportsRaw ? JSON.parse(supportsRaw) : [];
703
- if (!Array.isArray(supports) || !supports.includes("revisions")) return this.update(type, id, {
704
- ...input,
705
- data
706
- });
707
- const fieldSlugs = new Set(collectionRows.map((row) => row.fieldSlug).filter(Boolean));
708
- for (const field of Object.keys(data)) if (!fieldSlugs.has(field)) throw new EmDashValidationError(`Unknown field '${field}' in collection '${type}'`);
709
- const revisionRepo = new RevisionRepository(this.db);
710
- let existing = await this.findById(type, id);
711
- for (let attempt = 0; existing && attempt < MAX_DRAFT_STAGE_ATTEMPTS; attempt++) {
712
- let baseData = existing.data;
713
- if (existing.draftRevisionId) {
714
- const draft = await revisionRepo.findById(existing.draftRevisionId);
715
- if (draft) baseData = draft.data;
716
- }
717
- const mergedData = {
718
- ...baseData,
719
- ...data
720
- };
721
- if (stagedSlug !== void 0) mergedData._slug = stagedSlug;
722
- const revision = await revisionRepo.create({
723
- collection: type,
724
- entryId: id,
725
- data: mergedData,
726
- ...input.authorId ? { authorId: input.authorId } : {}
727
- });
728
- let staged;
729
- try {
730
- staged = await this.replaceDraftRevisionForUpdate(type, id, revision.id, existing, input);
731
- } catch (error) {
732
- await this.deleteUnstagedRevision(revisionRepo, type, id, revision.id);
733
- throw error;
734
- }
735
- if (staged) {
736
- const updated = await this.findById(type, id);
737
- if (!updated) throw new Error("Content not found");
738
- const draftData = {};
739
- for (const [key, value] of Object.entries(mergedData)) if (!key.startsWith("_")) draftData[key] = value;
740
- return {
741
- ...updated,
742
- data: {
743
- ...updated.data,
744
- ...draftData
745
- }
746
- };
747
- }
748
- await this.deleteUnstagedRevision(revisionRepo, type, id, revision.id);
749
- existing = await this.findById(type, id);
750
- }
751
- if (!existing) throw new Error("Content not found");
752
- throw new ContentMutationConflictError();
753
- }
754
- async deleteUnstagedRevision(revisionRepo, type, id, revisionId) {
755
- try {
756
- await revisionRepo.deleteIfUnreferenced(type, id, revisionId);
757
- } catch (error) {
758
- console.error(`[content] Failed to clean up unstaged revision ${revisionId}:`, error);
759
- }
760
- }
761
- async replaceDraftRevisionForUpdate(type, id, revisionId, expected, input) {
762
- const tableName = getTableName(type);
763
- const assignments = [sql`draft_revision_id = ${revisionId}`];
764
- let liveMetadataChanged = false;
765
- if (input.status !== void 0) {
766
- assignments.push(sql`status = ${input.status}`);
767
- liveMetadataChanged = true;
768
- }
769
- if (input.slug === null) {
770
- assignments.push(sql`slug = NULL`);
771
- liveMetadataChanged = true;
772
- }
773
- if (input.publishedAt !== void 0) {
774
- assignments.push(sql`published_at = ${input.publishedAt}`);
775
- liveMetadataChanged = true;
776
- }
777
- if (input.scheduledAt !== void 0) {
778
- assignments.push(sql`scheduled_at = ${this.normalizeScheduledAt(input.scheduledAt)}`);
779
- liveMetadataChanged = true;
780
- }
781
- if (input.authorId !== void 0) {
782
- assignments.push(sql`author_id = ${input.authorId}`);
783
- liveMetadataChanged = true;
784
- }
785
- if (input.primaryBylineId !== void 0) {
786
- assignments.push(sql`primary_byline_id = ${input.primaryBylineId}`);
787
- liveMetadataChanged = true;
788
- }
789
- if (liveMetadataChanged) assignments.push(sql`updated_at = ${(/* @__PURE__ */ new Date()).toISOString()}`);
790
- assignments.push(sql`version = version + 1`);
791
- const changed = ((await sql`
792
- UPDATE ${sql.ref(tableName)}
793
- SET ${sql.join(assignments, sql`, `)}
794
- WHERE id = ${id}
795
- AND deleted_at IS NULL
796
- AND version = ${expected.version}
797
- AND ${nullableColumnMatch("live_revision_id", expected.liveRevisionId)}
798
- AND ${nullableColumnMatch("draft_revision_id", expected.draftRevisionId)}
799
- AND EXISTS (
800
- SELECT 1 FROM revisions
801
- WHERE revisions.id = ${revisionId}
802
- AND revisions.collection = ${type}
803
- AND revisions.entry_id = ${id}
804
- )
805
- `.execute(this.db)).numAffectedRows ?? 0n) > 0n;
806
- if (changed && liveMetadataChanged) invalidateCollectionCache(type);
807
- return changed;
808
- }
809
- /**
810
- * Delete content (soft delete - moves to trash)
811
- */
812
- async delete(type, id) {
813
- const tableName = getTableName(type);
814
- const now = (/* @__PURE__ */ new Date()).toISOString();
815
- const changed = ((await sql`
816
- UPDATE ${sql.ref(tableName)}
817
- SET deleted_at = ${now}
818
- WHERE id = ${id}
819
- AND deleted_at IS NULL
820
- `.execute(this.db)).numAffectedRows ?? 0n) > 0n;
821
- if (changed) invalidateCollectionCache(type);
822
- return changed;
823
- }
824
- /**
825
- * Restore content from trash
826
- */
827
- async restore(type, id) {
828
- const tableName = getTableName(type);
829
- const restored = (await sql`
830
- UPDATE ${sql.ref(tableName)}
831
- SET deleted_at = NULL
832
- WHERE id = ${id}
833
- AND deleted_at IS NOT NULL
834
- RETURNING *
835
- `.execute(this.db)).rows[0];
836
- if (!restored) return null;
837
- invalidateCollectionCache(type);
838
- return this.mapRow(type, restored);
839
- }
840
- /**
841
- * Permanently delete content (cannot be undone)
842
- */
843
- /**
844
- * Permanently delete a soft-deleted content row.
845
- *
846
- * Returns `true` only when a soft-deleted (trashed) row was removed.
847
- * Returns `false` when no row exists OR when the row exists but is live —
848
- * the caller is responsible for distinguishing these cases (typically via
849
- * a follow-up `findByIdOrSlugIncludingTrashed` to surface NOT_FOUND vs
850
- * NOT_TRASHED). The `AND deleted_at IS NOT NULL` clause is the safety net
851
- * that prevents permanent delete from bypassing the trash workflow.
852
- */
853
- async permanentDelete(type, id) {
854
- const tableName = getTableName(type);
855
- const changed = ((await sql`
856
- DELETE FROM ${sql.ref(tableName)}
857
- WHERE id = ${id}
858
- AND deleted_at IS NOT NULL
859
- `.execute(this.db)).numAffectedRows ?? 0n) > 0n;
860
- if (changed) invalidateCollectionCache(type);
861
- return changed;
862
- }
863
- /**
864
- * Find trashed content items
865
- */
866
- async findTrashed(type, options = {}) {
867
- const tableName = getTableName(type);
868
- const limit = Math.min(options.limit || 50, 100);
869
- const orderField = options.orderBy?.field || "deletedAt";
870
- const orderDirection = options.orderBy?.direction || "desc";
871
- const dbField = this.mapOrderField(orderField);
872
- const safeOrderDirection = orderDirection.toLowerCase() === "asc" ? "ASC" : "DESC";
873
- let query = this.db.selectFrom(tableName).selectAll().where("deleted_at", "is not", null);
874
- if (options.where?.locale) query = query.where("locale", "=", options.where.locale);
875
- if (options.cursor) {
876
- const { orderValue, id: cursorId } = decodeCursor(options.cursor);
877
- if (safeOrderDirection === "DESC") query = query.where((eb) => eb.or([eb(dbField, "<", orderValue), eb.and([eb(dbField, "=", orderValue), eb("id", "<", cursorId)])]));
878
- else query = query.where((eb) => eb.or([eb(dbField, ">", orderValue), eb.and([eb(dbField, "=", orderValue), eb("id", ">", cursorId)])]));
879
- }
880
- query = query.orderBy(dbField, safeOrderDirection === "ASC" ? "asc" : "desc").orderBy("id", safeOrderDirection === "ASC" ? "asc" : "desc").limit(limit + 1);
881
- const rows = await query.execute();
882
- const hasMore = rows.length > limit;
883
- const items = rows.slice(0, limit);
884
- const mappedResult = { items: items.map((row) => {
885
- const record = row;
886
- return {
887
- ...this.mapRow(type, record),
888
- deletedAt: typeof record.deleted_at === "string" ? record.deleted_at : ""
889
- };
890
- }) };
891
- if (hasMore && items.length > 0) {
892
- const lastRow = items.at(-1);
893
- const lastOrderValue = lastRow[dbField];
894
- mappedResult.nextCursor = encodeCursor(typeof lastOrderValue === "string" || typeof lastOrderValue === "number" ? String(lastOrderValue) : "", String(lastRow.id));
895
- }
896
- return mappedResult;
897
- }
898
- /**
899
- * Count trashed content items
900
- */
901
- async countTrashed(type, options = {}) {
902
- const tableName = getTableName(type);
903
- let query = this.db.selectFrom(tableName).select((eb) => eb.fn.count("id").as("count")).where("deleted_at", "is not", null);
904
- if (options.locale) query = query.where("locale", "=", options.locale);
905
- const result = await query.executeTakeFirst();
906
- return Number(result?.count || 0);
907
- }
908
- /**
909
- * Apply the optional `q` filter.
910
- *
911
- * When the handler sets `useFts` (collection has a healthy FTS5 index
912
- * covering the display columns; SQLite only), the filter is served from
913
- * the index: a token-prefix MATCH against `_emdash_fts_<slug>` OR'd with
914
- * an index-served `slug GLOB 'term*'` prefix (the slug is not in the FTS
915
- * index). Both sides are index-backed, so SQLite's OR optimization avoids
916
- * the full-table scan the LIKE fallback needs (#1517). The trade-off is
917
- * search semantics: token-prefix matching instead of arbitrary substring.
918
- *
919
- * Fallback (Postgres, search disabled, or no usable terms): case-
920
- * insensitive substring LIKE across the handler-resolved `searchColumns`
921
- * (OR'd). User input is treated literally (LIKE wildcards escaped) and
922
- * `lower()` is applied on both sides for SQLite/Postgres parity.
923
- */
924
- applySearchFilter(query, where, type) {
925
- const term = where?.q?.trim();
926
- const columns = where?.searchColumns;
927
- if (!term || !columns || columns.length === 0) return query;
928
- if (where.useFts) {
929
- const match = buildFtsPrefixMatch(term);
930
- if (match) {
931
- validateIdentifier(type, "collection slug");
932
- const ftsTable = `_emdash_fts_${type}`;
933
- const slugPrefix = buildSlugGlobPrefix(term);
934
- return query.where((eb) => eb.or([sql`id IN (SELECT id FROM ${sql.ref(ftsTable)} WHERE ${sql.ref(ftsTable)} MATCH ${match})`, sql`slug GLOB ${slugPrefix}`]));
935
- }
936
- }
937
- const pattern = `%${term.replace(LIKE_WILDCARD_RE, (c) => `\\${c}`)}%`;
938
- return query.where((eb) => eb.or(columns.map((col) => {
939
- validateIdentifier(col, "search column");
940
- return sql`lower(CAST(${sql.ref(col)} AS TEXT)) LIKE lower(${pattern}) ESCAPE '\\'`;
941
- })));
942
- }
943
- /**
944
- * Apply the optional inclusive date-range filter. The field is mapped
945
- * through `DATE_FILTER_COLUMNS` (a closed whitelist), and bounds compare
946
- * lexicographically against the stored ISO 8601 timestamps. A `publishedAt`
947
- * range naturally excludes never-published rows (their column is NULL).
948
- */
949
- applyDateFilter(query, where) {
950
- const filter = where?.dateFilter;
951
- if (!filter) return query;
952
- const column = DATE_FILTER_COLUMNS[filter.field];
953
- if (!column) throw new EmDashValidationError(`Invalid date filter field: ${filter.field}`);
954
- const { from, to } = filter;
955
- if (!from && !to) return query;
956
- let next = query;
957
- if (from) next = next.where((eb) => eb(column, ">=", from));
958
- if (to) next = next.where((eb) => eb(column, "<=", to));
959
- return next;
960
- }
961
- /**
962
- * Apply the optional byline filter as a correlated (NOT) EXISTS against
963
- * `_emdash_content_bylines`.
964
- *
965
- * Correlating from the content table preserves the outer sort index so
966
- * `LIMIT` can short-circuit. `mode: "none"` tests the junction rather than
967
- * `primary_byline_id` because the two are written in the same call but
968
- * are not atomically consistent, so the junction is authoritative.
969
- *
970
- * Whether a credit *renders* is locale-scoped; whether one *exists* is
971
- * not. Both are needed: the first decides what the filter matches, the
972
- * second decides whether the author fallback applies at all.
973
- */
974
- applyBylineFilter(query, where, type) {
975
- const filter = where?.bylineFilter;
976
- if (!filter) return query;
977
- const tableName = getTableName(type);
978
- const idColumn = `${tableName}.id`;
979
- const authorColumn = `${tableName}.author_id`;
980
- const localeColumn = `${tableName}.locale`;
981
- const creditRenders = (eb, bylineIds) => {
982
- let sub = eb.selectFrom("_emdash_content_bylines as cb").innerJoin("_emdash_bylines as b", "b.translation_group", "cb.byline_id").select("cb.id").where("cb.collection_slug", "=", type).whereRef("cb.content_id", "=", idColumn);
983
- sub = filter.locale ? sub.where("b.locale", "=", filter.locale) : sub.whereRef("b.locale", "=", localeColumn);
984
- if (bylineIds) sub = sub.where("cb.byline_id", "in", bylineIds);
985
- return eb.exists(sub);
986
- };
987
- const hasExplicitCredit = (eb) => eb.exists(eb.selectFrom("_emdash_content_bylines as cb").select("cb.id").where("cb.collection_slug", "=", type).whereRef("cb.content_id", "=", idColumn));
988
- const authorHasByline = (eb, bylineIds) => {
989
- let sub = eb.selectFrom("_emdash_bylines as b").select("b.id").whereRef("b.user_id", "=", authorColumn);
990
- sub = filter.locale ? sub.where("b.locale", "=", filter.locale) : sub.whereRef("b.locale", "=", localeColumn);
991
- if (bylineIds) sub = sub.where("b.translation_group", "in", bylineIds);
992
- return eb.exists(sub);
993
- };
994
- if (filter.mode === "none") return query.where((eb) => {
995
- const uncredited = eb.not(creditRenders(eb));
996
- return filter.includeInferred ? eb.and([uncredited, eb.or([hasExplicitCredit(eb), eb.not(authorHasByline(eb))])]) : uncredited;
997
- });
998
- const bylineIds = filter.bylineIds ?? [];
999
- if (bylineIds.length === 0) return query.where(() => sql`1 = 0`);
1000
- return query.where((eb) => {
1001
- if (!filter.includeInferred) return creditRenders(eb, bylineIds);
1002
- return eb.or([creditRenders(eb, bylineIds), eb.and([eb.not(hasExplicitCredit(eb)), authorHasByline(eb, bylineIds)])]);
1003
- });
1004
- }
1005
- /**
1006
- * Count content items
1007
- */
1008
- async count(type, where) {
1009
- const resolvedFieldFilters = await this.resolveFieldFilters(type, where?.fieldFilters);
1010
- return this.countWithResolvedFilters(type, where, resolvedFieldFilters);
1011
- }
1012
- async countWithResolvedFilters(type, where, resolvedFieldFilters) {
1013
- const tableName = getTableName(type);
1014
- let query = this.db.selectFrom(tableName).select((eb) => eb.fn.count("id").as("count")).where("deleted_at", "is", null);
1015
- if (where?.status) query = query.where("status", "=", where.status);
1016
- if (where?.authorId) query = query.where("author_id", "=", where.authorId);
1017
- if (where?.locale) query = query.where("locale", "=", where.locale);
1018
- query = this.applySearchFilter(query, where, type);
1019
- query = this.applyDateFilter(query, where);
1020
- query = this.applyBylineFilter(query, where, type);
1021
- query = this.applyFieldFilters(query, resolvedFieldFilters);
1022
- const result = await query.executeTakeFirst();
1023
- return Number(result?.count || 0);
1024
- }
1025
- /**
1026
- * Distinct, non-null `author_id` values across the collection's live
1027
- * (non-trashed) content. Used to populate the admin author filter with
1028
- * only the users who have actually authored entries, rather than the
1029
- * full user directory (which requires admin privileges to read).
1030
- */
1031
- async findDistinctAuthorIds(type) {
1032
- const tableName = getTableName(type);
1033
- return (await this.db.selectFrom(tableName).select("author_id").distinct().where("deleted_at", "is", null).where("author_id", "is not", null).execute()).map((row) => row.author_id).filter((id) => id !== null);
1034
- }
1035
- async getStats(type, now = /* @__PURE__ */ new Date()) {
1036
- const tableName = getTableName(type);
1037
- const nowIso = now.toISOString();
1038
- const result = await this.db.selectFrom(tableName).select((eb) => [
1039
- eb.fn.count("id").as("total"),
1040
- eb.fn.sum(eb.case().when("status", "=", "published").then(1).else(0).end()).as("published"),
1041
- eb.fn.sum(eb.case().when("status", "=", "draft").then(1).else(0).end()).as("draft"),
1042
- sql`SUM(CASE WHEN scheduled_at IS NOT NULL THEN 1 ELSE 0 END)`.as("scheduled"),
1043
- sql`SUM(CASE WHEN scheduled_at IS NOT NULL AND scheduled_at <= ${nowIso} THEN 1 ELSE 0 END)`.as("overdue_scheduled")
1044
- ]).where("deleted_at", "is", null).executeTakeFirst();
1045
- return {
1046
- total: Number(result?.total || 0),
1047
- published: Number(result?.published || 0),
1048
- draft: Number(result?.draft || 0),
1049
- scheduled: Number(result?.scheduled || 0),
1050
- overdueScheduled: Number(result?.overdue_scheduled || 0)
1051
- };
1052
- }
1053
- /**
1054
- * Schedule content for future publishing
1055
- *
1056
- * Sets status to 'scheduled' and stores the scheduled publish time.
1057
- * The content will be auto-published when the scheduled time is reached.
1058
- */
1059
- async schedule(type, id, scheduledAt) {
1060
- const tableName = getTableName(type);
1061
- const now = (/* @__PURE__ */ new Date()).toISOString();
1062
- const scheduledDate = new Date(scheduledAt);
1063
- if (isNaN(scheduledDate.getTime())) throw new EmDashValidationError("Invalid scheduled date");
1064
- if (scheduledDate <= /* @__PURE__ */ new Date()) throw new EmDashValidationError("Scheduled date must be in the future");
1065
- const existing = await this.findById(type, id);
1066
- if (!existing) throw new EmDashValidationError("Content item not found");
1067
- const newStatus = existing.status === "published" ? "published" : "scheduled";
1068
- await sql`
1069
- UPDATE ${sql.ref(tableName)}
1070
- SET status = ${newStatus},
1071
- scheduled_at = ${scheduledDate.toISOString()},
1072
- updated_at = ${now}
1073
- WHERE id = ${id}
1074
- AND deleted_at IS NULL
1075
- `.execute(this.db);
1076
- invalidateCollectionCache(type);
1077
- const updated = await this.findById(type, id);
1078
- if (!updated) throw new Error("Content not found");
1079
- return updated;
1080
- }
1081
- /**
1082
- * Unschedule content
1083
- *
1084
- * Clears the scheduled time. Published posts stay published;
1085
- * draft/scheduled posts revert to 'draft'.
1086
- */
1087
- async unschedule(type, id) {
1088
- const tableName = getTableName(type);
1089
- const now = (/* @__PURE__ */ new Date()).toISOString();
1090
- const existing = await this.findById(type, id);
1091
- if (!existing) throw new EmDashValidationError("Content item not found");
1092
- const newStatus = existing.status === "published" ? "published" : "draft";
1093
- await sql`
1094
- UPDATE ${sql.ref(tableName)}
1095
- SET status = ${newStatus},
1096
- scheduled_at = NULL,
1097
- updated_at = ${now}
1098
- WHERE id = ${id}
1099
- AND scheduled_at IS NOT NULL
1100
- AND deleted_at IS NULL
1101
- `.execute(this.db);
1102
- invalidateCollectionCache(type);
1103
- const updated = await this.findById(type, id);
1104
- if (!updated) throw new Error("Content not found");
1105
- return updated;
1106
- }
1107
- /**
1108
- * Find content that is ready to be published
1109
- *
1110
- * Returns all content where scheduled_at <= now, regardless of status.
1111
- * This covers both draft-scheduled posts (status='scheduled') and
1112
- * published posts with scheduled draft changes (status='published').
1113
- *
1114
- * `limit` (optional) caps how many due rows are returned, oldest-due first.
1115
- * The scheduled-publishing sweep passes a limit so a large backlog can't
1116
- * fan out unbounded publish/webhook work in a single tick (and blow a Worker
1117
- * invocation's CPU/subrequest budget); the remainder drains on later ticks.
1118
- */
1119
- async findReadyToPublish(type, limit) {
1120
- const tableName = getTableName(type);
1121
- const now = (/* @__PURE__ */ new Date()).toISOString();
1122
- const limitClause = typeof limit === "number" && Number.isInteger(limit) && limit > 0 ? sql`LIMIT ${limit}` : sql``;
1123
- return (await sql`
1124
- SELECT * FROM ${sql.ref(tableName)}
1125
- WHERE scheduled_at IS NOT NULL
1126
- AND scheduled_at <= ${now}
1127
- AND deleted_at IS NULL
1128
- ORDER BY scheduled_at ASC
1129
- ${limitClause}
1130
- `.execute(this.db)).rows.map((row) => this.mapRow(type, row));
1131
- }
1132
- /**
1133
- * Find all translations in a translation group
1134
- */
1135
- async findTranslations(type, translationGroup) {
1136
- const tableName = getTableName(type);
1137
- return (await sql`
1138
- SELECT * FROM ${sql.ref(tableName)}
1139
- WHERE translation_group = ${translationGroup}
1140
- AND deleted_at IS NULL
1141
- ORDER BY locale ASC
1142
- `.execute(this.db)).rows.map((row) => this.mapRow(type, row));
1143
- }
1144
- /**
1145
- * Batch variant of {@link findTranslations}: every (non-deleted) locale
1146
- * variant for any of `translationGroups`, in one `WHERE translation_group IN
1147
- * (...)` query chunked at `SQL_BATCH_SIZE` for D1's bind-parameter limit.
1148
- * Lets callers resolve many edge groups without an N+1 per group. The caller
1149
- * groups the flat result by `translationGroup` itself.
1150
- *
1151
- * `translation_group` leads the sort so the ordering follows
1152
- * `idx_{table}_del_tg_locale` past its `deleted_at` equality; callers group by
1153
- * `translationGroup`, so the per-group locale order they rely on is preserved.
1154
- *
1155
- * `publishedOnly` restricts the result to `status = 'published'` — reference
1156
- * reads pass this for callers without `content:read_drafts` so draft/scheduled
1157
- * entries never leak through an edge traversal.
1158
- *
1159
- * A reference edge stores only a collection slug (no SQL FK), so the table may
1160
- * have been dropped since the edge was written. That is a tolerated dangling
1161
- * state, not an error: a missing table resolves to no rows, mirroring how the
1162
- * content read handlers treat `isMissingTableError`.
1163
- */
1164
- async findTranslationsForGroups(type, translationGroups, options = {}) {
1165
- if (translationGroups.length === 0) return [];
1166
- const tableName = getTableName(type);
1167
- const publishedFilter = options.publishedOnly ? sql`AND status = 'published'` : sql``;
1168
- const items = [];
1169
- try {
1170
- for (const chunk of chunks(translationGroups, SQL_BATCH_SIZE)) {
1171
- const result = await sql`
1172
- SELECT * FROM ${sql.ref(tableName)}
1173
- WHERE translation_group IN (${sql.join(chunk)})
1174
- AND deleted_at IS NULL
1175
- ${publishedFilter}
1176
- ORDER BY translation_group ASC, locale ASC
1177
- `.execute(this.db);
1178
- for (const row of result.rows) items.push(this.mapRow(type, row));
1179
- }
1180
- } catch (error) {
1181
- if (isMissingTableError(error)) return [];
1182
- throw error;
1183
- }
1184
- return items;
1185
- }
1186
- /**
1187
- * Batch variant of {@link findByIdOrSlug}: resolve many identifiers (each an
1188
- * id OR a slug) within `type` in a constant number of queries — one `WHERE id
1189
- * IN (...)` and one `WHERE slug IN (...)`, each chunked at `SQL_BATCH_SIZE`.
1190
- * Returns a map from the input identifier to its resolved item; identifiers
1191
- * that match nothing are absent. Used on write paths that accept a list of
1192
- * references, so a single request doesn't fan out to an N+1 of point lookups.
1193
- *
1194
- * Resolution mirrors {@link findByIdOrSlug}: a ULID-shaped identifier prefers
1195
- * the id match and falls back to slug; anything else prefers the slug match
1196
- * and falls back to id. Slug matches collapse to the lowest-locale variant
1197
- * (`ORDER BY locale ASC`), matching the slug-without-locale lookup.
1198
- */
1199
- async findManyByIdOrSlug(type, identifiers) {
1200
- const resolved = /* @__PURE__ */ new Map();
1201
- const unique = [...new Set(identifiers)];
1202
- if (unique.length === 0) return resolved;
1203
- const tableName = getTableName(type);
1204
- const byId = /* @__PURE__ */ new Map();
1205
- const bySlug = /* @__PURE__ */ new Map();
1206
- try {
1207
- for (const chunk of chunks(unique, SQL_BATCH_SIZE)) {
1208
- const idRows = await sql`
1209
- SELECT * FROM ${sql.ref(tableName)}
1210
- WHERE id IN (${sql.join(chunk)})
1211
- AND deleted_at IS NULL
1212
- `.execute(this.db);
1213
- for (const row of idRows.rows) {
1214
- const item = this.mapRow(type, row);
1215
- byId.set(item.id, item);
1216
- }
1217
- const slugRows = await sql`
1218
- SELECT * FROM ${sql.ref(tableName)}
1219
- WHERE slug IN (${sql.join(chunk)})
1220
- AND deleted_at IS NULL
1221
- ORDER BY locale ASC
1222
- `.execute(this.db);
1223
- for (const row of slugRows.rows) {
1224
- const item = this.mapRow(type, row);
1225
- if (item.slug != null && !bySlug.has(item.slug)) bySlug.set(item.slug, item);
1226
- }
1227
- }
1228
- } catch (error) {
1229
- if (isMissingTableError(error)) return resolved;
1230
- throw error;
1231
- }
1232
- for (const identifier of unique) {
1233
- const item = ULID_PATTERN.test(identifier) ? byId.get(identifier) ?? bySlug.get(identifier) : bySlug.get(identifier) ?? byId.get(identifier);
1234
- if (item) resolved.set(identifier, item);
1235
- }
1236
- return resolved;
1237
- }
1238
- /**
1239
- * Publish the current draft
1240
- *
1241
- * Promotes draft_revision_id to live_revision_id and clears draft pointer.
1242
- * Syncs the draft revision's data into the content table columns so the
1243
- * content table always reflects the published version.
1244
- * If no draft revision exists, creates one from current data and publishes it.
1245
- * When `promoteRevision` is false, publishes the current content-table data
1246
- * by changing lifecycle metadata only.
1247
- *
1248
- * `publishedAt` (optional) overrides the publication timestamp. If omitted,
1249
- * the existing `published_at` is preserved (idempotent re-publish keeps the
1250
- * original date) and falls back to the current time on first publish. Pass
1251
- * an explicit value to backdate a publish (e.g. when migrating content from
1252
- * another CMS).
1253
- *
1254
- * `requireDue` gates the final update on the row still being due.
1255
- * `expectedScheduledAt` additionally fences changes made after a sweep
1256
- * selected the row but before publication preparation began.
1257
- */
1258
- async publish(type, id, publishedAt, requireDue = false, expectedScheduledAt, promoteRevision = true, requireSlug = true, expectedRevision) {
1259
- const tableName = getTableName(type);
1260
- const now = (/* @__PURE__ */ new Date()).toISOString();
1261
- const existing = await this.findById(type, id);
1262
- if (!existing) throw new EmDashValidationError("Content item not found");
1263
- assertRevisionPrecondition(existing, expectedRevision);
1264
- if (requireDue && expectedScheduledAt !== void 0 && existing.scheduledAt !== expectedScheduledAt) throw new ScheduledNotDueError();
1265
- if (!promoteRevision && requireSlug && !existing.slug?.trim()) throw new EmDashValidationError("Cannot publish routable content without a slug");
1266
- if (!promoteRevision) {
1267
- const revisionRepo = new RevisionRepository(this.db);
1268
- let provisionalRevisionId = null;
1269
- try {
1270
- let liveRevisionId = existing.liveRevisionId;
1271
- if (!liveRevisionId) {
1272
- const revision = await revisionRepo.create({
1273
- collection: type,
1274
- entryId: id,
1275
- data: existing.data
1276
- });
1277
- liveRevisionId = revision.id;
1278
- provisionalRevisionId = revision.id;
1279
- }
1280
- const intendedPublishedAt = publishedAt ?? existing.publishedAt ?? now;
1281
- const duePredicate = requireDue ? sql`AND scheduled_at IS NOT NULL AND scheduled_at <= ${now}` : sql``;
1282
- let published = false;
1283
- try {
1284
- published = ((await sql`
1285
- UPDATE ${sql.ref(tableName)}
1286
- SET live_revision_id = ${liveRevisionId},
1287
- draft_revision_id = NULL,
1288
- status = 'published',
1289
- scheduled_at = NULL,
1290
- published_at = ${intendedPublishedAt},
1291
- updated_at = ${now},
1292
- version = version + 1
1293
- WHERE id = ${id}
1294
- AND deleted_at IS NULL
1295
- AND version = ${existing.version}
1296
- AND updated_at = ${existing.updatedAt}
1297
- AND status = ${existing.status}
1298
- AND ${nullableColumnMatch("live_revision_id", existing.liveRevisionId)}
1299
- AND ${nullableColumnMatch("draft_revision_id", existing.draftRevisionId)}
1300
- AND ${nullableColumnMatch("scheduled_at", existing.scheduledAt)}
1301
- ${duePredicate}
1302
- `.execute(this.db)).numAffectedRows ?? 0n) > 0n;
1303
- } catch (error) {
1304
- if (isConfirmedStatementFailure(error)) throw error;
1305
- let observed;
1306
- try {
1307
- observed = await this.findById(type, id);
1308
- } catch (reconciliationError) {
1309
- throw new Error("Unable to confirm whether content publication completed", { cause: reconciliationError });
1310
- }
1311
- if (!observed) throw new Error("Unable to confirm whether content publication completed", { cause: error });
1312
- published = matchesLifecyclePublication(observed, existing, liveRevisionId, intendedPublishedAt, now);
1313
- if (!published && matchesPublicationFence(observed, existing)) throw error;
1314
- if (!published) throw new Error("Unable to confirm whether content publication completed", { cause: error });
1315
- }
1316
- if (!published) throw requireDue ? new ScheduledNotDueError() : new ContentMutationConflictError();
1317
- invalidateCollectionCache(type);
1318
- const updated = await this.findById(type, id);
1319
- if (!updated) throw new Error("Content not found");
1320
- return updated;
1321
- } catch (error) {
1322
- if (provisionalRevisionId) try {
1323
- await revisionRepo.deleteIfUnreferenced(type, id, provisionalRevisionId);
1324
- } catch (cleanupError) {
1325
- console.error(`[content] Failed to clean up provisional revision ${provisionalRevisionId}:`, cleanupError);
1326
- }
1327
- throw error;
1328
- }
1329
- }
1330
- const revisionRepo = new RevisionRepository(this.db);
1331
- let provisionalRevisionId = null;
1332
- try {
1333
- let revisionToPublish = existing.draftRevisionId || existing.liveRevisionId;
1334
- if (!revisionToPublish) {
1335
- const revision = await revisionRepo.create({
1336
- collection: type,
1337
- entryId: id,
1338
- data: existing.data
1339
- });
1340
- revisionToPublish = revision.id;
1341
- provisionalRevisionId = revision.id;
1342
- }
1343
- const revision = await revisionRepo.findById(revisionToPublish);
1344
- if (!revision || revision.collection !== type || revision.entryId !== id) throw new EmDashValidationError("Revision does not belong to the specified content item");
1345
- const stagedSlug = typeof revision.data._slug === "string" ? revision.data._slug : null;
1346
- const intendedSlug = stagedSlug ?? existing.slug;
1347
- if (requireSlug && !intendedSlug?.trim()) throw new EmDashValidationError("Cannot publish routable content without a slug");
1348
- const intendedPublishedAt = publishedAt ?? existing.publishedAt ?? now;
1349
- if (stagedSlug !== null && stagedSlug !== existing.slug && existing.locale !== null) {
1350
- const conflict = await this.findBySlugIncludingTrashed(type, stagedSlug, existing.locale);
1351
- if (conflict && conflict.id !== id) throw new EmDashValidationError(`Cannot publish: slug '${stagedSlug}' is already used by another entry in this collection (id: ${conflict.id}). Choose a different slug.`, { code: "SLUG_CONFLICT" });
1352
- }
1353
- const assignments = [];
1354
- if (stagedSlug !== null) assignments.push(sql`slug = ${stagedSlug}`);
1355
- for (const [key, value] of Object.entries(revision.data)) {
1356
- if (SYSTEM_COLUMNS.has(key) || key.startsWith("_")) continue;
1357
- validateIdentifier(key, "content field name");
1358
- assignments.push(sql`${sql.ref(key)} = ${serializeValue(value)}`);
1359
- }
1360
- assignments.push(sql`live_revision_id = ${revisionToPublish}`, sql`draft_revision_id = NULL`, sql`status = 'published'`, sql`scheduled_at = NULL`, sql`published_at = ${intendedPublishedAt}`, sql`updated_at = ${now}`, sql`version = version + 1`);
1361
- const duePredicate = requireDue ? sql`AND scheduled_at IS NOT NULL AND scheduled_at <= ${now}` : sql``;
1362
- let promoted = false;
1363
- try {
1364
- promoted = ((await sql`
1365
- UPDATE ${sql.ref(tableName)}
1366
- SET ${sql.join(assignments, sql`, `)}
1367
- WHERE id = ${id}
1368
- AND deleted_at IS NULL
1369
- AND version = ${existing.version}
1370
- AND updated_at = ${existing.updatedAt}
1371
- AND status = ${existing.status}
1372
- AND ${nullableColumnMatch("live_revision_id", existing.liveRevisionId)}
1373
- AND ${nullableColumnMatch("draft_revision_id", existing.draftRevisionId)}
1374
- AND ${nullableColumnMatch("scheduled_at", existing.scheduledAt)}
1375
- ${duePredicate}
1376
- AND EXISTS (
1377
- SELECT 1 FROM revisions
1378
- WHERE revisions.id = ${revisionToPublish}
1379
- AND revisions.collection = ${type}
1380
- AND revisions.entry_id = ${id}
1381
- )
1382
- `.execute(this.db)).numAffectedRows ?? 0n) > 0n;
1383
- } catch (error) {
1384
- if (isConfirmedStatementFailure(error)) throw error;
1385
- let observed;
1386
- try {
1387
- observed = await this.findById(type, id);
1388
- } catch (reconciliationError) {
1389
- throw new Error("Unable to confirm whether content publication completed", { cause: reconciliationError });
1390
- }
1391
- if (!observed) throw new Error("Unable to confirm whether content publication completed", { cause: error });
1392
- promoted = matchesPublication(observed, existing, revision, revisionToPublish, intendedSlug, intendedPublishedAt, now);
1393
- if (!promoted && matchesPublicationFence(observed, existing)) throw error;
1394
- if (!promoted) throw new Error("Unable to confirm whether content publication completed", { cause: error });
1395
- }
1396
- if (!promoted) throw requireDue ? new ScheduledNotDueError() : new ContentMutationConflictError();
1397
- invalidateCollectionCache(type);
1398
- const updated = await this.findById(type, id);
1399
- if (!updated) throw new Error("Content not found");
1400
- return updated;
1401
- } catch (error) {
1402
- if (provisionalRevisionId) try {
1403
- await revisionRepo.deleteIfUnreferenced(type, id, provisionalRevisionId);
1404
- } catch (cleanupError) {
1405
- console.error(`[content] Failed to clean up provisional revision ${provisionalRevisionId}:`, cleanupError);
1406
- }
1407
- throw error;
1408
- }
1409
- }
1410
- /**
1411
- * Unpublish content
1412
- *
1413
- * Removes live pointer but preserves the draft and publication date. If no
1414
- * draft exists, creates one from the live version so the content isn't lost.
1415
- */
1416
- async unpublish(type, id, expectedRevision) {
1417
- const tableName = getTableName(type);
1418
- const now = (/* @__PURE__ */ new Date()).toISOString();
1419
- const existing = await this.findById(type, id);
1420
- if (!existing) throw new EmDashValidationError("Content item not found");
1421
- assertRevisionPrecondition(existing, expectedRevision);
1422
- if (existing.status === "draft" && !existing.liveRevisionId) return existing;
1423
- const revisionRepo = new RevisionRepository(this.db);
1424
- let provisionalRevisionId = null;
1425
- try {
1426
- let draftRevisionId = existing.draftRevisionId;
1427
- if (!draftRevisionId && existing.liveRevisionId) {
1428
- const liveRevision = await revisionRepo.findById(existing.liveRevisionId);
1429
- if (liveRevision) {
1430
- const draft = await revisionRepo.create({
1431
- collection: type,
1432
- entryId: id,
1433
- data: liveRevision.data
1434
- });
1435
- draftRevisionId = draft.id;
1436
- provisionalRevisionId = draft.id;
1437
- }
1438
- }
1439
- if (((await sql`
1440
- UPDATE ${sql.ref(tableName)}
1441
- SET live_revision_id = NULL,
1442
- draft_revision_id = ${draftRevisionId},
1443
- status = 'draft',
1444
- updated_at = ${now},
1445
- version = version + 1
1446
- WHERE id = ${id}
1447
- AND deleted_at IS NULL
1448
- AND version = ${existing.version}
1449
- AND updated_at = ${existing.updatedAt}
1450
- AND status = ${existing.status}
1451
- AND ${nullableColumnMatch("live_revision_id", existing.liveRevisionId)}
1452
- AND ${nullableColumnMatch("draft_revision_id", existing.draftRevisionId)}
1453
- AND ${nullableColumnMatch("scheduled_at", existing.scheduledAt)}
1454
- `.execute(this.db)).numAffectedRows ?? 0n) === 0n) throw new ContentMutationConflictError();
1455
- invalidateCollectionCache(type);
1456
- const updated = await this.findById(type, id);
1457
- if (!updated) throw new Error("Content not found");
1458
- return updated;
1459
- } catch (error) {
1460
- if (provisionalRevisionId) try {
1461
- await revisionRepo.deleteIfUnreferenced(type, id, provisionalRevisionId);
1462
- } catch (cleanupError) {
1463
- console.error(`[content] Failed to clean up provisional revision ${provisionalRevisionId}:`, cleanupError);
1464
- }
1465
- throw error;
1466
- }
1467
- }
1468
- /**
1469
- * Set the draft revision pointer for a content item.
1470
- *
1471
- * Used by seed/import paths that stage a new revision's data before
1472
- * promoting it to live via `publish()`.
1473
- *
1474
- * Validates that the content item exists and is not soft-deleted, that
1475
- * the revision exists, and that the revision belongs to the same
1476
- * collection and entry. Without these checks, a caller could leave the
1477
- * content row pointing at a missing or unrelated revision.
1478
- */
1479
- async setDraftRevision(type, id, revisionId) {
1480
- const existing = await this.findById(type, id);
1481
- if (!existing) throw new EmDashValidationError("Content item not found");
1482
- const revision = await new RevisionRepository(this.db).findById(revisionId);
1483
- if (!revision) throw new EmDashValidationError("Revision not found");
1484
- if (revision.collection !== type || revision.entryId !== id) throw new EmDashValidationError("Revision does not belong to the specified content item");
1485
- if (!await this.replaceDraftRevision(type, id, revisionId, existing)) throw new ContentMutationConflictError();
1486
- }
1487
- async replaceDraftRevision(type, id, revisionId, expected) {
1488
- const tableName = getTableName(type);
1489
- return ((await sql`
1490
- UPDATE ${sql.ref(tableName)}
1491
- SET draft_revision_id = ${revisionId},
1492
- version = version + 1
1493
- WHERE id = ${id}
1494
- AND deleted_at IS NULL
1495
- AND version = ${expected.version}
1496
- AND ${nullableColumnMatch("live_revision_id", expected.liveRevisionId)}
1497
- AND ${nullableColumnMatch("draft_revision_id", expected.draftRevisionId)}
1498
- AND EXISTS (
1499
- SELECT 1 FROM revisions
1500
- WHERE revisions.id = ${revisionId}
1501
- AND revisions.collection = ${type}
1502
- AND revisions.entry_id = ${id}
1503
- )
1504
- `.execute(this.db)).numAffectedRows ?? 0n) > 0n;
1505
- }
1506
- /**
1507
- * Discard pending draft changes
1508
- *
1509
- * Clears draft_revision_id. The content table columns already hold the
1510
- * published version, so no data sync is needed.
1511
- */
1512
- async discardDraft(type, id, expectedRevision) {
1513
- const tableName = getTableName(type);
1514
- const existing = await this.findById(type, id);
1515
- if (!existing) throw new EmDashValidationError("Content item not found");
1516
- assertRevisionPrecondition(existing, expectedRevision);
1517
- if (!existing.draftRevisionId) return existing;
1518
- if (((await sql`
1519
- UPDATE ${sql.ref(tableName)}
1520
- SET draft_revision_id = NULL,
1521
- version = version + 1
1522
- WHERE id = ${id}
1523
- AND deleted_at IS NULL
1524
- AND version = ${existing.version}
1525
- AND updated_at = ${existing.updatedAt}
1526
- AND status = ${existing.status}
1527
- AND ${nullableColumnMatch("live_revision_id", existing.liveRevisionId)}
1528
- AND ${nullableColumnMatch("draft_revision_id", existing.draftRevisionId)}
1529
- AND ${nullableColumnMatch("scheduled_at", existing.scheduledAt)}
1530
- `.execute(this.db)).numAffectedRows ?? 0n) === 0n) throw new ContentMutationConflictError();
1531
- const updated = await this.findById(type, id);
1532
- if (!updated) throw new Error("Content not found");
1533
- return updated;
1534
- }
1535
- /**
1536
- * Count content items with a pending schedule.
1537
- * Includes both draft-scheduled (status='scheduled') and published
1538
- * posts with scheduled draft changes (status='published', scheduled_at set).
1539
- */
1540
- async countScheduled(type) {
1541
- const tableName = getTableName(type);
1542
- const result = await sql`
1543
- SELECT COUNT(id) as count FROM ${sql.ref(tableName)}
1544
- WHERE scheduled_at IS NOT NULL
1545
- AND deleted_at IS NULL
1546
- `.execute(this.db);
1547
- return Number(result.rows[0]?.count || 0);
1548
- }
1549
- /**
1550
- * Map database row to ContentItem
1551
- * Extracts system columns and puts content fields in data
1552
- * Excludes null values from data to match input semantics
1553
- */
1554
- mapRow(type, row) {
1555
- const data = {};
1556
- for (const [key, value] of Object.entries(row)) if (!SYSTEM_COLUMNS.has(key) && value !== null) data[key] = deserializeValue(value);
1557
- return {
1558
- id: row.id,
1559
- type,
1560
- slug: row.slug,
1561
- status: row.status,
1562
- data,
1563
- authorId: row.author_id,
1564
- primaryBylineId: row.primary_byline_id ?? null,
1565
- createdAt: row.created_at,
1566
- updatedAt: row.updated_at,
1567
- publishedAt: row.published_at,
1568
- scheduledAt: row.scheduled_at,
1569
- liveRevisionId: row.live_revision_id ?? null,
1570
- draftRevisionId: row.draft_revision_id ?? null,
1571
- version: typeof row.version === "number" ? row.version : 1,
1572
- locale: row.locale ?? null,
1573
- translationGroup: row.translation_group ?? null
1574
- };
1575
- }
1576
- normalizeFilterScalar(field, type, value) {
1577
- if (type === "number" || type === "integer") {
1578
- if (typeof value !== "number" || !Number.isFinite(value)) throw new EmDashValidationError(`Filter for field "${field}" must use a finite number`);
1579
- if (type === "integer" && !Number.isInteger(value)) throw new EmDashValidationError(`Filter for field "${field}" must use an integer`);
1580
- return value;
1581
- }
1582
- if (type === "boolean") {
1583
- if (typeof value !== "boolean") throw new EmDashValidationError(`Filter for field "${field}" must use a boolean`);
1584
- return value ? 1 : 0;
1585
- }
1586
- if (typeof value !== "string") throw new EmDashValidationError(`Filter for field "${field}" must use a string`);
1587
- if (value.length > MAX_FILTER_STRING_LENGTH) throw new EmDashValidationError(`Filter value for field "${field}" exceeds ${MAX_FILTER_STRING_LENGTH} characters`);
1588
- return value;
1589
- }
1590
- normalizeFieldFilter(field, type, value) {
1591
- if (value === null) return {
1592
- column: field,
1593
- kind: "null"
1594
- };
1595
- if (typeof value !== "object") return {
1596
- column: field,
1597
- kind: "exact",
1598
- value: this.normalizeFilterScalar(field, type, value)
1599
- };
1600
- if (Array.isArray(value)) throw new EmDashValidationError(`Invalid filter for field "${field}"`);
1601
- const record = value;
1602
- const keys = Object.keys(record);
1603
- if (keys.length === 1 && keys[0] === "in") {
1604
- if (!Array.isArray(record.in) || record.in.length === 0) throw new EmDashValidationError(`IN filter for field "${field}" must not be empty`);
1605
- if (record.in.length > MAX_IN_FILTER_VALUES) throw new EmDashValidationError(`IN filter for field "${field}" exceeds ${MAX_IN_FILTER_VALUES} values`);
1606
- return {
1607
- column: field,
1608
- kind: "in",
1609
- values: record.in.map((entry) => this.normalizeFilterScalar(field, type, entry))
1610
- };
1611
- }
1612
- const rangeKeys = new Set([
1613
- "gt",
1614
- "gte",
1615
- "lt",
1616
- "lte"
1617
- ]);
1618
- if (keys.length === 0 || keys.some((key) => !rangeKeys.has(key))) throw new EmDashValidationError(`Invalid filter operator for field "${field}"`);
1619
- if (type === "boolean") throw new EmDashValidationError(`Boolean field "${field}" does not support range filters`);
1620
- const bounds = {};
1621
- for (const key of keys) {
1622
- if (record[key] === void 0) continue;
1623
- bounds[key] = this.normalizeFilterScalar(field, type, record[key]);
1624
- }
1625
- if (Object.keys(bounds).length === 0) throw new EmDashValidationError(`Range filter for field "${field}" has no bounds`);
1626
- return {
1627
- column: field,
1628
- kind: "range",
1629
- bounds
1630
- };
1631
- }
1632
- async collectionExists(type) {
1633
- return await this.db.selectFrom("_emdash_collections").where("slug", "=", type).select("id").executeTakeFirst() !== void 0;
1634
- }
1635
- async resolveFieldFilters(type, filters) {
1636
- const resolvedFilters = filters ?? {};
1637
- const fields = Object.keys(resolvedFilters);
1638
- if (fields.length === 0) return [];
1639
- if (fields.length > MAX_INDEXED_FIELD_FILTERS) {
1640
- if (!await this.collectionExists(type)) return [];
1641
- throw new EmDashValidationError(`Content list queries support at most ${MAX_INDEXED_FIELD_FILTERS} indexed field filters`);
1642
- }
1643
- const rows = await this.db.selectFrom("_emdash_fields as field").innerJoin("_emdash_collections as collection", "collection.id", "field.collection_id").where("collection.slug", "=", type).where("field.slug", "in", fields).where("field.indexed", "=", 1).select(["field.slug", "field.type"]).execute();
1644
- const metadata = new Map(rows.map((row) => [row.slug, row.type]));
1645
- if (metadata.size === 0 && !await this.collectionExists(type)) return [];
1646
- for (const field of fields) try {
1647
- validateIdentifier(field, "content filter field");
1648
- } catch {
1649
- throw new EmDashValidationError(`Invalid content filter field: ${field}`);
1650
- }
1651
- const normalized = fields.map((field) => {
1652
- const fieldType = metadata.get(field);
1653
- if (!fieldType || !isIndexableFieldType(fieldType)) throw new EmDashValidationError(`Cannot filter by field "${field}". Custom fields must be indexed before filtering.`);
1654
- return this.normalizeFieldFilter(field, fieldType, resolvedFilters[field]);
1655
- });
1656
- if (normalized.reduce((total, filter) => {
1657
- if (filter.kind === "null") return total;
1658
- if (filter.kind === "exact") return total + 1;
1659
- if (filter.kind === "in") return total + filter.values.length;
1660
- return total + Object.keys(filter.bounds).length;
1661
- }, 0) > SQL_BATCH_SIZE) throw new EmDashValidationError(`Indexed field filters have a total operand budget of ${SQL_BATCH_SIZE}`);
1662
- return normalized;
1663
- }
1664
- applyFieldFilters(query, filters) {
1665
- let next = query;
1666
- for (const filter of filters) {
1667
- const column = sql.ref(filter.column);
1668
- const isPresent = sql`${column} IS NOT NULL`;
1669
- if (filter.kind === "null") {
1670
- next = next.where(() => sql`(${isPresent}) = FALSE AND ${column} IS NULL`);
1671
- continue;
1672
- }
1673
- if (filter.kind === "exact") {
1674
- next = next.where(() => sql`(${isPresent}) = TRUE AND ${column} = ${filter.value}`);
1675
- continue;
1676
- }
1677
- if (filter.kind === "in") {
1678
- const values = sql.join(filter.values.map((value) => sql`${value}`), sql`, `);
1679
- next = next.where(() => sql`(${isPresent}) = TRUE AND ${column} IN (${values})`);
1680
- continue;
1681
- }
1682
- next = next.where(() => sql`(${isPresent}) = TRUE`);
1683
- if (filter.bounds.gt !== void 0) next = next.where(() => sql`${column} > ${filter.bounds.gt}`);
1684
- if (filter.bounds.gte !== void 0) next = next.where(() => sql`${column} >= ${filter.bounds.gte}`);
1685
- if (filter.bounds.lt !== void 0) next = next.where(() => sql`${column} < ${filter.bounds.lt}`);
1686
- if (filter.bounds.lte !== void 0) next = next.where(() => sql`${column} <= ${filter.bounds.lte}`);
1687
- }
1688
- return next;
1689
- }
1690
- /**
1691
- * Map order field names to database columns.
1692
- * Only allows known fields to prevent column enumeration via crafted orderBy values.
1693
- */
1694
- mapOrderField(field, sortableExtras = []) {
1695
- const mapped = ORDER_FIELD_COLUMNS[field];
1696
- if (mapped) return mapped;
1697
- if (sortableExtras.includes(field)) {
1698
- validateIdentifier(field, "order field");
1699
- return field;
1700
- }
1701
- throw new EmDashValidationError(`Invalid order field: ${field}`);
1702
- }
1703
- async resolveOrderField(type, field, sortableExtras = []) {
1704
- try {
1705
- return {
1706
- column: this.mapOrderField(field, sortableExtras),
1707
- indexedCustomField: false
1708
- };
1709
- } catch (error) {
1710
- if (!(error instanceof EmDashValidationError)) throw error;
1711
- }
1712
- const customField = await this.db.selectFrom("_emdash_collections as collection").leftJoin("_emdash_fields as field", (join) => join.onRef("field.collection_id", "=", "collection.id").on("field.slug", "=", field).on("field.indexed", "=", 1)).where("collection.slug", "=", type).select(["collection.id as collectionId", "field.slug as fieldSlug"]).executeTakeFirst();
1713
- if (!customField) throw new ContentCollectionNotFoundError(type);
1714
- if (!customField.fieldSlug) throw new EmDashValidationError(`Invalid order field: ${field}. Custom fields must be indexed before sorting.`);
1715
- validateIdentifier(customField.fieldSlug, "content order field");
1716
- return {
1717
- column: customField.fieldSlug,
1718
- indexedCustomField: true
1719
- };
1720
- }
1721
- };
1722
-
1723
- //#endregion
1724
- export { RevisionRepository as i, content_exports as n, isSystemOrderField as r, ContentRepository as t };
1725
- //# sourceMappingURL=content-DjvM0T92.mjs.map