emdash 0.34.0 → 0.36.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 (800) hide show
  1. package/dist/activation-K0kGBWuJ.mjs +382 -0
  2. package/dist/activation-K0kGBWuJ.mjs.map +1 -0
  3. package/dist/{adapters-34EN2eXO.d.mts → adapters-CzL3H752.d.mts} +10 -3
  4. package/dist/adapters-CzL3H752.d.mts.map +1 -0
  5. package/dist/{allowed-origins-DW7sYyqg.mjs → allowed-origins-maylGaHv.mjs} +2 -2
  6. package/dist/{allowed-origins-DW7sYyqg.mjs.map → allowed-origins-maylGaHv.mjs.map} +1 -1
  7. package/dist/api/route-utils.d.mts +3 -3
  8. package/dist/api/route-utils.mjs +22 -20
  9. package/dist/api/route-utils.mjs.map +1 -1
  10. package/dist/api/schemas/index.d.mts +2 -2
  11. package/dist/api/schemas/index.mjs +5 -5
  12. package/dist/api-B0w3uBiG.mjs +2269 -0
  13. package/dist/api-B0w3uBiG.mjs.map +1 -0
  14. package/dist/{api-tokens-CFXu8F_2.mjs → api-tokens-9YrrCoE6.mjs} +2 -2
  15. package/dist/{api-tokens-CFXu8F_2.mjs.map → api-tokens-9YrrCoE6.mjs.map} +1 -1
  16. package/dist/{apply-D5zfeD09.mjs → apply-B_VMpJ2P.mjs} +34 -35
  17. package/dist/{apply-D5zfeD09.mjs.map → apply-B_VMpJ2P.mjs.map} +1 -1
  18. package/dist/astro/index.d.mts +12 -12
  19. package/dist/astro/index.d.mts.map +1 -1
  20. package/dist/astro/index.mjs +92 -25
  21. package/dist/astro/index.mjs.map +1 -1
  22. package/dist/astro/middleware/auth.d.mts +10 -10
  23. package/dist/astro/middleware/auth.d.mts.map +1 -1
  24. package/dist/astro/middleware/auth.mjs +10 -7
  25. package/dist/astro/middleware/auth.mjs.map +1 -1
  26. package/dist/astro/middleware/media-usage-write-fence.mjs +2 -2
  27. package/dist/astro/middleware/redirect.mjs +4 -4
  28. package/dist/astro/middleware/request-context.mjs +3 -3
  29. package/dist/astro/middleware/setup.mjs +1 -1
  30. package/dist/astro/middleware.d.mts +11 -12
  31. package/dist/astro/middleware.d.mts.map +1 -1
  32. package/dist/astro/middleware.mjs +255 -1323
  33. package/dist/astro/middleware.mjs.map +1 -1
  34. package/dist/astro/routes/api/admin/allowed-domains/_domain_.mjs +6 -6
  35. package/dist/astro/routes/api/admin/allowed-domains/index.mjs +6 -6
  36. package/dist/astro/routes/api/admin/api-tokens/_id_.mjs +3 -3
  37. package/dist/astro/routes/api/admin/api-tokens/index.mjs +4 -4
  38. package/dist/astro/routes/api/admin/byline-fields/_slug_/usage.mjs +4 -4
  39. package/dist/astro/routes/api/admin/byline-fields/_slug_.mjs +9 -9
  40. package/dist/astro/routes/api/admin/byline-fields/index.mjs +9 -9
  41. package/dist/astro/routes/api/admin/byline-fields/reorder.mjs +9 -9
  42. package/dist/astro/routes/api/admin/bylines/_id_/index.mjs +15 -15
  43. package/dist/astro/routes/api/admin/bylines/_id_/translations.mjs +15 -15
  44. package/dist/astro/routes/api/admin/bylines/index.mjs +15 -15
  45. package/dist/astro/routes/api/admin/comments/_id_/status.mjs +12 -12
  46. package/dist/astro/routes/api/admin/comments/_id_.mjs +4 -4
  47. package/dist/astro/routes/api/admin/comments/bulk.mjs +9 -9
  48. package/dist/astro/routes/api/admin/comments/counts.mjs +4 -4
  49. package/dist/astro/routes/api/admin/comments/index.mjs +9 -9
  50. package/dist/astro/routes/api/admin/hooks/exclusive/_hookName_.mjs +4 -4
  51. package/dist/astro/routes/api/admin/hooks/exclusive/index.mjs +3 -3
  52. package/dist/astro/routes/api/admin/media-usage/activation.d.mts +9 -0
  53. package/dist/astro/routes/api/admin/media-usage/activation.d.mts.map +1 -0
  54. package/dist/astro/routes/api/admin/media-usage/activation.mjs +46 -0
  55. package/dist/astro/routes/api/admin/media-usage/activation.mjs.map +1 -0
  56. package/dist/astro/routes/api/admin/media-usage/collection-deletions/index.mjs +14 -13
  57. package/dist/astro/routes/api/admin/media-usage/collection-deletions/index.mjs.map +1 -1
  58. package/dist/astro/routes/api/admin/media-usage/collection-deletions/retry.mjs +14 -13
  59. package/dist/astro/routes/api/admin/media-usage/collection-deletions/retry.mjs.map +1 -1
  60. package/dist/astro/routes/api/admin/media-usage/progress.d.mts +9 -0
  61. package/dist/astro/routes/api/admin/media-usage/progress.d.mts.map +1 -0
  62. package/dist/astro/routes/api/admin/media-usage/progress.mjs +44 -0
  63. package/dist/astro/routes/api/admin/media-usage/progress.mjs.map +1 -0
  64. package/dist/astro/routes/api/admin/media-usage/repair.mjs +16 -11
  65. package/dist/astro/routes/api/admin/media-usage/repair.mjs.map +1 -1
  66. package/dist/astro/routes/api/admin/media-usage/work/index.mjs +14 -13
  67. package/dist/astro/routes/api/admin/media-usage/work/index.mjs.map +1 -1
  68. package/dist/astro/routes/api/admin/media-usage/work/retry.mjs +14 -13
  69. package/dist/astro/routes/api/admin/media-usage/work/retry.mjs.map +1 -1
  70. package/dist/astro/routes/api/admin/oauth-clients/_id_.mjs +3 -3
  71. package/dist/astro/routes/api/admin/oauth-clients/index.mjs +3 -3
  72. package/dist/astro/routes/api/admin/plugins/_id_/disable.mjs +54 -48
  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 +54 -48
  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 +52 -46
  77. package/dist/astro/routes/api/admin/plugins/_id_/index.mjs.map +1 -1
  78. package/dist/astro/routes/api/admin/plugins/_id_/mcp.mjs +4 -4
  79. package/dist/astro/routes/api/admin/plugins/_id_/settings.mjs +52 -46
  80. package/dist/astro/routes/api/admin/plugins/_id_/settings.mjs.map +1 -1
  81. package/dist/astro/routes/api/admin/plugins/_id_/uninstall.mjs +53 -47
  82. package/dist/astro/routes/api/admin/plugins/_id_/uninstall.mjs.map +1 -1
  83. package/dist/astro/routes/api/admin/plugins/_id_/update.mjs +53 -47
  84. package/dist/astro/routes/api/admin/plugins/_id_/update.mjs.map +1 -1
  85. package/dist/astro/routes/api/admin/plugins/index.mjs +52 -46
  86. package/dist/astro/routes/api/admin/plugins/index.mjs.map +1 -1
  87. package/dist/astro/routes/api/admin/plugins/marketplace/_id_/icon.mjs +2 -2
  88. package/dist/astro/routes/api/admin/plugins/marketplace/_id_/index.mjs +52 -46
  89. package/dist/astro/routes/api/admin/plugins/marketplace/_id_/index.mjs.map +1 -1
  90. package/dist/astro/routes/api/admin/plugins/marketplace/_id_/install.mjs +53 -47
  91. package/dist/astro/routes/api/admin/plugins/marketplace/_id_/install.mjs.map +1 -1
  92. package/dist/astro/routes/api/admin/plugins/marketplace/index.mjs +52 -46
  93. package/dist/astro/routes/api/admin/plugins/marketplace/index.mjs.map +1 -1
  94. package/dist/astro/routes/api/admin/plugins/registry/_id_/uninstall.mjs +53 -47
  95. package/dist/astro/routes/api/admin/plugins/registry/_id_/uninstall.mjs.map +1 -1
  96. package/dist/astro/routes/api/admin/plugins/registry/_id_/update.mjs +54 -48
  97. package/dist/astro/routes/api/admin/plugins/registry/_id_/update.mjs.map +1 -1
  98. package/dist/astro/routes/api/admin/plugins/registry/artifact.d.mts.map +1 -1
  99. package/dist/astro/routes/api/admin/plugins/registry/artifact.mjs +172 -133
  100. package/dist/astro/routes/api/admin/plugins/registry/artifact.mjs.map +1 -1
  101. package/dist/astro/routes/api/admin/plugins/registry/install.mjs +54 -48
  102. package/dist/astro/routes/api/admin/plugins/registry/install.mjs.map +1 -1
  103. package/dist/astro/routes/api/admin/plugins/updates.mjs +52 -46
  104. package/dist/astro/routes/api/admin/plugins/updates.mjs.map +1 -1
  105. package/dist/astro/routes/api/admin/themes/marketplace/_id_/index.mjs +52 -46
  106. package/dist/astro/routes/api/admin/themes/marketplace/_id_/index.mjs.map +1 -1
  107. package/dist/astro/routes/api/admin/themes/marketplace/_id_/thumbnail.mjs +2 -2
  108. package/dist/astro/routes/api/admin/themes/marketplace/index.mjs +52 -46
  109. package/dist/astro/routes/api/admin/themes/marketplace/index.mjs.map +1 -1
  110. package/dist/astro/routes/api/admin/users/_id_/disable.mjs +2 -2
  111. package/dist/astro/routes/api/admin/users/_id_/enable.mjs +1 -1
  112. package/dist/astro/routes/api/admin/users/_id_/index.mjs +7 -7
  113. package/dist/astro/routes/api/admin/users/_id_/send-recovery.mjs +3 -3
  114. package/dist/astro/routes/api/admin/users/index.mjs +6 -6
  115. package/dist/astro/routes/api/auth/dev-bypass.d.mts.map +1 -1
  116. package/dist/astro/routes/api/auth/dev-bypass.mjs +3 -7
  117. package/dist/astro/routes/api/auth/dev-bypass.mjs.map +1 -1
  118. package/dist/astro/routes/api/auth/invite/accept.mjs +1 -1
  119. package/dist/astro/routes/api/auth/invite/complete.mjs +11 -11
  120. package/dist/astro/routes/api/auth/invite/index.mjs +8 -8
  121. package/dist/astro/routes/api/auth/invite/register-options.mjs +10 -10
  122. package/dist/astro/routes/api/auth/logout.mjs +2 -2
  123. package/dist/astro/routes/api/auth/magic-link/send.mjs +10 -10
  124. package/dist/astro/routes/api/auth/magic-link/verify.mjs +2 -2
  125. package/dist/astro/routes/api/auth/me.d.mts.map +1 -1
  126. package/dist/astro/routes/api/auth/me.mjs +19 -9
  127. package/dist/astro/routes/api/auth/me.mjs.map +1 -1
  128. package/dist/astro/routes/api/auth/mode.mjs +2 -2
  129. package/dist/astro/routes/api/auth/oauth/_provider_/callback.mjs +4 -4
  130. package/dist/astro/routes/api/auth/oauth/_provider_.mjs +2 -2
  131. package/dist/astro/routes/api/auth/passkey/_id_.mjs +6 -6
  132. package/dist/astro/routes/api/auth/passkey/index.mjs +1 -1
  133. package/dist/astro/routes/api/auth/passkey/options.mjs +12 -12
  134. package/dist/astro/routes/api/auth/passkey/register/options.mjs +10 -10
  135. package/dist/astro/routes/api/auth/passkey/register/verify.mjs +11 -11
  136. package/dist/astro/routes/api/auth/passkey/verify.mjs +11 -11
  137. package/dist/astro/routes/api/auth/signup/complete.mjs +11 -11
  138. package/dist/astro/routes/api/auth/signup/request.mjs +10 -10
  139. package/dist/astro/routes/api/auth/signup/verify.mjs +1 -1
  140. package/dist/astro/routes/api/comments/_collection_/_contentId_/index.mjs +13 -13
  141. package/dist/astro/routes/api/comments/_collection_/_contentId_/reactions.mjs +12 -12
  142. package/dist/astro/routes/api/content/_collection_/_id_/compare.mjs +2 -2
  143. package/dist/astro/routes/api/content/_collection_/_id_/discard-draft.mjs +3 -3
  144. package/dist/astro/routes/api/content/_collection_/_id_/duplicate.mjs +3 -3
  145. package/dist/astro/routes/api/content/_collection_/_id_/permanent.mjs +2 -2
  146. package/dist/astro/routes/api/content/_collection_/_id_/preview-url.mjs +11 -11
  147. package/dist/astro/routes/api/content/_collection_/_id_/publish.mjs +8 -8
  148. package/dist/astro/routes/api/content/_collection_/_id_/references/_relation_/children.mjs +16 -14
  149. package/dist/astro/routes/api/content/_collection_/_id_/references/_relation_/children.mjs.map +1 -1
  150. package/dist/astro/routes/api/content/_collection_/_id_/references/_relation_/parents.mjs +16 -14
  151. package/dist/astro/routes/api/content/_collection_/_id_/references/_relation_/parents.mjs.map +1 -1
  152. package/dist/astro/routes/api/content/_collection_/_id_/restore.mjs +3 -3
  153. package/dist/astro/routes/api/content/_collection_/_id_/revisions.mjs +2 -2
  154. package/dist/astro/routes/api/content/_collection_/_id_/schedule.mjs +8 -8
  155. package/dist/astro/routes/api/content/_collection_/_id_/terms/_taxonomy_.mjs +13 -13
  156. package/dist/astro/routes/api/content/_collection_/_id_/translations.mjs +2 -2
  157. package/dist/astro/routes/api/content/_collection_/_id_/unpublish.mjs +3 -3
  158. package/dist/astro/routes/api/content/_collection_/_id_.mjs +8 -8
  159. package/dist/astro/routes/api/content/_collection_/authors.mjs +2 -2
  160. package/dist/astro/routes/api/content/_collection_/index.mjs +8 -8
  161. package/dist/astro/routes/api/content/_collection_/trash.mjs +7 -7
  162. package/dist/astro/routes/api/dashboard.mjs +7 -7
  163. package/dist/astro/routes/api/dev/emails.mjs +2 -2
  164. package/dist/astro/routes/api/import/probe.d.mts +3 -3
  165. package/dist/astro/routes/api/import/probe.mjs +16 -16
  166. package/dist/astro/routes/api/import/wordpress/analyze.mjs +2 -2
  167. package/dist/astro/routes/api/import/wordpress/execute.d.mts +11 -11
  168. package/dist/astro/routes/api/import/wordpress/execute.mjs +12 -12
  169. package/dist/astro/routes/api/import/wordpress/media.d.mts +10 -10
  170. package/dist/astro/routes/api/import/wordpress/media.mjs +11 -11
  171. package/dist/astro/routes/api/import/wordpress/prepare.mjs +9 -9
  172. package/dist/astro/routes/api/import/wordpress/rewrite-urls.d.mts +11 -11
  173. package/dist/astro/routes/api/import/wordpress/rewrite-urls.mjs +12 -10
  174. package/dist/astro/routes/api/import/wordpress/rewrite-urls.mjs.map +1 -1
  175. package/dist/astro/routes/api/import/wordpress-plugin/analyze.d.mts +1 -1
  176. package/dist/astro/routes/api/import/wordpress-plugin/analyze.mjs +16 -16
  177. package/dist/astro/routes/api/import/wordpress-plugin/execute.d.mts +11 -11
  178. package/dist/astro/routes/api/import/wordpress-plugin/execute.mjs +26 -26
  179. package/dist/astro/routes/api/manifest.mjs +4 -4
  180. package/dist/astro/routes/api/mcp.mjs +42 -42
  181. package/dist/astro/routes/api/media/_id_/confirm.mjs +11 -11
  182. package/dist/astro/routes/api/media/_id_/upload.mjs +6 -6
  183. package/dist/astro/routes/api/media/_id_/usage.mjs +18 -13
  184. package/dist/astro/routes/api/media/_id_/usage.mjs.map +1 -1
  185. package/dist/astro/routes/api/media/_id_.d.mts.map +1 -1
  186. package/dist/astro/routes/api/media/_id_.mjs +21 -13
  187. package/dist/astro/routes/api/media/_id_.mjs.map +1 -1
  188. package/dist/astro/routes/api/media/file/_...key_.mjs +1 -1
  189. package/dist/astro/routes/api/media/folders/_id_.d.mts +10 -0
  190. package/dist/astro/routes/api/media/folders/_id_.d.mts.map +1 -0
  191. package/dist/astro/routes/api/media/folders/_id_.mjs +52 -0
  192. package/dist/astro/routes/api/media/folders/_id_.mjs.map +1 -0
  193. package/dist/astro/routes/api/media/folders/index.d.mts +9 -0
  194. package/dist/astro/routes/api/media/folders/index.d.mts.map +1 -0
  195. package/dist/astro/routes/api/media/folders/index.mjs +41 -0
  196. package/dist/astro/routes/api/media/folders/index.mjs.map +1 -0
  197. package/dist/astro/routes/api/media/providers/_providerId_/_itemId_.mjs +2 -2
  198. package/dist/astro/routes/api/media/providers/_providerId_/index.mjs +2 -2
  199. package/dist/astro/routes/api/media/providers/index.mjs +2 -2
  200. package/dist/astro/routes/api/media/upload-url.mjs +9 -9
  201. package/dist/astro/routes/api/media.d.mts.map +1 -1
  202. package/dist/astro/routes/api/media.mjs +28 -19
  203. package/dist/astro/routes/api/media.mjs.map +1 -1
  204. package/dist/astro/routes/api/menus/_name_/items/_id_.mjs +8 -8
  205. package/dist/astro/routes/api/menus/_name_/items.mjs +8 -8
  206. package/dist/astro/routes/api/menus/_name_/reorder.mjs +8 -8
  207. package/dist/astro/routes/api/menus/_name_/translations.mjs +8 -8
  208. package/dist/astro/routes/api/menus/_name_.mjs +8 -8
  209. package/dist/astro/routes/api/menus/index.mjs +8 -8
  210. package/dist/astro/routes/api/oauth/authorize.mjs +6 -6
  211. package/dist/astro/routes/api/oauth/device/authorize.mjs +5 -5
  212. package/dist/astro/routes/api/oauth/device/code.mjs +8 -8
  213. package/dist/astro/routes/api/oauth/device/token.mjs +7 -7
  214. package/dist/astro/routes/api/oauth/register.mjs +2 -2
  215. package/dist/astro/routes/api/oauth/token/refresh.mjs +5 -5
  216. package/dist/astro/routes/api/oauth/token/revoke.mjs +5 -5
  217. package/dist/astro/routes/api/oauth/token.mjs +5 -5
  218. package/dist/astro/routes/api/openapi.json.mjs +153 -6
  219. package/dist/astro/routes/api/openapi.json.mjs.map +1 -1
  220. package/dist/astro/routes/api/plugins/_pluginId_/_...path_.mjs +4 -4
  221. package/dist/astro/routes/api/redirects/404s/index.mjs +10 -10
  222. package/dist/astro/routes/api/redirects/404s/summary.mjs +10 -10
  223. package/dist/astro/routes/api/redirects/_id_.mjs +11 -11
  224. package/dist/astro/routes/api/redirects/index.mjs +11 -11
  225. package/dist/astro/routes/api/relations/_id_/index.mjs +16 -14
  226. package/dist/astro/routes/api/relations/_id_/index.mjs.map +1 -1
  227. package/dist/astro/routes/api/relations/_id_/translations.mjs +11 -9
  228. package/dist/astro/routes/api/relations/_id_/translations.mjs.map +1 -1
  229. package/dist/astro/routes/api/relations/index.mjs +16 -14
  230. package/dist/astro/routes/api/relations/index.mjs.map +1 -1
  231. package/dist/astro/routes/api/revisions/_revisionId_/index.mjs +2 -2
  232. package/dist/astro/routes/api/revisions/_revisionId_/restore.mjs +3 -3
  233. package/dist/astro/routes/api/schema/collections/_slug_/fields/_fieldSlug_.mjs +52 -46
  234. package/dist/astro/routes/api/schema/collections/_slug_/fields/_fieldSlug_.mjs.map +1 -1
  235. package/dist/astro/routes/api/schema/collections/_slug_/fields/index.mjs +52 -46
  236. package/dist/astro/routes/api/schema/collections/_slug_/fields/index.mjs.map +1 -1
  237. package/dist/astro/routes/api/schema/collections/_slug_/fields/reorder.mjs +52 -46
  238. package/dist/astro/routes/api/schema/collections/_slug_/fields/reorder.mjs.map +1 -1
  239. package/dist/astro/routes/api/schema/collections/_slug_/index.mjs +52 -46
  240. package/dist/astro/routes/api/schema/collections/_slug_/index.mjs.map +1 -1
  241. package/dist/astro/routes/api/schema/collections/index.mjs +52 -46
  242. package/dist/astro/routes/api/schema/collections/index.mjs.map +1 -1
  243. package/dist/astro/routes/api/schema/collections/reorder.mjs +52 -46
  244. package/dist/astro/routes/api/schema/collections/reorder.mjs.map +1 -1
  245. package/dist/astro/routes/api/schema/index.mjs +10 -8
  246. package/dist/astro/routes/api/schema/index.mjs.map +1 -1
  247. package/dist/astro/routes/api/schema/orphans/_slug_.mjs +52 -46
  248. package/dist/astro/routes/api/schema/orphans/_slug_.mjs.map +1 -1
  249. package/dist/astro/routes/api/schema/orphans/index.mjs +52 -46
  250. package/dist/astro/routes/api/schema/orphans/index.mjs.map +1 -1
  251. package/dist/astro/routes/api/search/enable.mjs +10 -10
  252. package/dist/astro/routes/api/search/index.mjs +9 -9
  253. package/dist/astro/routes/api/search/rebuild.mjs +10 -10
  254. package/dist/astro/routes/api/search/stats.mjs +5 -5
  255. package/dist/astro/routes/api/search/suggest.mjs +9 -9
  256. package/dist/astro/routes/api/sections/_slug_.mjs +9 -9
  257. package/dist/astro/routes/api/sections/index.mjs +9 -9
  258. package/dist/astro/routes/api/settings/backups/archives/_name_.mjs +6 -6
  259. package/dist/astro/routes/api/settings/backups/archives/index.mjs +5 -5
  260. package/dist/astro/routes/api/settings/backups/export.mjs +6 -6
  261. package/dist/astro/routes/api/settings/backups/index.mjs +7 -7
  262. package/dist/astro/routes/api/settings/email.mjs +4 -4
  263. package/dist/astro/routes/api/settings.mjs +13 -13
  264. package/dist/astro/routes/api/setup/admin-verify.mjs +12 -12
  265. package/dist/astro/routes/api/setup/admin.mjs +11 -11
  266. package/dist/astro/routes/api/setup/dev-bypass.d.mts.map +1 -1
  267. package/dist/astro/routes/api/setup/dev-bypass.mjs +35 -31
  268. package/dist/astro/routes/api/setup/dev-bypass.mjs.map +1 -1
  269. package/dist/astro/routes/api/setup/dev-reset.mjs +2 -2
  270. package/dist/astro/routes/api/setup/index.d.mts.map +1 -1
  271. package/dist/astro/routes/api/setup/index.mjs +31 -35
  272. package/dist/astro/routes/api/setup/index.mjs.map +1 -1
  273. package/dist/astro/routes/api/setup/status.mjs +3 -3
  274. package/dist/astro/routes/api/snapshot.mjs +7 -7
  275. package/dist/astro/routes/api/taxonomies/_name_/reorder.mjs +13 -13
  276. package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_/translations.mjs +13 -13
  277. package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_.mjs +13 -13
  278. package/dist/astro/routes/api/taxonomies/_name_/terms/index.mjs +13 -13
  279. package/dist/astro/routes/api/taxonomies/_name_/translations.mjs +13 -13
  280. package/dist/astro/routes/api/taxonomies/_name_.mjs +13 -13
  281. package/dist/astro/routes/api/taxonomies/index.mjs +13 -13
  282. package/dist/astro/routes/api/themes/preview.mjs +5 -5
  283. package/dist/astro/routes/api/typegen.mjs +4 -4
  284. package/dist/astro/routes/api/well-known/auth.mjs +2 -2
  285. package/dist/astro/routes/api/well-known/oauth-authorization-server.mjs +2 -2
  286. package/dist/astro/routes/api/well-known/oauth-protected-resource.mjs +2 -2
  287. package/dist/astro/routes/api/widget-areas/_name_/reorder.mjs +7 -7
  288. package/dist/astro/routes/api/widget-areas/_name_/widgets/_id_.mjs +10 -10
  289. package/dist/astro/routes/api/widget-areas/_name_/widgets.mjs +10 -10
  290. package/dist/astro/routes/api/widget-areas/_name_.mjs +5 -5
  291. package/dist/astro/routes/api/widget-areas/index.mjs +10 -10
  292. package/dist/astro/routes/api/widget-components.mjs +2 -2
  293. package/dist/astro/routes/robots.txt.mjs +6 -6
  294. package/dist/astro/routes/sitemap-_collection_.xml.mjs +9 -9
  295. package/dist/astro/routes/sitemap.xml.mjs +7 -7
  296. package/dist/astro/types.d.mts +19 -14
  297. package/dist/astro/types.d.mts.map +1 -1
  298. package/dist/auth/providers/github.d.mts +1 -1
  299. package/dist/auth/providers/google.d.mts +1 -1
  300. package/dist/{authorize-1iFJzPaZ.mjs → authorize-ByYs-Uxs.mjs} +2 -2
  301. package/dist/{authorize-1iFJzPaZ.mjs.map → authorize-ByYs-Uxs.mjs.map} +1 -1
  302. package/dist/{backup-LHjIAVNP.mjs → backup-ChyHfIoX.mjs} +5 -5
  303. package/dist/{backup-LHjIAVNP.mjs.map → backup-ChyHfIoX.mjs.map} +1 -1
  304. package/dist/{bundle-CBEXrBnb.mjs → bundle-DZFhFurR.mjs} +7 -7
  305. package/dist/{bundle-CBEXrBnb.mjs.map → bundle-DZFhFurR.mjs.map} +1 -1
  306. package/dist/{byline-pEcoDps8.mjs → byline-Cpnwrje1.mjs} +6 -6
  307. package/dist/{byline-pEcoDps8.mjs.map → byline-Cpnwrje1.mjs.map} +1 -1
  308. package/dist/{byline-fields-C5S8wygO.mjs → byline-fields-CAyA_Umd.mjs} +2 -2
  309. package/dist/{byline-fields-C5S8wygO.mjs.map → byline-fields-CAyA_Umd.mjs.map} +1 -1
  310. package/dist/{byline-registry-DDun8sxh.mjs → byline-registry-Bpu9-MVs.mjs} +2 -2
  311. package/dist/{byline-registry-DDun8sxh.mjs.map → byline-registry-Bpu9-MVs.mjs.map} +1 -1
  312. package/dist/{bylines-BWemdX2k.mjs → bylines-BSo9B9RX.mjs} +7 -7
  313. package/dist/{bylines-BWemdX2k.mjs.map → bylines-BSo9B9RX.mjs.map} +1 -1
  314. package/dist/{bylines-DJfSfXCL.mjs → bylines-CHjvehVX.mjs} +3 -3
  315. package/dist/{bylines-DJfSfXCL.mjs.map → bylines-CHjvehVX.mjs.map} +1 -1
  316. package/dist/{cache-CBJaDy_E.mjs → cache-5VirJ2Cn.mjs} +4 -4
  317. package/dist/{cache-CBJaDy_E.mjs.map → cache-5VirJ2Cn.mjs.map} +1 -1
  318. package/dist/capture-triggers-CNW1q3HK.mjs +362 -0
  319. package/dist/capture-triggers-CNW1q3HK.mjs.map +1 -0
  320. package/dist/{challenge-store-CZyFVaad.mjs → challenge-store-D5pSY2S1.mjs} +1 -1
  321. package/dist/{challenge-store-CZyFVaad.mjs.map → challenge-store-D5pSY2S1.mjs.map} +1 -1
  322. package/dist/{chunks-DfPax1I0.mjs → chunks-bNiX6_DR.mjs} +2 -2
  323. package/dist/{chunks-DfPax1I0.mjs.map → chunks-bNiX6_DR.mjs.map} +1 -1
  324. package/dist/cli/index.mjs +568 -84
  325. package/dist/cli/index.mjs.map +1 -1
  326. package/dist/client/cf-access.d.mts +1 -1
  327. package/dist/client/index.d.mts +74 -4
  328. package/dist/client/index.d.mts.map +1 -1
  329. package/dist/client/index.mjs +54 -2
  330. package/dist/client/index.mjs.map +1 -1
  331. package/dist/{collection-deletion-C8BugSGz.mjs → collection-deletion-m_oi2c0N.mjs} +13 -356
  332. package/dist/collection-deletion-m_oi2c0N.mjs.map +1 -0
  333. package/dist/{comment-Dxlep6cE.mjs → comment-DhvLEdhQ.mjs} +1 -1
  334. package/dist/{comment-Dxlep6cE.mjs.map → comment-DhvLEdhQ.mjs.map} +1 -1
  335. package/dist/{comment-reaction-D6qfHKBc.mjs → comment-reaction-CRuItEjt.mjs} +2 -2
  336. package/dist/{comment-reaction-D6qfHKBc.mjs.map → comment-reaction-CRuItEjt.mjs.map} +1 -1
  337. package/dist/{comments-CTOuhTSX.mjs → comments-CLj4bi8I.mjs} +2 -2
  338. package/dist/{comments-CTOuhTSX.mjs.map → comments-CLj4bi8I.mjs.map} +1 -1
  339. package/dist/{components-CQy3lh9x.mjs → components-v4U4DT2y.mjs} +1 -1
  340. package/dist/{components-CQy3lh9x.mjs.map → components-v4U4DT2y.mjs.map} +1 -1
  341. package/dist/config-DrfghTPe.d.mts +34 -0
  342. package/dist/config-DrfghTPe.d.mts.map +1 -0
  343. package/dist/{content-BNfwh7xX.mjs → content-CP-SeXNa.mjs} +5 -4
  344. package/dist/content-CP-SeXNa.mjs.map +1 -0
  345. package/dist/{content-list-query-DhQ84eVV.d.mts → content-list-query-BhejKVqb.d.mts} +1 -1
  346. package/dist/{content-list-query-DhQ84eVV.d.mts.map → content-list-query-BhejKVqb.d.mts.map} +1 -1
  347. package/dist/{content-refresh-DNERP4-f.mjs → content-refresh-DLOfIhYc.mjs} +1094 -93
  348. package/dist/content-refresh-DLOfIhYc.mjs.map +1 -0
  349. package/dist/{media-usage-De3qvwjc.mjs → content-repair-BCxzy0r4.mjs} +5 -196
  350. package/dist/content-repair-BCxzy0r4.mjs.map +1 -0
  351. package/dist/{context-DRgOvSnW.mjs → context-BR5hRWiK.mjs} +13 -13
  352. package/dist/{context-DRgOvSnW.mjs.map → context-BR5hRWiK.mjs.map} +1 -1
  353. package/dist/{cron-Y9aLtgrA.mjs → cron-CWfWrWKG.mjs} +1 -1
  354. package/dist/{cron-Y9aLtgrA.mjs.map → cron-CWfWrWKG.mjs.map} +1 -1
  355. package/dist/{dashboard-CB8J89rJ.mjs → dashboard-CkIV2rnQ.mjs} +5 -5
  356. package/dist/{dashboard-CB8J89rJ.mjs.map → dashboard-CkIV2rnQ.mjs.map} +1 -1
  357. package/dist/db/index.d.mts +4 -4
  358. package/dist/db/index.mjs +32 -9
  359. package/dist/db/index.mjs.map +1 -1
  360. package/dist/db/libsql-migrations.d.mts +11 -0
  361. package/dist/db/libsql-migrations.d.mts.map +1 -0
  362. package/dist/db/libsql-migrations.mjs +57 -0
  363. package/dist/db/libsql-migrations.mjs.map +1 -0
  364. package/dist/db/libsql.d.mts +1 -1
  365. package/dist/db/postgres-migrations.d.mts +10 -0
  366. package/dist/db/postgres-migrations.d.mts.map +1 -0
  367. package/dist/db/postgres-migrations.mjs +47 -0
  368. package/dist/db/postgres-migrations.mjs.map +1 -0
  369. package/dist/db/postgres.d.mts +1 -1
  370. package/dist/db/sqlite-migrations.d.mts +10 -0
  371. package/dist/db/sqlite-migrations.d.mts.map +1 -0
  372. package/dist/db/sqlite-migrations.mjs +28 -0
  373. package/dist/db/sqlite-migrations.mjs.map +1 -0
  374. package/dist/db/sqlite.d.mts +1 -1
  375. package/dist/db/sqlite.mjs +3 -3
  376. package/dist/db/sqlite.mjs.map +1 -1
  377. package/dist/{default-DdDl3fxv.mjs → default-YMEfcQUx.mjs} +1 -1
  378. package/dist/{default-DdDl3fxv.mjs.map → default-YMEfcQUx.mjs.map} +1 -1
  379. package/dist/{deferred-tasks-BMsa9F64.d.mts → deferred-tasks-DfqxH5Xf.d.mts} +1 -1
  380. package/dist/{deferred-tasks-BMsa9F64.d.mts.map → deferred-tasks-DfqxH5Xf.d.mts.map} +1 -1
  381. package/dist/{device-flow-CaioYGK3.mjs → device-flow-CojjSBwb.mjs} +5 -5
  382. package/dist/{device-flow-CaioYGK3.mjs.map → device-flow-CojjSBwb.mjs.map} +1 -1
  383. package/dist/direct-executor-BWeWiRYB.mjs +85 -0
  384. package/dist/direct-executor-BWeWiRYB.mjs.map +1 -0
  385. package/dist/{dist-D_6CKR8z.mjs → dist-89xCrGqi.mjs} +1 -1
  386. package/dist/{dist-D_6CKR8z.mjs.map → dist-89xCrGqi.mjs.map} +1 -1
  387. package/dist/{email-console-BHNjIwiB.mjs → email-console-CEJgR_LB.mjs} +1 -1
  388. package/dist/{email-console-BHNjIwiB.mjs.map → email-console-CEJgR_LB.mjs.map} +1 -1
  389. package/dist/{enrich-_ySMEvEE.mjs → enrich-BX0IDp4z.mjs} +3 -3
  390. package/dist/{enrich-_ySMEvEE.mjs.map → enrich-BX0IDp4z.mjs.map} +1 -1
  391. package/dist/{error-DupyJZE2.mjs → error-D9w94fjV.mjs} +2 -2
  392. package/dist/{error-DupyJZE2.mjs.map → error-D9w94fjV.mjs.map} +1 -1
  393. package/dist/{errors-CLUPm7aD.mjs → errors-n2j49uNf.mjs} +22 -2
  394. package/dist/errors-n2j49uNf.mjs.map +1 -0
  395. package/dist/{escape-C_aLKP3H.mjs → escape-DN4Qmjsl.mjs} +1 -1
  396. package/dist/{escape-C_aLKP3H.mjs.map → escape-DN4Qmjsl.mjs.map} +1 -1
  397. package/dist/{field-defs-cache-hg6QkjV9.mjs → field-defs-cache-Bh4q6oar.mjs} +5 -5
  398. package/dist/{field-defs-cache-hg6QkjV9.mjs.map → field-defs-cache-Bh4q6oar.mjs.map} +1 -1
  399. package/dist/focal-point-BeWFo6Xx.mjs +23 -0
  400. package/dist/focal-point-BeWFo6Xx.mjs.map +1 -0
  401. package/dist/{fts-manager-CZ-5dVwJ.mjs → fts-manager-BhOdW0bi.mjs} +3 -3
  402. package/dist/{fts-manager-CZ-5dVwJ.mjs.map → fts-manager-BhOdW0bi.mjs.map} +1 -1
  403. package/dist/{hash-Cg0TXJPV.mjs → hash-CTcngWvj.mjs} +1 -1
  404. package/dist/{hash-Cg0TXJPV.mjs.map → hash-CTcngWvj.mjs.map} +1 -1
  405. package/dist/{hreflang-D3Uehfv2.d.mts → hreflang-7pTHsLZJ.d.mts} +2 -2
  406. package/dist/{hreflang-D3Uehfv2.d.mts.map → hreflang-7pTHsLZJ.d.mts.map} +1 -1
  407. package/dist/{hreflang-DNswoYsi.mjs → hreflang-Huc6O5wa.mjs} +7 -7
  408. package/dist/{hreflang-DNswoYsi.mjs.map → hreflang-Huc6O5wa.mjs.map} +1 -1
  409. package/dist/identity-DXmb4aVp.mjs +35 -0
  410. package/dist/identity-DXmb4aVp.mjs.map +1 -0
  411. package/dist/{import-B41u8Rot.mjs → import-C4_O3KXU.mjs} +5 -5
  412. package/dist/{import-B41u8Rot.mjs.map → import-C4_O3KXU.mjs.map} +1 -1
  413. package/dist/{index-Cof4-Fab.d.mts → index-6bRee8zb.d.mts} +3 -3
  414. package/dist/{index-Cof4-Fab.d.mts.map → index-6bRee8zb.d.mts.map} +1 -1
  415. package/dist/{index-C3Y-rsyN.d.mts → index-DWbJrsAg.d.mts} +138 -83
  416. package/dist/index-DWbJrsAg.d.mts.map +1 -0
  417. package/dist/index.d.mts +21 -20
  418. package/dist/index.mjs +78 -72
  419. package/dist/{init-lock-6b309ZrF.mjs → init-lock-DJkX6Hto.mjs} +1 -1
  420. package/dist/{init-lock-6b309ZrF.mjs.map → init-lock-DJkX6Hto.mjs.map} +1 -1
  421. package/dist/{load-DmvJrtxS.mjs → load-Bo7fZAbg.mjs} +2 -2
  422. package/dist/{load-DmvJrtxS.mjs.map → load-Bo7fZAbg.mjs.map} +1 -1
  423. package/dist/{loader-DLBqRiGP.mjs → loader-ZsjE4paL.mjs} +2 -2
  424. package/dist/{loader-DLBqRiGP.mjs.map → loader-ZsjE4paL.mjs.map} +1 -1
  425. package/dist/manifest-builder-QXuqvVMP.mjs +189 -0
  426. package/dist/manifest-builder-QXuqvVMP.mjs.map +1 -0
  427. package/dist/{manifest-schema-BXbUAHod.mjs → manifest-schema-CUYPfCEH.mjs} +1 -1
  428. package/dist/{manifest-schema-BXbUAHod.mjs.map → manifest-schema-CUYPfCEH.mjs.map} +1 -1
  429. package/dist/media/image-endpoint.mjs +1 -1
  430. package/dist/media/index.d.mts +1 -1
  431. package/dist/media/index.mjs +13 -3
  432. package/dist/media/index.mjs.map +1 -1
  433. package/dist/media/local-runtime.d.mts +14 -12
  434. package/dist/media/local-runtime.d.mts.map +1 -1
  435. package/dist/media/local-runtime.mjs +11 -5
  436. package/dist/media/local-runtime.mjs.map +1 -1
  437. package/dist/{media-BWWWb8kg.mjs → media-BjwNuLEu.mjs} +100 -6
  438. package/dist/media-BjwNuLEu.mjs.map +1 -0
  439. package/dist/{media-CzhAn2--.mjs → media-D6SeAfBl.mjs} +41 -12
  440. package/dist/media-D6SeAfBl.mjs.map +1 -0
  441. package/dist/{media-allowlist-BD6HhgXA.mjs → media-allowlist-D35v7bmL.mjs} +3 -2
  442. package/dist/media-allowlist-D35v7bmL.mjs.map +1 -0
  443. package/dist/media-folders-D-0CmRZj.mjs +210 -0
  444. package/dist/media-folders-D-0CmRZj.mjs.map +1 -0
  445. package/dist/{media-upload-9yas9zGH.mjs → media-upload-C7bLXGcI.mjs} +9 -9
  446. package/dist/{media-upload-9yas9zGH.mjs.map → media-upload-C7bLXGcI.mjs.map} +1 -1
  447. package/dist/{media-url-BvoX88FA.mjs → media-url-DH7giMx_.mjs} +1 -1
  448. package/dist/{media-url-BvoX88FA.mjs.map → media-url-DH7giMx_.mjs.map} +1 -1
  449. package/dist/media-usage-BTRJvS6V.mjs +1833 -0
  450. package/dist/media-usage-BTRJvS6V.mjs.map +1 -0
  451. package/dist/media-usage-activation-Dx0kPV6b.mjs +78 -0
  452. package/dist/media-usage-activation-Dx0kPV6b.mjs.map +1 -0
  453. package/dist/{media-usage-work-DrCbqBcl.mjs → media-usage-work-C-fhM30c.mjs} +221 -59
  454. package/dist/media-usage-work-C-fhM30c.mjs.map +1 -0
  455. package/dist/{media-usage-work-B9Bksh_b.mjs → media-usage-work-DWb2XPMI.mjs} +4 -4
  456. package/dist/{media-usage-work-B9Bksh_b.mjs.map → media-usage-work-DWb2XPMI.mjs.map} +1 -1
  457. package/dist/{media-usage-write-fence-aHEgN1zB.mjs → media-usage-write-fence-BwoJVRDC.mjs} +2 -2
  458. package/dist/{media-usage-write-fence-aHEgN1zB.mjs.map → media-usage-write-fence-BwoJVRDC.mjs.map} +1 -1
  459. package/dist/{menus-fxvEDYE6.mjs → menus-CD7EFLwz.mjs} +3 -3
  460. package/dist/{menus-fxvEDYE6.mjs.map → menus-CD7EFLwz.mjs.map} +1 -1
  461. package/dist/{menus-CC-yn1F9.mjs → menus-CNg0QlDt.mjs} +42 -26
  462. package/dist/menus-CNg0QlDt.mjs.map +1 -0
  463. package/dist/migrations/index.d.mts +22 -0
  464. package/dist/migrations/index.d.mts.map +1 -0
  465. package/dist/migrations/index.mjs +7 -0
  466. package/dist/{mime-DfIVjNkr.mjs → mime-CUIG6x84.mjs} +1 -1
  467. package/dist/mime-CUIG6x84.mjs.map +1 -0
  468. package/dist/{mode-Bpe-tNNy.mjs → mode-DaUM_MB2.mjs} +1 -1
  469. package/dist/{mode-Bpe-tNNy.mjs.map → mode-DaUM_MB2.mjs.map} +1 -1
  470. package/dist/node-sqlite-compat-Udb4Y-rs.mjs +46 -0
  471. package/dist/node-sqlite-compat-Udb4Y-rs.mjs.map +1 -0
  472. package/dist/{normalize-Bc-s_r-a.mjs → normalize-CSxdKBVa.mjs} +22 -1
  473. package/dist/normalize-CSxdKBVa.mjs.map +1 -0
  474. package/dist/{oauth-authorization-BXO1MKej.mjs → oauth-authorization-Dpsb-fMJ.mjs} +5 -5
  475. package/dist/{oauth-authorization-BXO1MKej.mjs.map → oauth-authorization-Dpsb-fMJ.mjs.map} +1 -1
  476. package/dist/{oauth-clients-C_DNqtRu.mjs → oauth-clients-Bxnoe_67.mjs} +1 -1
  477. package/dist/{oauth-clients-C_DNqtRu.mjs.map → oauth-clients-Bxnoe_67.mjs.map} +1 -1
  478. package/dist/{oauth-state-store-DwAxMtk4.mjs → oauth-state-store-0C4s0K6w.mjs} +1 -1
  479. package/dist/{oauth-state-store-DwAxMtk4.mjs.map → oauth-state-store-0C4s0K6w.mjs.map} +1 -1
  480. package/dist/{oauth-user-lookup-BxfZizdk.mjs → oauth-user-lookup-wlGYSeqX.mjs} +1 -1
  481. package/dist/{oauth-user-lookup-BxfZizdk.mjs.map → oauth-user-lookup-wlGYSeqX.mjs.map} +1 -1
  482. package/dist/object-cache/memory.d.mts +1 -1
  483. package/dist/{options-CBXIHUoT.mjs → options-BHPeIbBd.mjs} +1 -1
  484. package/dist/{options-CBXIHUoT.mjs.map → options-BHPeIbBd.mjs.map} +1 -1
  485. package/dist/{options-DRe1pIBL.d.mts → options-BhZIeFY1.d.mts} +3 -3
  486. package/dist/{options-DRe1pIBL.d.mts.map → options-BhZIeFY1.d.mts.map} +1 -1
  487. package/dist/page/index.d.mts +2 -2
  488. package/dist/{parse-DFbuc-Fh.mjs → parse-BRJg1kz8.mjs} +2 -2
  489. package/dist/{parse-DFbuc-Fh.mjs.map → parse-BRJg1kz8.mjs.map} +1 -1
  490. package/dist/{passkey-config-_2GOwwK8.mjs → passkey-config-B3P0nHRR.mjs} +1 -1
  491. package/dist/{passkey-config-_2GOwwK8.mjs.map → passkey-config-B3P0nHRR.mjs.map} +1 -1
  492. package/dist/{patterns-CiyXeDgr.mjs → patterns-D9iDO3j8.mjs} +1 -1
  493. package/dist/{patterns-CiyXeDgr.mjs.map → patterns-D9iDO3j8.mjs.map} +1 -1
  494. package/dist/{placeholder-CzW7Lshs.d.mts → placeholder-BR4ZhVJl.d.mts} +7 -1
  495. package/dist/placeholder-BR4ZhVJl.d.mts.map +1 -0
  496. package/dist/plugin-types.d.mts +1 -1
  497. package/dist/plugin-utils.d.mts +10 -10
  498. package/dist/plugins/adapt-sandbox-entry.d.mts +10 -10
  499. package/dist/plugins/adapt-sandbox-entry.mjs +2 -2
  500. package/dist/policy-BVRganJQ.mjs +45 -0
  501. package/dist/policy-BVRganJQ.mjs.map +1 -0
  502. package/dist/{portable-text-DhKbDAGr.mjs → portable-text-C8Tvp4_g.mjs} +1 -1
  503. package/dist/{portable-text-DhKbDAGr.mjs.map → portable-text-C8Tvp4_g.mjs.map} +1 -1
  504. package/dist/{preview-PW-nOnq4.mjs → preview-dn2dUyM0.mjs} +2 -2
  505. package/dist/{preview-PW-nOnq4.mjs.map → preview-dn2dUyM0.mjs.map} +1 -1
  506. package/dist/protocol-CuBEsqgE.d.mts +52 -0
  507. package/dist/protocol-CuBEsqgE.d.mts.map +1 -0
  508. package/dist/{public-url-CWoFhQT8.mjs → public-url-DRz_AinV.mjs} +1 -1
  509. package/dist/{public-url-CWoFhQT8.mjs.map → public-url-DRz_AinV.mjs.map} +1 -1
  510. package/dist/{query-BgjfiLUQ.mjs → query-D18vTdha.mjs} +14 -14
  511. package/dist/{query-BgjfiLUQ.mjs.map → query-D18vTdha.mjs.map} +1 -1
  512. package/dist/{query-vgZNwIhh.mjs → query-tZDEdtCN.mjs} +4 -4
  513. package/dist/{query-vgZNwIhh.mjs.map → query-tZDEdtCN.mjs.map} +1 -1
  514. package/dist/{rate-limit-L5anykgo.mjs → rate-limit-on7KPo-v.mjs} +2 -2
  515. package/dist/{rate-limit-L5anykgo.mjs.map → rate-limit-on7KPo-v.mjs.map} +1 -1
  516. package/dist/{redirect-COsS6SWJ.mjs → redirect-CZkbozu9.mjs} +2 -2
  517. package/dist/{redirect-COsS6SWJ.mjs.map → redirect-CZkbozu9.mjs.map} +1 -1
  518. package/dist/{redirect-KBNE3UEs.mjs → redirect-DrbEmU9a.mjs} +1 -1
  519. package/dist/{redirect-KBNE3UEs.mjs.map → redirect-DrbEmU9a.mjs.map} +1 -1
  520. package/dist/{redirects-CufRQt0Q.mjs → redirects-BahWiu8Z.mjs} +5 -5
  521. package/dist/{redirects-CufRQt0Q.mjs.map → redirects-BahWiu8Z.mjs.map} +1 -1
  522. package/dist/{redirects-cV9g7V-0.mjs → redirects-CRIM55KH.mjs} +6 -6
  523. package/dist/{redirects-cV9g7V-0.mjs.map → redirects-CRIM55KH.mjs.map} +1 -1
  524. package/dist/{api-DdAsirBe.mjs → registry-BiO5WwPq.mjs} +483 -2462
  525. package/dist/registry-BiO5WwPq.mjs.map +1 -0
  526. package/dist/{registry-C581V4TP.mjs → registry-Cx-jEJOS.mjs} +9 -123
  527. package/dist/registry-Cx-jEJOS.mjs.map +1 -0
  528. package/dist/{relation-DtmAQH7s.mjs → relation-A6wLF_DS.mjs} +2 -2
  529. package/dist/{relation-DtmAQH7s.mjs.map → relation-A6wLF_DS.mjs.map} +1 -1
  530. package/dist/{relations-BBApI4e2.mjs → relations-BTPM2saV.mjs} +2 -2
  531. package/dist/{relations-BBApI4e2.mjs.map → relations-BTPM2saV.mjs.map} +1 -1
  532. package/dist/{relations-DItI3MN9.d.mts → relations-C7B46bcU.d.mts} +189 -30
  533. package/dist/relations-C7B46bcU.d.mts.map +1 -0
  534. package/dist/{relations-DICSyfsh.mjs → relations-Cj5hZ6Zg.mjs} +4 -4
  535. package/dist/{relations-DICSyfsh.mjs.map → relations-Cj5hZ6Zg.mjs.map} +1 -1
  536. package/dist/{request-cache-BSUptuJR.mjs → request-cache-DH9zdCOD.mjs} +1 -1
  537. package/dist/{request-cache-BSUptuJR.mjs.map → request-cache-DH9zdCOD.mjs.map} +1 -1
  538. package/dist/request-context.d.mts +1 -1
  539. package/dist/{request-meta-DgZJh3zG.mjs → request-meta-DRp5ENd_.mjs} +2 -2
  540. package/dist/{request-meta-DgZJh3zG.mjs.map → request-meta-DRp5ENd_.mjs.map} +1 -1
  541. package/dist/{resolve-DOhVEvty.mjs → resolve-DxUpTMmE.mjs} +1 -1
  542. package/dist/{resolve-DOhVEvty.mjs.map → resolve-DxUpTMmE.mjs.map} +1 -1
  543. package/dist/{runner-BiDvq5dv.mjs → runner-77GOZCnH.mjs} +443 -289
  544. package/dist/runner-77GOZCnH.mjs.map +1 -0
  545. package/dist/{runner-CgQbELYC.d.mts → runner-zgqA_CqP.d.mts} +16 -3
  546. package/dist/runner-zgqA_CqP.d.mts.map +1 -0
  547. package/dist/runtime.d.mts +11 -11
  548. package/dist/runtime.mjs +1 -1
  549. package/dist/{schema-BFyTg38T.mjs → schema-BY-oVntF.mjs} +3 -3
  550. package/dist/{schema-BFyTg38T.mjs.map → schema-BY-oVntF.mjs.map} +1 -1
  551. package/dist/{schema-CeQSNwB3.mjs → schema-Cw9kVK0I.mjs} +35 -5
  552. package/dist/{schema-CeQSNwB3.mjs.map → schema-Cw9kVK0I.mjs.map} +1 -1
  553. package/dist/{scopes-BVeuhGBE.mjs → scopes-vMR1uIbt.mjs} +3 -3
  554. package/dist/{scopes-BVeuhGBE.mjs.map → scopes-vMR1uIbt.mjs.map} +1 -1
  555. package/dist/{search-BpuPKZb0.mjs → search-CfT3KxO5.mjs} +4 -4
  556. package/dist/{search-BpuPKZb0.mjs.map → search-CfT3KxO5.mjs.map} +1 -1
  557. package/dist/{secrets-dtYs2hDo.mjs → secrets-BH2Qow1-.mjs} +3 -3
  558. package/dist/{secrets-dtYs2hDo.mjs.map → secrets-BH2Qow1-.mjs.map} +1 -1
  559. package/dist/{sections-COctk6hf.mjs → sections-DTfjyf1z.mjs} +2 -2
  560. package/dist/{sections-COctk6hf.mjs.map → sections-DTfjyf1z.mjs.map} +1 -1
  561. package/dist/seed/index.d.mts +2 -2
  562. package/dist/seed/index.mjs +24 -22
  563. package/dist/seo/index.d.mts +3 -3
  564. package/dist/seo/index.mjs +16 -14
  565. package/dist/seo/index.mjs.map +1 -1
  566. package/dist/{seo-AFpVvTqr.mjs → seo-BSiTIXzd.mjs} +1 -1
  567. package/dist/{seo-AFpVvTqr.mjs.map → seo-BSiTIXzd.mjs.map} +1 -1
  568. package/dist/{seo-CvDxfvFb.mjs → seo-Cm-dtvgk.mjs} +2 -2
  569. package/dist/{seo-CvDxfvFb.mjs.map → seo-Cm-dtvgk.mjs.map} +1 -1
  570. package/dist/{service-xMiMSTsR.mjs → service-DYsDHEKe.mjs} +3 -3
  571. package/dist/{service-xMiMSTsR.mjs.map → service-DYsDHEKe.mjs.map} +1 -1
  572. package/dist/{session-user-BzVemLkw.mjs → session-user-CNAfvsdw.mjs} +1 -1
  573. package/dist/{session-user-BzVemLkw.mjs.map → session-user-CNAfvsdw.mjs.map} +1 -1
  574. package/dist/{settings-B372MV0p.mjs → settings-BgN-0DT-.mjs} +6 -6
  575. package/dist/{settings-B372MV0p.mjs.map → settings-BgN-0DT-.mjs.map} +1 -1
  576. package/dist/{settings-BE9aqn_9.mjs → settings-DjtkUo__.mjs} +3 -3
  577. package/dist/{settings-BE9aqn_9.mjs.map → settings-DjtkUo__.mjs.map} +1 -1
  578. package/dist/{setup-complete-DF7TAfD5.mjs → setup-complete-CcpXaPU7.mjs} +2 -2
  579. package/dist/{setup-complete-DF7TAfD5.mjs.map → setup-complete-CcpXaPU7.mjs.map} +1 -1
  580. package/dist/{setup-nonce-Do-U_cg9.mjs → setup-nonce-Reyw30jg.mjs} +1 -1
  581. package/dist/{setup-nonce-Do-U_cg9.mjs.map → setup-nonce-Reyw30jg.mjs.map} +1 -1
  582. package/dist/{single-flight-cache-B0eLKS6K.mjs → single-flight-cache-BPuGPdcN.mjs} +2 -2
  583. package/dist/{single-flight-cache-B0eLKS6K.mjs.map → single-flight-cache-BPuGPdcN.mjs.map} +1 -1
  584. package/dist/{site-url-Bowsi9T-.mjs → site-url-Cs_V9n3V.mjs} +3 -3
  585. package/dist/{site-url-Bowsi9T-.mjs.map → site-url-Cs_V9n3V.mjs.map} +1 -1
  586. package/dist/{snapshot-B5h6aPMh.mjs → snapshot-DSB8P7Lm.mjs} +1 -1
  587. package/dist/{snapshot-B5h6aPMh.mjs.map → snapshot-DSB8P7Lm.mjs.map} +1 -1
  588. package/dist/{ssrf-Cpvg_n3A.mjs → ssrf-DqebVE34.mjs} +21 -5
  589. package/dist/{ssrf-Cpvg_n3A.mjs.map → ssrf-DqebVE34.mjs.map} +1 -1
  590. package/dist/{state-DYwPue40.mjs → state-BJfU9Uzw.mjs} +12 -4
  591. package/dist/state-BJfU9Uzw.mjs.map +1 -0
  592. package/dist/{status-CWVYpbD8.mjs → status-DDu8HIQl.mjs} +1 -1
  593. package/dist/{status-CWVYpbD8.mjs.map → status-DDu8HIQl.mjs.map} +1 -1
  594. package/dist/storage/local.d.mts +1 -1
  595. package/dist/storage/local.mjs +3 -3
  596. package/dist/storage/s3.d.mts +1 -1
  597. package/dist/storage/s3.mjs +1 -1
  598. package/dist/target-D0o26Azo.mjs +27 -0
  599. package/dist/target-D0o26Azo.mjs.map +1 -0
  600. package/dist/{taxonomies-Dk3MAklL.mjs → taxonomies-CPGxo-bn.mjs} +5 -5
  601. package/dist/{taxonomies-Dk3MAklL.mjs.map → taxonomies-CPGxo-bn.mjs.map} +1 -1
  602. package/dist/{taxonomies-B0o9ExNV.mjs → taxonomies-kmyudNGP.mjs} +7 -7
  603. package/dist/{taxonomies-B0o9ExNV.mjs.map → taxonomies-kmyudNGP.mjs.map} +1 -1
  604. package/dist/{taxonomy-CPeM8d2o.mjs → taxonomy-8X09dLN5.mjs} +4 -4
  605. package/dist/{taxonomy-CPeM8d2o.mjs.map → taxonomy-8X09dLN5.mjs.map} +1 -1
  606. package/dist/{tokens-C39klX8R.mjs → tokens-gTS-IVUp.mjs} +1 -1
  607. package/dist/{tokens-C39klX8R.mjs.map → tokens-gTS-IVUp.mjs.map} +1 -1
  608. package/dist/{transaction-NQj4VJ7Z.mjs → transaction-0KOpOyMu.mjs} +2 -1
  609. package/dist/{transaction-NQj4VJ7Z.mjs.map → transaction-0KOpOyMu.mjs.map} +1 -1
  610. package/dist/{transport-B_rfeU-a.d.mts → transport-_6R1ub7t.d.mts} +1 -1
  611. package/dist/{transport-B_rfeU-a.d.mts.map → transport-_6R1ub7t.d.mts.map} +1 -1
  612. package/dist/{transport--CfOflrp.mjs → transport-fX59xaJz.mjs} +4 -3
  613. package/dist/{transport--CfOflrp.mjs.map → transport-fX59xaJz.mjs.map} +1 -1
  614. package/dist/{trusted-proxy-CEVekpby.mjs → trusted-proxy-fe6nEgR4.mjs} +1 -1
  615. package/dist/{trusted-proxy-CEVekpby.mjs.map → trusted-proxy-fe6nEgR4.mjs.map} +1 -1
  616. package/dist/types-75KIqzL9.mjs.map +1 -1
  617. package/dist/{types-BW1syrlw.mjs → types-BXUmsINL.mjs} +1 -1
  618. package/dist/{types-BW1syrlw.mjs.map → types-BXUmsINL.mjs.map} +1 -1
  619. package/dist/{types-CPx2lIGo.d.mts → types-Blb-MRC3.d.mts} +1 -1
  620. package/dist/{types-CPx2lIGo.d.mts.map → types-Blb-MRC3.d.mts.map} +1 -1
  621. package/dist/{types-C3_AbkDP.d.mts → types-Br-ERaxh.d.mts} +2 -1
  622. package/dist/types-Br-ERaxh.d.mts.map +1 -0
  623. package/dist/{types-BPuloofb.d.mts → types-BzBd3PeX.d.mts} +1 -1
  624. package/dist/{types-BPuloofb.d.mts.map → types-BzBd3PeX.d.mts.map} +1 -1
  625. package/dist/{types-DefV3OiO.d.mts → types-CLqvnd05.d.mts} +1 -1
  626. package/dist/{types-DefV3OiO.d.mts.map → types-CLqvnd05.d.mts.map} +1 -1
  627. package/dist/{types-X0MThr7x.d.mts → types-D5VVLr7J.d.mts} +1 -1
  628. package/dist/{types-X0MThr7x.d.mts.map → types-D5VVLr7J.d.mts.map} +1 -1
  629. package/dist/{types-CAGdePf3.d.mts → types-DHxzBjbD.d.mts} +10 -1
  630. package/dist/types-DHxzBjbD.d.mts.map +1 -0
  631. package/dist/{types-D4_1Ga4L.d.mts → types-DJQxln7q.d.mts} +3 -3
  632. package/dist/{types-D4_1Ga4L.d.mts.map → types-DJQxln7q.d.mts.map} +1 -1
  633. package/dist/{types-CtzytVXn.mjs → types-DM3vioBY.mjs} +1 -1
  634. package/dist/{types-CtzytVXn.mjs.map → types-DM3vioBY.mjs.map} +1 -1
  635. package/dist/{types-CFUfyt1s.d.mts → types-D_DWe7k9.d.mts} +1 -1
  636. package/dist/{types-CFUfyt1s.d.mts.map → types-D_DWe7k9.d.mts.map} +1 -1
  637. package/dist/{types-Cs-TFLNf.d.mts → types-Vg6f5i3s.d.mts} +3 -3
  638. package/dist/{types-Cs-TFLNf.d.mts.map → types-Vg6f5i3s.d.mts.map} +1 -1
  639. package/dist/{upload-attempts-hlne3iA1.mjs → upload-attempts-CNyGSepg.mjs} +1 -1
  640. package/dist/{upload-attempts-hlne3iA1.mjs.map → upload-attempts-CNyGSepg.mjs.map} +1 -1
  641. package/dist/{url-pattern-BHS0V5Ng.mjs → url-pattern-K-KdXcSe.mjs} +1 -1
  642. package/dist/{url-pattern-BHS0V5Ng.mjs.map → url-pattern-K-KdXcSe.mjs.map} +1 -1
  643. package/dist/{user-sHgJ62SP.mjs → user-CtYY0tp2.mjs} +2 -2
  644. package/dist/{user-sHgJ62SP.mjs.map → user-CtYY0tp2.mjs.map} +1 -1
  645. package/dist/{utils-D4vD_Y98.mjs → utils-HztC73hq.mjs} +1 -1
  646. package/dist/{utils-D4vD_Y98.mjs.map → utils-HztC73hq.mjs.map} +1 -1
  647. package/dist/{validate-BkqIG_Uj.mjs → validate-Dd-IUjnZ.mjs} +2 -2
  648. package/dist/{validate-BkqIG_Uj.mjs.map → validate-Dd-IUjnZ.mjs.map} +1 -1
  649. package/dist/{validate-DeGtBN84.d.mts → validate-DlqdOZXB.d.mts} +5 -5
  650. package/dist/{validate-DeGtBN84.d.mts.map → validate-DlqdOZXB.d.mts.map} +1 -1
  651. package/dist/{validation-CiJb_X5o.mjs → validation-D83n7Npi.mjs} +10 -8
  652. package/dist/{validation-CiJb_X5o.mjs.map → validation-D83n7Npi.mjs.map} +1 -1
  653. package/dist/version-ri-sCyAp.mjs +7 -0
  654. package/dist/{version-x0NjTScG.mjs.map → version-ri-sCyAp.mjs.map} +1 -1
  655. package/dist/{widgets-Cwzvww0W.mjs → widgets-CpmZd9Q-.mjs} +4 -4
  656. package/dist/{widgets-Cwzvww0W.mjs.map → widgets-CpmZd9Q-.mjs.map} +1 -1
  657. package/dist/{wxr-taxonomies-CmC0ZsDr.d.mts → wxr-taxonomies-BFd0y72_.d.mts} +1 -1
  658. package/dist/{wxr-taxonomies-CmC0ZsDr.d.mts.map → wxr-taxonomies-BFd0y72_.d.mts.map} +1 -1
  659. package/dist/{wxr-taxonomies-QZjWxjyk.mjs → wxr-taxonomies-Df4vxWcU.mjs} +4 -4
  660. package/dist/{wxr-taxonomies-QZjWxjyk.mjs.map → wxr-taxonomies-Df4vxWcU.mjs.map} +1 -1
  661. package/dist/{zod-generator-D11MhxG4.mjs → zod-generator-DylzusHh.mjs} +24 -18
  662. package/dist/zod-generator-DylzusHh.mjs.map +1 -0
  663. package/package.json +32 -8
  664. package/src/api/errors.ts +20 -0
  665. package/src/api/handlers/index.ts +17 -0
  666. package/src/api/handlers/media-allowlist.ts +1 -0
  667. package/src/api/handlers/media-folders.ts +130 -0
  668. package/src/api/handlers/media-usage-activation.ts +102 -0
  669. package/src/api/handlers/media-usage.ts +108 -0
  670. package/src/api/handlers/media.ts +62 -2
  671. package/src/api/handlers/registry.ts +134 -316
  672. package/src/api/openapi/document.ts +192 -2
  673. package/src/api/schemas/media-usage.ts +77 -0
  674. package/src/api/schemas/media.ts +69 -0
  675. package/src/astro/integration/index.ts +46 -14
  676. package/src/astro/integration/routes.ts +18 -0
  677. package/src/astro/integration/runtime.ts +3 -0
  678. package/src/astro/integration/vite-config.ts +2 -7
  679. package/src/astro/middleware/auth.ts +4 -0
  680. package/src/astro/middleware/scoped-db.ts +21 -0
  681. package/src/astro/middleware.ts +67 -17
  682. package/src/astro/routes/api/admin/media-usage/activation.ts +42 -0
  683. package/src/astro/routes/api/admin/media-usage/progress.ts +37 -0
  684. package/src/astro/routes/api/admin/plugins/registry/artifact.ts +246 -96
  685. package/src/astro/routes/api/auth/dev-bypass.ts +0 -4
  686. package/src/astro/routes/api/auth/me.ts +14 -2
  687. package/src/astro/routes/api/media/[id].ts +3 -0
  688. package/src/astro/routes/api/media/folders/[id].ts +55 -0
  689. package/src/astro/routes/api/media/folders/index.ts +37 -0
  690. package/src/astro/routes/api/media.ts +12 -2
  691. package/src/astro/routes/api/setup/dev-bypass.ts +14 -7
  692. package/src/astro/routes/api/setup/index.ts +5 -13
  693. package/src/astro/types.ts +11 -1
  694. package/src/cli/commands/migrate.ts +593 -0
  695. package/src/cli/index.ts +2 -23
  696. package/src/client/index.ts +140 -2
  697. package/src/client/transport.ts +6 -2
  698. package/src/components/EmDashImage.astro +154 -50
  699. package/src/components/Gallery.astro +7 -0
  700. package/src/components/InlinePortableTextEditor.tsx +130 -1
  701. package/src/components/LiveSearch.astro +23 -0
  702. package/src/components/inline-code-block.tsx +180 -49
  703. package/src/content/converters/gallery.ts +2 -0
  704. package/src/content/converters/types.ts +2 -0
  705. package/src/database/connection.ts +2 -31
  706. package/src/database/index.ts +9 -3
  707. package/src/database/json-recordset.ts +16 -0
  708. package/src/database/migrations/019_i18n.ts +1 -1
  709. package/src/database/migrations/071_restore_content_bylines_table.ts +43 -0
  710. package/src/database/migrations/072_media_folders.ts +72 -0
  711. package/src/database/migrations/073_media_focal_point.ts +57 -0
  712. package/src/database/migrations/policy.ts +70 -0
  713. package/src/database/migrations/runner.ts +57 -5
  714. package/src/database/repositories/content.ts +5 -4
  715. package/src/database/repositories/media-folders.ts +115 -0
  716. package/src/database/repositories/media-usage-work.ts +395 -111
  717. package/src/database/repositories/media-usage.ts +1038 -10
  718. package/src/database/repositories/media.ts +97 -29
  719. package/src/database/transaction.ts +1 -0
  720. package/src/database/types.ts +13 -0
  721. package/src/db/adapters.ts +52 -4
  722. package/src/db/index.ts +3 -1
  723. package/src/db/libsql-migrations.ts +72 -0
  724. package/src/db/node-sqlite-compat.ts +78 -0
  725. package/src/db/postgres-migrations.ts +59 -0
  726. package/src/db/sqlite-migrations.ts +37 -0
  727. package/src/db/sqlite.ts +3 -3
  728. package/src/emdash-runtime.ts +154 -120
  729. package/src/fields/image.ts +7 -1
  730. package/src/fields/types.ts +6 -2
  731. package/src/i18n/normalize.ts +31 -0
  732. package/src/index.ts +12 -1
  733. package/src/media/focal-point.ts +37 -0
  734. package/src/media/local-runtime.ts +8 -0
  735. package/src/media/mime.ts +1 -0
  736. package/src/media/normalize.ts +10 -0
  737. package/src/media/types.ts +10 -0
  738. package/src/media/usage/activation.ts +162 -35
  739. package/src/media/usage/capture-triggers.ts +19 -3
  740. package/src/media/usage/collection-deletion-processor.ts +7 -3
  741. package/src/media/usage/collection-deletion.ts +10 -0
  742. package/src/media/usage/content-refresh.ts +258 -39
  743. package/src/media/usage/content-snapshots.ts +128 -31
  744. package/src/media/usage/extractor.ts +32 -13
  745. package/src/media/usage/maintenance-engine.ts +166 -0
  746. package/src/media/usage/reconciliation-processor.ts +106 -29
  747. package/src/media/usage/reconciliation.ts +90 -7
  748. package/src/media/usage/work-processor.ts +342 -101
  749. package/src/migrations/config-loader.ts +205 -0
  750. package/src/migrations/direct-executor.ts +141 -0
  751. package/src/migrations/identity.ts +46 -0
  752. package/src/migrations/index.ts +19 -0
  753. package/src/migrations/integration-metadata.ts +67 -0
  754. package/src/migrations/manifest-builder.ts +55 -0
  755. package/src/migrations/manifest-writer.ts +63 -0
  756. package/src/migrations/manifest.ts +197 -0
  757. package/src/migrations/protocol.ts +59 -0
  758. package/src/migrations/target.ts +35 -0
  759. package/src/plugins/index.ts +1 -0
  760. package/src/plugins/save-rejection.ts +20 -0
  761. package/src/plugins/scheduler/node.ts +1 -13
  762. package/src/plugins/scheduler/types.ts +0 -2
  763. package/src/plugins/state.ts +13 -3
  764. package/src/registry/artifact-fetch.ts +530 -0
  765. package/src/registry/config.ts +24 -6
  766. package/src/registry/types.ts +12 -15
  767. package/src/schema/types.ts +1 -0
  768. package/src/schema/zod-generator.ts +12 -4
  769. package/src/security/ssrf.ts +21 -2
  770. package/src/seed/apply.ts +4 -4
  771. package/src/ui.ts +2 -0
  772. package/src/virtual-modules.d.ts +8 -0
  773. package/dist/adapters-34EN2eXO.d.mts.map +0 -1
  774. package/dist/api-DdAsirBe.mjs.map +0 -1
  775. package/dist/collection-deletion-C8BugSGz.mjs.map +0 -1
  776. package/dist/content-BNfwh7xX.mjs.map +0 -1
  777. package/dist/content-refresh-DNERP4-f.mjs.map +0 -1
  778. package/dist/errors-CLUPm7aD.mjs.map +0 -1
  779. package/dist/index-C3Y-rsyN.d.mts.map +0 -1
  780. package/dist/media-BWWWb8kg.mjs.map +0 -1
  781. package/dist/media-CzhAn2--.mjs.map +0 -1
  782. package/dist/media-allowlist-BD6HhgXA.mjs.map +0 -1
  783. package/dist/media-usage-De3qvwjc.mjs.map +0 -1
  784. package/dist/media-usage-work-DrCbqBcl.mjs.map +0 -1
  785. package/dist/menus-CC-yn1F9.mjs.map +0 -1
  786. package/dist/mime-DfIVjNkr.mjs.map +0 -1
  787. package/dist/normalize-Bc-s_r-a.mjs.map +0 -1
  788. package/dist/placeholder-CzW7Lshs.d.mts.map +0 -1
  789. package/dist/registry-C581V4TP.mjs.map +0 -1
  790. package/dist/relations-DItI3MN9.d.mts.map +0 -1
  791. package/dist/runner-BiDvq5dv.mjs.map +0 -1
  792. package/dist/runner-CgQbELYC.d.mts.map +0 -1
  793. package/dist/state-DYwPue40.mjs.map +0 -1
  794. package/dist/types-C3_AbkDP.d.mts.map +0 -1
  795. package/dist/types-CAGdePf3.d.mts.map +0 -1
  796. package/dist/version-x0NjTScG.mjs +0 -7
  797. package/dist/zod-generator-D11MhxG4.mjs.map +0 -1
  798. /package/dist/{api-tokens-CyTsLszZ.mjs → api-tokens-B5NHLNUN.mjs} +0 -0
  799. /package/dist/{ssrf-DpXgKsna.mjs → ssrf-BPKzkm6O.mjs} +0 -0
  800. /package/dist/{types-CP1CflWf.mjs → types-D6OcIp2P.mjs} +0 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"media-BjwNuLEu.mjs","names":[],"sources":["../src/api/schemas/common.ts","../src/api/schemas/media-usage.ts","../src/api/schemas/media.ts"],"sourcesContent":["import { z } from \"zod\";\n\nimport { LOCALE_CODE_PATTERN } from \"../../i18n/config.js\";\n\n// ---------------------------------------------------------------------------\n// Role level\n// ---------------------------------------------------------------------------\n\n/** Valid role level values */\nexport const VALID_ROLE_LEVELS = new Set([10, 20, 30, 40, 50]);\n\n/** Role level — coerces string/number to valid RoleLevel (10|20|30|40|50) */\nexport const roleLevel = z.coerce\n\t.number()\n\t.int()\n\t.refine((n): n is 10 | 20 | 30 | 40 | 50 => VALID_ROLE_LEVELS.has(n), {\n\t\tmessage: \"Invalid role level. Must be 10, 20, 30, 40, or 50\",\n\t});\n\n// ---------------------------------------------------------------------------\n// Pagination\n// ---------------------------------------------------------------------------\n\n/** Pagination query params — cursor-based */\nexport const cursorPaginationQuery = z\n\t.object({\n\t\tcursor: z.string().max(2048).optional().meta({ description: \"Opaque cursor for pagination\" }),\n\t\tlimit: z.coerce.number().int().min(1).max(100).optional().default(50).meta({\n\t\t\tdescription: \"Maximum number of items to return (1-100, default 50)\",\n\t\t}),\n\t})\n\t.meta({ id: \"CursorPaginationQuery\" });\n\n/** Pagination query params — offset-based */\nexport const offsetPaginationQuery = z\n\t.object({\n\t\tlimit: z.coerce.number().int().min(1).max(100).optional().default(50),\n\t\toffset: z.coerce.number().int().min(0).optional().default(0),\n\t})\n\t.meta({ id: \"OffsetPaginationQuery\" });\n\n// ---------------------------------------------------------------------------\n// Shared primitives\n// ---------------------------------------------------------------------------\n\n/** Slug pattern: lowercase letters, digits, underscores; starts with letter */\nexport const slugPattern = /^[a-z][a-z0-9_]*$/;\n\n/** Matches http(s) scheme at start of URL */\nconst HTTP_SCHEME_RE = /^https?:\\/\\//i;\n\n/** Validates that a URL string uses http or https scheme. Rejects javascript:/data: URI XSS vectors. */\nexport const httpUrl = z\n\t.string()\n\t.url()\n\t.refine((url) => HTTP_SCHEME_RE.test(url), \"URL must use http or https\");\n\n/**\n * BCP 47 locale code — language with optional script/region subtags (e.g. en, en-US, pt-BR, es-419, zh-Hant).\n * Validation is case-insensitive, but the value is preserved verbatim because the site config, stored\n * `locale` columns, and public query path all keep the raw BCP-47 casing.\n */\nexport const localeCode = z.string().regex(LOCALE_CODE_PATTERN, \"Invalid locale code\");\n\n/** Shared `?locale=xx` query shape for endpoints that filter by locale. */\nexport const localeFilterQuery = z\n\t.object({\n\t\tlocale: localeCode.optional(),\n\t})\n\t.meta({ id: \"LocaleFilterQuery\" });\n\n// ---------------------------------------------------------------------------\n// OpenAPI: Shared response schemas\n// ---------------------------------------------------------------------------\n\n/** Standard API error response */\nexport const apiErrorSchema = z\n\t.object({\n\t\tsuccess: z.literal(false).meta({ description: \"Discriminant: always false for errors\" }),\n\t\terror: z.object({\n\t\t\tcode: z.string().meta({ description: \"Machine-readable error code\", example: \"NOT_FOUND\" }),\n\t\t\tmessage: z.string().meta({ description: \"Human-readable error message\" }),\n\t\t}),\n\t})\n\t.meta({ id: \"ApiError\" });\n\n/** Wrap a data schema in the standard success envelope: { success: true, data: T } */\nexport function successEnvelope<T extends z.ZodType>(dataSchema: T) {\n\treturn z.object({\n\t\tsuccess: z.literal(true).meta({ description: \"Discriminant: always true for success\" }),\n\t\tdata: dataSchema,\n\t});\n}\n\n/** Standard delete response */\nexport const deleteResponseSchema = z.object({ deleted: z.literal(true) }).meta({\n\tid: \"DeleteResponse\",\n});\n\n/** Standard count response */\nexport const countResponseSchema = z\n\t.object({ count: z.number().int().min(0) })\n\t.meta({ id: \"CountResponse\" });\n","import { z } from \"zod\";\n\nimport { slugPattern } from \"./common.js\";\n\nexport const mediaUsageCoverageStatusSchema = z\n\t.enum([\"complete\", \"never\", \"running\", \"partial\", \"failed\", \"stale\", \"unknown\"])\n\t.meta({ id: \"MediaUsageCoverageStatus\" });\n\nexport const mediaUsageCoverageSchema = z\n\t.object({\n\t\tscope: z.literal(\"all_content_collections\"),\n\t\tstatus: mediaUsageCoverageStatusSchema,\n\t})\n\t.meta({ id: \"MediaUsageCoverage\" });\n\nexport const mediaUsageProgressSchema = z\n\t.object({\n\t\tstatus: z.enum([\"indexing\", \"ready\", \"needs_attention\"]),\n\t\treadyCollections: z.number().int().min(0),\n\t\ttotalCollections: z.number().int().min(0),\n\t})\n\t.meta({ id: \"MediaUsageProgress\" });\n\nexport const mediaUsageSummarySchema = z\n\t.object({\n\t\tcount: z.number().int().min(0).nullable(),\n\t\tcoverage: mediaUsageCoverageSchema,\n\t})\n\t.meta({ id: \"MediaUsageSummary\" });\n\nexport const mediaUsageDetailsQuery = z.object({\n\tcursor: z.string().min(1).max(2048).optional().meta({\n\t\tdescription: \"Opaque content-entry-group cursor\",\n\t}),\n\tlimit: z.coerce.number().int().min(1).max(100).optional().default(50).meta({\n\t\tdescription: \"Maximum number of content entry groups to return (1-100, default 50)\",\n\t}),\n});\n\nexport const mediaUsageOccurrenceDetailSchema = z\n\t.object({\n\t\tfieldSlug: z.string(),\n\t\tfieldPath: z.string(),\n\t\toccurrenceIndex: z.number().int().min(0),\n\t\treferenceType: z.enum([\"image_field\", \"file_field\", \"portable_text_image\", \"unknown\"]),\n\t})\n\t.meta({ id: \"MediaUsageOccurrenceDetail\" });\n\nexport const mediaUsageSourceDetailSchema = z\n\t.object({\n\t\tvariant: z.enum([\"columns\", \"draft_overlay\"]),\n\t\toccurrences: z.array(mediaUsageOccurrenceDetailSchema),\n\t})\n\t.meta({ id: \"MediaUsageSourceDetail\" });\n\nexport const mediaUsageEntryDetailSchema = z\n\t.object({\n\t\tcollection: z.string(),\n\t\tcontentId: z.string(),\n\t\ttitle: z.string().nullable(),\n\t\tslug: z.string().nullable(),\n\t\tlocale: z.string().nullable(),\n\t\tstatus: z.string().nullable(),\n\t\tscheduledAt: z.string().nullable(),\n\t\tdeletedAt: z.string().nullable(),\n\t\tsources: z.array(mediaUsageSourceDetailSchema),\n\t})\n\t.meta({ id: \"MediaUsageEntryDetail\" });\n\nexport const mediaUsageDetailsResponseSchema = z\n\t.object({\n\t\titems: z.array(mediaUsageEntryDetailSchema),\n\t\tnextCursor: z.string().optional(),\n\t\tcoverage: mediaUsageCoverageSchema,\n\t})\n\t.meta({ id: \"MediaUsageDetailsResponse\" });\n\nexport const mediaUsageRepairStatusSchema = z\n\t.enum([\"complete\", \"partial\", \"failed\", \"stale\"])\n\t.meta({ id: \"MediaUsageRepairStatus\" });\n\nconst mediaUsageRepairCollectionBody = z\n\t.object({\n\t\tscope: z.literal(\"collection\"),\n\t\tcollection: z.string().min(1).max(63).regex(slugPattern, \"Invalid collection slug\"),\n\t})\n\t.strict();\n\nconst mediaUsageRepairAllBody = z.object({ scope: z.literal(\"all\") }).strict();\n\nexport const mediaUsageRepairBody = z\n\t.discriminatedUnion(\"scope\", [mediaUsageRepairCollectionBody, mediaUsageRepairAllBody])\n\t.meta({ id: \"MediaUsageRepairBody\" });\n\nexport const mediaUsageRepairCollectionSummarySchema = z\n\t.object({\n\t\tcollection: z.string(),\n\t\tstatus: mediaUsageRepairStatusSchema,\n\t\tindexedSourceCount: z.number().int().min(0),\n\t\tfailedSourceCount: z.number().int().min(0),\n\t\tskippedSourceCount: z.number().int().min(0),\n\t\tdeletedSourceCount: z.number().int().min(0),\n\t\tlastErrorCode: z.string().nullable(),\n\t\tstartedAt: z.string(),\n\t\tcompletedAt: z.string().nullable(),\n\t})\n\t.meta({ id: \"MediaUsageRepairCollectionSummary\" });\n\nexport const mediaUsageRepairResponseSchema = z\n\t.object({\n\t\tstatus: mediaUsageRepairStatusSchema,\n\t\tindexedSourceCount: z.number().int().min(0),\n\t\tfailedSourceCount: z.number().int().min(0),\n\t\tskippedSourceCount: z.number().int().min(0),\n\t\tdeletedSourceCount: z.number().int().min(0),\n\t\tcollections: z.array(mediaUsageRepairCollectionSummarySchema),\n\t})\n\t.meta({ id: \"MediaUsageRepairResponse\" });\n\nexport const mediaUsageWorkStateSchema = z\n\t.enum([\"pending\", \"retry\", \"leased\", \"failed\"])\n\t.meta({ id: \"MediaUsageWorkState\" });\n\nexport const mediaUsageWorkListQuery = z.object({\n\tcollection: z.string().min(1).max(63).regex(slugPattern, \"Invalid collection slug\"),\n\tstate: mediaUsageWorkStateSchema.optional(),\n\tcursor: z.string().min(1).max(2048).optional().meta({\n\t\tdescription: \"Opaque work-page cursor\",\n\t}),\n\tlimit: z.coerce.number().int().min(1).max(100).optional().default(50).meta({\n\t\tdescription: \"Maximum number of work items to return (1-100, default 50)\",\n\t}),\n});\n\nexport const mediaUsageWorkItemSchema = z\n\t.object({\n\t\tcollectionId: z.string(),\n\t\tcollectionSlug: z.string(),\n\t\tcontentId: z.string(),\n\t\tstate: mediaUsageWorkStateSchema,\n\t\tattemptCount: z.number().int().min(0),\n\t\tnextAttemptAt: z.string(),\n\t\tleaseExpiresAt: z.string().nullable(),\n\t\tlastAttemptedAt: z.string().nullable(),\n\t\tlastErrorCode: z.string().nullable(),\n\t\tupdatedAt: z.string(),\n\t})\n\t.meta({ id: \"MediaUsageWorkItem\" });\n\nexport const mediaUsageWorkListResponseSchema = z\n\t.object({\n\t\titems: z.array(mediaUsageWorkItemSchema),\n\t\tnextCursor: z.string().optional(),\n\t})\n\t.meta({ id: \"MediaUsageWorkListResponse\" });\n\nconst boundedOpaqueMediaUsageId = z.string().min(1).max(2048);\n\nexport const mediaUsageWorkRetryBody = z\n\t.object({\n\t\tcollectionId: boundedOpaqueMediaUsageId.meta({\n\t\t\tdescription: \"Current immutable collection identity\",\n\t\t}),\n\t\tcontentId: boundedOpaqueMediaUsageId.meta({\n\t\t\tdescription: \"Content entry identity, including a deleted entry\",\n\t\t}),\n\t})\n\t.strict()\n\t.meta({ id: \"MediaUsageWorkRetryBody\" });\n\nexport const mediaUsageWorkRetryResponseSchema = z\n\t.object({\n\t\tchanged: z.boolean(),\n\t\titem: mediaUsageWorkItemSchema,\n\t})\n\t.meta({ id: \"MediaUsageWorkRetryResponse\" });\n\nexport const mediaUsageWorkRetryConflictSchema = z.object({\n\tsuccess: z.literal(false),\n\terror: z.discriminatedUnion(\"code\", [\n\t\tz.object({\n\t\t\tcode: z.literal(\"WORK_LEASE_ACTIVE\"),\n\t\t\tmessage: z.string(),\n\t\t\tdetails: z.object({ leaseExpiresAt: z.string() }),\n\t\t}),\n\t\tz.object({\n\t\t\tcode: z.literal(\"WORK_CHANGED\"),\n\t\t\tmessage: z.string(),\n\t\t}),\n\t]),\n});\n\nexport const mediaUsageActivationStateSchema = z\n\t.enum([\"expanded\", \"activating\", \"active\"])\n\t.meta({ id: \"MediaUsageActivationState\" });\n\nexport const mediaUsageActivationStatusSchema = z\n\t.object({\n\t\tstate: mediaUsageActivationStateSchema,\n\t\tcollectionCursor: z.string().nullable(),\n\t\tattemptCount: z.number().int().min(0),\n\t\tdrainConfirmedAt: z.string().nullable(),\n\t\tlastAttemptedAt: z.string().nullable(),\n\t\tlastErrorCode: z.literal(\"MEDIA_USAGE_ACTIVATION_FAILED\").nullable(),\n\t\tleaseExpiresAt: z.string().nullable(),\n\t\tactivatedAt: z.string().nullable(),\n\t\tupdatedAt: z.string(),\n\t})\n\t.meta({ id: \"MediaUsageActivationStatus\" });\n\nexport const mediaUsageActivationAdvanceBody = z\n\t.object({\n\t\twritersDrained: z.literal(true),\n\t})\n\t.strict()\n\t.meta({ id: \"MediaUsageActivationAdvanceBody\" });\n\nexport const mediaUsageActivationAdvanceResponseSchema = z\n\t.object({\n\t\toutcome: z.enum([\"activating\", \"active\"]),\n\t\tprocessedCollections: z.number().int().min(0).max(1),\n\t\tactivation: mediaUsageActivationStatusSchema,\n\t})\n\t.meta({ id: \"MediaUsageActivationAdvanceResponse\" });\n\nexport const mediaUsageProgressAdvanceResponseSchema = z\n\t.object({\n\t\tactivation: mediaUsageActivationStatusSchema,\n\t\tprogress: mediaUsageProgressSchema.nullable(),\n\t\tnextRequestInMs: z.union([z.literal(0), z.literal(30_000), z.null()]),\n\t})\n\t.meta({ id: \"MediaUsageProgressAdvanceResponse\" });\n\nexport const mediaUsageActivationConflictSchema = z.object({\n\tsuccess: z.literal(false),\n\terror: z.discriminatedUnion(\"code\", [\n\t\tz.object({\n\t\t\tcode: z.literal(\"MEDIA_USAGE_ACTIVATION_BUSY\"),\n\t\t\tmessage: z.string(),\n\t\t\tdetails: z.object({ leaseExpiresAt: z.string() }),\n\t\t}),\n\t\tz.object({\n\t\t\tcode: z.literal(\"MEDIA_USAGE_ACTIVATION_CONFLICT\"),\n\t\t\tmessage: z.string(),\n\t\t}),\n\t\tz.object({\n\t\t\tcode: z.literal(\"MEDIA_USAGE_ACTIVATION_VERSION_MISMATCH\"),\n\t\t\tmessage: z.string(),\n\t\t}),\n\t]),\n});\n\nexport const mediaUsageCollectionDeletionStateSchema = z\n\t.enum([\"pending\", \"retry\", \"leased\", \"failed\"])\n\t.meta({ id: \"MediaUsageCollectionDeletionState\" });\nexport const mediaUsageCollectionDeletionPhaseSchema = z\n\t.enum([\"fence\", \"registry\", \"table\", \"work\", \"sources\", \"status\", \"finalize\"])\n\t.meta({ id: \"MediaUsageCollectionDeletionPhase\" });\nexport const mediaUsageCollectionDeletionListQuery = z\n\t.object({\n\t\tstate: mediaUsageCollectionDeletionStateSchema.optional().default(\"failed\"),\n\t\tcursor: z.string().min(1).max(2048).optional(),\n\t\tlimit: z.coerce.number().int().min(1).max(100).optional().default(50),\n\t})\n\t.meta({ id: \"MediaUsageCollectionDeletionListQuery\" });\nexport const mediaUsageCollectionDeletionItemSchema = z\n\t.object({\n\t\tcollectionId: z.string(),\n\t\tcollectionSlug: z.string(),\n\t\tstate: mediaUsageCollectionDeletionStateSchema,\n\t\tphase: mediaUsageCollectionDeletionPhaseSchema,\n\t\tattemptCount: z.number().int().min(0),\n\t\tnextAttemptAt: z.string(),\n\t\tleaseExpiresAt: z.string().nullable(),\n\t\tlastErrorCode: z.string().nullable(),\n\t\tupdatedAt: z.string(),\n\t})\n\t.meta({ id: \"MediaUsageCollectionDeletionItem\" });\nexport const mediaUsageCollectionDeletionListResponseSchema = z\n\t.object({\n\t\titems: z.array(mediaUsageCollectionDeletionItemSchema),\n\t\tnextCursor: z.string().optional(),\n\t})\n\t.meta({ id: \"MediaUsageCollectionDeletionListResponse\" });\nexport const mediaUsageCollectionDeletionRetryBody = z\n\t.object({ collectionId: boundedOpaqueMediaUsageId })\n\t.strict()\n\t.meta({ id: \"MediaUsageCollectionDeletionRetryBody\" });\nexport const mediaUsageCollectionDeletionRetryResponseSchema = z\n\t.object({\n\t\tchanged: z.boolean(),\n\t\titem: mediaUsageCollectionDeletionItemSchema,\n\t})\n\t.meta({ id: \"MediaUsageCollectionDeletionRetryResponse\" });\n\nexport type MediaUsageRepairRequest = z.infer<typeof mediaUsageRepairBody>;\nexport type MediaUsageRepairResponse = z.infer<typeof mediaUsageRepairResponseSchema>;\nexport type MediaUsageProgress = z.infer<typeof mediaUsageProgressSchema>;\nexport type MediaUsageProgressAdvanceResponse = z.infer<\n\ttypeof mediaUsageProgressAdvanceResponseSchema\n>;\nexport type MediaUsageWorkListQuery = z.infer<typeof mediaUsageWorkListQuery>;\nexport type MediaUsageWorkItem = z.infer<typeof mediaUsageWorkItemSchema>;\nexport type MediaUsageWorkListResponse = z.infer<typeof mediaUsageWorkListResponseSchema>;\nexport type MediaUsageWorkRetryRequest = z.infer<typeof mediaUsageWorkRetryBody>;\nexport type MediaUsageWorkRetryResponse = z.infer<typeof mediaUsageWorkRetryResponseSchema>;\nexport type MediaUsageActivationStatus = z.infer<typeof mediaUsageActivationStatusSchema>;\nexport type MediaUsageActivationAdvanceRequest = z.infer<typeof mediaUsageActivationAdvanceBody>;\nexport type MediaUsageActivationAdvanceResponse = z.infer<\n\ttypeof mediaUsageActivationAdvanceResponseSchema\n>;\nexport type MediaUsageCollectionDeletionListQuery = z.infer<\n\ttypeof mediaUsageCollectionDeletionListQuery\n>;\nexport type MediaUsageCollectionDeletionListResponse = z.infer<\n\ttypeof mediaUsageCollectionDeletionListResponseSchema\n>;\nexport type MediaUsageCollectionDeletionRetryRequest = z.infer<\n\ttypeof mediaUsageCollectionDeletionRetryBody\n>;\nexport type MediaUsageCollectionDeletionRetryResponse = z.infer<\n\ttypeof mediaUsageCollectionDeletionRetryResponseSchema\n>;\nexport type MediaUsageCoverageStatus = z.infer<typeof mediaUsageCoverageStatusSchema>;\nexport type MediaUsageCoverage = z.infer<typeof mediaUsageCoverageSchema>;\nexport type MediaUsageSummary = z.infer<typeof mediaUsageSummarySchema>;\nexport type MediaUsageOccurrenceDetail = z.infer<typeof mediaUsageOccurrenceDetailSchema>;\nexport type MediaUsageSourceDetail = z.infer<typeof mediaUsageSourceDetailSchema>;\nexport type MediaUsageEntryDetail = z.infer<typeof mediaUsageEntryDetailSchema>;\nexport type MediaUsageDetailsResponse = z.infer<typeof mediaUsageDetailsResponseSchema>;\n","import { z } from \"zod\";\n\nimport { isValidFocalPointUpdate } from \"#media/focal-point.js\";\n\nimport { cursorPaginationQuery } from \"./common.js\";\nimport { mediaUsageSummarySchema } from \"./media-usage.js\";\n\n// ---------------------------------------------------------------------------\n// Media: Input schemas\n// ---------------------------------------------------------------------------\n\n/**\n * Accepts a comma-separated string (from URL query params) or an array of\n * strings (from JSON body or programmatic use) and normalises to string[].\n */\nconst mimeTypeFilter = z\n\t.union([z.string(), z.array(z.string())])\n\t.transform((v) => {\n\t\tconst arr = Array.isArray(v) ? v : v.split(\",\");\n\t\treturn arr.map((s) => s.trim()).filter((s) => s.length > 0);\n\t})\n\t.optional();\n\nexport const mediaListQuery = cursorPaginationQuery\n\t.extend({\n\t\tpage: z.coerce.number().int().min(1).max(Number.MAX_SAFE_INTEGER).optional(),\n\t\tmimeType: mimeTypeFilter,\n\t\tfolderId: z\n\t\t\t.union([z.literal(\"unfiled\"), z.string().min(1).max(64)])\n\t\t\t.optional()\n\t\t\t.meta({\n\t\t\t\tdescription:\n\t\t\t\t\t\"Filter by a media folder ID. Use `unfiled` for the Main library; omit for all media.\",\n\t\t\t}),\n\t\t/** Case-insensitive filename substring search (also matches extensions). */\n\t\tq: z.string().trim().min(1).max(200).optional(),\n\t\tincludeUsage: z.literal(\"1\").optional().meta({\n\t\t\tdescription: \"Include a coverage-aware usage summary on each media item\",\n\t\t}),\n\t})\n\t.refine(({ cursor, page }) => cursor === undefined || page === undefined, {\n\t\tmessage: \"cursor and page cannot be used together\",\n\t\tpath: [\"page\"],\n\t})\n\t.meta({ id: \"MediaListQuery\" });\n\nexport const mediaGetQuery = z\n\t.object({\n\t\tincludeUsage: z.literal(\"1\").optional().meta({\n\t\t\tdescription: \"Include a coverage-aware usage summary on the media item\",\n\t\t}),\n\t})\n\t.meta({ id: \"MediaGetQuery\" });\n\nexport const mediaUpdateBody = z\n\t.object({\n\t\talt: z.string().optional(),\n\t\tcaption: z.string().optional(),\n\t\twidth: z.number().int().positive().optional(),\n\t\theight: z.number().int().positive().optional(),\n\t\tfolderId: z\n\t\t\t.union([z.literal(\"unfiled\"), z.string().min(1).max(64)])\n\t\t\t.nullable()\n\t\t\t.optional()\n\t\t\t.transform((value) => (value === \"unfiled\" ? null : value))\n\t\t\t.meta({\n\t\t\t\tdescription:\n\t\t\t\t\t\"Assign a media folder ID, or use null or `unfiled` to return the item to the Main library.\",\n\t\t\t}),\n\t\tfocalX: z.number().min(0).max(1).nullable().optional(),\n\t\tfocalY: z.number().min(0).max(1).nullable().optional(),\n\t})\n\t.superRefine((value, context) => {\n\t\tif (!isValidFocalPointUpdate(value)) {\n\t\t\tcontext.addIssue({\n\t\t\t\tcode: \"custom\",\n\t\t\t\tmessage: \"focalX and focalY must both be numbers or both be null\",\n\t\t\t\tpath: [\"focalX\"],\n\t\t\t});\n\t\t}\n\t})\n\t.meta({ id: \"MediaUpdateBody\" });\n\nexport const mediaFolderIdSchema = z.string().min(1).max(64);\n\nexport const mediaFolderListQuery = cursorPaginationQuery\n\t.extend({ q: z.string().trim().min(1).max(200).optional() })\n\t.meta({ id: \"MediaFolderListQuery\" });\n\nconst mediaFolderNameSchema = z.string().refine(\n\t(value) => {\n\t\tconst length = value.trim().length;\n\t\treturn length >= 1 && length <= 200;\n\t},\n\t{ message: \"Folder name must be between 1 and 200 characters\" },\n);\n\nexport const mediaFolderBody = z\n\t.object({ name: mediaFolderNameSchema })\n\t.meta({ id: \"MediaFolderBody\" });\n\n/** Default maximum allowed file upload size (50 MB). */\nexport const DEFAULT_MAX_UPLOAD_SIZE = 50 * 1024 * 1024;\n\nexport function formatFileSize(bytes: number): string {\n\tif (bytes < 1024) return `${bytes}B`;\n\tif (bytes < 1024 * 1024) return `${Math.floor(bytes / 1024)}KB`;\n\treturn `${Math.floor(bytes / 1024 / 1024)}MB`;\n}\n\n// Matches a full MIME type (type/subtype) with an optional semicolon-delimited\n// parameter section. Forbids CR/LF to prevent header injection.\nexport const CONTENT_TYPE_RE = /^[a-z0-9][a-z0-9!#$&^_+\\-.]*\\/[a-z0-9!#$&^_+\\-.]+(\\s*;[^\\r\\n]*)?$/i;\n\nexport function mediaUploadUrlBody(maxSize: number) {\n\tif (!Number.isFinite(maxSize) || maxSize <= 0) {\n\t\tthrow new Error(`EmDash: maxUploadSize must be a positive finite number, got ${maxSize}`);\n\t}\n\treturn z\n\t\t.object({\n\t\t\tfilename: z.string().min(1, \"filename is required\"),\n\t\t\tcontentType: z\n\t\t\t\t.string()\n\t\t\t\t.min(1, \"contentType is required\")\n\t\t\t\t.regex(CONTENT_TYPE_RE, \"Invalid content type\"),\n\t\t\tsize: z\n\t\t\t\t.number()\n\t\t\t\t.int()\n\t\t\t\t.nonnegative()\n\t\t\t\t.max(maxSize, `File size must not exceed ${formatFileSize(maxSize)}`),\n\t\t\tcontentHash: z.string().optional(),\n\t\t\tfieldId: z.string().optional(),\n\t\t})\n\t\t.meta({ id: \"MediaUploadUrlBody\" });\n}\n\nexport const mediaConfirmBody = z\n\t.object({\n\t\tsize: z.number().int().nonnegative().optional(),\n\t\twidth: z.number().int().positive().optional(),\n\t\theight: z.number().int().positive().optional(),\n\t})\n\t.meta({ id: \"MediaConfirmBody\" });\n\nexport const mediaProviderListQuery = cursorPaginationQuery\n\t.extend({\n\t\tquery: z.string().optional(),\n\t\tmimeType: mimeTypeFilter,\n\t})\n\t.meta({ id: \"MediaProviderListQuery\" });\n\n// ---------------------------------------------------------------------------\n// Media: Response schemas\n// ---------------------------------------------------------------------------\n\nconst mediaStatusSchema = z.enum([\"pending\", \"ready\", \"failed\"]);\n\nexport const mediaItemSchema = z\n\t.object({\n\t\tid: z.string(),\n\t\tfilename: z.string(),\n\t\tmimeType: z.string(),\n\t\tsize: z.number().nullable(),\n\t\twidth: z.number().nullable(),\n\t\theight: z.number().nullable(),\n\t\tfocalX: z.number().nullable(),\n\t\tfocalY: z.number().nullable(),\n\t\talt: z.string().nullable(),\n\t\tcaption: z.string().nullable(),\n\t\tstorageKey: z.string(),\n\t\tstatus: mediaStatusSchema,\n\t\tcontentHash: z.string().nullable(),\n\t\tblurhash: z.string().nullable(),\n\t\tdominantColor: z.string().nullable(),\n\t\tcreatedAt: z.string(),\n\t\tauthorId: z.string().nullable(),\n\t\tfolderId: z.string().nullable(),\n\t})\n\t.meta({ id: \"MediaItem\" });\n\nexport const mediaFolderSchema = z\n\t.object({ id: z.string(), name: z.string() })\n\t.meta({ id: \"MediaFolder\" });\n\nexport const mediaFolderResponseSchema = z\n\t.object({ item: mediaFolderSchema })\n\t.meta({ id: \"MediaFolderResponse\" });\n\nexport const mediaFolderListResponseSchema = z\n\t.object({ items: z.array(mediaFolderSchema), nextCursor: z.string().optional() })\n\t.meta({ id: \"MediaFolderListResponse\" });\n\nexport const mediaResponseSchema = z\n\t.object({ item: mediaItemSchema })\n\t.meta({ id: \"MediaResponse\" });\n\nexport const mediaReadItemSchema = mediaItemSchema\n\t.extend({ usage: mediaUsageSummarySchema.optional() })\n\t.meta({ id: \"MediaReadItem\" });\n\nexport const mediaReadResponseSchema = z\n\t.object({ item: mediaReadItemSchema })\n\t.meta({ id: \"MediaReadResponse\" });\n\nexport const mediaListReadItemSchema = mediaReadItemSchema\n\t.extend({ url: z.string() })\n\t.meta({ id: \"MediaListReadItem\" });\n\nexport const mediaListReadResponseSchema = z\n\t.object({\n\t\titems: z.array(mediaListReadItemSchema),\n\t\tnextCursor: z.string().optional(),\n\t\ttotalCount: z.number().int().nonnegative().optional(),\n\t})\n\t.meta({ id: \"MediaListReadResponse\" });\n\nexport const mediaListResponseSchema = z\n\t.object({\n\t\titems: z.array(mediaItemSchema),\n\t\tnextCursor: z.string().optional(),\n\t\ttotalCount: z.number().int().nonnegative().optional(),\n\t})\n\t.meta({ id: \"MediaListResponse\" });\n\nexport const mediaUploadUrlResponseSchema = z\n\t.object({\n\t\tuploadUrl: z.string(),\n\t\tmethod: z.literal(\"PUT\"),\n\t\theaders: z.record(z.string(), z.string()),\n\t\tmediaId: z.string(),\n\t\tstorageKey: z.string(),\n\t\texpiresAt: z.string(),\n\t})\n\t.meta({ id: \"MediaUploadUrlResponse\" });\n\nexport const mediaExistingResponseSchema = z\n\t.object({\n\t\texisting: z.literal(true),\n\t\tmediaId: z.string(),\n\t\tstorageKey: z.string(),\n\t\turl: z.string(),\n\t})\n\t.meta({ id: \"MediaExistingResponse\" });\n\nexport const mediaConfirmResponseSchema = z\n\t.object({\n\t\titem: mediaItemSchema.extend({ url: z.string() }),\n\t})\n\t.meta({ id: \"MediaConfirmResponse\" });\n\nexport const mediaStreamUploadResponseSchema = z\n\t.object({\n\t\tuploaded: z.literal(true),\n\t\tsize: z.number().int().nonnegative(),\n\t})\n\t.meta({ id: \"MediaStreamUploadResponse\" });\n"],"mappings":";;;;;;AASA,MAAa,oBAAoB,IAAI,IAAI;CAAC;CAAI;CAAI;CAAI;CAAI;CAAG,CAAC;;AAG9D,MAAa,YAAY,EAAE,OACzB,QAAQ,CACR,KAAK,CACL,QAAQ,MAAmC,kBAAkB,IAAI,EAAE,EAAE,EACrE,SAAS,qDACT,CAAC;;AAOH,MAAa,wBAAwB,EACnC,OAAO;CACP,QAAQ,EAAE,QAAQ,CAAC,IAAI,KAAK,CAAC,UAAU,CAAC,KAAK,EAAE,aAAa,gCAAgC,CAAC;CAC7F,OAAO,EAAE,OAAO,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,IAAI,IAAI,CAAC,UAAU,CAAC,QAAQ,GAAG,CAAC,KAAK,EAC1E,aAAa,yDACb,CAAC;CACF,CAAC,CACD,KAAK,EAAE,IAAI,yBAAyB,CAAC;;AAGvC,MAAa,wBAAwB,EACnC,OAAO;CACP,OAAO,EAAE,OAAO,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,IAAI,IAAI,CAAC,UAAU,CAAC,QAAQ,GAAG;CACrE,QAAQ,EAAE,OAAO,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,UAAU,CAAC,QAAQ,EAAE;CAC5D,CAAC,CACD,KAAK,EAAE,IAAI,yBAAyB,CAAC;;AAOvC,MAAa,cAAc;;AAG3B,MAAM,iBAAiB;;AAGvB,MAAa,UAAU,EACrB,QAAQ,CACR,KAAK,CACL,QAAQ,QAAQ,eAAe,KAAK,IAAI,EAAE,6BAA6B;;;;;;AAOzE,MAAa,aAAa,EAAE,QAAQ,CAAC,MAAM,qBAAqB,sBAAsB;;AAGtF,MAAa,oBAAoB,EAC/B,OAAO,EACP,QAAQ,WAAW,UAAU,EAC7B,CAAC,CACD,KAAK,EAAE,IAAI,qBAAqB,CAAC;;AAOnC,MAAa,iBAAiB,EAC5B,OAAO;CACP,SAAS,EAAE,QAAQ,MAAM,CAAC,KAAK,EAAE,aAAa,yCAAyC,CAAC;CACxF,OAAO,EAAE,OAAO;EACf,MAAM,EAAE,QAAQ,CAAC,KAAK;GAAE,aAAa;GAA+B,SAAS;GAAa,CAAC;EAC3F,SAAS,EAAE,QAAQ,CAAC,KAAK,EAAE,aAAa,gCAAgC,CAAC;EACzE,CAAC;CACF,CAAC,CACD,KAAK,EAAE,IAAI,YAAY,CAAC;;AAG1B,SAAgB,gBAAqC,YAAe;AACnE,QAAO,EAAE,OAAO;EACf,SAAS,EAAE,QAAQ,KAAK,CAAC,KAAK,EAAE,aAAa,yCAAyC,CAAC;EACvF,MAAM;EACN,CAAC;;;AAIH,MAAa,uBAAuB,EAAE,OAAO,EAAE,SAAS,EAAE,QAAQ,KAAK,EAAE,CAAC,CAAC,KAAK,EAC/E,IAAI,kBACJ,CAAC;;AAGF,MAAa,sBAAsB,EACjC,OAAO,EAAE,OAAO,EAAE,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE,EAAE,CAAC,CAC1C,KAAK,EAAE,IAAI,iBAAiB,CAAC;;;;AClG/B,MAAa,iCAAiC,EAC5C,KAAK;CAAC;CAAY;CAAS;CAAW;CAAW;CAAU;CAAS;CAAU,CAAC,CAC/E,KAAK,EAAE,IAAI,4BAA4B,CAAC;AAE1C,MAAa,2BAA2B,EACtC,OAAO;CACP,OAAO,EAAE,QAAQ,0BAA0B;CAC3C,QAAQ;CACR,CAAC,CACD,KAAK,EAAE,IAAI,sBAAsB,CAAC;AAEpC,MAAa,2BAA2B,EACtC,OAAO;CACP,QAAQ,EAAE,KAAK;EAAC;EAAY;EAAS;EAAkB,CAAC;CACxD,kBAAkB,EAAE,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE;CACzC,kBAAkB,EAAE,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE;CACzC,CAAC,CACD,KAAK,EAAE,IAAI,sBAAsB,CAAC;AAEpC,MAAa,0BAA0B,EACrC,OAAO;CACP,OAAO,EAAE,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,UAAU;CACzC,UAAU;CACV,CAAC,CACD,KAAK,EAAE,IAAI,qBAAqB,CAAC;AAEnC,MAAa,yBAAyB,EAAE,OAAO;CAC9C,QAAQ,EAAE,QAAQ,CAAC,IAAI,EAAE,CAAC,IAAI,KAAK,CAAC,UAAU,CAAC,KAAK,EACnD,aAAa,qCACb,CAAC;CACF,OAAO,EAAE,OAAO,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,IAAI,IAAI,CAAC,UAAU,CAAC,QAAQ,GAAG,CAAC,KAAK,EAC1E,aAAa,wEACb,CAAC;CACF,CAAC;AAEF,MAAa,mCAAmC,EAC9C,OAAO;CACP,WAAW,EAAE,QAAQ;CACrB,WAAW,EAAE,QAAQ;CACrB,iBAAiB,EAAE,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE;CACxC,eAAe,EAAE,KAAK;EAAC;EAAe;EAAc;EAAuB;EAAU,CAAC;CACtF,CAAC,CACD,KAAK,EAAE,IAAI,8BAA8B,CAAC;AAE5C,MAAa,+BAA+B,EAC1C,OAAO;CACP,SAAS,EAAE,KAAK,CAAC,WAAW,gBAAgB,CAAC;CAC7C,aAAa,EAAE,MAAM,iCAAiC;CACtD,CAAC,CACD,KAAK,EAAE,IAAI,0BAA0B,CAAC;AAExC,MAAa,8BAA8B,EACzC,OAAO;CACP,YAAY,EAAE,QAAQ;CACtB,WAAW,EAAE,QAAQ;CACrB,OAAO,EAAE,QAAQ,CAAC,UAAU;CAC5B,MAAM,EAAE,QAAQ,CAAC,UAAU;CAC3B,QAAQ,EAAE,QAAQ,CAAC,UAAU;CAC7B,QAAQ,EAAE,QAAQ,CAAC,UAAU;CAC7B,aAAa,EAAE,QAAQ,CAAC,UAAU;CAClC,WAAW,EAAE,QAAQ,CAAC,UAAU;CAChC,SAAS,EAAE,MAAM,6BAA6B;CAC9C,CAAC,CACD,KAAK,EAAE,IAAI,yBAAyB,CAAC;AAEvC,MAAa,kCAAkC,EAC7C,OAAO;CACP,OAAO,EAAE,MAAM,4BAA4B;CAC3C,YAAY,EAAE,QAAQ,CAAC,UAAU;CACjC,UAAU;CACV,CAAC,CACD,KAAK,EAAE,IAAI,6BAA6B,CAAC;AAE3C,MAAa,+BAA+B,EAC1C,KAAK;CAAC;CAAY;CAAW;CAAU;CAAQ,CAAC,CAChD,KAAK,EAAE,IAAI,0BAA0B,CAAC;AAExC,MAAM,iCAAiC,EACrC,OAAO;CACP,OAAO,EAAE,QAAQ,aAAa;CAC9B,YAAY,EAAE,QAAQ,CAAC,IAAI,EAAE,CAAC,IAAI,GAAG,CAAC,MAAM,aAAa,0BAA0B;CACnF,CAAC,CACD,QAAQ;AAEV,MAAM,0BAA0B,EAAE,OAAO,EAAE,OAAO,EAAE,QAAQ,MAAM,EAAE,CAAC,CAAC,QAAQ;AAE9E,MAAa,uBAAuB,EAClC,mBAAmB,SAAS,CAAC,gCAAgC,wBAAwB,CAAC,CACtF,KAAK,EAAE,IAAI,wBAAwB,CAAC;AAEtC,MAAa,0CAA0C,EACrD,OAAO;CACP,YAAY,EAAE,QAAQ;CACtB,QAAQ;CACR,oBAAoB,EAAE,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE;CAC3C,mBAAmB,EAAE,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE;CAC1C,oBAAoB,EAAE,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE;CAC3C,oBAAoB,EAAE,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE;CAC3C,eAAe,EAAE,QAAQ,CAAC,UAAU;CACpC,WAAW,EAAE,QAAQ;CACrB,aAAa,EAAE,QAAQ,CAAC,UAAU;CAClC,CAAC,CACD,KAAK,EAAE,IAAI,qCAAqC,CAAC;AAEnD,MAAa,iCAAiC,EAC5C,OAAO;CACP,QAAQ;CACR,oBAAoB,EAAE,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE;CAC3C,mBAAmB,EAAE,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE;CAC1C,oBAAoB,EAAE,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE;CAC3C,oBAAoB,EAAE,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE;CAC3C,aAAa,EAAE,MAAM,wCAAwC;CAC7D,CAAC,CACD,KAAK,EAAE,IAAI,4BAA4B,CAAC;AAE1C,MAAa,4BAA4B,EACvC,KAAK;CAAC;CAAW;CAAS;CAAU;CAAS,CAAC,CAC9C,KAAK,EAAE,IAAI,uBAAuB,CAAC;AAErC,MAAa,0BAA0B,EAAE,OAAO;CAC/C,YAAY,EAAE,QAAQ,CAAC,IAAI,EAAE,CAAC,IAAI,GAAG,CAAC,MAAM,aAAa,0BAA0B;CACnF,OAAO,0BAA0B,UAAU;CAC3C,QAAQ,EAAE,QAAQ,CAAC,IAAI,EAAE,CAAC,IAAI,KAAK,CAAC,UAAU,CAAC,KAAK,EACnD,aAAa,2BACb,CAAC;CACF,OAAO,EAAE,OAAO,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,IAAI,IAAI,CAAC,UAAU,CAAC,QAAQ,GAAG,CAAC,KAAK,EAC1E,aAAa,8DACb,CAAC;CACF,CAAC;AAEF,MAAa,2BAA2B,EACtC,OAAO;CACP,cAAc,EAAE,QAAQ;CACxB,gBAAgB,EAAE,QAAQ;CAC1B,WAAW,EAAE,QAAQ;CACrB,OAAO;CACP,cAAc,EAAE,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE;CACrC,eAAe,EAAE,QAAQ;CACzB,gBAAgB,EAAE,QAAQ,CAAC,UAAU;CACrC,iBAAiB,EAAE,QAAQ,CAAC,UAAU;CACtC,eAAe,EAAE,QAAQ,CAAC,UAAU;CACpC,WAAW,EAAE,QAAQ;CACrB,CAAC,CACD,KAAK,EAAE,IAAI,sBAAsB,CAAC;AAEpC,MAAa,mCAAmC,EAC9C,OAAO;CACP,OAAO,EAAE,MAAM,yBAAyB;CACxC,YAAY,EAAE,QAAQ,CAAC,UAAU;CACjC,CAAC,CACD,KAAK,EAAE,IAAI,8BAA8B,CAAC;AAE5C,MAAM,4BAA4B,EAAE,QAAQ,CAAC,IAAI,EAAE,CAAC,IAAI,KAAK;AAE7D,MAAa,0BAA0B,EACrC,OAAO;CACP,cAAc,0BAA0B,KAAK,EAC5C,aAAa,yCACb,CAAC;CACF,WAAW,0BAA0B,KAAK,EACzC,aAAa,qDACb,CAAC;CACF,CAAC,CACD,QAAQ,CACR,KAAK,EAAE,IAAI,2BAA2B,CAAC;AAEzC,MAAa,oCAAoC,EAC/C,OAAO;CACP,SAAS,EAAE,SAAS;CACpB,MAAM;CACN,CAAC,CACD,KAAK,EAAE,IAAI,+BAA+B,CAAC;AAE7C,MAAa,oCAAoC,EAAE,OAAO;CACzD,SAAS,EAAE,QAAQ,MAAM;CACzB,OAAO,EAAE,mBAAmB,QAAQ,CACnC,EAAE,OAAO;EACR,MAAM,EAAE,QAAQ,oBAAoB;EACpC,SAAS,EAAE,QAAQ;EACnB,SAAS,EAAE,OAAO,EAAE,gBAAgB,EAAE,QAAQ,EAAE,CAAC;EACjD,CAAC,EACF,EAAE,OAAO;EACR,MAAM,EAAE,QAAQ,eAAe;EAC/B,SAAS,EAAE,QAAQ;EACnB,CAAC,CACF,CAAC;CACF,CAAC;AAEF,MAAa,kCAAkC,EAC7C,KAAK;CAAC;CAAY;CAAc;CAAS,CAAC,CAC1C,KAAK,EAAE,IAAI,6BAA6B,CAAC;AAE3C,MAAa,mCAAmC,EAC9C,OAAO;CACP,OAAO;CACP,kBAAkB,EAAE,QAAQ,CAAC,UAAU;CACvC,cAAc,EAAE,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE;CACrC,kBAAkB,EAAE,QAAQ,CAAC,UAAU;CACvC,iBAAiB,EAAE,QAAQ,CAAC,UAAU;CACtC,eAAe,EAAE,QAAQ,gCAAgC,CAAC,UAAU;CACpE,gBAAgB,EAAE,QAAQ,CAAC,UAAU;CACrC,aAAa,EAAE,QAAQ,CAAC,UAAU;CAClC,WAAW,EAAE,QAAQ;CACrB,CAAC,CACD,KAAK,EAAE,IAAI,8BAA8B,CAAC;AAE5C,MAAa,kCAAkC,EAC7C,OAAO,EACP,gBAAgB,EAAE,QAAQ,KAAK,EAC/B,CAAC,CACD,QAAQ,CACR,KAAK,EAAE,IAAI,mCAAmC,CAAC;AAEjD,MAAa,4CAA4C,EACvD,OAAO;CACP,SAAS,EAAE,KAAK,CAAC,cAAc,SAAS,CAAC;CACzC,sBAAsB,EAAE,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE;CACpD,YAAY;CACZ,CAAC,CACD,KAAK,EAAE,IAAI,uCAAuC,CAAC;AAErD,MAAa,0CAA0C,EACrD,OAAO;CACP,YAAY;CACZ,UAAU,yBAAyB,UAAU;CAC7C,iBAAiB,EAAE,MAAM;EAAC,EAAE,QAAQ,EAAE;EAAE,EAAE,QAAQ,IAAO;EAAE,EAAE,MAAM;EAAC,CAAC;CACrE,CAAC,CACD,KAAK,EAAE,IAAI,qCAAqC,CAAC;AAEnD,MAAa,qCAAqC,EAAE,OAAO;CAC1D,SAAS,EAAE,QAAQ,MAAM;CACzB,OAAO,EAAE,mBAAmB,QAAQ;EACnC,EAAE,OAAO;GACR,MAAM,EAAE,QAAQ,8BAA8B;GAC9C,SAAS,EAAE,QAAQ;GACnB,SAAS,EAAE,OAAO,EAAE,gBAAgB,EAAE,QAAQ,EAAE,CAAC;GACjD,CAAC;EACF,EAAE,OAAO;GACR,MAAM,EAAE,QAAQ,kCAAkC;GAClD,SAAS,EAAE,QAAQ;GACnB,CAAC;EACF,EAAE,OAAO;GACR,MAAM,EAAE,QAAQ,0CAA0C;GAC1D,SAAS,EAAE,QAAQ;GACnB,CAAC;EACF,CAAC;CACF,CAAC;AAEF,MAAa,0CAA0C,EACrD,KAAK;CAAC;CAAW;CAAS;CAAU;CAAS,CAAC,CAC9C,KAAK,EAAE,IAAI,qCAAqC,CAAC;AACnD,MAAa,0CAA0C,EACrD,KAAK;CAAC;CAAS;CAAY;CAAS;CAAQ;CAAW;CAAU;CAAW,CAAC,CAC7E,KAAK,EAAE,IAAI,qCAAqC,CAAC;AACnD,MAAa,wCAAwC,EACnD,OAAO;CACP,OAAO,wCAAwC,UAAU,CAAC,QAAQ,SAAS;CAC3E,QAAQ,EAAE,QAAQ,CAAC,IAAI,EAAE,CAAC,IAAI,KAAK,CAAC,UAAU;CAC9C,OAAO,EAAE,OAAO,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,IAAI,IAAI,CAAC,UAAU,CAAC,QAAQ,GAAG;CACrE,CAAC,CACD,KAAK,EAAE,IAAI,yCAAyC,CAAC;AACvD,MAAa,yCAAyC,EACpD,OAAO;CACP,cAAc,EAAE,QAAQ;CACxB,gBAAgB,EAAE,QAAQ;CAC1B,OAAO;CACP,OAAO;CACP,cAAc,EAAE,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE;CACrC,eAAe,EAAE,QAAQ;CACzB,gBAAgB,EAAE,QAAQ,CAAC,UAAU;CACrC,eAAe,EAAE,QAAQ,CAAC,UAAU;CACpC,WAAW,EAAE,QAAQ;CACrB,CAAC,CACD,KAAK,EAAE,IAAI,oCAAoC,CAAC;AAClD,MAAa,iDAAiD,EAC5D,OAAO;CACP,OAAO,EAAE,MAAM,uCAAuC;CACtD,YAAY,EAAE,QAAQ,CAAC,UAAU;CACjC,CAAC,CACD,KAAK,EAAE,IAAI,4CAA4C,CAAC;AAC1D,MAAa,wCAAwC,EACnD,OAAO,EAAE,cAAc,2BAA2B,CAAC,CACnD,QAAQ,CACR,KAAK,EAAE,IAAI,yCAAyC,CAAC;AACvD,MAAa,kDAAkD,EAC7D,OAAO;CACP,SAAS,EAAE,SAAS;CACpB,MAAM;CACN,CAAC,CACD,KAAK,EAAE,IAAI,6CAA6C,CAAC;;;;;;;;ACtR3D,MAAM,iBAAiB,EACrB,MAAM,CAAC,EAAE,QAAQ,EAAE,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC,CACxC,WAAW,MAAM;AAEjB,SADY,MAAM,QAAQ,EAAE,GAAG,IAAI,EAAE,MAAM,IAAI,EACpC,KAAK,MAAM,EAAE,MAAM,CAAC,CAAC,QAAQ,MAAM,EAAE,SAAS,EAAE;EAC1D,CACD,UAAU;AAEZ,MAAa,iBAAiB,sBAC5B,OAAO;CACP,MAAM,EAAE,OAAO,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,IAAI,OAAO,iBAAiB,CAAC,UAAU;CAC5E,UAAU;CACV,UAAU,EACR,MAAM,CAAC,EAAE,QAAQ,UAAU,EAAE,EAAE,QAAQ,CAAC,IAAI,EAAE,CAAC,IAAI,GAAG,CAAC,CAAC,CACxD,UAAU,CACV,KAAK,EACL,aACC,wFACD,CAAC;CAEH,GAAG,EAAE,QAAQ,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,IAAI,IAAI,CAAC,UAAU;CAC/C,cAAc,EAAE,QAAQ,IAAI,CAAC,UAAU,CAAC,KAAK,EAC5C,aAAa,6DACb,CAAC;CACF,CAAC,CACD,QAAQ,EAAE,QAAQ,WAAW,WAAW,UAAa,SAAS,QAAW;CACzE,SAAS;CACT,MAAM,CAAC,OAAO;CACd,CAAC,CACD,KAAK,EAAE,IAAI,kBAAkB,CAAC;AAEhC,MAAa,gBAAgB,EAC3B,OAAO,EACP,cAAc,EAAE,QAAQ,IAAI,CAAC,UAAU,CAAC,KAAK,EAC5C,aAAa,4DACb,CAAC,EACF,CAAC,CACD,KAAK,EAAE,IAAI,iBAAiB,CAAC;AAE/B,MAAa,kBAAkB,EAC7B,OAAO;CACP,KAAK,EAAE,QAAQ,CAAC,UAAU;CAC1B,SAAS,EAAE,QAAQ,CAAC,UAAU;CAC9B,OAAO,EAAE,QAAQ,CAAC,KAAK,CAAC,UAAU,CAAC,UAAU;CAC7C,QAAQ,EAAE,QAAQ,CAAC,KAAK,CAAC,UAAU,CAAC,UAAU;CAC9C,UAAU,EACR,MAAM,CAAC,EAAE,QAAQ,UAAU,EAAE,EAAE,QAAQ,CAAC,IAAI,EAAE,CAAC,IAAI,GAAG,CAAC,CAAC,CACxD,UAAU,CACV,UAAU,CACV,WAAW,UAAW,UAAU,YAAY,OAAO,MAAO,CAC1D,KAAK,EACL,aACC,8FACD,CAAC;CACH,QAAQ,EAAE,QAAQ,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC,UAAU,CAAC,UAAU;CACtD,QAAQ,EAAE,QAAQ,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC,UAAU,CAAC,UAAU;CACtD,CAAC,CACD,aAAa,OAAO,YAAY;AAChC,KAAI,CAAC,wBAAwB,MAAM,CAClC,SAAQ,SAAS;EAChB,MAAM;EACN,SAAS;EACT,MAAM,CAAC,SAAS;EAChB,CAAC;EAEF,CACD,KAAK,EAAE,IAAI,mBAAmB,CAAC;AAEjC,MAAa,sBAAsB,EAAE,QAAQ,CAAC,IAAI,EAAE,CAAC,IAAI,GAAG;AAE5D,MAAa,uBAAuB,sBAClC,OAAO,EAAE,GAAG,EAAE,QAAQ,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC,CAC3D,KAAK,EAAE,IAAI,wBAAwB,CAAC;AAEtC,MAAM,wBAAwB,EAAE,QAAQ,CAAC,QACvC,UAAU;CACV,MAAM,SAAS,MAAM,MAAM,CAAC;AAC5B,QAAO,UAAU,KAAK,UAAU;GAEjC,EAAE,SAAS,oDAAoD,CAC/D;AAED,MAAa,kBAAkB,EAC7B,OAAO,EAAE,MAAM,uBAAuB,CAAC,CACvC,KAAK,EAAE,IAAI,mBAAmB,CAAC;;AAGjC,MAAa,0BAA0B,KAAK,OAAO;AAEnD,SAAgB,eAAe,OAAuB;AACrD,KAAI,QAAQ,KAAM,QAAO,GAAG,MAAM;AAClC,KAAI,QAAQ,OAAO,KAAM,QAAO,GAAG,KAAK,MAAM,QAAQ,KAAK,CAAC;AAC5D,QAAO,GAAG,KAAK,MAAM,QAAQ,OAAO,KAAK,CAAC;;AAK3C,MAAa,kBAAkB;AAE/B,SAAgB,mBAAmB,SAAiB;AACnD,KAAI,CAAC,OAAO,SAAS,QAAQ,IAAI,WAAW,EAC3C,OAAM,IAAI,MAAM,+DAA+D,UAAU;AAE1F,QAAO,EACL,OAAO;EACP,UAAU,EAAE,QAAQ,CAAC,IAAI,GAAG,uBAAuB;EACnD,aAAa,EACX,QAAQ,CACR,IAAI,GAAG,0BAA0B,CACjC,MAAM,iBAAiB,uBAAuB;EAChD,MAAM,EACJ,QAAQ,CACR,KAAK,CACL,aAAa,CACb,IAAI,SAAS,6BAA6B,eAAe,QAAQ,GAAG;EACtE,aAAa,EAAE,QAAQ,CAAC,UAAU;EAClC,SAAS,EAAE,QAAQ,CAAC,UAAU;EAC9B,CAAC,CACD,KAAK,EAAE,IAAI,sBAAsB,CAAC;;AAGrC,MAAa,mBAAmB,EAC9B,OAAO;CACP,MAAM,EAAE,QAAQ,CAAC,KAAK,CAAC,aAAa,CAAC,UAAU;CAC/C,OAAO,EAAE,QAAQ,CAAC,KAAK,CAAC,UAAU,CAAC,UAAU;CAC7C,QAAQ,EAAE,QAAQ,CAAC,KAAK,CAAC,UAAU,CAAC,UAAU;CAC9C,CAAC,CACD,KAAK,EAAE,IAAI,oBAAoB,CAAC;AAElC,MAAa,yBAAyB,sBACpC,OAAO;CACP,OAAO,EAAE,QAAQ,CAAC,UAAU;CAC5B,UAAU;CACV,CAAC,CACD,KAAK,EAAE,IAAI,0BAA0B,CAAC;AAMxC,MAAM,oBAAoB,EAAE,KAAK;CAAC;CAAW;CAAS;CAAS,CAAC;AAEhE,MAAa,kBAAkB,EAC7B,OAAO;CACP,IAAI,EAAE,QAAQ;CACd,UAAU,EAAE,QAAQ;CACpB,UAAU,EAAE,QAAQ;CACpB,MAAM,EAAE,QAAQ,CAAC,UAAU;CAC3B,OAAO,EAAE,QAAQ,CAAC,UAAU;CAC5B,QAAQ,EAAE,QAAQ,CAAC,UAAU;CAC7B,QAAQ,EAAE,QAAQ,CAAC,UAAU;CAC7B,QAAQ,EAAE,QAAQ,CAAC,UAAU;CAC7B,KAAK,EAAE,QAAQ,CAAC,UAAU;CAC1B,SAAS,EAAE,QAAQ,CAAC,UAAU;CAC9B,YAAY,EAAE,QAAQ;CACtB,QAAQ;CACR,aAAa,EAAE,QAAQ,CAAC,UAAU;CAClC,UAAU,EAAE,QAAQ,CAAC,UAAU;CAC/B,eAAe,EAAE,QAAQ,CAAC,UAAU;CACpC,WAAW,EAAE,QAAQ;CACrB,UAAU,EAAE,QAAQ,CAAC,UAAU;CAC/B,UAAU,EAAE,QAAQ,CAAC,UAAU;CAC/B,CAAC,CACD,KAAK,EAAE,IAAI,aAAa,CAAC;AAE3B,MAAa,oBAAoB,EAC/B,OAAO;CAAE,IAAI,EAAE,QAAQ;CAAE,MAAM,EAAE,QAAQ;CAAE,CAAC,CAC5C,KAAK,EAAE,IAAI,eAAe,CAAC;AAE7B,MAAa,4BAA4B,EACvC,OAAO,EAAE,MAAM,mBAAmB,CAAC,CACnC,KAAK,EAAE,IAAI,uBAAuB,CAAC;AAErC,MAAa,gCAAgC,EAC3C,OAAO;CAAE,OAAO,EAAE,MAAM,kBAAkB;CAAE,YAAY,EAAE,QAAQ,CAAC,UAAU;CAAE,CAAC,CAChF,KAAK,EAAE,IAAI,2BAA2B,CAAC;AAEzC,MAAa,sBAAsB,EACjC,OAAO,EAAE,MAAM,iBAAiB,CAAC,CACjC,KAAK,EAAE,IAAI,iBAAiB,CAAC;AAE/B,MAAa,sBAAsB,gBACjC,OAAO,EAAE,OAAO,wBAAwB,UAAU,EAAE,CAAC,CACrD,KAAK,EAAE,IAAI,iBAAiB,CAAC;AAE/B,MAAa,0BAA0B,EACrC,OAAO,EAAE,MAAM,qBAAqB,CAAC,CACrC,KAAK,EAAE,IAAI,qBAAqB,CAAC;AAEnC,MAAa,0BAA0B,oBACrC,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,CAC3B,KAAK,EAAE,IAAI,qBAAqB,CAAC;AAEnC,MAAa,8BAA8B,EACzC,OAAO;CACP,OAAO,EAAE,MAAM,wBAAwB;CACvC,YAAY,EAAE,QAAQ,CAAC,UAAU;CACjC,YAAY,EAAE,QAAQ,CAAC,KAAK,CAAC,aAAa,CAAC,UAAU;CACrD,CAAC,CACD,KAAK,EAAE,IAAI,yBAAyB,CAAC;AAEvC,MAAa,0BAA0B,EACrC,OAAO;CACP,OAAO,EAAE,MAAM,gBAAgB;CAC/B,YAAY,EAAE,QAAQ,CAAC,UAAU;CACjC,YAAY,EAAE,QAAQ,CAAC,KAAK,CAAC,aAAa,CAAC,UAAU;CACrD,CAAC,CACD,KAAK,EAAE,IAAI,qBAAqB,CAAC;AAEnC,MAAa,+BAA+B,EAC1C,OAAO;CACP,WAAW,EAAE,QAAQ;CACrB,QAAQ,EAAE,QAAQ,MAAM;CACxB,SAAS,EAAE,OAAO,EAAE,QAAQ,EAAE,EAAE,QAAQ,CAAC;CACzC,SAAS,EAAE,QAAQ;CACnB,YAAY,EAAE,QAAQ;CACtB,WAAW,EAAE,QAAQ;CACrB,CAAC,CACD,KAAK,EAAE,IAAI,0BAA0B,CAAC;AAExC,MAAa,8BAA8B,EACzC,OAAO;CACP,UAAU,EAAE,QAAQ,KAAK;CACzB,SAAS,EAAE,QAAQ;CACnB,YAAY,EAAE,QAAQ;CACtB,KAAK,EAAE,QAAQ;CACf,CAAC,CACD,KAAK,EAAE,IAAI,yBAAyB,CAAC;AAEvC,MAAa,6BAA6B,EACxC,OAAO,EACP,MAAM,gBAAgB,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,EACjD,CAAC,CACD,KAAK,EAAE,IAAI,wBAAwB,CAAC;AAEtC,MAAa,kCAAkC,EAC7C,OAAO;CACP,UAAU,EAAE,QAAQ,KAAK;CACzB,MAAM,EAAE,QAAQ,CAAC,KAAK,CAAC,aAAa;CACpC,CAAC,CACD,KAAK,EAAE,IAAI,6BAA6B,CAAC"}
