emdash 0.29.0 → 0.31.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 (876) hide show
  1. package/dist/{adapters-DPAkL6QF.d.mts → adapters-C0ONzkUP.d.mts} +10 -1
  2. package/dist/adapters-C0ONzkUP.d.mts.map +1 -0
  3. package/dist/{allowed-origins-FXB-FplB.mjs → allowed-origins-CCEi9bPI.mjs} +2 -2
  4. package/dist/{allowed-origins-FXB-FplB.mjs.map → allowed-origins-CCEi9bPI.mjs.map} +1 -1
  5. package/dist/api/route-utils.d.mts +3 -3
  6. package/dist/api/route-utils.d.mts.map +1 -1
  7. package/dist/api/route-utils.mjs +19 -19
  8. package/dist/api/schemas/index.d.mts +2 -2
  9. package/dist/api/schemas/index.mjs +5 -4
  10. package/dist/{api-DVbHNApo.mjs → api-EibxGP-V.mjs} +260 -160
  11. package/dist/api-EibxGP-V.mjs.map +1 -0
  12. package/dist/api-tokens-Cvmixds7.mjs +3 -0
  13. package/dist/{api-tokens-UYBkl17d.mjs → api-tokens-uPt8UDpx.mjs} +2 -2
  14. package/dist/{api-tokens-UYBkl17d.mjs.map → api-tokens-uPt8UDpx.mjs.map} +1 -1
  15. package/dist/{apply-D23iUV4q.mjs → apply-fGHCAwWN.mjs} +42 -44
  16. package/dist/apply-fGHCAwWN.mjs.map +1 -0
  17. package/dist/astro/index.d.mts +12 -13
  18. package/dist/astro/index.d.mts.map +1 -1
  19. package/dist/astro/index.mjs +90 -11
  20. package/dist/astro/index.mjs.map +1 -1
  21. package/dist/astro/middleware/auth.d.mts +10 -11
  22. package/dist/astro/middleware/auth.d.mts.map +1 -1
  23. package/dist/astro/middleware/auth.mjs +56 -107
  24. package/dist/astro/middleware/auth.mjs.map +1 -1
  25. package/dist/astro/middleware/redirect.mjs +7 -7
  26. package/dist/astro/middleware/request-context.mjs +4 -4
  27. package/dist/astro/middleware/request-context.mjs.map +1 -1
  28. package/dist/astro/middleware/setup.mjs +1 -1
  29. package/dist/astro/middleware.d.mts +47 -3
  30. package/dist/astro/middleware.d.mts.map +1 -1
  31. package/dist/astro/middleware.mjs +410 -123
  32. package/dist/astro/middleware.mjs.map +1 -1
  33. package/dist/astro/routes/PluginRegistry.d.mts +5 -1
  34. package/dist/astro/routes/PluginRegistry.d.mts.map +1 -1
  35. package/dist/astro/routes/PluginRegistry.mjs +2 -1
  36. package/dist/astro/routes/PluginRegistry.mjs.map +1 -1
  37. package/dist/astro/routes/api/admin/allowed-domains/_domain_.mjs +9 -8
  38. package/dist/astro/routes/api/admin/allowed-domains/_domain_.mjs.map +1 -1
  39. package/dist/astro/routes/api/admin/allowed-domains/index.mjs +9 -8
  40. package/dist/astro/routes/api/admin/allowed-domains/index.mjs.map +1 -1
  41. package/dist/astro/routes/api/admin/api-tokens/_id_.mjs +5 -5
  42. package/dist/astro/routes/api/admin/api-tokens/index.mjs +7 -7
  43. package/dist/astro/routes/api/admin/api-tokens/index.mjs.map +1 -1
  44. package/dist/astro/routes/api/admin/byline-fields/_slug_/usage.mjs +5 -5
  45. package/dist/astro/routes/api/admin/byline-fields/_slug_.mjs +10 -9
  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 +10 -9
  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 +10 -9
  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 +16 -15
  52. package/dist/astro/routes/api/admin/bylines/_id_/index.mjs.map +1 -1
  53. package/dist/astro/routes/api/admin/bylines/_id_/translations.mjs +17 -22
  54. package/dist/astro/routes/api/admin/bylines/_id_/translations.mjs.map +1 -1
  55. package/dist/astro/routes/api/admin/bylines/index.d.mts.map +1 -1
  56. package/dist/astro/routes/api/admin/bylines/index.mjs +20 -18
  57. package/dist/astro/routes/api/admin/bylines/index.mjs.map +1 -1
  58. package/dist/astro/routes/api/admin/comments/_id_/status.mjs +13 -12
  59. package/dist/astro/routes/api/admin/comments/_id_/status.mjs.map +1 -1
  60. package/dist/astro/routes/api/admin/comments/_id_.mjs +6 -6
  61. package/dist/astro/routes/api/admin/comments/bulk.mjs +11 -10
  62. package/dist/astro/routes/api/admin/comments/bulk.mjs.map +1 -1
  63. package/dist/astro/routes/api/admin/comments/counts.mjs +6 -6
  64. package/dist/astro/routes/api/admin/comments/index.mjs +11 -10
  65. package/dist/astro/routes/api/admin/comments/index.mjs.map +1 -1
  66. package/dist/astro/routes/api/admin/hooks/exclusive/_hookName_.mjs +5 -5
  67. package/dist/astro/routes/api/admin/hooks/exclusive/index.mjs +4 -4
  68. package/dist/astro/routes/api/admin/media-usage/repair.mjs +12 -10
  69. package/dist/astro/routes/api/admin/media-usage/repair.mjs.map +1 -1
  70. package/dist/astro/routes/api/admin/oauth-clients/_id_.mjs +5 -5
  71. package/dist/astro/routes/api/admin/oauth-clients/index.mjs +5 -5
  72. package/dist/astro/routes/api/admin/plugins/_id_/disable.mjs +41 -40
  73. package/dist/astro/routes/api/admin/plugins/_id_/disable.mjs.map +1 -1
  74. package/dist/astro/routes/api/admin/plugins/_id_/enable.mjs +41 -40
  75. package/dist/astro/routes/api/admin/plugins/_id_/enable.mjs.map +1 -1
  76. package/dist/astro/routes/api/admin/plugins/_id_/index.mjs +46 -40
  77. package/dist/astro/routes/api/admin/plugins/_id_/index.mjs.map +1 -1
  78. package/dist/astro/routes/api/admin/plugins/_id_/mcp.d.mts +8 -0
  79. package/dist/astro/routes/api/admin/plugins/_id_/mcp.d.mts.map +1 -0
  80. package/dist/astro/routes/api/admin/plugins/_id_/mcp.mjs +39 -0
  81. package/dist/astro/routes/api/admin/plugins/_id_/mcp.mjs.map +1 -0
  82. package/dist/astro/routes/api/admin/plugins/_id_/settings.d.mts +9 -0
  83. package/dist/astro/routes/api/admin/plugins/_id_/settings.d.mts.map +1 -0
  84. package/dist/astro/routes/api/admin/plugins/_id_/settings.mjs +78 -0
  85. package/dist/astro/routes/api/admin/plugins/_id_/settings.mjs.map +1 -0
  86. package/dist/astro/routes/api/admin/plugins/_id_/uninstall.mjs +40 -39
  87. package/dist/astro/routes/api/admin/plugins/_id_/uninstall.mjs.map +1 -1
  88. package/dist/astro/routes/api/admin/plugins/_id_/update.d.mts.map +1 -1
  89. package/dist/astro/routes/api/admin/plugins/_id_/update.mjs +43 -40
  90. package/dist/astro/routes/api/admin/plugins/_id_/update.mjs.map +1 -1
  91. package/dist/astro/routes/api/admin/plugins/index.mjs +46 -40
  92. package/dist/astro/routes/api/admin/plugins/index.mjs.map +1 -1
  93. package/dist/astro/routes/api/admin/plugins/marketplace/_id_/icon.mjs +4 -4
  94. package/dist/astro/routes/api/admin/plugins/marketplace/_id_/index.mjs +40 -39
  95. package/dist/astro/routes/api/admin/plugins/marketplace/_id_/index.mjs.map +1 -1
  96. package/dist/astro/routes/api/admin/plugins/marketplace/_id_/install.d.mts.map +1 -1
  97. package/dist/astro/routes/api/admin/plugins/marketplace/_id_/install.mjs +46 -41
  98. package/dist/astro/routes/api/admin/plugins/marketplace/_id_/install.mjs.map +1 -1
  99. package/dist/astro/routes/api/admin/plugins/marketplace/index.mjs +40 -39
  100. package/dist/astro/routes/api/admin/plugins/marketplace/index.mjs.map +1 -1
  101. package/dist/astro/routes/api/admin/plugins/registry/_id_/uninstall.mjs +40 -39
  102. package/dist/astro/routes/api/admin/plugins/registry/_id_/uninstall.mjs.map +1 -1
  103. package/dist/astro/routes/api/admin/plugins/registry/_id_/update.d.mts.map +1 -1
  104. package/dist/astro/routes/api/admin/plugins/registry/_id_/update.mjs +44 -41
  105. package/dist/astro/routes/api/admin/plugins/registry/_id_/update.mjs.map +1 -1
  106. package/dist/astro/routes/api/admin/plugins/registry/artifact.mjs +40 -39
  107. package/dist/astro/routes/api/admin/plugins/registry/artifact.mjs.map +1 -1
  108. package/dist/astro/routes/api/admin/plugins/registry/install.d.mts.map +1 -1
  109. package/dist/astro/routes/api/admin/plugins/registry/install.mjs +45 -42
  110. package/dist/astro/routes/api/admin/plugins/registry/install.mjs.map +1 -1
  111. package/dist/astro/routes/api/admin/plugins/updates.mjs +41 -40
  112. package/dist/astro/routes/api/admin/plugins/updates.mjs.map +1 -1
  113. package/dist/astro/routes/api/admin/themes/marketplace/_id_/index.mjs +40 -39
  114. package/dist/astro/routes/api/admin/themes/marketplace/_id_/index.mjs.map +1 -1
  115. package/dist/astro/routes/api/admin/themes/marketplace/_id_/thumbnail.mjs +4 -4
  116. package/dist/astro/routes/api/admin/themes/marketplace/index.mjs +40 -39
  117. package/dist/astro/routes/api/admin/themes/marketplace/index.mjs.map +1 -1
  118. package/dist/astro/routes/api/admin/users/_id_/disable.mjs +4 -4
  119. package/dist/astro/routes/api/admin/users/_id_/enable.mjs +4 -4
  120. package/dist/astro/routes/api/admin/users/_id_/index.mjs +9 -8
  121. package/dist/astro/routes/api/admin/users/_id_/index.mjs.map +1 -1
  122. package/dist/astro/routes/api/admin/users/_id_/send-recovery.mjs +5 -5
  123. package/dist/astro/routes/api/admin/users/index.mjs +9 -8
  124. package/dist/astro/routes/api/admin/users/index.mjs.map +1 -1
  125. package/dist/astro/routes/api/auth/dev-bypass.mjs +7 -7
  126. package/dist/astro/routes/api/auth/invite/accept.mjs +4 -4
  127. package/dist/astro/routes/api/auth/invite/complete.mjs +13 -12
  128. package/dist/astro/routes/api/auth/invite/complete.mjs.map +1 -1
  129. package/dist/astro/routes/api/auth/invite/index.mjs +10 -9
  130. package/dist/astro/routes/api/auth/invite/index.mjs.map +1 -1
  131. package/dist/astro/routes/api/auth/invite/register-options.mjs +12 -11
  132. package/dist/astro/routes/api/auth/invite/register-options.mjs.map +1 -1
  133. package/dist/astro/routes/api/auth/logout.mjs +4 -4
  134. package/dist/astro/routes/api/auth/magic-link/send.mjs +12 -11
  135. package/dist/astro/routes/api/auth/magic-link/send.mjs.map +1 -1
  136. package/dist/astro/routes/api/auth/magic-link/verify.mjs +5 -5
  137. package/dist/astro/routes/api/auth/me.mjs +9 -8
  138. package/dist/astro/routes/api/auth/me.mjs.map +1 -1
  139. package/dist/astro/routes/api/auth/mode.d.mts.map +1 -1
  140. package/dist/astro/routes/api/auth/mode.mjs +6 -3
  141. package/dist/astro/routes/api/auth/mode.mjs.map +1 -1
  142. package/dist/astro/routes/api/auth/oauth/_provider_/callback.mjs +15 -5
  143. package/dist/astro/routes/api/auth/oauth/_provider_/callback.mjs.map +1 -1
  144. package/dist/astro/routes/api/auth/oauth/_provider_.d.mts.map +1 -1
  145. package/dist/astro/routes/api/auth/oauth/_provider_.mjs +11 -5
  146. package/dist/astro/routes/api/auth/oauth/_provider_.mjs.map +1 -1
  147. package/dist/astro/routes/api/auth/passkey/_id_.mjs +8 -7
  148. package/dist/astro/routes/api/auth/passkey/_id_.mjs.map +1 -1
  149. package/dist/astro/routes/api/auth/passkey/index.mjs +3 -3
  150. package/dist/astro/routes/api/auth/passkey/options.mjs +13 -12
  151. package/dist/astro/routes/api/auth/passkey/options.mjs.map +1 -1
  152. package/dist/astro/routes/api/auth/passkey/register/options.mjs +11 -10
  153. package/dist/astro/routes/api/auth/passkey/register/options.mjs.map +1 -1
  154. package/dist/astro/routes/api/auth/passkey/register/verify.mjs +12 -11
  155. package/dist/astro/routes/api/auth/passkey/register/verify.mjs.map +1 -1
  156. package/dist/astro/routes/api/auth/passkey/verify.mjs +12 -11
  157. package/dist/astro/routes/api/auth/passkey/verify.mjs.map +1 -1
  158. package/dist/astro/routes/api/auth/signup/complete.mjs +13 -12
  159. package/dist/astro/routes/api/auth/signup/complete.mjs.map +1 -1
  160. package/dist/astro/routes/api/auth/signup/request.mjs +12 -11
  161. package/dist/astro/routes/api/auth/signup/request.mjs.map +1 -1
  162. package/dist/astro/routes/api/auth/signup/verify.mjs +4 -4
  163. package/dist/astro/routes/api/comments/_collection_/_contentId_/index.mjs +14 -13
  164. package/dist/astro/routes/api/comments/_collection_/_contentId_/index.mjs.map +1 -1
  165. package/dist/astro/routes/api/comments/_collection_/_contentId_/reactions.mjs +13 -12
  166. package/dist/astro/routes/api/comments/_collection_/_contentId_/reactions.mjs.map +1 -1
  167. package/dist/astro/routes/api/content/_collection_/_id_/compare.mjs +5 -5
  168. package/dist/astro/routes/api/content/_collection_/_id_/compare.mjs.map +1 -1
  169. package/dist/astro/routes/api/content/_collection_/_id_/discard-draft.mjs +5 -4
  170. package/dist/astro/routes/api/content/_collection_/_id_/discard-draft.mjs.map +1 -1
  171. package/dist/astro/routes/api/content/_collection_/_id_/duplicate.mjs +6 -5
  172. package/dist/astro/routes/api/content/_collection_/_id_/duplicate.mjs.map +1 -1
  173. package/dist/astro/routes/api/content/_collection_/_id_/permanent.mjs +5 -5
  174. package/dist/astro/routes/api/content/_collection_/_id_/permanent.mjs.map +1 -1
  175. package/dist/astro/routes/api/content/_collection_/_id_/preview-url.mjs +14 -13
  176. package/dist/astro/routes/api/content/_collection_/_id_/preview-url.mjs.map +1 -1
  177. package/dist/astro/routes/api/content/_collection_/_id_/publish.mjs +10 -8
  178. package/dist/astro/routes/api/content/_collection_/_id_/publish.mjs.map +1 -1
  179. package/dist/astro/routes/api/content/_collection_/_id_/references/_relation_/children.d.mts.map +1 -1
  180. package/dist/astro/routes/api/content/_collection_/_id_/references/_relation_/children.mjs +20 -19
  181. package/dist/astro/routes/api/content/_collection_/_id_/references/_relation_/children.mjs.map +1 -1
  182. package/dist/astro/routes/api/content/_collection_/_id_/references/_relation_/parents.mjs +18 -17
  183. package/dist/astro/routes/api/content/_collection_/_id_/references/_relation_/parents.mjs.map +1 -1
  184. package/dist/astro/routes/api/content/_collection_/_id_/restore.mjs +5 -4
  185. package/dist/astro/routes/api/content/_collection_/_id_/restore.mjs.map +1 -1
  186. package/dist/astro/routes/api/content/_collection_/_id_/revisions.mjs +5 -5
  187. package/dist/astro/routes/api/content/_collection_/_id_/revisions.mjs.map +1 -1
  188. package/dist/astro/routes/api/content/_collection_/_id_/schedule.mjs +10 -8
  189. package/dist/astro/routes/api/content/_collection_/_id_/schedule.mjs.map +1 -1
  190. package/dist/astro/routes/api/content/_collection_/_id_/terms/_taxonomy_.d.mts.map +1 -1
  191. package/dist/astro/routes/api/content/_collection_/_id_/terms/_taxonomy_.mjs +19 -18
  192. package/dist/astro/routes/api/content/_collection_/_id_/terms/_taxonomy_.mjs.map +1 -1
  193. package/dist/astro/routes/api/content/_collection_/_id_/translations.mjs +5 -5
  194. package/dist/astro/routes/api/content/_collection_/_id_/translations.mjs.map +1 -1
  195. package/dist/astro/routes/api/content/_collection_/_id_/unpublish.mjs +5 -4
  196. package/dist/astro/routes/api/content/_collection_/_id_/unpublish.mjs.map +1 -1
  197. package/dist/astro/routes/api/content/_collection_/_id_.d.mts.map +1 -1
  198. package/dist/astro/routes/api/content/_collection_/_id_.mjs +11 -9
  199. package/dist/astro/routes/api/content/_collection_/_id_.mjs.map +1 -1
  200. package/dist/astro/routes/api/content/_collection_/authors.mjs +5 -5
  201. package/dist/astro/routes/api/content/_collection_/authors.mjs.map +1 -1
  202. package/dist/astro/routes/api/content/_collection_/index.d.mts.map +1 -1
  203. package/dist/astro/routes/api/content/_collection_/index.mjs +12 -10
  204. package/dist/astro/routes/api/content/_collection_/index.mjs.map +1 -1
  205. package/dist/astro/routes/api/content/_collection_/trash.mjs +10 -9
  206. package/dist/astro/routes/api/content/_collection_/trash.mjs.map +1 -1
  207. package/dist/astro/routes/api/dashboard.mjs +8 -8
  208. package/dist/astro/routes/api/dev/emails.mjs +4 -4
  209. package/dist/astro/routes/api/import/probe.d.mts +3 -3
  210. package/dist/astro/routes/api/import/probe.mjs +17 -16
  211. package/dist/astro/routes/api/import/probe.mjs.map +1 -1
  212. package/dist/astro/routes/api/import/wordpress/analyze.mjs +4 -4
  213. package/dist/astro/routes/api/import/wordpress/execute.d.mts +11 -12
  214. package/dist/astro/routes/api/import/wordpress/execute.d.mts.map +1 -1
  215. package/dist/astro/routes/api/import/wordpress/execute.mjs +13 -13
  216. package/dist/astro/routes/api/import/wordpress/media.d.mts +10 -11
  217. package/dist/astro/routes/api/import/wordpress/media.d.mts.map +1 -1
  218. package/dist/astro/routes/api/import/wordpress/media.mjs +11 -10
  219. package/dist/astro/routes/api/import/wordpress/media.mjs.map +1 -1
  220. package/dist/astro/routes/api/import/wordpress/prepare.mjs +11 -10
  221. package/dist/astro/routes/api/import/wordpress/prepare.mjs.map +1 -1
  222. package/dist/astro/routes/api/import/wordpress/rewrite-urls.d.mts +11 -12
  223. package/dist/astro/routes/api/import/wordpress/rewrite-urls.d.mts.map +1 -1
  224. package/dist/astro/routes/api/import/wordpress/rewrite-urls.mjs +11 -10
  225. package/dist/astro/routes/api/import/wordpress/rewrite-urls.mjs.map +1 -1
  226. package/dist/astro/routes/api/import/wordpress-plugin/analyze.d.mts +1 -1
  227. package/dist/astro/routes/api/import/wordpress-plugin/analyze.mjs +17 -16
  228. package/dist/astro/routes/api/import/wordpress-plugin/analyze.mjs.map +1 -1
  229. package/dist/astro/routes/api/import/wordpress-plugin/callback.mjs +1 -1
  230. package/dist/astro/routes/api/import/wordpress-plugin/execute.d.mts +11 -12
  231. package/dist/astro/routes/api/import/wordpress-plugin/execute.d.mts.map +1 -1
  232. package/dist/astro/routes/api/import/wordpress-plugin/execute.mjs +24 -23
  233. package/dist/astro/routes/api/import/wordpress-plugin/execute.mjs.map +1 -1
  234. package/dist/astro/routes/api/manifest.mjs +7 -8
  235. package/dist/astro/routes/api/manifest.mjs.map +1 -1
  236. package/dist/astro/routes/api/mcp.d.mts.map +1 -1
  237. package/dist/astro/routes/api/mcp.mjs +149 -45
  238. package/dist/astro/routes/api/mcp.mjs.map +1 -1
  239. package/dist/astro/routes/api/media/_id_/confirm.mjs +9 -8
  240. package/dist/astro/routes/api/media/_id_/confirm.mjs.map +1 -1
  241. package/dist/astro/routes/api/media/_id_/usage.d.mts +8 -0
  242. package/dist/astro/routes/api/media/_id_/usage.d.mts.map +1 -0
  243. package/dist/astro/routes/api/media/_id_/usage.mjs +37 -0
  244. package/dist/astro/routes/api/media/_id_/usage.mjs.map +1 -0
  245. package/dist/astro/routes/api/media/_id_.d.mts.map +1 -1
  246. package/dist/astro/routes/api/media/_id_.mjs +26 -10
  247. package/dist/astro/routes/api/media/_id_.mjs.map +1 -1
  248. package/dist/astro/routes/api/media/file/_...key_.mjs +4 -3
  249. package/dist/astro/routes/api/media/file/_...key_.mjs.map +1 -1
  250. package/dist/astro/routes/api/media/providers/_providerId_/_itemId_.mjs +4 -4
  251. package/dist/astro/routes/api/media/providers/_providerId_/index.mjs +4 -4
  252. package/dist/astro/routes/api/media/providers/index.mjs +4 -4
  253. package/dist/astro/routes/api/media/upload-url.mjs +10 -9
  254. package/dist/astro/routes/api/media/upload-url.mjs.map +1 -1
  255. package/dist/astro/routes/api/media.d.mts.map +1 -1
  256. package/dist/astro/routes/api/media.mjs +31 -11
  257. package/dist/astro/routes/api/media.mjs.map +1 -1
  258. package/dist/astro/routes/api/menus/_name_/items/_id_.mjs +10 -9
  259. package/dist/astro/routes/api/menus/_name_/items/_id_.mjs.map +1 -1
  260. package/dist/astro/routes/api/menus/_name_/items.mjs +10 -9
  261. package/dist/astro/routes/api/menus/_name_/items.mjs.map +1 -1
  262. package/dist/astro/routes/api/menus/_name_/reorder.mjs +10 -9
  263. package/dist/astro/routes/api/menus/_name_/reorder.mjs.map +1 -1
  264. package/dist/astro/routes/api/menus/_name_/translations.mjs +10 -9
  265. package/dist/astro/routes/api/menus/_name_/translations.mjs.map +1 -1
  266. package/dist/astro/routes/api/menus/_name_.mjs +10 -9
  267. package/dist/astro/routes/api/menus/_name_.mjs.map +1 -1
  268. package/dist/astro/routes/api/menus/index.mjs +10 -9
  269. package/dist/astro/routes/api/menus/index.mjs.map +1 -1
  270. package/dist/astro/routes/api/oauth/authorize.d.mts.map +1 -1
  271. package/dist/astro/routes/api/oauth/authorize.mjs +29 -16
  272. package/dist/astro/routes/api/oauth/authorize.mjs.map +1 -1
  273. package/dist/astro/routes/api/oauth/device/authorize.mjs +7 -7
  274. package/dist/astro/routes/api/oauth/device/code.mjs +10 -10
  275. package/dist/astro/routes/api/oauth/device/token.mjs +9 -9
  276. package/dist/astro/routes/api/oauth/register.mjs +4 -4
  277. package/dist/astro/routes/api/oauth/token/refresh.mjs +7 -7
  278. package/dist/astro/routes/api/oauth/token/revoke.mjs +7 -7
  279. package/dist/astro/routes/api/oauth/token.mjs +7 -7
  280. package/dist/astro/routes/api/openapi.json.mjs +52 -24
  281. package/dist/astro/routes/api/openapi.json.mjs.map +1 -1
  282. package/dist/astro/routes/api/plugins/_pluginId_/_...path_.d.mts.map +1 -1
  283. package/dist/astro/routes/api/plugins/_pluginId_/_...path_.mjs +20 -32
  284. package/dist/astro/routes/api/plugins/_pluginId_/_...path_.mjs.map +1 -1
  285. package/dist/astro/routes/api/redirects/404s/index.mjs +12 -11
  286. package/dist/astro/routes/api/redirects/404s/index.mjs.map +1 -1
  287. package/dist/astro/routes/api/redirects/404s/summary.mjs +12 -11
  288. package/dist/astro/routes/api/redirects/404s/summary.mjs.map +1 -1
  289. package/dist/astro/routes/api/redirects/_id_.mjs +13 -12
  290. package/dist/astro/routes/api/redirects/_id_.mjs.map +1 -1
  291. package/dist/astro/routes/api/redirects/index.mjs +13 -12
  292. package/dist/astro/routes/api/redirects/index.mjs.map +1 -1
  293. package/dist/astro/routes/api/relations/_id_/index.mjs +16 -15
  294. package/dist/astro/routes/api/relations/_id_/index.mjs.map +1 -1
  295. package/dist/astro/routes/api/relations/_id_/translations.mjs +11 -11
  296. package/dist/astro/routes/api/relations/index.mjs +16 -15
  297. package/dist/astro/routes/api/relations/index.mjs.map +1 -1
  298. package/dist/astro/routes/api/revisions/_revisionId_/index.mjs +4 -4
  299. package/dist/astro/routes/api/revisions/_revisionId_/restore.mjs +5 -4
  300. package/dist/astro/routes/api/revisions/_revisionId_/restore.mjs.map +1 -1
  301. package/dist/astro/routes/api/schema/collections/_slug_/fields/_fieldSlug_.mjs +40 -39
  302. package/dist/astro/routes/api/schema/collections/_slug_/fields/_fieldSlug_.mjs.map +1 -1
  303. package/dist/astro/routes/api/schema/collections/_slug_/fields/index.mjs +40 -39
  304. package/dist/astro/routes/api/schema/collections/_slug_/fields/index.mjs.map +1 -1
  305. package/dist/astro/routes/api/schema/collections/_slug_/fields/reorder.mjs +40 -39
  306. package/dist/astro/routes/api/schema/collections/_slug_/fields/reorder.mjs.map +1 -1
  307. package/dist/astro/routes/api/schema/collections/_slug_/index.mjs +40 -39
  308. package/dist/astro/routes/api/schema/collections/_slug_/index.mjs.map +1 -1
  309. package/dist/astro/routes/api/schema/collections/index.mjs +40 -39
  310. package/dist/astro/routes/api/schema/collections/index.mjs.map +1 -1
  311. package/dist/astro/routes/api/schema/index.mjs +9 -9
  312. package/dist/astro/routes/api/schema/orphans/_slug_.mjs +40 -39
  313. package/dist/astro/routes/api/schema/orphans/_slug_.mjs.map +1 -1
  314. package/dist/astro/routes/api/schema/orphans/index.mjs +40 -39
  315. package/dist/astro/routes/api/schema/orphans/index.mjs.map +1 -1
  316. package/dist/astro/routes/api/search/enable.mjs +13 -12
  317. package/dist/astro/routes/api/search/enable.mjs.map +1 -1
  318. package/dist/astro/routes/api/search/index.mjs +12 -11
  319. package/dist/astro/routes/api/search/index.mjs.map +1 -1
  320. package/dist/astro/routes/api/search/rebuild.mjs +13 -12
  321. package/dist/astro/routes/api/search/rebuild.mjs.map +1 -1
  322. package/dist/astro/routes/api/search/stats.mjs +8 -8
  323. package/dist/astro/routes/api/search/suggest.mjs +12 -11
  324. package/dist/astro/routes/api/search/suggest.mjs.map +1 -1
  325. package/dist/astro/routes/api/sections/_slug_.mjs +12 -11
  326. package/dist/astro/routes/api/sections/_slug_.mjs.map +1 -1
  327. package/dist/astro/routes/api/sections/index.mjs +12 -11
  328. package/dist/astro/routes/api/sections/index.mjs.map +1 -1
  329. package/dist/astro/routes/api/settings/backups/archives/_name_.d.mts +9 -0
  330. package/dist/astro/routes/api/settings/backups/archives/_name_.d.mts.map +1 -0
  331. package/dist/astro/routes/api/settings/backups/archives/_name_.mjs +48 -0
  332. package/dist/astro/routes/api/settings/backups/archives/_name_.mjs.map +1 -0
  333. package/dist/astro/routes/api/settings/backups/archives/index.d.mts +8 -0
  334. package/dist/astro/routes/api/settings/backups/archives/index.d.mts.map +1 -0
  335. package/dist/astro/routes/api/settings/backups/archives/index.mjs +23 -0
  336. package/dist/astro/routes/api/settings/backups/archives/index.mjs.map +1 -0
  337. package/dist/astro/routes/api/settings/backups/export.d.mts +8 -0
  338. package/dist/astro/routes/api/settings/backups/export.d.mts.map +1 -0
  339. package/dist/astro/routes/api/settings/backups/export.mjs +35 -0
  340. package/dist/astro/routes/api/settings/backups/export.mjs.map +1 -0
  341. package/dist/astro/routes/api/settings/backups/index.d.mts +9 -0
  342. package/dist/astro/routes/api/settings/backups/index.d.mts.map +1 -0
  343. package/dist/astro/routes/api/settings/backups/index.mjs +52 -0
  344. package/dist/astro/routes/api/settings/backups/index.mjs.map +1 -0
  345. package/dist/astro/routes/api/settings/email.mjs +5 -5
  346. package/dist/astro/routes/api/settings.mjs +14 -13
  347. package/dist/astro/routes/api/settings.mjs.map +1 -1
  348. package/dist/astro/routes/api/setup/admin-verify.mjs +19 -15
  349. package/dist/astro/routes/api/setup/admin-verify.mjs.map +1 -1
  350. package/dist/astro/routes/api/setup/admin.mjs +18 -14
  351. package/dist/astro/routes/api/setup/admin.mjs.map +1 -1
  352. package/dist/astro/routes/api/setup/dev-bypass.mjs +26 -26
  353. package/dist/astro/routes/api/setup/dev-reset.mjs +3 -3
  354. package/dist/astro/routes/api/setup/index.mjs +28 -27
  355. package/dist/astro/routes/api/setup/index.mjs.map +1 -1
  356. package/dist/astro/routes/api/setup/status.mjs +5 -5
  357. package/dist/astro/routes/api/snapshot.mjs +8 -215
  358. package/dist/astro/routes/api/snapshot.mjs.map +1 -1
  359. package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_/translations.mjs +15 -14
  360. package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_/translations.mjs.map +1 -1
  361. package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_.mjs +15 -14
  362. package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_.mjs.map +1 -1
  363. package/dist/astro/routes/api/taxonomies/_name_/terms/index.mjs +15 -14
  364. package/dist/astro/routes/api/taxonomies/_name_/terms/index.mjs.map +1 -1
  365. package/dist/astro/routes/api/taxonomies/index.mjs +15 -14
  366. package/dist/astro/routes/api/taxonomies/index.mjs.map +1 -1
  367. package/dist/astro/routes/api/themes/preview.mjs +6 -6
  368. package/dist/astro/routes/api/typegen.mjs +6 -6
  369. package/dist/astro/routes/api/well-known/auth.mjs +1 -1
  370. package/dist/astro/routes/api/well-known/oauth-authorization-server.d.mts.map +1 -1
  371. package/dist/astro/routes/api/well-known/oauth-authorization-server.mjs +4 -3
  372. package/dist/astro/routes/api/well-known/oauth-authorization-server.mjs.map +1 -1
  373. package/dist/astro/routes/api/well-known/oauth-protected-resource.d.mts.map +1 -1
  374. package/dist/astro/routes/api/well-known/oauth-protected-resource.mjs +4 -3
  375. package/dist/astro/routes/api/well-known/oauth-protected-resource.mjs.map +1 -1
  376. package/dist/astro/routes/api/widget-areas/_name_/reorder.mjs +9 -8
  377. package/dist/astro/routes/api/widget-areas/_name_/reorder.mjs.map +1 -1
  378. package/dist/astro/routes/api/widget-areas/_name_/widgets/_id_.mjs +12 -11
  379. package/dist/astro/routes/api/widget-areas/_name_/widgets/_id_.mjs.map +1 -1
  380. package/dist/astro/routes/api/widget-areas/_name_/widgets.mjs +12 -11
  381. package/dist/astro/routes/api/widget-areas/_name_/widgets.mjs.map +1 -1
  382. package/dist/astro/routes/api/widget-areas/_name_.mjs +7 -7
  383. package/dist/astro/routes/api/widget-areas/index.mjs +12 -11
  384. package/dist/astro/routes/api/widget-areas/index.mjs.map +1 -1
  385. package/dist/astro/routes/api/widget-components.mjs +4 -4
  386. package/dist/astro/routes/robots.txt.mjs +7 -7
  387. package/dist/astro/routes/sitemap-_collection_.xml.mjs +11 -11
  388. package/dist/astro/routes/sitemap.xml.mjs +8 -8
  389. package/dist/astro/types.d.mts +38 -17
  390. package/dist/astro/types.d.mts.map +1 -1
  391. package/dist/auth/providers/github.d.mts +1 -1
  392. package/dist/auth/providers/google.d.mts +1 -1
  393. package/dist/{authorize-BmCwQCib.mjs → authorize-6WPZa1xZ.mjs} +7 -4
  394. package/dist/authorize-6WPZa1xZ.mjs.map +1 -0
  395. package/dist/backup-Qr9PaGUo.mjs +241 -0
  396. package/dist/backup-Qr9PaGUo.mjs.map +1 -0
  397. package/dist/{base64-C74Msx8h.mjs → base64-B-PsqheR.mjs} +8 -4
  398. package/dist/base64-B-PsqheR.mjs.map +1 -0
  399. package/dist/{byline-BWb5H-65.mjs → byline-BTOxUlFF.mjs} +6 -6
  400. package/dist/{byline-BWb5H-65.mjs.map → byline-BTOxUlFF.mjs.map} +1 -1
  401. package/dist/{byline-fields-DO6bAYK8.mjs → byline-fields-CdU_LTF1.mjs} +1 -1
  402. package/dist/{byline-fields-DO6bAYK8.mjs.map → byline-fields-CdU_LTF1.mjs.map} +1 -1
  403. package/dist/{bylines-CHojDMpj.mjs → bylines-FyZu6TbJ.mjs} +7 -7
  404. package/dist/{bylines-CHojDMpj.mjs.map → bylines-FyZu6TbJ.mjs.map} +1 -1
  405. package/dist/{bylines-BGuKFaBy.mjs → bylines-oVN0iPwX.mjs} +12 -8
  406. package/dist/bylines-oVN0iPwX.mjs.map +1 -0
  407. package/dist/{cache-BeR7RfN8.mjs → cache-DDwy3JDW.mjs} +2 -2
  408. package/dist/{cache-BeR7RfN8.mjs.map → cache-DDwy3JDW.mjs.map} +1 -1
  409. package/dist/{challenge-store-B426wQ6O.mjs → challenge-store-BFzgFRog.mjs} +1 -1
  410. package/dist/{challenge-store-B426wQ6O.mjs.map → challenge-store-BFzgFRog.mjs.map} +1 -1
  411. package/dist/{chunks-BU5_nrAC.mjs → chunks-Bq-5DPrD.mjs} +2 -2
  412. package/dist/{chunks-BU5_nrAC.mjs.map → chunks-Bq-5DPrD.mjs.map} +1 -1
  413. package/dist/cli/index.mjs +139 -32
  414. package/dist/cli/index.mjs.map +1 -1
  415. package/dist/client/cf-access.d.mts +1 -1
  416. package/dist/client/index.d.mts +54 -3
  417. package/dist/client/index.d.mts.map +1 -1
  418. package/dist/client/index.mjs +16 -4
  419. package/dist/client/index.mjs.map +1 -1
  420. package/dist/{comment-SWh31kS0.mjs → comment-B9cUud8H.mjs} +2 -2
  421. package/dist/{comment-SWh31kS0.mjs.map → comment-B9cUud8H.mjs.map} +1 -1
  422. package/dist/{comment-reaction-DgcpziXI.mjs → comment-reaction-VUXO981F.mjs} +2 -2
  423. package/dist/{comment-reaction-DgcpziXI.mjs.map → comment-reaction-VUXO981F.mjs.map} +1 -1
  424. package/dist/{comments-kZYGppMS.mjs → comments-PXj1E9Si.mjs} +3 -3
  425. package/dist/{comments-kZYGppMS.mjs.map → comments-PXj1E9Si.mjs.map} +1 -1
  426. package/dist/{components-CliOkZAs.mjs → components-DZkL4Fx0.mjs} +1 -1
  427. package/dist/{components-CliOkZAs.mjs.map → components-DZkL4Fx0.mjs.map} +1 -1
  428. package/dist/{config-CVssduLe.mjs → config-B6b_BobR.mjs} +6 -2
  429. package/dist/config-B6b_BobR.mjs.map +1 -0
  430. package/dist/{content-BO61Sx4j.mjs → content-BC43pICM.mjs} +53 -19
  431. package/dist/content-BC43pICM.mjs.map +1 -0
  432. package/dist/{content-refresh-BkkApzeS.mjs → content-refresh-CPMSauD3.mjs} +96 -4
  433. package/dist/content-refresh-CPMSauD3.mjs.map +1 -0
  434. package/dist/{context-DtSFYFuS.mjs → context-DOurRIrb.mjs} +97 -74
  435. package/dist/context-DOurRIrb.mjs.map +1 -0
  436. package/dist/{cron-YFJ7uNVA.mjs → cron-BlKIMD_e.mjs} +1 -1
  437. package/dist/{cron-YFJ7uNVA.mjs.map → cron-BlKIMD_e.mjs.map} +1 -1
  438. package/dist/{dashboard-xo_gPs_D.mjs → dashboard-CBm4zhc3.mjs} +4 -4
  439. package/dist/{dashboard-xo_gPs_D.mjs.map → dashboard-CBm4zhc3.mjs.map} +1 -1
  440. package/dist/database/pg-migration-lock.d.mts.map +1 -1
  441. package/dist/database/pg-migration-lock.mjs +1 -4
  442. package/dist/database/pg-migration-lock.mjs.map +1 -1
  443. package/dist/db/index.d.mts +3 -3
  444. package/dist/db/index.mjs +2 -2
  445. package/dist/db/index.mjs.map +1 -1
  446. package/dist/db/libsql.d.mts +1 -1
  447. package/dist/db/postgres.d.mts +1 -1
  448. package/dist/db/sqlite.d.mts +1 -1
  449. package/dist/{db-errors-BKuXh_fi.mjs → db-errors-CcWLaRiR.mjs} +4 -2
  450. package/dist/db-errors-CcWLaRiR.mjs.map +1 -0
  451. package/dist/{default-DY5ovGUG.mjs → default-C4v9KP56.mjs} +1 -1
  452. package/dist/{default-DY5ovGUG.mjs.map → default-C4v9KP56.mjs.map} +1 -1
  453. package/dist/{device-flow-CPXQ_QfW.mjs → device-flow-BeA6lUS1.mjs} +5 -6
  454. package/dist/device-flow-BeA6lUS1.mjs.map +1 -0
  455. package/dist/{dialect-helpers-Cue7QQOR.mjs → dialect-helpers-BtOwo2us.mjs} +60 -14
  456. package/dist/dialect-helpers-BtOwo2us.mjs.map +1 -0
  457. package/dist/{email-console-CjkQc7oY.mjs → email-console-C-9Ng8DM.mjs} +1 -1
  458. package/dist/{email-console-CjkQc7oY.mjs.map → email-console-C-9Ng8DM.mjs.map} +1 -1
  459. package/dist/error-DJ98TRbQ.mjs +90 -0
  460. package/dist/error-DJ98TRbQ.mjs.map +1 -0
  461. package/dist/{error-CfJMLSkd.mjs → errors-DtEXIQQV.mjs} +15 -84
  462. package/dist/errors-DtEXIQQV.mjs.map +1 -0
  463. package/dist/{escape-r8_GbEU2.mjs → escape-CFedIB1C.mjs} +1 -1
  464. package/dist/{escape-r8_GbEU2.mjs.map → escape-CFedIB1C.mjs.map} +1 -1
  465. package/dist/{field-defs-cache-BVrNCgSj.mjs → field-defs-cache-KfNJ_qLQ.mjs} +2 -2
  466. package/dist/{field-defs-cache-BVrNCgSj.mjs.map → field-defs-cache-KfNJ_qLQ.mjs.map} +1 -1
  467. package/dist/{fts-manager-BD9s77qh.mjs → fts-manager-hyCU9OOp.mjs} +3 -3
  468. package/dist/{fts-manager-BD9s77qh.mjs.map → fts-manager-hyCU9OOp.mjs.map} +1 -1
  469. package/dist/{hreflang-CgIxhH4k.d.mts → hreflang-CIxH_LKz.d.mts} +2 -2
  470. package/dist/{hreflang-CgIxhH4k.d.mts.map → hreflang-CIxH_LKz.d.mts.map} +1 -1
  471. package/dist/{hreflang-pAWUiPd_.mjs → hreflang-CbYeCzl9.mjs} +7 -7
  472. package/dist/{hreflang-pAWUiPd_.mjs.map → hreflang-CbYeCzl9.mjs.map} +1 -1
  473. package/dist/{import-2jHtLzsO.mjs → import-oDYCgNYQ.mjs} +4 -4
  474. package/dist/{import-2jHtLzsO.mjs.map → import-oDYCgNYQ.mjs.map} +1 -1
  475. package/dist/{index-DxjWLKGT.d.mts → index-BEui-cRd.d.mts} +3 -3
  476. package/dist/{index-DxjWLKGT.d.mts.map → index-BEui-cRd.d.mts.map} +1 -1
  477. package/dist/{index-BXOCyLj0.d.mts → index-BcEH_FfS.d.mts} +812 -16
  478. package/dist/index-BcEH_FfS.d.mts.map +1 -0
  479. package/dist/index.d.mts +18 -19
  480. package/dist/index.mjs +61 -60
  481. package/dist/{load-DgoWMdRX.mjs → load-Dg5gtWma.mjs} +2 -2
  482. package/dist/{load-DgoWMdRX.mjs.map → load-Dg5gtWma.mjs.map} +1 -1
  483. package/dist/{loader-Rb8QlGZp.mjs → loader-D4rigvjR.mjs} +170 -6
  484. package/dist/loader-D4rigvjR.mjs.map +1 -0
  485. package/dist/{manifest-schema-DeGNma2O.mjs → manifest-schema-bCq54i7F.mjs} +16 -2
  486. package/dist/manifest-schema-bCq54i7F.mjs.map +1 -0
  487. package/dist/media/image-endpoint.d.mts +30 -2
  488. package/dist/media/image-endpoint.d.mts.map +1 -1
  489. package/dist/media/image-endpoint.mjs +29 -3
  490. package/dist/media/image-endpoint.mjs.map +1 -1
  491. package/dist/media/index.d.mts +1 -1
  492. package/dist/media/local-runtime.d.mts +12 -13
  493. package/dist/media/local-runtime.d.mts.map +1 -1
  494. package/dist/media/local-runtime.mjs +6 -6
  495. package/dist/media-BJ6SRY3g.mjs +247 -0
  496. package/dist/media-BJ6SRY3g.mjs.map +1 -0
  497. package/dist/{media-allowlist-Dc05vKtt.mjs → media-allowlist-jUppPWFy.mjs} +1 -1
  498. package/dist/{media-allowlist-Dc05vKtt.mjs.map → media-allowlist-jUppPWFy.mjs.map} +1 -1
  499. package/dist/{media-D2ZFowpn.mjs → media-its1WLYv.mjs} +2 -2
  500. package/dist/{media-D2ZFowpn.mjs.map → media-its1WLYv.mjs.map} +1 -1
  501. package/dist/media-upload-DNu3QySc.mjs +145 -0
  502. package/dist/media-upload-DNu3QySc.mjs.map +1 -0
  503. package/dist/{media-url-DgIEYZr4.mjs → media-url-BCm5vBn6.mjs} +1 -1
  504. package/dist/{media-url-DgIEYZr4.mjs.map → media-url-BCm5vBn6.mjs.map} +1 -1
  505. package/dist/{media-usage-B__v9NMm.mjs → media-usage-DPQ3K4xB.mjs} +138 -5
  506. package/dist/{media-usage-B__v9NMm.mjs.map → media-usage-DPQ3K4xB.mjs.map} +1 -1
  507. package/dist/{menus-BpfevlJD.mjs → menus-BMGzWyWH.mjs} +15 -8
  508. package/dist/menus-BMGzWyWH.mjs.map +1 -0
  509. package/dist/{menus-BtvH7Z7t.mjs → menus-CPf_SW7u.mjs} +234 -13
  510. package/dist/menus-CPf_SW7u.mjs.map +1 -0
  511. package/dist/{mode-BVnhGZ2o.mjs → mode-fiXRMfeA.mjs} +1 -1
  512. package/dist/{mode-BVnhGZ2o.mjs.map → mode-fiXRMfeA.mjs.map} +1 -1
  513. package/dist/{oauth-authorization-BWqWTHBK.mjs → oauth-authorization-oqfbBuMH.mjs} +5 -6
  514. package/dist/oauth-authorization-oqfbBuMH.mjs.map +1 -0
  515. package/dist/{oauth-clients-43_XADoa.mjs → oauth-clients-BlrUHAsf.mjs} +1 -1
  516. package/dist/{oauth-clients-43_XADoa.mjs.map → oauth-clients-BlrUHAsf.mjs.map} +1 -1
  517. package/dist/{oauth-state-store-BRSUEkmx.mjs → oauth-state-store-DnvjRMy6.mjs} +2 -1
  518. package/dist/{oauth-state-store-BRSUEkmx.mjs.map → oauth-state-store-DnvjRMy6.mjs.map} +1 -1
  519. package/dist/{oauth-user-lookup-Ctgemb0k.mjs → oauth-user-lookup-oUllxvAv.mjs} +1 -1
  520. package/dist/{oauth-user-lookup-Ctgemb0k.mjs.map → oauth-user-lookup-oUllxvAv.mjs.map} +1 -1
  521. package/dist/object-cache/memory.d.mts +1 -1
  522. package/dist/{options-COXGTtqd.d.mts → options-BqMkWfYa.d.mts} +6 -6
  523. package/dist/{options-COXGTtqd.d.mts.map → options-BqMkWfYa.d.mts.map} +1 -1
  524. package/dist/page/index.d.mts +2 -2
  525. package/dist/page/index.d.mts.map +1 -1
  526. package/dist/page/index.mjs.map +1 -1
  527. package/dist/{parse-GLksnn-B.mjs → parse-53zyxlpv.mjs} +4 -12
  528. package/dist/{parse-GLksnn-B.mjs.map → parse-53zyxlpv.mjs.map} +1 -1
  529. package/dist/{passkey-config-CjA1UbDj.mjs → passkey-config-C-SKpc0-.mjs} +1 -1
  530. package/dist/{passkey-config-CjA1UbDj.mjs.map → passkey-config-C-SKpc0-.mjs.map} +1 -1
  531. package/dist/{placeholder-DR-eeZr-.d.mts → placeholder-Dop47JMM.d.mts} +1 -1
  532. package/dist/{placeholder-DR-eeZr-.d.mts.map → placeholder-Dop47JMM.d.mts.map} +1 -1
  533. package/dist/plugin-types.d.mts +21 -2
  534. package/dist/plugin-types.d.mts.map +1 -1
  535. package/dist/plugin-utils.d.mts +18 -17
  536. package/dist/plugin-utils.d.mts.map +1 -1
  537. package/dist/plugin-utils.mjs +8 -6
  538. package/dist/plugin-utils.mjs.map +1 -1
  539. package/dist/plugins/adapt-sandbox-entry.d.mts +10 -11
  540. package/dist/plugins/adapt-sandbox-entry.d.mts.map +1 -1
  541. package/dist/plugins/adapt-sandbox-entry.mjs +15 -3
  542. package/dist/plugins/adapt-sandbox-entry.mjs.map +1 -1
  543. package/dist/{portable-text-BAkgEKcv.mjs → portable-text-sDj92Kxv.mjs} +1 -1
  544. package/dist/{portable-text-BAkgEKcv.mjs.map → portable-text-sDj92Kxv.mjs.map} +1 -1
  545. package/dist/{preview-Rloa09Wp.mjs → preview-D4Jnbfx7.mjs} +2 -2
  546. package/dist/{preview-Rloa09Wp.mjs.map → preview-D4Jnbfx7.mjs.map} +1 -1
  547. package/dist/{public-url-C0cEvrRu.mjs → public-url-DSGTnJFw.mjs} +5 -3
  548. package/dist/public-url-DSGTnJFw.mjs.map +1 -0
  549. package/dist/{query-ZzvXyxWq.mjs → query-BbJQ-dGg.mjs} +15 -15
  550. package/dist/{query-ZzvXyxWq.mjs.map → query-BbJQ-dGg.mjs.map} +1 -1
  551. package/dist/{query-BxT95opY.mjs → query-DdFGHzQF.mjs} +3 -3
  552. package/dist/{query-BxT95opY.mjs.map → query-DdFGHzQF.mjs.map} +1 -1
  553. package/dist/{rate-limit-Cg4Rvc_-.mjs → rate-limit-D3IEiUi2.mjs} +2 -2
  554. package/dist/{rate-limit-Cg4Rvc_-.mjs.map → rate-limit-D3IEiUi2.mjs.map} +1 -1
  555. package/dist/{redirect-Ch3E98qZ.mjs → redirect-BoUac4NT.mjs} +10 -4
  556. package/dist/redirect-BoUac4NT.mjs.map +1 -0
  557. package/dist/{redirect-Ce_6Yb6z.mjs → redirect-Botom7X6.mjs} +1 -1
  558. package/dist/{redirect-Ce_6Yb6z.mjs.map → redirect-Botom7X6.mjs.map} +1 -1
  559. package/dist/{redirects-CXmVGRNZ.mjs → redirects-ChbpqKiS.mjs} +4 -4
  560. package/dist/{redirects-CXmVGRNZ.mjs.map → redirects-ChbpqKiS.mjs.map} +1 -1
  561. package/dist/{redirects-CeD7K7EX.mjs → redirects-D457qwt0.mjs} +10 -181
  562. package/dist/redirects-D457qwt0.mjs.map +1 -0
  563. package/dist/{registry-CyIXPi4E.mjs → registry-y21kjhfG.mjs} +97 -8
  564. package/dist/registry-y21kjhfG.mjs.map +1 -0
  565. package/dist/{relation-Ba68Tm4Z.mjs → relation-Du0r04E0.mjs} +3 -3
  566. package/dist/{relation-Ba68Tm4Z.mjs.map → relation-Du0r04E0.mjs.map} +1 -1
  567. package/dist/{relations-CbBpoOys.d.mts → relations-BKybBoOX.d.mts} +315 -9
  568. package/dist/relations-BKybBoOX.d.mts.map +1 -0
  569. package/dist/{relations-BmBmX4Eb.mjs → relations-CZMpBqEd.mjs} +3 -3
  570. package/dist/{relations-BmBmX4Eb.mjs.map → relations-CZMpBqEd.mjs.map} +1 -1
  571. package/dist/{relations-C8hVyEy0.mjs → relations-DtX1UMBH.mjs} +13 -7
  572. package/dist/relations-DtX1UMBH.mjs.map +1 -0
  573. package/dist/{request-meta-DCwktC5P.mjs → request-meta-DzXYYI-n.mjs} +2 -2
  574. package/dist/{request-meta-DCwktC5P.mjs.map → request-meta-DzXYYI-n.mjs.map} +1 -1
  575. package/dist/{resolve-Cd9dzclN.mjs → resolve-DFr4kq72.mjs} +2 -2
  576. package/dist/{resolve-Cd9dzclN.mjs.map → resolve-DFr4kq72.mjs.map} +1 -1
  577. package/dist/{runner-jt65bF7F.mjs → runner-BdeLEgad.mjs} +334 -200
  578. package/dist/runner-BdeLEgad.mjs.map +1 -0
  579. package/dist/{runner-CiNdIk3y.d.mts → runner-Dd8m8k9F.d.mts} +2 -2
  580. package/dist/{runner-CiNdIk3y.d.mts.map → runner-Dd8m8k9F.d.mts.map} +1 -1
  581. package/dist/runtime.d.mts +11 -12
  582. package/dist/runtime.d.mts.map +1 -1
  583. package/dist/runtime.mjs +4 -4
  584. package/dist/{schema-DwjufZ1S.mjs → schema-BH8P8vaC.mjs} +3 -3
  585. package/dist/{schema-DwjufZ1S.mjs.map → schema-BH8P8vaC.mjs.map} +1 -1
  586. package/dist/scopes-DTIkIaGA.mjs +27 -0
  587. package/dist/scopes-DTIkIaGA.mjs.map +1 -0
  588. package/dist/{search-Cl875CVE.mjs → search-D-Yhpmvs.mjs} +8 -7
  589. package/dist/search-D-Yhpmvs.mjs.map +1 -0
  590. package/dist/{secrets-CO_bEmII.mjs → secrets-CQ-69kF9.mjs} +25 -19
  591. package/dist/secrets-CQ-69kF9.mjs.map +1 -0
  592. package/dist/{sections-DTKzgoiS.mjs → sections-CzVBAKjw.mjs} +3 -3
  593. package/dist/{sections-DTKzgoiS.mjs.map → sections-CzVBAKjw.mjs.map} +1 -1
  594. package/dist/seed/index.d.mts +2 -2
  595. package/dist/seed/index.mjs +20 -20
  596. package/dist/seo/index.d.mts +14 -3
  597. package/dist/seo/index.d.mts.map +1 -1
  598. package/dist/seo/index.mjs +17 -17
  599. package/dist/seo/index.mjs.map +1 -1
  600. package/dist/{seo-BjrbXAd_.mjs → seo-C3GDfT0V.mjs} +1 -1
  601. package/dist/{seo-BjrbXAd_.mjs.map → seo-C3GDfT0V.mjs.map} +1 -1
  602. package/dist/{seo-BLm6SXzS.mjs → seo-kJzVAmmu.mjs} +2 -2
  603. package/dist/{seo-BLm6SXzS.mjs.map → seo-kJzVAmmu.mjs.map} +1 -1
  604. package/dist/{service-D6zDmKXy.mjs → service-CQnc276a.mjs} +3 -3
  605. package/dist/{service-D6zDmKXy.mjs.map → service-CQnc276a.mjs.map} +1 -1
  606. package/dist/{session-user-DoSs6YM8.mjs → session-user-DbHqKDKe.mjs} +1 -1
  607. package/dist/{session-user-DoSs6YM8.mjs.map → session-user-DbHqKDKe.mjs.map} +1 -1
  608. package/dist/{settings-BuQYvLfy.mjs → settings-C2PaBS49.mjs} +4 -4
  609. package/dist/{settings-BuQYvLfy.mjs.map → settings-C2PaBS49.mjs.map} +1 -1
  610. package/dist/{settings-CmS3TwXf.mjs → settings-Dtc0DU31.mjs} +3 -3
  611. package/dist/{settings-CmS3TwXf.mjs.map → settings-Dtc0DU31.mjs.map} +1 -1
  612. package/dist/{setup-complete-BPNgLHlU.mjs → setup-complete-CdIlqloh.mjs} +1 -1
  613. package/dist/{setup-complete-BPNgLHlU.mjs.map → setup-complete-CdIlqloh.mjs.map} +1 -1
  614. package/dist/{setup-nonce-DEPZX96T.mjs → setup-nonce-DqiIPr-J.mjs} +1 -1
  615. package/dist/{setup-nonce-DEPZX96T.mjs.map → setup-nonce-DqiIPr-J.mjs.map} +1 -1
  616. package/dist/{single-flight-cache-DEtW-OEG.mjs → single-flight-cache-C2exrGAi.mjs} +1 -1
  617. package/dist/{single-flight-cache-DEtW-OEG.mjs.map → single-flight-cache-C2exrGAi.mjs.map} +1 -1
  618. package/dist/{site-url-CcLy5D5s.mjs → site-url-NGJT6NTU.mjs} +1 -1
  619. package/dist/{site-url-CcLy5D5s.mjs.map → site-url-NGJT6NTU.mjs.map} +1 -1
  620. package/dist/snapshot-BdpUJKD-.mjs +216 -0
  621. package/dist/snapshot-BdpUJKD-.mjs.map +1 -0
  622. package/dist/{ssrf-TrKYJAy0.mjs → ssrf-CviKqWmq.mjs} +1 -1
  623. package/dist/{ssrf-TrKYJAy0.mjs.map → ssrf-CviKqWmq.mjs.map} +1 -1
  624. package/dist/state-xxv6ZTMv.mjs +128 -0
  625. package/dist/state-xxv6ZTMv.mjs.map +1 -0
  626. package/dist/{status-D3Gy1Zc6.mjs → status-COfycGIU.mjs} +1 -1
  627. package/dist/{status-D3Gy1Zc6.mjs.map → status-COfycGIU.mjs.map} +1 -1
  628. package/dist/storage/local.d.mts +1 -1
  629. package/dist/storage/local.mjs +1 -1
  630. package/dist/storage/s3.d.mts +1 -1
  631. package/dist/storage/s3.mjs +1 -1
  632. package/dist/{taxonomies-pUkuD6nj.mjs → taxonomies-HI9fnTdp.mjs} +8 -8
  633. package/dist/{taxonomies-pUkuD6nj.mjs.map → taxonomies-HI9fnTdp.mjs.map} +1 -1
  634. package/dist/{taxonomies-ClS4RKaZ.mjs → taxonomies-rMeBzOjX.mjs} +26 -17
  635. package/dist/taxonomies-rMeBzOjX.mjs.map +1 -0
  636. package/dist/{taxonomy-BkxbUMSw.mjs → taxonomy-0mCI25HN.mjs} +51 -13
  637. package/dist/taxonomy-0mCI25HN.mjs.map +1 -0
  638. package/dist/{tokens-BV6fgl5A.mjs → tokens-DVltpO2D.mjs} +2 -2
  639. package/dist/{tokens-BV6fgl5A.mjs.map → tokens-DVltpO2D.mjs.map} +1 -1
  640. package/dist/{transport-DTFhhPOg.mjs → transport-CKrlqSpD.mjs} +1 -1
  641. package/dist/{transport-DTFhhPOg.mjs.map → transport-CKrlqSpD.mjs.map} +1 -1
  642. package/dist/{transport-DmlmzD2U.d.mts → transport-Vd7VdqHv.d.mts} +1 -1
  643. package/dist/{transport-DmlmzD2U.d.mts.map → transport-Vd7VdqHv.d.mts.map} +1 -1
  644. package/dist/{trusted-proxy-CSgZVESw.mjs → trusted-proxy-CwjQj0YG.mjs} +1 -1
  645. package/dist/{trusted-proxy-CSgZVESw.mjs.map → trusted-proxy-CwjQj0YG.mjs.map} +1 -1
  646. package/dist/{types-B6-N9cBB.d.mts → types-B4vm81VH.d.mts} +1 -1
  647. package/dist/{types-B6-N9cBB.d.mts.map → types-B4vm81VH.d.mts.map} +1 -1
  648. package/dist/{types-Cm4Cz-8M.d.mts → types-B97jg3aW.d.mts} +6 -1
  649. package/dist/{types-Cm4Cz-8M.d.mts.map → types-B97jg3aW.d.mts.map} +1 -1
  650. package/dist/{types-BNZsPL9z.mjs → types-BD40g7zz.mjs} +1 -1
  651. package/dist/{types-BNZsPL9z.mjs.map → types-BD40g7zz.mjs.map} +1 -1
  652. package/dist/{types-QnlQIyPE.d.mts → types-BNfPHfay.d.mts} +1 -1
  653. package/dist/{types-QnlQIyPE.d.mts.map → types-BNfPHfay.d.mts.map} +1 -1
  654. package/dist/{types-DLIrNtv5.d.mts → types-BfYUPJdP.d.mts} +2 -2
  655. package/dist/{types-DLIrNtv5.d.mts.map → types-BfYUPJdP.d.mts.map} +1 -1
  656. package/dist/{types-CtDVagM4.d.mts → types-BvB7gDOD.d.mts} +38 -4
  657. package/dist/types-BvB7gDOD.d.mts.map +1 -0
  658. package/dist/{types-B_pmP7Yq.d.mts → types-C7U0HlEr.d.mts} +1 -1
  659. package/dist/{types-B_pmP7Yq.d.mts.map → types-C7U0HlEr.d.mts.map} +1 -1
  660. package/dist/{types-Ch8pFMEm.mjs → types-CrRUFdej.mjs} +3 -3
  661. package/dist/{types-Ch8pFMEm.mjs.map → types-CrRUFdej.mjs.map} +1 -1
  662. package/dist/{types-momGysZk.d.mts → types-DPKhI5ib.d.mts} +9 -1
  663. package/dist/types-DPKhI5ib.d.mts.map +1 -0
  664. package/dist/{types-BCVuUPrL.d.mts → types-Kmaxdarz.d.mts} +1 -1
  665. package/dist/{types-BCVuUPrL.d.mts.map → types-Kmaxdarz.d.mts.map} +1 -1
  666. package/dist/{types-qljd1hsL.d.mts → types-iVeZ5g6N.d.mts} +1 -1
  667. package/dist/{types-qljd1hsL.d.mts.map → types-iVeZ5g6N.d.mts.map} +1 -1
  668. package/dist/{user-DTxX_Fha.mjs → user-aTXqmXBz.mjs} +3 -3
  669. package/dist/{user-DTxX_Fha.mjs.map → user-aTXqmXBz.mjs.map} +1 -1
  670. package/dist/{utils-Cz8PVrl4.mjs → utils-BbUgmeZG.mjs} +1 -1
  671. package/dist/{utils-Cz8PVrl4.mjs.map → utils-BbUgmeZG.mjs.map} +1 -1
  672. package/dist/{validate-C3CpWlNt.mjs → validate-CDT1jl6_.mjs} +11 -6
  673. package/dist/validate-CDT1jl6_.mjs.map +1 -0
  674. package/dist/{validate-9jLuE301.d.mts → validate-DULfgpJP.d.mts} +5 -5
  675. package/dist/{validate-9jLuE301.d.mts.map → validate-DULfgpJP.d.mts.map} +1 -1
  676. package/dist/{validation-DM2K_NJC.mjs → validation-DlD0E35W.mjs} +10 -10
  677. package/dist/{validation-DM2K_NJC.mjs.map → validation-DlD0E35W.mjs.map} +1 -1
  678. package/dist/version-Ci6bw6YK.mjs +7 -0
  679. package/dist/{version-BlIJvNAZ.mjs.map → version-Ci6bw6YK.mjs.map} +1 -1
  680. package/dist/{widgets-B_X6_UXJ.mjs → widgets-5fipNkMT.mjs} +3 -3
  681. package/dist/{widgets-B_X6_UXJ.mjs.map → widgets-5fipNkMT.mjs.map} +1 -1
  682. package/dist/{wxr-taxonomies-tADW4KTa.d.mts → wxr-taxonomies-B4tMuN5T.d.mts} +1 -1
  683. package/dist/{wxr-taxonomies-tADW4KTa.d.mts.map → wxr-taxonomies-B4tMuN5T.d.mts.map} +1 -1
  684. package/dist/{wxr-taxonomies-oNJB2S81.mjs → wxr-taxonomies-BmUnBNgz.mjs} +4 -4
  685. package/dist/{wxr-taxonomies-oNJB2S81.mjs.map → wxr-taxonomies-BmUnBNgz.mjs.map} +1 -1
  686. package/dist/{zod-generator-CrfV79De.mjs → zod-generator-CwkHWz4f.mjs} +2 -2
  687. package/dist/{zod-generator-CrfV79De.mjs.map → zod-generator-CwkHWz4f.mjs.map} +1 -1
  688. package/package.json +8 -8
  689. package/src/api/authorize.ts +10 -1
  690. package/src/api/error.ts +5 -5
  691. package/src/api/errors.ts +14 -0
  692. package/src/api/handlers/backup.ts +312 -0
  693. package/src/api/handlers/bylines.ts +5 -4
  694. package/src/api/handlers/content.ts +61 -9
  695. package/src/api/handlers/device-flow.ts +2 -3
  696. package/src/api/handlers/index.ts +16 -0
  697. package/src/api/handlers/marketplace.ts +38 -0
  698. package/src/api/handlers/media-upload.ts +210 -0
  699. package/src/api/handlers/media-usage.ts +211 -2
  700. package/src/api/handlers/menus.ts +11 -6
  701. package/src/api/handlers/oauth-authorization.ts +2 -6
  702. package/src/api/handlers/plugin-settings.ts +218 -0
  703. package/src/api/handlers/plugins.ts +41 -0
  704. package/src/api/handlers/registry.ts +39 -0
  705. package/src/api/handlers/relations.ts +7 -2
  706. package/src/api/handlers/snapshot.ts +21 -3
  707. package/src/api/handlers/taxonomies.ts +22 -14
  708. package/src/api/openapi/document.ts +48 -6
  709. package/src/api/parse.ts +1 -15
  710. package/src/api/public-url.ts +4 -2
  711. package/src/api/schemas/bylines.ts +4 -4
  712. package/src/api/schemas/common.ts +13 -8
  713. package/src/api/schemas/media-usage.ts +72 -0
  714. package/src/api/schemas/media.ts +32 -1
  715. package/src/api/schemas/menus.ts +2 -1
  716. package/src/api/schemas/relations.ts +3 -1
  717. package/src/api/schemas/taxonomies.ts +4 -2
  718. package/src/astro/integration/index.ts +38 -0
  719. package/src/astro/integration/routes.ts +35 -0
  720. package/src/astro/integration/runtime.ts +6 -0
  721. package/src/astro/integration/virtual-modules.ts +41 -7
  722. package/src/astro/integration/vite-config.ts +17 -1
  723. package/src/astro/middleware/auth.ts +70 -78
  724. package/src/astro/middleware/csp.ts +5 -2
  725. package/src/astro/middleware.ts +86 -31
  726. package/src/astro/public-plugin-api-routes.ts +2 -1
  727. package/src/astro/routes/PluginRegistry.tsx +5 -2
  728. package/src/astro/routes/admin.astro +56 -16
  729. package/src/astro/routes/api/admin/api-tokens/index.ts +2 -2
  730. package/src/astro/routes/api/admin/bylines/[id]/translations.ts +2 -5
  731. package/src/astro/routes/api/admin/bylines/index.ts +5 -8
  732. package/src/astro/routes/api/admin/plugins/[id]/index.ts +6 -0
  733. package/src/astro/routes/api/admin/plugins/[id]/mcp.ts +42 -0
  734. package/src/astro/routes/api/admin/plugins/[id]/settings.ts +80 -0
  735. package/src/astro/routes/api/admin/plugins/[id]/update.ts +2 -0
  736. package/src/astro/routes/api/admin/plugins/index.ts +9 -0
  737. package/src/astro/routes/api/admin/plugins/marketplace/[id]/install.ts +2 -0
  738. package/src/astro/routes/api/admin/plugins/registry/[id]/update.ts +2 -0
  739. package/src/astro/routes/api/admin/plugins/registry/install.ts +2 -0
  740. package/src/astro/routes/api/admin/plugins/updates.ts +2 -4
  741. package/src/astro/routes/api/auth/mode.ts +6 -14
  742. package/src/astro/routes/api/auth/oauth/[provider]/callback.ts +21 -4
  743. package/src/astro/routes/api/auth/oauth/[provider].ts +24 -6
  744. package/src/astro/routes/api/content/[collection]/[id]/compare.ts +3 -4
  745. package/src/astro/routes/api/content/[collection]/[id]/duplicate.ts +2 -3
  746. package/src/astro/routes/api/content/[collection]/[id]/permanent.ts +2 -3
  747. package/src/astro/routes/api/content/[collection]/[id]/preview-url.ts +3 -4
  748. package/src/astro/routes/api/content/[collection]/[id]/references/[relation]/children.ts +4 -6
  749. package/src/astro/routes/api/content/[collection]/[id]/references/[relation]/parents.ts +2 -3
  750. package/src/astro/routes/api/content/[collection]/[id]/revisions.ts +3 -4
  751. package/src/astro/routes/api/content/[collection]/[id]/terms/[taxonomy].ts +4 -6
  752. package/src/astro/routes/api/content/[collection]/[id]/translations.ts +3 -4
  753. package/src/astro/routes/api/content/[collection]/[id].ts +3 -4
  754. package/src/astro/routes/api/content/[collection]/authors.ts +2 -3
  755. package/src/astro/routes/api/content/[collection]/index.ts +6 -8
  756. package/src/astro/routes/api/content/[collection]/trash.ts +2 -3
  757. package/src/astro/routes/api/manifest.ts +2 -9
  758. package/src/astro/routes/api/mcp.ts +2 -1
  759. package/src/astro/routes/api/media/[id]/usage.ts +30 -0
  760. package/src/astro/routes/api/media/[id].ts +17 -6
  761. package/src/astro/routes/api/media/file/[...key].ts +8 -0
  762. package/src/astro/routes/api/media.ts +21 -2
  763. package/src/astro/routes/api/oauth/authorize.ts +43 -15
  764. package/src/astro/routes/api/plugins/[pluginId]/[...path].ts +17 -3
  765. package/src/astro/routes/api/settings/backups/archives/[name].ts +78 -0
  766. package/src/astro/routes/api/settings/backups/archives/index.ts +33 -0
  767. package/src/astro/routes/api/settings/backups/export.ts +43 -0
  768. package/src/astro/routes/api/settings/backups/index.ts +76 -0
  769. package/src/astro/routes/api/setup/admin-verify.ts +8 -4
  770. package/src/astro/routes/api/setup/admin.ts +11 -4
  771. package/src/astro/routes/api/well-known/oauth-authorization-server.ts +4 -1
  772. package/src/astro/routes/api/well-known/oauth-protected-resource.ts +5 -1
  773. package/src/astro/types.ts +48 -2
  774. package/src/auth/api-tokens.ts +1 -0
  775. package/src/auth/oauth-state-store.ts +3 -0
  776. package/src/auth/providers/github-admin.tsx +5 -6
  777. package/src/auth/providers/google-admin.tsx +5 -6
  778. package/src/auth/scopes.ts +3 -9
  779. package/src/cli/client-factory.ts +0 -1
  780. package/src/cli/commands/bundle-utils.ts +50 -1
  781. package/src/cli/commands/bundle.ts +9 -2
  782. package/src/cli/commands/media.ts +127 -0
  783. package/src/client/index.ts +84 -2
  784. package/src/client/transport.ts +1 -1
  785. package/src/components/EmDashHead.astro +4 -8
  786. package/src/components/Gallery.astro +141 -26
  787. package/src/components/InlinePortableTextEditor.tsx +56 -35
  788. package/src/components/marks/Link.astro +5 -1
  789. package/src/config/secrets.ts +25 -19
  790. package/src/content/converters/gallery.ts +61 -0
  791. package/src/content/converters/portable-text-to-prosemirror.ts +19 -0
  792. package/src/content/converters/prosemirror-to-portable-text.ts +18 -0
  793. package/src/content/converters/types.ts +36 -0
  794. package/src/database/dialect-helpers.ts +80 -7
  795. package/src/database/migrations/051_content_taxonomies_denorm.ts +120 -0
  796. package/src/database/migrations/052_media_usage_read_index.ts +26 -0
  797. package/src/database/migrations/053_plugin_mcp_tools.ts +21 -0
  798. package/src/database/migrations/runner.ts +6 -0
  799. package/src/database/pg-migration-lock.ts +1 -4
  800. package/src/database/repositories/audit.ts +2 -1
  801. package/src/database/repositories/content.ts +98 -16
  802. package/src/database/repositories/media-usage.ts +250 -1
  803. package/src/database/repositories/plugin-storage.ts +29 -32
  804. package/src/database/repositories/redirect.ts +14 -2
  805. package/src/database/repositories/taxonomy.ts +57 -8
  806. package/src/database/types.ts +23 -0
  807. package/src/db/adapters.ts +9 -0
  808. package/src/emdash-runtime.ts +365 -83
  809. package/src/i18n/config.ts +8 -0
  810. package/src/i18n/repair-locale-casing.ts +51 -0
  811. package/src/loader.ts +292 -1
  812. package/src/mcp/server.ts +222 -5
  813. package/src/media/image-endpoint.ts +38 -2
  814. package/src/page/metadata.ts +27 -0
  815. package/src/plugin-types.ts +19 -0
  816. package/src/plugin-utils.ts +8 -6
  817. package/src/plugins/adapt-sandbox-entry.ts +30 -1
  818. package/src/plugins/context.ts +7 -0
  819. package/src/plugins/define-plugin.ts +16 -0
  820. package/src/plugins/manifest-schema.ts +28 -1
  821. package/src/plugins/routes.ts +27 -1
  822. package/src/plugins/sandbox/runner-options.ts +16 -0
  823. package/src/plugins/sandbox/types.ts +6 -1
  824. package/src/plugins/state.ts +17 -1
  825. package/src/plugins/storage-query.ts +67 -33
  826. package/src/plugins/types.ts +41 -0
  827. package/src/schema/registry.ts +141 -5
  828. package/src/search/query.ts +3 -2
  829. package/src/seed/apply.ts +37 -36
  830. package/src/seed/validate.ts +15 -4
  831. package/src/seo/index.ts +19 -4
  832. package/src/storage/types.ts +6 -0
  833. package/src/utils/base64.ts +7 -2
  834. package/src/utils/db-errors.ts +3 -1
  835. package/src/virtual-modules.d.ts +13 -0
  836. package/src/visual-editing/toolbar.ts +1 -1
  837. package/dist/adapters-DPAkL6QF.d.mts.map +0 -1
  838. package/dist/api-DVbHNApo.mjs.map +0 -1
  839. package/dist/api-tokens-Dk2GrJMY.mjs +0 -3
  840. package/dist/apply-D23iUV4q.mjs.map +0 -1
  841. package/dist/authorize-BmCwQCib.mjs.map +0 -1
  842. package/dist/base64-C74Msx8h.mjs.map +0 -1
  843. package/dist/bylines-BGuKFaBy.mjs.map +0 -1
  844. package/dist/config-CVssduLe.mjs.map +0 -1
  845. package/dist/content-BO61Sx4j.mjs.map +0 -1
  846. package/dist/content-refresh-BkkApzeS.mjs.map +0 -1
  847. package/dist/context-DtSFYFuS.mjs.map +0 -1
  848. package/dist/db-errors-BKuXh_fi.mjs.map +0 -1
  849. package/dist/device-flow-CPXQ_QfW.mjs.map +0 -1
  850. package/dist/dialect-helpers-Cue7QQOR.mjs.map +0 -1
  851. package/dist/error-CfJMLSkd.mjs.map +0 -1
  852. package/dist/index-BXOCyLj0.d.mts.map +0 -1
  853. package/dist/loader-Rb8QlGZp.mjs.map +0 -1
  854. package/dist/manifest-schema-DeGNma2O.mjs.map +0 -1
  855. package/dist/menus-BpfevlJD.mjs.map +0 -1
  856. package/dist/menus-BtvH7Z7t.mjs.map +0 -1
  857. package/dist/oauth-authorization-BWqWTHBK.mjs.map +0 -1
  858. package/dist/public-url-C0cEvrRu.mjs.map +0 -1
  859. package/dist/redirect-Ch3E98qZ.mjs.map +0 -1
  860. package/dist/redirects-CeD7K7EX.mjs.map +0 -1
  861. package/dist/registry-CyIXPi4E.mjs.map +0 -1
  862. package/dist/relations-C8hVyEy0.mjs.map +0 -1
  863. package/dist/relations-CbBpoOys.d.mts.map +0 -1
  864. package/dist/runner-jt65bF7F.mjs.map +0 -1
  865. package/dist/scheduled-publish-DlJHGcuL.d.mts +0 -11
  866. package/dist/scheduled-publish-DlJHGcuL.d.mts.map +0 -1
  867. package/dist/search-Cl875CVE.mjs.map +0 -1
  868. package/dist/secrets-CO_bEmII.mjs.map +0 -1
  869. package/dist/taxonomies-ClS4RKaZ.mjs.map +0 -1
  870. package/dist/taxonomy-BkxbUMSw.mjs.map +0 -1
  871. package/dist/types-CtDVagM4.d.mts.map +0 -1
  872. package/dist/types-momGysZk.d.mts.map +0 -1
  873. package/dist/validate-C3CpWlNt.mjs.map +0 -1
  874. package/dist/version-BlIJvNAZ.mjs +0 -7
  875. /package/dist/{ssrf-B5DOv5E5.mjs → ssrf-BB__xfNM.mjs} +0 -0
  876. /package/dist/{types-DeCZBZxn.mjs → types-CK0LxPUQ.mjs} +0 -0
