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
@@ -1,11 +1,13 @@
1
1
  import { t as validateIdentifier } from "./validate-BpwoDOgt.mjs";
2
2
  import { p as tableExists, s as isPostgres } from "./dialect-helpers-BSbfaO3F.mjs";
3
3
  import { i as isI18nEnabled } from "./config-C3EBstHi.mjs";
4
- import { n as chunks, t as SQL_BATCH_SIZE } from "./chunks-DfPax1I0.mjs";
4
+ import { getRequestContext } from "./request-context.mjs";
5
+ import { n as chunks, t as SQL_BATCH_SIZE } from "./chunks-bNiX6_DR.mjs";
5
6
  import { i as InvalidCursorError, o as decodeCursor, s as encodeCursor } from "./types-CQPWhPxE.mjs";
6
- import { t as withTransaction } from "./transaction-NQj4VJ7Z.mjs";
7
- import { t as INTERNAL_MEDIA_PREFIX } from "./normalize-Bc-s_r-a.mjs";
8
- import { n as normalizeMime } from "./mime-DfIVjNkr.mjs";
7
+ import { t as withTransaction } from "./transaction-0KOpOyMu.mjs";
8
+ import { t as INTERNAL_MEDIA_PREFIX } from "./normalize-CSxdKBVa.mjs";
9
+ import { n as normalizeMime } from "./mime-CUIG6x84.mjs";
10
+ import { n as MediaUsageActivationVersionMismatchError, t as MEDIA_USAGE_ACTIVATION_RUNTIME_GENERATION } from "./activation-K0kGBWuJ.mjs";
9
11
  import { sql } from "kysely";
10
12
  import { ulid } from "ulidx";
11
13
 
@@ -100,17 +102,82 @@ function isRecord$3(value) {
100
102
  return typeof value === "object" && value !== null && !Array.isArray(value);
101
103
  }
102
104
 
105
+ //#endregion
106
+ //#region src/media/usage/types.ts
107
+ const CONTENT_SOURCE_SCHEMA_VERSION = 1;
108
+
109
+ //#endregion
110
+ //#region src/database/json-recordset.ts
111
+ function jsonTextValues(db, values) {
112
+ const payload = JSON.stringify([...new Set(values)]);
113
+ return isPostgres(db) ? sql`SELECT value::text AS value FROM jsonb_array_elements_text(${payload}::jsonb) AS value` : sql`SELECT value AS value FROM json_each(${payload})`;
114
+ }
115
+
103
116
  //#endregion
104
117
  //#region src/database/repositories/media-usage.ts
105
118
  const OCCURRENCE_BIND_COLUMNS = 13;
119
+ const D1_MAX_BOUND_PARAMETERS = 100;
106
120
  const MEDIA_USAGE_GENERATION_WRITE_LEASE_MS = 3600 * 1e3;
107
- const OCCURRENCE_INSERT_BATCH_SIZE = Math.max(1, Math.floor(SQL_BATCH_SIZE / OCCURRENCE_BIND_COLUMNS));
121
+ const OCCURRENCE_INSERT_BATCH_SIZE = Math.max(1, Math.floor(D1_MAX_BOUND_PARAMETERS / OCCURRENCE_BIND_COLUMNS));
108
122
  function cleanupDeleteBatchSize(cleanupLease) {
109
123
  return cleanupLease ? SQL_BATCH_SIZE - 3 : SQL_BATCH_SIZE;
110
124
  }
111
125
  function canIssueCleanupStatement(canIssueStatement) {
112
126
  return canIssueStatement?.() ?? true;
113
127
  }
