emdash 0.32.0 → 0.34.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 (946) hide show
  1. package/dist/{adapters-C0ONzkUP.d.mts → adapters-34EN2eXO.d.mts} +34 -2
  2. package/dist/adapters-34EN2eXO.d.mts.map +1 -0
  3. package/dist/after-CBU2vkoO.mjs +96 -0
  4. package/dist/after-CBU2vkoO.mjs.map +1 -0
  5. package/dist/{allowed-origins-CCEi9bPI.mjs → allowed-origins-DW7sYyqg.mjs} +2 -2
  6. package/dist/{allowed-origins-CCEi9bPI.mjs.map → allowed-origins-DW7sYyqg.mjs.map} +1 -1
  7. package/dist/api/route-utils.d.mts +3 -4
  8. package/dist/api/route-utils.d.mts.map +1 -1
  9. package/dist/api/route-utils.mjs +26 -25
  10. package/dist/api/route-utils.mjs.map +1 -1
  11. package/dist/api/schemas/index.d.mts +2 -2
  12. package/dist/api/schemas/index.mjs +6 -5
  13. package/dist/{api-DgPbMlng.mjs → api-DdAsirBe.mjs} +321 -428
  14. package/dist/api-DdAsirBe.mjs.map +1 -0
  15. package/dist/{api-tokens-p-iMzvXR.mjs → api-tokens-CFXu8F_2.mjs} +2 -2
  16. package/dist/{api-tokens-p-iMzvXR.mjs.map → api-tokens-CFXu8F_2.mjs.map} +1 -1
  17. package/dist/{apply-1_6ra7NP.mjs → apply-D5zfeD09.mjs} +139 -102
  18. package/dist/apply-D5zfeD09.mjs.map +1 -0
  19. package/dist/astro/index.d.mts +12 -12
  20. package/dist/astro/index.d.mts.map +1 -1
  21. package/dist/astro/index.mjs +103 -35
  22. package/dist/astro/index.mjs.map +1 -1
  23. package/dist/astro/middleware/auth.d.mts +10 -10
  24. package/dist/astro/middleware/auth.mjs +9 -9
  25. package/dist/astro/middleware/media-usage-write-fence.d.mts +7 -0
  26. package/dist/astro/middleware/media-usage-write-fence.d.mts.map +1 -0
  27. package/dist/astro/middleware/media-usage-write-fence.mjs +35 -0
  28. package/dist/astro/middleware/media-usage-write-fence.mjs.map +1 -0
  29. package/dist/astro/middleware/redirect.d.mts.map +1 -1
  30. package/dist/astro/middleware/redirect.mjs +13 -10
  31. package/dist/astro/middleware/redirect.mjs.map +1 -1
  32. package/dist/astro/middleware/request-context.mjs +5 -5
  33. package/dist/astro/middleware/setup.mjs +1 -1
  34. package/dist/astro/middleware.d.mts +12 -11
  35. package/dist/astro/middleware.d.mts.map +1 -1
  36. package/dist/astro/middleware.mjs +1915 -223
  37. package/dist/astro/middleware.mjs.map +1 -1
  38. package/dist/astro/routes/api/admin/allowed-domains/_domain_.mjs +9 -8
  39. package/dist/astro/routes/api/admin/allowed-domains/_domain_.mjs.map +1 -1
  40. package/dist/astro/routes/api/admin/allowed-domains/index.mjs +9 -8
  41. package/dist/astro/routes/api/admin/allowed-domains/index.mjs.map +1 -1
  42. package/dist/astro/routes/api/admin/api-tokens/_id_.mjs +5 -5
  43. package/dist/astro/routes/api/admin/api-tokens/index.mjs +6 -6
  44. package/dist/astro/routes/api/admin/byline-fields/_slug_/usage.mjs +6 -6
  45. package/dist/astro/routes/api/admin/byline-fields/_slug_.mjs +12 -11
  46. package/dist/astro/routes/api/admin/byline-fields/_slug_.mjs.map +1 -1
  47. package/dist/astro/routes/api/admin/byline-fields/index.mjs +12 -11
  48. package/dist/astro/routes/api/admin/byline-fields/index.mjs.map +1 -1
  49. package/dist/astro/routes/api/admin/byline-fields/reorder.mjs +12 -11
  50. package/dist/astro/routes/api/admin/byline-fields/reorder.mjs.map +1 -1
  51. package/dist/astro/routes/api/admin/bylines/_id_/index.mjs +20 -20
  52. package/dist/astro/routes/api/admin/bylines/_id_/translations.mjs +20 -20
  53. package/dist/astro/routes/api/admin/bylines/index.mjs +20 -20
  54. package/dist/astro/routes/api/admin/comments/_id_/status.mjs +18 -17
  55. package/dist/astro/routes/api/admin/comments/_id_/status.mjs.map +1 -1
  56. package/dist/astro/routes/api/admin/comments/_id_.mjs +8 -8
  57. package/dist/astro/routes/api/admin/comments/bulk.mjs +14 -13
  58. package/dist/astro/routes/api/admin/comments/bulk.mjs.map +1 -1
  59. package/dist/astro/routes/api/admin/comments/counts.mjs +8 -8
  60. package/dist/astro/routes/api/admin/comments/index.mjs +14 -13
  61. package/dist/astro/routes/api/admin/comments/index.mjs.map +1 -1
  62. package/dist/astro/routes/api/admin/hooks/exclusive/_hookName_.mjs +6 -6
  63. package/dist/astro/routes/api/admin/hooks/exclusive/index.mjs +5 -5
  64. package/dist/astro/routes/api/admin/media-usage/collection-deletions/index.d.mts +8 -0
  65. package/dist/astro/routes/api/admin/media-usage/collection-deletions/index.d.mts.map +1 -0
  66. package/dist/astro/routes/api/admin/media-usage/collection-deletions/index.mjs +36 -0
  67. package/dist/astro/routes/api/admin/media-usage/collection-deletions/index.mjs.map +1 -0
  68. package/dist/astro/routes/api/admin/media-usage/collection-deletions/retry.d.mts +8 -0
  69. package/dist/astro/routes/api/admin/media-usage/collection-deletions/retry.d.mts.map +1 -0
  70. package/dist/astro/routes/api/admin/media-usage/collection-deletions/retry.mjs +36 -0
  71. package/dist/astro/routes/api/admin/media-usage/collection-deletions/retry.mjs.map +1 -0
  72. package/dist/astro/routes/api/admin/media-usage/repair.mjs +15 -14
  73. package/dist/astro/routes/api/admin/media-usage/repair.mjs.map +1 -1
  74. package/dist/astro/routes/api/admin/media-usage/work/index.d.mts +8 -0
  75. package/dist/astro/routes/api/admin/media-usage/work/index.d.mts.map +1 -0
  76. package/dist/astro/routes/api/admin/media-usage/work/index.mjs +37 -0
  77. package/dist/astro/routes/api/admin/media-usage/work/index.mjs.map +1 -0
  78. package/dist/astro/routes/api/admin/media-usage/work/retry.d.mts +8 -0
  79. package/dist/astro/routes/api/admin/media-usage/work/retry.d.mts.map +1 -0
  80. package/dist/astro/routes/api/admin/media-usage/work/retry.mjs +37 -0
  81. package/dist/astro/routes/api/admin/media-usage/work/retry.mjs.map +1 -0
  82. package/dist/astro/routes/api/admin/oauth-clients/_id_.mjs +5 -5
  83. package/dist/astro/routes/api/admin/oauth-clients/index.mjs +5 -5
  84. package/dist/astro/routes/api/admin/plugins/_id_/disable.d.mts.map +1 -1
  85. package/dist/astro/routes/api/admin/plugins/_id_/disable.mjs +56 -47
  86. package/dist/astro/routes/api/admin/plugins/_id_/disable.mjs.map +1 -1
  87. package/dist/astro/routes/api/admin/plugins/_id_/enable.d.mts.map +1 -1
  88. package/dist/astro/routes/api/admin/plugins/_id_/enable.mjs +56 -47
  89. package/dist/astro/routes/api/admin/plugins/_id_/enable.mjs.map +1 -1
  90. package/dist/astro/routes/api/admin/plugins/_id_/index.mjs +52 -46
  91. package/dist/astro/routes/api/admin/plugins/_id_/index.mjs.map +1 -1
  92. package/dist/astro/routes/api/admin/plugins/_id_/mcp.mjs +6 -6
  93. package/dist/astro/routes/api/admin/plugins/_id_/settings.mjs +52 -46
  94. package/dist/astro/routes/api/admin/plugins/_id_/settings.mjs.map +1 -1
  95. package/dist/astro/routes/api/admin/plugins/_id_/uninstall.d.mts.map +1 -1
  96. package/dist/astro/routes/api/admin/plugins/_id_/uninstall.mjs +55 -46
  97. package/dist/astro/routes/api/admin/plugins/_id_/uninstall.mjs.map +1 -1
  98. package/dist/astro/routes/api/admin/plugins/_id_/update.d.mts.map +1 -1
  99. package/dist/astro/routes/api/admin/plugins/_id_/update.mjs +55 -46
  100. package/dist/astro/routes/api/admin/plugins/_id_/update.mjs.map +1 -1
  101. package/dist/astro/routes/api/admin/plugins/index.mjs +52 -46
  102. package/dist/astro/routes/api/admin/plugins/index.mjs.map +1 -1
  103. package/dist/astro/routes/api/admin/plugins/marketplace/_id_/icon.mjs +4 -4
  104. package/dist/astro/routes/api/admin/plugins/marketplace/_id_/index.mjs +52 -46
  105. package/dist/astro/routes/api/admin/plugins/marketplace/_id_/index.mjs.map +1 -1
  106. package/dist/astro/routes/api/admin/plugins/marketplace/_id_/install.d.mts.map +1 -1
  107. package/dist/astro/routes/api/admin/plugins/marketplace/_id_/install.mjs +55 -46
  108. package/dist/astro/routes/api/admin/plugins/marketplace/_id_/install.mjs.map +1 -1
  109. package/dist/astro/routes/api/admin/plugins/marketplace/index.mjs +52 -46
  110. package/dist/astro/routes/api/admin/plugins/marketplace/index.mjs.map +1 -1
  111. package/dist/astro/routes/api/admin/plugins/registry/_id_/uninstall.d.mts.map +1 -1
  112. package/dist/astro/routes/api/admin/plugins/registry/_id_/uninstall.mjs +55 -46
  113. package/dist/astro/routes/api/admin/plugins/registry/_id_/uninstall.mjs.map +1 -1
  114. package/dist/astro/routes/api/admin/plugins/registry/_id_/update.d.mts.map +1 -1
  115. package/dist/astro/routes/api/admin/plugins/registry/_id_/update.mjs +56 -47
  116. package/dist/astro/routes/api/admin/plugins/registry/_id_/update.mjs.map +1 -1
  117. package/dist/astro/routes/api/admin/plugins/registry/artifact.mjs +52 -46
  118. package/dist/astro/routes/api/admin/plugins/registry/artifact.mjs.map +1 -1
  119. package/dist/astro/routes/api/admin/plugins/registry/install.d.mts.map +1 -1
  120. package/dist/astro/routes/api/admin/plugins/registry/install.mjs +56 -47
  121. package/dist/astro/routes/api/admin/plugins/registry/install.mjs.map +1 -1
  122. package/dist/astro/routes/api/admin/plugins/updates.mjs +52 -46
  123. package/dist/astro/routes/api/admin/plugins/updates.mjs.map +1 -1
  124. package/dist/astro/routes/api/admin/themes/marketplace/_id_/index.mjs +52 -46
  125. package/dist/astro/routes/api/admin/themes/marketplace/_id_/index.mjs.map +1 -1
  126. package/dist/astro/routes/api/admin/themes/marketplace/_id_/thumbnail.mjs +4 -4
  127. package/dist/astro/routes/api/admin/themes/marketplace/index.mjs +52 -46
  128. package/dist/astro/routes/api/admin/themes/marketplace/index.mjs.map +1 -1
  129. package/dist/astro/routes/api/admin/users/_id_/disable.mjs +4 -4
  130. package/dist/astro/routes/api/admin/users/_id_/enable.mjs +3 -3
  131. package/dist/astro/routes/api/admin/users/_id_/index.mjs +10 -9
  132. package/dist/astro/routes/api/admin/users/_id_/index.mjs.map +1 -1
  133. package/dist/astro/routes/api/admin/users/_id_/send-recovery.mjs +6 -6
  134. package/dist/astro/routes/api/admin/users/_id_/send-recovery.mjs.map +1 -1
  135. package/dist/astro/routes/api/admin/users/index.mjs +9 -8
  136. package/dist/astro/routes/api/admin/users/index.mjs.map +1 -1
  137. package/dist/astro/routes/api/auth/dev-bypass.mjs +8 -8
  138. package/dist/astro/routes/api/auth/invite/accept.mjs +3 -3
  139. package/dist/astro/routes/api/auth/invite/complete.mjs +14 -13
  140. package/dist/astro/routes/api/auth/invite/complete.mjs.map +1 -1
  141. package/dist/astro/routes/api/auth/invite/index.mjs +12 -11
  142. package/dist/astro/routes/api/auth/invite/index.mjs.map +1 -1
  143. package/dist/astro/routes/api/auth/invite/register-options.mjs +13 -12
  144. package/dist/astro/routes/api/auth/invite/register-options.mjs.map +1 -1
  145. package/dist/astro/routes/api/auth/logout.mjs +4 -4
  146. package/dist/astro/routes/api/auth/magic-link/send.mjs +14 -13
  147. package/dist/astro/routes/api/auth/magic-link/send.mjs.map +1 -1
  148. package/dist/astro/routes/api/auth/magic-link/verify.mjs +4 -4
  149. package/dist/astro/routes/api/auth/me.mjs +10 -9
  150. package/dist/astro/routes/api/auth/me.mjs.map +1 -1
  151. package/dist/astro/routes/api/auth/mode.mjs +4 -4
  152. package/dist/astro/routes/api/auth/oauth/_provider_/callback.mjs +4 -4
  153. package/dist/astro/routes/api/auth/oauth/_provider_.mjs +2 -2
  154. package/dist/astro/routes/api/auth/passkey/_id_.mjs +9 -8
  155. package/dist/astro/routes/api/auth/passkey/_id_.mjs.map +1 -1
  156. package/dist/astro/routes/api/auth/passkey/index.mjs +3 -3
  157. package/dist/astro/routes/api/auth/passkey/options.mjs +15 -14
  158. package/dist/astro/routes/api/auth/passkey/options.mjs.map +1 -1
  159. package/dist/astro/routes/api/auth/passkey/register/options.mjs +13 -12
  160. package/dist/astro/routes/api/auth/passkey/register/options.mjs.map +1 -1
  161. package/dist/astro/routes/api/auth/passkey/register/verify.mjs +14 -13
  162. package/dist/astro/routes/api/auth/passkey/register/verify.mjs.map +1 -1
  163. package/dist/astro/routes/api/auth/passkey/verify.mjs +14 -13
  164. package/dist/astro/routes/api/auth/passkey/verify.mjs.map +1 -1
  165. package/dist/astro/routes/api/auth/signup/complete.mjs +14 -13
  166. package/dist/astro/routes/api/auth/signup/complete.mjs.map +1 -1
  167. package/dist/astro/routes/api/auth/signup/request.mjs +14 -13
  168. package/dist/astro/routes/api/auth/signup/request.mjs.map +1 -1
  169. package/dist/astro/routes/api/auth/signup/verify.mjs +3 -3
  170. package/dist/astro/routes/api/comments/_collection_/_contentId_/index.mjs +20 -19
  171. package/dist/astro/routes/api/comments/_collection_/_contentId_/index.mjs.map +1 -1
  172. package/dist/astro/routes/api/comments/_collection_/_contentId_/reactions.mjs +17 -16
  173. package/dist/astro/routes/api/comments/_collection_/_contentId_/reactions.mjs.map +1 -1
  174. package/dist/astro/routes/api/content/_collection_/_id_/compare.mjs +4 -4
  175. package/dist/astro/routes/api/content/_collection_/_id_/discard-draft.mjs +5 -5
  176. package/dist/astro/routes/api/content/_collection_/_id_/duplicate.mjs +5 -5
  177. package/dist/astro/routes/api/content/_collection_/_id_/permanent.mjs +4 -4
  178. package/dist/astro/routes/api/content/_collection_/_id_/preview-url.mjs +15 -15
  179. package/dist/astro/routes/api/content/_collection_/_id_/publish.mjs +11 -10
  180. package/dist/astro/routes/api/content/_collection_/_id_/publish.mjs.map +1 -1
  181. package/dist/astro/routes/api/content/_collection_/_id_/references/_relation_/children.mjs +21 -20
  182. package/dist/astro/routes/api/content/_collection_/_id_/references/_relation_/children.mjs.map +1 -1
  183. package/dist/astro/routes/api/content/_collection_/_id_/references/_relation_/parents.mjs +21 -20
  184. package/dist/astro/routes/api/content/_collection_/_id_/references/_relation_/parents.mjs.map +1 -1
  185. package/dist/astro/routes/api/content/_collection_/_id_/restore.mjs +5 -5
  186. package/dist/astro/routes/api/content/_collection_/_id_/revisions.mjs +4 -4
  187. package/dist/astro/routes/api/content/_collection_/_id_/schedule.mjs +11 -10
  188. package/dist/astro/routes/api/content/_collection_/_id_/schedule.mjs.map +1 -1
  189. package/dist/astro/routes/api/content/_collection_/_id_/terms/_taxonomy_.d.mts.map +1 -1
  190. package/dist/astro/routes/api/content/_collection_/_id_/terms/_taxonomy_.mjs +47 -34
  191. package/dist/astro/routes/api/content/_collection_/_id_/terms/_taxonomy_.mjs.map +1 -1
  192. package/dist/astro/routes/api/content/_collection_/_id_/translations.mjs +4 -4
  193. package/dist/astro/routes/api/content/_collection_/_id_/unpublish.mjs +5 -5
  194. package/dist/astro/routes/api/content/_collection_/_id_.mjs +11 -10
  195. package/dist/astro/routes/api/content/_collection_/_id_.mjs.map +1 -1
  196. package/dist/astro/routes/api/content/_collection_/authors.mjs +4 -4
  197. package/dist/astro/routes/api/content/_collection_/index.mjs +11 -10
  198. package/dist/astro/routes/api/content/_collection_/index.mjs.map +1 -1
  199. package/dist/astro/routes/api/content/_collection_/trash.mjs +10 -9
  200. package/dist/astro/routes/api/content/_collection_/trash.mjs.map +1 -1
  201. package/dist/astro/routes/api/dashboard.mjs +12 -10
  202. package/dist/astro/routes/api/dashboard.mjs.map +1 -1
  203. package/dist/astro/routes/api/dev/emails.mjs +4 -4
  204. package/dist/astro/routes/api/import/probe.d.mts +3 -3
  205. package/dist/astro/routes/api/import/probe.mjs +22 -20
  206. package/dist/astro/routes/api/import/probe.mjs.map +1 -1
  207. package/dist/astro/routes/api/import/wordpress/analyze.mjs +5 -5
  208. package/dist/astro/routes/api/import/wordpress/execute.d.mts +11 -11
  209. package/dist/astro/routes/api/import/wordpress/execute.mjs +18 -18
  210. package/dist/astro/routes/api/import/wordpress/execute.mjs.map +1 -1
  211. package/dist/astro/routes/api/import/wordpress/media.d.mts +10 -10
  212. package/dist/astro/routes/api/import/wordpress/media.mjs +14 -12
  213. package/dist/astro/routes/api/import/wordpress/media.mjs.map +1 -1
  214. package/dist/astro/routes/api/import/wordpress/prepare.mjs +13 -12
  215. package/dist/astro/routes/api/import/wordpress/prepare.mjs.map +1 -1
  216. package/dist/astro/routes/api/import/wordpress/rewrite-urls.d.mts +11 -11
  217. package/dist/astro/routes/api/import/wordpress/rewrite-urls.mjs +15 -15
  218. package/dist/astro/routes/api/import/wordpress-plugin/analyze.d.mts +1 -1
  219. package/dist/astro/routes/api/import/wordpress-plugin/analyze.mjs +22 -20
  220. package/dist/astro/routes/api/import/wordpress-plugin/analyze.mjs.map +1 -1
  221. package/dist/astro/routes/api/import/wordpress-plugin/callback.mjs +1 -1
  222. package/dist/astro/routes/api/import/wordpress-plugin/execute.d.mts +11 -11
  223. package/dist/astro/routes/api/import/wordpress-plugin/execute.mjs +32 -31
  224. package/dist/astro/routes/api/import/wordpress-plugin/execute.mjs.map +1 -1
  225. package/dist/astro/routes/api/manifest.mjs +6 -6
  226. package/dist/astro/routes/api/mcp.d.mts.map +1 -1
  227. package/dist/astro/routes/api/mcp.mjs +174 -72
  228. package/dist/astro/routes/api/mcp.mjs.map +1 -1
  229. package/dist/astro/routes/api/media/_id_/confirm.mjs +14 -12
  230. package/dist/astro/routes/api/media/_id_/confirm.mjs.map +1 -1
  231. package/dist/astro/routes/api/media/_id_/upload.mjs +7 -7
  232. package/dist/astro/routes/api/media/_id_/usage.mjs +17 -16
  233. package/dist/astro/routes/api/media/_id_/usage.mjs.map +1 -1
  234. package/dist/astro/routes/api/media/_id_.mjs +16 -15
  235. package/dist/astro/routes/api/media/_id_.mjs.map +1 -1
  236. package/dist/astro/routes/api/media/file/_...key_.mjs +3 -3
  237. package/dist/astro/routes/api/media/providers/_providerId_/_itemId_.mjs +4 -4
  238. package/dist/astro/routes/api/media/providers/_providerId_/index.mjs +4 -4
  239. package/dist/astro/routes/api/media/providers/index.mjs +4 -4
  240. package/dist/astro/routes/api/media/upload-url.mjs +11 -10
  241. package/dist/astro/routes/api/media/upload-url.mjs.map +1 -1
  242. package/dist/astro/routes/api/media.mjs +19 -16
  243. package/dist/astro/routes/api/media.mjs.map +1 -1
  244. package/dist/astro/routes/api/menus/_name_/items/_id_.mjs +13 -13
  245. package/dist/astro/routes/api/menus/_name_/items.mjs +13 -13
  246. package/dist/astro/routes/api/menus/_name_/reorder.mjs +13 -13
  247. package/dist/astro/routes/api/menus/_name_/translations.mjs +13 -13
  248. package/dist/astro/routes/api/menus/_name_.mjs +13 -13
  249. package/dist/astro/routes/api/menus/index.mjs +13 -13
  250. package/dist/astro/routes/api/oauth/authorize.mjs +6 -6
  251. package/dist/astro/routes/api/oauth/device/authorize.mjs +7 -7
  252. package/dist/astro/routes/api/oauth/device/code.mjs +10 -10
  253. package/dist/astro/routes/api/oauth/device/token.mjs +9 -9
  254. package/dist/astro/routes/api/oauth/register.mjs +4 -4
  255. package/dist/astro/routes/api/oauth/token/refresh.mjs +7 -7
  256. package/dist/astro/routes/api/oauth/token/revoke.mjs +7 -7
  257. package/dist/astro/routes/api/oauth/token.mjs +7 -7
  258. package/dist/astro/routes/api/openapi.json.mjs +183 -6
  259. package/dist/astro/routes/api/openapi.json.mjs.map +1 -1
  260. package/dist/astro/routes/api/plugins/_pluginId_/_...path_.d.mts.map +1 -1
  261. package/dist/astro/routes/api/plugins/_pluginId_/_...path_.mjs +8 -7
  262. package/dist/astro/routes/api/plugins/_pluginId_/_...path_.mjs.map +1 -1
  263. package/dist/astro/routes/api/redirects/404s/index.mjs +14 -13
  264. package/dist/astro/routes/api/redirects/404s/index.mjs.map +1 -1
  265. package/dist/astro/routes/api/redirects/404s/summary.mjs +14 -13
  266. package/dist/astro/routes/api/redirects/404s/summary.mjs.map +1 -1
  267. package/dist/astro/routes/api/redirects/_id_.mjs +16 -14
  268. package/dist/astro/routes/api/redirects/_id_.mjs.map +1 -1
  269. package/dist/astro/routes/api/redirects/index.mjs +16 -14
  270. package/dist/astro/routes/api/redirects/index.mjs.map +1 -1
  271. package/dist/astro/routes/api/relations/_id_/index.mjs +21 -20
  272. package/dist/astro/routes/api/relations/_id_/index.mjs.map +1 -1
  273. package/dist/astro/routes/api/relations/_id_/translations.mjs +16 -15
  274. package/dist/astro/routes/api/relations/_id_/translations.mjs.map +1 -1
  275. package/dist/astro/routes/api/relations/index.mjs +21 -20
  276. package/dist/astro/routes/api/relations/index.mjs.map +1 -1
  277. package/dist/astro/routes/api/revisions/_revisionId_/index.mjs +4 -4
  278. package/dist/astro/routes/api/revisions/_revisionId_/restore.mjs +5 -5
  279. package/dist/astro/routes/api/schema/collections/_slug_/fields/_fieldSlug_.mjs +52 -46
  280. package/dist/astro/routes/api/schema/collections/_slug_/fields/_fieldSlug_.mjs.map +1 -1
  281. package/dist/astro/routes/api/schema/collections/_slug_/fields/index.mjs +52 -46
  282. package/dist/astro/routes/api/schema/collections/_slug_/fields/index.mjs.map +1 -1
  283. package/dist/astro/routes/api/schema/collections/_slug_/fields/reorder.mjs +52 -46
  284. package/dist/astro/routes/api/schema/collections/_slug_/fields/reorder.mjs.map +1 -1
  285. package/dist/astro/routes/api/schema/collections/_slug_/index.d.mts.map +1 -1
  286. package/dist/astro/routes/api/schema/collections/_slug_/index.mjs +52 -46
  287. package/dist/astro/routes/api/schema/collections/_slug_/index.mjs.map +1 -1
  288. package/dist/astro/routes/api/schema/collections/index.mjs +52 -46
  289. package/dist/astro/routes/api/schema/collections/index.mjs.map +1 -1
  290. package/dist/astro/routes/api/schema/collections/reorder.d.mts +8 -0
  291. package/dist/astro/routes/api/schema/collections/reorder.d.mts.map +1 -0
  292. package/dist/astro/routes/api/schema/collections/reorder.mjs +71 -0
  293. package/dist/astro/routes/api/schema/collections/reorder.mjs.map +1 -0
  294. package/dist/astro/routes/api/schema/index.mjs +14 -11
  295. package/dist/astro/routes/api/schema/index.mjs.map +1 -1
  296. package/dist/astro/routes/api/schema/orphans/_slug_.mjs +52 -46
  297. package/dist/astro/routes/api/schema/orphans/_slug_.mjs.map +1 -1
  298. package/dist/astro/routes/api/schema/orphans/index.mjs +52 -46
  299. package/dist/astro/routes/api/schema/orphans/index.mjs.map +1 -1
  300. package/dist/astro/routes/api/search/enable.d.mts +1 -0
  301. package/dist/astro/routes/api/search/enable.d.mts.map +1 -1
  302. package/dist/astro/routes/api/search/enable.mjs +19 -15
  303. package/dist/astro/routes/api/search/enable.mjs.map +1 -1
  304. package/dist/astro/routes/api/search/index.mjs +13 -13
  305. package/dist/astro/routes/api/search/rebuild.mjs +15 -15
  306. package/dist/astro/routes/api/search/rebuild.mjs.map +1 -1
  307. package/dist/astro/routes/api/search/stats.mjs +9 -9
  308. package/dist/astro/routes/api/search/suggest.mjs +13 -13
  309. package/dist/astro/routes/api/sections/_slug_.mjs +13 -12
  310. package/dist/astro/routes/api/sections/_slug_.mjs.map +1 -1
  311. package/dist/astro/routes/api/sections/index.mjs +13 -12
  312. package/dist/astro/routes/api/sections/index.mjs.map +1 -1
  313. package/dist/astro/routes/api/settings/backups/archives/_name_.mjs +8 -8
  314. package/dist/astro/routes/api/settings/backups/archives/index.mjs +7 -7
  315. package/dist/astro/routes/api/settings/backups/export.mjs +8 -8
  316. package/dist/astro/routes/api/settings/backups/index.mjs +9 -9
  317. package/dist/astro/routes/api/settings/email.mjs +6 -6
  318. package/dist/astro/routes/api/settings.mjs +18 -17
  319. package/dist/astro/routes/api/settings.mjs.map +1 -1
  320. package/dist/astro/routes/api/setup/admin-verify.mjs +15 -14
  321. package/dist/astro/routes/api/setup/admin-verify.mjs.map +1 -1
  322. package/dist/astro/routes/api/setup/admin.mjs +14 -13
  323. package/dist/astro/routes/api/setup/admin.mjs.map +1 -1
  324. package/dist/astro/routes/api/setup/dev-bypass.mjs +34 -32
  325. package/dist/astro/routes/api/setup/dev-bypass.mjs.map +1 -1
  326. package/dist/astro/routes/api/setup/dev-reset.mjs +4 -4
  327. package/dist/astro/routes/api/setup/index.mjs +36 -34
  328. package/dist/astro/routes/api/setup/index.mjs.map +1 -1
  329. package/dist/astro/routes/api/setup/status.mjs +5 -5
  330. package/dist/astro/routes/api/snapshot.mjs +10 -10
  331. package/dist/astro/routes/api/taxonomies/_name_/reorder.d.mts +8 -0
  332. package/dist/astro/routes/api/taxonomies/_name_/reorder.d.mts.map +1 -0
  333. package/dist/astro/routes/api/taxonomies/_name_/reorder.mjs +44 -0
  334. package/dist/astro/routes/api/taxonomies/_name_/reorder.mjs.map +1 -0
  335. package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_/translations.mjs +19 -18
  336. package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_/translations.mjs.map +1 -1
  337. package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_.mjs +19 -18
  338. package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_.mjs.map +1 -1
  339. package/dist/astro/routes/api/taxonomies/_name_/terms/index.d.mts.map +1 -1
  340. package/dist/astro/routes/api/taxonomies/_name_/terms/index.mjs +21 -19
  341. package/dist/astro/routes/api/taxonomies/_name_/terms/index.mjs.map +1 -1
  342. package/dist/astro/routes/api/taxonomies/_name_/translations.d.mts +8 -0
  343. package/dist/astro/routes/api/taxonomies/_name_/translations.d.mts.map +1 -0
  344. package/dist/astro/routes/api/taxonomies/_name_/translations.mjs +46 -0
  345. package/dist/astro/routes/api/taxonomies/_name_/translations.mjs.map +1 -0
  346. package/dist/astro/routes/api/taxonomies/_name_.d.mts +19 -0
  347. package/dist/astro/routes/api/taxonomies/_name_.d.mts.map +1 -0
  348. package/dist/astro/routes/api/taxonomies/_name_.mjs +88 -0
  349. package/dist/astro/routes/api/taxonomies/_name_.mjs.map +1 -0
  350. package/dist/astro/routes/api/taxonomies/index.mjs +19 -18
  351. package/dist/astro/routes/api/taxonomies/index.mjs.map +1 -1
  352. package/dist/astro/routes/api/themes/preview.mjs +8 -8
  353. package/dist/astro/routes/api/typegen.mjs +6 -6
  354. package/dist/astro/routes/api/well-known/auth.mjs +2 -2
  355. package/dist/astro/routes/api/well-known/oauth-authorization-server.mjs +2 -2
  356. package/dist/astro/routes/api/well-known/oauth-protected-resource.mjs +2 -2
  357. package/dist/astro/routes/api/widget-areas/_name_/reorder.mjs +10 -9
  358. package/dist/astro/routes/api/widget-areas/_name_/reorder.mjs.map +1 -1
  359. package/dist/astro/routes/api/widget-areas/_name_/widgets/_id_.mjs +13 -12
  360. package/dist/astro/routes/api/widget-areas/_name_/widgets/_id_.mjs.map +1 -1
  361. package/dist/astro/routes/api/widget-areas/_name_/widgets.mjs +13 -12
  362. package/dist/astro/routes/api/widget-areas/_name_/widgets.mjs.map +1 -1
  363. package/dist/astro/routes/api/widget-areas/_name_.mjs +8 -7
  364. package/dist/astro/routes/api/widget-areas/_name_.mjs.map +1 -1
  365. package/dist/astro/routes/api/widget-areas/index.mjs +13 -12
  366. package/dist/astro/routes/api/widget-areas/index.mjs.map +1 -1
  367. package/dist/astro/routes/api/widget-components.mjs +4 -4
  368. package/dist/astro/routes/robots.txt.mjs +11 -10
  369. package/dist/astro/routes/robots.txt.mjs.map +1 -1
  370. package/dist/astro/routes/sitemap-_collection_.xml.mjs +14 -14
  371. package/dist/astro/routes/sitemap.xml.mjs +12 -11
  372. package/dist/astro/routes/sitemap.xml.mjs.map +1 -1
  373. package/dist/astro/types.d.mts +41 -17
  374. package/dist/astro/types.d.mts.map +1 -1
  375. package/dist/auth/providers/github.d.mts +1 -1
  376. package/dist/auth/providers/google.d.mts +1 -1
  377. package/dist/{authorize-R5iYYrpa.mjs → authorize-1iFJzPaZ.mjs} +2 -2
  378. package/dist/{authorize-R5iYYrpa.mjs.map → authorize-1iFJzPaZ.mjs.map} +1 -1
  379. package/dist/{backup-LpQ1V_sR.mjs → backup-LHjIAVNP.mjs} +5 -5
  380. package/dist/{backup-LpQ1V_sR.mjs.map → backup-LHjIAVNP.mjs.map} +1 -1
  381. package/dist/{base64-B-PsqheR.mjs → base64-CvLhUKQv.mjs} +1 -1
  382. package/dist/{base64-B-PsqheR.mjs.map → base64-CvLhUKQv.mjs.map} +1 -1
  383. package/dist/bundle-CBEXrBnb.mjs +663 -0
  384. package/dist/bundle-CBEXrBnb.mjs.map +1 -0
  385. package/dist/{byline-fields-T9ZLZMxJ.mjs → byline-fields-C5S8wygO.mjs} +2 -2
  386. package/dist/{byline-fields-T9ZLZMxJ.mjs.map → byline-fields-C5S8wygO.mjs.map} +1 -1
  387. package/dist/{byline-C5TAqs8N.mjs → byline-pEcoDps8.mjs} +9 -9
  388. package/dist/{byline-C5TAqs8N.mjs.map → byline-pEcoDps8.mjs.map} +1 -1
  389. package/dist/{byline-registry-BCuOp4UF.mjs → byline-registry-DDun8sxh.mjs} +4 -4
  390. package/dist/{byline-registry-BCuOp4UF.mjs.map → byline-registry-DDun8sxh.mjs.map} +1 -1
  391. package/dist/{bylines-B8-WGdja.mjs → bylines-BWemdX2k.mjs} +8 -8
  392. package/dist/{bylines-B8-WGdja.mjs.map → bylines-BWemdX2k.mjs.map} +1 -1
  393. package/dist/{bylines-DGuqBLjV.mjs → bylines-DJfSfXCL.mjs} +5 -5
  394. package/dist/{bylines-DGuqBLjV.mjs.map → bylines-DJfSfXCL.mjs.map} +1 -1
  395. package/dist/cache-CBJaDy_E.mjs +108 -0
  396. package/dist/cache-CBJaDy_E.mjs.map +1 -0
  397. package/dist/{challenge-store-BFzgFRog.mjs → challenge-store-CZyFVaad.mjs} +1 -1
  398. package/dist/{challenge-store-BFzgFRog.mjs.map → challenge-store-CZyFVaad.mjs.map} +1 -1
  399. package/dist/{chunks-D5dlPeRb.mjs → chunks-DfPax1I0.mjs} +2 -2
  400. package/dist/{chunks-D5dlPeRb.mjs.map → chunks-DfPax1I0.mjs.map} +1 -1
  401. package/dist/cli/index.mjs +193 -707
  402. package/dist/cli/index.mjs.map +1 -1
  403. package/dist/client/cf-access.d.mts +1 -1
  404. package/dist/client/index.d.mts +74 -4
  405. package/dist/client/index.d.mts.map +1 -1
  406. package/dist/client/index.mjs +25 -2
  407. package/dist/client/index.mjs.map +1 -1
  408. package/dist/collection-deletion-C8BugSGz.mjs +779 -0
  409. package/dist/collection-deletion-C8BugSGz.mjs.map +1 -0
  410. package/dist/{comment-DnTxxVHv.mjs → comment-Dxlep6cE.mjs} +3 -3
  411. package/dist/{comment-DnTxxVHv.mjs.map → comment-Dxlep6cE.mjs.map} +1 -1
  412. package/dist/{comment-reaction-BUlUz2bh.mjs → comment-reaction-D6qfHKBc.mjs} +2 -2
  413. package/dist/{comment-reaction-BUlUz2bh.mjs.map → comment-reaction-D6qfHKBc.mjs.map} +1 -1
  414. package/dist/{comments-QPKgK3nk.mjs → comments-CTOuhTSX.mjs} +3 -3
  415. package/dist/{comments-QPKgK3nk.mjs.map → comments-CTOuhTSX.mjs.map} +1 -1
  416. package/dist/{components-DZkL4Fx0.mjs → components-CQy3lh9x.mjs} +1 -1
  417. package/dist/{components-DZkL4Fx0.mjs.map → components-CQy3lh9x.mjs.map} +1 -1
  418. package/dist/{config-DyF3OKg_.mjs → config-C3EBstHi.mjs} +18 -2
  419. package/dist/config-C3EBstHi.mjs.map +1 -0
  420. package/dist/{content-CpfKV9QE.mjs → content-BNfwh7xX.mjs} +667 -183
  421. package/dist/content-BNfwh7xX.mjs.map +1 -0
  422. package/dist/content-list-query-DhQ84eVV.d.mts +26 -0
  423. package/dist/content-list-query-DhQ84eVV.d.mts.map +1 -0
  424. package/dist/content-refresh-DNERP4-f.mjs +2560 -0
  425. package/dist/content-refresh-DNERP4-f.mjs.map +1 -0
  426. package/dist/{context-kO4YZB03.mjs → context-DRgOvSnW.mjs} +28 -20
  427. package/dist/context-DRgOvSnW.mjs.map +1 -0
  428. package/dist/{cron-BlKIMD_e.mjs → cron-Y9aLtgrA.mjs} +1 -1
  429. package/dist/{cron-BlKIMD_e.mjs.map → cron-Y9aLtgrA.mjs.map} +1 -1
  430. package/dist/{dashboard-DoBwPnON.mjs → dashboard-CB8J89rJ.mjs} +45 -11
  431. package/dist/dashboard-CB8J89rJ.mjs.map +1 -0
  432. package/dist/db/index.d.mts +4 -4
  433. package/dist/db/index.mjs +3 -3
  434. package/dist/db/index.mjs.map +1 -1
  435. package/dist/db/libsql.d.mts +1 -1
  436. package/dist/db/postgres.d.mts +1 -1
  437. package/dist/db/sqlite.d.mts +1 -1
  438. package/dist/{db-errors-CcWLaRiR.mjs → db-errors-Cl-sKYTm.mjs} +1 -1
  439. package/dist/{db-errors-CcWLaRiR.mjs.map → db-errors-Cl-sKYTm.mjs.map} +1 -1
  440. package/dist/{default-C4v9KP56.mjs → default-DdDl3fxv.mjs} +1 -1
  441. package/dist/{default-C4v9KP56.mjs.map → default-DdDl3fxv.mjs.map} +1 -1
  442. package/dist/deferred-tasks-BMsa9F64.d.mts +9 -0
  443. package/dist/deferred-tasks-BMsa9F64.d.mts.map +1 -0
  444. package/dist/{device-flow-DhUsyJU6.mjs → device-flow-CaioYGK3.mjs} +5 -5
  445. package/dist/{device-flow-DhUsyJU6.mjs.map → device-flow-CaioYGK3.mjs.map} +1 -1
  446. package/dist/{dialect-helpers-DFwyWjTM.mjs → dialect-helpers-BSbfaO3F.mjs} +24 -16
  447. package/dist/dialect-helpers-BSbfaO3F.mjs.map +1 -0
  448. package/dist/dist-D_6CKR8z.mjs +810 -0
  449. package/dist/dist-D_6CKR8z.mjs.map +1 -0
  450. package/dist/{email-console-C-9Ng8DM.mjs → email-console-BHNjIwiB.mjs} +1 -1
  451. package/dist/{email-console-C-9Ng8DM.mjs.map → email-console-BHNjIwiB.mjs.map} +1 -1
  452. package/dist/{enrich-CFJJgxs_.mjs → enrich-_ySMEvEE.mjs} +2 -2
  453. package/dist/{enrich-CFJJgxs_.mjs.map → enrich-_ySMEvEE.mjs.map} +1 -1
  454. package/dist/{error-DmmN74gW.mjs → error-DupyJZE2.mjs} +3 -3
  455. package/dist/{error-DmmN74gW.mjs.map → error-DupyJZE2.mjs.map} +1 -1
  456. package/dist/{errors-DtEXIQQV.mjs → errors-CLUPm7aD.mjs} +15 -2
  457. package/dist/errors-CLUPm7aD.mjs.map +1 -0
  458. package/dist/{escape-CdW31WsG.mjs → escape-C_aLKP3H.mjs} +1 -1
  459. package/dist/{escape-CdW31WsG.mjs.map → escape-C_aLKP3H.mjs.map} +1 -1
  460. package/dist/{field-defs-cache-QMVnzTH6.mjs → field-defs-cache-hg6QkjV9.mjs} +5 -5
  461. package/dist/{field-defs-cache-QMVnzTH6.mjs.map → field-defs-cache-hg6QkjV9.mjs.map} +1 -1
  462. package/dist/{fts-manager-vncsZIJm.mjs → fts-manager-CZ-5dVwJ.mjs} +111 -61
  463. package/dist/fts-manager-CZ-5dVwJ.mjs.map +1 -0
  464. package/dist/{hash-Cb7U1b5M.mjs → hash-Cg0TXJPV.mjs} +1 -1
  465. package/dist/{hash-Cb7U1b5M.mjs.map → hash-Cg0TXJPV.mjs.map} +1 -1
  466. package/dist/{hreflang-CZbSx6Bg.d.mts → hreflang-D3Uehfv2.d.mts} +2 -2
  467. package/dist/{hreflang-CZbSx6Bg.d.mts.map → hreflang-D3Uehfv2.d.mts.map} +1 -1
  468. package/dist/{hreflang-Bg-zMpkr.mjs → hreflang-DNswoYsi.mjs} +7 -7
  469. package/dist/{hreflang-Bg-zMpkr.mjs.map → hreflang-DNswoYsi.mjs.map} +1 -1
  470. package/dist/{import-PKhLeXvn.mjs → import-B41u8Rot.mjs} +7 -7
  471. package/dist/{import-PKhLeXvn.mjs.map → import-B41u8Rot.mjs.map} +1 -1
  472. package/dist/{index-j9rTh3cp.d.mts → index-C3Y-rsyN.d.mts} +286 -93
  473. package/dist/index-C3Y-rsyN.d.mts.map +1 -0
  474. package/dist/{index-BeNto_Vs.d.mts → index-Cof4-Fab.d.mts} +5 -10
  475. package/dist/index-Cof4-Fab.d.mts.map +1 -0
  476. package/dist/index.d.mts +20 -19
  477. package/dist/index.mjs +79 -71
  478. package/dist/{init-lock-DJkX6Hto.mjs → init-lock-6b309ZrF.mjs} +1 -1
  479. package/dist/{init-lock-DJkX6Hto.mjs.map → init-lock-6b309ZrF.mjs.map} +1 -1
  480. package/dist/{load-BwTdWE8B.mjs → load-DmvJrtxS.mjs} +2 -2
  481. package/dist/{load-BwTdWE8B.mjs.map → load-DmvJrtxS.mjs.map} +1 -1
  482. package/dist/{loader-C1XOLV5b.mjs → loader-DLBqRiGP.mjs} +120 -64
  483. package/dist/loader-DLBqRiGP.mjs.map +1 -0
  484. package/dist/{manifest-schema-bCq54i7F.mjs → manifest-schema-BXbUAHod.mjs} +1 -1
  485. package/dist/{manifest-schema-bCq54i7F.mjs.map → manifest-schema-BXbUAHod.mjs.map} +1 -1
  486. package/dist/media/image-endpoint.mjs +1 -1
  487. package/dist/media/index.d.mts +1 -1
  488. package/dist/media/index.mjs +3 -2
  489. package/dist/media/index.mjs.map +1 -1
  490. package/dist/media/local-runtime.d.mts +12 -12
  491. package/dist/media/local-runtime.mjs +10 -9
  492. package/dist/media/local-runtime.mjs.map +1 -1
  493. package/dist/{media-DWIzoVFL.mjs → media-BWWWb8kg.mjs} +92 -3
  494. package/dist/media-BWWWb8kg.mjs.map +1 -0
  495. package/dist/{media-tQDZEdu7.mjs → media-CzhAn2--.mjs} +2 -2
  496. package/dist/{media-tQDZEdu7.mjs.map → media-CzhAn2--.mjs.map} +1 -1
  497. package/dist/{media-allowlist-B7TPD6aq.mjs → media-allowlist-BD6HhgXA.mjs} +14 -3
  498. package/dist/media-allowlist-BD6HhgXA.mjs.map +1 -0
  499. package/dist/{media-upload-Bc9Nc5Zf.mjs → media-upload-9yas9zGH.mjs} +11 -9
  500. package/dist/{media-upload-Bc9Nc5Zf.mjs.map → media-upload-9yas9zGH.mjs.map} +1 -1
  501. package/dist/{media-url-BCm5vBn6.mjs → media-url-BvoX88FA.mjs} +1 -1
  502. package/dist/{media-url-BCm5vBn6.mjs.map → media-url-BvoX88FA.mjs.map} +1 -1
  503. package/dist/{media-usage-DPJcNaAq.mjs → media-usage-De3qvwjc.mjs} +138 -61
  504. package/dist/media-usage-De3qvwjc.mjs.map +1 -0
  505. package/dist/media-usage-work-B9Bksh_b.mjs +152 -0
  506. package/dist/media-usage-work-B9Bksh_b.mjs.map +1 -0
  507. package/dist/media-usage-work-DrCbqBcl.mjs +424 -0
  508. package/dist/media-usage-work-DrCbqBcl.mjs.map +1 -0
  509. package/dist/media-usage-write-fence-aHEgN1zB.mjs +42 -0
  510. package/dist/media-usage-write-fence-aHEgN1zB.mjs.map +1 -0
  511. package/dist/{menus-C6qhqP4X.mjs → menus-CC-yn1F9.mjs} +554 -121
  512. package/dist/menus-CC-yn1F9.mjs.map +1 -0
  513. package/dist/{menus-BxPLFfIc.mjs → menus-fxvEDYE6.mjs} +5 -5
  514. package/dist/{menus-BxPLFfIc.mjs.map → menus-fxvEDYE6.mjs.map} +1 -1
  515. package/dist/{mode-fiXRMfeA.mjs → mode-Bpe-tNNy.mjs} +1 -1
  516. package/dist/{mode-fiXRMfeA.mjs.map → mode-Bpe-tNNy.mjs.map} +1 -1
  517. package/dist/{normalize-C-SHXmra.mjs → normalize-Bc-s_r-a.mjs} +1 -1
  518. package/dist/{normalize-C-SHXmra.mjs.map → normalize-Bc-s_r-a.mjs.map} +1 -1
  519. package/dist/{oauth-authorization-C9tFinly.mjs → oauth-authorization-BXO1MKej.mjs} +5 -5
  520. package/dist/{oauth-authorization-C9tFinly.mjs.map → oauth-authorization-BXO1MKej.mjs.map} +1 -1
  521. package/dist/{oauth-clients-BwTxE1aE.mjs → oauth-clients-C_DNqtRu.mjs} +1 -1
  522. package/dist/{oauth-clients-BwTxE1aE.mjs.map → oauth-clients-C_DNqtRu.mjs.map} +1 -1
  523. package/dist/{oauth-state-store-DaRUwPWO.mjs → oauth-state-store-DwAxMtk4.mjs} +1 -1
  524. package/dist/{oauth-state-store-DaRUwPWO.mjs.map → oauth-state-store-DwAxMtk4.mjs.map} +1 -1
  525. package/dist/{oauth-user-lookup-CzuzOSlF.mjs → oauth-user-lookup-BxfZizdk.mjs} +1 -1
  526. package/dist/{oauth-user-lookup-CzuzOSlF.mjs.map → oauth-user-lookup-BxfZizdk.mjs.map} +1 -1
  527. package/dist/object-cache/memory.d.mts +1 -1
  528. package/dist/{object-cache-Bok5j2ae.mjs → object-cache-71tPfV4A.mjs} +106 -5
  529. package/dist/object-cache-71tPfV4A.mjs.map +1 -0
  530. package/dist/{options-BlmBHTvX.mjs → options-CBXIHUoT.mjs} +1 -1
  531. package/dist/{options-BlmBHTvX.mjs.map → options-CBXIHUoT.mjs.map} +1 -1
  532. package/dist/{options-aeIs8WFu.d.mts → options-DRe1pIBL.d.mts} +4 -3
  533. package/dist/options-DRe1pIBL.d.mts.map +1 -0
  534. package/dist/page/index.d.mts +2 -2
  535. package/dist/{parse-BL49yb9D.mjs → parse-DFbuc-Fh.mjs} +2 -2
  536. package/dist/{parse-BL49yb9D.mjs.map → parse-DFbuc-Fh.mjs.map} +1 -1
  537. package/dist/{passkey-config-KMhgFjdQ.mjs → passkey-config-_2GOwwK8.mjs} +1 -1
  538. package/dist/{passkey-config-KMhgFjdQ.mjs.map → passkey-config-_2GOwwK8.mjs.map} +1 -1
  539. package/dist/{placeholder-Dxo5Zt58.d.mts → placeholder-CzW7Lshs.d.mts} +1 -1
  540. package/dist/{placeholder-Dxo5Zt58.d.mts.map → placeholder-CzW7Lshs.d.mts.map} +1 -1
  541. package/dist/plugin-types.d.mts +8 -1
  542. package/dist/plugin-types.d.mts.map +1 -1
  543. package/dist/plugin-utils.d.mts +10 -10
  544. package/dist/plugins/adapt-sandbox-entry.d.mts +10 -10
  545. package/dist/plugins/adapt-sandbox-entry.mjs +7 -4
  546. package/dist/plugins/adapt-sandbox-entry.mjs.map +1 -1
  547. package/dist/{portable-text-CNahFfj6.mjs → portable-text-DhKbDAGr.mjs} +1 -1
  548. package/dist/{portable-text-CNahFfj6.mjs.map → portable-text-DhKbDAGr.mjs.map} +1 -1
  549. package/dist/{preview-D4Jnbfx7.mjs → preview-PW-nOnq4.mjs} +2 -2
  550. package/dist/{preview-D4Jnbfx7.mjs.map → preview-PW-nOnq4.mjs.map} +1 -1
  551. package/dist/{public-url-DSGTnJFw.mjs → public-url-CWoFhQT8.mjs} +14 -3
  552. package/dist/public-url-CWoFhQT8.mjs.map +1 -0
  553. package/dist/{query-DCiXI7OZ.mjs → query-BgjfiLUQ.mjs} +38 -77
  554. package/dist/query-BgjfiLUQ.mjs.map +1 -0
  555. package/dist/{query-1xOcEy18.mjs → query-vgZNwIhh.mjs} +4 -4
  556. package/dist/{query-1xOcEy18.mjs.map → query-vgZNwIhh.mjs.map} +1 -1
  557. package/dist/{rate-limit-Vkp9gQ1Y.mjs → rate-limit-L5anykgo.mjs} +2 -2
  558. package/dist/{rate-limit-Vkp9gQ1Y.mjs.map → rate-limit-L5anykgo.mjs.map} +1 -1
  559. package/dist/{redirect-BJ6d1yHh.mjs → redirect-COsS6SWJ.mjs} +3 -3
  560. package/dist/{redirect-BJ6d1yHh.mjs.map → redirect-COsS6SWJ.mjs.map} +1 -1
  561. package/dist/{redirect-CDgfv9vh.mjs → redirect-KBNE3UEs.mjs} +1 -1
  562. package/dist/{redirect-CDgfv9vh.mjs.map → redirect-KBNE3UEs.mjs.map} +1 -1
  563. package/dist/{redirects-Cwkq2H-G.mjs → redirects-CufRQt0Q.mjs} +5 -5
  564. package/dist/{redirects-Cwkq2H-G.mjs.map → redirects-CufRQt0Q.mjs.map} +1 -1
  565. package/dist/{redirects-BOn2DIUs.mjs → redirects-cV9g7V-0.mjs} +149 -16
  566. package/dist/redirects-cV9g7V-0.mjs.map +1 -0
  567. package/dist/registry-C581V4TP.mjs +1275 -0
  568. package/dist/registry-C581V4TP.mjs.map +1 -0
  569. package/dist/{relation-DJ5DZh7B.mjs → relation-DtmAQH7s.mjs} +3 -3
  570. package/dist/{relation-DJ5DZh7B.mjs.map → relation-DtmAQH7s.mjs.map} +1 -1
  571. package/dist/{relations-C4duJnwI.mjs → relations-BBApI4e2.mjs} +3 -3
  572. package/dist/{relations-C4duJnwI.mjs.map → relations-BBApI4e2.mjs.map} +1 -1
  573. package/dist/{relations-DpTjftCl.mjs → relations-DICSyfsh.mjs} +6 -6
  574. package/dist/{relations-DpTjftCl.mjs.map → relations-DICSyfsh.mjs.map} +1 -1
  575. package/dist/{relations-DHFQGX0h.d.mts → relations-DItI3MN9.d.mts} +401 -40
  576. package/dist/relations-DItI3MN9.d.mts.map +1 -0
  577. package/dist/request-context.d.mts +3 -0
  578. package/dist/request-context.d.mts.map +1 -1
  579. package/dist/request-context.mjs.map +1 -1
  580. package/dist/{request-meta-DzXYYI-n.mjs → request-meta-DgZJh3zG.mjs} +2 -2
  581. package/dist/{request-meta-DzXYYI-n.mjs.map → request-meta-DgZJh3zG.mjs.map} +1 -1
  582. package/dist/{resolve-BUvFE0Lr.mjs → resolve-DOhVEvty.mjs} +2 -2
  583. package/dist/{resolve-BUvFE0Lr.mjs.map → resolve-DOhVEvty.mjs.map} +1 -1
  584. package/dist/{runner-BsI18UgP.mjs → runner-BiDvq5dv.mjs} +1404 -235
  585. package/dist/runner-BiDvq5dv.mjs.map +1 -0
  586. package/dist/{runner-CHdkERbt.d.mts → runner-CgQbELYC.d.mts} +2 -2
  587. package/dist/{runner-CHdkERbt.d.mts.map → runner-CgQbELYC.d.mts.map} +1 -1
  588. package/dist/runtime.d.mts +11 -11
  589. package/dist/runtime.mjs +5 -4
  590. package/dist/runtime.mjs.map +1 -1
  591. package/dist/{schema-eqZhkR0S.mjs → schema-BFyTg38T.mjs} +3 -3
  592. package/dist/{schema-eqZhkR0S.mjs.map → schema-BFyTg38T.mjs.map} +1 -1
  593. package/dist/schema-CeQSNwB3.mjs +390 -0
  594. package/dist/schema-CeQSNwB3.mjs.map +1 -0
  595. package/dist/{scopes-Be2d8bSb.mjs → scopes-BVeuhGBE.mjs} +3 -3
  596. package/dist/{scopes-Be2d8bSb.mjs.map → scopes-BVeuhGBE.mjs.map} +1 -1
  597. package/dist/{search-CeO678cp.mjs → search-BpuPKZb0.mjs} +26 -16
  598. package/dist/search-BpuPKZb0.mjs.map +1 -0
  599. package/dist/{secrets-870d-7yA.mjs → secrets-dtYs2hDo.mjs} +5 -5
  600. package/dist/{secrets-870d-7yA.mjs.map → secrets-dtYs2hDo.mjs.map} +1 -1
  601. package/dist/{sections-DSuEfirn.mjs → sections-COctk6hf.mjs} +3 -3
  602. package/dist/{sections-DSuEfirn.mjs.map → sections-COctk6hf.mjs.map} +1 -1
  603. package/dist/seed/index.d.mts +2 -2
  604. package/dist/seed/index.mjs +28 -26
  605. package/dist/seo/index.d.mts +3 -3
  606. package/dist/seo/index.mjs +20 -19
  607. package/dist/seo/index.mjs.map +1 -1
  608. package/dist/{seo-C3GDfT0V.mjs → seo-AFpVvTqr.mjs} +6 -4
  609. package/dist/seo-AFpVvTqr.mjs.map +1 -0
  610. package/dist/{seo-BAPKiED8.mjs → seo-CvDxfvFb.mjs} +3 -3
  611. package/dist/{seo-BAPKiED8.mjs.map → seo-CvDxfvFb.mjs.map} +1 -1
  612. package/dist/{service-DyFT-k-R.mjs → service-xMiMSTsR.mjs} +4 -4
  613. package/dist/{service-DyFT-k-R.mjs.map → service-xMiMSTsR.mjs.map} +1 -1
  614. package/dist/{session-user-BrK2zz7S.mjs → session-user-BzVemLkw.mjs} +2 -2
  615. package/dist/{session-user-BrK2zz7S.mjs.map → session-user-BzVemLkw.mjs.map} +1 -1
  616. package/dist/{settings-DgKouY2S.mjs → settings-B372MV0p.mjs} +7 -7
  617. package/dist/{settings-DgKouY2S.mjs.map → settings-B372MV0p.mjs.map} +1 -1
  618. package/dist/{settings-CREKyj8I.mjs → settings-BE9aqn_9.mjs} +3 -3
  619. package/dist/{settings-CREKyj8I.mjs.map → settings-BE9aqn_9.mjs.map} +1 -1
  620. package/dist/{setup-complete-L7bMK2VI.mjs → setup-complete-DF7TAfD5.mjs} +2 -2
  621. package/dist/{setup-complete-L7bMK2VI.mjs.map → setup-complete-DF7TAfD5.mjs.map} +1 -1
  622. package/dist/{setup-nonce-Ct5tjWcq.mjs → setup-nonce-Do-U_cg9.mjs} +1 -1
  623. package/dist/{setup-nonce-Ct5tjWcq.mjs.map → setup-nonce-Do-U_cg9.mjs.map} +1 -1
  624. package/dist/{single-flight-cache-C2exrGAi.mjs → single-flight-cache-B0eLKS6K.mjs} +2 -2
  625. package/dist/{single-flight-cache-C2exrGAi.mjs.map → single-flight-cache-B0eLKS6K.mjs.map} +1 -1
  626. package/dist/site-url-Bowsi9T-.mjs +16 -0
  627. package/dist/site-url-Bowsi9T-.mjs.map +1 -0
  628. package/dist/slugify-B994zkXC.mjs +17 -0
  629. package/dist/slugify-B994zkXC.mjs.map +1 -0
  630. package/dist/{snapshot-BdpUJKD-.mjs → snapshot-B5h6aPMh.mjs} +2 -2
  631. package/dist/{snapshot-BdpUJKD-.mjs.map → snapshot-B5h6aPMh.mjs.map} +1 -1
  632. package/dist/{ssrf-CviKqWmq.mjs → ssrf-Cpvg_n3A.mjs} +1 -1
  633. package/dist/{ssrf-CviKqWmq.mjs.map → ssrf-Cpvg_n3A.mjs.map} +1 -1
  634. package/dist/{state-xxv6ZTMv.mjs → state-DYwPue40.mjs} +1 -1
  635. package/dist/{state-xxv6ZTMv.mjs.map → state-DYwPue40.mjs.map} +1 -1
  636. package/dist/{status-COfycGIU.mjs → status-CWVYpbD8.mjs} +1 -1
  637. package/dist/{status-COfycGIU.mjs.map → status-CWVYpbD8.mjs.map} +1 -1
  638. package/dist/storage/local.d.mts +1 -1
  639. package/dist/storage/local.mjs +1 -1
  640. package/dist/storage/s3.d.mts +1 -1
  641. package/dist/storage/s3.mjs +1 -1
  642. package/dist/{taxonomies-B61CRSha.mjs → taxonomies-B0o9ExNV.mjs} +85 -75
  643. package/dist/taxonomies-B0o9ExNV.mjs.map +1 -0
  644. package/dist/{taxonomies-Dbdki3Un.mjs → taxonomies-Dk3MAklL.mjs} +360 -56
  645. package/dist/taxonomies-Dk3MAklL.mjs.map +1 -0
  646. package/dist/taxonomy-CPeM8d2o.mjs +484 -0
  647. package/dist/taxonomy-CPeM8d2o.mjs.map +1 -0
  648. package/dist/{tokens-DVltpO2D.mjs → tokens-C39klX8R.mjs} +2 -2
  649. package/dist/{tokens-DVltpO2D.mjs.map → tokens-C39klX8R.mjs.map} +1 -1
  650. package/dist/{transaction-D0FOsb3X.mjs → transaction-NQj4VJ7Z.mjs} +1 -1
  651. package/dist/{transaction-D0FOsb3X.mjs.map → transaction-NQj4VJ7Z.mjs.map} +1 -1
  652. package/dist/{transport-BWQo0Foy.mjs → transport--CfOflrp.mjs} +1 -1
  653. package/dist/{transport-BWQo0Foy.mjs.map → transport--CfOflrp.mjs.map} +1 -1
  654. package/dist/{transport-DokJOScS.d.mts → transport-B_rfeU-a.d.mts} +1 -1
  655. package/dist/{transport-DokJOScS.d.mts.map → transport-B_rfeU-a.d.mts.map} +1 -1
  656. package/dist/{trusted-proxy-CwjQj0YG.mjs → trusted-proxy-CEVekpby.mjs} +1 -1
  657. package/dist/{trusted-proxy-CwjQj0YG.mjs.map → trusted-proxy-CEVekpby.mjs.map} +1 -1
  658. package/dist/{types-o7xo7VgH.mjs → types-75KIqzL9.mjs} +20 -3
  659. package/dist/types-75KIqzL9.mjs.map +1 -0
  660. package/dist/{types-C9P3ysxq.d.mts → types-BPuloofb.d.mts} +1 -1
  661. package/dist/{types-C9P3ysxq.d.mts.map → types-BPuloofb.d.mts.map} +1 -1
  662. package/dist/{types-BD40g7zz.mjs → types-BW1syrlw.mjs} +1 -1
  663. package/dist/{types-BD40g7zz.mjs.map → types-BW1syrlw.mjs.map} +1 -1
  664. package/dist/{types-jISEalTX.d.mts → types-C3_AbkDP.d.mts} +53 -10
  665. package/dist/types-C3_AbkDP.d.mts.map +1 -0
  666. package/dist/{types-84Bque3-.d.mts → types-CAGdePf3.d.mts} +133 -1
  667. package/dist/types-CAGdePf3.d.mts.map +1 -0
  668. package/dist/{types-CcSZCcF1.d.mts → types-CFUfyt1s.d.mts} +1 -1
  669. package/dist/{types-CcSZCcF1.d.mts.map → types-CFUfyt1s.d.mts.map} +1 -1
  670. package/dist/{types-DQLZ58GV.d.mts → types-CPx2lIGo.d.mts} +1 -1
  671. package/dist/{types-DQLZ58GV.d.mts.map → types-CPx2lIGo.d.mts.map} +1 -1
  672. package/dist/{types-XrQQ-Aex.mjs → types-CQPWhPxE.mjs} +15 -11
  673. package/dist/types-CQPWhPxE.mjs.map +1 -0
  674. package/dist/{types-BQY7VYw6.d.mts → types-Cs-TFLNf.d.mts} +28 -8
  675. package/dist/types-Cs-TFLNf.d.mts.map +1 -0
  676. package/dist/types-CtzytVXn.mjs +18 -0
  677. package/dist/types-CtzytVXn.mjs.map +1 -0
  678. package/dist/{types-DqZVPILm.d.mts → types-D4_1Ga4L.d.mts} +44 -5
  679. package/dist/types-D4_1Ga4L.d.mts.map +1 -0
  680. package/dist/{types-Dr2GLlwu.d.mts → types-DefV3OiO.d.mts} +1 -1
  681. package/dist/{types-Dr2GLlwu.d.mts.map → types-DefV3OiO.d.mts.map} +1 -1
  682. package/dist/{types-DsAMyD_o.d.mts → types-X0MThr7x.d.mts} +1 -1
  683. package/dist/{types-DsAMyD_o.d.mts.map → types-X0MThr7x.d.mts.map} +1 -1
  684. package/dist/{upload-attempts-C5yd6Gae.mjs → upload-attempts-hlne3iA1.mjs} +1 -1
  685. package/dist/{upload-attempts-C5yd6Gae.mjs.map → upload-attempts-hlne3iA1.mjs.map} +1 -1
  686. package/dist/url-pattern-BHS0V5Ng.mjs +33 -0
  687. package/dist/url-pattern-BHS0V5Ng.mjs.map +1 -0
  688. package/dist/{user-BAumEmpA.mjs → user-sHgJ62SP.mjs} +3 -3
  689. package/dist/{user-BAumEmpA.mjs.map → user-sHgJ62SP.mjs.map} +1 -1
  690. package/dist/{utils-BbUgmeZG.mjs → utils-D4vD_Y98.mjs} +3 -3
  691. package/dist/{utils-BbUgmeZG.mjs.map → utils-D4vD_Y98.mjs.map} +1 -1
  692. package/dist/{validate-Bs_wT2ul.mjs → validate-BkqIG_Uj.mjs} +24 -5
  693. package/dist/validate-BkqIG_Uj.mjs.map +1 -0
  694. package/dist/{validate-VPnKoIzW.mjs → validate-BpwoDOgt.mjs} +25 -2
  695. package/dist/validate-BpwoDOgt.mjs.map +1 -0
  696. package/dist/{validate-CdYcY-Ln.d.mts → validate-DeGtBN84.d.mts} +25 -7
  697. package/dist/validate-DeGtBN84.d.mts.map +1 -0
  698. package/dist/{validation-BngR0nit.mjs → validation-CiJb_X5o.mjs} +14 -13
  699. package/dist/{validation-BngR0nit.mjs.map → validation-CiJb_X5o.mjs.map} +1 -1
  700. package/dist/version-x0NjTScG.mjs +7 -0
  701. package/dist/{version-Bdfb34kk.mjs.map → version-x0NjTScG.mjs.map} +1 -1
  702. package/dist/{widgets-L-VndTKD.mjs → widgets-Cwzvww0W.mjs} +3 -3
  703. package/dist/{widgets-L-VndTKD.mjs.map → widgets-Cwzvww0W.mjs.map} +1 -1
  704. package/dist/{wxr-taxonomies-DueaLFd9.d.mts → wxr-taxonomies-CmC0ZsDr.d.mts} +1 -1
  705. package/dist/{wxr-taxonomies-DueaLFd9.d.mts.map → wxr-taxonomies-CmC0ZsDr.d.mts.map} +1 -1
  706. package/dist/{wxr-taxonomies-BexjtNid.mjs → wxr-taxonomies-QZjWxjyk.mjs} +13 -32
  707. package/dist/{wxr-taxonomies-BexjtNid.mjs.map → wxr-taxonomies-QZjWxjyk.mjs.map} +1 -1
  708. package/dist/{zod-generator-DMzfga3g.mjs → zod-generator-D11MhxG4.mjs} +53 -6
  709. package/dist/zod-generator-D11MhxG4.mjs.map +1 -0
  710. package/package.json +18 -7
  711. package/src/after.ts +6 -1
  712. package/src/api/errors.ts +13 -0
  713. package/src/api/handlers/content.ts +172 -33
  714. package/src/api/handlers/dashboard.ts +12 -2
  715. package/src/api/handlers/index.ts +16 -0
  716. package/src/api/handlers/manifest.ts +2 -0
  717. package/src/api/handlers/marketplace.ts +14 -0
  718. package/src/api/handlers/media-allowlist.ts +13 -2
  719. package/src/api/handlers/media-usage-work.ts +188 -0
  720. package/src/api/handlers/media-usage.ts +5 -3
  721. package/src/api/handlers/registry.ts +14 -0
  722. package/src/api/handlers/revision.ts +19 -5
  723. package/src/api/handlers/schema.ts +46 -3
  724. package/src/api/handlers/seo.ts +5 -2
  725. package/src/api/handlers/snapshot.ts +1 -1
  726. package/src/api/handlers/taxonomies.ts +446 -83
  727. package/src/api/media-usage-write-fence.ts +64 -0
  728. package/src/api/openapi/document.ts +247 -0
  729. package/src/api/public-url.ts +14 -2
  730. package/src/api/schemas/common.ts +3 -1
  731. package/src/api/schemas/content.ts +122 -1
  732. package/src/api/schemas/media-usage.ts +133 -0
  733. package/src/api/schemas/schema.ts +91 -3
  734. package/src/api/schemas/search.ts +2 -0
  735. package/src/api/schemas/taxonomies.ts +58 -8
  736. package/src/api/site-url.ts +16 -6
  737. package/src/api/types.ts +1 -0
  738. package/src/astro/integration/index.ts +55 -42
  739. package/src/astro/integration/routes.ts +48 -4
  740. package/src/astro/integration/runtime.ts +28 -0
  741. package/src/astro/integration/virtual-modules.ts +27 -1
  742. package/src/astro/integration/vite-config.ts +16 -1
  743. package/src/astro/middleware/media-usage-write-fence.ts +30 -0
  744. package/src/astro/middleware/redirect.ts +14 -12
  745. package/src/astro/middleware/scoped-db.ts +35 -4
  746. package/src/astro/middleware.ts +131 -30
  747. package/src/astro/routes/api/admin/comments/[id]/status.ts +1 -1
  748. package/src/astro/routes/api/admin/media-usage/collection-deletions/index.ts +22 -0
  749. package/src/astro/routes/api/admin/media-usage/collection-deletions/retry.ts +22 -0
  750. package/src/astro/routes/api/admin/media-usage/work/index.ts +26 -0
  751. package/src/astro/routes/api/admin/media-usage/work/retry.ts +26 -0
  752. package/src/astro/routes/api/admin/plugins/[id]/disable.ts +4 -0
  753. package/src/astro/routes/api/admin/plugins/[id]/enable.ts +4 -0
  754. package/src/astro/routes/api/admin/plugins/[id]/uninstall.ts +4 -0
  755. package/src/astro/routes/api/admin/plugins/[id]/update.ts +4 -0
  756. package/src/astro/routes/api/admin/plugins/marketplace/[id]/install.ts +4 -0
  757. package/src/astro/routes/api/admin/plugins/registry/[id]/uninstall.ts +4 -0
  758. package/src/astro/routes/api/admin/plugins/registry/[id]/update.ts +4 -0
  759. package/src/astro/routes/api/admin/plugins/registry/install.ts +4 -0
  760. package/src/astro/routes/api/admin/users/[id]/send-recovery.ts +2 -2
  761. package/src/astro/routes/api/auth/invite/index.ts +2 -2
  762. package/src/astro/routes/api/auth/magic-link/send.ts +2 -2
  763. package/src/astro/routes/api/auth/signup/request.ts +2 -2
  764. package/src/astro/routes/api/comments/[collection]/[contentId]/index.ts +1 -1
  765. package/src/astro/routes/api/content/[collection]/[id]/terms/[taxonomy].ts +67 -31
  766. package/src/astro/routes/api/import/wordpress/execute.ts +3 -10
  767. package/src/astro/routes/api/mcp.ts +1 -0
  768. package/src/astro/routes/api/plugins/[pluginId]/[...path].ts +7 -1
  769. package/src/astro/routes/api/schema/collections/[slug]/index.ts +1 -7
  770. package/src/astro/routes/api/schema/collections/reorder.ts +31 -0
  771. package/src/astro/routes/api/schema/index.ts +2 -0
  772. package/src/astro/routes/api/search/enable.ts +5 -1
  773. package/src/astro/routes/api/search/rebuild.ts +6 -1
  774. package/src/astro/routes/api/taxonomies/[name]/reorder.ts +41 -0
  775. package/src/astro/routes/api/taxonomies/[name]/terms/index.ts +1 -0
  776. package/src/astro/routes/api/taxonomies/[name]/translations.ts +48 -0
  777. package/src/astro/routes/api/taxonomies/[name].ts +102 -0
  778. package/src/astro/types.ts +31 -4
  779. package/src/cleanup.ts +25 -26
  780. package/src/cli/commands/dev.ts +13 -3
  781. package/src/cli/commands/doctor.ts +193 -6
  782. package/src/cli/commands/export-seed.ts +6 -1
  783. package/src/cli/index.ts +1 -1
  784. package/src/client/index.ts +119 -0
  785. package/src/components/Block.astro +12 -0
  786. package/src/components/CommentForm.astro +1 -1
  787. package/src/components/Comments.astro +1 -1
  788. package/src/components/InlinePortableTextEditor.tsx +260 -32
  789. package/src/components/OrderedList.astro +14 -0
  790. package/src/components/PortableText.astro +26 -4
  791. package/src/components/index.ts +12 -1
  792. package/src/components/ordered-list.ts +549 -0
  793. package/src/content/converters/mark-safety.ts +120 -0
  794. package/src/content/converters/numbered-list.ts +148 -0
  795. package/src/content/converters/portable-text-to-prosemirror.ts +84 -25
  796. package/src/content/converters/prosemirror-to-portable-text.ts +35 -14
  797. package/src/content/converters/types.ts +2 -0
  798. package/src/content/portable-text-lists.ts +205 -0
  799. package/src/content-list-query.ts +29 -0
  800. package/src/database/dialect-helpers.ts +3 -22
  801. package/src/database/migrations/055_content_translation_group_locale_index.ts +67 -0
  802. package/src/database/migrations/056_taxonomy_term_sort_order.ts +189 -0
  803. package/src/database/migrations/057_collection_hidden.ts +24 -0
  804. package/src/database/migrations/058_collection_sort_order.ts +20 -0
  805. package/src/database/migrations/059_revision_prune_queue.ts +36 -0
  806. package/src/database/migrations/060_collection_admin_config.ts +16 -0
  807. package/src/database/migrations/061_media_usage_cleanup.ts +77 -0
  808. package/src/database/migrations/062_media_usage_cleanup_fence.ts +295 -0
  809. package/src/database/migrations/063_media_usage_incremental_work.ts +397 -0
  810. package/src/database/migrations/064_fts_plain_text.ts +253 -0
  811. package/src/database/migrations/065_media_usage_collection_deletion.ts +85 -0
  812. package/src/database/migrations/066_media_usage_reconciliation.ts +115 -0
  813. package/src/database/migrations/067_indexed_content_fields.ts +39 -0
  814. package/src/database/migrations/068_content_taxonomy_entry_groups.ts +61 -0
  815. package/src/database/migrations/069_collection_title_date_fields.ts +45 -0
  816. package/src/database/migrations/070_collection_routable.ts +18 -0
  817. package/src/database/migrations/runner.ts +32 -0
  818. package/src/database/repositories/content.ts +1051 -273
  819. package/src/database/repositories/media-usage-work.ts +848 -0
  820. package/src/database/repositories/media-usage.ts +1502 -138
  821. package/src/database/repositories/revision.ts +98 -22
  822. package/src/database/repositories/taxonomy.ts +429 -103
  823. package/src/database/repositories/types.ts +58 -2
  824. package/src/database/types.ts +147 -17
  825. package/src/database/validate.ts +39 -0
  826. package/src/db/adapters.ts +36 -0
  827. package/src/db/index.ts +3 -0
  828. package/src/deferred-tasks.ts +71 -0
  829. package/src/emdash-runtime.ts +493 -110
  830. package/src/fields/file.ts +7 -4
  831. package/src/fields/image.ts +8 -1
  832. package/src/fields/types.ts +18 -5
  833. package/src/i18n/config.ts +32 -0
  834. package/src/i18n/repair-locale-casing.ts +0 -14
  835. package/src/i18n/taxonomy-locale-diagnostic.ts +47 -0
  836. package/src/import/wxr-taxonomies.ts +7 -47
  837. package/src/index.ts +27 -2
  838. package/src/loader.ts +165 -89
  839. package/src/mcp/server.ts +242 -34
  840. package/src/media/usage/activation.ts +626 -0
  841. package/src/media/usage/capture-triggers.ts +543 -0
  842. package/src/media/usage/cleanup.ts +305 -0
  843. package/src/media/usage/collection-deletion-processor.ts +356 -0
  844. package/src/media/usage/collection-deletion.ts +836 -0
  845. package/src/media/usage/content-fields.ts +40 -3
  846. package/src/media/usage/content-refresh.ts +356 -47
  847. package/src/media/usage/content-repair.ts +180 -61
  848. package/src/media/usage/content-snapshots.ts +85 -105
  849. package/src/media/usage/gc.ts +50 -0
  850. package/src/media/usage/projection-fingerprint.ts +129 -0
  851. package/src/media/usage/reconciliation-processor.ts +372 -0
  852. package/src/media/usage/reconciliation.ts +1117 -0
  853. package/src/media/usage/source-key.ts +4 -0
  854. package/src/media/usage/types.ts +2 -0
  855. package/src/media/usage/work-processor.ts +248 -0
  856. package/src/menus/index.ts +246 -141
  857. package/src/object-cache/index.ts +160 -3
  858. package/src/plugin-types.ts +8 -0
  859. package/src/plugins/adapt-sandbox-entry.ts +24 -5
  860. package/src/plugins/context.ts +24 -7
  861. package/src/plugins/index.ts +9 -0
  862. package/src/plugins/routes.ts +77 -1
  863. package/src/plugins/sandbox/index.ts +10 -1
  864. package/src/plugins/sandbox/types.ts +78 -1
  865. package/src/plugins/scheduler/node.ts +13 -1
  866. package/src/plugins/scheduler/types.ts +2 -0
  867. package/src/plugins/storage-indexes.ts +50 -11
  868. package/src/plugins/types.ts +39 -2
  869. package/src/query.ts +50 -79
  870. package/src/redirects/cache.ts +79 -19
  871. package/src/request-context.ts +3 -0
  872. package/src/scheduled-publish.ts +6 -1
  873. package/src/scheduler-health.ts +46 -0
  874. package/src/schema/registry.ts +863 -249
  875. package/src/schema/types.ts +74 -8
  876. package/src/schema/url-pattern.ts +33 -0
  877. package/src/schema/zod-generator.ts +77 -5
  878. package/src/search/fts-manager.ts +167 -86
  879. package/src/search/index.ts +2 -0
  880. package/src/search/query.ts +32 -11
  881. package/src/search/types.ts +8 -0
  882. package/src/seed/apply.ts +89 -16
  883. package/src/seed/types.ts +21 -3
  884. package/src/seed/validate.ts +52 -2
  885. package/src/taxonomies/index.ts +88 -82
  886. package/src/taxonomies/term-counts.ts +23 -12
  887. package/src/ui-comments.ts +19 -0
  888. package/src/ui.ts +11 -3
  889. package/src/utils/slugify.ts +1 -29
  890. package/src/virtual-modules.d.ts +24 -0
  891. package/dist/adapters-C0ONzkUP.d.mts.map +0 -1
  892. package/dist/after-B1IIdH3Y.mjs +0 -29
  893. package/dist/after-B1IIdH3Y.mjs.map +0 -1
  894. package/dist/api-DgPbMlng.mjs.map +0 -1
  895. package/dist/apply-1_6ra7NP.mjs.map +0 -1
  896. package/dist/cache-B26cufFd.mjs +0 -65
  897. package/dist/cache-B26cufFd.mjs.map +0 -1
  898. package/dist/config-DyF3OKg_.mjs.map +0 -1
  899. package/dist/content-CpfKV9QE.mjs.map +0 -1
  900. package/dist/content-refresh-DgqUBeTv.mjs +0 -1629
  901. package/dist/content-refresh-DgqUBeTv.mjs.map +0 -1
  902. package/dist/context-kO4YZB03.mjs.map +0 -1
  903. package/dist/dashboard-DoBwPnON.mjs.map +0 -1
  904. package/dist/dialect-helpers-DFwyWjTM.mjs.map +0 -1
  905. package/dist/errors-DtEXIQQV.mjs.map +0 -1
  906. package/dist/fts-manager-vncsZIJm.mjs.map +0 -1
  907. package/dist/index-BeNto_Vs.d.mts.map +0 -1
  908. package/dist/index-j9rTh3cp.d.mts.map +0 -1
  909. package/dist/loader-C1XOLV5b.mjs.map +0 -1
  910. package/dist/media-DWIzoVFL.mjs.map +0 -1
  911. package/dist/media-allowlist-B7TPD6aq.mjs.map +0 -1
  912. package/dist/media-usage-DPJcNaAq.mjs.map +0 -1
  913. package/dist/menus-C6qhqP4X.mjs.map +0 -1
  914. package/dist/object-cache-Bok5j2ae.mjs.map +0 -1
  915. package/dist/options-aeIs8WFu.d.mts.map +0 -1
  916. package/dist/public-url-DSGTnJFw.mjs.map +0 -1
  917. package/dist/query-DCiXI7OZ.mjs.map +0 -1
  918. package/dist/redirects-BOn2DIUs.mjs.map +0 -1
  919. package/dist/registry-BP1JK2xh.mjs +0 -795
  920. package/dist/registry-BP1JK2xh.mjs.map +0 -1
  921. package/dist/relations-DHFQGX0h.d.mts.map +0 -1
  922. package/dist/runner-BsI18UgP.mjs.map +0 -1
  923. package/dist/search-CeO678cp.mjs.map +0 -1
  924. package/dist/seo-C3GDfT0V.mjs.map +0 -1
  925. package/dist/site-url-8N3kSyVZ.mjs +0 -13
  926. package/dist/site-url-8N3kSyVZ.mjs.map +0 -1
  927. package/dist/slugify-C_tqlU4G.mjs +0 -30
  928. package/dist/slugify-C_tqlU4G.mjs.map +0 -1
  929. package/dist/taxonomies-B61CRSha.mjs.map +0 -1
  930. package/dist/taxonomies-Dbdki3Un.mjs.map +0 -1
  931. package/dist/taxonomy-DvwWAPvA.mjs +0 -304
  932. package/dist/taxonomy-DvwWAPvA.mjs.map +0 -1
  933. package/dist/types-84Bque3-.d.mts.map +0 -1
  934. package/dist/types-BQY7VYw6.d.mts.map +0 -1
  935. package/dist/types-DqZVPILm.d.mts.map +0 -1
  936. package/dist/types-XrQQ-Aex.mjs.map +0 -1
  937. package/dist/types-jISEalTX.d.mts.map +0 -1
  938. package/dist/types-o7xo7VgH.mjs.map +0 -1
  939. package/dist/validate-Bs_wT2ul.mjs.map +0 -1
  940. package/dist/validate-CdYcY-Ln.d.mts.map +0 -1
  941. package/dist/validate-VPnKoIzW.mjs.map +0 -1
  942. package/dist/version-Bdfb34kk.mjs +0 -7
  943. package/dist/zod-generator-DMzfga3g.mjs.map +0 -1
  944. /package/dist/{api-tokens-CEsW_jCg.mjs → api-tokens-CyTsLszZ.mjs} +0 -0
  945. /package/dist/{ssrf-BB__xfNM.mjs → ssrf-DpXgKsna.mjs} +0 -0
  946. /package/dist/{types-CK0LxPUQ.mjs → types-CP1CflWf.mjs} +0 -0