@@ -1,4 +1,5 @@
1
1
  import { o as decodeCursor, s as encodeCursor } from "./types-CQPWhPxE.mjs";
2
+ import { n as normalizeFocalPoint } from "./focal-point-BeWFo6Xx.mjs";
2
3
  import { sql } from "kysely";
3
4
  import { ulid } from "ulidx";
4
5
 
@@ -45,6 +46,8 @@ var MediaRepository = class {
45
46
  size: input.size ?? null,
46
47
  width: input.width ?? null,
47
48
  height: input.height ?? null,
49
+ focal_x: null,
50
+ focal_y: null,
48
51
  alt: input.alt ?? null,
49
52
  caption: input.caption ?? null,
50
53
  storage_key: input.storageKey,
@@ -53,7 +56,8 @@ var MediaRepository = class {
53
56
  dominant_color: input.dominantColor ?? null,
54
57
  status: input.status ?? "ready",
55
58
  created_at: now,
56
- author_id: input.authorId ?? null
59
+ author_id: input.authorId ?? null,
60
+ folder_id: null
57
61
  };
58
62
  await this.db.insertInto("media").values(row).execute();
59
63
  return this.rowToItem(row);
@@ -161,19 +165,11 @@ var MediaRepository = class {
161
165
  */
162
166
  async findMany(options = {}) {
163
167
  const limit = Math.min(options.limit || 50, 100);
164
- let query = this.db.selectFrom("media").selectAll().orderBy("created_at", "desc").orderBy("id", "desc").limit(limit + 1);
168
+ let query = this.applyListFilters(this.db.selectFrom("media"), options).selectAll().orderBy("created_at", "desc").orderBy("id", "desc").limit(limit + 1);
165
169
  if (options.cursor) {
166
170
  const { orderValue: createdAt, id: cursorId } = decodeCursor(options.cursor);
167
171
  query = query.where((eb) => eb.or([eb("created_at", "<", createdAt), eb.and([eb("created_at", "=", createdAt), eb("id", "<", cursorId)])]));
168
172
  }
169
- const mimeFilters = normalizeMimeFilter(options.mimeType);
170
- if (mimeFilters.length > 0) query = query.where((eb) => mimeMatchExpr(eb, mimeFilters));
171
- const term = options.q?.trim();
172
- if (term) {
173
- const pattern = `%${escapeLike(term)}%`;
174
- query = query.where(sql`lower(filename)`, "like", sql`lower(${pattern}) escape '\\'`);
175
- }
176
- if (options.status !== "all") query = query.where("status", "=", options.status ?? "ready");
177
173
  const rows = await query.execute();
178
174
  const hasMore = rows.length > limit;
179
175
  const items = rows.slice(0, limit).map((row) => this.rowToItem(row));
@@ -187,6 +183,17 @@ var MediaRepository = class {
187
183
  nextCursor
188
184
  };
189
185
  }
186
+ async findPage(options) {
187
+ const limit = Math.min(options.limit || 50, 100);
188
+ const offset = (options.page - 1) * limit;
189
+ const filtered = this.applyListFilters(this.db.selectFrom("media"), options);
190
+ const rows = await filtered.selectAll().orderBy("created_at", "desc").orderBy("id", "desc").limit(limit).offset(offset).execute();
191
+ const count = await filtered.select((eb) => eb.fn.count("id").as("count")).executeTakeFirst();
192
+ return {
193
+ items: rows.map((row) => this.rowToItem(row)),
194
+ totalCount: Number(count?.count ?? 0)
195
+ };
196
+ }
190
197
  /**
191
198
  * Update media metadata
192
199
  */
@@ -197,6 +204,11 @@ var MediaRepository = class {
197
204
  if (input.caption !== void 0) updates.caption = input.caption;
198
205
  if (input.width !== void 0) updates.width = input.width;
199
206
  if (input.height !== void 0) updates.height = input.height;
207
+ if (input.folderId !== void 0) updates.folder_id = input.folderId;
208
+ if (input.focalX !== void 0 && input.focalY !== void 0) {
209
+ updates.focal_x = input.focalX;
210
+ updates.focal_y = input.focalY;
211
+ }
200
212
  if (Object.keys(updates).length > 0) await this.db.updateTable("media").set(updates).where("id", "=", id).execute();
201
213
  return this.findById(id);
202
214
  }
@@ -221,6 +233,19 @@ var MediaRepository = class {
221
233
  const result = await query.executeTakeFirst();
222
234
  return Number(result?.count || 0);
223
235
  }
236
+ applyListFilters(query, options) {
237
+ const mimeFilters = normalizeMimeFilter(options.mimeType);
238
+ if (mimeFilters.length > 0) query = query.where((eb) => mimeMatchExpr(eb, mimeFilters));
239
+ const term = options.q?.trim();
240
+ if (term) {
241
+ const pattern = `%${escapeLike(term)}%`;
242
+ query = query.where(sql`lower(filename)`, "like", sql`lower(${pattern}) escape '\\'`);
243
+ }
244
+ if (options.status !== "all") query = query.where("status", "=", options.status ?? "ready");
245
+ if (options.folderId === null) query = query.where("folder_id", "is", null);
246
+ else if (options.folderId !== void 0) query = query.where("folder_id", "=", options.folderId);
247
+ return query;
248
+ }
224
249
  /**
225
250
  * Delete pending uploads older than the given age.
226
251
  * Pending uploads that were never confirmed indicate abandoned upload flows.
@@ -236,6 +261,7 @@ var MediaRepository = class {
236
261
  * Convert database row to MediaItem
237
262
  */
238
263
  rowToItem(row) {
264
+ const focalPoint = normalizeFocalPoint(row.focal_x, row.focal_y);
239
265
  return {
240
266
  id: row.id,
241
267
  filename: row.filename,
@@ -243,6 +269,8 @@ var MediaRepository = class {
243
269
  size: row.size,
244
270
  width: row.width,
245
271
  height: row.height,
272
+ focalX: focalPoint?.focalX ?? null,
273
+ focalY: focalPoint?.focalY ?? null,
246
274
  alt: row.alt,
247
275
  caption: row.caption,
248
276
  storageKey: row.storage_key,
@@ -251,11 +279,12 @@ var MediaRepository = class {
251
279
  dominantColor: row.dominant_color,
252
280
  status: row.status,
253
281
  createdAt: row.created_at,
254
- authorId: row.author_id
282
+ authorId: row.author_id,
283
+ folderId: row.folder_id
255
284
  };
256
285
  }
257
286
  };
258
287
 
259
288
  //#endregion
260
289
  export { MediaRepository as t };
261
- //# sourceMappingURL=media-CzhAn2--.mjs.map
290
+ //# sourceMappingURL=media-D6SeAfBl.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"media-D6SeAfBl.mjs","names":[],"sources":["../src/database/repositories/media.ts"],"sourcesContent":["import {\n\tsql,\n\ttype ExpressionBuilder,\n\ttype Kysely,\n\ttype SelectQueryBuilder,\n\ttype SqlBool,\n} from \"kysely\";\nimport { ulid } from \"ulidx\";\n\nimport { normalizeFocalPoint, type FocalPointUpdate } from \"../../media/focal-point.js\";\nimport type { Database, MediaRow } from \"../types.js\";\nimport type { FindManyResult } from \"./types.js\";\nimport { encodeCursor, decodeCursor } from \"./types.js\";\n\n/** Escape LIKE wildcard characters and the escape char itself in user-supplied values */\nfunction escapeLike(value: string): string {\n\treturn value.replaceAll(\"\\\\\", \"\\\\\\\\\").replaceAll(\"%\", \"\\\\%\").replaceAll(\"_\", \"\\\\_\");\n}\n\n/**\n * Normalize a mimeType filter (string or array) into a clean string[].\n * Entries that are empty strings are dropped.\n */\nfunction normalizeMimeFilter(input?: string | readonly string[]): string[] {\n\tif (!input) return [];\n\tconst arr = Array.isArray(input) ? input : [input];\n\treturn arr\n\t\t.filter((entry): entry is string => typeof entry === \"string\" && entry.length > 0)\n\t\t.map((entry) =>\n\t\t\tentry.endsWith(\"/\") ? entry.toLowerCase() : entry.split(\";\")[0].trim().toLowerCase(),\n\t\t);\n}\n\n/**\n * Build a WHERE clause that matches `mime_type` against any of the given\n * filter entries — exact equality for full MIMEs, LIKE prefix for entries\n * ending in \"/\".\n */\nfunction mimeMatchExpr(eb: ExpressionBuilder<Database, \"media\">, filters: string[]) {\n\treturn eb.or(\n\t\tfilters.map((entry) =>\n\t\t\tentry.endsWith(\"/\")\n\t\t\t\t? sql<SqlBool>`mime_type LIKE ${`${escapeLike(entry)}%`} ESCAPE '\\\\'`\n\t\t\t\t: eb(\"mime_type\", \"=\", entry),\n\t\t),\n\t);\n}\n\nexport type MediaStatus = \"pending\" | \"ready\" | \"failed\";\n\nexport interface MediaItem {\n\tid: string;\n\tfilename: string;\n\tmimeType: string;\n\tsize: number | null;\n\twidth: number | null;\n\theight: number | null;\n\tfocalX: number | null;\n\tfocalY: number | null;\n\talt: string | null;\n\tcaption: string | null;\n\tstorageKey: string;\n\tstatus: MediaStatus;\n\tcontentHash: string | null;\n\tblurhash: string | null;\n\tdominantColor: string | null;\n\tcreatedAt: string;\n\tauthorId: string | null;\n\tfolderId?: string | null;\n}\n\nexport interface CreateMediaInput {\n\tfilename: string;\n\tmimeType: string;\n\tsize?: number;\n\twidth?: number;\n\theight?: number;\n\talt?: string;\n\tcaption?: string;\n\tstorageKey: string;\n\tcontentHash?: string;\n\tblurhash?: string;\n\tdominantColor?: string;\n\tstatus?: MediaStatus;\n\tauthorId?: string;\n}\n\nexport interface FindManyMediaOptions {\n\tlimit?: number;\n\tcursor?: string;\n\t/** Filter by MIME type. Pass a string for a single prefix/exact, or an array to match any. Strings ending with \"/\" are treated as LIKE prefix matches; others are exact equality. */\n\tmimeType?: string | readonly string[];\n\tstatus?: MediaStatus | \"all\"; // Filter by status, defaults to \"ready\"\n\t/** Case-insensitive substring matched against the filename (covers filename and extension). */\n\tq?: string;\n\t/** Omit for all media, pass null for the Main library, or pass a folder ID. */\n\tfolderId?: string | null;\n}\n\nexport interface UpdateMediaInput extends FocalPointUpdate {\n\talt?: string;\n\tcaption?: string;\n\twidth?: number;\n\theight?: number;\n\tfolderId?: string | null;\n}\n\nexport interface FindMediaPageOptions extends Omit<FindManyMediaOptions, \"cursor\"> {\n\tpage: number;\n}\n\nexport interface MediaPageResult {\n\titems: MediaItem[];\n\ttotalCount: number;\n}\n\nconst UPLOAD_ATTEMPT_CLEANUP_AGE_MS = 60 * 60 * 1000;\nconst UPLOAD_ATTEMPT_CLEANUP_BATCH_SIZE = 100;\n\n/**\n * Media repository for database operations\n */\nexport class MediaRepository {\n\tconstructor(private db: Kysely<Database>) {}\n\n\t/**\n\t * Create a new media item\n\t */\n\tasync create(input: CreateMediaInput): Promise<MediaItem> {\n\t\tconst id = ulid();\n\t\tconst now = new Date().toISOString();\n\n\t\tconst row: Omit<MediaRow, \"rowid\"> = {\n\t\t\tid,\n\t\t\tfilename: input.filename,\n\t\t\tmime_type: input.mimeType,\n\t\t\tsize: input.size ?? null,\n\t\t\twidth: input.width ?? null,\n\t\t\theight: input.height ?? null,\n\t\t\tfocal_x: null,\n\t\t\tfocal_y: null,\n\t\t\talt: input.alt ?? null,\n\t\t\tcaption: input.caption ?? null,\n\t\t\tstorage_key: input.storageKey,\n\t\t\tcontent_hash: input.contentHash ?? null,\n\t\t\tblurhash: input.blurhash ?? null,\n\t\t\tdominant_color: input.dominantColor ?? null,\n\t\t\tstatus: input.status ?? \"ready\",\n\t\t\tcreated_at: now,\n\t\t\tauthor_id: input.authorId ?? null,\n\t\t\tfolder_id: null,\n\t\t};\n\n\t\tawait this.db.insertInto(\"media\").values(row).execute();\n\n\t\treturn this.rowToItem(row);\n\t}\n\n\t/**\n\t * Create a pending media item (for signed URL upload flow)\n\t */\n\tasync createPending(input: {\n\t\tfilename: string;\n\t\tmimeType: string;\n\t\tsize?: number;\n\t\tstorageKey: string;\n\t\tcontentHash?: string;\n\t\tauthorId?: string;\n\t}): Promise<MediaItem> {\n\t\treturn this.create({\n\t\t\t...input,\n\t\t\tstatus: \"pending\",\n\t\t});\n\t}\n\n\tasync createUploadAttempt(mediaId: string, storageKey: string): Promise<void> {\n\t\tconst now = new Date().toISOString();\n\t\tawait this.db\n\t\t\t.insertInto(\"_emdash_media_upload_attempts\")\n\t\t\t.values({\n\t\t\t\tmedia_id: mediaId,\n\t\t\t\tstorage_key: storageKey,\n\t\t\t\tstatus: \"active\",\n\t\t\t\tcreated_at: now,\n\t\t\t\tupdated_at: now,\n\t\t\t})\n\t\t\t.execute();\n\t}\n\n\tasync hasUploadAttempt(storageKey: string): Promise<boolean> {\n\t\tconst row = await this.db\n\t\t\t.selectFrom(\"_emdash_media_upload_attempts\")\n\t\t\t.select(\"storage_key\")\n\t\t\t.where(\"storage_key\", \"=\", storageKey)\n\t\t\t.executeTakeFirst();\n\t\treturn row !== undefined;\n\t}\n\n\tasync claimUploadAttemptForCleanup(storageKey: string): Promise<boolean> {\n\t\tconst result = await this.db\n\t\t\t.updateTable(\"_emdash_media_upload_attempts\")\n\t\t\t.set({ status: \"cleanup\", updated_at: new Date().toISOString() })\n\t\t\t.where(\"storage_key\", \"=\", storageKey)\n\t\t\t.where((eb) =>\n\t\t\t\teb.not(\n\t\t\t\t\teb.exists(\n\t\t\t\t\t\teb\n\t\t\t\t\t\t\t.selectFrom(\"media\")\n\t\t\t\t\t\t\t.select(\"media.id\")\n\t\t\t\t\t\t\t.whereRef(\"media.storage_key\", \"=\", \"_emdash_media_upload_attempts.storage_key\"),\n\t\t\t\t\t),\n\t\t\t\t),\n\t\t\t)\n\t\t\t.executeTakeFirst();\n\n\t\treturn Number(result.numUpdatedRows ?? 0) > 0;\n\t}\n\n\tasync deleteUploadAttempt(storageKey: string): Promise<void> {\n\t\tawait this.db\n\t\t\t.deleteFrom(\"_emdash_media_upload_attempts\")\n\t\t\t.where(\"storage_key\", \"=\", storageKey)\n\t\t\t.execute();\n\t}\n\n\tasync deleteCompletedUploadAttempts(): Promise<number> {\n\t\tconst result = await this.db\n\t\t\t.deleteFrom(\"_emdash_media_upload_attempts\")\n\t\t\t.where((eb) =>\n\t\t\t\teb.exists(\n\t\t\t\t\teb\n\t\t\t\t\t\t.selectFrom(\"media\")\n\t\t\t\t\t\t.select(\"media.id\")\n\t\t\t\t\t\t.whereRef(\"media.id\", \"=\", \"_emdash_media_upload_attempts.media_id\")\n\t\t\t\t\t\t.whereRef(\"media.storage_key\", \"=\", \"_emdash_media_upload_attempts.storage_key\")\n\t\t\t\t\t\t.where(\"media.status\", \"=\", \"ready\"),\n\t\t\t\t),\n\t\t\t)\n\t\t\t.executeTakeFirst();\n\t\treturn Number(result.numDeletedRows ?? 0);\n\t}\n\n\tasync findUploadAttemptsForCleanup(\n\t\tmaxAgeMs: number = UPLOAD_ATTEMPT_CLEANUP_AGE_MS,\n\t\tlimit: number = UPLOAD_ATTEMPT_CLEANUP_BATCH_SIZE,\n\t): Promise<string[]> {\n\t\tconst cutoff = new Date(Date.now() - maxAgeMs).toISOString();\n\t\tconst rows = await this.db\n\t\t\t.selectFrom(\"_emdash_media_upload_attempts\")\n\t\t\t.select(\"storage_key\")\n\t\t\t.where((eb) => eb.or([eb(\"status\", \"=\", \"cleanup\"), eb(\"created_at\", \"<\", cutoff)]))\n\t\t\t.where((eb) =>\n\t\t\t\teb.not(\n\t\t\t\t\teb.exists(\n\t\t\t\t\t\teb\n\t\t\t\t\t\t\t.selectFrom(\"media\")\n\t\t\t\t\t\t\t.select(\"media.id\")\n\t\t\t\t\t\t\t.whereRef(\"media.storage_key\", \"=\", \"_emdash_media_upload_attempts.storage_key\"),\n\t\t\t\t\t),\n\t\t\t\t),\n\t\t\t)\n\t\t\t.orderBy(\"created_at\", \"asc\")\n\t\t\t.limit(limit)\n\t\t\t.execute();\n\n\t\treturn rows.map((row) => row.storage_key);\n\t}\n\n\tasync publishPendingStorageKey(\n\t\tid: string,\n\t\texpectedStorageKey: string,\n\t\tstorageKey: string,\n\t\tcontentHash?: string,\n\t): Promise<boolean> {\n\t\tconst result = await this.db\n\t\t\t.updateTable(\"media\")\n\t\t\t.set({\n\t\t\t\tstorage_key: storageKey,\n\t\t\t\t...(contentHash !== undefined ? { content_hash: contentHash } : {}),\n\t\t\t})\n\t\t\t.where(\"id\", \"=\", id)\n\t\t\t.where(\"status\", \"=\", \"pending\")\n\t\t\t.where(\"storage_key\", \"=\", expectedStorageKey)\n\t\t\t.where((eb) =>\n\t\t\t\teb.exists(\n\t\t\t\t\teb\n\t\t\t\t\t\t.selectFrom(\"_emdash_media_upload_attempts\")\n\t\t\t\t\t\t.select(\"storage_key\")\n\t\t\t\t\t\t.where(\"media_id\", \"=\", id)\n\t\t\t\t\t\t.where(\"storage_key\", \"=\", storageKey)\n\t\t\t\t\t\t.where(\"status\", \"=\", \"active\"),\n\t\t\t\t),\n\t\t\t)\n\t\t\t.executeTakeFirst();\n\n\t\treturn Number(result.numUpdatedRows ?? 0) > 0;\n\t}\n\n\t/**\n\t * Confirm upload (mark as ready)\n\t */\n\tasync confirmUpload(\n\t\tid: string,\n\t\tmetadata?: {\n\t\t\twidth?: number;\n\t\t\theight?: number;\n\t\t\tsize?: number;\n\t\t\tblurhash?: string;\n\t\t\tdominantColor?: string;\n\t\t\tcontentHash?: string | null;\n\t\t},\n\t\texpectedStorageKey?: string,\n\t): Promise<MediaItem | null> {\n\t\tconst updates: Partial<MediaRow> = {\n\t\t\tstatus: \"ready\",\n\t\t};\n\t\tif (metadata?.width !== undefined) updates.width = metadata.width;\n\t\tif (metadata?.height !== undefined) updates.height = metadata.height;\n\t\tif (metadata?.size !== undefined) updates.size = metadata.size;\n\t\tif (metadata?.blurhash !== undefined) updates.blurhash = metadata.blurhash;\n\t\tif (metadata?.dominantColor !== undefined) updates.dominant_color = metadata.dominantColor;\n\t\tif (metadata?.contentHash !== undefined) updates.content_hash = metadata.contentHash;\n\n\t\tlet query = this.db\n\t\t\t.updateTable(\"media\")\n\t\t\t.set(updates)\n\t\t\t.where(\"id\", \"=\", id)\n\t\t\t.where(\"status\", \"=\", \"pending\");\n\t\tif (expectedStorageKey !== undefined) {\n\t\t\tquery = query.where(\"storage_key\", \"=\", expectedStorageKey);\n\t\t}\n\n\t\tconst row = await query.returningAll().executeTakeFirst();\n\n\t\treturn row ? this.rowToItem(row) : null;\n\t}\n\n\t/**\n\t * Mark upload as failed\n\t */\n\tasync markFailed(id: string, expectedStorageKey?: string): Promise<MediaItem | null> {\n\t\tlet query = this.db.updateTable(\"media\").set({ status: \"failed\" }).where(\"id\", \"=\", id);\n\t\tif (expectedStorageKey !== undefined) {\n\t\t\tquery = query.where(\"status\", \"=\", \"pending\").where(\"storage_key\", \"=\", expectedStorageKey);\n\t\t}\n\n\t\tconst row = await query.returningAll().executeTakeFirst();\n\t\treturn row ? this.rowToItem(row) : null;\n\t}\n\n\t/**\n\t * Find media by ID\n\t */\n\tasync findById(id: string): Promise<MediaItem | null> {\n\t\tconst row = await this.db\n\t\t\t.selectFrom(\"media\")\n\t\t\t.selectAll()\n\t\t\t.where(\"id\", \"=\", id)\n\t\t\t.executeTakeFirst();\n\n\t\treturn row ? this.rowToItem(row) : null;\n\t}\n\n\t/**\n\t * Find media by filename\n\t * Useful for idempotent imports\n\t */\n\tasync findByFilename(filename: string): Promise<MediaItem | null> {\n\t\tconst row = await this.db\n\t\t\t.selectFrom(\"media\")\n\t\t\t.selectAll()\n\t\t\t.where(\"filename\", \"=\", filename)\n\t\t\t.executeTakeFirst();\n\n\t\treturn row ? this.rowToItem(row) : null;\n\t}\n\n\t/**\n\t * Find media by content hash\n\t * Used for deduplication - same content = same hash\n\t */\n\tasync findByContentHash(contentHash: string): Promise<MediaItem | null> {\n\t\tconst row = await this.db\n\t\t\t.selectFrom(\"media\")\n\t\t\t.selectAll()\n\t\t\t.where(\"content_hash\", \"=\", contentHash)\n\t\t\t.where(\"status\", \"=\", \"ready\")\n\t\t\t.executeTakeFirst();\n\n\t\treturn row ? this.rowToItem(row) : null;\n\t}\n\n\t/**\n\t * Find many media items with cursor pagination\n\t *\n\t * Uses keyset pagination (cursor-based) for consistent results.\n\t * The cursor encodes the created_at and id of the last item.\n\t */\n\tasync findMany(options: FindManyMediaOptions = {}): Promise<FindManyResult<MediaItem>> {\n\t\tconst limit = Math.min(options.limit || 50, 100);\n\n\t\tlet query = this.applyListFilters(this.db.selectFrom(\"media\"), options)\n\t\t\t.selectAll()\n\t\t\t.orderBy(\"created_at\", \"desc\")\n\t\t\t.orderBy(\"id\", \"desc\")\n\t\t\t.limit(limit + 1);\n\n\t\t// Handle cursor-based pagination — throws on invalid cursor.\n\t\tif (options.cursor) {\n\t\t\tconst { orderValue: createdAt, id: cursorId } = decodeCursor(options.cursor);\n\n\t\t\t// Keyset pagination: get items where (created_at, id) < cursor\n\t\t\tquery = query.where((eb) =>\n\t\t\t\teb.or([\n\t\t\t\t\teb(\"created_at\", \"<\", createdAt),\n\t\t\t\t\teb.and([eb(\"created_at\", \"=\", createdAt), eb(\"id\", \"<\", cursorId)]),\n\t\t\t\t]),\n\t\t\t);\n\t\t}\n\n\t\tconst rows = await query.execute();\n\n\t\tconst hasMore = rows.length > limit;\n\t\tconst items = rows.slice(0, limit).map((row) => this.rowToItem(row));\n\n\t\tlet nextCursor: string | undefined;\n\t\tif (hasMore && items.length > 0) {\n\t\t\tconst lastItem = items.at(-1)!;\n\t\t\tnextCursor = encodeCursor(lastItem.createdAt, lastItem.id);\n\t\t}\n\n\t\treturn { items, nextCursor };\n\t}\n\n\tasync findPage(options: FindMediaPageOptions): Promise<MediaPageResult> {\n\t\tconst limit = Math.min(options.limit || 50, 100);\n\t\tconst offset = (options.page - 1) * limit;\n\t\tconst filtered = this.applyListFilters(this.db.selectFrom(\"media\"), options);\n\t\tconst rows = await filtered\n\t\t\t.selectAll()\n\t\t\t.orderBy(\"created_at\", \"desc\")\n\t\t\t.orderBy(\"id\", \"desc\")\n\t\t\t.limit(limit)\n\t\t\t.offset(offset)\n\t\t\t.execute();\n\t\tconst count = await filtered\n\t\t\t.select((eb) => eb.fn.count<number>(\"id\").as(\"count\"))\n\t\t\t.executeTakeFirst();\n\n\t\treturn {\n\t\t\titems: rows.map((row) => this.rowToItem(row)),\n\t\t\ttotalCount: Number(count?.count ?? 0),\n\t\t};\n\t}\n\n\t/**\n\t * Update media metadata\n\t */\n\tasync update(id: string, input: UpdateMediaInput): Promise<MediaItem | null> {\n\t\tconst existing = await this.findById(id);\n\t\tif (!existing) {\n\t\t\treturn null;\n\t\t}\n\n\t\tconst updates: Partial<MediaRow> = {};\n\t\tif (input.alt !== undefined) updates.alt = input.alt;\n\t\tif (input.caption !== undefined) updates.caption = input.caption;\n\t\tif (input.width !== undefined) updates.width = input.width;\n\t\tif (input.height !== undefined) updates.height = input.height;\n\t\tif (input.folderId !== undefined) updates.folder_id = input.folderId;\n\t\tif (input.focalX !== undefined && input.focalY !== undefined) {\n\t\t\tupdates.focal_x = input.focalX;\n\t\t\tupdates.focal_y = input.focalY;\n\t\t}\n\n\t\tif (Object.keys(updates).length > 0) {\n\t\t\tawait this.db.updateTable(\"media\").set(updates).where(\"id\", \"=\", id).execute();\n\t\t}\n\n\t\treturn this.findById(id);\n\t}\n\n\t/**\n\t * Delete media item\n\t */\n\tasync deleteWithStorageKey(id: string): Promise<string | null> {\n\t\tconst deleted = await this.db\n\t\t\t.deleteFrom(\"media\")\n\t\t\t.where(\"id\", \"=\", id)\n\t\t\t.returning(\"storage_key\")\n\t\t\t.executeTakeFirst();\n\t\tif (deleted) return deleted.storage_key;\n\t\treturn null;\n\t}\n\n\tasync delete(id: string): Promise<boolean> {\n\t\treturn (await this.deleteWithStorageKey(id)) !== null;\n\t}\n\n\t/**\n\t * Count media items\n\t */\n\tasync count(mimeType?: string | readonly string[]): Promise<number> {\n\t\tconst filters = normalizeMimeFilter(mimeType);\n\t\tlet query = this.db.selectFrom(\"media\").select((eb) => eb.fn.count<number>(\"id\").as(\"count\"));\n\n\t\tif (filters.length > 0) {\n\t\t\tquery = query.where((eb) => mimeMatchExpr(eb, filters));\n\t\t}\n\n\t\tconst result = await query.executeTakeFirst();\n\t\treturn Number(result?.count || 0);\n\t}\n\n\tprivate applyListFilters<O>(\n\t\tquery: SelectQueryBuilder<Database, \"media\", O>,\n\t\toptions: Omit<FindManyMediaOptions, \"cursor\" | \"limit\">,\n\t): SelectQueryBuilder<Database, \"media\", O> {\n\t\tconst mimeFilters = normalizeMimeFilter(options.mimeType);\n\t\tif (mimeFilters.length > 0) {\n\t\t\tquery = query.where((eb) => mimeMatchExpr(eb, mimeFilters));\n\t\t}\n\n\t\tconst term = options.q?.trim();\n\t\tif (term) {\n\t\t\tconst pattern = `%${escapeLike(term)}%`;\n\t\t\tquery = query.where(\n\t\t\t\tsql<string>`lower(filename)`,\n\t\t\t\t\"like\",\n\t\t\t\tsql<string>`lower(${pattern}) escape '\\\\'`,\n\t\t\t);\n\t\t}\n\n\t\tif (options.status !== \"all\") {\n\t\t\tquery = query.where(\"status\", \"=\", options.status ?? \"ready\");\n\t\t}\n\n\t\tif (options.folderId === null) {\n\t\t\tquery = query.where(\"folder_id\", \"is\", null);\n\t\t} else if (options.folderId !== undefined) {\n\t\t\tquery = query.where(\"folder_id\", \"=\", options.folderId);\n\t\t}\n\n\t\treturn query;\n\t}\n\n\t/**\n\t * Delete pending uploads older than the given age.\n\t * Pending uploads that were never confirmed indicate abandoned upload flows.\n\t *\n\t * Returns the storage keys of deleted rows so callers can remove the\n\t * corresponding files from object storage.\n\t */\n\tasync cleanupPendingUploads(maxAgeMs: number = 60 * 60 * 1000): Promise<string[]> {\n\t\tconst cutoff = new Date(Date.now() - maxAgeMs).toISOString();\n\n\t\tconst rows = await this.db\n\t\t\t.deleteFrom(\"media\")\n\t\t\t.where(\"status\", \"=\", \"pending\")\n\t\t\t.where(\"created_at\", \"<\", cutoff)\n\t\t\t.returning(\"storage_key\")\n\t\t\t.execute();\n\n\t\treturn rows.map((r) => r.storage_key);\n\t}\n\n\t/**\n\t * Convert database row to MediaItem\n\t */\n\tprivate rowToItem(row: MediaRow): MediaItem {\n\t\tconst focalPoint = normalizeFocalPoint(row.focal_x, row.focal_y);\n\t\treturn {\n\t\t\tid: row.id,\n\t\t\tfilename: row.filename,\n\t\t\tmimeType: row.mime_type,\n\t\t\tsize: row.size,\n\t\t\twidth: row.width,\n\t\t\theight: row.height,\n\t\t\tfocalX: focalPoint?.focalX ?? null,\n\t\t\tfocalY: focalPoint?.focalY ?? null,\n\t\t\talt: row.alt,\n\t\t\tcaption: row.caption,\n\t\t\tstorageKey: row.storage_key,\n\t\t\tcontentHash: row.content_hash,\n\t\t\tblurhash: row.blurhash,\n\t\t\tdominantColor: row.dominant_color,\n\t\t\t// eslint-disable-next-line typescript/no-unsafe-type-assertion -- DB stores string; validated at insert but linter can't follow\n\t\t\tstatus: row.status as MediaStatus,\n\t\t\tcreatedAt: row.created_at,\n\t\t\tauthorId: row.author_id,\n\t\t\tfolderId: row.folder_id,\n\t\t};\n\t}\n}\n"],"mappings":";;;;;;;AAeA,SAAS,WAAW,OAAuB;AAC1C,QAAO,MAAM,WAAW,MAAM,OAAO,CAAC,WAAW,KAAK,MAAM,CAAC,WAAW,KAAK,MAAM;;;;;;AAOpF,SAAS,oBAAoB,OAA8C;AAC1E,KAAI,CAAC,MAAO,QAAO,EAAE;AAErB,SADY,MAAM,QAAQ,MAAM,GAAG,QAAQ,CAAC,MAAM,EAEhD,QAAQ,UAA2B,OAAO,UAAU,YAAY,MAAM,SAAS,EAAE,CACjF,KAAK,UACL,MAAM,SAAS,IAAI,GAAG,MAAM,aAAa,GAAG,MAAM,MAAM,IAAI,CAAC,GAAG,MAAM,CAAC,aAAa,CACpF;;;;;;;AAQH,SAAS,cAAc,IAA0C,SAAmB;AACnF,QAAO,GAAG,GACT,QAAQ,KAAK,UACZ,MAAM,SAAS,IAAI,GAChB,GAAY,kBAAkB,GAAG,WAAW,MAAM,CAAC,GAAG,gBACtD,GAAG,aAAa,KAAK,MAAM,CAC9B,CACD;;AAuEF,MAAM,gCAAgC,OAAU;AAChD,MAAM,oCAAoC;;;;AAK1C,IAAa,kBAAb,MAA6B;CAC5B,YAAY,AAAQ,IAAsB;EAAtB;;;;;CAKpB,MAAM,OAAO,OAA6C;EACzD,MAAM,KAAK,MAAM;EACjB,MAAM,uBAAM,IAAI,MAAM,EAAC,aAAa;EAEpC,MAAM,MAA+B;GACpC;GACA,UAAU,MAAM;GAChB,WAAW,MAAM;GACjB,MAAM,MAAM,QAAQ;GACpB,OAAO,MAAM,SAAS;GACtB,QAAQ,MAAM,UAAU;GACxB,SAAS;GACT,SAAS;GACT,KAAK,MAAM,OAAO;GAClB,SAAS,MAAM,WAAW;GAC1B,aAAa,MAAM;GACnB,cAAc,MAAM,eAAe;GACnC,UAAU,MAAM,YAAY;GAC5B,gBAAgB,MAAM,iBAAiB;GACvC,QAAQ,MAAM,UAAU;GACxB,YAAY;GACZ,WAAW,MAAM,YAAY;GAC7B,WAAW;GACX;AAED,QAAM,KAAK,GAAG,WAAW,QAAQ,CAAC,OAAO,IAAI,CAAC,SAAS;AAEvD,SAAO,KAAK,UAAU,IAAI;;;;;CAM3B,MAAM,cAAc,OAOG;AACtB,SAAO,KAAK,OAAO;GAClB,GAAG;GACH,QAAQ;GACR,CAAC;;CAGH,MAAM,oBAAoB,SAAiB,YAAmC;EAC7E,MAAM,uBAAM,IAAI,MAAM,EAAC,aAAa;AACpC,QAAM,KAAK,GACT,WAAW,gCAAgC,CAC3C,OAAO;GACP,UAAU;GACV,aAAa;GACb,QAAQ;GACR,YAAY;GACZ,YAAY;GACZ,CAAC,CACD,SAAS;;CAGZ,MAAM,iBAAiB,YAAsC;AAM5D,SALY,MAAM,KAAK,GACrB,WAAW,gCAAgC,CAC3C,OAAO,cAAc,CACrB,MAAM,eAAe,KAAK,WAAW,CACrC,kBAAkB,KACL;;CAGhB,MAAM,6BAA6B,YAAsC;EACxE,MAAM,SAAS,MAAM,KAAK,GACxB,YAAY,gCAAgC,CAC5C,IAAI;GAAE,QAAQ;GAAW,6BAAY,IAAI,MAAM,EAAC,aAAa;GAAE,CAAC,CAChE,MAAM,eAAe,KAAK,WAAW,CACrC,OAAO,OACP,GAAG,IACF,GAAG,OACF,GACE,WAAW,QAAQ,CACnB,OAAO,WAAW,CAClB,SAAS,qBAAqB,KAAK,4CAA4C,CACjF,CACD,CACD,CACA,kBAAkB;AAEpB,SAAO,OAAO,OAAO,kBAAkB,EAAE,GAAG;;CAG7C,MAAM,oBAAoB,YAAmC;AAC5D,QAAM,KAAK,GACT,WAAW,gCAAgC,CAC3C,MAAM,eAAe,KAAK,WAAW,CACrC,SAAS;;CAGZ,MAAM,gCAAiD;EACtD,MAAM,SAAS,MAAM,KAAK,GACxB,WAAW,gCAAgC,CAC3C,OAAO,OACP,GAAG,OACF,GACE,WAAW,QAAQ,CACnB,OAAO,WAAW,CAClB,SAAS,YAAY,KAAK,yCAAyC,CACnE,SAAS,qBAAqB,KAAK,4CAA4C,CAC/E,MAAM,gBAAgB,KAAK,QAAQ,CACrC,CACD,CACA,kBAAkB;AACpB,SAAO,OAAO,OAAO,kBAAkB,EAAE;;CAG1C,MAAM,6BACL,WAAmB,+BACnB,QAAgB,mCACI;EACpB,MAAM,SAAS,IAAI,KAAK,KAAK,KAAK,GAAG,SAAS,CAAC,aAAa;AAmB5D,UAlBa,MAAM,KAAK,GACtB,WAAW,gCAAgC,CAC3C,OAAO,cAAc,CACrB,OAAO,OAAO,GAAG,GAAG,CAAC,GAAG,UAAU,KAAK,UAAU,EAAE,GAAG,cAAc,KAAK,OAAO,CAAC,CAAC,CAAC,CACnF,OAAO,OACP,GAAG,IACF,GAAG,OACF,GACE,WAAW,QAAQ,CACnB,OAAO,WAAW,CAClB,SAAS,qBAAqB,KAAK,4CAA4C,CACjF,CACD,CACD,CACA,QAAQ,cAAc,MAAM,CAC5B,MAAM,MAAM,CACZ,SAAS,EAEC,KAAK,QAAQ,IAAI,YAAY;;CAG1C,MAAM,yBACL,IACA,oBACA,YACA,aACmB;EACnB,MAAM,SAAS,MAAM,KAAK,GACxB,YAAY,QAAQ,CACpB,IAAI;GACJ,aAAa;GACb,GAAI,gBAAgB,SAAY,EAAE,cAAc,aAAa,GAAG,EAAE;GAClE,CAAC,CACD,MAAM,MAAM,KAAK,GAAG,CACpB,MAAM,UAAU,KAAK,UAAU,CAC/B,MAAM,eAAe,KAAK,mBAAmB,CAC7C,OAAO,OACP,GAAG,OACF,GACE,WAAW,gCAAgC,CAC3C,OAAO,cAAc,CACrB,MAAM,YAAY,KAAK,GAAG,CAC1B,MAAM,eAAe,KAAK,WAAW,CACrC,MAAM,UAAU,KAAK,SAAS,CAChC,CACD,CACA,kBAAkB;AAEpB,SAAO,OAAO,OAAO,kBAAkB,EAAE,GAAG;;;;;CAM7C,MAAM,cACL,IACA,UAQA,oBAC4B;EAC5B,MAAM,UAA6B,EAClC,QAAQ,SACR;AACD,MAAI,UAAU,UAAU,OAAW,SAAQ,QAAQ,SAAS;AAC5D,MAAI,UAAU,WAAW,OAAW,SAAQ,SAAS,SAAS;AAC9D,MAAI,UAAU,SAAS,OAAW,SAAQ,OAAO,SAAS;AAC1D,MAAI,UAAU,aAAa,OAAW,SAAQ,WAAW,SAAS;AAClE,MAAI,UAAU,kBAAkB,OAAW,SAAQ,iBAAiB,SAAS;AAC7E,MAAI,UAAU,gBAAgB,OAAW,SAAQ,eAAe,SAAS;EAEzE,IAAI,QAAQ,KAAK,GACf,YAAY,QAAQ,CACpB,IAAI,QAAQ,CACZ,MAAM,MAAM,KAAK,GAAG,CACpB,MAAM,UAAU,KAAK,UAAU;AACjC,MAAI,uBAAuB,OAC1B,SAAQ,MAAM,MAAM,eAAe,KAAK,mBAAmB;EAG5D,MAAM,MAAM,MAAM,MAAM,cAAc,CAAC,kBAAkB;AAEzD,SAAO,MAAM,KAAK,UAAU,IAAI,GAAG;;;;;CAMpC,MAAM,WAAW,IAAY,oBAAwD;EACpF,IAAI,QAAQ,KAAK,GAAG,YAAY,QAAQ,CAAC,IAAI,EAAE,QAAQ,UAAU,CAAC,CAAC,MAAM,MAAM,KAAK,GAAG;AACvF,MAAI,uBAAuB,OAC1B,SAAQ,MAAM,MAAM,UAAU,KAAK,UAAU,CAAC,MAAM,eAAe,KAAK,mBAAmB;EAG5F,MAAM,MAAM,MAAM,MAAM,cAAc,CAAC,kBAAkB;AACzD,SAAO,MAAM,KAAK,UAAU,IAAI,GAAG;;;;;CAMpC,MAAM,SAAS,IAAuC;EACrD,MAAM,MAAM,MAAM,KAAK,GACrB,WAAW,QAAQ,CACnB,WAAW,CACX,MAAM,MAAM,KAAK,GAAG,CACpB,kBAAkB;AAEpB,SAAO,MAAM,KAAK,UAAU,IAAI,GAAG;;;;;;CAOpC,MAAM,eAAe,UAA6C;EACjE,MAAM,MAAM,MAAM,KAAK,GACrB,WAAW,QAAQ,CACnB,WAAW,CACX,MAAM,YAAY,KAAK,SAAS,CAChC,kBAAkB;AAEpB,SAAO,MAAM,KAAK,UAAU,IAAI,GAAG;;;;;;CAOpC,MAAM,kBAAkB,aAAgD;EACvE,MAAM,MAAM,MAAM,KAAK,GACrB,WAAW,QAAQ,CACnB,WAAW,CACX,MAAM,gBAAgB,KAAK,YAAY,CACvC,MAAM,UAAU,KAAK,QAAQ,CAC7B,kBAAkB;AAEpB,SAAO,MAAM,KAAK,UAAU,IAAI,GAAG;;;;;;;;CASpC,MAAM,SAAS,UAAgC,EAAE,EAAsC;EACtF,MAAM,QAAQ,KAAK,IAAI,QAAQ,SAAS,IAAI,IAAI;EAEhD,IAAI,QAAQ,KAAK,iBAAiB,KAAK,GAAG,WAAW,QAAQ,EAAE,QAAQ,CACrE,WAAW,CACX,QAAQ,cAAc,OAAO,CAC7B,QAAQ,MAAM,OAAO,CACrB,MAAM,QAAQ,EAAE;AAGlB,MAAI,QAAQ,QAAQ;GACnB,MAAM,EAAE,YAAY,WAAW,IAAI,aAAa,aAAa,QAAQ,OAAO;AAG5E,WAAQ,MAAM,OAAO,OACpB,GAAG,GAAG,CACL,GAAG,cAAc,KAAK,UAAU,EAChC,GAAG,IAAI,CAAC,GAAG,cAAc,KAAK,UAAU,EAAE,GAAG,MAAM,KAAK,SAAS,CAAC,CAAC,CACnE,CAAC,CACF;;EAGF,MAAM,OAAO,MAAM,MAAM,SAAS;EAElC,MAAM,UAAU,KAAK,SAAS;EAC9B,MAAM,QAAQ,KAAK,MAAM,GAAG,MAAM,CAAC,KAAK,QAAQ,KAAK,UAAU,IAAI,CAAC;EAEpE,IAAI;AACJ,MAAI,WAAW,MAAM,SAAS,GAAG;GAChC,MAAM,WAAW,MAAM,GAAG,GAAG;AAC7B,gBAAa,aAAa,SAAS,WAAW,SAAS,GAAG;;AAG3D,SAAO;GAAE;GAAO;GAAY;;CAG7B,MAAM,SAAS,SAAyD;EACvE,MAAM,QAAQ,KAAK,IAAI,QAAQ,SAAS,IAAI,IAAI;EAChD,MAAM,UAAU,QAAQ,OAAO,KAAK;EACpC,MAAM,WAAW,KAAK,iBAAiB,KAAK,GAAG,WAAW,QAAQ,EAAE,QAAQ;EAC5E,MAAM,OAAO,MAAM,SACjB,WAAW,CACX,QAAQ,cAAc,OAAO,CAC7B,QAAQ,MAAM,OAAO,CACrB,MAAM,MAAM,CACZ,OAAO,OAAO,CACd,SAAS;EACX,MAAM,QAAQ,MAAM,SAClB,QAAQ,OAAO,GAAG,GAAG,MAAc,KAAK,CAAC,GAAG,QAAQ,CAAC,CACrD,kBAAkB;AAEpB,SAAO;GACN,OAAO,KAAK,KAAK,QAAQ,KAAK,UAAU,IAAI,CAAC;GAC7C,YAAY,OAAO,OAAO,SAAS,EAAE;GACrC;;;;;CAMF,MAAM,OAAO,IAAY,OAAoD;AAE5E,MAAI,CADa,MAAM,KAAK,SAAS,GAAG,CAEvC,QAAO;EAGR,MAAM,UAA6B,EAAE;AACrC,MAAI,MAAM,QAAQ,OAAW,SAAQ,MAAM,MAAM;AACjD,MAAI,MAAM,YAAY,OAAW,SAAQ,UAAU,MAAM;AACzD,MAAI,MAAM,UAAU,OAAW,SAAQ,QAAQ,MAAM;AACrD,MAAI,MAAM,WAAW,OAAW,SAAQ,SAAS,MAAM;AACvD,MAAI,MAAM,aAAa,OAAW,SAAQ,YAAY,MAAM;AAC5D,MAAI,MAAM,WAAW,UAAa,MAAM,WAAW,QAAW;AAC7D,WAAQ,UAAU,MAAM;AACxB,WAAQ,UAAU,MAAM;;AAGzB,MAAI,OAAO,KAAK,QAAQ,CAAC,SAAS,EACjC,OAAM,KAAK,GAAG,YAAY,QAAQ,CAAC,IAAI,QAAQ,CAAC,MAAM,MAAM,KAAK,GAAG,CAAC,SAAS;AAG/E,SAAO,KAAK,SAAS,GAAG;;;;;CAMzB,MAAM,qBAAqB,IAAoC;EAC9D,MAAM,UAAU,MAAM,KAAK,GACzB,WAAW,QAAQ,CACnB,MAAM,MAAM,KAAK,GAAG,CACpB,UAAU,cAAc,CACxB,kBAAkB;AACpB,MAAI,QAAS,QAAO,QAAQ;AAC5B,SAAO;;CAGR,MAAM,OAAO,IAA8B;AAC1C,SAAQ,MAAM,KAAK,qBAAqB,GAAG,KAAM;;;;;CAMlD,MAAM,MAAM,UAAwD;EACnE,MAAM,UAAU,oBAAoB,SAAS;EAC7C,IAAI,QAAQ,KAAK,GAAG,WAAW,QAAQ,CAAC,QAAQ,OAAO,GAAG,GAAG,MAAc,KAAK,CAAC,GAAG,QAAQ,CAAC;AAE7F,MAAI,QAAQ,SAAS,EACpB,SAAQ,MAAM,OAAO,OAAO,cAAc,IAAI,QAAQ,CAAC;EAGxD,MAAM,SAAS,MAAM,MAAM,kBAAkB;AAC7C,SAAO,OAAO,QAAQ,SAAS,EAAE;;CAGlC,AAAQ,iBACP,OACA,SAC2C;EAC3C,MAAM,cAAc,oBAAoB,QAAQ,SAAS;AACzD,MAAI,YAAY,SAAS,EACxB,SAAQ,MAAM,OAAO,OAAO,cAAc,IAAI,YAAY,CAAC;EAG5D,MAAM,OAAO,QAAQ,GAAG,MAAM;AAC9B,MAAI,MAAM;GACT,MAAM,UAAU,IAAI,WAAW,KAAK,CAAC;AACrC,WAAQ,MAAM,MACb,GAAW,mBACX,QACA,GAAW,SAAS,QAAQ,eAC5B;;AAGF,MAAI,QAAQ,WAAW,MACtB,SAAQ,MAAM,MAAM,UAAU,KAAK,QAAQ,UAAU,QAAQ;AAG9D,MAAI,QAAQ,aAAa,KACxB,SAAQ,MAAM,MAAM,aAAa,MAAM,KAAK;WAClC,QAAQ,aAAa,OAC/B,SAAQ,MAAM,MAAM,aAAa,KAAK,QAAQ,SAAS;AAGxD,SAAO;;;;;;;;;CAUR,MAAM,sBAAsB,WAAmB,OAAU,KAAyB;EACjF,MAAM,SAAS,IAAI,KAAK,KAAK,KAAK,GAAG,SAAS,CAAC,aAAa;AAS5D,UAPa,MAAM,KAAK,GACtB,WAAW,QAAQ,CACnB,MAAM,UAAU,KAAK,UAAU,CAC/B,MAAM,cAAc,KAAK,OAAO,CAChC,UAAU,cAAc,CACxB,SAAS,EAEC,KAAK,MAAM,EAAE,YAAY;;;;;CAMtC,AAAQ,UAAU,KAA0B;EAC3C,MAAM,aAAa,oBAAoB,IAAI,SAAS,IAAI,QAAQ;AAChE,SAAO;GACN,IAAI,IAAI;GACR,UAAU,IAAI;GACd,UAAU,IAAI;GACd,MAAM,IAAI;GACV,OAAO,IAAI;GACX,QAAQ,IAAI;GACZ,QAAQ,YAAY,UAAU;GAC9B,QAAQ,YAAY,UAAU;GAC9B,KAAK,IAAI;GACT,SAAS,IAAI;GACb,YAAY,IAAI;GAChB,aAAa,IAAI;GACjB,UAAU,IAAI;GACd,eAAe,IAAI;GAEnB,QAAQ,IAAI;GACZ,WAAW,IAAI;GACf,UAAU,IAAI;GACd,UAAU,IAAI;GACd"}
@@ -1,4 +1,4 @@
1
- import { r as parseAllowedMimeTypes } from "./mime-DfIVjNkr.mjs";
1
+ import { r as parseAllowedMimeTypes } from "./mime-CUIG6x84.mjs";
2
2
 
3
3
  //#region src/api/handlers/media-allowlist.ts
4
4
  /**
@@ -19,6 +19,7 @@ const GLOBAL_UPLOAD_ALLOWLIST = [
19
19
  "image/jpeg",
20
20
  "image/gif",
21
21
  "image/webp",
22
+ "image/avif",
22
23
  "video/",
23
24
  "audio/",
24
25
  "application/pdf"
@@ -40,4 +41,4 @@ async function resolveFieldAllowlist(db, fieldId) {
40
41
 
41
42
  //#endregion
42
43
  export { resolveFieldAllowlist as n, GLOBAL_UPLOAD_ALLOWLIST as t };
43
- //# sourceMappingURL=media-allowlist-BD6HhgXA.mjs.map
44
+ //# sourceMappingURL=media-allowlist-D35v7bmL.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"media-allowlist-D35v7bmL.mjs","names":[],"sources":["../src/api/handlers/media-allowlist.ts"],"sourcesContent":["import type { Kysely } from \"kysely\";\n\nimport type { Database } from \"../../database/types.js\";\nimport { parseAllowedMimeTypes } from \"../../media/mime.js\";\n\n/**\n * MIME types allowed for upload by default (when no field-specific list\n * overrides this). Entries ending with \"/\" are prefix-matched (e.g.\n * \"video/\" matches \"video/mp4\", \"video/webm\", etc.).\n *\n * Image types are enumerated explicitly rather than using a bare \"image/\"\n * prefix so that \"image/svg+xml\" is excluded by default: there is no\n * upload-time content validation for SVG, so an unvalidated bare-prefix\n * allowlist would let a Contributor+ upload an SVG with an embedded\n * `<script>`. Fields that genuinely need SVG uploads can still opt in via\n * their own `allowedMimeTypes` (see `resolveFieldAllowlist` below), which is\n * unaffected by this default.\n */\nexport const GLOBAL_UPLOAD_ALLOWLIST: readonly string[] = [\n\t\"image/png\",\n\t\"image/jpeg\",\n\t\"image/gif\",\n\t\"image/webp\",\n\t\"image/avif\",\n\t\"video/\",\n\t\"audio/\",\n\t\"application/pdf\",\n];\n\n/**\n * Resolve the MIME allowlist for a specific field.\n *\n * Returns the field's `allowedMimeTypes` list when the field exists, is of\n * type \"file\" or \"image\", and has a non-empty list configured. Returns null\n * in all other cases — callers should fall back to GLOBAL_UPLOAD_ALLOWLIST.\n *\n * Authentication is the caller's responsibility (the upload routes already\n * gate on `media:upload`).\n */\nexport async function resolveFieldAllowlist(\n\tdb: Kysely<Database>,\n\tfieldId: string,\n): Promise<string[] | null> {\n\tconst row = await db\n\t\t.selectFrom(\"_emdash_fields\")\n\t\t.select([\"type\", \"validation\"])\n\t\t.where(\"id\", \"=\", fieldId)\n\t\t.where(\"type\", \"in\", [\"file\", \"image\"])\n\t\t.executeTakeFirst();\n\n\treturn row ? parseAllowedMimeTypes(row.validation) : null;\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAkBA,MAAa,0BAA6C;CACzD;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;;;;;;;;;;;AAYD,eAAsB,sBACrB,IACA,SAC2B;CAC3B,MAAM,MAAM,MAAM,GAChB,WAAW,iBAAiB,CAC5B,OAAO,CAAC,QAAQ,aAAa,CAAC,CAC9B,MAAM,MAAM,KAAK,QAAQ,CACzB,MAAM,QAAQ,MAAM,CAAC,QAAQ,QAAQ,CAAC,CACtC,kBAAkB;AAEpB,QAAO,MAAM,sBAAsB,IAAI,WAAW,GAAG"}
@@ -0,0 +1,210 @@
1
+ import { i as InvalidCursorError, o as decodeCursor, r as EmDashValidationError, s as encodeCursor } from "./types-CQPWhPxE.mjs";
2
+ import { sql } from "kysely";
3
+ import { ulid } from "ulidx";
4
+
5
+ //#region src/database/repositories/media-folders.ts
6
+ function escapeLike(value) {
7
+ return value.replaceAll("\\", "\\\\").replaceAll("%", "\\%").replaceAll("_", "\\_");
8
+ }
9
+ function normalizeFolderSearch(value) {
10
+ return value.trim().normalize("NFKC").toLowerCase();
11
+ }
12
+ function normalizeFolderName(name) {
13
+ if (typeof name !== "string") throw new EmDashValidationError("Folder name must be a string");
14
+ const trimmed = name.trim();
15
+ if (trimmed.length < 1 || trimmed.length > 200) throw new EmDashValidationError("Folder name must be between 1 and 200 characters");
16
+ return {
17
+ name: trimmed,
18
+ nameKey: trimmed.normalize("NFKC").toLowerCase()
19
+ };
20
+ }
21
+ var MediaFolderRepository = class {
22
+ constructor(db) {
23
+ this.db = db;
24
+ }
25
+ async findMany(options = {}) {
26
+ const limit = Math.max(1, Math.min(options.limit ?? 50, 100));
27
+ let query = this.db.selectFrom("media_folders").select([
28
+ "id",
29
+ "name",
30
+ "name_key"
31
+ ]).orderBy("name_key", "asc").orderBy("id", "asc").limit(limit + 1);
32
+ const term = normalizeFolderSearch(options.q ?? "");
33
+ if (term) {
34
+ const pattern = `%${escapeLike(term)}%`;
35
+ query = query.where("name_key", "like", sql`${pattern} escape '\\'`);
36
+ }
37
+ if (options.cursor !== void 0) {
38
+ const { orderValue: nameKey, id } = decodeCursor(options.cursor);
39
+ query = query.where((eb) => eb.or([eb("name_key", ">", nameKey), eb.and([eb("name_key", "=", nameKey), eb("id", ">", id)])]));
40
+ }
41
+ const rows = await query.execute();
42
+ const hasMore = rows.length > limit;
43
+ const visible = rows.slice(0, limit);
44
+ return {
45
+ items: visible.map(({ id, name }) => ({
46
+ id,
47
+ name
48
+ })),
49
+ nextCursor: hasMore && visible.length > 0 ? encodeCursor(visible.at(-1).name_key, visible.at(-1).id) : void 0
50
+ };
51
+ }
52
+ async findById(id) {
53
+ return await this.db.selectFrom("media_folders").select(["id", "name"]).where("id", "=", id).executeTakeFirst() ?? null;
54
+ }
55
+ async create(inputName) {
56
+ const { name, nameKey } = normalizeFolderName(inputName);
57
+ return await this.db.insertInto("media_folders").values({
58
+ id: ulid(),
59
+ name,
60
+ name_key: nameKey
61
+ }).returning(["id", "name"]).executeTakeFirstOrThrow();
62
+ }
63
+ async update(id, inputName) {
64
+ const { name, nameKey } = normalizeFolderName(inputName);
65
+ return await this.db.updateTable("media_folders").set({
66
+ name,
67
+ name_key: nameKey
68
+ }).where("id", "=", id).returning(["id", "name"]).executeTakeFirst() ?? null;
69
+ }
70
+ async delete(id) {
71
+ return await this.db.deleteFrom("media_folders").where("id", "=", id).returning("id").executeTakeFirst() !== void 0;
72
+ }
73
+ };
74
+
75
+ //#endregion
76
+ //#region src/api/handlers/media-folders.ts
77
+ const UNIQUE_VIOLATION_RE = /unique constraint failed|duplicate key value violates unique constraint/i;
78
+ async function handleMediaFolderList(db, options = {}) {
79
+ try {
80
+ return {
81
+ success: true,
82
+ data: await new MediaFolderRepository(db).findMany(options)
83
+ };
84
+ } catch (error) {
85
+ if (error instanceof InvalidCursorError) return {
86
+ success: false,
87
+ error: {
88
+ code: "INVALID_CURSOR",
89
+ message: error.message
90
+ }
91
+ };
92
+ return {
93
+ success: false,
94
+ error: {
95
+ code: "MEDIA_FOLDER_LIST_ERROR",
96
+ message: "Failed to list media folders"
97
+ }
98
+ };
99
+ }
100
+ }
101
+ async function handleMediaFolderGet(db, id) {
102
+ try {
103
+ const item = await new MediaFolderRepository(db).findById(id);
104
+ if (!item) return {
105
+ success: false,
106
+ error: {
107
+ code: "NOT_FOUND",
108
+ message: "Media folder not found"
109
+ }
110
+ };
111
+ return {
112
+ success: true,
113
+ data: { item }
114
+ };
115
+ } catch {
116
+ return {
117
+ success: false,
118
+ error: {
119
+ code: "MEDIA_FOLDER_GET_ERROR",
120
+ message: "Failed to get media folder"
121
+ }
122
+ };
123
+ }
124
+ }
125
+ async function handleMediaFolderCreate(db, input) {
126
+ try {
127
+ return {
128
+ success: true,
129
+ data: { item: await new MediaFolderRepository(db).create(input.name) }
130
+ };
131
+ } catch (error) {
132
+ return mediaFolderWriteError(error, "MEDIA_FOLDER_CREATE_ERROR", "Failed to create media folder");
133
+ }
134
+ }
135
+ async function handleMediaFolderUpdate(db, id, input) {
136
+ try {
137
+ const item = await new MediaFolderRepository(db).update(id, input.name);
138
+ if (!item) return {
139
+ success: false,
140
+ error: {
141
+ code: "NOT_FOUND",
142
+ message: "Media folder not found"
143
+ }
144
+ };
145
+ return {
146
+ success: true,
147
+ data: { item }
148
+ };
149
+ } catch (error) {
150
+ return mediaFolderWriteError(error, "MEDIA_FOLDER_UPDATE_ERROR", "Failed to update media folder");
151
+ }
152
+ }
153
+ async function handleMediaFolderDelete(db, id) {
154
+ try {
155
+ if (!await new MediaFolderRepository(db).delete(id)) return {
156
+ success: false,
157
+ error: {
158
+ code: "NOT_FOUND",
159
+ message: "Media folder not found"
160
+ }
161
+ };
162
+ return {
163
+ success: true,
164
+ data: { deleted: true }
165
+ };
166
+ } catch {
167
+ return {
168
+ success: false,
169
+ error: {
170
+ code: "MEDIA_FOLDER_DELETE_ERROR",
171
+ message: "Failed to delete media folder"
172
+ }
173
+ };
174
+ }
175
+ }
176
+ function mediaFolderWriteError(error, code, message) {
177
+ if (error instanceof EmDashValidationError) return {
178
+ success: false,
179
+ error: {
180
+ code: "VALIDATION_ERROR",
181
+ message: error.message
182
+ }
183
+ };
184
+ if (isUniqueViolation(error)) return {
185
+ success: false,
186
+ error: {
187
+ code: "CONFLICT",
188
+ message: "A media folder with this name already exists"
189
+ }
190
+ };
191
+ return {
192
+ success: false,
193
+ error: {
194
+ code,
195
+ message
196
+ }
197
+ };
198
+ }
199
+ function isUniqueViolation(error) {
200
+ if (error && typeof error === "object") {
201
+ if ("code" in error && error.code === "23505") return true;
202
+ }
203
+ const message = error instanceof Error ? error.message : "";
204
+ if (UNIQUE_VIOLATION_RE.test(message)) return true;
205
+ return Boolean(error && typeof error === "object" && "cause" in error && isUniqueViolation(error.cause));
206
+ }
207
+
208
+ //#endregion
209
+ export { handleMediaFolderUpdate as a, handleMediaFolderList as i, handleMediaFolderDelete as n, handleMediaFolderGet as r, handleMediaFolderCreate as t };
210
+ //# sourceMappingURL=media-folders-D-0CmRZj.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"media-folders-D-0CmRZj.mjs","names":[],"sources":["../src/database/repositories/media-folders.ts","../src/api/handlers/media-folders.ts"],"sourcesContent":["import { sql, type Kysely } from \"kysely\";\nimport { ulid } from \"ulidx\";\n\nimport type { Database } from \"../types.js\";\nimport { decodeCursor, EmDashValidationError, encodeCursor, type FindManyResult } from \"./types.js\";\n\nexport interface MediaFolder {\n\tid: string;\n\tname: string;\n}\n\nexport interface FindManyMediaFoldersOptions {\n\tlimit?: number;\n\tcursor?: string;\n\tq?: string;\n}\n\nfunction escapeLike(value: string): string {\n\treturn value.replaceAll(\"\\\\\", \"\\\\\\\\\").replaceAll(\"%\", \"\\\\%\").replaceAll(\"_\", \"\\\\_\");\n}\n\nfunction normalizeFolderSearch(value: string): string {\n\treturn value.trim().normalize(\"NFKC\").toLowerCase();\n}\n\nfunction normalizeFolderName(name: string): { name: string; nameKey: string } {\n\tif (typeof name !== \"string\") {\n\t\tthrow new EmDashValidationError(\"Folder name must be a string\");\n\t}\n\tconst trimmed = name.trim();\n\tif (trimmed.length < 1 || trimmed.length > 200) {\n\t\tthrow new EmDashValidationError(\"Folder name must be between 1 and 200 characters\");\n\t}\n\treturn { name: trimmed, nameKey: trimmed.normalize(\"NFKC\").toLowerCase() };\n}\n\nexport class MediaFolderRepository {\n\tconstructor(private db: Kysely<Database>) {}\n\n\tasync findMany(options: FindManyMediaFoldersOptions = {}): Promise<FindManyResult<MediaFolder>> {\n\t\tconst limit = Math.max(1, Math.min(options.limit ?? 50, 100));\n\t\tlet query = this.db\n\t\t\t.selectFrom(\"media_folders\")\n\t\t\t.select([\"id\", \"name\", \"name_key\"])\n\t\t\t.orderBy(\"name_key\", \"asc\")\n\t\t\t.orderBy(\"id\", \"asc\")\n\t\t\t.limit(limit + 1);\n\n\t\tconst term = normalizeFolderSearch(options.q ?? \"\");\n\t\tif (term) {\n\t\t\tconst pattern = `%${escapeLike(term)}%`;\n\t\t\tquery = query.where(\"name_key\", \"like\", sql<string>`${pattern} escape '\\\\'`);\n\t\t}\n\n\t\tif (options.cursor !== undefined) {\n\t\t\tconst { orderValue: nameKey, id } = decodeCursor(options.cursor);\n\t\t\tquery = query.where((eb) =>\n\t\t\t\teb.or([\n\t\t\t\t\teb(\"name_key\", \">\", nameKey),\n\t\t\t\t\teb.and([eb(\"name_key\", \"=\", nameKey), eb(\"id\", \">\", id)]),\n\t\t\t\t]),\n\t\t\t);\n\t\t}\n\n\t\tconst rows = await query.execute();\n\t\tconst hasMore = rows.length > limit;\n\t\tconst visible = rows.slice(0, limit);\n\t\treturn {\n\t\t\titems: visible.map(({ id, name }) => ({ id, name })),\n\t\t\tnextCursor:\n\t\t\t\thasMore && visible.length > 0\n\t\t\t\t\t? encodeCursor(visible.at(-1)!.name_key, visible.at(-1)!.id)\n\t\t\t\t\t: undefined,\n\t\t};\n\t}\n\n\tasync findById(id: string): Promise<MediaFolder | null> {\n\t\tconst row = await this.db\n\t\t\t.selectFrom(\"media_folders\")\n\t\t\t.select([\"id\", \"name\"])\n\t\t\t.where(\"id\", \"=\", id)\n\t\t\t.executeTakeFirst();\n\t\treturn row ?? null;\n\t}\n\n\tasync create(inputName: string): Promise<MediaFolder> {\n\t\tconst { name, nameKey } = normalizeFolderName(inputName);\n\t\tconst row = await this.db\n\t\t\t.insertInto(\"media_folders\")\n\t\t\t.values({ id: ulid(), name, name_key: nameKey })\n\t\t\t.returning([\"id\", \"name\"])\n\t\t\t.executeTakeFirstOrThrow();\n\t\treturn row;\n\t}\n\n\tasync update(id: string, inputName: string): Promise<MediaFolder | null> {\n\t\tconst { name, nameKey } = normalizeFolderName(inputName);\n\t\tconst row = await this.db\n\t\t\t.updateTable(\"media_folders\")\n\t\t\t.set({ name, name_key: nameKey })\n\t\t\t.where(\"id\", \"=\", id)\n\t\t\t.returning([\"id\", \"name\"])\n\t\t\t.executeTakeFirst();\n\t\treturn row ?? null;\n\t}\n\n\tasync delete(id: string): Promise<boolean> {\n\t\tconst row = await this.db\n\t\t\t.deleteFrom(\"media_folders\")\n\t\t\t.where(\"id\", \"=\", id)\n\t\t\t.returning(\"id\")\n\t\t\t.executeTakeFirst();\n\t\treturn row !== undefined;\n\t}\n}\n","import type { Kysely } from \"kysely\";\n\nimport {\n\tMediaFolderRepository,\n\ttype MediaFolder,\n} from \"../../database/repositories/media-folders.js\";\nimport { EmDashValidationError, InvalidCursorError } from \"../../database/repositories/types.js\";\nimport type { Database } from \"../../database/types.js\";\nimport type { ApiResult } from \"../types.js\";\n\nconst UNIQUE_VIOLATION_RE =\n\t/unique constraint failed|duplicate key value violates unique constraint/i;\n\nexport async function handleMediaFolderList(\n\tdb: Kysely<Database>,\n\toptions: { limit?: number; cursor?: string; q?: string } = {},\n): Promise<ApiResult<{ items: MediaFolder[]; nextCursor?: string }>> {\n\ttry {\n\t\tconst result = await new MediaFolderRepository(db).findMany(options);\n\t\treturn { success: true, data: result };\n\t} catch (error) {\n\t\tif (error instanceof InvalidCursorError) {\n\t\t\treturn { success: false, error: { code: \"INVALID_CURSOR\", message: error.message } };\n\t\t}\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\terror: { code: \"MEDIA_FOLDER_LIST_ERROR\", message: \"Failed to list media folders\" },\n\t\t};\n\t}\n}\n\nexport async function handleMediaFolderGet(\n\tdb: Kysely<Database>,\n\tid: string,\n): Promise<ApiResult<{ item: MediaFolder }>> {\n\ttry {\n\t\tconst item = await new MediaFolderRepository(db).findById(id);\n\t\tif (!item) {\n\t\t\treturn { success: false, error: { code: \"NOT_FOUND\", message: \"Media folder not found\" } };\n\t\t}\n\t\treturn { success: true, data: { item } };\n\t} catch {\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\terror: { code: \"MEDIA_FOLDER_GET_ERROR\", message: \"Failed to get media folder\" },\n\t\t};\n\t}\n}\n\nexport async function handleMediaFolderCreate(\n\tdb: Kysely<Database>,\n\tinput: { name: string },\n): Promise<ApiResult<{ item: MediaFolder }>> {\n\ttry {\n\t\tconst item = await new MediaFolderRepository(db).create(input.name);\n\t\treturn { success: true, data: { item } };\n\t} catch (error) {\n\t\treturn mediaFolderWriteError(\n\t\t\terror,\n\t\t\t\"MEDIA_FOLDER_CREATE_ERROR\",\n\t\t\t\"Failed to create media folder\",\n\t\t);\n\t}\n}\n\nexport async function handleMediaFolderUpdate(\n\tdb: Kysely<Database>,\n\tid: string,\n\tinput: { name: string },\n): Promise<ApiResult<{ item: MediaFolder }>> {\n\ttry {\n\t\tconst item = await new MediaFolderRepository(db).update(id, input.name);\n\t\tif (!item) {\n\t\t\treturn { success: false, error: { code: \"NOT_FOUND\", message: \"Media folder not found\" } };\n\t\t}\n\t\treturn { success: true, data: { item } };\n\t} catch (error) {\n\t\treturn mediaFolderWriteError(\n\t\t\terror,\n\t\t\t\"MEDIA_FOLDER_UPDATE_ERROR\",\n\t\t\t\"Failed to update media folder\",\n\t\t);\n\t}\n}\n\nexport async function handleMediaFolderDelete(\n\tdb: Kysely<Database>,\n\tid: string,\n): Promise<ApiResult<{ deleted: true }>> {\n\ttry {\n\t\tconst deleted = await new MediaFolderRepository(db).delete(id);\n\t\tif (!deleted) {\n\t\t\treturn { success: false, error: { code: \"NOT_FOUND\", message: \"Media folder not found\" } };\n\t\t}\n\t\treturn { success: true, data: { deleted: true } };\n\t} catch {\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\terror: { code: \"MEDIA_FOLDER_DELETE_ERROR\", message: \"Failed to delete media folder\" },\n\t\t};\n\t}\n}\n\nfunction mediaFolderWriteError(\n\terror: unknown,\n\tcode: \"MEDIA_FOLDER_CREATE_ERROR\" | \"MEDIA_FOLDER_UPDATE_ERROR\",\n\tmessage: string,\n): ApiResult<never> {\n\tif (error instanceof EmDashValidationError) {\n\t\treturn { success: false, error: { code: \"VALIDATION_ERROR\", message: error.message } };\n\t}\n\tif (isUniqueViolation(error)) {\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\terror: { code: \"CONFLICT\", message: \"A media folder with this name already exists\" },\n\t\t};\n\t}\n\treturn { success: false, error: { code, message } };\n}\n\nfunction isUniqueViolation(error: unknown): boolean {\n\tif (error && typeof error === \"object\") {\n\t\tif (\"code\" in error && error.code === \"23505\") return true;\n\t}\n\tconst message = error instanceof Error ? error.message : \"\";\n\tif (UNIQUE_VIOLATION_RE.test(message)) return true;\n\treturn Boolean(\n\t\terror && typeof error === \"object\" && \"cause\" in error && isUniqueViolation(error.cause),\n\t);\n}\n"],"mappings":"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"}
@@ -1,14 +1,14 @@
1
1
  import "./config-C3EBstHi.mjs";
2
2
  import { n as decodeBase64Bytes } from "./base64-CvLhUKQv.mjs";
3
3
  import "./types-CQPWhPxE.mjs";
4
- import { t as MediaRepository } from "./media-CzhAn2--.mjs";
5
- import "./dist-D_6CKR8z.mjs";
6
- import { n as normalizeMime, t as matchesMimeAllowlist } from "./mime-DfIVjNkr.mjs";
7
- import { t as enrichImageMetadata } from "./enrich-_ySMEvEE.mjs";
8
- import { n as computeContentHash } from "./hash-Cg0TXJPV.mjs";
9
- import { r as ssrfSafeFetch, t as SsrfError } from "./ssrf-Cpvg_n3A.mjs";
10
- import { n as DEFAULT_MAX_UPLOAD_SIZE, r as formatFileSize, t as CONTENT_TYPE_RE } from "./media-BWWWb8kg.mjs";
11
- import { t as GLOBAL_UPLOAD_ALLOWLIST } from "./media-allowlist-BD6HhgXA.mjs";
4
+ import { t as MediaRepository } from "./media-D6SeAfBl.mjs";
5
+ import "./dist-89xCrGqi.mjs";
6
+ import { n as normalizeMime, t as matchesMimeAllowlist } from "./mime-CUIG6x84.mjs";
7
+ import { t as enrichImageMetadata } from "./enrich-BX0IDp4z.mjs";
8
+ import { n as computeContentHash } from "./hash-CTcngWvj.mjs";
9
+ import { i as ssrfSafeFetch, t as SsrfError } from "./ssrf-DqebVE34.mjs";
10
+ import { n as DEFAULT_MAX_UPLOAD_SIZE, r as formatFileSize, t as CONTENT_TYPE_RE } from "./media-BjwNuLEu.mjs";
11
+ import { t as GLOBAL_UPLOAD_ALLOWLIST } from "./media-allowlist-D35v7bmL.mjs";
12
12
  import { ulid } from "ulidx";
13
13
  import * as path from "node:path";
14
14
 
@@ -144,4 +144,4 @@ async function handleMediaUpload(db, storage, input) {
144
144
 
145
145
  //#endregion
146
146
  export { handleMediaUpload };
147
- //# sourceMappingURL=media-upload-9yas9zGH.mjs.map
147
+ //# sourceMappingURL=media-upload-C7bLXGcI.mjs.map