128
+ function nullableRefMatch(left, right) {
129
+ const leftRef = sql.ref(left);
130
+ const rightRef = sql.ref(right);
131
+ return sql`(
132
+ (${leftRef} IS NULL AND ${rightRef} IS NULL)
133
+ OR ${leftRef} = ${rightRef}
134
+ )`;
135
+ }
136
+ const MAX_JSON_BIND_BYTES = 19e5;
137
+ const MEDIA_USAGE_EVENT_QUERY_CEILING = 900;
138
+ const MEDIA_USAGE_QUERY_RESERVE = 150;
139
+ function chunkJsonRows(rows) {
140
+ const batches = [];
141
+ let batch = [];
142
+ let batchBytes = 2;
143
+ for (const row of rows) {
144
+ const rowBytes = new TextEncoder().encode(JSON.stringify(row)).byteLength + (batch.length > 0 ? 1 : 0);
145
+ if (batch.length > 0 && batchBytes + rowBytes > MAX_JSON_BIND_BYTES) {
146
+ batches.push(batch);
147
+ batch = [];
148
+ batchBytes = 2;
149
+ }
150
+ batch.push(row);
151
+ batchBytes += rowBytes;
152
+ }
153
+ if (batch.length > 0) batches.push(batch);
154
+ return batches;
155
+ }
156
+ function mediaUsageQueryBudgetAllows(queries) {
157
+ const metrics = getRequestContext()?.metrics;
158
+ return !metrics || metrics.dbCount + queries + MEDIA_USAGE_QUERY_RESERVE <= MEDIA_USAGE_EVENT_QUERY_CEILING;
159
+ }
160
+ function mergeInto(target, source) {
161
+ for (const value of source) target.add(value);
162
+ }
163
+ function batchOccurrenceRows(prepared, now) {
164
+ return prepared.flatMap((item) => item.projection.occurrences.map((occurrence) => ({
165
+ id: ulid(),
166
+ source_key: item.row.source_key,
167
+ generation: item.generation,
168
+ field_slug: occurrence.fieldSlug,
169
+ field_path: occurrence.fieldPath,
170
+ occurrence_index: occurrence.occurrenceIndex ?? 0,
171
+ reference_type: occurrence.referenceType,
172
+ media_id: occurrence.mediaId,
173
+ provider: occurrence.provider,
174
+ provider_asset_id: occurrence.providerAssetId,
175
+ media_kind: occurrence.mediaKind ?? null,
176
+ mime_type: occurrence.mimeType ?? null,
177
+ created_at: now,
178
+ lease_token: item.leaseToken
179
+ })));
180
+ }
114
181
  function cleanupDurationSeconds(value) {
115
182
  if (!Number.isSafeInteger(value) || value < 0) throw new Error("Media usage cleanup duration must be a non-negative whole number of seconds");
116
183
  return value;
@@ -199,9 +266,14 @@ var MediaUsageRepository = class {
199
266
  const uniqueSourceKeys = [...new Set(sourceKeys)];
200
267
  const sources = /* @__PURE__ */ new Map();
201
268
  if (uniqueSourceKeys.length === 0) return sources;
202
- for (const sourceKeyBatch of chunks(uniqueSourceKeys, SQL_BATCH_SIZE)) {
203
- const rows = await this.db.selectFrom("_emdash_media_usage_sources").selectAll().where("source_key", "in", sourceKeyBatch).execute();
204
- for (const row of rows) {
269
+ for (const sourceKeyBatch of chunkJsonRows(uniqueSourceKeys)) {
270
+ const result = await sql`
271
+ WITH requested AS (${jsonTextValues(this.db, sourceKeyBatch)})
272
+ SELECT source.*
273
+ FROM _emdash_media_usage_sources AS source
274
+ INNER JOIN requested ON requested.value = source.source_key
275
+ `.execute(this.db);
276
+ for (const row of result.rows) {
205
277
  const source = rowToSource(row);
206
278
  sources.set(source.sourceKey, source);
207
279
  }
@@ -250,6 +322,388 @@ var MediaUsageRepository = class {
250
322
  source: replaced ? null : await this.findSource(source.sourceKey)
251
323
  };
252
324
  }
325
+ async replaceNewSourcesBatch(projections) {
326
+ const unique = [...new Map(projections.map((projection) => [projection.source.sourceKey, projection])).values()];
327
+ if (unique.length === 0) return /* @__PURE__ */ new Set();
328
+ const collectionSlug = unique[0]?.source.collectionSlug;
329
+ const collectionId = unique[0]?.source.collectionId;
330
+ if (!collectionSlug || !collectionId) throw new Error("Canonical media usage batch requires collection identity");
331
+ validateIdentifier(collectionSlug, "collection slug");
332
+ if (unique.some((projection) => projection.source.collectionSlug !== collectionSlug || projection.source.collectionId !== collectionId)) throw new Error("Canonical media usage batch must contain one collection");
333
+ const now = (/* @__PURE__ */ new Date()).toISOString();
334
+ const expiresAt = new Date(Date.now() + MEDIA_USAGE_GENERATION_WRITE_LEASE_MS).toISOString();
335
+ const prepared = unique.map((projection) => {
336
+ const generation = ulid();
337
+ return {
338
+ projection,
339
+ generation,
340
+ leaseToken: ulid(),
341
+ row: this.buildSourceRow(projection.source, generation, now)
342
+ };
343
+ });
344
+ const sourceRows = prepared.map((item) => ({
345
+ ...item.row,
346
+ lease_token: item.leaseToken
347
+ }));
348
+ const occurrenceRows = batchOccurrenceRows(prepared, now);
349
+ if (!mediaUsageQueryBudgetAllows(2 + chunkJsonRows(occurrenceRows).length + chunkJsonRows(sourceRows).length)) {
350
+ if (unique.length === 1) return /* @__PURE__ */ new Set();
351
+ const midpoint = Math.ceil(unique.length / 2);
352
+ const inserted = /* @__PURE__ */ new Set();
353
+ mergeInto(inserted, await this.replaceNewSourcesBatch(unique.slice(0, midpoint)));
354
+ mergeInto(inserted, await this.replaceNewSourcesBatch(unique.slice(midpoint)));
355
+ return inserted;
356
+ }
357
+ const leasesPayload = JSON.stringify(prepared.map((item) => ({
358
+ source_key: item.row.source_key,
359
+ collection_id: item.row.collection_id,
360
+ collection_slug: item.row.collection_slug,
361
+ generation: item.generation,
362
+ lease_token: item.leaseToken,
363
+ expires_at: expiresAt,
364
+ created_at: now
365
+ })));
366
+ const leases = this.generationWriteBatchInput(leasesPayload);
367
+ await sql`
368
+ WITH input AS (${leases})
369
+ INSERT INTO _emdash_media_usage_generation_writes (
370
+ source_key, generation, lease_token, expires_at, created_at
371
+ )
372
+ SELECT source_key, generation, lease_token, expires_at, created_at
373
+ FROM input
374
+ WHERE EXISTS (
375
+ SELECT 1
376
+ FROM _emdash_collections AS collection
377
+ INNER JOIN _emdash_media_usage_index_status AS status
378
+ ON status.collection_id = collection.id
379
+ AND status.scope_key = collection.slug
380
+ WHERE collection.id = input.collection_id
381
+ AND collection.slug = input.collection_slug
382
+ AND status.adapter_id = 'content-media'
383
+ AND status.scope_type = 'collection'
384
+ AND status.capture_state = 'active'
385
+ AND NOT EXISTS (
386
+ SELECT 1 FROM _emdash_media_usage_collection_deletions AS deletion
387
+ WHERE deletion.collection_id = input.collection_id
388
+ )
389
+ )
390
+ `.execute(this.db);
391
+ try {
392
+ await this.insertBatchOccurrences(occurrenceRows);
393
+ const tableName = `ec_${collectionSlug}`;
394
+ validateIdentifier(tableName, "content table");
395
+ const inserted = /* @__PURE__ */ new Set();
396
+ for (const sourceRowBatch of chunkJsonRows(sourceRows)) {
397
+ const result = await sql`
398
+ WITH input AS (${this.sourceBatchInput(JSON.stringify(sourceRowBatch))})
399
+ INSERT INTO _emdash_media_usage_sources (
400
+ source_key, source_type, collection_id, collection_slug, content_id,
401
+ source_variant, locale, translation_group, content_slug, content_title,
402
+ content_status, content_scheduled_at, content_deleted_at, revision_id,
403
+ current_generation, schema_version, source_updated_at, source_version,
404
+ source_fingerprint, identity_version, source_completeness,
405
+ last_attempted_at, last_error_code, indexed_at, updated_at
406
+ )
407
+ SELECT
408
+ input.source_key, input.source_type, input.collection_id, input.collection_slug,
409
+ input.content_id, input.source_variant, input.locale, input.translation_group,
410
+ input.content_slug, input.content_title, input.content_status,
411
+ input.content_scheduled_at, input.content_deleted_at, input.revision_id,
412
+ input.current_generation, input.schema_version, input.source_updated_at,
413
+ input.source_version, input.source_fingerprint, input.identity_version,
414
+ input.source_completeness, input.last_attempted_at, input.last_error_code,
415
+ input.indexed_at, input.updated_at
416
+ FROM input
417
+ WHERE EXISTS (
418
+ SELECT 1
419
+ FROM _emdash_media_usage_generation_writes AS writer
420
+ WHERE writer.source_key = input.source_key
421
+ AND writer.generation = input.current_generation
422
+ AND writer.lease_token = input.lease_token
423
+ AND ${this.generationWriteLeaseExpiryIsInFuture("writer.expires_at")}
424
+ )
425
+ AND EXISTS (
426
+ SELECT 1
427
+ FROM _emdash_collections AS collection
428
+ INNER JOIN _emdash_media_usage_index_status AS status
429
+ ON status.collection_id = collection.id
430
+ AND status.scope_key = collection.slug
431
+ WHERE collection.id = input.collection_id
432
+ AND collection.slug = input.collection_slug
433
+ AND status.adapter_id = 'content-media'
434
+ AND status.scope_type = 'collection'
435
+ AND status.capture_state = 'active'
436
+ AND NOT EXISTS (
437
+ SELECT 1
438
+ FROM _emdash_media_usage_collection_deletions AS deletion
439
+ WHERE deletion.collection_id = input.collection_id
440
+ )
441
+ )
442
+ AND EXISTS (
443
+ SELECT 1
444
+ FROM ${sql.ref(tableName)} AS content
445
+ WHERE content.id = input.content_id
446
+ AND content.version = input.source_version
447
+ AND content.updated_at = input.source_updated_at
448
+ AND (
449
+ (input.source_variant = 'columns' AND ${nullableRefMatch("content.live_revision_id", "input.revision_id")})
450
+ OR
451
+ (input.source_variant = 'draft_overlay' AND ${nullableRefMatch("content.draft_revision_id", "input.revision_id")})
452
+ )
453
+ )
454
+ ON CONFLICT (source_key) DO NOTHING
455
+ RETURNING source_key
456
+ `.execute(this.db);
457
+ for (const row of result.rows) inserted.add(row.source_key);
458
+ }
459
+ return inserted;
460
+ } finally {
461
+ await sql`
462
+ WITH input AS (${leases})
463
+ DELETE FROM _emdash_media_usage_generation_writes AS writer
464
+ WHERE EXISTS (
465
+ SELECT 1
466
+ FROM input
467
+ WHERE input.source_key = writer.source_key
468
+ AND input.generation = writer.generation
469
+ AND input.lease_token = writer.lease_token
470
+ )
471
+ `.execute(this.db);
472
+ }
473
+ }
474
+ async replaceExistingSourcesBatch(projections) {
475
+ const unique = [...new Map(projections.map((projection) => [projection.source.sourceKey, projection])).values()];
476
+ if (unique.length === 0) return /* @__PURE__ */ new Set();
477
+ const collectionSlug = unique[0]?.source.collectionSlug;
478
+ const collectionId = unique[0]?.source.collectionId;
479
+ if (!collectionSlug || !collectionId) throw new Error("Canonical media usage batch requires collection identity");
480
+ validateIdentifier(collectionSlug, "collection slug");
481
+ if (unique.some((projection) => projection.source.collectionSlug !== collectionSlug || projection.source.collectionId !== collectionId)) throw new Error("Canonical media usage batch must contain one collection");
482
+ const now = (/* @__PURE__ */ new Date()).toISOString();
483
+ const expiresAt = new Date(Date.now() + MEDIA_USAGE_GENERATION_WRITE_LEASE_MS).toISOString();
484
+ const prepared = unique.map((projection) => {
485
+ const generation = ulid();
486
+ return {
487
+ projection,
488
+ generation,
489
+ leaseToken: ulid(),
490
+ row: this.buildSourceRow(projection.source, generation, now)
491
+ };
492
+ });
493
+ const sourceRows = prepared.map((item) => ({
494
+ ...item.row,
495
+ lease_token: item.leaseToken,
496
+ expected_generation: item.projection.expectedSource.currentGeneration,
497
+ expected_collection_id: item.projection.expectedSource.collectionId,
498
+ expected_updated_at: item.projection.expectedSource.updatedAt,
499
+ expected_source_fingerprint: item.projection.expectedSource.sourceFingerprint,
500
+ expected_source_updated_at: item.projection.expectedSource.sourceUpdatedAt,
501
+ expected_source_version: item.projection.expectedSource.sourceVersion,
502
+ expected_identity_version: item.projection.expectedSource.identityVersion,
503
+ expected_revision_id: item.projection.expectedSource.revisionId,
504
+ expected_source_completeness: item.projection.expectedSource.sourceCompleteness,
505
+ expected_last_attempted_at: item.projection.expectedSource.lastAttemptedAt,
506
+ expected_last_error_code: item.projection.expectedSource.lastErrorCode
507
+ }));
508
+ const occurrenceRows = batchOccurrenceRows(prepared, now);
509
+ if (!mediaUsageQueryBudgetAllows(2 + chunkJsonRows(occurrenceRows).length + chunkJsonRows(sourceRows).length)) {
510
+ if (unique.length === 1) return /* @__PURE__ */ new Set();
511
+ const midpoint = Math.ceil(unique.length / 2);
512
+ const replaced = /* @__PURE__ */ new Set();
513
+ mergeInto(replaced, await this.replaceExistingSourcesBatch(unique.slice(0, midpoint)));
514
+ mergeInto(replaced, await this.replaceExistingSourcesBatch(unique.slice(midpoint)));
515
+ return replaced;
516
+ }
517
+ const leasesPayload = JSON.stringify(prepared.map((item) => ({
518
+ source_key: item.row.source_key,
519
+ collection_id: item.row.collection_id,
520
+ collection_slug: item.row.collection_slug,
521
+ generation: item.generation,
522
+ lease_token: item.leaseToken,
523
+ expires_at: expiresAt,
524
+ created_at: now
525
+ })));
526
+ const leases = this.generationWriteBatchInput(leasesPayload);
527
+ await sql`
528
+ WITH input AS (${leases})
529
+ INSERT INTO _emdash_media_usage_generation_writes (
530
+ source_key, generation, lease_token, expires_at, created_at
531
+ )
532
+ SELECT source_key, generation, lease_token, expires_at, created_at
533
+ FROM input
534
+ WHERE EXISTS (
535
+ SELECT 1
536
+ FROM _emdash_collections AS collection
537
+ INNER JOIN _emdash_media_usage_index_status AS status
538
+ ON status.collection_id = collection.id
539
+ AND status.scope_key = collection.slug
540
+ WHERE collection.id = input.collection_id
541
+ AND collection.slug = input.collection_slug
542
+ AND status.adapter_id = 'content-media'
543
+ AND status.scope_type = 'collection'
544
+ AND status.capture_state = 'active'
545
+ AND NOT EXISTS (
546
+ SELECT 1 FROM _emdash_media_usage_collection_deletions AS deletion
547
+ WHERE deletion.collection_id = input.collection_id
548
+ )
549
+ )
550
+ `.execute(this.db);
551
+ try {
552
+ await this.insertBatchOccurrences(occurrenceRows);
553
+ const tableName = `ec_${collectionSlug}`;
554
+ validateIdentifier(tableName, "content table");
555
+ const replaced = /* @__PURE__ */ new Set();
556
+ for (const sourceRowBatch of chunkJsonRows(sourceRows)) {
557
+ const result = await sql`
558
+ WITH input AS (${this.sourceBatchInput(JSON.stringify(sourceRowBatch))})
559
+ UPDATE _emdash_media_usage_sources AS source
560
+ SET source_type = input.source_type,
561
+ collection_id = input.collection_id,
562
+ collection_slug = input.collection_slug,
563
+ content_id = input.content_id,
564
+ source_variant = input.source_variant,
565
+ locale = input.locale,
566
+ translation_group = input.translation_group,
567
+ content_slug = input.content_slug,
568
+ content_title = input.content_title,
569
+ content_status = input.content_status,
570
+ content_scheduled_at = input.content_scheduled_at,
571
+ content_deleted_at = input.content_deleted_at,
572
+ revision_id = input.revision_id,
573
+ current_generation = input.current_generation,
574
+ schema_version = input.schema_version,
575
+ source_updated_at = input.source_updated_at,
576
+ source_version = input.source_version,
577
+ source_fingerprint = input.source_fingerprint,
578
+ identity_version = input.identity_version,
579
+ source_completeness = input.source_completeness,
580
+ last_attempted_at = input.last_attempted_at,
581
+ last_error_code = input.last_error_code,
582
+ indexed_at = input.indexed_at,
583
+ updated_at = input.updated_at
584
+ FROM input
585
+ WHERE source.source_key = input.source_key
586
+ AND source.current_generation = input.expected_generation
587
+ AND ${this.batchRefsMatch("source.collection_id", "input.expected_collection_id")}
588
+ AND source.updated_at = input.expected_updated_at
589
+ AND ${this.batchRefsMatch("source.source_fingerprint", "input.expected_source_fingerprint")}
590
+ AND ${this.batchRefsMatch("source.source_updated_at", "input.expected_source_updated_at")}
591
+ AND ${this.batchRefsMatch("source.source_version", "input.expected_source_version")}
592
+ AND ${this.batchRefsMatch("source.identity_version", "input.expected_identity_version")}
593
+ AND ${this.batchRefsMatch("source.revision_id", "input.expected_revision_id")}
594
+ AND source.source_completeness = input.expected_source_completeness
595
+ AND ${this.batchRefsMatch("source.last_attempted_at", "input.expected_last_attempted_at")}
596
+ AND ${this.batchRefsMatch("source.last_error_code", "input.expected_last_error_code")}
597
+ AND EXISTS (
598
+ SELECT 1
599
+ FROM _emdash_media_usage_generation_writes AS writer
600
+ WHERE writer.source_key = input.source_key
601
+ AND writer.generation = input.current_generation
602
+ AND writer.lease_token = input.lease_token
603
+ AND ${this.generationWriteLeaseExpiryIsInFuture("writer.expires_at")}
604
+ )
605
+ AND EXISTS (
606
+ SELECT 1
607
+ FROM _emdash_collections AS collection
608
+ INNER JOIN _emdash_media_usage_index_status AS status
609
+ ON status.collection_id = collection.id
610
+ AND status.scope_key = collection.slug
611
+ WHERE collection.id = input.collection_id
612
+ AND collection.slug = input.collection_slug
613
+ AND status.adapter_id = 'content-media'
614
+ AND status.scope_type = 'collection'
615
+ AND status.capture_state = 'active'
616
+ AND NOT EXISTS (
617
+ SELECT 1
618
+ FROM _emdash_media_usage_collection_deletions AS deletion
619
+ WHERE deletion.collection_id = input.collection_id
620
+ )
621
+ )
622
+ AND EXISTS (
623
+ SELECT 1
624
+ FROM ${sql.ref(tableName)} AS content
625
+ WHERE content.id = input.content_id
626
+ AND content.version = input.source_version
627
+ AND content.updated_at = input.source_updated_at
628
+ AND (
629
+ (input.source_variant = 'columns' AND ${nullableRefMatch("content.live_revision_id", "input.revision_id")})
630
+ OR
631
+ (input.source_variant = 'draft_overlay' AND ${nullableRefMatch("content.draft_revision_id", "input.revision_id")})
632
+ )
633
+ )
634
+ RETURNING ${isPostgres(this.db) ? sql`source.source_key` : sql`source_key`} AS source_key
635
+ `.execute(this.db);
636
+ for (const row of result.rows) replaced.add(row.source_key);
637
+ }
638
+ return replaced;
639
+ } finally {
640
+ await sql`
641
+ WITH input AS (${leases})
642
+ DELETE FROM _emdash_media_usage_generation_writes AS writer
643
+ WHERE EXISTS (
644
+ SELECT 1
645
+ FROM input
646
+ WHERE input.source_key = writer.source_key
647
+ AND input.generation = writer.generation
648
+ AND input.lease_token = writer.lease_token
649
+ )
650
+ `.execute(this.db);
651
+ }
652
+ }
653
+ async matchingExistingSourcesBatch(projections) {
654
+ if (projections.length === 0) return /* @__PURE__ */ new Set();
655
+ const now = (/* @__PURE__ */ new Date()).toISOString();
656
+ const rows = projections.map((projection) => ({
657
+ ...this.buildSourceRow(projection.source, projection.expectedSource.currentGeneration, now),
658
+ expected_generation: projection.expectedSource.currentGeneration,
659
+ expected_collection_id: projection.expectedSource.collectionId,
660
+ expected_updated_at: projection.expectedSource.updatedAt,
661
+ expected_source_fingerprint: projection.expectedSource.sourceFingerprint,
662
+ expected_source_updated_at: projection.expectedSource.sourceUpdatedAt,
663
+ expected_source_version: projection.expectedSource.sourceVersion,
664
+ expected_identity_version: projection.expectedSource.identityVersion,
665
+ expected_revision_id: projection.expectedSource.revisionId,
666
+ expected_source_completeness: projection.expectedSource.sourceCompleteness,
667
+ expected_last_attempted_at: projection.expectedSource.lastAttemptedAt,
668
+ expected_last_error_code: projection.expectedSource.lastErrorCode
669
+ }));
670
+ if (!mediaUsageQueryBudgetAllows(chunkJsonRows(rows).length)) {
671
+ if (projections.length === 1) return /* @__PURE__ */ new Set();
672
+ const midpoint = Math.ceil(projections.length / 2);
673
+ const matched = /* @__PURE__ */ new Set();
674
+ mergeInto(matched, await this.matchingExistingSourcesBatch(projections.slice(0, midpoint)));
675
+ mergeInto(matched, await this.matchingExistingSourcesBatch(projections.slice(midpoint)));
676
+ return matched;
677
+ }
678
+ const matched = /* @__PURE__ */ new Set();
679
+ for (const batch of chunkJsonRows(rows)) {
680
+ const result = await sql`
681
+ WITH input AS (${this.sourceBatchInput(JSON.stringify(batch))})
682
+ SELECT source.source_key
683
+ FROM _emdash_media_usage_sources AS source
684
+ INNER JOIN input ON input.source_key = source.source_key
685
+ WHERE source.current_generation = input.expected_generation
686
+ AND ${this.batchRefsMatch("source.collection_id", "input.expected_collection_id")}
687
+ AND source.updated_at = input.expected_updated_at
688
+ AND ${this.batchRefsMatch("source.source_fingerprint", "input.expected_source_fingerprint")}
689
+ AND ${this.batchRefsMatch("source.source_updated_at", "input.expected_source_updated_at")}
690
+ AND ${this.batchRefsMatch("source.source_version", "input.expected_source_version")}
691
+ AND ${this.batchRefsMatch("source.identity_version", "input.expected_identity_version")}
692
+ AND ${this.batchRefsMatch("source.revision_id", "input.expected_revision_id")}
693
+ AND source.source_completeness = input.expected_source_completeness
694
+ AND ${this.batchRefsMatch("source.last_attempted_at", "input.expected_last_attempted_at")}
695
+ AND ${this.batchRefsMatch("source.last_error_code", "input.expected_last_error_code")}
696
+ AND EXISTS (
697
+ SELECT 1
698
+ FROM _emdash_collections AS collection
699
+ WHERE collection.id = source.collection_id
700
+ AND collection.slug = source.collection_slug
701
+ )
702
+ `.execute(this.db);
703
+ for (const row of result.rows) matched.add(row.source_key);
704
+ }
705
+ return matched;
706
+ }
253
707
  async markSourceAttempted(source) {
254
708
  if (source.collectionId !== void 0 && source.collectionId !== null) {
255
709
  const expectedSource = await this.findSource(source.sourceKey);
@@ -317,6 +771,103 @@ var MediaUsageRepository = class {
317
771
  reconciliationRequired: row.reconciliation_required !== null && Number(row.reconciliation_required) !== 0
318
772
  }));
319
773
  }
774
+ async findCollectionProgress() {
775
+ const row = (await sql`
776
+ WITH collection_progress AS (
777
+ SELECT
778
+ CASE WHEN status.status = 'complete'
779
+ AND status.schema_version = ${CONTENT_SOURCE_SCHEMA_VERSION}
780
+ AND status.reconciliation_required = 0
781
+ AND status.capture_state = 'active'
782
+ AND NOT EXISTS (
783
+ SELECT 1 FROM _emdash_media_usage_work AS work
784
+ WHERE work.collection_id = collection.id
785
+ AND work.collection_slug = collection.slug
786
+ )
787
+ THEN 1 ELSE 0 END AS is_ready,
788
+ CASE WHEN status.collection_id IS NULL
789
+ OR COALESCE(status.capture_state, '') <> 'active'
790
+ OR status.status NOT IN ('complete', 'never', 'running', 'partial', 'failed', 'stale')
791
+ OR status.status = 'failed'
792
+ OR (
793
+ status.reconciliation_required = 0
794
+ AND (
795
+ status.status <> 'complete'
796
+ OR COALESCE(status.schema_version, -1) <> ${CONTENT_SOURCE_SCHEMA_VERSION}
797
+ )
798
+ AND NOT EXISTS (
799
+ SELECT 1 FROM _emdash_media_usage_work AS work
800
+ WHERE work.collection_id = collection.id
801
+ AND work.collection_slug = collection.slug
802
+ )
803
+ )
804
+ OR EXISTS (
805
+ SELECT 1 FROM _emdash_media_usage_work AS work
806
+ WHERE work.collection_id = collection.id
807
+ AND work.collection_slug = collection.slug
808
+ AND work.state = 'failed'
809
+ )
810
+ OR EXISTS (
811
+ SELECT 1 FROM _emdash_media_usage_reconciliations AS reconciliation
812
+ WHERE reconciliation.collection_id = collection.id
813
+ AND reconciliation.collection_slug = collection.slug
814
+ AND reconciliation.state = 'failed'
815
+ AND status.reconciliation_required = 1
816
+ AND (
817
+ reconciliation.target_epoch IS NULL
818
+ OR reconciliation.target_epoch >= status.change_epoch
819
+ )
820
+ )
821
+ THEN 1 ELSE 0 END AS needs_attention
822
+ FROM _emdash_collections AS collection
823
+ LEFT JOIN _emdash_media_usage_index_status AS status
824
+ ON status.adapter_id = 'content-media'
825
+ AND status.scope_type = 'collection'
826
+ AND status.collection_id = collection.id
827
+ AND status.scope_key = collection.slug
828
+ WHERE NOT EXISTS (
829
+ SELECT 1 FROM _emdash_media_usage_collection_deletions AS deletion
830
+ WHERE deletion.collection_id = collection.id
831
+ AND deletion.collection_slug = collection.slug
832
+ )
833
+ )
834
+ SELECT
835
+ (
836
+ SELECT activation.runtime_generation
837
+ FROM _emdash_media_usage_activation AS activation
838
+ WHERE activation.task_key = 'incremental_capture'
839
+ ) AS activation_generation,
840
+ EXISTS (
841
+ SELECT 1 FROM _emdash_media_usage_activation AS activation
842
+ WHERE activation.task_key = 'incremental_capture'
843
+ AND activation.state = 'active'
844
+ ) AS activation_active,
845
+ COUNT(*) AS total_collections,
846
+ COALESCE(SUM(is_ready), 0) AS ready_collections,
847
+ EXISTS (
848
+ SELECT 1 FROM _emdash_media_usage_collection_deletions AS deletion
849
+ WHERE deletion.state IN ('pending', 'retry', 'leased')
850
+ ) AS cleanup_pending,
851
+ CASE WHEN COALESCE(MAX(needs_attention), 0) = 1 OR EXISTS (
852
+ SELECT 1 FROM _emdash_media_usage_collection_deletions AS deletion
853
+ WHERE deletion.state = 'failed'
854
+ ) THEN 1 ELSE 0 END AS needs_attention
855
+ FROM collection_progress
856
+ `.execute(this.db)).rows[0];
857
+ if (!row) throw new Error("Media usage progress query returned no result");
858
+ if (!row.activation_active) return null;
859
+ if (Number(row.activation_generation) !== MEDIA_USAGE_ACTIVATION_RUNTIME_GENERATION) throw new MediaUsageActivationVersionMismatchError("Media usage activation runtime generation is incompatible");
860
+ const readyCollections = Number(row.ready_collections);
861
+ const totalCollections = Number(row.total_collections);
862
+ const cleanupPending = Number(row.cleanup_pending);
863
+ const needsAttention = Number(row.needs_attention);
864
+ if (!Number.isSafeInteger(readyCollections) || !Number.isSafeInteger(totalCollections) || readyCollections < 0 || totalCollections < readyCollections || cleanupPending !== 0 && cleanupPending !== 1 || needsAttention !== 0 && needsAttention !== 1) throw new Error("Media usage progress query returned invalid counts");
865
+ return {
866
+ status: needsAttention ? "needs_attention" : readyCollections === totalCollections && cleanupPending === 0 ? "ready" : "indexing",
867
+ readyCollections,
868
+ totalCollections
869
+ };
870
+ }
320
871
  async findCurrentEntryUsagePageByMediaId(mediaId, options = {}) {
321
872
  const requestedLimit = Math.floor(options.limit ?? 50);
322
873
  const limit = Number.isFinite(requestedLimit) ? Math.min(Math.max(1, requestedLimit), 100) : 50;
@@ -746,6 +1297,7 @@ var MediaUsageRepository = class {
746
1297
  status: sql`CASE WHEN ${canComplete} THEN 'complete' ELSE status END`,
747
1298
  completed_at: sql`CASE WHEN ${canComplete} THEN ${now} ELSE completed_at END`,
748
1299
  last_error_code: sql`CASE WHEN ${canComplete} THEN NULL ELSE last_error_code END`,
1300
+ cursor: sql`CASE WHEN ${canComplete} THEN NULL ELSE cursor END`,
749
1301
  last_incremental_success_at: now,
750
1302
  updated_at: now
751
1303
  }).where("adapter_id", "=", "content-media").where("scope_type", "=", "collection").where("scope_key", "=", input.collectionSlug).where("collection_id", "=", input.collectionId).where("change_epoch", "=", observed.change_epoch).where("capture_state", "=", "active").where(sql`EXISTS (
@@ -756,6 +1308,65 @@ var MediaUsageRepository = class {
756
1308
  )`).executeTakeFirst();
757
1309
  return Number(result.numUpdatedRows ?? 0) > 0;
758
1310
  }
1311
+ async prepareIncrementalFinalization(input) {
1312
+ const observed = await this.db.selectFrom("_emdash_media_usage_index_status").select(["change_epoch", "reconciliation_required"]).where("adapter_id", "=", "content-media").where("scope_type", "=", "collection").where("scope_key", "=", input.collectionSlug).where("collection_id", "=", input.collectionId).where("capture_state", "=", "active").executeTakeFirst();
1313
+ if (!observed) return { outcome: "lost" };
1314
+ if (observed.reconciliation_required !== 0) return { outcome: "not_required" };
1315
+ const marker = `incremental-finalize:${String(observed.change_epoch)}:${ulid()}`;
1316
+ const result = await this.db.updateTable("_emdash_media_usage_index_status").set({
1317
+ cursor: marker,
1318
+ updated_at: this.sortableUtcTimestamp()
1319
+ }).where("adapter_id", "=", "content-media").where("scope_type", "=", "collection").where("scope_key", "=", input.collectionSlug).where("collection_id", "=", input.collectionId).where("capture_state", "=", "active").where("reconciliation_required", "=", 0).where("change_epoch", "=", observed.change_epoch).where(sql`EXISTS (
1320
+ SELECT 1
1321
+ FROM _emdash_collections AS collection
1322
+ WHERE collection.id = ${input.collectionId}
1323
+ AND collection.slug = ${input.collectionSlug}
1324
+ )`).where(sql`NOT EXISTS (
1325
+ SELECT 1
1326
+ FROM _emdash_media_usage_collection_deletions AS deletion
1327
+ WHERE deletion.collection_id = ${input.collectionId}
1328
+ )`).executeTakeFirst();
1329
+ return Number(result.numUpdatedRows ?? 0) > 0 ? {
1330
+ outcome: "marked",
1331
+ marker
1332
+ } : { outcome: "lost" };
1333
+ }
1334
+ async recoverIncrementalFinalizations() {
1335
+ const markerMatchesEpoch = isPostgres(this.db) ? sql`status.cursor LIKE ('incremental-finalize:' || status.change_epoch::text || ':%')` : sql`status.cursor LIKE ('incremental-finalize:' || CAST(status.change_epoch AS text) || ':%')`;
1336
+ const now = (/* @__PURE__ */ new Date()).toISOString();
1337
+ return (await sql`
1338
+ UPDATE _emdash_media_usage_index_status AS status
1339
+ SET status = 'complete',
1340
+ completed_at = ${now},
1341
+ cursor = NULL,
1342
+ last_error_code = NULL,
1343
+ last_incremental_success_at = ${now},
1344
+ updated_at = ${now}
1345
+ WHERE status.adapter_id = 'content-media'
1346
+ AND status.scope_type = 'collection'
1347
+ AND status.capture_state = 'active'
1348
+ AND status.reconciliation_required = 0
1349
+ AND status.cursor IS NOT NULL
1350
+ AND ${markerMatchesEpoch}
1351
+ AND EXISTS (
1352
+ SELECT 1
1353
+ FROM _emdash_collections AS collection
1354
+ WHERE collection.id = status.collection_id
1355
+ AND collection.slug = status.scope_key
1356
+ )
1357
+ AND NOT EXISTS (
1358
+ SELECT 1
1359
+ FROM _emdash_media_usage_collection_deletions AS deletion
1360
+ WHERE deletion.collection_id = status.collection_id
1361
+ )
1362
+ AND NOT EXISTS (
1363
+ SELECT 1
1364
+ FROM _emdash_media_usage_work AS work
1365
+ WHERE work.collection_id = status.collection_id
1366
+ )
1367
+ RETURNING collection_id
1368
+ `.execute(this.db)).rows.length;
1369
+ }
759
1370
  async recordIncrementalFailure(input) {
760
1371
  const now = this.sortableUtcTimestamp();
761
1372
  const automaticRunOwnsCoverage = sql`EXISTS (
@@ -799,6 +1410,67 @@ var MediaUsageRepository = class {
799
1410
  )`).executeTakeFirst();
800
1411
  return Number(result.numUpdatedRows ?? 0) > 0;
801
1412
  }
1413
+ async recordIncrementalFailuresByCollection(input) {
1414
+ const collectionIds = [...new Set(input.collectionIds)];
1415
+ if (collectionIds.length === 0) return /* @__PURE__ */ new Set();
1416
+ const collections = jsonTextValues(this.db, collectionIds);
1417
+ const now = (/* @__PURE__ */ new Date()).toISOString();
1418
+ const result = await sql`
1419
+ WITH failed_collections AS (${collections})
1420
+ UPDATE _emdash_media_usage_index_status AS status
1421
+ SET status = CASE
1422
+ WHEN EXISTS (
1423
+ SELECT 1
1424
+ FROM _emdash_media_usage_reconciliations AS reconciliation
1425
+ WHERE reconciliation.collection_id = status.collection_id
1426
+ AND reconciliation.run_token = status.cursor
1427
+ ) THEN status.status
1428
+ WHEN status.reconciliation_required = 0 THEN 'partial'
1429
+ WHEN status.status = 'running' THEN 'stale'
1430
+ ELSE status.status
1431
+ END,
1432
+ completed_at = CASE
1433
+ WHEN EXISTS (
1434
+ SELECT 1
1435
+ FROM _emdash_media_usage_reconciliations AS reconciliation
1436
+ WHERE reconciliation.collection_id = status.collection_id
1437
+ AND reconciliation.run_token = status.cursor
1438
+ ) THEN status.completed_at
1439
+ WHEN status.reconciliation_required = 0 OR status.status = 'running' THEN NULL
1440
+ ELSE status.completed_at
1441
+ END,
1442
+ cursor = CASE
1443
+ WHEN EXISTS (
1444
+ SELECT 1
1445
+ FROM _emdash_media_usage_reconciliations AS reconciliation
1446
+ WHERE reconciliation.collection_id = status.collection_id
1447
+ AND reconciliation.run_token = status.cursor
1448
+ ) THEN status.cursor
1449
+ WHEN status.status = 'running' THEN NULL
1450
+ ELSE status.cursor
1451
+ END,
1452
+ last_error_code = ${input.errorCode},
1453
+ updated_at = ${now}
1454
+ WHERE status.adapter_id = 'content-media'
1455
+ AND status.scope_type = 'collection'
1456
+ AND status.collection_id IN (SELECT value FROM failed_collections)
1457
+ AND EXISTS (
1458
+ SELECT 1
1459
+ FROM _emdash_media_usage_work AS work
1460
+ WHERE work.collection_id = status.collection_id
1461
+ AND work.state = 'failed'
1462
+ AND work.last_error_code = ${input.errorCode}
1463
+ )
1464
+ AND EXISTS (
1465
+ SELECT 1
1466
+ FROM _emdash_collections AS collection
1467
+ WHERE collection.id = status.collection_id
1468
+ AND collection.slug = status.scope_key
1469
+ )
1470
+ RETURNING collection_id
1471
+ `.execute(this.db);
1472
+ return new Set(result.rows.map((row) => row.collection_id));
1473
+ }
802
1474
  async findIndexStatus(identity) {
803
1475
  const row = await this.db.selectFrom("_emdash_media_usage_index_status").selectAll().where("adapter_id", "=", identity.adapterId).where("scope_type", "=", identity.scopeType).where("scope_key", "=", identity.scopeKey).executeTakeFirst();
804
1476
  return row ? rowToIndexStatus(row) : null;
@@ -982,6 +1654,180 @@ var MediaUsageRepository = class {
982
1654
  }));