@@ -1 +1 @@
1
- {"version":3,"file":"redirects-Cwkq2H-G.mjs","names":[],"sources":["../src/redirects/loops.ts","../src/api/handlers/redirects.ts"],"sourcesContent":["/**\n * Redirect loop and chain detection utilities.\n *\n * Builds a directed graph from redirect rules and detects:\n * - Cycles (loops): /a → /b → /c → /a\n * - Long chains: /a → /b → /c → /d → /e (exceeding a warning threshold)\n *\n * Handles both exact and pattern redirects. When the walker encounters\n * a path with no exact source match, it tests against compiled pattern\n * sources and resolves the destination using captured parameters.\n */\n\nimport {\n\tcompilePattern,\n\tmatchPattern,\n\tinterpolateDestination,\n\ttype CompiledPattern,\n} from \"./patterns.js\";\n\nexport interface RedirectEdge {\n\tid: string;\n\tsource: string;\n\tdestination: string;\n\tenabled: boolean;\n\tisPattern: boolean;\n}\n\ninterface CompiledPatternRedirect {\n\tid: string;\n\tcompiled: CompiledPattern;\n\tdestination: string;\n}\n\n/**\n * Compile all enabled pattern redirects for matching during graph walks.\n */\nfunction compilePatterns(edges: RedirectEdge[]): CompiledPatternRedirect[] {\n\tconst result: CompiledPatternRedirect[] = [];\n\tfor (const edge of edges) {\n\t\tif (edge.enabled && edge.isPattern) {\n\t\t\tresult.push({\n\t\t\t\tid: edge.id,\n\t\t\t\tcompiled: compilePattern(edge.source),\n\t\t\t\tdestination: edge.destination,\n\t\t\t});\n\t\t}\n\t}\n\treturn result;\n}\n\n/** Single-segment dummy value for representative path generation */\nconst DUMMY_SEGMENT = \"__p__\";\n\n/** Splat pattern: [...paramName] */\nconst SPLAT_RE = /\\[\\.\\.\\.(\\w+)\\]/g;\n\n/** Param pattern: [paramName] */\nconst PARAM_RE = /\\[(\\w+)\\]/g;\n\n/**\n * Extract the literal prefix from a pattern source (everything before the\n * first placeholder), stripped of leading segments shared with a base path.\n * e.g., \"/new/docs/[slug]\" → \"docs/__p__\" (the part after \"/new/\")\n */\nfunction extractPatternSuffix(patternSource: string): string {\n\t// Replace placeholders with dummy values\n\tlet result = patternSource.replace(SPLAT_RE, DUMMY_SEGMENT);\n\tSPLAT_RE.lastIndex = 0;\n\tresult = result.replace(PARAM_RE, DUMMY_SEGMENT);\n\t// Strip leading slash and first segment (e.g., \"/new/docs/__p__\" → \"docs/__p__\")\n\tconst parts = result.split(\"/\").filter(Boolean);\n\treturn parts.slice(1).join(\"/\");\n}\n\n/**\n * Generate representative concrete paths from a template string.\n * Replaces [param] with a dummy segment and [...rest] with multiple\n * depth variants. For catch-alls, also generates representatives using\n * literal prefixes from existing pattern sources to catch cross-pattern loops.\n */\nfunction generateRepresentatives(template: string, existingEdges?: RedirectEdge[]): string[] {\n\tconst hasSplat = SPLAT_RE.test(template);\n\tSPLAT_RE.lastIndex = 0;\n\n\tif (hasSplat) {\n\t\t// Extract the static prefix before the catch-all (e.g., \"/old/\" from \"/old/[...path]\")\n\t\tconst splatIndex = template.indexOf(\"[...\");\n\t\tconst prefix = template.slice(0, splatIndex);\n\n\t\tconst reps = [\n\t\t\ttemplate.replace(SPLAT_RE, DUMMY_SEGMENT).replace(PARAM_RE, DUMMY_SEGMENT),\n\t\t\ttemplate\n\t\t\t\t.replace(SPLAT_RE, `${DUMMY_SEGMENT}/${DUMMY_SEGMENT}`)\n\t\t\t\t.replace(PARAM_RE, DUMMY_SEGMENT),\n\t\t\ttemplate\n\t\t\t\t.replace(SPLAT_RE, `${DUMMY_SEGMENT}/${DUMMY_SEGMENT}/${DUMMY_SEGMENT}`)\n\t\t\t\t.replace(PARAM_RE, DUMMY_SEGMENT),\n\t\t];\n\n\t\t// Add representatives derived from existing pattern sources' literal prefixes\n\t\tif (existingEdges) {\n\t\t\tfor (const edge of existingEdges) {\n\t\t\t\tif (edge.enabled && edge.isPattern && edge.source !== template) {\n\t\t\t\t\tconst suffix = extractPatternSuffix(edge.source);\n\t\t\t\t\tif (suffix) {\n\t\t\t\t\t\treps.push(`${prefix}${suffix}`);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn reps;\n\t}\n\n\treturn [template.replace(PARAM_RE, DUMMY_SEGMENT)];\n}\n\n/**\n * Resolve the next hop for a given path. Tries exact match first,\n * then pattern matching with parameter interpolation for concrete paths,\n * then representative-based matching for template strings.\n */\nfunction resolveNext(\n\tpath: string,\n\tgraph: Map<string, { destination: string; id: string }>,\n\tpatterns: CompiledPatternRedirect[],\n\tedges?: RedirectEdge[],\n): { destination: string; id: string } | null {\n\t// Exact match (fast) — works for both real paths and template strings\n\tconst exact = graph.get(path);\n\tif (exact) return exact;\n\n\tif (!path.includes(\"[\")) {\n\t\t// Concrete path — try pattern matching directly\n\t\tfor (const pr of patterns) {\n\t\t\tconst params = matchPattern(pr.compiled, path);\n\t\t\tif (params) {\n\t\t\t\tconst resolved = interpolateDestination(pr.destination, params);\n\t\t\t\treturn { destination: resolved, id: pr.id };\n\t\t\t}\n\t\t}\n\t} else {\n\t\t// Template string — generate representative paths and test against patterns\n\t\tconst representatives = generateRepresentatives(path, edges);\n\t\tfor (const pr of patterns) {\n\t\t\tfor (const rep of representatives) {\n\t\t\t\tconst params = matchPattern(pr.compiled, rep);\n\t\t\t\tif (params) {\n\t\t\t\t\tconst resolved = interpolateDestination(pr.destination, params);\n\t\t\t\t\treturn { destination: resolved, id: pr.id };\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn null;\n}\n\n/**\n * Build an adjacency map from redirect edges.\n * Includes both exact and pattern redirects — pattern redirects use their\n * template strings as literal graph edges, which works because EmDash\n * patterns pass parameters through without transformation.\n */\nfunction buildGraph(edges: RedirectEdge[]): Map<string, { destination: string; id: string }> {\n\tconst graph = new Map<string, { destination: string; id: string }>();\n\tfor (const edge of edges) {\n\t\tif (edge.enabled) {\n\t\t\tgraph.set(edge.source, { destination: edge.destination, id: edge.id });\n\t\t}\n\t}\n\treturn graph;\n}\n\n/**\n * Detect all redirect IDs that participate in cycles.\n * Walks every node in the graph once, collecting IDs from any cycles found.\n *\n * @returns Array of redirect IDs that are part of a loop\n */\nexport function detectLoops(edges: RedirectEdge[]): string[] {\n\tconst graph = buildGraph(edges);\n\tconst patterns = compilePatterns(edges);\n\tconst visited = new Set<string>();\n\tconst loopRedirectIds = new Set<string>();\n\n\tfor (const [startSource] of graph) {\n\t\tif (visited.has(startSource)) continue;\n\n\t\tconst path: string[] = [];\n\t\tconst pathSet = new Set<string>();\n\t\tconst pathIds: string[] = [];\n\t\tlet current: string | undefined = startSource;\n\n\t\twhile (current) {\n\t\t\tif (pathSet.has(current)) {\n\t\t\t\t// Found a cycle — collect IDs of redirects in the loop\n\t\t\t\tconst loopStart = path.indexOf(current);\n\t\t\t\tfor (const id of pathIds.slice(loopStart)) loopRedirectIds.add(id);\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tif (visited.has(current)) {\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tconst next = resolveNext(current, graph, patterns, edges);\n\t\t\tif (!next) break;\n\n\t\t\tpath.push(current);\n\t\t\tpathSet.add(current);\n\t\t\tpathIds.push(next.id);\n\t\t\tcurrent = next.destination;\n\t\t}\n\n\t\tfor (const node of path) visited.add(node);\n\t}\n\n\treturn [...loopRedirectIds];\n}\n\n/**\n * Find a compiled pattern redirect whose source matches the given resolved path,\n * returning the source template string for display purposes.\n */\nfunction findMatchingTemplate(\n\tresolvedPath: string,\n\tpatterns: CompiledPatternRedirect[],\n): string | null {\n\tfor (const pr of patterns) {\n\t\tif (matchPattern(pr.compiled, resolvedPath) !== null) {\n\t\t\treturn pr.compiled.source;\n\t\t}\n\t}\n\treturn null;\n}\n\n/**\n * Check if adding or updating a redirect would create a loop.\n *\n * Walks the chain from `destination` through existing redirects.\n * If it reaches `source`, a cycle would form.\n *\n * @returns The loop path if a cycle would be created, or null if safe\n */\nexport function wouldCreateLoop(\n\tsource: string,\n\tdestination: string,\n\texistingEdges: RedirectEdge[],\n\texcludeId?: string,\n): string[] | null {\n\tconst filtered = excludeId ? existingEdges.filter((e) => e.id !== excludeId) : existingEdges;\n\tconst graph = buildGraph(filtered);\n\tconst patterns = compilePatterns(filtered);\n\n\t// If the proposed source is a pattern, compile it so we can check\n\t// whether resolved paths would match it (not just string equality)\n\tconst sourceIsPattern = source.includes(\"[\");\n\tconst compiledSource = sourceIsPattern ? compilePattern(source) : null;\n\n\t// Determine starting points for the walk. If the destination is a\n\t// template, generate representative concrete paths AND find existing\n\t// exact sources in the graph that match the template.\n\tlet startingPoints: string[];\n\tif (destination.includes(\"[\")) {\n\t\tconst reps = generateRepresentatives(destination, filtered);\n\t\t// Also find existing exact graph keys that match this template\n\t\tconst compiled = compilePattern(destination);\n\t\tfor (const [key] of graph) {\n\t\t\tif (!key.includes(\"[\") && matchPattern(compiled, key) !== null) {\n\t\t\t\treps.push(key);\n\t\t\t}\n\t\t}\n\t\t// Always include the destination itself — it may be an exact graph key\n\t\t// (e.g., /a/sub/[...path] exists as a literal source in the graph)\n\t\treps.push(destination);\n\t\tstartingPoints = reps;\n\t} else {\n\t\tstartingPoints = [destination];\n\t}\n\n\tfor (const start of startingPoints) {\n\t\tconst path = [source, destination];\n\t\tlet current = start;\n\t\tconst seen = new Set<string>([source, destination, start]);\n\n\t\t// Walk the chain until it ends or we revisit a node\n\t\t// eslint-disable-next-line no-constant-condition -- terminates via return/break when chain ends or cycle found\n\t\twhile (true) {\n\t\t\tconst next = resolveNext(current, graph, patterns, filtered);\n\t\t\tif (!next) break; // chain ends, try next starting point\n\n\t\t\t// Check if we've looped back — either exact match or pattern match\n\t\t\tconst loopsBack =\n\t\t\t\tseen.has(next.destination) ||\n\t\t\t\t(compiledSource !== null && matchPattern(compiledSource, next.destination) !== null);\n\n\t\t\tif (loopsBack) {\n\t\t\t\t// Show the source template instead of dummy resolved path\n\t\t\t\tconst displayPath =\n\t\t\t\t\t!seen.has(next.destination) && compiledSource !== null ? source : next.destination;\n\t\t\t\tpath.push(displayPath);\n\t\t\t\treturn path; // cycle found\n\t\t\t}\n\n\t\t\t// If the resolved path contains dummy segments, try to find the\n\t\t\t// original pattern template that produced it for cleaner display\n\t\t\tconst cleanDest = next.destination.includes(DUMMY_SEGMENT)\n\t\t\t\t? (findMatchingTemplate(next.destination, patterns) ?? next.destination)\n\t\t\t\t: next.destination;\n\t\t\tpath.push(cleanDest);\n\t\t\tseen.add(next.destination);\n\t\t\tcurrent = next.destination;\n\t\t}\n\t}\n\n\treturn null;\n}\n","/**\n * Redirect CRUD and 404 log handlers\n */\n\nimport type { Kysely } from \"kysely\";\n\nimport { OptionsRepository } from \"../../database/repositories/options.js\";\nimport {\n\tRedirectRepository,\n\ttype Redirect,\n\ttype NotFoundEntry,\n\ttype NotFoundSummary,\n} from \"../../database/repositories/redirect.js\";\nimport { InvalidCursorError } from \"../../database/repositories/types.js\";\nimport type { FindManyResult } from \"../../database/repositories/types.js\";\nimport type { Database } from \"../../database/types.js\";\nimport { wouldCreateLoop, detectLoops, type RedirectEdge } from \"../../redirects/loops.js\";\nimport { validatePattern, validateDestinationParams, isPattern } from \"../../redirects/patterns.js\";\nimport { isTerminalStatus } from \"../../redirects/status.js\";\nimport type { ApiResult } from \"../types.js\";\n\n// ---------------------------------------------------------------------------\n// Redirects\n// ---------------------------------------------------------------------------\n\n/**\n * List redirects with cursor pagination and optional filters\n */\nexport async function handleRedirectList(\n\tdb: Kysely<Database>,\n\tparams: {\n\t\tcursor?: string;\n\t\tlimit?: number;\n\t\tsearch?: string;\n\t\tgroup?: string;\n\t\tenabled?: boolean;\n\t\tauto?: boolean;\n\t},\n): Promise<ApiResult<FindManyResult<Redirect> & { loopRedirectIds?: string[] }>> {\n\ttry {\n\t\tconst repo = new RedirectRepository(db);\n\t\tconst result = await repo.findMany(params);\n\n\t\tconst loopRedirectIds = await getLoopRedirectIds(db);\n\n\t\treturn {\n\t\t\tsuccess: true,\n\t\t\tdata: {\n\t\t\t\t...result,\n\t\t\t\t...(loopRedirectIds.length > 0 ? { loopRedirectIds } : {}),\n\t\t\t},\n\t\t};\n\t} catch (error) {\n\t\tif (error instanceof InvalidCursorError) {\n\t\t\treturn {\n\t\t\t\tsuccess: false,\n\t\t\t\terror: { code: \"INVALID_CURSOR\", message: error.message },\n\t\t\t};\n\t\t}\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\terror: { code: \"REDIRECT_LIST_ERROR\", message: \"Failed to fetch redirects\" },\n\t\t};\n\t}\n}\n\n/**\n * Create a redirect rule\n */\nexport async function handleRedirectCreate(\n\tdb: Kysely<Database>,\n\tinput: {\n\t\tsource: string;\n\t\tdestination?: string;\n\t\ttype?: number;\n\t\tenabled?: boolean;\n\t\tgroupName?: string | null;\n\t},\n): Promise<ApiResult<Redirect>> {\n\ttry {\n\t\tconst repo = new RedirectRepository(db);\n\n\t\tconst type = input.type ?? 301;\n\t\t// Terminal statuses (410 Gone / 451) are served directly and have no\n\t\t// destination — skip the destination/loop checks for them.\n\t\tconst terminal = isTerminalStatus(type);\n\t\tconst destination = terminal ? \"\" : (input.destination ?? \"\");\n\n\t\t// Source and destination must differ\n\t\tif (!terminal && input.source === destination) {\n\t\t\treturn {\n\t\t\t\tsuccess: false,\n\t\t\t\terror: {\n\t\t\t\t\tcode: \"VALIDATION_ERROR\",\n\t\t\t\t\tmessage: \"Source and destination must be different\",\n\t\t\t\t},\n\t\t\t};\n\t\t}\n\n\t\t// If source looks like a pattern, validate it\n\t\tconst sourceIsPattern = isPattern(input.source);\n\t\tif (sourceIsPattern) {\n\t\t\tconst patternError = validatePattern(input.source);\n\t\t\tif (patternError) {\n\t\t\t\treturn {\n\t\t\t\t\tsuccess: false,\n\t\t\t\t\terror: { code: \"VALIDATION_ERROR\", message: `Invalid source pattern: ${patternError}` },\n\t\t\t\t};\n\t\t\t}\n\n\t\t\t// Validate destination params reference valid source params\n\t\t\t// (terminal rules have no destination to interpolate)\n\t\t\tif (!terminal) {\n\t\t\t\tconst destError = validateDestinationParams(input.source, destination);\n\t\t\t\tif (destError) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tsuccess: false,\n\t\t\t\t\t\terror: { code: \"VALIDATION_ERROR\", message: destError },\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Check for duplicate source (exact match only for non-patterns)\n\t\tconst existing = await repo.findBySource(input.source);\n\t\tif (existing) {\n\t\t\treturn {\n\t\t\t\tsuccess: false,\n\t\t\t\terror: {\n\t\t\t\t\tcode: \"CONFLICT\",\n\t\t\t\t\tmessage: `A redirect from \"${input.source}\" already exists`,\n\t\t\t\t},\n\t\t\t};\n\t\t}\n\n\t\t// Check for redirect loops (skip if creating as disabled, or terminal —\n\t\t// a Gone rule has no destination, so it can't form a loop)\n\t\tif (!terminal && input.enabled !== false) {\n\t\t\tconst edges = toEdges(await repo.findAllEnabled());\n\t\t\tconst loopPath = wouldCreateLoop(input.source, destination, edges);\n\t\t\tif (loopPath) return loopError(loopPath);\n\t\t}\n\n\t\tconst redirect = await repo.create({\n\t\t\tsource: input.source,\n\t\t\tdestination,\n\t\t\ttype,\n\t\t\tisPattern: sourceIsPattern,\n\t\t\tenabled: input.enabled ?? true,\n\t\t\tgroupName: input.groupName ?? null,\n\t\t});\n\n\t\treturn { success: true, data: redirect };\n\t} catch {\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\terror: { code: \"REDIRECT_CREATE_ERROR\", message: \"Failed to create redirect\" },\n\t\t};\n\t}\n}\n\n/**\n * Get a redirect by ID\n */\nexport async function handleRedirectGet(\n\tdb: Kysely<Database>,\n\tid: string,\n): Promise<ApiResult<Redirect>> {\n\ttry {\n\t\tconst repo = new RedirectRepository(db);\n\t\tconst redirect = await repo.findById(id);\n\n\t\tif (!redirect) {\n\t\t\treturn {\n\t\t\t\tsuccess: false,\n\t\t\t\terror: { code: \"NOT_FOUND\", message: `Redirect \"${id}\" not found` },\n\t\t\t};\n\t\t}\n\n\t\treturn { success: true, data: redirect };\n\t} catch {\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\terror: { code: \"REDIRECT_GET_ERROR\", message: \"Failed to fetch redirect\" },\n\t\t};\n\t}\n}\n\n/**\n * Update a redirect by ID\n */\nexport async function handleRedirectUpdate(\n\tdb: Kysely<Database>,\n\tid: string,\n\tinput: {\n\t\tsource?: string;\n\t\tdestination?: string;\n\t\ttype?: number;\n\t\tenabled?: boolean;\n\t\tgroupName?: string | null;\n\t},\n): Promise<ApiResult<Redirect>> {\n\ttry {\n\t\tconst repo = new RedirectRepository(db);\n\n\t\tconst existing = await repo.findById(id);\n\t\tif (!existing) {\n\t\t\treturn {\n\t\t\t\tsuccess: false,\n\t\t\t\terror: { code: \"NOT_FOUND\", message: `Redirect \"${id}\" not found` },\n\t\t\t};\n\t\t}\n\n\t\tconst newSource = input.source ?? existing.source;\n\t\tconst newDest = input.destination ?? existing.destination;\n\n\t\t// Source and destination must differ\n\t\tif (newSource === newDest) {\n\t\t\treturn {\n\t\t\t\tsuccess: false,\n\t\t\t\terror: {\n\t\t\t\t\tcode: \"VALIDATION_ERROR\",\n\t\t\t\t\tmessage: \"Source and destination must be different\",\n\t\t\t\t},\n\t\t\t};\n\t\t}\n\n\t\t// If source is changing, validate patterns\n\t\tif (input.source !== undefined) {\n\t\t\tconst sourceIsPattern = isPattern(input.source);\n\t\t\tif (sourceIsPattern) {\n\t\t\t\tconst patternError = validatePattern(input.source);\n\t\t\t\tif (patternError) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tsuccess: false,\n\t\t\t\t\t\terror: {\n\t\t\t\t\t\t\tcode: \"VALIDATION_ERROR\",\n\t\t\t\t\t\t\tmessage: `Invalid source pattern: ${patternError}`,\n\t\t\t\t\t\t},\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Check for duplicate source (exclude self)\n\t\t\tconst dup = await repo.findBySource(input.source);\n\t\t\tif (dup && dup.id !== id) {\n\t\t\t\treturn {\n\t\t\t\t\tsuccess: false,\n\t\t\t\t\terror: {\n\t\t\t\t\t\tcode: \"CONFLICT\",\n\t\t\t\t\t\tmessage: `A redirect from \"${input.source}\" already exists`,\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\n\t\t// Validate destination params against the (possibly updated) source\n\t\tconst newSourceIsPattern = isPattern(newSource);\n\t\tif (newSourceIsPattern) {\n\t\t\tconst destError = validateDestinationParams(newSource, newDest);\n\t\t\tif (destError) {\n\t\t\t\treturn {\n\t\t\t\t\tsuccess: false,\n\t\t\t\t\terror: { code: \"VALIDATION_ERROR\", message: destError },\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\n\t\t// Check for redirect loops if source or destination changed\n\t\tif (input.source !== undefined || input.destination !== undefined) {\n\t\t\tconst edges = toEdges(await repo.findAllEnabled());\n\t\t\tconst loopPath = wouldCreateLoop(newSource, newDest, edges, id);\n\t\t\tif (loopPath) return loopError(loopPath);\n\t\t}\n\n\t\tconst updated = await repo.update(id, {\n\t\t\tsource: input.source,\n\t\t\tdestination: input.destination,\n\t\t\ttype: input.type,\n\t\t\tenabled: input.enabled,\n\t\t\tgroupName: input.groupName,\n\t\t});\n\n\t\tif (!updated) {\n\t\t\treturn {\n\t\t\t\tsuccess: false,\n\t\t\t\terror: { code: \"REDIRECT_UPDATE_ERROR\", message: \"Failed to update redirect\" },\n\t\t\t};\n\t\t}\n\n\t\t// Recompute cache — redirect was modified, so re-fetch\n\t\tawait updateLoopCache(db);\n\n\t\treturn { success: true, data: updated };\n\t} catch {\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\terror: { code: \"REDIRECT_UPDATE_ERROR\", message: \"Failed to update redirect\" },\n\t\t};\n\t}\n}\n\n/**\n * Delete a redirect by ID\n */\nexport async function handleRedirectDelete(\n\tdb: Kysely<Database>,\n\tid: string,\n): Promise<ApiResult<{ deleted: true }>> {\n\ttry {\n\t\tconst repo = new RedirectRepository(db);\n\t\tconst deleted = await repo.delete(id);\n\n\t\tif (!deleted) {\n\t\t\treturn {\n\t\t\t\tsuccess: false,\n\t\t\t\terror: { code: \"NOT_FOUND\", message: `Redirect \"${id}\" not found` },\n\t\t\t};\n\t\t}\n\n\t\tawait updateLoopCache(db);\n\n\t\treturn { success: true, data: { deleted: true } };\n\t} catch {\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\terror: { code: \"REDIRECT_DELETE_ERROR\", message: \"Failed to delete redirect\" },\n\t\t};\n\t}\n}\n\n// ---------------------------------------------------------------------------\n// Loop analysis cache\n// ---------------------------------------------------------------------------\n\nfunction loopError(loopPath: string[]): ApiResult<never> {\n\tconst hops = loopPath\n\t\t.slice(0, -1)\n\t\t.map((p, i) => `${p} \\u2192 ${loopPath[i + 1]}`)\n\t\t.join(\"\\n\");\n\treturn {\n\t\tsuccess: false,\n\t\terror: {\n\t\t\tcode: \"VALIDATION_ERROR\",\n\t\t\tmessage: `This redirect would create a loop:\\n${hops}`,\n\t\t},\n\t};\n}\n\nfunction toEdges(redirects: Redirect[]): RedirectEdge[] {\n\treturn redirects.map((r) => ({\n\t\tid: r.id,\n\t\tsource: r.source,\n\t\tdestination: r.destination,\n\t\tenabled: r.enabled,\n\t\tisPattern: r.isPattern,\n\t}));\n}\n\nconst LOOP_CACHE_KEY = \"_redirect_loop_ids\";\n\n/**\n * Recompute loop redirect IDs and store in the options table.\n */\nasync function updateLoopCache(db: Kysely<Database>): Promise<void> {\n\ttry {\n\t\tconst options = new OptionsRepository(db);\n\t\tconst edges = toEdges(await new RedirectRepository(db).findAllEnabled());\n\t\tconst loopRedirectIds = detectLoops(edges);\n\t\tawait options.set(LOOP_CACHE_KEY, loopRedirectIds);\n\t} catch (error) {\n\t\tconsole.error(\"Failed to update redirect loop cache:\", error);\n\t}\n}\n\n/**\n * Get loop redirect IDs from cache, computing lazily on first access.\n */\nasync function getLoopRedirectIds(db: Kysely<Database>): Promise<string[]> {\n\ttry {\n\t\tconst options = new OptionsRepository(db);\n\t\tconst cached = await options.get<string[]>(LOOP_CACHE_KEY);\n\t\tif (cached !== null) return cached;\n\n\t\t// First access after upgrade — compute and cache\n\t\tawait updateLoopCache(db);\n\t\treturn (await options.get<string[]>(LOOP_CACHE_KEY)) ?? [];\n\t} catch {\n\t\treturn [];\n\t}\n}\n\n// ---------------------------------------------------------------------------\n// 404 Log\n// ---------------------------------------------------------------------------\n\n/**\n * List 404 log entries with cursor pagination\n */\nexport async function handleNotFoundList(\n\tdb: Kysely<Database>,\n\tparams: { cursor?: string; limit?: number; search?: string },\n): Promise<ApiResult<FindManyResult<NotFoundEntry>>> {\n\ttry {\n\t\tconst repo = new RedirectRepository(db);\n\t\tconst result = await repo.find404s(params);\n\t\treturn { success: true, data: result };\n\t} catch (error) {\n\t\tif (error instanceof InvalidCursorError) {\n\t\t\treturn {\n\t\t\t\tsuccess: false,\n\t\t\t\terror: { code: \"INVALID_CURSOR\", message: error.message },\n\t\t\t};\n\t\t}\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\terror: { code: \"NOT_FOUND_LIST_ERROR\", message: \"Failed to fetch 404 log\" },\n\t\t};\n\t}\n}\n\n/**\n * Get 404 summary (grouped by path, sorted by count)\n */\nexport async function handleNotFoundSummary(\n\tdb: Kysely<Database>,\n\tlimit?: number,\n): Promise<ApiResult<{ items: NotFoundSummary[] }>> {\n\ttry {\n\t\tconst repo = new RedirectRepository(db);\n\t\tconst items = await repo.get404Summary(limit);\n\t\treturn { success: true, data: { items } };\n\t} catch {\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\terror: { code: \"NOT_FOUND_SUMMARY_ERROR\", message: \"Failed to fetch 404 summary\" },\n\t\t};\n\t}\n}\n\n/**\n * Clear all 404 log entries\n */\nexport async function handleNotFoundClear(\n\tdb: Kysely<Database>,\n): Promise<ApiResult<{ deleted: number }>> {\n\ttry {\n\t\tconst repo = new RedirectRepository(db);\n\t\tconst deleted = await repo.clear404s();\n\t\treturn { success: true, data: { deleted } };\n\t} catch {\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\terror: { code: \"NOT_FOUND_CLEAR_ERROR\", message: \"Failed to clear 404 log\" },\n\t\t};\n\t}\n}\n\n/**\n * Prune 404 log entries older than a given date\n */\nexport async function handleNotFoundPrune(\n\tdb: Kysely<Database>,\n\tolderThan: string,\n): Promise<ApiResult<{ deleted: number }>> {\n\ttry {\n\t\tconst repo = new RedirectRepository(db);\n\t\tconst deleted = await repo.prune404s(olderThan);\n\t\treturn { success: true, data: { deleted } };\n\t} catch {\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\terror: { code: \"NOT_FOUND_PRUNE_ERROR\", message: \"Failed to prune 404 log\" },\n\t\t};\n\t}\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAoCA,SAAS,gBAAgB,OAAkD;CAC1E,MAAM,SAAoC,EAAE;AAC5C,MAAK,MAAM,QAAQ,MAClB,KAAI,KAAK,WAAW,KAAK,UACxB,QAAO,KAAK;EACX,IAAI,KAAK;EACT,UAAU,eAAe,KAAK,OAAO;EACrC,aAAa,KAAK;EAClB,CAAC;AAGJ,QAAO;;;AAIR,MAAM,gBAAgB;;AAGtB,MAAM,WAAW;;AAGjB,MAAM,WAAW;;;;;;AAOjB,SAAS,qBAAqB,eAA+B;CAE5D,IAAI,SAAS,cAAc,QAAQ,UAAU,cAAc;AAC3D,UAAS,YAAY;AACrB,UAAS,OAAO,QAAQ,UAAU,cAAc;AAGhD,QADc,OAAO,MAAM,IAAI,CAAC,OAAO,QAAQ,CAClC,MAAM,EAAE,CAAC,KAAK,IAAI;;;;;;;;AAShC,SAAS,wBAAwB,UAAkB,eAA0C;CAC5F,MAAM,WAAW,SAAS,KAAK,SAAS;AACxC,UAAS,YAAY;AAErB,KAAI,UAAU;EAEb,MAAM,aAAa,SAAS,QAAQ,OAAO;EAC3C,MAAM,SAAS,SAAS,MAAM,GAAG,WAAW;EAE5C,MAAM,OAAO;GACZ,SAAS,QAAQ,UAAU,cAAc,CAAC,QAAQ,UAAU,cAAc;GAC1E,SACE,QAAQ,UAAU,GAAG,cAAc,GAAG,gBAAgB,CACtD,QAAQ,UAAU,cAAc;GAClC,SACE,QAAQ,UAAU,GAAG,cAAc,GAAG,cAAc,GAAG,gBAAgB,CACvE,QAAQ,UAAU,cAAc;GAClC;AAGD,MAAI,eACH;QAAK,MAAM,QAAQ,cAClB,KAAI,KAAK,WAAW,KAAK,aAAa,KAAK,WAAW,UAAU;IAC/D,MAAM,SAAS,qBAAqB,KAAK,OAAO;AAChD,QAAI,OACH,MAAK,KAAK,GAAG,SAAS,SAAS;;;AAMnC,SAAO;;AAGR,QAAO,CAAC,SAAS,QAAQ,UAAU,cAAc,CAAC;;;;;;;AAQnD,SAAS,YACR,MACA,OACA,UACA,OAC6C;CAE7C,MAAM,QAAQ,MAAM,IAAI,KAAK;AAC7B,KAAI,MAAO,QAAO;AAElB,KAAI,CAAC,KAAK,SAAS,IAAI,CAEtB,MAAK,MAAM,MAAM,UAAU;EAC1B,MAAM,SAAS,aAAa,GAAG,UAAU,KAAK;AAC9C,MAAI,OAEH,QAAO;GAAE,aADQ,uBAAuB,GAAG,aAAa,OAAO;GAC/B,IAAI,GAAG;GAAI;;MAGvC;EAEN,MAAM,kBAAkB,wBAAwB,MAAM,MAAM;AAC5D,OAAK,MAAM,MAAM,SAChB,MAAK,MAAM,OAAO,iBAAiB;GAClC,MAAM,SAAS,aAAa,GAAG,UAAU,IAAI;AAC7C,OAAI,OAEH,QAAO;IAAE,aADQ,uBAAuB,GAAG,aAAa,OAAO;IAC/B,IAAI,GAAG;IAAI;;;AAM/C,QAAO;;;;;;;;AASR,SAAS,WAAW,OAAyE;CAC5F,MAAM,wBAAQ,IAAI,KAAkD;AACpE,MAAK,MAAM,QAAQ,MAClB,KAAI,KAAK,QACR,OAAM,IAAI,KAAK,QAAQ;EAAE,aAAa,KAAK;EAAa,IAAI,KAAK;EAAI,CAAC;AAGxE,QAAO;;;;;;;;AASR,SAAgB,YAAY,OAAiC;CAC5D,MAAM,QAAQ,WAAW,MAAM;CAC/B,MAAM,WAAW,gBAAgB,MAAM;CACvC,MAAM,0BAAU,IAAI,KAAa;CACjC,MAAM,kCAAkB,IAAI,KAAa;AAEzC,MAAK,MAAM,CAAC,gBAAgB,OAAO;AAClC,MAAI,QAAQ,IAAI,YAAY,CAAE;EAE9B,MAAM,OAAiB,EAAE;EACzB,MAAM,0BAAU,IAAI,KAAa;EACjC,MAAM,UAAoB,EAAE;EAC5B,IAAI,UAA8B;AAElC,SAAO,SAAS;AACf,OAAI,QAAQ,IAAI,QAAQ,EAAE;IAEzB,MAAM,YAAY,KAAK,QAAQ,QAAQ;AACvC,SAAK,MAAM,MAAM,QAAQ,MAAM,UAAU,CAAE,iBAAgB,IAAI,GAAG;AAClE;;AAGD,OAAI,QAAQ,IAAI,QAAQ,CACvB;GAGD,MAAM,OAAO,YAAY,SAAS,OAAO,UAAU,MAAM;AACzD,OAAI,CAAC,KAAM;AAEX,QAAK,KAAK,QAAQ;AAClB,WAAQ,IAAI,QAAQ;AACpB,WAAQ,KAAK,KAAK,GAAG;AACrB,aAAU,KAAK;;AAGhB,OAAK,MAAM,QAAQ,KAAM,SAAQ,IAAI,KAAK;;AAG3C,QAAO,CAAC,GAAG,gBAAgB;;;;;;AAO5B,SAAS,qBACR,cACA,UACgB;AAChB,MAAK,MAAM,MAAM,SAChB,KAAI,aAAa,GAAG,UAAU,aAAa,KAAK,KAC/C,QAAO,GAAG,SAAS;AAGrB,QAAO;;;;;;;;;;AAWR,SAAgB,gBACf,QACA,aACA,eACA,WACkB;CAClB,MAAM,WAAW,YAAY,cAAc,QAAQ,MAAM,EAAE,OAAO,UAAU,GAAG;CAC/E,MAAM,QAAQ,WAAW,SAAS;CAClC,MAAM,WAAW,gBAAgB,SAAS;CAK1C,MAAM,iBADkB,OAAO,SAAS,IAAI,GACH,eAAe,OAAO,GAAG;CAKlE,IAAI;AACJ,KAAI,YAAY,SAAS,IAAI,EAAE;EAC9B,MAAM,OAAO,wBAAwB,aAAa,SAAS;EAE3D,MAAM,WAAW,eAAe,YAAY;AAC5C,OAAK,MAAM,CAAC,QAAQ,MACnB,KAAI,CAAC,IAAI,SAAS,IAAI,IAAI,aAAa,UAAU,IAAI,KAAK,KACzD,MAAK,KAAK,IAAI;AAKhB,OAAK,KAAK,YAAY;AACtB,mBAAiB;OAEjB,kBAAiB,CAAC,YAAY;AAG/B,MAAK,MAAM,SAAS,gBAAgB;EACnC,MAAM,OAAO,CAAC,QAAQ,YAAY;EAClC,IAAI,UAAU;EACd,MAAM,OAAO,IAAI,IAAY;GAAC;GAAQ;GAAa;GAAM,CAAC;AAI1D,SAAO,MAAM;GACZ,MAAM,OAAO,YAAY,SAAS,OAAO,UAAU,SAAS;AAC5D,OAAI,CAAC,KAAM;AAOX,OAHC,KAAK,IAAI,KAAK,YAAY,IACzB,mBAAmB,QAAQ,aAAa,gBAAgB,KAAK,YAAY,KAAK,MAEjE;IAEd,MAAM,cACL,CAAC,KAAK,IAAI,KAAK,YAAY,IAAI,mBAAmB,OAAO,SAAS,KAAK;AACxE,SAAK,KAAK,YAAY;AACtB,WAAO;;GAKR,MAAM,YAAY,KAAK,YAAY,SAAS,cAAc,GACtD,qBAAqB,KAAK,aAAa,SAAS,IAAI,KAAK,cAC1D,KAAK;AACR,QAAK,KAAK,UAAU;AACpB,QAAK,IAAI,KAAK,YAAY;AAC1B,aAAU,KAAK;;;AAIjB,QAAO;;;;;;;;AChSR,eAAsB,mBACrB,IACA,QAQgF;AAChF,KAAI;EAEH,MAAM,SAAS,MADF,IAAI,mBAAmB,GAAG,CACb,SAAS,OAAO;EAE1C,MAAM,kBAAkB,MAAM,mBAAmB,GAAG;AAEpD,SAAO;GACN,SAAS;GACT,MAAM;IACL,GAAG;IACH,GAAI,gBAAgB,SAAS,IAAI,EAAE,iBAAiB,GAAG,EAAE;IACzD;GACD;UACO,OAAO;AACf,MAAI,iBAAiB,mBACpB,QAAO;GACN,SAAS;GACT,OAAO;IAAE,MAAM;IAAkB,SAAS,MAAM;IAAS;GACzD;AAEF,SAAO;GACN,SAAS;GACT,OAAO;IAAE,MAAM;IAAuB,SAAS;IAA6B;GAC5E;;;;;;AAOH,eAAsB,qBACrB,IACA,OAO+B;AAC/B,KAAI;EACH,MAAM,OAAO,IAAI,mBAAmB,GAAG;EAEvC,MAAM,OAAO,MAAM,QAAQ;EAG3B,MAAM,WAAW,iBAAiB,KAAK;EACvC,MAAM,cAAc,WAAW,KAAM,MAAM,eAAe;AAG1D,MAAI,CAAC,YAAY,MAAM,WAAW,YACjC,QAAO;GACN,SAAS;GACT,OAAO;IACN,MAAM;IACN,SAAS;IACT;GACD;EAIF,MAAM,kBAAkB,UAAU,MAAM,OAAO;AAC/C,MAAI,iBAAiB;GACpB,MAAM,eAAe,gBAAgB,MAAM,OAAO;AAClD,OAAI,aACH,QAAO;IACN,SAAS;IACT,OAAO;KAAE,MAAM;KAAoB,SAAS,2BAA2B;KAAgB;IACvF;AAKF,OAAI,CAAC,UAAU;IACd,MAAM,YAAY,0BAA0B,MAAM,QAAQ,YAAY;AACtE,QAAI,UACH,QAAO;KACN,SAAS;KACT,OAAO;MAAE,MAAM;MAAoB,SAAS;MAAW;KACvD;;;AAOJ,MADiB,MAAM,KAAK,aAAa,MAAM,OAAO,CAErD,QAAO;GACN,SAAS;GACT,OAAO;IACN,MAAM;IACN,SAAS,oBAAoB,MAAM,OAAO;IAC1C;GACD;AAKF,MAAI,CAAC,YAAY,MAAM,YAAY,OAAO;GACzC,MAAM,QAAQ,QAAQ,MAAM,KAAK,gBAAgB,CAAC;GAClD,MAAM,WAAW,gBAAgB,MAAM,QAAQ,aAAa,MAAM;AAClE,OAAI,SAAU,QAAO,UAAU,SAAS;;AAYzC,SAAO;GAAE,SAAS;GAAM,MATP,MAAM,KAAK,OAAO;IAClC,QAAQ,MAAM;IACd;IACA;IACA,WAAW;IACX,SAAS,MAAM,WAAW;IAC1B,WAAW,MAAM,aAAa;IAC9B,CAAC;GAEsC;SACjC;AACP,SAAO;GACN,SAAS;GACT,OAAO;IAAE,MAAM;IAAyB,SAAS;IAA6B;GAC9E;;;;;;AAOH,eAAsB,kBACrB,IACA,IAC+B;AAC/B,KAAI;EAEH,MAAM,WAAW,MADJ,IAAI,mBAAmB,GAAG,CACX,SAAS,GAAG;AAExC,MAAI,CAAC,SACJ,QAAO;GACN,SAAS;GACT,OAAO;IAAE,MAAM;IAAa,SAAS,aAAa,GAAG;IAAc;GACnE;AAGF,SAAO;GAAE,SAAS;GAAM,MAAM;GAAU;SACjC;AACP,SAAO;GACN,SAAS;GACT,OAAO;IAAE,MAAM;IAAsB,SAAS;IAA4B;GAC1E;;;;;;AAOH,eAAsB,qBACrB,IACA,IACA,OAO+B;AAC/B,KAAI;EACH,MAAM,OAAO,IAAI,mBAAmB,GAAG;EAEvC,MAAM,WAAW,MAAM,KAAK,SAAS,GAAG;AACxC,MAAI,CAAC,SACJ,QAAO;GACN,SAAS;GACT,OAAO;IAAE,MAAM;IAAa,SAAS,aAAa,GAAG;IAAc;GACnE;EAGF,MAAM,YAAY,MAAM,UAAU,SAAS;EAC3C,MAAM,UAAU,MAAM,eAAe,SAAS;AAG9C,MAAI,cAAc,QACjB,QAAO;GACN,SAAS;GACT,OAAO;IACN,MAAM;IACN,SAAS;IACT;GACD;AAIF,MAAI,MAAM,WAAW,QAAW;AAE/B,OADwB,UAAU,MAAM,OAAO,EAC1B;IACpB,MAAM,eAAe,gBAAgB,MAAM,OAAO;AAClD,QAAI,aACH,QAAO;KACN,SAAS;KACT,OAAO;MACN,MAAM;MACN,SAAS,2BAA2B;MACpC;KACD;;GAKH,MAAM,MAAM,MAAM,KAAK,aAAa,MAAM,OAAO;AACjD,OAAI,OAAO,IAAI,OAAO,GACrB,QAAO;IACN,SAAS;IACT,OAAO;KACN,MAAM;KACN,SAAS,oBAAoB,MAAM,OAAO;KAC1C;IACD;;AAMH,MAD2B,UAAU,UAAU,EACvB;GACvB,MAAM,YAAY,0BAA0B,WAAW,QAAQ;AAC/D,OAAI,UACH,QAAO;IACN,SAAS;IACT,OAAO;KAAE,MAAM;KAAoB,SAAS;KAAW;IACvD;;AAKH,MAAI,MAAM,WAAW,UAAa,MAAM,gBAAgB,QAAW;GAElE,MAAM,WAAW,gBAAgB,WAAW,SAD9B,QAAQ,MAAM,KAAK,gBAAgB,CAAC,EACU,GAAG;AAC/D,OAAI,SAAU,QAAO,UAAU,SAAS;;EAGzC,MAAM,UAAU,MAAM,KAAK,OAAO,IAAI;GACrC,QAAQ,MAAM;GACd,aAAa,MAAM;GACnB,MAAM,MAAM;GACZ,SAAS,MAAM;GACf,WAAW,MAAM;GACjB,CAAC;AAEF,MAAI,CAAC,QACJ,QAAO;GACN,SAAS;GACT,OAAO;IAAE,MAAM;IAAyB,SAAS;IAA6B;GAC9E;AAIF,QAAM,gBAAgB,GAAG;AAEzB,SAAO;GAAE,SAAS;GAAM,MAAM;GAAS;SAChC;AACP,SAAO;GACN,SAAS;GACT,OAAO;IAAE,MAAM;IAAyB,SAAS;IAA6B;GAC9E;;;;;;AAOH,eAAsB,qBACrB,IACA,IACwC;AACxC,KAAI;AAIH,MAAI,CAFY,MADH,IAAI,mBAAmB,GAAG,CACZ,OAAO,GAAG,CAGpC,QAAO;GACN,SAAS;GACT,OAAO;IAAE,MAAM;IAAa,SAAS,aAAa,GAAG;IAAc;GACnE;AAGF,QAAM,gBAAgB,GAAG;AAEzB,SAAO;GAAE,SAAS;GAAM,MAAM,EAAE,SAAS,MAAM;GAAE;SAC1C;AACP,SAAO;GACN,SAAS;GACT,OAAO;IAAE,MAAM;IAAyB,SAAS;IAA6B;GAC9E;;;AAQH,SAAS,UAAU,UAAsC;AAKxD,QAAO;EACN,SAAS;EACT,OAAO;GACN,MAAM;GACN,SAAS,uCARE,SACX,MAAM,GAAG,GAAG,CACZ,KAAK,GAAG,MAAM,GAAG,EAAE,UAAU,SAAS,IAAI,KAAK,CAC/C,KAAK,KAAK;GAMV;EACD;;AAGF,SAAS,QAAQ,WAAuC;AACvD,QAAO,UAAU,KAAK,OAAO;EAC5B,IAAI,EAAE;EACN,QAAQ,EAAE;EACV,aAAa,EAAE;EACf,SAAS,EAAE;EACX,WAAW,EAAE;EACb,EAAE;;AAGJ,MAAM,iBAAiB;;;;AAKvB,eAAe,gBAAgB,IAAqC;AACnE,KAAI;EACH,MAAM,UAAU,IAAI,kBAAkB,GAAG;EAEzC,MAAM,kBAAkB,YADV,QAAQ,MAAM,IAAI,mBAAmB,GAAG,CAAC,gBAAgB,CAAC,CAC9B;AAC1C,QAAM,QAAQ,IAAI,gBAAgB,gBAAgB;UAC1C,OAAO;AACf,UAAQ,MAAM,yCAAyC,MAAM;;;;;;AAO/D,eAAe,mBAAmB,IAAyC;AAC1E,KAAI;EACH,MAAM,UAAU,IAAI,kBAAkB,GAAG;EACzC,MAAM,SAAS,MAAM,QAAQ,IAAc,eAAe;AAC1D,MAAI,WAAW,KAAM,QAAO;AAG5B,QAAM,gBAAgB,GAAG;AACzB,SAAQ,MAAM,QAAQ,IAAc,eAAe,IAAK,EAAE;SACnD;AACP,SAAO,EAAE;;;;;;AAWX,eAAsB,mBACrB,IACA,QACoD;AACpD,KAAI;AAGH,SAAO;GAAE,SAAS;GAAM,MADT,MADF,IAAI,mBAAmB,GAAG,CACb,SAAS,OAAO;GACJ;UAC9B,OAAO;AACf,MAAI,iBAAiB,mBACpB,QAAO;GACN,SAAS;GACT,OAAO;IAAE,MAAM;IAAkB,SAAS,MAAM;IAAS;GACzD;AAEF,SAAO;GACN,SAAS;GACT,OAAO;IAAE,MAAM;IAAwB,SAAS;IAA2B;GAC3E;;;;;;AAOH,eAAsB,sBACrB,IACA,OACmD;AACnD,KAAI;AAGH,SAAO;GAAE,SAAS;GAAM,MAAM,EAAE,OADlB,MADD,IAAI,mBAAmB,GAAG,CACd,cAAc,MAAM,EACN;GAAE;SAClC;AACP,SAAO;GACN,SAAS;GACT,OAAO;IAAE,MAAM;IAA2B,SAAS;IAA+B;GAClF;;;;;;AAOH,eAAsB,oBACrB,IAC0C;AAC1C,KAAI;AAGH,SAAO;GAAE,SAAS;GAAM,MAAM,EAAE,SADhB,MADH,IAAI,mBAAmB,GAAG,CACZ,WAAW,EACG;GAAE;SACpC;AACP,SAAO;GACN,SAAS;GACT,OAAO;IAAE,MAAM;IAAyB,SAAS;IAA2B;GAC5E;;;;;;AAOH,eAAsB,oBACrB,IACA,WAC0C;AAC1C,KAAI;AAGH,SAAO;GAAE,SAAS;GAAM,MAAM,EAAE,SADhB,MADH,IAAI,mBAAmB,GAAG,CACZ,UAAU,UAAU,EACN;GAAE;SACpC;AACP,SAAO;GACN,SAAS;GACT,OAAO;IAAE,MAAM;IAAyB,SAAS;IAA2B;GAC5E"}
1
+ {"version":3,"file":"redirects-CufRQt0Q.mjs","names":[],"sources":["../src/redirects/loops.ts","../src/api/handlers/redirects.ts"],"sourcesContent":["/**\n * Redirect loop and chain detection utilities.\n *\n * Builds a directed graph from redirect rules and detects:\n * - Cycles (loops): /a → /b → /c → /a\n * - Long chains: /a → /b → /c → /d → /e (exceeding a warning threshold)\n *\n * Handles both exact and pattern redirects. When the walker encounters\n * a path with no exact source match, it tests against compiled pattern\n * sources and resolves the destination using captured parameters.\n */\n\nimport {\n\tcompilePattern,\n\tmatchPattern,\n\tinterpolateDestination,\n\ttype CompiledPattern,\n} from \"./patterns.js\";\n\nexport interface RedirectEdge {\n\tid: string;\n\tsource: string;\n\tdestination: string;\n\tenabled: boolean;\n\tisPattern: boolean;\n}\n\ninterface CompiledPatternRedirect {\n\tid: string;\n\tcompiled: CompiledPattern;\n\tdestination: string;\n}\n\n/**\n * Compile all enabled pattern redirects for matching during graph walks.\n */\nfunction compilePatterns(edges: RedirectEdge[]): CompiledPatternRedirect[] {\n\tconst result: CompiledPatternRedirect[] = [];\n\tfor (const edge of edges) {\n\t\tif (edge.enabled && edge.isPattern) {\n\t\t\tresult.push({\n\t\t\t\tid: edge.id,\n\t\t\t\tcompiled: compilePattern(edge.source),\n\t\t\t\tdestination: edge.destination,\n\t\t\t});\n\t\t}\n\t}\n\treturn result;\n}\n\n/** Single-segment dummy value for representative path generation */\nconst DUMMY_SEGMENT = \"__p__\";\n\n/** Splat pattern: [...paramName] */\nconst SPLAT_RE = /\\[\\.\\.\\.(\\w+)\\]/g;\n\n/** Param pattern: [paramName] */\nconst PARAM_RE = /\\[(\\w+)\\]/g;\n\n/**\n * Extract the literal prefix from a pattern source (everything before the\n * first placeholder), stripped of leading segments shared with a base path.\n * e.g., \"/new/docs/[slug]\" → \"docs/__p__\" (the part after \"/new/\")\n */\nfunction extractPatternSuffix(patternSource: string): string {\n\t// Replace placeholders with dummy values\n\tlet result = patternSource.replace(SPLAT_RE, DUMMY_SEGMENT);\n\tSPLAT_RE.lastIndex = 0;\n\tresult = result.replace(PARAM_RE, DUMMY_SEGMENT);\n\t// Strip leading slash and first segment (e.g., \"/new/docs/__p__\" → \"docs/__p__\")\n\tconst parts = result.split(\"/\").filter(Boolean);\n\treturn parts.slice(1).join(\"/\");\n}\n\n/**\n * Generate representative concrete paths from a template string.\n * Replaces [param] with a dummy segment and [...rest] with multiple\n * depth variants. For catch-alls, also generates representatives using\n * literal prefixes from existing pattern sources to catch cross-pattern loops.\n */\nfunction generateRepresentatives(template: string, existingEdges?: RedirectEdge[]): string[] {\n\tconst hasSplat = SPLAT_RE.test(template);\n\tSPLAT_RE.lastIndex = 0;\n\n\tif (hasSplat) {\n\t\t// Extract the static prefix before the catch-all (e.g., \"/old/\" from \"/old/[...path]\")\n\t\tconst splatIndex = template.indexOf(\"[...\");\n\t\tconst prefix = template.slice(0, splatIndex);\n\n\t\tconst reps = [\n\t\t\ttemplate.replace(SPLAT_RE, DUMMY_SEGMENT).replace(PARAM_RE, DUMMY_SEGMENT),\n\t\t\ttemplate\n\t\t\t\t.replace(SPLAT_RE, `${DUMMY_SEGMENT}/${DUMMY_SEGMENT}`)\n\t\t\t\t.replace(PARAM_RE, DUMMY_SEGMENT),\n\t\t\ttemplate\n\t\t\t\t.replace(SPLAT_RE, `${DUMMY_SEGMENT}/${DUMMY_SEGMENT}/${DUMMY_SEGMENT}`)\n\t\t\t\t.replace(PARAM_RE, DUMMY_SEGMENT),\n\t\t];\n\n\t\t// Add representatives derived from existing pattern sources' literal prefixes\n\t\tif (existingEdges) {\n\t\t\tfor (const edge of existingEdges) {\n\t\t\t\tif (edge.enabled && edge.isPattern && edge.source !== template) {\n\t\t\t\t\tconst suffix = extractPatternSuffix(edge.source);\n\t\t\t\t\tif (suffix) {\n\t\t\t\t\t\treps.push(`${prefix}${suffix}`);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn reps;\n\t}\n\n\treturn [template.replace(PARAM_RE, DUMMY_SEGMENT)];\n}\n\n/**\n * Resolve the next hop for a given path. Tries exact match first,\n * then pattern matching with parameter interpolation for concrete paths,\n * then representative-based matching for template strings.\n */\nfunction resolveNext(\n\tpath: string,\n\tgraph: Map<string, { destination: string; id: string }>,\n\tpatterns: CompiledPatternRedirect[],\n\tedges?: RedirectEdge[],\n): { destination: string; id: string } | null {\n\t// Exact match (fast) — works for both real paths and template strings\n\tconst exact = graph.get(path);\n\tif (exact) return exact;\n\n\tif (!path.includes(\"[\")) {\n\t\t// Concrete path — try pattern matching directly\n\t\tfor (const pr of patterns) {\n\t\t\tconst params = matchPattern(pr.compiled, path);\n\t\t\tif (params) {\n\t\t\t\tconst resolved = interpolateDestination(pr.destination, params);\n\t\t\t\treturn { destination: resolved, id: pr.id };\n\t\t\t}\n\t\t}\n\t} else {\n\t\t// Template string — generate representative paths and test against patterns\n\t\tconst representatives = generateRepresentatives(path, edges);\n\t\tfor (const pr of patterns) {\n\t\t\tfor (const rep of representatives) {\n\t\t\t\tconst params = matchPattern(pr.compiled, rep);\n\t\t\t\tif (params) {\n\t\t\t\t\tconst resolved = interpolateDestination(pr.destination, params);\n\t\t\t\t\treturn { destination: resolved, id: pr.id };\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn null;\n}\n\n/**\n * Build an adjacency map from redirect edges.\n * Includes both exact and pattern redirects — pattern redirects use their\n * template strings as literal graph edges, which works because EmDash\n * patterns pass parameters through without transformation.\n */\nfunction buildGraph(edges: RedirectEdge[]): Map<string, { destination: string; id: string }> {\n\tconst graph = new Map<string, { destination: string; id: string }>();\n\tfor (const edge of edges) {\n\t\tif (edge.enabled) {\n\t\t\tgraph.set(edge.source, { destination: edge.destination, id: edge.id });\n\t\t}\n\t}\n\treturn graph;\n}\n\n/**\n * Detect all redirect IDs that participate in cycles.\n * Walks every node in the graph once, collecting IDs from any cycles found.\n *\n * @returns Array of redirect IDs that are part of a loop\n */\nexport function detectLoops(edges: RedirectEdge[]): string[] {\n\tconst graph = buildGraph(edges);\n\tconst patterns = compilePatterns(edges);\n\tconst visited = new Set<string>();\n\tconst loopRedirectIds = new Set<string>();\n\n\tfor (const [startSource] of graph) {\n\t\tif (visited.has(startSource)) continue;\n\n\t\tconst path: string[] = [];\n\t\tconst pathSet = new Set<string>();\n\t\tconst pathIds: string[] = [];\n\t\tlet current: string | undefined = startSource;\n\n\t\twhile (current) {\n\t\t\tif (pathSet.has(current)) {\n\t\t\t\t// Found a cycle — collect IDs of redirects in the loop\n\t\t\t\tconst loopStart = path.indexOf(current);\n\t\t\t\tfor (const id of pathIds.slice(loopStart)) loopRedirectIds.add(id);\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tif (visited.has(current)) {\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tconst next = resolveNext(current, graph, patterns, edges);\n\t\t\tif (!next) break;\n\n\t\t\tpath.push(current);\n\t\t\tpathSet.add(current);\n\t\t\tpathIds.push(next.id);\n\t\t\tcurrent = next.destination;\n\t\t}\n\n\t\tfor (const node of path) visited.add(node);\n\t}\n\n\treturn [...loopRedirectIds];\n}\n\n/**\n * Find a compiled pattern redirect whose source matches the given resolved path,\n * returning the source template string for display purposes.\n */\nfunction findMatchingTemplate(\n\tresolvedPath: string,\n\tpatterns: CompiledPatternRedirect[],\n): string | null {\n\tfor (const pr of patterns) {\n\t\tif (matchPattern(pr.compiled, resolvedPath) !== null) {\n\t\t\treturn pr.compiled.source;\n\t\t}\n\t}\n\treturn null;\n}\n\n/**\n * Check if adding or updating a redirect would create a loop.\n *\n * Walks the chain from `destination` through existing redirects.\n * If it reaches `source`, a cycle would form.\n *\n * @returns The loop path if a cycle would be created, or null if safe\n */\nexport function wouldCreateLoop(\n\tsource: string,\n\tdestination: string,\n\texistingEdges: RedirectEdge[],\n\texcludeId?: string,\n): string[] | null {\n\tconst filtered = excludeId ? existingEdges.filter((e) => e.id !== excludeId) : existingEdges;\n\tconst graph = buildGraph(filtered);\n\tconst patterns = compilePatterns(filtered);\n\n\t// If the proposed source is a pattern, compile it so we can check\n\t// whether resolved paths would match it (not just string equality)\n\tconst sourceIsPattern = source.includes(\"[\");\n\tconst compiledSource = sourceIsPattern ? compilePattern(source) : null;\n\n\t// Determine starting points for the walk. If the destination is a\n\t// template, generate representative concrete paths AND find existing\n\t// exact sources in the graph that match the template.\n\tlet startingPoints: string[];\n\tif (destination.includes(\"[\")) {\n\t\tconst reps = generateRepresentatives(destination, filtered);\n\t\t// Also find existing exact graph keys that match this template\n\t\tconst compiled = compilePattern(destination);\n\t\tfor (const [key] of graph) {\n\t\t\tif (!key.includes(\"[\") && matchPattern(compiled, key) !== null) {\n\t\t\t\treps.push(key);\n\t\t\t}\n\t\t}\n\t\t// Always include the destination itself — it may be an exact graph key\n\t\t// (e.g., /a/sub/[...path] exists as a literal source in the graph)\n\t\treps.push(destination);\n\t\tstartingPoints = reps;\n\t} else {\n\t\tstartingPoints = [destination];\n\t}\n\n\tfor (const start of startingPoints) {\n\t\tconst path = [source, destination];\n\t\tlet current = start;\n\t\tconst seen = new Set<string>([source, destination, start]);\n\n\t\t// Walk the chain until it ends or we revisit a node\n\t\t// eslint-disable-next-line no-constant-condition -- terminates via return/break when chain ends or cycle found\n\t\twhile (true) {\n\t\t\tconst next = resolveNext(current, graph, patterns, filtered);\n\t\t\tif (!next) break; // chain ends, try next starting point\n\n\t\t\t// Check if we've looped back — either exact match or pattern match\n\t\t\tconst loopsBack =\n\t\t\t\tseen.has(next.destination) ||\n\t\t\t\t(compiledSource !== null && matchPattern(compiledSource, next.destination) !== null);\n\n\t\t\tif (loopsBack) {\n\t\t\t\t// Show the source template instead of dummy resolved path\n\t\t\t\tconst displayPath =\n\t\t\t\t\t!seen.has(next.destination) && compiledSource !== null ? source : next.destination;\n\t\t\t\tpath.push(displayPath);\n\t\t\t\treturn path; // cycle found\n\t\t\t}\n\n\t\t\t// If the resolved path contains dummy segments, try to find the\n\t\t\t// original pattern template that produced it for cleaner display\n\t\t\tconst cleanDest = next.destination.includes(DUMMY_SEGMENT)\n\t\t\t\t? (findMatchingTemplate(next.destination, patterns) ?? next.destination)\n\t\t\t\t: next.destination;\n\t\t\tpath.push(cleanDest);\n\t\t\tseen.add(next.destination);\n\t\t\tcurrent = next.destination;\n\t\t}\n\t}\n\n\treturn null;\n}\n","/**\n * Redirect CRUD and 404 log handlers\n */\n\nimport type { Kysely } from \"kysely\";\n\nimport { OptionsRepository } from \"../../database/repositories/options.js\";\nimport {\n\tRedirectRepository,\n\ttype Redirect,\n\ttype NotFoundEntry,\n\ttype NotFoundSummary,\n} from \"../../database/repositories/redirect.js\";\nimport { InvalidCursorError } from \"../../database/repositories/types.js\";\nimport type { FindManyResult } from \"../../database/repositories/types.js\";\nimport type { Database } from \"../../database/types.js\";\nimport { wouldCreateLoop, detectLoops, type RedirectEdge } from \"../../redirects/loops.js\";\nimport { validatePattern, validateDestinationParams, isPattern } from \"../../redirects/patterns.js\";\nimport { isTerminalStatus } from \"../../redirects/status.js\";\nimport type { ApiResult } from \"../types.js\";\n\n// ---------------------------------------------------------------------------\n// Redirects\n// ---------------------------------------------------------------------------\n\n/**\n * List redirects with cursor pagination and optional filters\n */\nexport async function handleRedirectList(\n\tdb: Kysely<Database>,\n\tparams: {\n\t\tcursor?: string;\n\t\tlimit?: number;\n\t\tsearch?: string;\n\t\tgroup?: string;\n\t\tenabled?: boolean;\n\t\tauto?: boolean;\n\t},\n): Promise<ApiResult<FindManyResult<Redirect> & { loopRedirectIds?: string[] }>> {\n\ttry {\n\t\tconst repo = new RedirectRepository(db);\n\t\tconst result = await repo.findMany(params);\n\n\t\tconst loopRedirectIds = await getLoopRedirectIds(db);\n\n\t\treturn {\n\t\t\tsuccess: true,\n\t\t\tdata: {\n\t\t\t\t...result,\n\t\t\t\t...(loopRedirectIds.length > 0 ? { loopRedirectIds } : {}),\n\t\t\t},\n\t\t};\n\t} catch (error) {\n\t\tif (error instanceof InvalidCursorError) {\n\t\t\treturn {\n\t\t\t\tsuccess: false,\n\t\t\t\terror: { code: \"INVALID_CURSOR\", message: error.message },\n\t\t\t};\n\t\t}\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\terror: { code: \"REDIRECT_LIST_ERROR\", message: \"Failed to fetch redirects\" },\n\t\t};\n\t}\n}\n\n/**\n * Create a redirect rule\n */\nexport async function handleRedirectCreate(\n\tdb: Kysely<Database>,\n\tinput: {\n\t\tsource: string;\n\t\tdestination?: string;\n\t\ttype?: number;\n\t\tenabled?: boolean;\n\t\tgroupName?: string | null;\n\t},\n): Promise<ApiResult<Redirect>> {\n\ttry {\n\t\tconst repo = new RedirectRepository(db);\n\n\t\tconst type = input.type ?? 301;\n\t\t// Terminal statuses (410 Gone / 451) are served directly and have no\n\t\t// destination — skip the destination/loop checks for them.\n\t\tconst terminal = isTerminalStatus(type);\n\t\tconst destination = terminal ? \"\" : (input.destination ?? \"\");\n\n\t\t// Source and destination must differ\n\t\tif (!terminal && input.source === destination) {\n\t\t\treturn {\n\t\t\t\tsuccess: false,\n\t\t\t\terror: {\n\t\t\t\t\tcode: \"VALIDATION_ERROR\",\n\t\t\t\t\tmessage: \"Source and destination must be different\",\n\t\t\t\t},\n\t\t\t};\n\t\t}\n\n\t\t// If source looks like a pattern, validate it\n\t\tconst sourceIsPattern = isPattern(input.source);\n\t\tif (sourceIsPattern) {\n\t\t\tconst patternError = validatePattern(input.source);\n\t\t\tif (patternError) {\n\t\t\t\treturn {\n\t\t\t\t\tsuccess: false,\n\t\t\t\t\terror: { code: \"VALIDATION_ERROR\", message: `Invalid source pattern: ${patternError}` },\n\t\t\t\t};\n\t\t\t}\n\n\t\t\t// Validate destination params reference valid source params\n\t\t\t// (terminal rules have no destination to interpolate)\n\t\t\tif (!terminal) {\n\t\t\t\tconst destError = validateDestinationParams(input.source, destination);\n\t\t\t\tif (destError) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tsuccess: false,\n\t\t\t\t\t\terror: { code: \"VALIDATION_ERROR\", message: destError },\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Check for duplicate source (exact match only for non-patterns)\n\t\tconst existing = await repo.findBySource(input.source);\n\t\tif (existing) {\n\t\t\treturn {\n\t\t\t\tsuccess: false,\n\t\t\t\terror: {\n\t\t\t\t\tcode: \"CONFLICT\",\n\t\t\t\t\tmessage: `A redirect from \"${input.source}\" already exists`,\n\t\t\t\t},\n\t\t\t};\n\t\t}\n\n\t\t// Check for redirect loops (skip if creating as disabled, or terminal —\n\t\t// a Gone rule has no destination, so it can't form a loop)\n\t\tif (!terminal && input.enabled !== false) {\n\t\t\tconst edges = toEdges(await repo.findAllEnabled());\n\t\t\tconst loopPath = wouldCreateLoop(input.source, destination, edges);\n\t\t\tif (loopPath) return loopError(loopPath);\n\t\t}\n\n\t\tconst redirect = await repo.create({\n\t\t\tsource: input.source,\n\t\t\tdestination,\n\t\t\ttype,\n\t\t\tisPattern: sourceIsPattern,\n\t\t\tenabled: input.enabled ?? true,\n\t\t\tgroupName: input.groupName ?? null,\n\t\t});\n\n\t\treturn { success: true, data: redirect };\n\t} catch {\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\terror: { code: \"REDIRECT_CREATE_ERROR\", message: \"Failed to create redirect\" },\n\t\t};\n\t}\n}\n\n/**\n * Get a redirect by ID\n */\nexport async function handleRedirectGet(\n\tdb: Kysely<Database>,\n\tid: string,\n): Promise<ApiResult<Redirect>> {\n\ttry {\n\t\tconst repo = new RedirectRepository(db);\n\t\tconst redirect = await repo.findById(id);\n\n\t\tif (!redirect) {\n\t\t\treturn {\n\t\t\t\tsuccess: false,\n\t\t\t\terror: { code: \"NOT_FOUND\", message: `Redirect \"${id}\" not found` },\n\t\t\t};\n\t\t}\n\n\t\treturn { success: true, data: redirect };\n\t} catch {\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\terror: { code: \"REDIRECT_GET_ERROR\", message: \"Failed to fetch redirect\" },\n\t\t};\n\t}\n}\n\n/**\n * Update a redirect by ID\n */\nexport async function handleRedirectUpdate(\n\tdb: Kysely<Database>,\n\tid: string,\n\tinput: {\n\t\tsource?: string;\n\t\tdestination?: string;\n\t\ttype?: number;\n\t\tenabled?: boolean;\n\t\tgroupName?: string | null;\n\t},\n): Promise<ApiResult<Redirect>> {\n\ttry {\n\t\tconst repo = new RedirectRepository(db);\n\n\t\tconst existing = await repo.findById(id);\n\t\tif (!existing) {\n\t\t\treturn {\n\t\t\t\tsuccess: false,\n\t\t\t\terror: { code: \"NOT_FOUND\", message: `Redirect \"${id}\" not found` },\n\t\t\t};\n\t\t}\n\n\t\tconst newSource = input.source ?? existing.source;\n\t\tconst newDest = input.destination ?? existing.destination;\n\n\t\t// Source and destination must differ\n\t\tif (newSource === newDest) {\n\t\t\treturn {\n\t\t\t\tsuccess: false,\n\t\t\t\terror: {\n\t\t\t\t\tcode: \"VALIDATION_ERROR\",\n\t\t\t\t\tmessage: \"Source and destination must be different\",\n\t\t\t\t},\n\t\t\t};\n\t\t}\n\n\t\t// If source is changing, validate patterns\n\t\tif (input.source !== undefined) {\n\t\t\tconst sourceIsPattern = isPattern(input.source);\n\t\t\tif (sourceIsPattern) {\n\t\t\t\tconst patternError = validatePattern(input.source);\n\t\t\t\tif (patternError) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tsuccess: false,\n\t\t\t\t\t\terror: {\n\t\t\t\t\t\t\tcode: \"VALIDATION_ERROR\",\n\t\t\t\t\t\t\tmessage: `Invalid source pattern: ${patternError}`,\n\t\t\t\t\t\t},\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Check for duplicate source (exclude self)\n\t\t\tconst dup = await repo.findBySource(input.source);\n\t\t\tif (dup && dup.id !== id) {\n\t\t\t\treturn {\n\t\t\t\t\tsuccess: false,\n\t\t\t\t\terror: {\n\t\t\t\t\t\tcode: \"CONFLICT\",\n\t\t\t\t\t\tmessage: `A redirect from \"${input.source}\" already exists`,\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\n\t\t// Validate destination params against the (possibly updated) source\n\t\tconst newSourceIsPattern = isPattern(newSource);\n\t\tif (newSourceIsPattern) {\n\t\t\tconst destError = validateDestinationParams(newSource, newDest);\n\t\t\tif (destError) {\n\t\t\t\treturn {\n\t\t\t\t\tsuccess: false,\n\t\t\t\t\terror: { code: \"VALIDATION_ERROR\", message: destError },\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\n\t\t// Check for redirect loops if source or destination changed\n\t\tif (input.source !== undefined || input.destination !== undefined) {\n\t\t\tconst edges = toEdges(await repo.findAllEnabled());\n\t\t\tconst loopPath = wouldCreateLoop(newSource, newDest, edges, id);\n\t\t\tif (loopPath) return loopError(loopPath);\n\t\t}\n\n\t\tconst updated = await repo.update(id, {\n\t\t\tsource: input.source,\n\t\t\tdestination: input.destination,\n\t\t\ttype: input.type,\n\t\t\tenabled: input.enabled,\n\t\t\tgroupName: input.groupName,\n\t\t});\n\n\t\tif (!updated) {\n\t\t\treturn {\n\t\t\t\tsuccess: false,\n\t\t\t\terror: { code: \"REDIRECT_UPDATE_ERROR\", message: \"Failed to update redirect\" },\n\t\t\t};\n\t\t}\n\n\t\t// Recompute cache — redirect was modified, so re-fetch\n\t\tawait updateLoopCache(db);\n\n\t\treturn { success: true, data: updated };\n\t} catch {\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\terror: { code: \"REDIRECT_UPDATE_ERROR\", message: \"Failed to update redirect\" },\n\t\t};\n\t}\n}\n\n/**\n * Delete a redirect by ID\n */\nexport async function handleRedirectDelete(\n\tdb: Kysely<Database>,\n\tid: string,\n): Promise<ApiResult<{ deleted: true }>> {\n\ttry {\n\t\tconst repo = new RedirectRepository(db);\n\t\tconst deleted = await repo.delete(id);\n\n\t\tif (!deleted) {\n\t\t\treturn {\n\t\t\t\tsuccess: false,\n\t\t\t\terror: { code: \"NOT_FOUND\", message: `Redirect \"${id}\" not found` },\n\t\t\t};\n\t\t}\n\n\t\tawait updateLoopCache(db);\n\n\t\treturn { success: true, data: { deleted: true } };\n\t} catch {\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\terror: { code: \"REDIRECT_DELETE_ERROR\", message: \"Failed to delete redirect\" },\n\t\t};\n\t}\n}\n\n// ---------------------------------------------------------------------------\n// Loop analysis cache\n// ---------------------------------------------------------------------------\n\nfunction loopError(loopPath: string[]): ApiResult<never> {\n\tconst hops = loopPath\n\t\t.slice(0, -1)\n\t\t.map((p, i) => `${p} \\u2192 ${loopPath[i + 1]}`)\n\t\t.join(\"\\n\");\n\treturn {\n\t\tsuccess: false,\n\t\terror: {\n\t\t\tcode: \"VALIDATION_ERROR\",\n\t\t\tmessage: `This redirect would create a loop:\\n${hops}`,\n\t\t},\n\t};\n}\n\nfunction toEdges(redirects: Redirect[]): RedirectEdge[] {\n\treturn redirects.map((r) => ({\n\t\tid: r.id,\n\t\tsource: r.source,\n\t\tdestination: r.destination,\n\t\tenabled: r.enabled,\n\t\tisPattern: r.isPattern,\n\t}));\n}\n\nconst LOOP_CACHE_KEY = \"_redirect_loop_ids\";\n\n/**\n * Recompute loop redirect IDs and store in the options table.\n */\nasync function updateLoopCache(db: Kysely<Database>): Promise<void> {\n\ttry {\n\t\tconst options = new OptionsRepository(db);\n\t\tconst edges = toEdges(await new RedirectRepository(db).findAllEnabled());\n\t\tconst loopRedirectIds = detectLoops(edges);\n\t\tawait options.set(LOOP_CACHE_KEY, loopRedirectIds);\n\t} catch (error) {\n\t\tconsole.error(\"Failed to update redirect loop cache:\", error);\n\t}\n}\n\n/**\n * Get loop redirect IDs from cache, computing lazily on first access.\n */\nasync function getLoopRedirectIds(db: Kysely<Database>): Promise<string[]> {\n\ttry {\n\t\tconst options = new OptionsRepository(db);\n\t\tconst cached = await options.get<string[]>(LOOP_CACHE_KEY);\n\t\tif (cached !== null) return cached;\n\n\t\t// First access after upgrade — compute and cache\n\t\tawait updateLoopCache(db);\n\t\treturn (await options.get<string[]>(LOOP_CACHE_KEY)) ?? [];\n\t} catch {\n\t\treturn [];\n\t}\n}\n\n// ---------------------------------------------------------------------------\n// 404 Log\n// ---------------------------------------------------------------------------\n\n/**\n * List 404 log entries with cursor pagination\n */\nexport async function handleNotFoundList(\n\tdb: Kysely<Database>,\n\tparams: { cursor?: string; limit?: number; search?: string },\n): Promise<ApiResult<FindManyResult<NotFoundEntry>>> {\n\ttry {\n\t\tconst repo = new RedirectRepository(db);\n\t\tconst result = await repo.find404s(params);\n\t\treturn { success: true, data: result };\n\t} catch (error) {\n\t\tif (error instanceof InvalidCursorError) {\n\t\t\treturn {\n\t\t\t\tsuccess: false,\n\t\t\t\terror: { code: \"INVALID_CURSOR\", message: error.message },\n\t\t\t};\n\t\t}\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\terror: { code: \"NOT_FOUND_LIST_ERROR\", message: \"Failed to fetch 404 log\" },\n\t\t};\n\t}\n}\n\n/**\n * Get 404 summary (grouped by path, sorted by count)\n */\nexport async function handleNotFoundSummary(\n\tdb: Kysely<Database>,\n\tlimit?: number,\n): Promise<ApiResult<{ items: NotFoundSummary[] }>> {\n\ttry {\n\t\tconst repo = new RedirectRepository(db);\n\t\tconst items = await repo.get404Summary(limit);\n\t\treturn { success: true, data: { items } };\n\t} catch {\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\terror: { code: \"NOT_FOUND_SUMMARY_ERROR\", message: \"Failed to fetch 404 summary\" },\n\t\t};\n\t}\n}\n\n/**\n * Clear all 404 log entries\n */\nexport async function handleNotFoundClear(\n\tdb: Kysely<Database>,\n): Promise<ApiResult<{ deleted: number }>> {\n\ttry {\n\t\tconst repo = new RedirectRepository(db);\n\t\tconst deleted = await repo.clear404s();\n\t\treturn { success: true, data: { deleted } };\n\t} catch {\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\terror: { code: \"NOT_FOUND_CLEAR_ERROR\", message: \"Failed to clear 404 log\" },\n\t\t};\n\t}\n}\n\n/**\n * Prune 404 log entries older than a given date\n */\nexport async function handleNotFoundPrune(\n\tdb: Kysely<Database>,\n\tolderThan: string,\n): Promise<ApiResult<{ deleted: number }>> {\n\ttry {\n\t\tconst repo = new RedirectRepository(db);\n\t\tconst deleted = await repo.prune404s(olderThan);\n\t\treturn { success: true, data: { deleted } };\n\t} catch {\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\terror: { code: \"NOT_FOUND_PRUNE_ERROR\", message: \"Failed to prune 404 log\" },\n\t\t};\n\t}\n}\n"],"mappings":"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"}
@@ -1,5 +1,9 @@
1
- import { H as roleLevel, I as cursorPaginationQuery, R as httpUrl, U as slugPattern, z as localeCode } from "./media-DWIzoVFL.mjs";
2
- import { n as isTerminalStatus, t as REDIRECT_RULE_STATUSES } from "./status-COfycGIU.mjs";
1
+ import { i as MAX_COLLECTION_LIST_COLUMNS } from "./types-75KIqzL9.mjs";
2
+ import { t as SQL_BATCH_SIZE } from "./chunks-DfPax1I0.mjs";
3
+ import { t as SEARCH_TOKENIZERS } from "./types-CtzytVXn.mjs";
4
+ import { $ as localeCode, Q as httpUrl, X as cursorPaginationQuery, nt as roleLevel, rt as slugPattern } from "./media-BWWWb8kg.mjs";
5
+ import { t as compileUrlPattern } from "./url-pattern-BHS0V5Ng.mjs";
6
+ import { n as isTerminalStatus, t as REDIRECT_RULE_STATUSES } from "./status-CWVYpbD8.mjs";
3
7
  import { z } from "zod";
4
8
 
5
9
  //#region src/api/schemas/bylines.ts
@@ -95,6 +99,57 @@ const contentDateBound = z.union([z.iso.datetime({
95
99
  offset: true,
96
100
  message: "must be an ISO 8601 datetime"
97
101
  }), z.iso.date({ message: "must be an ISO 8601 date" })]).optional();
102
+ /**
103
+ * Byline ids for the content-list filter: either the literal `none` or a
104
+ * comma-separated list, parsed into an array.
105
+ *
106
+ * The 25-id cap keeps the `IN (...)` clause clear of D1's bound-parameter
107
+ * ceiling once the rest of the list query's placeholders are counted
108
+ * (`SQL_BATCH_SIZE` is 50 for a query binding nothing else).
109
+ */
110
+ const bylineFilterParam = z.string().trim().min(1).max(2e3).optional().transform((value) => value === void 0 ? void 0 : value === "none" ? "none" : [...new Set(value.split(",").map((id) => id.trim()))].filter((id) => id.length > 0)).refine((value) => value === void 0 || value === "none" || value.length <= 25, { message: "at most 25 bylines may be selected" }).refine((value) => value === void 0 || value === "none" || value.length > 0, { message: "must contain at least one byline id" });
111
+ /** Query-string boolean. Explicit values only — `z.coerce.boolean()` reads "false" as true. */
112
+ const booleanParam = z.enum([
113
+ "1",
114
+ "0",
115
+ "true",
116
+ "false"
117
+ ]).optional().transform((value) => value === "1" || value === "true");
118
+ const contentFieldComparable = z.union([z.string().max(2048), z.number().finite()]);
119
+ const contentFieldFilterScalar = z.union([
120
+ contentFieldComparable,
121
+ z.boolean(),
122
+ z.null()
123
+ ]);
124
+ const contentFieldFilterValue = z.union([
125
+ contentFieldFilterScalar,
126
+ z.object({ in: z.array(z.union([contentFieldComparable, z.boolean()])).min(1).max(SQL_BATCH_SIZE) }).strict(),
127
+ z.object({
128
+ gt: contentFieldComparable.optional(),
129
+ gte: contentFieldComparable.optional(),
130
+ lt: contentFieldComparable.optional(),
131
+ lte: contentFieldComparable.optional()
132
+ }).strict().refine((value) => Object.values(value).some((bound) => bound !== void 0), { message: "Range filter must include at least one bound" })
133
+ ]);
134
+ function contentFieldFilterOperandCount(value) {
135
+ if (value === null) return 0;
136
+ if (!value || typeof value !== "object" || Array.isArray(value)) return 1;
137
+ if ("in" in value && Array.isArray(value.in)) return value.in.length;
138
+ return Object.values(value).filter((bound) => bound !== void 0).length;
139
+ }
140
+ /** AND-combined filters over custom fields explicitly marked as indexed. */
141
+ const contentFieldFiltersSchema = z.record(z.string().max(128).regex(/^[a-z][a-z0-9_]*$/, "must be a safe field identifier"), contentFieldFilterValue).refine((filters) => Object.keys(filters).length <= 20, { message: "At most 20 indexed field filters are allowed" }).refine((filters) => Object.values(filters).reduce((total, value) => total + contentFieldFilterOperandCount(value), 0) <= SQL_BATCH_SIZE, { message: `Indexed field filters have a total operand budget of ${SQL_BATCH_SIZE}` });
142
+ const contentFieldFiltersQuery = z.string().max(8192).transform((value, ctx) => {
143
+ try {
144
+ return JSON.parse(value);
145
+ } catch {
146
+ ctx.addIssue({
147
+ code: "custom",
148
+ message: "must be valid JSON"
149
+ });
150
+ return z.NEVER;
151
+ }
152
+ }).pipe(contentFieldFiltersSchema);
98
153
  const contentListQuery = cursorPaginationQuery.extend({
99
154
  status: z.string().optional(),
100
155
  orderBy: z.string().optional(),
@@ -108,8 +163,15 @@ const contentListQuery = cursorPaginationQuery.extend({
108
163
  "publishedAt"
109
164
  ]).optional(),
110
165
  dateFrom: contentDateBound,
111
- dateTo: contentDateBound
112
- }).meta({ id: "ContentListQuery" });
166
+ dateTo: contentDateBound,
167
+ bylines: bylineFilterParam,
168
+ includeInferredBylines: booleanParam,
169
+ fieldFilters: contentFieldFiltersQuery.optional()
170
+ }).transform(({ bylines, ...rest }) => ({
171
+ ...rest,
172
+ bylinesNone: bylines === "none",
173
+ bylines: bylines === "none" ? void 0 : bylines
174
+ })).meta({ id: "ContentListQuery" });
113
175
  /** ISO 8601 datetime for `publishedAt` / `createdAt`. Routes gate writes behind `content:publish_any`. */