@@ -1 +1 @@
1
- {"version":3,"file":"redirects-CXmVGRNZ.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
+ {"version":3,"file":"redirects-ChbpqKiS.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,55 +1,7 @@
1
- import { n as isTerminalStatus, t as REDIRECT_RULE_STATUSES } from "./status-D3Gy1Zc6.mjs";
1
+ import { F as cursorPaginationQuery, H as slugPattern, L as httpUrl, R as localeCode, V as roleLevel } from "./media-BJ6SRY3g.mjs";
2
+ import { n as isTerminalStatus, t as REDIRECT_RULE_STATUSES } from "./status-COfycGIU.mjs";
2
3
  import { z } from "zod";
3
4
 
4
- //#region src/api/schemas/common.ts
5
- /** Valid role level values */
6
- const VALID_ROLE_LEVELS = new Set([
7
- 10,
8
- 20,
9
- 30,
10
- 40,
11
- 50
12
- ]);
13
- /** Role level — coerces string/number to valid RoleLevel (10|20|30|40|50) */
14
- const roleLevel = z.coerce.number().int().refine((n) => VALID_ROLE_LEVELS.has(n), { message: "Invalid role level. Must be 10, 20, 30, 40, or 50" });
15
- /** Pagination query params — cursor-based */
16
- const cursorPaginationQuery = z.object({
17
- cursor: z.string().max(2048).optional().meta({ description: "Opaque cursor for pagination" }),
18
- limit: z.coerce.number().int().min(1).max(100).optional().default(50).meta({ description: "Maximum number of items to return (1-100, default 50)" })
19
- }).meta({ id: "CursorPaginationQuery" });
20
- /** Pagination query params — offset-based */
21
- const offsetPaginationQuery = z.object({
22
- limit: z.coerce.number().int().min(1).max(100).optional().default(50),
23
- offset: z.coerce.number().int().min(0).optional().default(0)
24
- }).meta({ id: "OffsetPaginationQuery" });
25
- /** Slug pattern: lowercase letters, digits, underscores; starts with letter */
26
- const slugPattern = /^[a-z][a-z0-9_]*$/;
27
- /** Matches http(s) scheme at start of URL */
28
- const HTTP_SCHEME_RE = /^https?:\/\//i;
29
- /** Validates that a URL string uses http or https scheme. Rejects javascript:/data: URI XSS vectors. */
30
- const httpUrl = z.string().url().refine((url) => HTTP_SCHEME_RE.test(url), "URL must use http or https");
31
- /** BCP 47 locale code — language with optional script/region subtags (e.g. en, en-US, pt-BR, es-419, zh-Hant) */
32
- const localeCode = z.string().regex(/^[a-z]{2,3}(-[a-z0-9]{2,8})*$/i, "Invalid locale code").transform((v) => v.toLowerCase());
33
- /** Shared `?locale=xx` query shape for endpoints that filter by locale. */
34
- const localeFilterQuery = z.object({ locale: z.string().min(1).optional() }).meta({ id: "LocaleFilterQuery" });
35
- /** Standard API error response */
36
- const apiErrorSchema = z.object({ error: z.object({
37
- code: z.string().meta({
38
- description: "Machine-readable error code",
39
- example: "NOT_FOUND"
40
- }),
41
- message: z.string().meta({ description: "Human-readable error message" })
42
- }) }).meta({ id: "ApiError" });
43
- /** Wrap a data schema in the standard success envelope: { data: T } */
44
- function successEnvelope(dataSchema) {
45
- return z.object({ data: dataSchema });
46
- }
47
- /** Standard delete response */
48
- const deleteResponseSchema = z.object({ deleted: z.literal(true) }).meta({ id: "DeleteResponse" });
49
- /** Standard count response */
50
- const countResponseSchema = z.object({ count: z.number().int().min(0) }).meta({ id: "CountResponse" });
51
-
52
- //#endregion
53
5
  //#region src/api/schemas/bylines.ts
54
6
  /** Slug pattern: lowercase letters, digits, and hyphens; must start with a letter */
55
7
  const bylineSlugPattern = /^[a-z][a-z0-9-]*$/;
@@ -90,7 +42,7 @@ const bylinesListQuery = cursorPaginationQuery.extend({
90
42
  search: z.string().optional(),
91
43
  isGuest: z.coerce.boolean().optional(),
92
44
  userId: z.string().optional(),
93
- locale: z.string().min(1).optional()
45
+ locale: localeCode.optional()
94
46
  }).meta({ id: "BylinesListQuery" });
95
47
  const bylineCreateBody = z.object({
96
48
  slug: z.string().min(1).regex(bylineSlugPattern, "Slug must contain only lowercase letters, digits, and hyphens"),
@@ -100,12 +52,12 @@ const bylineCreateBody = z.object({
100
52
  websiteUrl: httpUrl.nullish(),
101
53
  userId: z.string().nullish(),
102
54
  isGuest: z.boolean().optional(),
103
- locale: z.string().min(1).optional(),
55
+ locale: localeCode.optional(),
104
56
  translationOf: z.string().min(1).optional(),
105
57
  customFields: z.record(z.string(), z.unknown()).optional()
106
58
  }).meta({ id: "BylineCreateBody" });
107
59
  const bylineTranslationCreateBody = z.object({
108
- locale: z.string().min(1),
60
+ locale: localeCode,
109
61
  slug: z.string().min(1).regex(bylineSlugPattern, "Slug must contain only lowercase letters, digits, and hyphens").optional(),
110
62
  displayName: z.string().min(1).optional(),
111
63
  bio: z.string().nullish(),
@@ -289,129 +241,6 @@ const contentTranslationsResponseSchema = z.object({
289
241
  translations: z.array(contentTranslationSchema)
290
242
  }).meta({ id: "ContentTranslationsResponse" });
291
243
 
292
- //#endregion
293
- //#region src/api/schemas/media.ts
294
- /**
295
- * Accepts a comma-separated string (from URL query params) or an array of
296
- * strings (from JSON body or programmatic use) and normalises to string[].
297
- */
298
- const mimeTypeFilter = z.union([z.string(), z.array(z.string())]).transform((v) => {
299
- return (Array.isArray(v) ? v : v.split(",")).map((s) => s.trim()).filter((s) => s.length > 0);
300
- }).optional();
301
- const mediaListQuery = cursorPaginationQuery.extend({
302
- mimeType: mimeTypeFilter,
303
- q: z.string().trim().min(1).max(200).optional()
304
- }).meta({ id: "MediaListQuery" });
305
- const mediaUpdateBody = z.object({
306
- alt: z.string().optional(),
307
- caption: z.string().optional(),
308
- width: z.number().int().positive().optional(),
309
- height: z.number().int().positive().optional()
310
- }).meta({ id: "MediaUpdateBody" });
311
- /** Default maximum allowed file upload size (50 MB). */
312
- const DEFAULT_MAX_UPLOAD_SIZE = 50 * 1024 * 1024;
313
- function formatFileSize(bytes) {
314
- if (bytes < 1024) return `${bytes}B`;
315
- if (bytes < 1024 * 1024) return `${Math.floor(bytes / 1024)}KB`;
316
- return `${Math.floor(bytes / 1024 / 1024)}MB`;
317
- }
318
- const CONTENT_TYPE_RE = /^[a-z0-9][a-z0-9!#$&^_+\-.]*\/[a-z0-9!#$&^_+\-.]+(\s*;[^\r\n]*)?$/i;
319
- function mediaUploadUrlBody(maxSize) {
320
- if (!Number.isFinite(maxSize) || maxSize <= 0) throw new Error(`EmDash: maxUploadSize must be a positive finite number, got ${maxSize}`);
321
- return z.object({
322
- filename: z.string().min(1, "filename is required"),
323
- contentType: z.string().min(1, "contentType is required").regex(CONTENT_TYPE_RE, "Invalid content type"),
324
- size: z.number().int().positive().max(maxSize, `File size must not exceed ${formatFileSize(maxSize)}`),
325
- contentHash: z.string().optional(),
326
- fieldId: z.string().optional()
327
- }).meta({ id: "MediaUploadUrlBody" });
328
- }
329
- const mediaConfirmBody = z.object({
330
- size: z.number().int().positive().optional(),
331
- width: z.number().int().positive().optional(),
332
- height: z.number().int().positive().optional()
333
- }).meta({ id: "MediaConfirmBody" });
334
- const mediaProviderListQuery = cursorPaginationQuery.extend({
335
- query: z.string().optional(),
336
- mimeType: mimeTypeFilter
337
- }).meta({ id: "MediaProviderListQuery" });
338
- const mediaStatusSchema = z.enum([
339
- "pending",
340
- "ready",
341
- "failed"
342
- ]);
343
- const mediaItemSchema = z.object({
344
- id: z.string(),
345
- filename: z.string(),
346
- mimeType: z.string(),
347
- size: z.number().nullable(),
348
- width: z.number().nullable(),
349
- height: z.number().nullable(),
350
- alt: z.string().nullable(),
351
- caption: z.string().nullable(),
352
- storageKey: z.string(),
353
- status: mediaStatusSchema,
354
- contentHash: z.string().nullable(),
355
- blurhash: z.string().nullable(),
356
- dominantColor: z.string().nullable(),
357
- createdAt: z.string(),
358
- authorId: z.string().nullable()
359
- }).meta({ id: "MediaItem" });
360
- const mediaResponseSchema = z.object({ item: mediaItemSchema }).meta({ id: "MediaResponse" });
361
- const mediaListResponseSchema = z.object({
362
- items: z.array(mediaItemSchema),
363
- nextCursor: z.string().optional()
364
- }).meta({ id: "MediaListResponse" });
365
- const mediaUploadUrlResponseSchema = z.object({
366
- uploadUrl: z.string(),
367
- method: z.literal("PUT"),
368
- headers: z.record(z.string(), z.string()),
369
- mediaId: z.string(),
370
- storageKey: z.string(),
371
- expiresAt: z.string()
372
- }).meta({ id: "MediaUploadUrlResponse" });
373
- const mediaExistingResponseSchema = z.object({
374
- existing: z.literal(true),
375
- mediaId: z.string(),
376
- storageKey: z.string(),
377
- url: z.string()
378
- }).meta({ id: "MediaExistingResponse" });
379
- const mediaConfirmResponseSchema = z.object({ item: mediaItemSchema.extend({ url: z.string() }) }).meta({ id: "MediaConfirmResponse" });
380
-
381
- //#endregion
382
- //#region src/api/schemas/media-usage.ts
383
- const mediaUsageRepairStatusSchema = z.enum([
384
- "complete",
385
- "partial",
386
- "failed",
387
- "stale"
388
- ]).meta({ id: "MediaUsageRepairStatus" });
389
- const mediaUsageRepairCollectionBody = z.object({
390
- scope: z.literal("collection"),
391
- collection: z.string().min(1).max(63).regex(slugPattern, "Invalid collection slug")
392
- }).strict();
393
- const mediaUsageRepairAllBody = z.object({ scope: z.literal("all") }).strict();
394
- const mediaUsageRepairBody = z.discriminatedUnion("scope", [mediaUsageRepairCollectionBody, mediaUsageRepairAllBody]).meta({ id: "MediaUsageRepairBody" });
395
- const mediaUsageRepairCollectionSummarySchema = z.object({
396
- collection: z.string(),
397
- status: mediaUsageRepairStatusSchema,
398
- indexedSourceCount: z.number().int().min(0),
399
- failedSourceCount: z.number().int().min(0),
400
- skippedSourceCount: z.number().int().min(0),
401
- deletedSourceCount: z.number().int().min(0),
402
- lastErrorCode: z.string().nullable(),
403
- startedAt: z.string(),
404
- completedAt: z.string().nullable()
405
- }).meta({ id: "MediaUsageRepairCollectionSummary" });
406
- const mediaUsageRepairResponseSchema = z.object({
407
- status: mediaUsageRepairStatusSchema,
408
- indexedSourceCount: z.number().int().min(0),
409
- failedSourceCount: z.number().int().min(0),
410
- skippedSourceCount: z.number().int().min(0),
411
- deletedSourceCount: z.number().int().min(0),
412
- collections: z.array(mediaUsageRepairCollectionSummarySchema)
413
- }).meta({ id: "MediaUsageRepairResponse" });
414
-
415
244
  //#endregion
416
245
  //#region src/api/schemas/schema.ts
417
246
  const collectionSupportValues = z.enum([
@@ -738,7 +567,7 @@ const safeHref = z.string().trim().refine(isSafeHref, "URL must use http, https,
738
567
  const createMenuBody = z.object({
739
568
  name: z.string().min(1),
740
569
  label: z.string().min(1),
741
- locale: z.string().min(1).optional(),
570
+ locale: localeCode.optional(),
742
571
  translationOf: z.string().min(1).optional()
743
572
  }).strict().meta({ id: "CreateMenuBody" });
744
573
  const updateMenuBody = z.object({ label: z.string().min(1).optional() }).strict().meta({ id: "UpdateMenuBody" });
@@ -817,7 +646,7 @@ const createTaxonomyDefBody = z.object({
817
646
  labelSingular: z.string().min(1).max(200).optional(),
818
647
  hierarchical: z.boolean().optional().default(false),
819
648
  collections: z.array(z.string().min(1).max(63).regex(collectionSlugPattern, "Invalid collection slug format")).max(100).optional().default([]),
820
- locale: z.string().min(1).optional(),
649
+ locale: localeCode.optional(),
821
650
  translationOf: z.string().min(1).optional()
822
651
  }).meta({ id: "CreateTaxonomyDefBody" });
823
652
  const createTermBody = z.object({
@@ -825,7 +654,7 @@ const createTermBody = z.object({
825
654
  label: z.string().min(1),
826
655
  parentId: z.string().nullish(),
827
656
  description: z.string().optional(),
828
- locale: z.string().min(1).optional(),
657
+ locale: localeCode.optional(),
829
658
  translationOf: z.string().min(1).optional()
830
659
  }).meta({ id: "CreateTermBody" });
831
660
  const updateTermBody = z.object({
@@ -1233,5 +1062,5 @@ const notFoundSummarySchema = z.object({
1233
1062
  const notFoundSummaryResponseSchema = z.object({ items: z.array(notFoundSummarySchema) }).meta({ id: "NotFoundSummaryResponse" });
1234
1063
 
1235
1064
  //#endregion
1236
- export { createMenuBody as $, mediaResponseSchema as $t, searchRebuildBody as A, bylinesListQuery as An, fieldListResponseSchema as At, updateSectionBody as B, offsetPaginationQuery as Bn, mediaUsageRepairBody as Bt, userDetailSchema as C, bylineCreateBody as Cn, collectionGetQuery as Ct, usersListQuery as D, bylineTranslationCreateBody as Dn, collectionWithFieldsResponseSchema as Dt, userUpdateBody as E, bylineSummarySchema as En, collectionSchema as Et, siteSettingsSchema as F, cursorPaginationQuery as Fn, orphanedTableListResponseSchema as Ft, taxonomyListResponseSchema as G, formatFileSize as Gt, createTermBody as H, slugPattern as Hn, mediaUsageRepairResponseSchema as Ht, createSectionBody as I, deleteResponseSchema as In, orphanedTableSchema as It, termResponseSchema as J, mediaExistingResponseSchema as Jt, termGetResponseSchema as K, mediaConfirmBody as Kt, sectionListResponseSchema as L, httpUrl as Ln, schemaExportQuery as Lt, searchResultSchema as M, VALID_ROLE_LEVELS as Mn, fieldResponseSchema as Mt, searchSuggestQuery as N, apiErrorSchema as Nn, fieldSchema as Nt, searchEnableBody as O, bylineTranslationsResponseSchema as On, createCollectionBody as Ot, settingsUpdateBody as P, countResponseSchema as Pn, orphanRegisterBody as Pt, updateTermBody as Q, mediaProviderListQuery as Qt, sectionSchema as R, localeCode as Rn, updateCollectionBody as Rt, allowedDomainUpdateBody as S, trashedContentListResponseSchema as Sn, publicCommentSchema as St, userSchema as T, bylineListResponseSchema as Tn, collectionResponseSchema as Tt, taxonomyDefSchema as U, successEnvelope as Un, mediaUsageRepairStatusSchema as Ut, createTaxonomyDefBody as V, roleLevel as Vn, mediaUsageRepairCollectionSummarySchema as Vt, taxonomyDefTranslationsSchema as W, DEFAULT_MAX_UPLOAD_SIZE as Wt, termTranslationsSchema as X, mediaListQuery as Xt, termSchema as Y, mediaItemSchema as Yt, termWithCountSchema as Z, mediaListResponseSchema as Zt, widgetAreaSchema as _, contentTranslationSchema as _n, commentSchema as _t, notFoundPruneBody as a, contentCompareResponseSchema as an, menuTranslationsSchema as at, widgetSchema as b, contentUpdateBody as bn, createReactionBody as bt, notFoundSummarySchema as c, contentListQuery as cn, updateMenuBody as ct, redirectsListQuery as d, contentPublishBody as dn, sanitizeHref as dt, mediaUpdateBody as en, createMenuItemBody as et, updateRedirectBody as f, contentResponseSchema as fn, adminCommentListResponseSchema as ft, updateWidgetBody as g, contentTermsBody as gn, commentListQuery as gt, reorderWidgetsBody as h, contentSeoSchema as hn, commentCountsResponseSchema as ht, notFoundListResponseSchema as i, contentAuthorsResponseSchema as in, menuSchema as it, searchResponseSchema as j, contentBylineInputSchema as jn, fieldReorderBody as jt, searchQuery as k, bylineUpdateBody as kn, createFieldBody as kt, redirectListResponseSchema as l, contentListResponseSchema as ln, updateMenuItemBody as lt, createWidgetBody as m, contentSeoInput as mn, commentBulkResponseSchema as mt, notFoundEntrySchema as n, mediaUploadUrlResponseSchema as nn, menuItemTypeEnum as nt, notFoundSummaryQuery as o, contentCreateBody as on, menuWithItemsSchema as ot, createWidgetAreaBody as p, contentScheduleBody as pn, commentBulkBody as pt, termListResponseSchema as q, mediaConfirmResponseSchema as qt, notFoundListQuery as r, contentAuthorSchema as rn, menuListItemSchema as rt, notFoundSummaryResponseSchema as s, contentItemSchema as sn, reorderMenuItemsBody as st, createRedirectBody as t, mediaUploadUrlBody as tn, menuItemSchema as tt, redirectSchema as u, contentPreviewUrlBody as un, isSafeHref as ut, widgetAreaWithWidgetsAndCountSchema as v, contentTranslationsResponseSchema as vn, commentStatusBody as vt, userListResponseSchema as w, bylineCreditSchema as wn, collectionListResponseSchema as wt, allowedDomainCreateBody as x, trashedContentItemSchema as xn, publicCommentListResponseSchema as xt, widgetAreaWithWidgetsSchema as y, contentTrashQuery as yn, createCommentBody as yt, sectionsListQuery as z, localeFilterQuery as zn, updateFieldBody as zt };
1237
- //# sourceMappingURL=redirects-CeD7K7EX.mjs.map
1065
+ export { createMenuBody as $, contentTermsBody as $t, searchRebuildBody as A, fieldListResponseSchema as At, updateSectionBody as B, contentAuthorSchema as Bt, userDetailSchema as C, collectionGetQuery as Ct, usersListQuery as D, collectionWithFieldsResponseSchema as Dt, userUpdateBody as E, collectionSchema as Et, siteSettingsSchema as F, orphanedTableListResponseSchema as Ft, taxonomyListResponseSchema as G, contentListQuery as Gt, createTermBody as H, contentCompareResponseSchema as Ht, createSectionBody as I, orphanedTableSchema as It, termResponseSchema as J, contentPublishBody as Jt, termGetResponseSchema as K, contentListResponseSchema as Kt, sectionListResponseSchema as L, schemaExportQuery as Lt, searchResultSchema as M, fieldResponseSchema as Mt, searchSuggestQuery as N, fieldSchema as Nt, searchEnableBody as O, createCollectionBody as Ot, settingsUpdateBody as P, orphanRegisterBody as Pt, updateTermBody as Q, contentSeoSchema as Qt, sectionSchema as R, updateCollectionBody as Rt, allowedDomainUpdateBody as S, publicCommentSchema as St, userSchema as T, collectionResponseSchema as Tt, taxonomyDefSchema as U, contentCreateBody as Ut, createTaxonomyDefBody as V, contentAuthorsResponseSchema as Vt, taxonomyDefTranslationsSchema as W, contentItemSchema as Wt, termTranslationsSchema as X, contentScheduleBody as Xt, termSchema as Y, contentResponseSchema as Yt, termWithCountSchema as Z, contentSeoInput as Zt, widgetAreaSchema as _, commentSchema as _t, notFoundPruneBody as a, trashedContentListResponseSchema as an, menuTranslationsSchema as at, widgetSchema as b, createReactionBody as bt, notFoundSummarySchema as c, bylineListResponseSchema as cn, updateMenuBody as ct, redirectsListQuery as d, bylineTranslationsResponseSchema as dn, sanitizeHref as dt, contentTranslationSchema as en, createMenuItemBody as et, updateRedirectBody as f, bylineUpdateBody as fn, adminCommentListResponseSchema as ft, updateWidgetBody as g, commentListQuery as gt, reorderWidgetsBody as h, commentCountsResponseSchema as ht, notFoundListResponseSchema as i, trashedContentItemSchema as in, menuSchema as it, searchResponseSchema as j, fieldReorderBody as jt, searchQuery as k, createFieldBody as kt, redirectListResponseSchema as l, bylineSummarySchema as ln, updateMenuItemBody as lt, createWidgetBody as m, contentBylineInputSchema as mn, commentBulkResponseSchema as mt, notFoundEntrySchema as n, contentTrashQuery as nn, menuItemTypeEnum as nt, notFoundSummaryQuery as o, bylineCreateBody as on, menuWithItemsSchema as ot, createWidgetAreaBody as p, bylinesListQuery as pn, commentBulkBody as pt, termListResponseSchema as q, contentPreviewUrlBody as qt, notFoundListQuery as r, contentUpdateBody as rn, menuListItemSchema as rt, notFoundSummaryResponseSchema as s, bylineCreditSchema as sn, reorderMenuItemsBody as st, createRedirectBody as t, contentTranslationsResponseSchema as tn, menuItemSchema as tt, redirectSchema as u, bylineTranslationCreateBody as un, isSafeHref as ut, widgetAreaWithWidgetsAndCountSchema as v, commentStatusBody as vt, userListResponseSchema as w, collectionListResponseSchema as wt, allowedDomainCreateBody as x, publicCommentListResponseSchema as xt, widgetAreaWithWidgetsSchema as y, createCommentBody as yt, sectionsListQuery as z, updateFieldBody as zt };
1066
+ //# sourceMappingURL=redirects-D457qwt0.mjs.map