983
1655
  for (const rowBatch of chunks(rows, OCCURRENCE_INSERT_BATCH_SIZE)) await db.insertInto("_emdash_media_usage").values(rowBatch).execute();
984
1656
  }
1657
+ async insertBatchOccurrences(rows) {
1658
+ for (const rowBatch of chunkJsonRows(rows)) await sql`
1659
+ WITH input AS (${this.occurrenceBatchInput(JSON.stringify(rowBatch))})
1660
+ INSERT INTO _emdash_media_usage (
1661
+ id, source_key, generation, field_slug, field_path, occurrence_index,
1662
+ reference_type, media_id, provider, provider_asset_id, media_kind,
1663
+ mime_type, created_at
1664
+ )
1665
+ SELECT
1666
+ id, source_key, generation, field_slug, field_path, occurrence_index,
1667
+ reference_type, media_id, provider, provider_asset_id, media_kind,
1668
+ mime_type, created_at
1669
+ FROM input
1670
+ WHERE EXISTS (
1671
+ SELECT 1
1672
+ FROM _emdash_media_usage_generation_writes AS writer
1673
+ WHERE writer.source_key = input.source_key
1674
+ AND writer.generation = input.generation
1675
+ AND writer.lease_token = input.lease_token
1676
+ AND ${this.generationWriteLeaseExpiryIsInFuture("writer.expires_at")}
1677
+ )
1678
+ `.execute(this.db);
1679
+ }
1680
+ occurrenceBatchInput(payload) {
1681
+ if (isPostgres(this.db)) return sql`
1682
+ SELECT
1683
+ entry.value ->> 'id' AS id,
1684
+ entry.value ->> 'source_key' AS source_key,
1685
+ entry.value ->> 'generation' AS generation,
1686
+ entry.value ->> 'field_slug' AS field_slug,
1687
+ entry.value ->> 'field_path' AS field_path,
1688
+ CAST(entry.value ->> 'occurrence_index' AS integer) AS occurrence_index,
1689
+ entry.value ->> 'reference_type' AS reference_type,
1690
+ entry.value ->> 'media_id' AS media_id,
1691
+ entry.value ->> 'provider' AS provider,
1692
+ entry.value ->> 'provider_asset_id' AS provider_asset_id,
1693
+ entry.value ->> 'media_kind' AS media_kind,
1694
+ entry.value ->> 'mime_type' AS mime_type,
1695
+ entry.value ->> 'created_at' AS created_at,
1696
+ entry.value ->> 'lease_token' AS lease_token
1697
+ FROM jsonb_array_elements(${payload}::jsonb) AS entry(value)
1698
+ `;
1699
+ return sql`
1700
+ SELECT
1701
+ json_extract(entry.value, '$.id') AS id,
1702
+ json_extract(entry.value, '$.source_key') AS source_key,
1703
+ json_extract(entry.value, '$.generation') AS generation,
1704
+ json_extract(entry.value, '$.field_slug') AS field_slug,
1705
+ json_extract(entry.value, '$.field_path') AS field_path,
1706
+ CAST(json_extract(entry.value, '$.occurrence_index') AS integer) AS occurrence_index,
1707
+ json_extract(entry.value, '$.reference_type') AS reference_type,
1708
+ json_extract(entry.value, '$.media_id') AS media_id,
1709
+ json_extract(entry.value, '$.provider') AS provider,
1710
+ json_extract(entry.value, '$.provider_asset_id') AS provider_asset_id,
1711
+ json_extract(entry.value, '$.media_kind') AS media_kind,
1712
+ json_extract(entry.value, '$.mime_type') AS mime_type,
1713
+ json_extract(entry.value, '$.created_at') AS created_at,
1714
+ json_extract(entry.value, '$.lease_token') AS lease_token
1715
+ FROM json_each(${payload}) AS entry
1716
+ `;
1717
+ }
1718
+ sourceBatchInput(payload) {
1719
+ if (isPostgres(this.db)) return sql`
1720
+ SELECT
1721
+ entry.value ->> 'source_key' AS source_key,
1722
+ entry.value ->> 'source_type' AS source_type,
1723
+ entry.value ->> 'collection_id' AS collection_id,
1724
+ entry.value ->> 'collection_slug' AS collection_slug,
1725
+ entry.value ->> 'content_id' AS content_id,
1726
+ entry.value ->> 'source_variant' AS source_variant,
1727
+ entry.value ->> 'locale' AS locale,
1728
+ entry.value ->> 'translation_group' AS translation_group,
1729
+ entry.value ->> 'content_slug' AS content_slug,
1730
+ entry.value ->> 'content_title' AS content_title,
1731
+ entry.value ->> 'content_status' AS content_status,
1732
+ entry.value ->> 'content_scheduled_at' AS content_scheduled_at,
1733
+ entry.value ->> 'content_deleted_at' AS content_deleted_at,
1734
+ entry.value ->> 'revision_id' AS revision_id,
1735
+ entry.value ->> 'current_generation' AS current_generation,
1736
+ CAST(entry.value ->> 'schema_version' AS integer) AS schema_version,
1737
+ entry.value ->> 'source_updated_at' AS source_updated_at,
1738
+ CAST(entry.value ->> 'source_version' AS bigint) AS source_version,
1739
+ entry.value ->> 'source_fingerprint' AS source_fingerprint,
1740
+ CAST(entry.value ->> 'identity_version' AS integer) AS identity_version,
1741
+ entry.value ->> 'source_completeness' AS source_completeness,
1742
+ entry.value ->> 'last_attempted_at' AS last_attempted_at,
1743
+ entry.value ->> 'last_error_code' AS last_error_code,
1744
+ entry.value ->> 'indexed_at' AS indexed_at,
1745
+ entry.value ->> 'updated_at' AS updated_at,
1746
+ entry.value ->> 'lease_token' AS lease_token,
1747
+ entry.value ->> 'expected_generation' AS expected_generation,
1748
+ entry.value ->> 'expected_collection_id' AS expected_collection_id,
1749
+ entry.value ->> 'expected_updated_at' AS expected_updated_at,
1750
+ entry.value ->> 'expected_source_fingerprint' AS expected_source_fingerprint,
1751
+ entry.value ->> 'expected_source_updated_at' AS expected_source_updated_at,
1752
+ CAST(entry.value ->> 'expected_source_version' AS bigint) AS expected_source_version,
1753
+ CAST(entry.value ->> 'expected_identity_version' AS integer) AS expected_identity_version,
1754
+ entry.value ->> 'expected_revision_id' AS expected_revision_id,
1755
+ entry.value ->> 'expected_source_completeness' AS expected_source_completeness,
1756
+ entry.value ->> 'expected_last_attempted_at' AS expected_last_attempted_at,
1757
+ entry.value ->> 'expected_last_error_code' AS expected_last_error_code
1758
+ FROM jsonb_array_elements(${payload}::jsonb) AS entry(value)
1759
+ `;
1760
+ return sql`
1761
+ SELECT
1762
+ json_extract(entry.value, '$.source_key') AS source_key,
1763
+ json_extract(entry.value, '$.source_type') AS source_type,
1764
+ json_extract(entry.value, '$.collection_id') AS collection_id,
1765
+ json_extract(entry.value, '$.collection_slug') AS collection_slug,
1766
+ json_extract(entry.value, '$.content_id') AS content_id,
1767
+ json_extract(entry.value, '$.source_variant') AS source_variant,
1768
+ json_extract(entry.value, '$.locale') AS locale,
1769
+ json_extract(entry.value, '$.translation_group') AS translation_group,
1770
+ json_extract(entry.value, '$.content_slug') AS content_slug,
1771
+ json_extract(entry.value, '$.content_title') AS content_title,
1772
+ json_extract(entry.value, '$.content_status') AS content_status,
1773
+ json_extract(entry.value, '$.content_scheduled_at') AS content_scheduled_at,
1774
+ json_extract(entry.value, '$.content_deleted_at') AS content_deleted_at,
1775
+ json_extract(entry.value, '$.revision_id') AS revision_id,
1776
+ json_extract(entry.value, '$.current_generation') AS current_generation,
1777
+ CAST(json_extract(entry.value, '$.schema_version') AS integer) AS schema_version,
1778
+ json_extract(entry.value, '$.source_updated_at') AS source_updated_at,
1779
+ CAST(json_extract(entry.value, '$.source_version') AS integer) AS source_version,
1780
+ json_extract(entry.value, '$.source_fingerprint') AS source_fingerprint,
1781
+ CAST(json_extract(entry.value, '$.identity_version') AS integer) AS identity_version,
1782
+ json_extract(entry.value, '$.source_completeness') AS source_completeness,
1783
+ json_extract(entry.value, '$.last_attempted_at') AS last_attempted_at,
1784
+ json_extract(entry.value, '$.last_error_code') AS last_error_code,
1785
+ json_extract(entry.value, '$.indexed_at') AS indexed_at,
1786
+ json_extract(entry.value, '$.updated_at') AS updated_at,
1787
+ json_extract(entry.value, '$.lease_token') AS lease_token,
1788
+ json_extract(entry.value, '$.expected_generation') AS expected_generation,
1789
+ json_extract(entry.value, '$.expected_collection_id') AS expected_collection_id,
1790
+ json_extract(entry.value, '$.expected_updated_at') AS expected_updated_at,
1791
+ json_extract(entry.value, '$.expected_source_fingerprint') AS expected_source_fingerprint,
1792
+ json_extract(entry.value, '$.expected_source_updated_at') AS expected_source_updated_at,
1793
+ CAST(json_extract(entry.value, '$.expected_source_version') AS integer) AS expected_source_version,
1794
+ CAST(json_extract(entry.value, '$.expected_identity_version') AS integer) AS expected_identity_version,
1795
+ json_extract(entry.value, '$.expected_revision_id') AS expected_revision_id,
1796
+ json_extract(entry.value, '$.expected_source_completeness') AS expected_source_completeness,
1797
+ json_extract(entry.value, '$.expected_last_attempted_at') AS expected_last_attempted_at,
1798
+ json_extract(entry.value, '$.expected_last_error_code') AS expected_last_error_code
1799
+ FROM json_each(${payload}) AS entry
1800
+ `;
1801
+ }
1802
+ generationWriteBatchInput(payload) {
1803
+ if (isPostgres(this.db)) return sql`
1804
+ SELECT
1805
+ entry.value ->> 'source_key' AS source_key,
1806
+ entry.value ->> 'collection_id' AS collection_id,
1807
+ entry.value ->> 'collection_slug' AS collection_slug,
1808
+ entry.value ->> 'generation' AS generation,
1809
+ entry.value ->> 'lease_token' AS lease_token,
1810
+ entry.value ->> 'expires_at' AS expires_at,
1811
+ entry.value ->> 'created_at' AS created_at
1812
+ FROM jsonb_array_elements(${payload}::jsonb) AS entry(value)
1813
+ `;
1814
+ return sql`
1815
+ SELECT
1816
+ json_extract(entry.value, '$.source_key') AS source_key,
1817
+ json_extract(entry.value, '$.collection_id') AS collection_id,
1818
+ json_extract(entry.value, '$.collection_slug') AS collection_slug,
1819
+ json_extract(entry.value, '$.generation') AS generation,
1820
+ json_extract(entry.value, '$.lease_token') AS lease_token,
1821
+ json_extract(entry.value, '$.expires_at') AS expires_at,
1822
+ json_extract(entry.value, '$.created_at') AS created_at
1823
+ FROM json_each(${payload}) AS entry
1824
+ `;
1825
+ }
1826
+ batchRefsMatch(left, right) {
1827
+ const leftRef = sql.ref(left);
1828
+ const rightRef = sql.ref(right);
1829
+ return isPostgres(this.db) ? sql`${leftRef} IS NOT DISTINCT FROM ${rightRef}` : sql`${leftRef} IS ${rightRef}`;
1830
+ }
985
1831
  async lockCanonicalSourceCollection(db, source) {
986
1832
  if (source.collectionId === void 0 || source.collectionId === null) return true;
987
1833
  if (!source.collectionSlug) return false;
@@ -1507,10 +2353,6 @@ function rowToIndexStatus(row) {
1507
2353
  };
1508
2354
  }