114
176
  const contentDateOverride = z.iso.datetime({
115
177
  offset: true,
@@ -248,9 +310,13 @@ const collectionSupportValues = z.enum([
248
310
  "revisions",
249
311
  "preview",
250
312
  "scheduling",
251
- "search"
313
+ "search",
314
+ "seo"
252
315
  ]);
253
316
  const collectionSourcePattern = /^(template:.+|import:.+|manual|discovered|seed)$/;
317
+ const collectionListColumns = z.array(z.string().min(1).max(63).regex(slugPattern, "Invalid field slug format"));
318
+ const collectionAdminInputConfig = z.object({ listColumns: collectionListColumns.max(MAX_COLLECTION_LIST_COLUMNS, `At most ${MAX_COLLECTION_LIST_COLUMNS} list columns are allowed`).optional() });
319
+ const collectionAdminResponseConfig = z.object({ listColumns: collectionListColumns.optional() });
254
320
  const fieldTypeValues = z.enum([
255
321
  "string",
256
322
  "text",
@@ -286,6 +352,16 @@ const repeaterSubFieldSchema = z.object({
286
352
  required: z.boolean().optional(),
287
353
  options: z.array(z.string()).optional()
288
354
  });
355
+ const urlPatternValue = z.string().superRefine((pattern, ctx) => {
356
+ try {
357
+ compileUrlPattern(pattern);
358
+ } catch {
359
+ ctx.addIssue({
360
+ code: "custom",
361
+ message: "Invalid URL pattern"
362
+ });
363
+ }
364
+ });
289
365
  const fieldValidation = z.object({
290
366
  required: z.boolean().optional(),
291
367
  min: z.number().optional(),
@@ -298,6 +374,29 @@ const fieldValidation = z.object({
298
374
  minItems: z.number().int().min(0).optional(),
299
375
  maxItems: z.number().int().min(1).optional(),
300
376
  allowedMimeTypes: z.array(z.string().regex(/^[a-z0-9][a-z0-9!#$&^_+\-.]*\/[a-z0-9!#$&^_+\-.]*$/i, "Invalid MIME type")).min(1, "allowedMimeTypes must not be empty — omit the field to allow all types").max(64, "allowedMimeTypes may contain at most 64 entries").optional()
377
+ }).superRefine((validation, ctx) => {
378
+ for (const [minimum, maximum] of [
379
+ ["min", "max"],
380
+ ["minLength", "maxLength"],
381
+ ["minItems", "maxItems"]
382
+ ]) {
383
+ const minimumValue = validation[minimum];
384
+ const maximumValue = validation[maximum];
385
+ if (minimumValue !== void 0 && maximumValue !== void 0 && minimumValue > maximumValue) ctx.addIssue({
386
+ code: "custom",
387
+ path: [maximum],
388
+ message: `${maximum} must be greater than or equal to ${minimum}`
389
+ });
390
+ }
391
+ if (validation.pattern !== void 0) try {
392
+ RegExp(validation.pattern);
393
+ } catch {
394
+ ctx.addIssue({
395
+ code: "custom",
396
+ path: ["pattern"],
397
+ message: "Invalid validation pattern"
398
+ });
399
+ }
301
400
  }).optional();
302
401
  const fieldWidgetOptions = z.record(z.string(), z.unknown()).optional();
303
402
  const createCollectionBody = z.object({
@@ -306,19 +405,27 @@ const createCollectionBody = z.object({
306
405
  labelSingular: z.string().optional(),
307
406
  description: z.string().optional(),
308
407
  icon: z.string().optional(),
408
+ admin: collectionAdminInputConfig.optional(),
309
409
  supports: z.array(collectionSupportValues).optional(),
310
410
  source: z.string().regex(collectionSourcePattern).optional(),
311
- urlPattern: z.string().optional(),
312
- hasSeo: z.boolean().optional()
411
+ urlPattern: urlPatternValue.optional(),
412
+ routable: z.boolean().optional(),
413
+ hasSeo: z.boolean().optional(),
414
+ hidden: z.boolean().optional(),
415
+ sortOrder: z.number().int().nullish()
313
416
  }).meta({ id: "CreateCollectionBody" });
314
417
  const updateCollectionBody = z.object({
315
418
  label: z.string().min(1).optional(),
316
419
  labelSingular: z.string().optional(),
317
420
  description: z.string().optional(),
318
421
  icon: z.string().optional(),
422
+ admin: collectionAdminInputConfig.optional(),
319
423
  supports: z.array(collectionSupportValues).optional(),
320
- urlPattern: z.string().nullish(),
424
+ urlPattern: urlPatternValue.nullish(),
425
+ routable: z.boolean().optional(),
321
426
  hasSeo: z.boolean().optional(),
427
+ hidden: z.boolean().optional(),
428
+ sortOrder: z.number().int().nullish(),
322
429
  commentsEnabled: z.boolean().optional(),
323
430
  commentsModeration: z.enum([
324
431
  "all",
@@ -340,6 +447,7 @@ const createFieldBody = z.object({
340
447
  options: fieldWidgetOptions,
341
448
  sortOrder: z.number().int().min(0).optional(),
342
449
  searchable: z.boolean().optional(),
450
+ indexed: z.boolean().optional(),
343
451
  translatable: z.boolean().optional()
344
452
  }).meta({ id: "CreateFieldBody" });
345
453
  const updateFieldBody = z.object({
@@ -353,9 +461,11 @@ const updateFieldBody = z.object({
353
461
  options: fieldWidgetOptions,
354
462
  sortOrder: z.number().int().min(0).optional(),
355
463
  searchable: z.boolean().optional(),
464
+ indexed: z.boolean().optional(),
356
465
  translatable: z.boolean().optional()
357
466
  }).meta({ id: "UpdateFieldBody" });
358
467
  const fieldReorderBody = z.object({ fieldSlugs: z.array(z.string().min(1)) }).meta({ id: "FieldReorderBody" });
468
+ const collectionReorderBody = z.object({ slugs: z.array(z.string().min(1)) }).meta({ id: "CollectionReorderBody" });
359
469
  const orphanRegisterBody = z.object({
360
470
  label: z.string().optional(),
361
471
  labelSingular: z.string().optional(),
@@ -370,10 +480,14 @@ const collectionSchema = z.object({
370
480
  labelSingular: z.string().nullable(),
371
481
  description: z.string().nullable(),
372
482
  icon: z.string().nullable(),
483
+ admin: collectionAdminResponseConfig.optional(),
373
484
  supports: z.array(z.string()),
374
485
  source: z.string().nullable(),
375
486
  urlPattern: z.string().nullable(),
487
+ routable: z.boolean(),
376
488
  hasSeo: z.boolean(),
489
+ hidden: z.boolean(),
490
+ sortOrder: z.number().int().nullable(),
377
491
  createdAt: z.string(),
378
492
  updatedAt: z.string()
379
493
  }).meta({ id: "Collection" });
@@ -391,6 +505,7 @@ const fieldSchema = z.object({
391
505
  options: z.record(z.string(), z.unknown()).nullable(),
392
506
  sortOrder: z.number().int(),
393
507
  searchable: z.boolean(),
508
+ indexed: z.boolean(),
394
509
  translatable: z.boolean(),
395
510
  createdAt: z.string(),
396
511
  updatedAt: z.string()
@@ -638,19 +753,29 @@ const menuWithItemsSchema = menuSchema.extend({ items: z.array(menuItemSchema) }
638
753
 
639
754
  //#endregion
640
755
  //#region src/api/schemas/taxonomies.ts
641
- /** Collection slug format: lowercase alphanumeric + underscores, starts with letter */
642
- const collectionSlugPattern = /^[a-z][a-z0-9_]*$/;
756
+ const collectionSlug = z.string().min(1).max(63).regex(/^[a-z][a-z0-9_]*$/, "Invalid collection slug format");
643
757
  const createTaxonomyDefBody = z.object({
644
758
  name: z.string().min(1).max(63).regex(/^[a-z][a-z0-9_]*$/, "Name must be lowercase alphanumeric with underscores"),
645
759
  label: z.string().min(1).max(200),
646
760
  labelSingular: z.string().min(1).max(200).optional(),
647
761
  hierarchical: z.boolean().optional().default(false),
648
- collections: z.array(z.string().min(1).max(63).regex(collectionSlugPattern, "Invalid collection slug format")).max(100).optional().default([]),
762
+ collections: z.array(collectionSlug).max(100).optional().default([]),
649
763
  locale: localeCode.optional(),
650
764
  translationOf: z.string().min(1).optional()
651
765
  }).meta({ id: "CreateTaxonomyDefBody" });
766
+ /**
767
+ * `name` and `locale` are absent on purpose: both identify the definition row
768
+ * being written, and `.strict()` turns an attempt to change either into a 400
769
+ * rather than a silently ignored field.
770
+ */
771
+ const updateTaxonomyDefBody = z.object({
772
+ label: z.string().min(1).max(200).optional(),
773
+ labelSingular: z.string().min(1).max(200).nullish(),
774
+ hierarchical: z.boolean().optional(),
775
+ collections: z.array(collectionSlug).max(100).optional()
776
+ }).strict().meta({ id: "UpdateTaxonomyDefBody" });
652
777
  const createTermBody = z.object({
653
- slug: z.string().min(1),
778
+ slug: z.string().min(1).optional().meta({ description: "Term slug. Omit to derive a unique slug from the label." }),
654
779
  label: z.string().min(1),
655
780
  parentId: z.string().nullish(),
656
781
  description: z.string().optional(),
@@ -663,9 +788,14 @@ const updateTermBody = z.object({
663
788
  parentId: z.string().nullish(),
664
789
  description: z.string().optional()
665
790
  }).meta({ id: "UpdateTermBody" });
791
+ const reorderTermsBody = z.object({
792
+ parentId: z.string().min(1).nullish().meta({ description: "Parent term whose children are being ordered (translation_group or row id). Omit or null for the top level, which for a flat taxonomy is every term." }),
793
+ ids: z.array(z.string().min(1)).max(100).meta({ description: "Terms to move, in the desired order — each a row id or translation_group. May be a subset of the group: the listed terms are permuted within the positions they already occupy and every other member keeps its place. An id outside the group is rejected with REORDER_MISMATCH." })
794
+ }).strict().meta({ id: "ReorderTermsBody" });
666
795
  const termListQuery = z.object({
667
796
  locale: localeCode.optional(),
668
- includeCounts: z.enum(["true", "false"]).transform((v) => v === "true").optional().default(true).meta({ description: "Include each term's visible-usage count. Pass false to skip the aggregate; `count` is then absent from every term." })
797
+ includeCounts: z.enum(["true", "false"]).transform((v) => v === "true").optional().default(true).meta({ description: "Include each term's visible-usage count. Pass false to skip the aggregate; `count` is then absent from every term." }),
798
+ resolveFallback: z.enum(["true", "false"]).transform((value) => value === "true").optional().default(false).meta({ description: "Resolve one term per translation group, preferring the requested locale and then the configured default locale." })
669
799
  }).meta({ id: "TermListQuery" });
670
800
  const taxonomyDefSchema = z.object({
671
801
  id: z.string(),
@@ -687,6 +817,7 @@ const taxonomyDefTranslationsSchema = z.object({
687
817
  }))
688
818
  }).meta({ id: "TaxonomyDefTranslations" });
689
819
  const taxonomyListResponseSchema = z.object({ taxonomies: z.array(taxonomyDefSchema) }).meta({ id: "TaxonomyListResponse" });
820
+ const taxonomyResponseSchema = z.object({ taxonomy: taxonomyDefSchema }).meta({ id: "TaxonomyResponse" });
690
821
  const termSchema = z.object({
691
822
  id: z.string(),
692
823
  name: z.string(),
@@ -720,6 +851,7 @@ const termWithCountSchema = z.object({
720
851
  }).meta({ id: "TermWithCount" });
721
852
  const termListResponseSchema = z.object({ terms: z.array(termWithCountSchema) }).meta({ id: "TermListResponse" });
722
853
  const termResponseSchema = z.object({ term: termSchema }).meta({ id: "TermResponse" });
854
+ const termReorderResponseSchema = z.object({ reordered: z.literal(true) }).meta({ id: "TermReorderResponse" });
723
855
  const termGetResponseSchema = z.object({ term: termSchema.extend({
724
856
  count: z.number().int(),
725
857
  children: z.array(z.object({
@@ -859,7 +991,8 @@ const searchRebuildBody = z.object({ collection: z.string().min(1) }).meta({ id:
859
991
  const searchEnableBody = z.object({
860
992
  collection: z.string().min(1),
861
993
  enabled: z.boolean(),
862
- weights: z.record(z.string(), z.number()).optional()
994
+ weights: z.record(z.string(), z.number()).optional(),
995
+ tokenize: z.enum(SEARCH_TOKENIZERS).optional()
863
996
  }).meta({ id: "SearchEnableBody" });
864
997
  const searchResultSchema = z.object({
865
998
  collection: z.string(),
@@ -1066,5 +1199,5 @@ const notFoundSummarySchema = z.object({
1066
1199
  const notFoundSummaryResponseSchema = z.object({ items: z.array(notFoundSummarySchema) }).meta({ id: "NotFoundSummaryResponse" });
1067
1200
 
1068
1201
  //#endregion
1069
- export { updateTermBody as $, contentSeoSchema as $t, searchRebuildBody as A, createFieldBody as At, updateSectionBody as B, updateFieldBody as Bt, userDetailSchema as C, publicCommentSchema as Ct, usersListQuery as D, collectionSchema as Dt, userUpdateBody as E, collectionResponseSchema as Et, siteSettingsSchema as F, orphanRegisterBody as Ft, taxonomyListResponseSchema as G, contentItemSchema as Gt, createTermBody as H, contentAuthorsResponseSchema as Ht, createSectionBody as I, orphanedTableListResponseSchema as It, termListResponseSchema as J, contentPreviewUrlBody as Jt, termGetResponseSchema as K, contentListQuery as Kt, sectionListResponseSchema as L, orphanedTableSchema as Lt, searchResultSchema as M, fieldReorderBody as Mt, searchSuggestQuery as N, fieldResponseSchema as Nt, searchEnableBody as O, collectionWithFieldsResponseSchema as Ot, settingsUpdateBody as P, fieldSchema as Pt, termWithCountSchema as Q, contentSeoInput as Qt, sectionSchema as R, schemaExportQuery as Rt, allowedDomainUpdateBody as S, publicCommentListResponseSchema as St, userSchema as T, collectionListResponseSchema as Tt, taxonomyDefSchema as U, contentCompareResponseSchema as Ut, createTaxonomyDefBody as V, contentAuthorSchema as Vt, taxonomyDefTranslationsSchema as W, contentCreateBody as Wt, termSchema as X, contentResponseSchema as Xt, termResponseSchema as Y, contentPublishBody as Yt, termTranslationsSchema as Z, contentScheduleBody as Zt, widgetAreaSchema as _, commentListQuery as _t, notFoundPruneBody as a, trashedContentItemSchema as an, menuSchema as at, widgetSchema as b, createCommentBody as bt, notFoundSummarySchema as c, bylineCreditSchema as cn, reorderMenuItemsBody as ct, redirectsListQuery as d, bylineTranslationCreateBody as dn, isSafeHref as dt, contentTermsBody as en, createMenuBody as et, updateRedirectBody as f, bylineTranslationsResponseSchema as fn, sanitizeHref as ft, updateWidgetBody as g, commentCountsResponseSchema as gt, reorderWidgetsBody as h, contentBylineInputSchema as hn, commentBulkResponseSchema as ht, notFoundListResponseSchema as i, contentUpdateBody as in, menuListItemSchema as it, searchResponseSchema as j, fieldListResponseSchema as jt, searchQuery as k, createCollectionBody as kt, redirectListResponseSchema as l, bylineListResponseSchema as ln, updateMenuBody as lt, createWidgetBody as m, bylinesListQuery as mn, commentBulkBody as mt, notFoundEntrySchema as n, contentTranslationsResponseSchema as nn, menuItemSchema as nt, notFoundSummaryQuery as o, trashedContentListResponseSchema as on, menuTranslationsSchema as ot, createWidgetAreaBody as p, bylineUpdateBody as pn, adminCommentListResponseSchema as pt, termListQuery as q, contentListResponseSchema as qt, notFoundListQuery as r, contentTrashQuery as rn, menuItemTypeEnum as rt, notFoundSummaryResponseSchema as s, bylineCreateBody as sn, menuWithItemsSchema as st, createRedirectBody as t, contentTranslationSchema as tn, createMenuItemBody as tt, redirectSchema as u, bylineSummarySchema as un, updateMenuItemBody as ut, widgetAreaWithWidgetsAndCountSchema as v, commentSchema as vt, userListResponseSchema as w, collectionGetQuery as wt, allowedDomainCreateBody as x, createReactionBody as xt, widgetAreaWithWidgetsSchema as y, commentStatusBody as yt, sectionsListQuery as z, updateCollectionBody as zt };
1070
- //# sourceMappingURL=redirects-BOn2DIUs.mjs.map
1202
+ export { termSchema as $, contentListResponseSchema as $t, searchRebuildBody as A, collectionReorderBody as At, updateSectionBody as B, orphanRegisterBody as Bt, userDetailSchema as C, commentStatusBody as Ct, usersListQuery as D, publicCommentSchema as Dt, userUpdateBody as E, publicCommentListResponseSchema as Et, siteSettingsSchema as F, createFieldBody as Ft, taxonomyDefTranslationsSchema as G, updateFieldBody as Gt, createTermBody as H, orphanedTableSchema as Ht, createSectionBody as I, fieldListResponseSchema as It, termGetResponseSchema as J, contentCompareResponseSchema as Jt, taxonomyListResponseSchema as K, contentAuthorSchema as Kt, sectionListResponseSchema as L, fieldReorderBody as Lt, searchResultSchema as M, collectionSchema as Mt, searchSuggestQuery as N, collectionWithFieldsResponseSchema as Nt, searchEnableBody as O, collectionGetQuery as Ot, settingsUpdateBody as P, createCollectionBody as Pt, termResponseSchema as Q, contentListQuery as Qt, sectionSchema as R, fieldResponseSchema as Rt, allowedDomainUpdateBody as S, commentSchema as St, userSchema as T, createReactionBody as Tt, reorderTermsBody as U, schemaExportQuery as Ut, createTaxonomyDefBody as V, orphanedTableListResponseSchema as Vt, taxonomyDefSchema as W, updateCollectionBody as Wt, termListResponseSchema as X, contentFieldFiltersSchema as Xt, termListQuery as Y, contentCreateBody as Yt, termReorderResponseSchema as Z, contentItemSchema as Zt, widgetAreaSchema as _, bylineTranslationCreateBody as _n, adminCommentListResponseSchema as _t, notFoundPruneBody as a, contentSeoSchema as an, createMenuItemBody as at, widgetSchema as b, bylinesListQuery as bn, commentCountsResponseSchema as bt, notFoundSummarySchema as c, contentTranslationsResponseSchema as cn, menuListItemSchema as ct, redirectsListQuery as d, trashedContentItemSchema as dn, menuWithItemsSchema as dt, contentPreviewUrlBody as en, termTranslationsSchema as et, updateRedirectBody as f, trashedContentListResponseSchema as fn, reorderMenuItemsBody as ft, updateWidgetBody as g, bylineSummarySchema as gn, sanitizeHref as gt, reorderWidgetsBody as h, bylineListResponseSchema as hn, isSafeHref as ht, notFoundListResponseSchema as i, contentSeoInput as in, createMenuBody as it, searchResponseSchema as j, collectionResponseSchema as jt, searchQuery as k, collectionListResponseSchema as kt, redirectListResponseSchema as l, contentTrashQuery as ln, menuSchema as lt, createWidgetBody as m, bylineCreditSchema as mn, updateMenuItemBody as mt, notFoundEntrySchema as n, contentResponseSchema as nn, updateTaxonomyDefBody as nt, notFoundSummaryQuery as o, contentTermsBody as on, menuItemSchema as ot, createWidgetAreaBody as p, bylineCreateBody as pn, updateMenuBody as pt, taxonomyResponseSchema as q, contentAuthorsResponseSchema as qt, notFoundListQuery as r, contentScheduleBody as rn, updateTermBody as rt, notFoundSummaryResponseSchema as s, contentTranslationSchema as sn, menuItemTypeEnum as st, createRedirectBody as t, contentPublishBody as tn, termWithCountSchema as tt, redirectSchema as u, contentUpdateBody as un, menuTranslationsSchema as ut, widgetAreaWithWidgetsAndCountSchema as v, bylineTranslationsResponseSchema as vn, commentBulkBody as vt, userListResponseSchema as w, createCommentBody as wt, allowedDomainCreateBody as x, contentBylineInputSchema as xn, commentListQuery as xt, widgetAreaWithWidgetsSchema as y, bylineUpdateBody as yn, commentBulkResponseSchema as yt, sectionsListQuery as z, fieldSchema as zt };
1203
+ //# sourceMappingURL=redirects-cV9g7V-0.mjs.map