1509
2355
 
1510
- //#endregion
1511
- //#region src/media/usage/types.ts
1512
- const CONTENT_SOURCE_SCHEMA_VERSION = 1;
1513
-
1514
2356
  //#endregion
1515
2357
  //#region src/media/usage/content-fields.ts
1516
2358
  async function buildContentMediaUsageFieldFingerprint(discovery) {
@@ -1627,13 +2469,7 @@ function extractMediaUsageOccurrences({ fields, data }) {
1627
2469
  for (const field of fields) {
1628
2470
  const value = data[field.slug];
1629
2471
  if (field.type === "image") {
1630
- addOccurrence(occurrences, seen, {
1631
- fieldSlug: field.slug,
1632
- fieldPath: field.slug,
1633
- referenceType: "image_field",
1634
- value,
1635
- fallbackKind: "image"
1636
- });
2472
+ addImageOccurrences(occurrences, seen, field.slug, field.slug, value);
1637
2473
  continue;
1638
2474
  }
1639
2475
  if (field.type === "file") {
@@ -1660,16 +2496,26 @@ function extractRepeaterOccurrences(occurrences, seen, fieldSlug, value, subFiel
1660
2496
  if (!isRecord$1(item)) continue;
1661
2497
  for (const subField of subFields) {
1662
2498
  if (subField.type !== "image") continue;
1663
- addOccurrence(occurrences, seen, {
1664
- fieldSlug,
1665
- fieldPath: `${fieldSlug}[${itemIndex}].${subField.slug}`,
1666
- referenceType: "image_field",
1667
- value: item[subField.slug],
1668
- fallbackKind: "image"
1669
- });
2499
+ addImageOccurrences(occurrences, seen, fieldSlug, `${fieldSlug}[${itemIndex}].${subField.slug}`, item[subField.slug]);
1670
2500
  }
1671
2501
  }
1672
2502
  }
2503
+ function addImageOccurrences(occurrences, seen, fieldSlug, fieldPath, value) {
2504
+ addOccurrence(occurrences, seen, {
2505
+ fieldSlug,
2506
+ fieldPath,
2507
+ referenceType: "image_field",
2508
+ value,
2509
+ fallbackKind: "image"
2510
+ });
2511
+ if (isRecord$1(value) && value.darkVariant != null) addOccurrence(occurrences, seen, {
2512
+ fieldSlug,
2513
+ fieldPath: `${fieldPath}.darkVariant`,
2514
+ referenceType: "image_field",
2515
+ value: value.darkVariant,
2516
+ fallbackKind: "image"
2517
+ });
2518
+ }
1673
2519
  function extractPortableTextOccurrences(occurrences, seen, fieldSlug, value) {
1674
2520
  if (!Array.isArray(value)) return;
1675
2521
  for (const [blockIndex, block] of value.entries()) {
@@ -1844,14 +2690,38 @@ const CONTENT_SYSTEM_COLUMNS = [
1844
2690
  "translation_group"
1845
2691
  ];
1846
2692
  async function loadContentMediaUsageSnapshots(db, collectionSlug, contentId, fieldDiscovery, options = {}) {
1847
- validateIdentifier(collectionSlug, "collection slug");
1848
- if (options.identityVersion !== void 0 && !options.collectionId) throw new Error("Canonical media usage snapshots require a collection identity");
1849
- const discovery = fieldDiscovery ?? await loadContentMediaUsageFields(db, collectionSlug);
1850
- const row = await loadContentRow(db, collectionSlug, contentId, [...discovery.extractionFields.map((field) => field.slug), ...discovery.displayFieldSlugs], options.collectionId);
1851
- if (!row) return {
2693
+ return (await loadContentMediaUsageSnapshotsBatch(db, collectionSlug, [contentId], fieldDiscovery, options)).get(contentId) ?? {
1852
2694
  success: false,
1853
2695
  error: "CONTENT_NOT_FOUND"
1854
2696
  };
2697
+ }
2698
+ async function loadContentMediaUsageSnapshotsBatch(db, collectionSlug, contentIds, fieldDiscovery, options = {}, control = {}) {
2699
+ validateIdentifier(collectionSlug, "collection slug");
2700
+ if (options.identityVersion !== void 0 && !options.collectionId) throw new Error("Canonical media usage snapshots require a collection identity");
2701
+ const discovery = fieldDiscovery ?? await loadContentMediaUsageFields(db, collectionSlug);
2702
+ const rows = await loadContentRows(db, collectionSlug, contentIds, [...discovery.extractionFields.map((field) => field.slug), ...discovery.displayFieldSlugs], options.collectionId);
2703
+ const revisions = await loadRevisionRows(db, Array.from(rows.values(), (row) => readNullableString(row.draft_revision_id)).filter((revisionId) => revisionId !== null));
2704
+ const results = /* @__PURE__ */ new Map();
2705
+ let occurrenceCount = 0;
2706
+ let projectionBytes = 0;
2707
+ for (const contentId of new Set(contentIds)) {
2708
+ if (control.shouldContinue && !control.shouldContinue()) break;
2709
+ const row = rows.get(contentId);
2710
+ const result = row ? await buildContentMediaUsageSnapshots(row, collectionSlug, discovery, options, revisions) : {
2711
+ success: false,
2712
+ error: "CONTENT_NOT_FOUND"
2713
+ };
2714
+ const snapshots = result.success ? result.snapshots : result.snapshots ?? [];
2715
+ const itemOccurrenceCount = snapshots.reduce((total, snapshot) => total + snapshot.occurrences.length, 0);
2716
+ const itemProjectionBytes = snapshots.reduce((total, snapshot) => total + snapshot.projectionByteLength, 0);
2717
+ if (results.size > 0 && (control.maxOccurrenceCount !== void 0 && occurrenceCount + itemOccurrenceCount > control.maxOccurrenceCount || control.maxProjectionBytes !== void 0 && projectionBytes + itemProjectionBytes > control.maxProjectionBytes)) break;
2718
+ results.set(contentId, result);
2719
+ occurrenceCount += itemOccurrenceCount;
2720
+ projectionBytes += itemProjectionBytes;
2721
+ }
2722
+ return results;
2723
+ }
2724
+ async function buildContentMediaUsageSnapshots(row, collectionSlug, discovery, options, revisions) {
1855
2725
  const collectionId = readString(row[CONTENT_COLLECTION_ID_RESULT]);
1856
2726
  if (!collectionId) throw new Error("Media usage snapshot query did not return a collection identity");
1857
2727
  const columnsData = projectData(row, discovery.extractionFields.map((field) => field.slug));
@@ -1894,7 +2764,7 @@ async function loadContentMediaUsageSnapshots(db, collectionSlug, contentId, fie
1894
2764
  sourceVariant: "draft_overlay",
1895
2765
  revisionId: draftRevisionId
1896
2766
  });
1897
- const revisionResult = await loadRevisionRow(db, draftRevisionId);
2767
+ const revisionResult = revisions.get(draftRevisionId);
1898
2768
  if (!revisionResult) return {
1899
2769
  success: false,
1900
2770
  error: "DRAFT_REVISION_NOT_FOUND",
@@ -1957,40 +2827,52 @@ async function loadContentMediaUsageSnapshots(db, collectionSlug, contentId, fie
1957
2827
  snapshots
1958
2828
  };
1959
2829
  }
1960
- async function loadContentRow(db, collectionSlug, contentId, fieldSlugs, expectedCollectionId) {
2830
+ async function loadContentRows(db, collectionSlug, contentIds, fieldSlugs, expectedCollectionId) {
1961
2831
  const tableName = getContentTableName(collectionSlug);
1962
2832
  const columnRefs = uniqueColumns([...CONTENT_SYSTEM_COLUMNS, ...fieldSlugs]).map((column) => sql.ref(`content.${column}`));
1963
- return (await sql`
2833
+ const rows = /* @__PURE__ */ new Map();
2834
+ const uniqueContentIds = [...new Set(contentIds)];
2835
+ if (uniqueContentIds.length === 0) return rows;
2836
+ const result = await sql`
2837
+ WITH requested AS (${jsonTextValues(db, uniqueContentIds)})
1964
2838
  SELECT
1965
2839
  ${sql.join(columnRefs, sql`, `)},
1966
2840
  collection.id AS __emdash_media_usage_collection_id
1967
2841
  FROM ${sql.ref(tableName)} AS content
2842
+ INNER JOIN requested ON requested.value = content.id
1968
2843
  INNER JOIN _emdash_collections AS collection
1969
2844
  ON collection.slug = ${collectionSlug}
1970
2845
  ${expectedCollectionId ? sql`AND collection.id = ${expectedCollectionId}` : sql``}
1971
- WHERE content.id = ${contentId}
1972
- LIMIT 1
1973
- `.execute(db)).rows[0] ?? null;
1974
- }
1975
- async function loadRevisionRow(db, revisionId) {
1976
- const row = await db.selectFrom("revisions").select([
1977
- "id",
1978
- "collection",
1979
- "entry_id",
1980
- "data"
1981
- ]).where("id", "=", revisionId).executeTakeFirst();
1982
- if (!row) return null;
1983
- const data = parseRevisionData(row.data);
1984
- if (!data) return { success: false };
1985
- return {
1986
- success: true,
1987
- revision: {
1988
- id: row.id,
1989
- collection: row.collection,
1990
- entryId: row.entry_id,
1991
- data
1992
- }
1993
- };
2846
+ `.execute(db);
2847
+ for (const row of result.rows) {
2848
+ const contentId = readString(row.id);
2849
+ if (contentId) rows.set(contentId, row);
2850
+ }
2851
+ return rows;
2852
+ }
2853
+ async function loadRevisionRows(db, revisionIds) {
2854
+ const revisions = /* @__PURE__ */ new Map();
2855
+ const uniqueRevisionIds = [...new Set(revisionIds)];
2856
+ if (uniqueRevisionIds.length === 0) return revisions;
2857
+ const rows = await sql`
2858
+ WITH requested AS (${jsonTextValues(db, uniqueRevisionIds)})
2859
+ SELECT revision.id, revision.collection, revision.entry_id, revision.data
2860
+ FROM revisions AS revision
2861
+ INNER JOIN requested ON requested.value = revision.id
2862
+ `.execute(db);
2863
+ for (const row of rows.rows) {
2864
+ const data = parseRevisionData(row.data);
2865
+ revisions.set(row.id, data ? {
2866
+ success: true,
2867
+ revision: {
2868
+ id: row.id,
2869
+ collection: row.collection,
2870
+ entryId: row.entry_id,
2871
+ data
2872
+ }
2873
+ } : { success: false });
2874
+ }
2875
+ return revisions;
1994
2876
  }
1995
2877
  function buildContentSource(input) {
1996
2878
  const { collectionId, collectionSlug, identityVersion, row, displayData, sourceVariant, revisionId } = input;
@@ -2102,8 +2984,11 @@ const CONTENT_USAGE_LOCKS_KEY = Symbol.for("emdash.mediaUsage.contentLocks");
2102
2984
  const CONTENT_USAGE_COLLECTION_LOCKS_KEY = Symbol.for("emdash.mediaUsage.collectionLocks");
2103
2985
  const CONTENT_USAGE_REFRESH_MAX_ATTEMPTS = 2;
2104
2986
  const MEDIA_USAGE_PROJECTION_ADMISSION_LIMITS = Object.freeze({
2105
- maxOccurrenceMutationUnitsPerClaim: 12,
2106
- maxProjectionMutationBytesPerClaim: 512 * 1024
2987
+ maxOccurrenceMutationUnitsPerClaim: 500,
2988
+ maxProjectionMutationBytesPerVariant: 2e6,
2989
+ maxProjectionMutationBytesPerClaim: 4e6,
2990
+ maxOccurrenceMutationUnitsPerBatch: 5e4,
2991
+ maxProjectionMutationBytesPerBatch: 16e6
2107
2992
  });
2108
2993
  const ZERO_RESULT = {
2109
2994
  success: true,
@@ -2111,10 +2996,10 @@ const ZERO_RESULT = {
2111
2996
  deletedSourceCount: 0,
2112
2997
  failedSourceCount: 0
2113
2998
  };
2114
- function createContentMediaUsageAdmissionBudget() {
2999
+ function createContentMediaUsageAdmissionBudget(limits = {}) {
2115
3000
  return {
2116
- remainingOccurrenceMutationUnits: MEDIA_USAGE_PROJECTION_ADMISSION_LIMITS.maxOccurrenceMutationUnitsPerClaim,
2117
- remainingProjectionMutationBytes: MEDIA_USAGE_PROJECTION_ADMISSION_LIMITS.maxProjectionMutationBytesPerClaim,
3001
+ remainingOccurrenceMutationUnits: limits.maxOccurrenceMutationUnits ?? MEDIA_USAGE_PROJECTION_ADMISSION_LIMITS.maxOccurrenceMutationUnitsPerClaim,
3002
+ remainingProjectionMutationBytes: limits.maxProjectionMutationBytes ?? MEDIA_USAGE_PROJECTION_ADMISSION_LIMITS.maxProjectionMutationBytesPerClaim,
2118
3003
  hasReservedMutation: false
2119
3004
  };
2120
3005
  }
@@ -2123,20 +3008,23 @@ async function planContentMediaUsageProjectionAdmission(repo, snapshots, observe
2123
3008
  const absentSources = canonicalSourceKeys.filter((sourceKey) => !snapshotSourceKeys.has(sourceKey)).map((sourceKey) => observedSources.get(sourceKey)).filter((source) => source !== void 0);
2124
3009
  let deletionOccurrenceUnits = 0;
2125
3010
  let deletionBytes = 0;
3011
+ let largestDeletionBytes = 0;
2126
3012
  for (const source of absentSources) {
2127
3013
  const measurement = await repo.measureSourceGenerationDeletion(source.sourceKey, source.currentGeneration, MEDIA_USAGE_PROJECTION_ADMISSION_LIMITS.maxOccurrenceMutationUnitsPerClaim);
2128
3014
  if (measurement.exceedsOccurrenceLimit) return budget.hasReservedMutation ? { outcome: "claim_budget_deferred" } : { outcome: "intrinsic_resource_limit" };
2129
3015
  deletionOccurrenceUnits += measurement.occurrenceCount;
2130
- deletionBytes += storedMediaUsageSourceByteLength(source) + measurement.occurrenceBytes * 2;
3016
+ const sourceDeletionBytes = storedMediaUsageSourceByteLength(source) + measurement.occurrenceBytes * 2;
3017
+ deletionBytes += sourceDeletionBytes;
3018
+ largestDeletionBytes = Math.max(largestDeletionBytes, sourceDeletionBytes);
2131
3019
  }
2132
3020
  const noOpSourceKeys = /* @__PURE__ */ new Set();
2133
- let cost = projectionAdmissionCost(snapshots, noOpSourceKeys, deletionOccurrenceUnits, deletionBytes);
3021
+ let cost = projectionAdmissionCost(snapshots, noOpSourceKeys, deletionOccurrenceUnits, deletionBytes, largestDeletionBytes);
2134
3022
  if (exceedsProjectionAdmissionLimits(cost)) {
2135
3023
  for (const snapshot of snapshots) {
2136
3024
  const expectedSource = observedSources.get(snapshot.source.sourceKey);
2137
3025
  if (expectedSource && await repo.projectionMatchesExpectedSource(snapshot.source, expectedSource)) noOpSourceKeys.add(snapshot.source.sourceKey);
2138
3026
  }
2139
- cost = projectionAdmissionCost(snapshots, noOpSourceKeys, deletionOccurrenceUnits, deletionBytes);
3027
+ cost = projectionAdmissionCost(snapshots, noOpSourceKeys, deletionOccurrenceUnits, deletionBytes, largestDeletionBytes);
2140
3028
  }
2141
3029
  if (exceedsProjectionAdmissionLimits(cost)) return budget.hasReservedMutation ? { outcome: "claim_budget_deferred" } : { outcome: "intrinsic_resource_limit" };
2142
3030
  if (cost.occurrenceMutationUnits > budget.remainingOccurrenceMutationUnits || cost.projectionMutationBytes > budget.remainingProjectionMutationBytes) return { outcome: "claim_budget_deferred" };
@@ -2150,19 +3038,21 @@ async function planContentMediaUsageProjectionAdmission(repo, snapshots, observe
2150
3038
  ...cost
2151
3039
  };
2152
3040
  }
2153
- function projectionAdmissionCost(snapshots, noOpSourceKeys, deletionOccurrenceUnits, deletionBytes) {
3041
+ function projectionAdmissionCost(snapshots, noOpSourceKeys, deletionOccurrenceUnits, deletionBytes, largestDeletionBytes) {
2154
3042
  return snapshots.reduce((cost, snapshot) => {
2155
3043
  if (noOpSourceKeys.has(snapshot.source.sourceKey)) return cost;
2156
3044
  cost.occurrenceMutationUnits += snapshot.occurrences.length;
2157
3045
  cost.projectionMutationBytes += snapshot.projectionByteLength;
3046
+ cost.largestProjectionMutationBytes = Math.max(cost.largestProjectionMutationBytes, snapshot.projectionByteLength);
2158
3047
  return cost;
2159
3048
  }, {
2160
3049
  occurrenceMutationUnits: deletionOccurrenceUnits,
2161
- projectionMutationBytes: deletionBytes
3050
+ projectionMutationBytes: deletionBytes,
3051
+ largestProjectionMutationBytes: largestDeletionBytes
2162
3052
  });
2163
3053
  }
2164
3054
  function exceedsProjectionAdmissionLimits(cost) {
2165
- return cost.occurrenceMutationUnits > MEDIA_USAGE_PROJECTION_ADMISSION_LIMITS.maxOccurrenceMutationUnitsPerClaim || cost.projectionMutationBytes > MEDIA_USAGE_PROJECTION_ADMISSION_LIMITS.maxProjectionMutationBytesPerClaim;
3055
+ return cost.occurrenceMutationUnits > MEDIA_USAGE_PROJECTION_ADMISSION_LIMITS.maxOccurrenceMutationUnitsPerClaim || cost.largestProjectionMutationBytes > MEDIA_USAGE_PROJECTION_ADMISSION_LIMITS.maxProjectionMutationBytesPerVariant || cost.projectionMutationBytes > MEDIA_USAGE_PROJECTION_ADMISSION_LIMITS.maxProjectionMutationBytesPerClaim;
2166
3056
  }
2167
3057
  function storedMediaUsageSourceByteLength(source) {
2168
3058
  return new TextEncoder().encode(JSON.stringify(source)).byteLength;
@@ -2171,13 +3061,133 @@ async function refreshContentMediaUsage(db, collectionSlug, contentId) {
2171
3061
  validateIdentifier(collectionSlug, "collection slug");
2172
3062
  return withContentUsageCollectionLock(collectionSlug, () => withContentUsageLock(collectionSlug, contentId, () => refreshContentMediaUsageUnlocked(db, collectionSlug, contentId, {})));
2173
3063
  }
2174
- async function refreshContentMediaUsageForWork(db, collectionId, collectionSlug, contentId) {
2175
- validateIdentifier(collectionSlug, "collection slug");
2176
- if (!collectionId) throw new Error("Durable media usage work requires a collection identity");
2177
- return withContentUsageCollectionLock(collectionSlug, () => withContentUsageLock(collectionSlug, contentId, () => refreshContentMediaUsageUnlocked(db, collectionSlug, contentId, {
2178
- collectionId,
2179
- durableWork: true
2180
- })));
3064
+ async function refreshContentMediaUsageForWorkBatch(db, items, options = {}) {
3065
+ const results = /* @__PURE__ */ new Map();
3066
+ const batchBudget = createContentMediaUsageAdmissionBudget({
3067
+ maxOccurrenceMutationUnits: MEDIA_USAGE_PROJECTION_ADMISSION_LIMITS.maxOccurrenceMutationUnitsPerBatch,
3068
+ maxProjectionMutationBytes: MEDIA_USAGE_PROJECTION_ADMISSION_LIMITS.maxProjectionMutationBytesPerBatch
3069
+ });
3070
+ const collections = /* @__PURE__ */ new Map();
3071
+ for (const item of items) {
3072
+ const key = `${item.collectionId}\u0000${item.collectionSlug}`;
3073
+ const collectionItems = collections.get(key) ?? [];
3074
+ collectionItems.push(item);
3075
+ collections.set(key, collectionItems);
3076
+ }
3077
+ for (const collectionItems of collections.values()) {
3078
+ if (options.shouldContinue && !options.shouldContinue()) break;
3079
+ const first = collectionItems[0];
3080
+ if (!first) continue;
3081
+ validateIdentifier(first.collectionSlug, "collection slug");
3082
+ if (!first.collectionId) throw new Error("Durable media usage work requires a collection identity");
3083
+ await withContentUsageCollectionLock(first.collectionSlug, async () => {
3084
+ const fieldDiscovery = await loadContentMediaUsageFields(db, first.collectionSlug, first.collectionId);
3085
+ const sourceKeys = collectionItems.flatMap((item) => contentSourceKeys(item.collectionSlug, item.contentId, item.collectionId));
3086
+ const repo = new MediaUsageRepository(db);
3087
+ const observedSources = await repo.findSources(sourceKeys);
3088
+ const snapshots = await loadContentMediaUsageSnapshotsBatch(db, first.collectionSlug, collectionItems.map((item) => item.contentId), fieldDiscovery, {
3089
+ collectionId: first.collectionId,
3090
+ identityVersion: 1
3091
+ }, {
3092
+ shouldContinue: options.shouldContinue,
3093
+ maxOccurrenceCount: MEDIA_USAGE_PROJECTION_ADMISSION_LIMITS.maxOccurrenceMutationUnitsPerBatch,
3094
+ maxProjectionBytes: MEDIA_USAGE_PROJECTION_ADMISSION_LIMITS.maxProjectionMutationBytesPerBatch
3095
+ });
3096
+ const newSourceProjections = [];
3097
+ const newSourceKeys = /* @__PURE__ */ new Map();
3098
+ const existingSourceProjections = [];
3099
+ const unchangedSourceProjections = [];
3100
+ const existingSourceKeys = /* @__PURE__ */ new Map();
3101
+ for (const item of collectionItems) {
3102
+ if (options.shouldContinue && !options.shouldContinue()) break;
3103
+ const snapshotsResult = snapshots.get(item.contentId);
3104
+ const itemSourceKeys = contentSourceKeys(item.collectionSlug, item.contentId, item.collectionId);
3105
+ if (!snapshotsResult?.success) continue;
3106
+ const snapshotsByKey = new Map(snapshotsResult.snapshots.map((snapshot) => [snapshot.source.sourceKey, snapshot]));
3107
+ const existing = itemSourceKeys.map((sourceKey) => observedSources.get(sourceKey)).filter((source) => source !== void 0);
3108
+ const allNew = existing.length === 0;
3109
+ const allExisting = existing.length === snapshotsResult.snapshots.length && existing.every((source) => snapshotsByKey.has(source.sourceKey));
3110
+ if (!allNew && !allExisting) continue;
3111
+ const admission = await planContentMediaUsageProjectionAdmission(repo, snapshotsResult.snapshots, observedSources, itemSourceKeys, batchBudget);
3112
+ if (admission.outcome === "claim_budget_deferred") break;
3113
+ if (admission.outcome !== "admitted") {
3114
+ results.set(contentRefreshKey(item.collectionId, item.contentId), admissionFailureResult(admission.outcome));
3115
+ continue;
3116
+ }
3117
+ const key = contentRefreshKey(item.collectionId, item.contentId);
3118
+ if (allNew) {
3119
+ newSourceProjections.push(...snapshotsResult.snapshots.map((snapshot) => ({
3120
+ source: snapshot.source,
3121
+ occurrences: snapshot.occurrences
3122
+ })));
3123
+ newSourceKeys.set(key, snapshotsResult.snapshots.map((snapshot) => snapshot.source.sourceKey));
3124
+ continue;
3125
+ }
3126
+ const changed = [];
3127
+ const unchanged = [];
3128
+ for (const snapshot of snapshotsResult.snapshots) {
3129
+ const expectedSource = observedSources.get(snapshot.source.sourceKey);
3130
+ if (!expectedSource) continue;
3131
+ if (expectedSource.sourceFingerprint === snapshot.source.sourceFingerprint && expectedSource.sourceCompleteness === (snapshot.source.sourceCompleteness ?? "complete") && expectedSource.lastErrorCode === null) {
3132
+ unchanged.push(snapshot.source.sourceKey);
3133
+ unchangedSourceProjections.push({
3134
+ source: snapshot.source,
3135
+ occurrences: snapshot.occurrences,
3136
+ expectedSource
3137
+ });
3138
+ continue;
3139
+ }
3140
+ changed.push(snapshot.source.sourceKey);
3141
+ existingSourceProjections.push({
3142
+ source: snapshot.source,
3143
+ occurrences: snapshot.occurrences,
3144
+ expectedSource
3145
+ });
3146
+ }
3147
+ existingSourceKeys.set(key, {
3148
+ allCount: snapshotsResult.snapshots.length,
3149
+ changed,
3150
+ unchanged
3151
+ });
3152
+ }
3153
+ const insertedSourceKeys = await repo.replaceNewSourcesBatch(newSourceProjections);
3154
+ const replacedSourceKeys = await repo.replaceExistingSourcesBatch(existingSourceProjections);
3155
+ const matchedSourceKeys = await repo.matchingExistingSourcesBatch(unchangedSourceProjections);
3156
+ for (const [key, expectedSourceKeys] of newSourceKeys) results.set(key, expectedSourceKeys.every((sourceKey) => insertedSourceKeys.has(sourceKey)) ? {
3157
+ success: true,
3158
+ refreshedSourceCount: expectedSourceKeys.length,
3159
+ deletedSourceCount: 0,
3160
+ failedSourceCount: 0
3161
+ } : generationConflictResult({
3162
+ refreshedSourceCount: 0,
3163
+ deletedSourceCount: 0
3164
+ }));
3165
+ for (const [key, expected] of existingSourceKeys) results.set(key, expected.changed.every((sourceKey) => replacedSourceKeys.has(sourceKey)) && expected.unchanged.every((sourceKey) => matchedSourceKeys.has(sourceKey)) ? {
3166
+ success: true,
3167
+ refreshedSourceCount: expected.allCount,
3168
+ deletedSourceCount: 0,
3169
+ failedSourceCount: 0
3170
+ } : generationConflictResult({
3171
+ refreshedSourceCount: 0,
3172
+ deletedSourceCount: 0
3173
+ }));
3174
+ for (const item of collectionItems) {
3175
+ if (options.shouldContinue && !options.shouldContinue()) break;
3176
+ const key = contentRefreshKey(item.collectionId, item.contentId);
3177
+ if (!snapshots.has(item.contentId)) continue;
3178
+ if (results.has(key)) continue;
3179
+ const result = await withContentUsageLock(item.collectionSlug, item.contentId, () => refreshContentMediaUsageUnlocked(db, item.collectionSlug, item.contentId, {
3180
+ collectionId: item.collectionId,
3181
+ durableWork: true,
3182
+ fieldDiscovery,
3183
+ observedSources,
3184
+ snapshotsResult: snapshots.get(item.contentId)
3185
+ }));
3186
+ results.set(key, result);
3187
+ }
3188
+ });
3189
+ }
3190
+ return results;
2181
3191
  }
2182
3192
  async function refreshContentMediaUsageUnlocked(db, collectionSlug, contentId, options) {
2183
3193
  try {
@@ -2212,17 +3222,13 @@ async function refreshContentMediaUsageUnlocked(db, collectionSlug, contentId, o
2212
3222
  async function refreshContentMediaUsageAttempt(db, collectionSlug, contentId, options) {
2213
3223
  const repo = new MediaUsageRepository(db);
2214
3224
  const canonicalSourceKeys = contentSourceKeys(collectionSlug, contentId, options.collectionId);
2215
- const observedSources = await repo.findSources(canonicalSourceKeys);
2216
- const snapshotsResult = await loadContentMediaUsageSnapshots(db, collectionSlug, contentId, void 0, options.collectionId ? {
3225
+ const observedSources = options.observedSources ?? await repo.findSources(canonicalSourceKeys);
3226
+ const snapshotsResult = options.snapshotsResult ?? await loadContentMediaUsageSnapshots(db, collectionSlug, contentId, options.fieldDiscovery, options.collectionId ? {
2217
3227
  collectionId: options.collectionId,
2218
3228
  identityVersion: 1
2219
3229
  } : void 0);
2220
3230
  if (!snapshotsResult.success) {
2221
3231
  if (snapshotsResult.error === "CONTENT_NOT_FOUND" && options.collectionId) {
2222
- if (!await contentCollectionExists(db, collectionSlug, options.collectionId)) return generationConflictResult({
2223
- refreshedSourceCount: 0,
2224
- deletedSourceCount: 0
2225
- });
2226
3232
  if (!options.admissionBudget) throw new Error("Durable media usage work requires an admission budget");
2227
3233
  const admission = await planContentMediaUsageProjectionAdmission(repo, [], observedSources, canonicalSourceKeys, options.admissionBudget);
2228
3234
  if (admission.outcome !== "admitted") return admissionFailureResult(admission.outcome);
@@ -2237,11 +3243,7 @@ async function refreshContentMediaUsageAttempt(db, collectionSlug, contentId, op
2237
3243
  }
2238
3244
  return options.durableWork ? snapshotFailureResult(snapshotsResult) : markSnapshotFailure(db, collectionSlug, snapshotsResult);
2239
3245
  }
2240
- if (!await contentCollectionExists(db, collectionSlug, options.collectionId)) {
2241
- if (options.collectionId) return generationConflictResult({
2242
- refreshedSourceCount: 0,
2243
- deletedSourceCount: 0
2244
- });
3246
+ if (!options.collectionId && !await contentCollectionExists(db, collectionSlug)) {
2245
3247
  const deletedSourceCount = await repo.deleteContentSources(collectionSlug, contentId);
2246
3248
  return {
2247
3249
  ...ZERO_RESULT,
@@ -2267,11 +3269,7 @@ async function refreshContentMediaUsageAttempt(db, collectionSlug, contentId, op
2267
3269
  });
2268
3270
  refreshedSourceCount++;
2269
3271
  }
2270
- if (!await contentCollectionExists(db, collectionSlug, options.collectionId)) {
2271
- if (options.collectionId) return generationConflictResult({
2272
- refreshedSourceCount,
2273
- deletedSourceCount: 0
2274
- });
3272
+ if (!options.collectionId && !await contentCollectionExists(db, collectionSlug)) {
2275
3273
  const deletedSourceCount = await repo.deleteContentSources(collectionSlug, contentId);
2276
3274
  return {
2277
3275
  ...ZERO_RESULT,
@@ -2299,6 +3297,9 @@ async function refreshContentMediaUsageAttempt(db, collectionSlug, contentId, op
2299
3297
  failedSourceCount: 0
2300
3298
  };
2301
3299
  }
3300
+ function contentRefreshKey(collectionId, contentId) {
3301
+ return `${collectionId}\u0000${contentId}`;
3302
+ }
2302
3303
  function contentSourceKeys(collectionSlug, contentId, collectionId) {
2303
3304
  return MEDIA_USAGE_CONTENT_SOURCE_VARIANTS.map((sourceVariant) => buildContentMediaUsageSourceKey({
2304
3305
  collectionId,
@@ -2556,5 +3557,5 @@ function getContentUsageCollectionLocks() {
2556
3557
  }
2557
3558
 
2558
3559
  //#endregion
2559
- export { loadContentMediaUsageFields as _, findNonTranslatableSiblingContentIds as a, markContentMediaUsageCollectionStaleSafely as c, withContentUsageCollectionLock as d, loadContentMediaUsageSnapshots as f, buildContentMediaUsageFieldFingerprint as g, MediaUsageFieldDiscoveryError as h, deleteContentMediaUsageCollection as i, refreshContentMediaUsageAfterWrite as l, buildContentMediaUsageSourceKey as m, CONTENT_MEDIA_USAGE_COLLECTION_SCOPE as n, invalidateContentMediaUsageSchemaChange as o, MEDIA_USAGE_CONTENT_SOURCE_VARIANTS as p, deleteContentMediaUsage as r, markContentMediaUsageCollectionStale as s, CONTENT_MEDIA_USAGE_ADAPTER_ID as t, refreshContentMediaUsageForWork as u, CONTENT_SOURCE_SCHEMA_VERSION as v, MediaUsageRepository as y };
2560
- //# sourceMappingURL=content-refresh-DNERP4-f.mjs.map
3560
+ export { buildContentMediaUsageFieldFingerprint as _, deleteContentMediaUsageCollection as a, jsonTextValues as b, markContentMediaUsageCollectionStale as c, refreshContentMediaUsageForWorkBatch as d, withContentUsageCollectionLock as f, MediaUsageFieldDiscoveryError as g, buildContentMediaUsageSourceKey as h, deleteContentMediaUsage as i, markContentMediaUsageCollectionStaleSafely as l, MEDIA_USAGE_CONTENT_SOURCE_VARIANTS as m, CONTENT_MEDIA_USAGE_COLLECTION_SCOPE as n, findNonTranslatableSiblingContentIds as o, loadContentMediaUsageSnapshots as p, contentRefreshKey as r, invalidateContentMediaUsageSchemaChange as s, CONTENT_MEDIA_USAGE_ADAPTER_ID as t, refreshContentMediaUsageAfterWrite as u, loadContentMediaUsageFields as v, CONTENT_SOURCE_SCHEMA_VERSION as x, MediaUsageRepository as y };
3561
+ //# sourceMappingURL=content-refresh-DLOfIhYc.mjs.map