emdash 0.27.0 → 0.28.1

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 (537) hide show
  1. package/dist/{adapters-u037EnTR.d.mts → adapters-hUy8vOB-.d.mts} +1 -1
  2. package/dist/{adapters-u037EnTR.d.mts.map → adapters-hUy8vOB-.d.mts.map} +1 -1
  3. package/dist/{allowed-origins-D5FxMUo8.mjs → allowed-origins-CRsJ6BPM.mjs} +2 -2
  4. package/dist/{allowed-origins-D5FxMUo8.mjs.map → allowed-origins-CRsJ6BPM.mjs.map} +1 -1
  5. package/dist/api/route-utils.d.mts +3 -3
  6. package/dist/api/route-utils.mjs +17 -16
  7. package/dist/api/route-utils.mjs.map +1 -1
  8. package/dist/api/schemas/index.d.mts +1 -1
  9. package/dist/api/schemas/index.mjs +3 -3
  10. package/dist/{api-80kycR9o.mjs → api-DxFSorgk.mjs} +33 -23
  11. package/dist/api-DxFSorgk.mjs.map +1 -0
  12. package/dist/{api-tokens-D6ppjIVi.mjs → api-tokens-DvqeZmVq.mjs} +2 -2
  13. package/dist/{api-tokens-D6ppjIVi.mjs.map → api-tokens-DvqeZmVq.mjs.map} +1 -1
  14. package/dist/{apply-DSypk6Iu.mjs → apply-CDJqIjPU.mjs} +111 -74
  15. package/dist/apply-CDJqIjPU.mjs.map +1 -0
  16. package/dist/astro/index.d.mts +12 -12
  17. package/dist/astro/index.mjs +3 -3
  18. package/dist/astro/index.mjs.map +1 -1
  19. package/dist/astro/middleware/auth.d.mts +10 -10
  20. package/dist/astro/middleware/auth.d.mts.map +1 -1
  21. package/dist/astro/middleware/auth.mjs +50 -11
  22. package/dist/astro/middleware/auth.mjs.map +1 -1
  23. package/dist/astro/middleware/redirect.mjs +5 -5
  24. package/dist/astro/middleware/request-context.mjs +2 -2
  25. package/dist/astro/middleware/setup.mjs +1 -1
  26. package/dist/astro/middleware.d.mts +2 -2
  27. package/dist/astro/middleware.mjs +124 -71
  28. package/dist/astro/middleware.mjs.map +1 -1
  29. package/dist/astro/routes/api/admin/allowed-domains/_domain_.mjs +6 -6
  30. package/dist/astro/routes/api/admin/allowed-domains/index.mjs +6 -6
  31. package/dist/astro/routes/api/admin/api-tokens/_id_.mjs +4 -4
  32. package/dist/astro/routes/api/admin/api-tokens/index.mjs +5 -5
  33. package/dist/astro/routes/api/admin/byline-fields/_slug_/usage.mjs +4 -4
  34. package/dist/astro/routes/api/admin/byline-fields/_slug_.mjs +8 -8
  35. package/dist/astro/routes/api/admin/byline-fields/index.mjs +8 -8
  36. package/dist/astro/routes/api/admin/byline-fields/reorder.mjs +8 -8
  37. package/dist/astro/routes/api/admin/bylines/_id_/index.mjs +14 -14
  38. package/dist/astro/routes/api/admin/bylines/_id_/translations.mjs +14 -14
  39. package/dist/astro/routes/api/admin/bylines/index.mjs +14 -14
  40. package/dist/astro/routes/api/admin/comments/_id_/status.mjs +12 -12
  41. package/dist/astro/routes/api/admin/comments/_id_.mjs +6 -6
  42. package/dist/astro/routes/api/admin/comments/bulk.mjs +10 -10
  43. package/dist/astro/routes/api/admin/comments/counts.mjs +6 -6
  44. package/dist/astro/routes/api/admin/comments/index.mjs +10 -10
  45. package/dist/astro/routes/api/admin/hooks/exclusive/_hookName_.mjs +4 -4
  46. package/dist/astro/routes/api/admin/hooks/exclusive/index.mjs +3 -3
  47. package/dist/astro/routes/api/admin/oauth-clients/_id_.mjs +4 -4
  48. package/dist/astro/routes/api/admin/oauth-clients/index.mjs +4 -4
  49. package/dist/astro/routes/api/admin/plugins/_id_/disable.mjs +37 -36
  50. package/dist/astro/routes/api/admin/plugins/_id_/disable.mjs.map +1 -1
  51. package/dist/astro/routes/api/admin/plugins/_id_/enable.mjs +37 -36
  52. package/dist/astro/routes/api/admin/plugins/_id_/enable.mjs.map +1 -1
  53. package/dist/astro/routes/api/admin/plugins/_id_/index.mjs +36 -35
  54. package/dist/astro/routes/api/admin/plugins/_id_/index.mjs.map +1 -1
  55. package/dist/astro/routes/api/admin/plugins/_id_/uninstall.mjs +36 -35
  56. package/dist/astro/routes/api/admin/plugins/_id_/uninstall.mjs.map +1 -1
  57. package/dist/astro/routes/api/admin/plugins/_id_/update.mjs +36 -35
  58. package/dist/astro/routes/api/admin/plugins/_id_/update.mjs.map +1 -1
  59. package/dist/astro/routes/api/admin/plugins/index.mjs +36 -35
  60. package/dist/astro/routes/api/admin/plugins/index.mjs.map +1 -1
  61. package/dist/astro/routes/api/admin/plugins/marketplace/_id_/icon.mjs +3 -3
  62. package/dist/astro/routes/api/admin/plugins/marketplace/_id_/index.mjs +36 -35
  63. package/dist/astro/routes/api/admin/plugins/marketplace/_id_/index.mjs.map +1 -1
  64. package/dist/astro/routes/api/admin/plugins/marketplace/_id_/install.mjs +36 -35
  65. package/dist/astro/routes/api/admin/plugins/marketplace/_id_/install.mjs.map +1 -1
  66. package/dist/astro/routes/api/admin/plugins/marketplace/index.mjs +36 -35
  67. package/dist/astro/routes/api/admin/plugins/marketplace/index.mjs.map +1 -1
  68. package/dist/astro/routes/api/admin/plugins/registry/_id_/uninstall.mjs +36 -35
  69. package/dist/astro/routes/api/admin/plugins/registry/_id_/uninstall.mjs.map +1 -1
  70. package/dist/astro/routes/api/admin/plugins/registry/_id_/update.mjs +37 -36
  71. package/dist/astro/routes/api/admin/plugins/registry/_id_/update.mjs.map +1 -1
  72. package/dist/astro/routes/api/admin/plugins/registry/artifact.mjs +36 -35
  73. package/dist/astro/routes/api/admin/plugins/registry/artifact.mjs.map +1 -1
  74. package/dist/astro/routes/api/admin/plugins/registry/install.mjs +37 -36
  75. package/dist/astro/routes/api/admin/plugins/registry/install.mjs.map +1 -1
  76. package/dist/astro/routes/api/admin/plugins/updates.mjs +36 -35
  77. package/dist/astro/routes/api/admin/plugins/updates.mjs.map +1 -1
  78. package/dist/astro/routes/api/admin/themes/marketplace/_id_/index.mjs +36 -35
  79. package/dist/astro/routes/api/admin/themes/marketplace/_id_/index.mjs.map +1 -1
  80. package/dist/astro/routes/api/admin/themes/marketplace/_id_/thumbnail.mjs +3 -3
  81. package/dist/astro/routes/api/admin/themes/marketplace/index.mjs +36 -35
  82. package/dist/astro/routes/api/admin/themes/marketplace/index.mjs.map +1 -1
  83. package/dist/astro/routes/api/admin/users/_id_/disable.mjs +2 -2
  84. package/dist/astro/routes/api/admin/users/_id_/enable.mjs +2 -2
  85. package/dist/astro/routes/api/admin/users/_id_/index.mjs +6 -6
  86. package/dist/astro/routes/api/admin/users/_id_/send-recovery.mjs +3 -3
  87. package/dist/astro/routes/api/admin/users/index.mjs +6 -6
  88. package/dist/astro/routes/api/auth/dev-bypass.mjs +5 -5
  89. package/dist/astro/routes/api/auth/invite/accept.mjs +2 -2
  90. package/dist/astro/routes/api/auth/invite/complete.mjs +10 -10
  91. package/dist/astro/routes/api/auth/invite/index.mjs +7 -7
  92. package/dist/astro/routes/api/auth/invite/register-options.mjs +9 -9
  93. package/dist/astro/routes/api/auth/logout.mjs +3 -3
  94. package/dist/astro/routes/api/auth/magic-link/send.mjs +9 -9
  95. package/dist/astro/routes/api/auth/magic-link/verify.mjs +3 -3
  96. package/dist/astro/routes/api/auth/me.mjs +7 -7
  97. package/dist/astro/routes/api/auth/mode.mjs +1 -1
  98. package/dist/astro/routes/api/auth/oauth/_provider_/callback.mjs +3 -3
  99. package/dist/astro/routes/api/auth/oauth/_provider_.mjs +2 -2
  100. package/dist/astro/routes/api/auth/passkey/_id_.mjs +6 -6
  101. package/dist/astro/routes/api/auth/passkey/index.mjs +2 -2
  102. package/dist/astro/routes/api/auth/passkey/options.mjs +11 -11
  103. package/dist/astro/routes/api/auth/passkey/register/options.mjs +9 -9
  104. package/dist/astro/routes/api/auth/passkey/register/verify.mjs +10 -10
  105. package/dist/astro/routes/api/auth/passkey/verify.mjs +10 -10
  106. package/dist/astro/routes/api/auth/signup/complete.mjs +10 -10
  107. package/dist/astro/routes/api/auth/signup/request.mjs +9 -9
  108. package/dist/astro/routes/api/auth/signup/verify.mjs +2 -2
  109. package/dist/astro/routes/api/comments/_collection_/_contentId_/index.mjs +13 -13
  110. package/dist/astro/routes/api/comments/_collection_/_contentId_/reactions.mjs +12 -12
  111. package/dist/astro/routes/api/content/_collection_/_id_/compare.mjs +3 -3
  112. package/dist/astro/routes/api/content/_collection_/_id_/discard-draft.mjs +3 -3
  113. package/dist/astro/routes/api/content/_collection_/_id_/duplicate.mjs +3 -3
  114. package/dist/astro/routes/api/content/_collection_/_id_/permanent.mjs +3 -3
  115. package/dist/astro/routes/api/content/_collection_/_id_/preview-url.mjs +10 -10
  116. package/dist/astro/routes/api/content/_collection_/_id_/publish.mjs +7 -7
  117. package/dist/astro/routes/api/content/_collection_/_id_/restore.mjs +3 -3
  118. package/dist/astro/routes/api/content/_collection_/_id_/revisions.mjs +3 -3
  119. package/dist/astro/routes/api/content/_collection_/_id_/schedule.mjs +7 -7
  120. package/dist/astro/routes/api/content/_collection_/_id_/terms/_taxonomy_.mjs +13 -13
  121. package/dist/astro/routes/api/content/_collection_/_id_/translations.mjs +3 -3
  122. package/dist/astro/routes/api/content/_collection_/_id_/unpublish.mjs +3 -3
  123. package/dist/astro/routes/api/content/_collection_/_id_.mjs +7 -7
  124. package/dist/astro/routes/api/content/_collection_/authors.mjs +3 -3
  125. package/dist/astro/routes/api/content/_collection_/index.mjs +7 -7
  126. package/dist/astro/routes/api/content/_collection_/trash.mjs +7 -7
  127. package/dist/astro/routes/api/dashboard.mjs +8 -8
  128. package/dist/astro/routes/api/dev/emails.mjs +3 -3
  129. package/dist/astro/routes/api/import/probe.d.mts +3 -3
  130. package/dist/astro/routes/api/import/probe.mjs +19 -11
  131. package/dist/astro/routes/api/import/probe.mjs.map +1 -1
  132. package/dist/astro/routes/api/import/wordpress/analyze.mjs +3 -3
  133. package/dist/astro/routes/api/import/wordpress/execute.d.mts +11 -41
  134. package/dist/astro/routes/api/import/wordpress/execute.d.mts.map +1 -1
  135. package/dist/astro/routes/api/import/wordpress/execute.mjs +12 -407
  136. package/dist/astro/routes/api/import/wordpress/execute.mjs.map +1 -1
  137. package/dist/astro/routes/api/import/wordpress/media.d.mts +10 -10
  138. package/dist/astro/routes/api/import/wordpress/media.mjs +9 -9
  139. package/dist/astro/routes/api/import/wordpress/prepare.mjs +9 -9
  140. package/dist/astro/routes/api/import/wordpress/rewrite-urls.d.mts +19 -1
  141. package/dist/astro/routes/api/import/wordpress/rewrite-urls.d.mts.map +1 -1
  142. package/dist/astro/routes/api/import/wordpress/rewrite-urls.mjs +97 -79
  143. package/dist/astro/routes/api/import/wordpress/rewrite-urls.mjs.map +1 -1
  144. package/dist/astro/routes/api/import/wordpress-plugin/analyze.d.mts +1 -1
  145. package/dist/astro/routes/api/import/wordpress-plugin/analyze.mjs +19 -11
  146. package/dist/astro/routes/api/import/wordpress-plugin/analyze.mjs.map +1 -1
  147. package/dist/astro/routes/api/import/wordpress-plugin/execute.d.mts +40 -2
  148. package/dist/astro/routes/api/import/wordpress-plugin/execute.d.mts.map +1 -1
  149. package/dist/astro/routes/api/import/wordpress-plugin/execute.mjs +519 -39
  150. package/dist/astro/routes/api/import/wordpress-plugin/execute.mjs.map +1 -1
  151. package/dist/astro/routes/api/manifest.mjs +4 -4
  152. package/dist/astro/routes/api/mcp.mjs +39 -39
  153. package/dist/astro/routes/api/media/_id_/confirm.mjs +7 -7
  154. package/dist/astro/routes/api/media/_id_.mjs +7 -7
  155. package/dist/astro/routes/api/media/file/_...key_.mjs +2 -2
  156. package/dist/astro/routes/api/media/providers/_providerId_/_itemId_.mjs +3 -3
  157. package/dist/astro/routes/api/media/providers/_providerId_/index.mjs +3 -3
  158. package/dist/astro/routes/api/media/providers/index.mjs +3 -3
  159. package/dist/astro/routes/api/media/upload-url.mjs +8 -8
  160. package/dist/astro/routes/api/media.mjs +9 -9
  161. package/dist/astro/routes/api/menus/_name_/items/_id_.mjs +9 -9
  162. package/dist/astro/routes/api/menus/_name_/items.mjs +9 -9
  163. package/dist/astro/routes/api/menus/_name_/reorder.mjs +9 -9
  164. package/dist/astro/routes/api/menus/_name_/translations.mjs +9 -9
  165. package/dist/astro/routes/api/menus/_name_.mjs +9 -9
  166. package/dist/astro/routes/api/menus/index.mjs +9 -9
  167. package/dist/astro/routes/api/oauth/authorize.mjs +6 -6
  168. package/dist/astro/routes/api/oauth/device/authorize.mjs +6 -6
  169. package/dist/astro/routes/api/oauth/device/code.mjs +9 -9
  170. package/dist/astro/routes/api/oauth/device/token.mjs +8 -8
  171. package/dist/astro/routes/api/oauth/register.mjs +3 -3
  172. package/dist/astro/routes/api/oauth/token/refresh.mjs +6 -6
  173. package/dist/astro/routes/api/oauth/token/revoke.mjs +6 -6
  174. package/dist/astro/routes/api/oauth/token.mjs +6 -6
  175. package/dist/astro/routes/api/openapi.json.mjs +4 -4
  176. package/dist/astro/routes/api/plugins/_pluginId_/_...path_.d.mts.map +1 -1
  177. package/dist/astro/routes/api/plugins/_pluginId_/_...path_.mjs +6 -14
  178. package/dist/astro/routes/api/plugins/_pluginId_/_...path_.mjs.map +1 -1
  179. package/dist/astro/routes/api/redirects/404s/index.mjs +9 -9
  180. package/dist/astro/routes/api/redirects/404s/summary.mjs +9 -9
  181. package/dist/astro/routes/api/redirects/_id_.mjs +10 -10
  182. package/dist/astro/routes/api/redirects/index.mjs +10 -10
  183. package/dist/astro/routes/api/revisions/_revisionId_/index.mjs +3 -3
  184. package/dist/astro/routes/api/revisions/_revisionId_/restore.mjs +3 -3
  185. package/dist/astro/routes/api/schema/collections/_slug_/fields/_fieldSlug_.mjs +36 -35
  186. package/dist/astro/routes/api/schema/collections/_slug_/fields/_fieldSlug_.mjs.map +1 -1
  187. package/dist/astro/routes/api/schema/collections/_slug_/fields/index.mjs +36 -35
  188. package/dist/astro/routes/api/schema/collections/_slug_/fields/index.mjs.map +1 -1
  189. package/dist/astro/routes/api/schema/collections/_slug_/fields/reorder.mjs +36 -35
  190. package/dist/astro/routes/api/schema/collections/_slug_/fields/reorder.mjs.map +1 -1
  191. package/dist/astro/routes/api/schema/collections/_slug_/index.mjs +36 -35
  192. package/dist/astro/routes/api/schema/collections/_slug_/index.mjs.map +1 -1
  193. package/dist/astro/routes/api/schema/collections/index.mjs +36 -35
  194. package/dist/astro/routes/api/schema/collections/index.mjs.map +1 -1
  195. package/dist/astro/routes/api/schema/index.mjs +7 -6
  196. package/dist/astro/routes/api/schema/index.mjs.map +1 -1
  197. package/dist/astro/routes/api/schema/orphans/_slug_.mjs +36 -35
  198. package/dist/astro/routes/api/schema/orphans/_slug_.mjs.map +1 -1
  199. package/dist/astro/routes/api/schema/orphans/index.mjs +36 -35
  200. package/dist/astro/routes/api/schema/orphans/index.mjs.map +1 -1
  201. package/dist/astro/routes/api/search/enable.mjs +10 -10
  202. package/dist/astro/routes/api/search/index.mjs +9 -9
  203. package/dist/astro/routes/api/search/rebuild.mjs +10 -10
  204. package/dist/astro/routes/api/search/stats.mjs +6 -6
  205. package/dist/astro/routes/api/search/suggest.mjs +9 -9
  206. package/dist/astro/routes/api/sections/_slug_.mjs +9 -9
  207. package/dist/astro/routes/api/sections/index.mjs +9 -9
  208. package/dist/astro/routes/api/settings/email.mjs +4 -4
  209. package/dist/astro/routes/api/settings.mjs +12 -12
  210. package/dist/astro/routes/api/setup/admin-verify.mjs +11 -11
  211. package/dist/astro/routes/api/setup/admin.mjs +10 -10
  212. package/dist/astro/routes/api/setup/dev-bypass.mjs +25 -24
  213. package/dist/astro/routes/api/setup/dev-bypass.mjs.map +1 -1
  214. package/dist/astro/routes/api/setup/dev-reset.mjs +2 -2
  215. package/dist/astro/routes/api/setup/index.mjs +26 -25
  216. package/dist/astro/routes/api/setup/index.mjs.map +1 -1
  217. package/dist/astro/routes/api/setup/status.mjs +4 -4
  218. package/dist/astro/routes/api/snapshot.mjs +6 -6
  219. package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_/translations.mjs +13 -13
  220. package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_.mjs +13 -13
  221. package/dist/astro/routes/api/taxonomies/_name_/terms/index.mjs +13 -13
  222. package/dist/astro/routes/api/taxonomies/index.mjs +13 -13
  223. package/dist/astro/routes/api/themes/preview.mjs +5 -5
  224. package/dist/astro/routes/api/typegen.mjs +5 -5
  225. package/dist/astro/routes/api/well-known/auth.mjs +1 -1
  226. package/dist/astro/routes/api/well-known/oauth-authorization-server.mjs +2 -2
  227. package/dist/astro/routes/api/well-known/oauth-protected-resource.mjs +2 -2
  228. package/dist/astro/routes/api/widget-areas/_name_/reorder.mjs +7 -7
  229. package/dist/astro/routes/api/widget-areas/_name_/widgets/_id_.mjs +9 -9
  230. package/dist/astro/routes/api/widget-areas/_name_/widgets.mjs +9 -9
  231. package/dist/astro/routes/api/widget-areas/_name_.mjs +5 -5
  232. package/dist/astro/routes/api/widget-areas/index.mjs +9 -9
  233. package/dist/astro/routes/api/widget-components.mjs +3 -3
  234. package/dist/astro/routes/robots.txt.mjs +6 -6
  235. package/dist/astro/routes/sitemap-_collection_.xml.mjs +9 -9
  236. package/dist/astro/routes/sitemap.xml.mjs +7 -7
  237. package/dist/astro/types.d.mts +13 -13
  238. package/dist/auth/providers/github.d.mts +1 -1
  239. package/dist/auth/providers/google.d.mts +1 -1
  240. package/dist/{authorize-C3a_zGsM.mjs → authorize-Dz88F_Fw.mjs} +2 -2
  241. package/dist/{authorize-C3a_zGsM.mjs.map → authorize-Dz88F_Fw.mjs.map} +1 -1
  242. package/dist/{byline-DEKSVPTy.mjs → byline-Bm8ZgUP9.mjs} +6 -6
  243. package/dist/{byline-DEKSVPTy.mjs.map → byline-Bm8ZgUP9.mjs.map} +1 -1
  244. package/dist/{byline-fields-eyJMblSr.mjs → byline-fields-2Lp5Hbgf.mjs} +18 -3
  245. package/dist/byline-fields-2Lp5Hbgf.mjs.map +1 -0
  246. package/dist/{byline-fields-CtQ6blXd.d.mts → byline-fields-CHE8UStY.d.mts} +47 -32
  247. package/dist/{byline-fields-CtQ6blXd.d.mts.map → byline-fields-CHE8UStY.d.mts.map} +1 -1
  248. package/dist/{byline-fields-DaMKzkhO.mjs → byline-fields-CIx_GuN4.mjs} +1 -1
  249. package/dist/{byline-fields-DaMKzkhO.mjs.map → byline-fields-CIx_GuN4.mjs.map} +1 -1
  250. package/dist/{bylines-Ds4-otXl.mjs → bylines-6tm9mgQb.mjs} +4 -4
  251. package/dist/{bylines-Ds4-otXl.mjs.map → bylines-6tm9mgQb.mjs.map} +1 -1
  252. package/dist/{bylines-CiqgTHWF.mjs → bylines-CAZxGSrm.mjs} +6 -6
  253. package/dist/{bylines-CiqgTHWF.mjs.map → bylines-CAZxGSrm.mjs.map} +1 -1
  254. package/dist/{cache-Ciu3e3AF.mjs → cache-CEBAZjir.mjs} +2 -2
  255. package/dist/{cache-Ciu3e3AF.mjs.map → cache-CEBAZjir.mjs.map} +1 -1
  256. package/dist/{challenge-store-LhiqMccz.mjs → challenge-store-anhwVER0.mjs} +1 -1
  257. package/dist/{challenge-store-LhiqMccz.mjs.map → challenge-store-anhwVER0.mjs.map} +1 -1
  258. package/dist/{chunks-CZFiauig.mjs → chunks-B2isWQhr.mjs} +2 -2
  259. package/dist/{chunks-CZFiauig.mjs.map → chunks-B2isWQhr.mjs.map} +1 -1
  260. package/dist/cli/index.mjs +22 -21
  261. package/dist/cli/index.mjs.map +1 -1
  262. package/dist/client/cf-access.d.mts +1 -1
  263. package/dist/client/index.d.mts +1 -1
  264. package/dist/client/index.mjs +2 -2
  265. package/dist/{comment-CH1IrFFs.mjs → comment-CzeatwBV.mjs} +3 -3
  266. package/dist/{comment-CH1IrFFs.mjs.map → comment-CzeatwBV.mjs.map} +1 -1
  267. package/dist/{comment-reaction-kruNY-kP.mjs → comment-reaction-Cj9QJY7I.mjs} +2 -2
  268. package/dist/{comment-reaction-kruNY-kP.mjs.map → comment-reaction-Cj9QJY7I.mjs.map} +1 -1
  269. package/dist/{comments-BUJyXbgq.mjs → comments-BLE-jv5k.mjs} +3 -3
  270. package/dist/{comments-BUJyXbgq.mjs.map → comments-BLE-jv5k.mjs.map} +1 -1
  271. package/dist/{components-CYt4uVK9.mjs → components-B_sATNUc.mjs} +1 -1
  272. package/dist/{components-CYt4uVK9.mjs.map → components-B_sATNUc.mjs.map} +1 -1
  273. package/dist/{content-RmfHoWqK.mjs → content-DhgEth4k.mjs} +4 -4
  274. package/dist/{content-RmfHoWqK.mjs.map → content-DhgEth4k.mjs.map} +1 -1
  275. package/dist/content-refresh-Br4gMzh8.mjs +1537 -0
  276. package/dist/content-refresh-Br4gMzh8.mjs.map +1 -0
  277. package/dist/{context-CzUU_WzL.mjs → context-BRIpHARC.mjs} +76 -54
  278. package/dist/context-BRIpHARC.mjs.map +1 -0
  279. package/dist/{cron-C5LVoNmP.mjs → cron-v4FTEFR_.mjs} +1 -1
  280. package/dist/{cron-C5LVoNmP.mjs.map → cron-v4FTEFR_.mjs.map} +1 -1
  281. package/dist/{dashboard-CVyGhift.mjs → dashboard-EvEKF5en.mjs} +4 -4
  282. package/dist/{dashboard-CVyGhift.mjs.map → dashboard-EvEKF5en.mjs.map} +1 -1
  283. package/dist/db/index.d.mts +3 -3
  284. package/dist/db/index.mjs +1 -1
  285. package/dist/db/libsql.d.mts +1 -1
  286. package/dist/db/postgres.d.mts +1 -1
  287. package/dist/db/sqlite.d.mts +1 -1
  288. package/dist/{default-CeRG-Ot4.mjs → default-CM_D83Mg.mjs} +1 -1
  289. package/dist/{default-CeRG-Ot4.mjs.map → default-CM_D83Mg.mjs.map} +1 -1
  290. package/dist/{device-flow-DENDCQ9F.mjs → device-flow-CfGP18Uw.mjs} +4 -4
  291. package/dist/{device-flow-DENDCQ9F.mjs.map → device-flow-CfGP18Uw.mjs.map} +1 -1
  292. package/dist/{email-console-DJP32ucW.mjs → email-console-CIf4Lfvv.mjs} +1 -1
  293. package/dist/{email-console-DJP32ucW.mjs.map → email-console-CIf4Lfvv.mjs.map} +1 -1
  294. package/dist/{error-BHkLZk-w.mjs → error-CkAseSqZ.mjs} +2 -2
  295. package/dist/{error-BHkLZk-w.mjs.map → error-CkAseSqZ.mjs.map} +1 -1
  296. package/dist/{escape-Bjio4ZsM.mjs → escape-DqD0aCKu.mjs} +1 -1
  297. package/dist/{escape-Bjio4ZsM.mjs.map → escape-DqD0aCKu.mjs.map} +1 -1
  298. package/dist/{field-defs-cache-BA-8ZPiT.mjs → field-defs-cache-WUI88LX5.mjs} +2 -2
  299. package/dist/{field-defs-cache-BA-8ZPiT.mjs.map → field-defs-cache-WUI88LX5.mjs.map} +1 -1
  300. package/dist/{fts-manager-Db9jGavf.mjs → fts-manager-BbFaF_V8.mjs} +2 -2
  301. package/dist/{fts-manager-Db9jGavf.mjs.map → fts-manager-BbFaF_V8.mjs.map} +1 -1
  302. package/dist/{import-Bb1T9WJS.mjs → import-fYLf14Co.mjs} +514 -25
  303. package/dist/import-fYLf14Co.mjs.map +1 -0
  304. package/dist/{index-CDZZjrLT.d.mts → index-B9sIxwe4.d.mts} +21 -22
  305. package/dist/{index-CDZZjrLT.d.mts.map → index-B9sIxwe4.d.mts.map} +1 -1
  306. package/dist/{index-DGIjmUXQ.d.mts → index-Bm-Gy8Mh.d.mts} +25 -4
  307. package/dist/index-Bm-Gy8Mh.d.mts.map +1 -0
  308. package/dist/index.d.mts +18 -18
  309. package/dist/index.mjs +54 -53
  310. package/dist/{load-DpHICVPh.mjs → load-Djn3HWQS.mjs} +2 -2
  311. package/dist/{load-DpHICVPh.mjs.map → load-Djn3HWQS.mjs.map} +1 -1
  312. package/dist/{loader-4K37qA-y.mjs → loader-CB6YHeul.mjs} +6 -5
  313. package/dist/loader-CB6YHeul.mjs.map +1 -0
  314. package/dist/{manifest-schema-kPGX7VS-.mjs → manifest-schema-BHlgZM1W.mjs} +1 -1
  315. package/dist/{manifest-schema-kPGX7VS-.mjs.map → manifest-schema-BHlgZM1W.mjs.map} +1 -1
  316. package/dist/media/index.d.mts +1 -1
  317. package/dist/media/local-runtime.d.mts +12 -12
  318. package/dist/media/local-runtime.mjs +5 -5
  319. package/dist/{media-C0nRRfs1.mjs → media-BrXIaMFN.mjs} +2 -2
  320. package/dist/{media-C0nRRfs1.mjs.map → media-BrXIaMFN.mjs.map} +1 -1
  321. package/dist/{media-allowlist-Du8t1u6a.mjs → media-allowlist-CRHEeJ_i.mjs} +1 -1
  322. package/dist/{media-allowlist-Du8t1u6a.mjs.map → media-allowlist-CRHEeJ_i.mjs.map} +1 -1
  323. package/dist/{media-url-O4rm9-SQ.mjs → media-url-CKi5XSw4.mjs} +1 -1
  324. package/dist/{media-url-O4rm9-SQ.mjs.map → media-url-CKi5XSw4.mjs.map} +1 -1
  325. package/dist/{menus-SL2K0xq2.mjs → menus-Cfivc2Ad.mjs} +3 -3
  326. package/dist/{menus-SL2K0xq2.mjs.map → menus-Cfivc2Ad.mjs.map} +1 -1
  327. package/dist/{menus-DzRyC1ID.mjs → menus-b2T4clbO.mjs} +16 -12
  328. package/dist/{menus-DzRyC1ID.mjs.map → menus-b2T4clbO.mjs.map} +1 -1
  329. package/dist/{mode-BB0F8xTC.mjs → mode-BM9QgEmt.mjs} +1 -1
  330. package/dist/{mode-BB0F8xTC.mjs.map → mode-BM9QgEmt.mjs.map} +1 -1
  331. package/dist/{oauth-authorization-CsvzIp_F.mjs → oauth-authorization-CXWkIGT4.mjs} +4 -4
  332. package/dist/{oauth-authorization-CsvzIp_F.mjs.map → oauth-authorization-CXWkIGT4.mjs.map} +1 -1
  333. package/dist/{oauth-clients-C9SYwEbZ.mjs → oauth-clients-BmTI5rsl.mjs} +1 -1
  334. package/dist/{oauth-clients-C9SYwEbZ.mjs.map → oauth-clients-BmTI5rsl.mjs.map} +1 -1
  335. package/dist/{oauth-state-store---zrApfB.mjs → oauth-state-store-YLFLcH5F.mjs} +1 -1
  336. package/dist/{oauth-state-store---zrApfB.mjs.map → oauth-state-store-YLFLcH5F.mjs.map} +1 -1
  337. package/dist/{oauth-user-lookup-SHsWRlG9.mjs → oauth-user-lookup-Bsc_GsX-.mjs} +1 -1
  338. package/dist/{oauth-user-lookup-SHsWRlG9.mjs.map → oauth-user-lookup-Bsc_GsX-.mjs.map} +1 -1
  339. package/dist/object-cache/memory.d.mts +1 -1
  340. package/dist/{object-cache-CHbHv83-.mjs → object-cache-Bok5j2ae.mjs} +43 -3
  341. package/dist/object-cache-Bok5j2ae.mjs.map +1 -0
  342. package/dist/{options-41nCWqi9.d.mts → options-iMpRRxIe.d.mts} +3 -3
  343. package/dist/{options-41nCWqi9.d.mts.map → options-iMpRRxIe.d.mts.map} +1 -1
  344. package/dist/page/index.d.mts +2 -2
  345. package/dist/{parse-CqyZj3Hp.mjs → parse-GmjecGct.mjs} +2 -2
  346. package/dist/{parse-CqyZj3Hp.mjs.map → parse-GmjecGct.mjs.map} +1 -1
  347. package/dist/{passkey-config-C0YfSBko.mjs → passkey-config-De0ahnRg.mjs} +1 -1
  348. package/dist/{passkey-config-C0YfSBko.mjs.map → passkey-config-De0ahnRg.mjs.map} +1 -1
  349. package/dist/{placeholder-Cuce9U-m.d.mts → placeholder-BSKwzRe4.d.mts} +1 -1
  350. package/dist/{placeholder-Cuce9U-m.d.mts.map → placeholder-BSKwzRe4.d.mts.map} +1 -1
  351. package/dist/plugin-types.d.mts +1 -1
  352. package/dist/plugin-utils.d.mts +10 -10
  353. package/dist/plugins/adapt-sandbox-entry.d.mts +10 -10
  354. package/dist/plugins/adapt-sandbox-entry.mjs +2 -2
  355. package/dist/{portable-text-BICg8bTk.mjs → portable-text-cCa0cGV6.mjs} +1 -1
  356. package/dist/{portable-text-BICg8bTk.mjs.map → portable-text-cCa0cGV6.mjs.map} +1 -1
  357. package/dist/{preview-DKGCt2_p.mjs → preview-SSXNVPAC.mjs} +2 -2
  358. package/dist/{preview-DKGCt2_p.mjs.map → preview-SSXNVPAC.mjs.map} +1 -1
  359. package/dist/{public-url-CTVqgMmg.mjs → public-url-Danv47cS.mjs} +1 -1
  360. package/dist/{public-url-CTVqgMmg.mjs.map → public-url-Danv47cS.mjs.map} +1 -1
  361. package/dist/{query-B0M-9LYR.mjs → query-1Cp6U9oo.mjs} +14 -14
  362. package/dist/{query-B0M-9LYR.mjs.map → query-1Cp6U9oo.mjs.map} +1 -1
  363. package/dist/{rate-limit-BwoUdIpC.mjs → rate-limit-C_Lf63Dd.mjs} +2 -2
  364. package/dist/{rate-limit-BwoUdIpC.mjs.map → rate-limit-C_Lf63Dd.mjs.map} +1 -1
  365. package/dist/{redirect-CS-PHtNh.mjs → redirect-CoW3G-0U.mjs} +1 -1
  366. package/dist/{redirect-CS-PHtNh.mjs.map → redirect-CoW3G-0U.mjs.map} +1 -1
  367. package/dist/{redirect-lMOzG04S.mjs → redirect-IyfNirgS.mjs} +2 -2
  368. package/dist/{redirect-lMOzG04S.mjs.map → redirect-IyfNirgS.mjs.map} +1 -1
  369. package/dist/{redirects-9218MmYl.mjs → redirects-Bs1g42Ri.mjs} +4 -4
  370. package/dist/{redirects-9218MmYl.mjs.map → redirects-Bs1g42Ri.mjs.map} +1 -1
  371. package/dist/{redirects-Dcbuisoj.mjs → redirects-DXEXBAII.mjs} +2 -2
  372. package/dist/{redirects-Dcbuisoj.mjs.map → redirects-DXEXBAII.mjs.map} +1 -1
  373. package/dist/{registry-DP-iEtdR.mjs → registry-B57vp_X9.mjs} +122 -79
  374. package/dist/registry-B57vp_X9.mjs.map +1 -0
  375. package/dist/{request-meta-CmS1tDFf.mjs → request-meta-DbvXaAvU.mjs} +2 -2
  376. package/dist/{request-meta-CmS1tDFf.mjs.map → request-meta-DbvXaAvU.mjs.map} +1 -1
  377. package/dist/{resolve-C7I0qiR0.mjs → resolve-DR3wqMTy.mjs} +1 -1
  378. package/dist/{resolve-C7I0qiR0.mjs.map → resolve-DR3wqMTy.mjs.map} +1 -1
  379. package/dist/{runner-BbR3DfrL.d.mts → runner-DvFWoz8-.d.mts} +2 -2
  380. package/dist/{runner-BbR3DfrL.d.mts.map → runner-DvFWoz8-.d.mts.map} +1 -1
  381. package/dist/{runner-CFngB4WZ.mjs → runner-K8XK101B.mjs} +309 -190
  382. package/dist/runner-K8XK101B.mjs.map +1 -0
  383. package/dist/runtime.d.mts +11 -11
  384. package/dist/runtime.mjs +2 -2
  385. package/dist/{scheduled-publish-BMljtY5G.d.mts → scheduled-publish-Drffrf2a.d.mts} +1 -1
  386. package/dist/scheduled-publish-Drffrf2a.d.mts.map +1 -0
  387. package/dist/{schema-BfJ7bIXH.mjs → schema-CX9cfNkZ.mjs} +5 -5
  388. package/dist/{schema-BfJ7bIXH.mjs.map → schema-CX9cfNkZ.mjs.map} +1 -1
  389. package/dist/{search-C7t3PH1J.mjs → search-DZN2HZ-V.mjs} +4 -4
  390. package/dist/{search-C7t3PH1J.mjs.map → search-DZN2HZ-V.mjs.map} +1 -1
  391. package/dist/{secrets-BSf9pRRY.mjs → secrets-kp760LlD.mjs} +2 -2
  392. package/dist/{secrets-BSf9pRRY.mjs.map → secrets-kp760LlD.mjs.map} +1 -1
  393. package/dist/{sections-Dm0CVX23.mjs → sections-CpF5SaGr.mjs} +3 -3
  394. package/dist/{sections-Dm0CVX23.mjs.map → sections-CpF5SaGr.mjs.map} +1 -1
  395. package/dist/seed/index.d.mts +2 -2
  396. package/dist/seed/index.mjs +19 -18
  397. package/dist/seo/index.d.mts +1 -1
  398. package/dist/seo/index.mjs +1 -1
  399. package/dist/{seo-BkhuuaaE.mjs → seo-89-53DDs.mjs} +1 -1
  400. package/dist/{seo-BkhuuaaE.mjs.map → seo-89-53DDs.mjs.map} +1 -1
  401. package/dist/{seo-Dd3tbY_k.mjs → seo-DXu2UQnC.mjs} +3 -3
  402. package/dist/{seo-Dd3tbY_k.mjs.map → seo-DXu2UQnC.mjs.map} +1 -1
  403. package/dist/{service-CTrqp_Jy.mjs → service-DQmiBMzt.mjs} +3 -3
  404. package/dist/{service-CTrqp_Jy.mjs.map → service-DQmiBMzt.mjs.map} +1 -1
  405. package/dist/{session-user-B8aLtKAH.mjs → session-user-Cascbax7.mjs} +1 -1
  406. package/dist/{session-user-B8aLtKAH.mjs.map → session-user-Cascbax7.mjs.map} +1 -1
  407. package/dist/{settings-CZ7ZP9cW.mjs → settings-rZyHEcNT.mjs} +3 -3
  408. package/dist/{settings-CZ7ZP9cW.mjs.map → settings-rZyHEcNT.mjs.map} +1 -1
  409. package/dist/{settings-BX8cWBus.mjs → settings-zhmdKyJQ.mjs} +5 -5
  410. package/dist/{settings-BX8cWBus.mjs.map → settings-zhmdKyJQ.mjs.map} +1 -1
  411. package/dist/{setup-complete-gEiySUc-.mjs → setup-complete-Cb3LRyzy.mjs} +1 -1
  412. package/dist/{setup-complete-gEiySUc-.mjs.map → setup-complete-Cb3LRyzy.mjs.map} +1 -1
  413. package/dist/{setup-nonce-DzS50zme.mjs → setup-nonce-Z8x0tHf8.mjs} +1 -1
  414. package/dist/{setup-nonce-DzS50zme.mjs.map → setup-nonce-Z8x0tHf8.mjs.map} +1 -1
  415. package/dist/{single-flight-cache-Cdfkic3t.mjs → single-flight-cache-BG3B_GhN.mjs} +1 -1
  416. package/dist/{single-flight-cache-Cdfkic3t.mjs.map → single-flight-cache-BG3B_GhN.mjs.map} +1 -1
  417. package/dist/{site-url-BLebyON8.mjs → site-url-BBfDTgZB.mjs} +1 -1
  418. package/dist/{site-url-BLebyON8.mjs.map → site-url-BBfDTgZB.mjs.map} +1 -1
  419. package/dist/{ssrf-BRKb343l.mjs → ssrf-1g7usGBg.mjs} +1 -1
  420. package/dist/{ssrf-BRKb343l.mjs.map → ssrf-1g7usGBg.mjs.map} +1 -1
  421. package/dist/{status-vUK0SA17.mjs → status-CqJQX1QN.mjs} +1 -1
  422. package/dist/{status-vUK0SA17.mjs.map → status-CqJQX1QN.mjs.map} +1 -1
  423. package/dist/storage/local.d.mts +1 -1
  424. package/dist/storage/local.mjs +1 -1
  425. package/dist/storage/s3.d.mts +1 -1
  426. package/dist/storage/s3.mjs +1 -1
  427. package/dist/{taxonomies-DChKcVxf.mjs → taxonomies-Bs13SN-F.mjs} +4 -4
  428. package/dist/{taxonomies-DChKcVxf.mjs.map → taxonomies-Bs13SN-F.mjs.map} +1 -1
  429. package/dist/{taxonomies-ckPjz-6d.mjs → taxonomies-kH9ABDUF.mjs} +7 -7
  430. package/dist/{taxonomies-ckPjz-6d.mjs.map → taxonomies-kH9ABDUF.mjs.map} +1 -1
  431. package/dist/{taxonomy-Cru-he6s.mjs → taxonomy-BxGxZZdu.mjs} +4 -4
  432. package/dist/{taxonomy-Cru-he6s.mjs.map → taxonomy-BxGxZZdu.mjs.map} +1 -1
  433. package/dist/{tokens-LeuXF9gG.mjs → tokens-BGT0TUUo.mjs} +1 -1
  434. package/dist/{tokens-LeuXF9gG.mjs.map → tokens-BGT0TUUo.mjs.map} +1 -1
  435. package/dist/{transport-Blrl2k_o.d.mts → transport-BMDWHSgZ.d.mts} +1 -1
  436. package/dist/{transport-Blrl2k_o.d.mts.map → transport-BMDWHSgZ.d.mts.map} +1 -1
  437. package/dist/{transport-_2nBz7e9.mjs → transport-DPefPMcz.mjs} +1 -1
  438. package/dist/{transport-_2nBz7e9.mjs.map → transport-DPefPMcz.mjs.map} +1 -1
  439. package/dist/{trusted-proxy-DZY5WCn2.mjs → trusted-proxy-VTPRiX2s.mjs} +1 -1
  440. package/dist/{trusted-proxy-DZY5WCn2.mjs.map → trusted-proxy-VTPRiX2s.mjs.map} +1 -1
  441. package/dist/{types-ETmO_jQr.d.mts → types-BcLUUbbR.d.mts} +2 -2
  442. package/dist/{types-ETmO_jQr.d.mts.map → types-BcLUUbbR.d.mts.map} +1 -1
  443. package/dist/{types-BYnDBVwe.d.mts → types-CGbYowGQ.d.mts} +2 -2
  444. package/dist/{types-BYnDBVwe.d.mts.map → types-CGbYowGQ.d.mts.map} +1 -1
  445. package/dist/{types-CvuKO5Pn.d.mts → types-CgvhU-hF.d.mts} +1 -1
  446. package/dist/{types-CvuKO5Pn.d.mts.map → types-CgvhU-hF.d.mts.map} +1 -1
  447. package/dist/{types-Y09-wtyU.d.mts → types-ClUkdbWb.d.mts} +1 -1
  448. package/dist/{types-Y09-wtyU.d.mts.map → types-ClUkdbWb.d.mts.map} +1 -1
  449. package/dist/{types-DU4TSFS5.mjs → types-CuW0zWDA.mjs} +2 -2
  450. package/dist/{types-DU4TSFS5.mjs.map → types-CuW0zWDA.mjs.map} +1 -1
  451. package/dist/{types-BkZ8DUEI.d.mts → types-DmHk7vAt.d.mts} +1 -1
  452. package/dist/{types-BkZ8DUEI.d.mts.map → types-DmHk7vAt.d.mts.map} +1 -1
  453. package/dist/{types-CQAugunJ.mjs → types-Jo3UYd6b.mjs} +1 -1
  454. package/dist/{types-CQAugunJ.mjs.map → types-Jo3UYd6b.mjs.map} +1 -1
  455. package/dist/{types-xIfVRNLp.d.mts → types-_HFLRzTn.d.mts} +22 -1
  456. package/dist/types-_HFLRzTn.d.mts.map +1 -0
  457. package/dist/{types-ByChcBgE.d.mts → types-ea9sAPck.d.mts} +1 -1
  458. package/dist/{types-ByChcBgE.d.mts.map → types-ea9sAPck.d.mts.map} +1 -1
  459. package/dist/{types-CNlaBFzx.d.mts → types-g_aFIdW0.d.mts} +1 -1
  460. package/dist/{types-CNlaBFzx.d.mts.map → types-g_aFIdW0.d.mts.map} +1 -1
  461. package/dist/{types-Dbqff978.d.mts → types-vgEWF18A.d.mts} +19 -1
  462. package/dist/{types-Dbqff978.d.mts.map → types-vgEWF18A.d.mts.map} +1 -1
  463. package/dist/{user-DgGbKL9s.mjs → user-BjAOvU3Z.mjs} +3 -3
  464. package/dist/{user-DgGbKL9s.mjs.map → user-BjAOvU3Z.mjs.map} +1 -1
  465. package/dist/{utils-B7A57fm9.mjs → utils-BJXElxdw.mjs} +156 -7
  466. package/dist/utils-BJXElxdw.mjs.map +1 -0
  467. package/dist/{validate-CRkcYZAR.mjs → validate-CWSnKVIJ.mjs} +2 -2
  468. package/dist/{validate-CRkcYZAR.mjs.map → validate-CWSnKVIJ.mjs.map} +1 -1
  469. package/dist/{validate-9ECmtEpJ.d.mts → validate-Z1b86_3B.d.mts} +5 -5
  470. package/dist/{validate-9ECmtEpJ.d.mts.map → validate-Z1b86_3B.d.mts.map} +1 -1
  471. package/dist/{validation-sR26SOwD.mjs → validation-0l8-RYj4.mjs} +8 -5
  472. package/dist/{validation-sR26SOwD.mjs.map → validation-0l8-RYj4.mjs.map} +1 -1
  473. package/dist/version-qmeO1XZY.mjs +7 -0
  474. package/dist/{version-CrqhKGWn.mjs.map → version-qmeO1XZY.mjs.map} +1 -1
  475. package/dist/{widgets-DRgtn7Cl.mjs → widgets-hWcIicX8.mjs} +3 -3
  476. package/dist/{widgets-DRgtn7Cl.mjs.map → widgets-hWcIicX8.mjs.map} +1 -1
  477. package/dist/wxr-taxonomies-0_uxSrmf.d.mts +34 -0
  478. package/dist/wxr-taxonomies-0_uxSrmf.d.mts.map +1 -0
  479. package/dist/wxr-taxonomies-CNFcsNCr.mjs +425 -0
  480. package/dist/wxr-taxonomies-CNFcsNCr.mjs.map +1 -0
  481. package/dist/{zod-generator-C5JaV--i.mjs → zod-generator-CacrR-i8.mjs} +2 -2
  482. package/dist/{zod-generator-C5JaV--i.mjs.map → zod-generator-CacrR-i8.mjs.map} +1 -1
  483. package/package.json +7 -7
  484. package/src/api/handlers/content.ts +10 -7
  485. package/src/api/schemas/import.ts +19 -0
  486. package/src/astro/integration/runtime.ts +3 -6
  487. package/src/astro/middleware/auth.ts +9 -3
  488. package/src/astro/middleware/csp.ts +54 -3
  489. package/src/astro/routes/admin.astro +9 -0
  490. package/src/astro/routes/api/import/wordpress/rewrite-urls.ts +122 -98
  491. package/src/astro/routes/api/import/wordpress-plugin/execute.ts +794 -44
  492. package/src/astro/routes/api/plugins/[pluginId]/[...path].ts +17 -15
  493. package/src/components/EmDashImage.astro +59 -23
  494. package/src/components/Image.astro +36 -35
  495. package/src/database/migrations/049_taxonomies_name_locale_index.ts +42 -0
  496. package/src/database/migrations/050_media_usage_index_status.ts +142 -0
  497. package/src/database/migrations/runner.ts +4 -0
  498. package/src/database/repositories/media-usage.ts +955 -59
  499. package/src/database/types.ts +22 -0
  500. package/src/emdash-runtime.ts +123 -3
  501. package/src/import/comments.ts +159 -0
  502. package/src/import/index.ts +8 -1
  503. package/src/import/settings.ts +65 -189
  504. package/src/import/sources/wordpress-plugin.ts +338 -42
  505. package/src/import/sources/wxr.ts +4 -1
  506. package/src/import/types.ts +12 -0
  507. package/src/import/utils.ts +207 -0
  508. package/src/import/wxr-taxonomies.ts +39 -0
  509. package/src/loader.ts +13 -2
  510. package/src/media/usage/content-fields.ts +119 -0
  511. package/src/media/usage/content-refresh.ts +524 -0
  512. package/src/media/usage/content-repair.ts +675 -0
  513. package/src/media/usage/content-snapshots.ts +439 -0
  514. package/src/media/usage/extractor.ts +4 -4
  515. package/src/media/usage/source-key.ts +22 -0
  516. package/src/menus/index.ts +17 -1
  517. package/src/object-cache/index.ts +82 -7
  518. package/src/plugins/context.ts +100 -71
  519. package/src/schema/registry.ts +240 -154
  520. package/src/seed/apply.ts +156 -99
  521. package/dist/api-80kycR9o.mjs.map +0 -1
  522. package/dist/apply-DSypk6Iu.mjs.map +0 -1
  523. package/dist/byline-fields-eyJMblSr.mjs.map +0 -1
  524. package/dist/context-CzUU_WzL.mjs.map +0 -1
  525. package/dist/import-Bb1T9WJS.mjs.map +0 -1
  526. package/dist/index-DGIjmUXQ.d.mts.map +0 -1
  527. package/dist/loader-4K37qA-y.mjs.map +0 -1
  528. package/dist/object-cache-CHbHv83-.mjs.map +0 -1
  529. package/dist/registry-DP-iEtdR.mjs.map +0 -1
  530. package/dist/runner-CFngB4WZ.mjs.map +0 -1
  531. package/dist/scheduled-publish-BMljtY5G.d.mts.map +0 -1
  532. package/dist/types-xIfVRNLp.d.mts.map +0 -1
  533. package/dist/utils-B7A57fm9.mjs.map +0 -1
  534. package/dist/version-CrqhKGWn.mjs +0 -7
  535. /package/dist/{api-tokens-B4BQybOp.mjs → api-tokens-DsvvCtdh.mjs} +0 -0
  536. /package/dist/{ssrf-CcX9zvMK.mjs → ssrf-CmuGgCq3.mjs} +0 -0
  537. /package/dist/{types-BvbeGEtr.mjs → types-DROWRxYV.mjs} +0 -0
@@ -0,0 +1,1537 @@
1
+ import { t as validateIdentifier } from "./validate-VPnKoIzW.mjs";
2
+ import { r as isI18nEnabled } from "./config-CVssduLe.mjs";
3
+ import { a as encodeCursor, i as decodeCursor } from "./types-CuW0zWDA.mjs";
4
+ import { n as chunks, t as SQL_BATCH_SIZE } from "./chunks-B2isWQhr.mjs";
5
+ import { t as withTransaction } from "./transaction-qfqpPVpu.mjs";
6
+ import { t as INTERNAL_MEDIA_PREFIX } from "./normalize-CeglrBT9.mjs";
7
+ import { n as normalizeMime } from "./mime-CCEzze7W.mjs";
8
+ import { n as hashString } from "./hash-DrvzIXcz.mjs";
9
+ import { sql } from "kysely";
10
+ import { ulid } from "ulidx";
11
+
12
+ //#region src/database/repositories/media-usage.ts
13
+ const OCCURRENCE_INSERT_BATCH_SIZE = Math.max(1, Math.floor(SQL_BATCH_SIZE / 13));
14
+ /** Persistence-only repository for the internal media usage projection tables. */
15
+ var MediaUsageRepository = class {
16
+ constructor(db) {
17
+ this.db = db;
18
+ }
19
+ async replaceSource(source, occurrences) {
20
+ const generation = ulid();
21
+ const now = (/* @__PURE__ */ new Date()).toISOString();
22
+ await withTransaction(this.db, async (trx) => {
23
+ await this.insertOccurrences(trx, source.sourceKey, generation, occurrences, now);
24
+ await this.upsertSource(trx, source, generation, now);
25
+ });
26
+ const replaced = await this.findSource(source.sourceKey);
27
+ if (!replaced) throw new Error(`Media usage source ${source.sourceKey} was not persisted`);
28
+ return replaced;
29
+ }
30
+ async replaceSourceIfCurrent(source, occurrences, expectedCurrentGeneration) {
31
+ const generation = ulid();
32
+ const now = (/* @__PURE__ */ new Date()).toISOString();
33
+ const row = this.buildSourceRow(source, generation, now);
34
+ let replaced = false;
35
+ await withTransaction(this.db, async (trx) => {
36
+ await this.insertOccurrences(trx, source.sourceKey, generation, occurrences, now);
37
+ if (expectedCurrentGeneration === null) {
38
+ replaced = await this.insertSourceIfAbsent(trx, row);
39
+ return;
40
+ }
41
+ replaced = await this.updateSourceIfGeneration(trx, row, expectedCurrentGeneration);
42
+ });
43
+ return {
44
+ replaced,
45
+ source: replaced ? null : await this.findSource(source.sourceKey)
46
+ };
47
+ }
48
+ async findSource(sourceKey) {
49
+ const row = await this.db.selectFrom("_emdash_media_usage_sources").selectAll().where("source_key", "=", sourceKey).executeTakeFirst();
50
+ return row ? rowToSource(row) : null;
51
+ }
52
+ async findSources(sourceKeys) {
53
+ const uniqueSourceKeys = [...new Set(sourceKeys)];
54
+ const sources = /* @__PURE__ */ new Map();
55
+ if (uniqueSourceKeys.length === 0) return sources;
56
+ for (const sourceKeyBatch of chunks(uniqueSourceKeys, SQL_BATCH_SIZE)) {
57
+ const rows = await this.db.selectFrom("_emdash_media_usage_sources").selectAll().where("source_key", "in", sourceKeyBatch).execute();
58
+ for (const row of rows) {
59
+ const source = rowToSource(row);
60
+ sources.set(source.sourceKey, source);
61
+ }
62
+ }
63
+ return sources;
64
+ }
65
+ async replaceSourceIfMatching(source, occurrences, expectedSource) {
66
+ const generation = ulid();
67
+ const now = (/* @__PURE__ */ new Date()).toISOString();
68
+ const row = this.buildSourceRow(source, generation, now);
69
+ let replaced = false;
70
+ await withTransaction(this.db, async (trx) => {
71
+ await this.insertOccurrences(trx, source.sourceKey, generation, occurrences, now);
72
+ if (expectedSource === null) {
73
+ replaced = await this.insertSourceIfAbsent(trx, row);
74
+ return;
75
+ }
76
+ replaced = await this.updateSourceIfMatching(trx, row, expectedSource);
77
+ });
78
+ return {
79
+ replaced,
80
+ source: replaced ? null : await this.findSource(source.sourceKey)
81
+ };
82
+ }
83
+ async markSourceAttempted(source) {
84
+ const now = (/* @__PURE__ */ new Date()).toISOString();
85
+ const row = this.buildAttemptedSourceRow(source, now);
86
+ const updates = this.attemptedSourceUpdateSet(source, row);
87
+ await this.db.insertInto("_emdash_media_usage_sources").values(row).onConflict((oc) => oc.column("source_key").doUpdateSet(updates)).execute();
88
+ const attempted = await this.findSource(source.sourceKey);
89
+ if (!attempted) throw new Error(`Media usage source ${source.sourceKey} was not persisted`);
90
+ return attempted;
91
+ }
92
+ async markSourceAttemptedIfMatching(source, expectedSource) {
93
+ const now = (/* @__PURE__ */ new Date()).toISOString();
94
+ const row = this.buildAttemptedSourceRow(source, now);
95
+ let attempted = false;
96
+ if (expectedSource === null) attempted = await this.insertSourceIfAbsent(this.db, row);
97
+ else attempted = await this.updateAttemptedSourceIfMatching(this.db, source, row, expectedSource);
98
+ return {
99
+ attempted,
100
+ source: attempted ? null : await this.findSource(source.sourceKey)
101
+ };
102
+ }
103
+ async findCurrentUsageByMediaId(mediaId) {
104
+ return (await this.db.selectFrom("_emdash_media_usage_sources as s").innerJoin("_emdash_media_usage as u", (join) => join.onRef("u.source_key", "=", "s.source_key").onRef("u.generation", "=", "s.current_generation")).select(currentUsageSelect).where("u.media_id", "=", mediaId).orderBy("s.source_key", "asc").orderBy("u.field_path", "asc").orderBy("u.occurrence_index", "asc").execute()).map(rowToUsageRecord);
105
+ }
106
+ async findCurrentUsageByProviderAsset(provider, providerAssetId) {
107
+ return (await this.db.selectFrom("_emdash_media_usage_sources as s").innerJoin("_emdash_media_usage as u", (join) => join.onRef("u.source_key", "=", "s.source_key").onRef("u.generation", "=", "s.current_generation")).select(currentUsageSelect).where("u.provider", "=", provider).where("u.provider_asset_id", "=", providerAssetId).orderBy("s.source_key", "asc").orderBy("u.field_path", "asc").orderBy("u.occurrence_index", "asc").execute()).map(rowToUsageRecord);
108
+ }
109
+ async findCurrentUsagePageByMediaId(mediaId, options = {}) {
110
+ return this.findCurrentUsagePage((query) => query.where("u.media_id", "=", mediaId), options);
111
+ }
112
+ async findCurrentUsagePageByProviderAsset(provider, providerAssetId, options = {}) {
113
+ return this.findCurrentUsagePage((query) => query.where("u.provider", "=", provider).where("u.provider_asset_id", "=", providerAssetId), options);
114
+ }
115
+ async deleteSource(sourceKey) {
116
+ return this.deleteSources([sourceKey]);
117
+ }
118
+ async deleteSourceIfCurrent(sourceKey, expectedCurrentGeneration) {
119
+ let deleted = false;
120
+ await withTransaction(this.db, async (trx) => {
121
+ const result = await trx.deleteFrom("_emdash_media_usage_sources").where("source_key", "=", sourceKey).where("current_generation", "=", expectedCurrentGeneration).executeTakeFirst();
122
+ deleted = Number(result.numDeletedRows ?? 0) > 0;
123
+ if (!deleted) return;
124
+ await this.deleteSourceGenerationOccurrences(trx, sourceKey, expectedCurrentGeneration);
125
+ });
126
+ return {
127
+ deleted,
128
+ source: await this.findSource(sourceKey)
129
+ };
130
+ }
131
+ async deleteSourceIfMatching(sourceKey, expectedSource) {
132
+ let deleted = false;
133
+ await withTransaction(this.db, async (trx) => {
134
+ const result = await trx.deleteFrom("_emdash_media_usage_sources").where("source_key", "=", sourceKey).where(this.sourceMatchExpression(expectedSource)).executeTakeFirst();
135
+ deleted = Number(result.numDeletedRows ?? 0) > 0;
136
+ if (!deleted) return;
137
+ await this.deleteSourceGenerationOccurrences(trx, sourceKey, expectedSource.currentGeneration);
138
+ });
139
+ return {
140
+ deleted,
141
+ source: await this.findSource(sourceKey)
142
+ };
143
+ }
144
+ async deleteSourceIfMatchingContentAbsent(sourceKey, expectedSource, collectionSlug, contentId) {
145
+ validateIdentifier(collectionSlug, "collection slug");
146
+ const tableName = `ec_${collectionSlug}`;
147
+ let deleted = false;
148
+ await withTransaction(this.db, async (trx) => {
149
+ const result = await trx.deleteFrom("_emdash_media_usage_sources").where("source_key", "=", sourceKey).where(this.sourceMatchExpression(expectedSource)).where(sql`NOT EXISTS (SELECT 1 FROM ${sql.ref(tableName)} WHERE id = ${contentId})`).executeTakeFirst();
150
+ deleted = Number(result.numDeletedRows ?? 0) > 0;
151
+ if (!deleted) return;
152
+ await this.deleteSourceGenerationOccurrences(trx, sourceKey, expectedSource.currentGeneration);
153
+ });
154
+ const contentPresent = deleted ? false : await this.contentRowExists(tableName, contentId);
155
+ return {
156
+ deleted,
157
+ contentPresent,
158
+ source: deleted || contentPresent ? null : await this.findSource(sourceKey)
159
+ };
160
+ }
161
+ async deleteSources(sourceKeys) {
162
+ return this.deleteSourceKeys(sourceKeys);
163
+ }
164
+ async deleteContentSources(collectionSlug, contentId) {
165
+ const sourceKeys = (await this.db.selectFrom("_emdash_media_usage_sources").select("source_key").where("source_type", "=", "content").where("collection_slug", "=", collectionSlug).where("content_id", "=", contentId).execute()).map((row) => row.source_key);
166
+ return this.deleteSourceKeys(sourceKeys);
167
+ }
168
+ async deleteCollectionSources(collectionSlug) {
169
+ let deleted = 0;
170
+ while (true) {
171
+ const sourceRows = await this.db.selectFrom("_emdash_media_usage_sources").select("source_key").where("source_type", "=", "content").where("collection_slug", "=", collectionSlug).orderBy("source_key", "asc").limit(SQL_BATCH_SIZE).execute();
172
+ if (sourceRows.length === 0) break;
173
+ deleted += await this.deleteSourceKeys(sourceRows.map((row) => row.source_key));
174
+ }
175
+ return deleted;
176
+ }
177
+ async findCollectionContentSources(collectionSlug) {
178
+ return (await this.db.selectFrom("_emdash_media_usage_sources").selectAll().where("source_type", "=", "content").where("collection_slug", "=", collectionSlug).orderBy("source_key", "asc").execute()).map((row) => rowToSource(row));
179
+ }
180
+ async deleteOrphanOccurrencesOlderThan(cutoff, limit) {
181
+ const batchLimit = Math.floor(limit);
182
+ if (batchLimit <= 0) return 0;
183
+ const rows = await this.db.selectFrom("_emdash_media_usage as u").leftJoin("_emdash_media_usage_sources as s", (join) => join.onRef("s.source_key", "=", "u.source_key")).select("u.id").where("s.source_key", "is", null).where("u.created_at", "<", cutoff).orderBy("u.created_at", "asc").orderBy("u.id", "asc").limit(batchLimit).execute();
184
+ let deleted = 0;
185
+ for (const idBatch of chunks(rows.map((row) => row.id), SQL_BATCH_SIZE)) {
186
+ const result = await this.db.deleteFrom("_emdash_media_usage").where("id", "in", idBatch).where("created_at", "<", cutoff).where(sql`NOT EXISTS (SELECT 1 FROM _emdash_media_usage_sources s WHERE s.source_key = _emdash_media_usage.source_key)`).executeTakeFirst();
187
+ deleted += Number(result.numDeletedRows ?? 0);
188
+ }
189
+ return deleted;
190
+ }
191
+ async deleteStaleGenerationsOlderThan(cutoff, limit) {
192
+ const batchLimit = Math.floor(limit);
193
+ if (batchLimit <= 0) return 0;
194
+ const ids = (await this.db.selectFrom("_emdash_media_usage as u").innerJoin("_emdash_media_usage_sources as s", (join) => join.onRef("s.source_key", "=", "u.source_key")).select("u.id").where("u.created_at", "<", cutoff).whereRef("u.generation", "!=", "s.current_generation").whereRef("u.created_at", "<", "s.indexed_at").orderBy("u.created_at", "asc").orderBy("u.id", "asc").limit(batchLimit).execute()).map((row) => row.id);
195
+ if (ids.length === 0) return 0;
196
+ let deleted = 0;
197
+ for (const idBatch of chunks(ids, SQL_BATCH_SIZE)) {
198
+ const result = await this.db.deleteFrom("_emdash_media_usage").where("id", "in", idBatch).where("created_at", "<", cutoff).where((eb) => eb.exists(eb.selectFrom("_emdash_media_usage_sources as s").select("s.source_key").whereRef("s.source_key", "=", "_emdash_media_usage.source_key").whereRef("s.current_generation", "!=", "_emdash_media_usage.generation").whereRef("_emdash_media_usage.created_at", "<", "s.indexed_at"))).executeTakeFirst();
199
+ deleted += Number(result.numDeletedRows ?? 0);
200
+ }
201
+ return deleted;
202
+ }
203
+ async deleteAbandonedGenerationsOlderThan(cutoff, limit) {
204
+ const batchLimit = Math.floor(limit);
205
+ if (batchLimit <= 0) return 0;
206
+ const rows = await this.db.selectFrom("_emdash_media_usage as u").innerJoin("_emdash_media_usage_sources as s", (join) => join.onRef("s.source_key", "=", "u.source_key")).select("u.id").where("u.created_at", "<", cutoff).whereRef("u.generation", "!=", "s.current_generation").whereRef("u.created_at", ">=", "s.indexed_at").orderBy("u.created_at", "asc").orderBy("u.id", "asc").limit(batchLimit).execute();
207
+ let deleted = 0;
208
+ for (const idBatch of chunks(rows.map((row) => row.id), SQL_BATCH_SIZE)) {
209
+ const result = await this.db.deleteFrom("_emdash_media_usage").where("id", "in", idBatch).where("created_at", "<", cutoff).where((eb) => eb.exists(eb.selectFrom("_emdash_media_usage_sources as s").select("s.source_key").whereRef("s.source_key", "=", "_emdash_media_usage.source_key").whereRef("s.current_generation", "!=", "_emdash_media_usage.generation").whereRef("_emdash_media_usage.created_at", ">=", "s.indexed_at"))).executeTakeFirst();
210
+ deleted += Number(result.numDeletedRows ?? 0);
211
+ }
212
+ return deleted;
213
+ }
214
+ async upsertIndexStatus(input) {
215
+ const now = input.updatedAt ?? (/* @__PURE__ */ new Date()).toISOString();
216
+ const row = {
217
+ adapter_id: input.adapterId,
218
+ scope_type: input.scopeType,
219
+ scope_key: input.scopeKey,
220
+ status: input.status,
221
+ schema_version: input.schemaVersion ?? 1,
222
+ started_at: input.startedAt ?? null,
223
+ completed_at: input.completedAt ?? null,
224
+ cursor: input.cursor ?? null,
225
+ indexed_source_count: input.indexedSourceCount ?? 0,
226
+ failed_source_count: input.failedSourceCount ?? 0,
227
+ last_error_code: input.lastErrorCode ?? null,
228
+ updated_at: now
229
+ };
230
+ await this.db.insertInto("_emdash_media_usage_index_status").values(row).onConflict((oc) => oc.columns([
231
+ "adapter_id",
232
+ "scope_type",
233
+ "scope_key"
234
+ ]).doUpdateSet({
235
+ status: row.status,
236
+ schema_version: row.schema_version,
237
+ started_at: row.started_at,
238
+ completed_at: row.completed_at,
239
+ cursor: row.cursor,
240
+ indexed_source_count: row.indexed_source_count,
241
+ failed_source_count: row.failed_source_count,
242
+ last_error_code: row.last_error_code,
243
+ updated_at: row.updated_at
244
+ })).execute();
245
+ const status = await this.findIndexStatus(input);
246
+ if (!status) throw new Error(`Media usage index status ${input.adapterId}:${input.scopeType}:${input.scopeKey} was not persisted`);
247
+ return status;
248
+ }
249
+ async beginIndexStatusRepair(input) {
250
+ return this.upsertIndexStatus({
251
+ adapterId: input.adapterId,
252
+ scopeType: input.scopeType,
253
+ scopeKey: input.scopeKey,
254
+ status: "running",
255
+ schemaVersion: input.schemaVersion,
256
+ startedAt: input.startedAt,
257
+ completedAt: null,
258
+ cursor: input.runToken,
259
+ indexedSourceCount: 0,
260
+ failedSourceCount: 0,
261
+ lastErrorCode: null,
262
+ updatedAt: input.updatedAt
263
+ });
264
+ }
265
+ async finalizeIndexStatusRepairIfRunning(input) {
266
+ const updates = {
267
+ status: input.status,
268
+ completed_at: input.completedAt,
269
+ cursor: null,
270
+ indexed_source_count: input.indexedSourceCount ?? 0,
271
+ failed_source_count: input.failedSourceCount ?? 0,
272
+ last_error_code: input.lastErrorCode ?? null,
273
+ updated_at: input.updatedAt ?? (/* @__PURE__ */ new Date()).toISOString()
274
+ };
275
+ if (input.schemaVersion !== void 0) updates.schema_version = input.schemaVersion;
276
+ const result = await this.db.updateTable("_emdash_media_usage_index_status").set(updates).where("adapter_id", "=", input.adapterId).where("scope_type", "=", input.scopeType).where("scope_key", "=", input.scopeKey).where("status", "=", "running").where("cursor", "=", input.runToken).executeTakeFirst();
277
+ return {
278
+ finalized: Number(result.numUpdatedRows ?? 0) > 0,
279
+ status: await this.findIndexStatus(input)
280
+ };
281
+ }
282
+ async findIndexStatus(identity) {
283
+ 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();
284
+ return row ? rowToIndexStatus(row) : null;
285
+ }
286
+ async deleteIndexStatus(identity) {
287
+ const result = await this.db.deleteFrom("_emdash_media_usage_index_status").where("adapter_id", "=", identity.adapterId).where("scope_type", "=", identity.scopeType).where("scope_key", "=", identity.scopeKey).executeTakeFirst();
288
+ return Number(result.numDeletedRows ?? 0);
289
+ }
290
+ async findCurrentUsagePage(applyFilter, options) {
291
+ const limit = Math.min(Math.max(1, options.limit ?? 50), 100);
292
+ let query = applyFilter(this.currentUsageBaseQuery()).orderBy("u.id", "asc").limit(limit + 1);
293
+ if (options.cursor) {
294
+ const { id } = decodeCursor(options.cursor);
295
+ query = query.where("u.id", ">", id);
296
+ }
297
+ const rows = await query.execute();
298
+ const items = rows.slice(0, limit).map(rowToUsageRecord);
299
+ const result = { items };
300
+ if (rows.length > limit && items.length > 0) {
301
+ const last = items.at(-1);
302
+ result.nextCursor = encodeCursor(last.occurrence.id, last.occurrence.id);
303
+ }
304
+ return result;
305
+ }
306
+ currentUsageBaseQuery() {
307
+ return this.db.selectFrom("_emdash_media_usage_sources as s").innerJoin("_emdash_media_usage as u", (join) => join.onRef("u.source_key", "=", "s.source_key").onRef("u.generation", "=", "s.current_generation")).select(currentUsageSelect);
308
+ }
309
+ async deleteSourceKeys(sourceKeys) {
310
+ const uniqueSourceKeys = [...new Set(sourceKeys)];
311
+ if (uniqueSourceKeys.length === 0) return 0;
312
+ return withTransaction(this.db, async (trx) => {
313
+ let deleted = 0;
314
+ for (const sourceKeyBatch of chunks(uniqueSourceKeys, SQL_BATCH_SIZE)) {
315
+ const result = await trx.deleteFrom("_emdash_media_usage_sources").where("source_key", "in", sourceKeyBatch).executeTakeFirst();
316
+ deleted += Number(result.numDeletedRows ?? 0);
317
+ await trx.deleteFrom("_emdash_media_usage").where("source_key", "in", sourceKeyBatch).execute();
318
+ }
319
+ return deleted;
320
+ });
321
+ }
322
+ async deleteSourceGenerationOccurrences(db, sourceKey, generation) {
323
+ await db.deleteFrom("_emdash_media_usage").where("source_key", "=", sourceKey).where("generation", "=", generation).execute();
324
+ }
325
+ async insertOccurrences(db, sourceKey, generation, occurrences, now) {
326
+ if (occurrences.length === 0) return;
327
+ const rows = occurrences.map((occurrence) => ({
328
+ id: ulid(),
329
+ source_key: sourceKey,
330
+ generation,
331
+ field_slug: occurrence.fieldSlug,
332
+ field_path: occurrence.fieldPath,
333
+ occurrence_index: occurrence.occurrenceIndex ?? 0,
334
+ reference_type: occurrence.referenceType,
335
+ media_id: occurrence.mediaId,
336
+ provider: occurrence.provider,
337
+ provider_asset_id: occurrence.providerAssetId,
338
+ media_kind: occurrence.mediaKind ?? null,
339
+ mime_type: occurrence.mimeType ?? null,
340
+ created_at: now
341
+ }));
342
+ for (const rowBatch of chunks(rows, OCCURRENCE_INSERT_BATCH_SIZE)) await db.insertInto("_emdash_media_usage").values(rowBatch).execute();
343
+ }
344
+ async upsertSource(db, source, generation, now) {
345
+ const row = this.buildSourceRow(source, generation, now);
346
+ await db.insertInto("_emdash_media_usage_sources").values(row).onConflict((oc) => oc.column("source_key").doUpdateSet(this.sourceUpdateSet(row))).execute();
347
+ }
348
+ async insertSourceIfAbsent(db, row) {
349
+ return ((await db.insertInto("_emdash_media_usage_sources").values(row).onConflict((oc) => oc.column("source_key").doNothing()).executeTakeFirst()).numInsertedOrUpdatedRows ?? 0n) > 0n;
350
+ }
351
+ async updateSourceIfGeneration(db, row, expectedCurrentGeneration) {
352
+ const result = await db.updateTable("_emdash_media_usage_sources").set(this.sourceUpdateSet(row)).where("source_key", "=", row.source_key).where("current_generation", "=", expectedCurrentGeneration).executeTakeFirst();
353
+ return Number(result.numUpdatedRows ?? 0) > 0;
354
+ }
355
+ async updateSourceIfMatching(db, row, expectedSource) {
356
+ const result = await db.updateTable("_emdash_media_usage_sources").set(this.sourceUpdateSet(row)).where("source_key", "=", row.source_key).where(this.sourceMatchExpression(expectedSource)).executeTakeFirst();
357
+ return Number(result.numUpdatedRows ?? 0) > 0;
358
+ }
359
+ async updateAttemptedSourceIfMatching(db, source, row, expectedSource) {
360
+ const result = await db.updateTable("_emdash_media_usage_sources").set(this.attemptedSourceUpdateSet(source, row)).where("source_key", "=", row.source_key).where(this.sourceMatchExpression(expectedSource)).executeTakeFirst();
361
+ return Number(result.numUpdatedRows ?? 0) > 0;
362
+ }
363
+ sourceMatchExpression(expectedSource) {
364
+ return (eb) => eb.and([
365
+ eb("current_generation", "=", expectedSource.currentGeneration),
366
+ eb("source_completeness", "=", expectedSource.sourceCompleteness),
367
+ this.nullableStringExpression(eb, "updated_at", expectedSource.updatedAt),
368
+ this.nullableStringExpression(eb, "source_fingerprint", expectedSource.sourceFingerprint),
369
+ this.nullableStringExpression(eb, "source_updated_at", expectedSource.sourceUpdatedAt),
370
+ this.nullableNumberExpression(eb, "source_version", expectedSource.sourceVersion),
371
+ this.nullableStringExpression(eb, "revision_id", expectedSource.revisionId),
372
+ this.nullableStringExpression(eb, "last_attempted_at", expectedSource.lastAttemptedAt),
373
+ this.nullableStringExpression(eb, "last_error_code", expectedSource.lastErrorCode)
374
+ ]);
375
+ }
376
+ nullableStringExpression(eb, column, value) {
377
+ return value === null ? eb(column, "is", null) : eb(column, "=", value);
378
+ }
379
+ nullableNumberExpression(eb, column, value) {
380
+ return value === null ? eb(column, "is", null) : eb(column, "=", value);
381
+ }
382
+ async contentRowExists(tableName, contentId) {
383
+ return (await sql`
384
+ SELECT id
385
+ FROM ${sql.ref(tableName)}
386
+ WHERE id = ${contentId}
387
+ LIMIT 1
388
+ `.execute(this.db)).rows.length > 0;
389
+ }
390
+ buildSourceRow(source, generation, now) {
391
+ return {
392
+ source_key: source.sourceKey,
393
+ source_type: source.sourceType,
394
+ collection_slug: source.collectionSlug ?? null,
395
+ content_id: source.contentId ?? null,
396
+ source_variant: source.sourceVariant,
397
+ locale: source.locale ?? null,
398
+ translation_group: source.translationGroup ?? null,
399
+ content_slug: source.contentSlug ?? null,
400
+ content_title: source.contentTitle ?? null,
401
+ content_status: source.contentStatus ?? null,
402
+ content_scheduled_at: source.contentScheduledAt ?? null,
403
+ content_deleted_at: source.contentDeletedAt ?? null,
404
+ revision_id: source.revisionId ?? null,
405
+ current_generation: generation,
406
+ schema_version: source.schemaVersion ?? 1,
407
+ source_updated_at: source.sourceUpdatedAt ?? null,
408
+ source_version: source.sourceVersion ?? null,
409
+ source_fingerprint: source.sourceFingerprint ?? null,
410
+ source_completeness: source.sourceCompleteness ?? "complete",
411
+ last_attempted_at: source.lastAttemptedAt ?? now,
412
+ last_error_code: null,
413
+ indexed_at: now,
414
+ updated_at: now
415
+ };
416
+ }
417
+ buildAttemptedSourceRow(source, now) {
418
+ return {
419
+ source_key: source.sourceKey,
420
+ source_type: source.sourceType,
421
+ collection_slug: source.collectionSlug ?? null,
422
+ content_id: source.contentId ?? null,
423
+ source_variant: source.sourceVariant,
424
+ locale: source.locale ?? null,
425
+ translation_group: source.translationGroup ?? null,
426
+ content_slug: source.contentSlug ?? null,
427
+ content_title: source.contentTitle ?? null,
428
+ content_status: source.contentStatus ?? null,
429
+ content_scheduled_at: source.contentScheduledAt ?? null,
430
+ content_deleted_at: source.contentDeletedAt ?? null,
431
+ revision_id: source.revisionId ?? null,
432
+ current_generation: ulid(),
433
+ schema_version: source.schemaVersion ?? 1,
434
+ source_updated_at: source.sourceUpdatedAt ?? null,
435
+ source_version: source.sourceVersion ?? null,
436
+ source_fingerprint: source.sourceFingerprint ?? null,
437
+ source_completeness: source.sourceCompleteness ?? (source.lastErrorCode ? "failed" : "unknown"),
438
+ last_attempted_at: source.lastAttemptedAt ?? now,
439
+ last_error_code: source.lastErrorCode ?? null,
440
+ indexed_at: now,
441
+ updated_at: now
442
+ };
443
+ }
444
+ attemptedSourceUpdateSet(source, row) {
445
+ const updates = {
446
+ source_type: row.source_type,
447
+ source_variant: row.source_variant,
448
+ source_completeness: row.source_completeness,
449
+ last_attempted_at: row.last_attempted_at,
450
+ last_error_code: row.last_error_code,
451
+ updated_at: row.updated_at
452
+ };
453
+ if (source.collectionSlug !== void 0) updates.collection_slug = row.collection_slug;
454
+ if (source.contentId !== void 0) updates.content_id = row.content_id;
455
+ if (source.locale !== void 0) updates.locale = row.locale;
456
+ if (source.translationGroup !== void 0) updates.translation_group = row.translation_group;
457
+ if (source.contentSlug !== void 0) updates.content_slug = row.content_slug;
458
+ if (source.contentTitle !== void 0) updates.content_title = row.content_title;
459
+ if (source.contentStatus !== void 0) updates.content_status = row.content_status;
460
+ if (source.contentScheduledAt !== void 0) updates.content_scheduled_at = row.content_scheduled_at;
461
+ if (source.contentDeletedAt !== void 0) updates.content_deleted_at = row.content_deleted_at;
462
+ if (source.revisionId !== void 0) updates.revision_id = row.revision_id;
463
+ if (source.schemaVersion !== void 0) updates.schema_version = row.schema_version;
464
+ if (source.sourceUpdatedAt !== void 0) updates.source_updated_at = row.source_updated_at;
465
+ if (source.sourceVersion !== void 0) updates.source_version = row.source_version;
466
+ if (source.sourceFingerprint !== void 0) updates.source_fingerprint = row.source_fingerprint;
467
+ return updates;
468
+ }
469
+ sourceUpdateSet(row) {
470
+ return {
471
+ source_type: row.source_type,
472
+ collection_slug: row.collection_slug,
473
+ content_id: row.content_id,
474
+ source_variant: row.source_variant,
475
+ locale: row.locale,
476
+ translation_group: row.translation_group,
477
+ content_slug: row.content_slug,
478
+ content_title: row.content_title,
479
+ content_status: row.content_status,
480
+ content_scheduled_at: row.content_scheduled_at,
481
+ content_deleted_at: row.content_deleted_at,
482
+ revision_id: row.revision_id,
483
+ current_generation: row.current_generation,
484
+ schema_version: row.schema_version,
485
+ source_updated_at: row.source_updated_at,
486
+ source_version: row.source_version,
487
+ source_fingerprint: row.source_fingerprint,
488
+ source_completeness: row.source_completeness,
489
+ last_attempted_at: row.last_attempted_at,
490
+ last_error_code: row.last_error_code,
491
+ indexed_at: row.indexed_at,
492
+ updated_at: row.updated_at
493
+ };
494
+ }
495
+ };
496
+ const currentUsageSelect = [
497
+ "s.source_key as source_key",
498
+ "s.source_type as source_type",
499
+ "s.collection_slug as collection_slug",
500
+ "s.content_id as content_id",
501
+ "s.source_variant as source_variant",
502
+ "s.locale as locale",
503
+ "s.translation_group as translation_group",
504
+ "s.content_slug as content_slug",
505
+ "s.content_title as content_title",
506
+ "s.content_status as content_status",
507
+ "s.content_scheduled_at as content_scheduled_at",
508
+ "s.content_deleted_at as content_deleted_at",
509
+ "s.revision_id as revision_id",
510
+ "s.current_generation as current_generation",
511
+ "s.schema_version as schema_version",
512
+ "s.source_updated_at as source_updated_at",
513
+ "s.source_version as source_version",
514
+ "s.source_fingerprint as source_fingerprint",
515
+ "s.source_completeness as source_completeness",
516
+ "s.last_attempted_at as last_attempted_at",
517
+ "s.last_error_code as last_error_code",
518
+ "s.indexed_at as indexed_at",
519
+ "s.created_at as source_created_at",
520
+ "s.updated_at as source_row_updated_at",
521
+ "u.id as occurrence_id",
522
+ "u.generation as generation",
523
+ "u.field_slug as field_slug",
524
+ "u.field_path as field_path",
525
+ "u.occurrence_index as occurrence_index",
526
+ "u.reference_type as reference_type",
527
+ "u.media_id as media_id",
528
+ "u.provider as provider",
529
+ "u.provider_asset_id as provider_asset_id",
530
+ "u.media_kind as media_kind",
531
+ "u.mime_type as mime_type",
532
+ "u.created_at as occurrence_created_at"
533
+ ];
534
+ function rowToSource(row) {
535
+ return {
536
+ sourceKey: row.source_key,
537
+ sourceType: row.source_type,
538
+ collectionSlug: row.collection_slug,
539
+ contentId: row.content_id,
540
+ sourceVariant: row.source_variant,
541
+ locale: row.locale,
542
+ translationGroup: row.translation_group,
543
+ contentSlug: row.content_slug,
544
+ contentTitle: row.content_title,
545
+ contentStatus: row.content_status,
546
+ contentScheduledAt: row.content_scheduled_at,
547
+ contentDeletedAt: row.content_deleted_at,
548
+ revisionId: row.revision_id,
549
+ currentGeneration: row.current_generation,
550
+ schemaVersion: Number(row.schema_version),
551
+ sourceUpdatedAt: row.source_updated_at,
552
+ sourceVersion: row.source_version === null ? null : Number(row.source_version),
553
+ sourceFingerprint: row.source_fingerprint,
554
+ sourceCompleteness: row.source_completeness,
555
+ lastAttemptedAt: row.last_attempted_at,
556
+ lastErrorCode: row.last_error_code,
557
+ indexedAt: row.indexed_at,
558
+ createdAt: row.created_at,
559
+ updatedAt: row.updated_at
560
+ };
561
+ }
562
+ function rowToOccurrence(row) {
563
+ return {
564
+ id: row.id,
565
+ sourceKey: row.source_key,
566
+ generation: row.generation,
567
+ fieldSlug: row.field_slug,
568
+ fieldPath: row.field_path,
569
+ occurrenceIndex: Number(row.occurrence_index),
570
+ referenceType: row.reference_type,
571
+ mediaId: row.media_id,
572
+ provider: row.provider,
573
+ providerAssetId: row.provider_asset_id,
574
+ mediaKind: row.media_kind,
575
+ mimeType: row.mime_type,
576
+ createdAt: row.created_at
577
+ };
578
+ }
579
+ function rowToUsageRecord(row) {
580
+ return {
581
+ source: rowToSource({
582
+ source_key: row.source_key,
583
+ source_type: row.source_type,
584
+ collection_slug: row.collection_slug,
585
+ content_id: row.content_id,
586
+ source_variant: row.source_variant,
587
+ locale: row.locale,
588
+ translation_group: row.translation_group,
589
+ content_slug: row.content_slug,
590
+ content_title: row.content_title,
591
+ content_status: row.content_status,
592
+ content_scheduled_at: row.content_scheduled_at,
593
+ content_deleted_at: row.content_deleted_at,
594
+ revision_id: row.revision_id,
595
+ current_generation: row.current_generation,
596
+ schema_version: row.schema_version,
597
+ source_updated_at: row.source_updated_at,
598
+ source_version: row.source_version,
599
+ source_fingerprint: row.source_fingerprint,
600
+ source_completeness: row.source_completeness,
601
+ last_attempted_at: row.last_attempted_at,
602
+ last_error_code: row.last_error_code,
603
+ indexed_at: row.indexed_at,
604
+ created_at: row.source_created_at,
605
+ updated_at: row.source_row_updated_at
606
+ }),
607
+ occurrence: rowToOccurrence({
608
+ id: row.occurrence_id,
609
+ source_key: row.source_key,
610
+ generation: row.generation,
611
+ field_slug: row.field_slug,
612
+ field_path: row.field_path,
613
+ occurrence_index: row.occurrence_index,
614
+ reference_type: row.reference_type,
615
+ media_id: row.media_id,
616
+ provider: row.provider,
617
+ provider_asset_id: row.provider_asset_id,
618
+ media_kind: row.media_kind,
619
+ mime_type: row.mime_type,
620
+ created_at: row.occurrence_created_at
621
+ })
622
+ };
623
+ }
624
+ function rowToIndexStatus(row) {
625
+ return {
626
+ adapterId: row.adapter_id,
627
+ scopeType: row.scope_type,
628
+ scopeKey: row.scope_key,
629
+ status: row.status,
630
+ schemaVersion: Number(row.schema_version),
631
+ startedAt: row.started_at,
632
+ completedAt: row.completed_at,
633
+ cursor: row.cursor,
634
+ indexedSourceCount: Number(row.indexed_source_count),
635
+ failedSourceCount: Number(row.failed_source_count),
636
+ lastErrorCode: row.last_error_code,
637
+ updatedAt: row.updated_at
638
+ };
639
+ }
640
+
641
+ //#endregion
642
+ //#region src/media/usage/content-fields.ts
643
+ var MediaUsageFieldDiscoveryError = class extends Error {
644
+ constructor(message, code) {
645
+ super(message);
646
+ this.code = code;
647
+ this.name = "MediaUsageFieldDiscoveryError";
648
+ }
649
+ };
650
+ const DISPLAY_FIELD_SLUGS = ["title", "name"];
651
+ const SUPPORTED_TOP_LEVEL_TYPES = [
652
+ "file",
653
+ "image",
654
+ "portableText"
655
+ ];
656
+ async function loadContentMediaUsageFields(db, collectionSlug) {
657
+ validateIdentifier(collectionSlug, "collection slug");
658
+ const rows = await db.selectFrom("_emdash_fields").innerJoin("_emdash_collections", "_emdash_collections.id", "_emdash_fields.collection_id").select([
659
+ "_emdash_fields.slug",
660
+ "_emdash_fields.type",
661
+ "_emdash_fields.validation"
662
+ ]).where("_emdash_collections.slug", "=", collectionSlug).execute();
663
+ const extractionFields = [];
664
+ const rowBySlug = /* @__PURE__ */ new Map();
665
+ for (const row of rows) {
666
+ rowBySlug.set(row.slug, row);
667
+ if (isSupportedTopLevelType(row.type)) {
668
+ validateIdentifier(row.slug, "media usage field slug");
669
+ extractionFields.push({
670
+ slug: row.slug,
671
+ type: row.type
672
+ });
673
+ continue;
674
+ }
675
+ if (row.type === "repeater") {
676
+ validateIdentifier(row.slug, "media usage field slug");
677
+ const subFields = normalizeRepeaterImageSubFields(row.validation);
678
+ if (subFields.length > 0) extractionFields.push({
679
+ slug: row.slug,
680
+ type: "repeater",
681
+ validation: { subFields }
682
+ });
683
+ }
684
+ }
685
+ extractionFields.sort((a, b) => a.slug.localeCompare(b.slug));
686
+ return {
687
+ extractionFields,
688
+ displayFieldSlugs: DISPLAY_FIELD_SLUGS.filter((slug) => {
689
+ if (!rowBySlug.has(slug)) return false;
690
+ validateIdentifier(slug, "media usage display field slug");
691
+ return true;
692
+ })
693
+ };
694
+ }
695
+ function normalizeRepeaterImageSubFields(rawValidation) {
696
+ const validation = parseValidation(rawValidation);
697
+ if (!isRecord$2(validation) || !Array.isArray(validation.subFields)) return [];
698
+ const subFields = [];
699
+ for (const subField of validation.subFields) {
700
+ if (!isRecord$2(subField) || subField.type !== "image") continue;
701
+ if (typeof subField.slug !== "string") continue;
702
+ validateIdentifier(subField.slug, "media usage repeater sub-field slug");
703
+ subFields.push({
704
+ slug: subField.slug,
705
+ type: "image"
706
+ });
707
+ }
708
+ return subFields.toSorted((a, b) => a.slug.localeCompare(b.slug));
709
+ }
710
+ function parseValidation(rawValidation) {
711
+ if (!rawValidation) return null;
712
+ try {
713
+ return JSON.parse(rawValidation);
714
+ } catch {
715
+ throw new MediaUsageFieldDiscoveryError("Repeater field validation must be valid JSON before media usage can be discovered", "INVALID_REPEATER_VALIDATION");
716
+ }
717
+ }
718
+ function isSupportedTopLevelType(value) {
719
+ return SUPPORTED_TOP_LEVEL_TYPES.includes(value);
720
+ }
721
+ function isRecord$2(value) {
722
+ return typeof value === "object" && value !== null && !Array.isArray(value);
723
+ }
724
+
725
+ //#endregion
726
+ //#region src/media/usage/extractor.ts
727
+ const URL_LIKE_RE = /^(?:[a-z][a-z0-9+.-]*:|\/\/)/i;
728
+ function extractMediaUsageOccurrences({ fields, data }) {
729
+ const occurrences = [];
730
+ const seen = /* @__PURE__ */ new Set();
731
+ for (const field of fields) {
732
+ const value = data[field.slug];
733
+ if (field.type === "image") {
734
+ addOccurrence(occurrences, seen, {
735
+ fieldSlug: field.slug,
736
+ fieldPath: field.slug,
737
+ referenceType: "image_field",
738
+ value,
739
+ fallbackKind: "image"
740
+ });
741
+ continue;
742
+ }
743
+ if (field.type === "file") {
744
+ addOccurrence(occurrences, seen, {
745
+ fieldSlug: field.slug,
746
+ fieldPath: field.slug,
747
+ referenceType: "file_field",
748
+ value,
749
+ fallbackKind: null
750
+ });
751
+ continue;
752
+ }
753
+ if (field.type === "repeater") {
754
+ extractRepeaterOccurrences(occurrences, seen, field.slug, value, field.validation?.subFields);
755
+ continue;
756
+ }
757
+ if (field.type === "portableText") extractPortableTextOccurrences(occurrences, seen, field.slug, value);
758
+ }
759
+ return occurrences;
760
+ }
761
+ function extractRepeaterOccurrences(occurrences, seen, fieldSlug, value, subFields) {
762
+ if (!Array.isArray(value) || !Array.isArray(subFields)) return;
763
+ for (const [itemIndex, item] of value.entries()) {
764
+ if (!isRecord$1(item)) continue;
765
+ for (const subField of subFields) {
766
+ if (subField.type !== "image") continue;
767
+ addOccurrence(occurrences, seen, {
768
+ fieldSlug,
769
+ fieldPath: `${fieldSlug}[${itemIndex}].${subField.slug}`,
770
+ referenceType: "image_field",
771
+ value: item[subField.slug],
772
+ fallbackKind: "image"
773
+ });
774
+ }
775
+ }
776
+ }
777
+ function extractPortableTextOccurrences(occurrences, seen, fieldSlug, value) {
778
+ if (!Array.isArray(value)) return;
779
+ for (const [blockIndex, block] of value.entries()) {
780
+ if (!isRecord$1(block) || block._type !== "image" || !isRecord$1(block.asset)) continue;
781
+ const provider = normalizeProvider(block.asset.provider);
782
+ const ref = readPortableTextAssetRef(block.asset, provider);
783
+ if (!ref) continue;
784
+ addRefOccurrence(occurrences, seen, {
785
+ fieldSlug,
786
+ fieldPath: `${fieldSlug}[${blockIndex}].asset.${ref.key}`,
787
+ referenceType: "portable_text_image",
788
+ ref: buildMediaRef({
789
+ id: ref.id,
790
+ provider,
791
+ mimeType: normalizeMimeValue(block.asset.mimeType),
792
+ fallbackKind: "image"
793
+ })
794
+ });
795
+ }
796
+ }
797
+ function addOccurrence(occurrences, seen, input) {
798
+ const ref = readMediaRef(input.value, input.fallbackKind);
799
+ if (!ref) return;
800
+ addRefOccurrence(occurrences, seen, {
801
+ fieldSlug: input.fieldSlug,
802
+ fieldPath: input.fieldPath,
803
+ referenceType: input.referenceType,
804
+ ref
805
+ });
806
+ }
807
+ function addRefOccurrence(occurrences, seen, input) {
808
+ if (!input.ref) return;
809
+ const occurrence = {
810
+ fieldSlug: input.fieldSlug,
811
+ fieldPath: input.fieldPath,
812
+ occurrenceIndex: 0,
813
+ referenceType: input.referenceType,
814
+ mediaId: input.ref.mediaId,
815
+ provider: input.ref.provider,
816
+ providerAssetId: input.ref.providerAssetId,
817
+ mediaKind: input.ref.mediaKind,
818
+ mimeType: input.ref.mimeType
819
+ };
820
+ const key = [
821
+ occurrence.fieldSlug,
822
+ occurrence.fieldPath,
823
+ occurrence.occurrenceIndex,
824
+ occurrence.referenceType,
825
+ occurrence.provider,
826
+ occurrence.providerAssetId,
827
+ occurrence.mediaId ?? ""
828
+ ].join("\0");
829
+ if (seen.has(key)) return;
830
+ seen.add(key);
831
+ occurrences.push(occurrence);
832
+ }
833
+ function readMediaRef(value, fallbackKind) {
834
+ if (typeof value === "string") {
835
+ const id = normalizeLocalMediaId(value);
836
+ return id ? buildMediaRef({
837
+ id,
838
+ provider: "local",
839
+ mimeType: null,
840
+ fallbackKind
841
+ }) : null;
842
+ }
843
+ if (!isRecord$1(value)) return null;
844
+ const provider = normalizeProvider(value.provider);
845
+ const id = provider === "local" ? normalizeLocalMediaId(value.id) : normalizeStableId(value.id);
846
+ if (!id) return null;
847
+ return buildMediaRef({
848
+ id,
849
+ provider,
850
+ mimeType: normalizeMimeValue(value.mimeType),
851
+ fallbackKind
852
+ });
853
+ }
854
+ function buildMediaRef(input) {
855
+ const provider = normalizeProvider(input.provider);
856
+ if (provider === "external") return null;
857
+ return {
858
+ mediaId: provider === "local" ? input.id : null,
859
+ provider,
860
+ providerAssetId: input.id,
861
+ mediaKind: mediaKindFromMime(input.mimeType) ?? input.fallbackKind,
862
+ mimeType: input.mimeType
863
+ };
864
+ }
865
+ function readPortableTextAssetRef(asset, provider) {
866
+ const normalizeId = provider === "local" ? normalizeLocalMediaId : normalizeStableId;
867
+ const ref = normalizeId(asset._ref);
868
+ if (ref) return {
869
+ key: "_ref",
870
+ id: ref
871
+ };
872
+ const id = normalizeId(asset.id);
873
+ if (id) return {
874
+ key: "id",
875
+ id
876
+ };
877
+ return null;
878
+ }
879
+ function normalizeProvider(value) {
880
+ return readString$1(value)?.trim() || "local";
881
+ }
882
+ function normalizeLocalMediaId(value) {
883
+ const id = normalizeStableId(value);
884
+ if (!id) return null;
885
+ return id.includes("/") ? null : id;
886
+ }
887
+ function normalizeStableId(value) {
888
+ if (typeof value !== "string") return null;
889
+ const trimmed = value.trim();
890
+ if (!trimmed) return null;
891
+ if (URL_LIKE_RE.test(trimmed)) return null;
892
+ if (trimmed.startsWith(INTERNAL_MEDIA_PREFIX)) return null;
893
+ return trimmed;
894
+ }
895
+ function normalizeMimeValue(value) {
896
+ if (typeof value !== "string") return null;
897
+ const normalized = normalizeMime(value);
898
+ return normalized.includes("/") ? normalized : null;
899
+ }
900
+ function mediaKindFromMime(mimeType) {
901
+ if (!mimeType) return null;
902
+ if (mimeType.startsWith("image/")) return "image";
903
+ if (mimeType.startsWith("video/")) return "video";
904
+ if (mimeType.startsWith("audio/")) return "audio";
905
+ if (mimeType.startsWith("font/") || mimeType.startsWith("application/font-")) return "font";
906
+ if (mimeType.startsWith("text/")) return "text";
907
+ if (isDocumentMime(mimeType)) return "document";
908
+ if (isArchiveMime(mimeType)) return "archive";
909
+ return "other";
910
+ }
911
+ function isDocumentMime(mimeType) {
912
+ return mimeType === "application/pdf" || mimeType === "application/msword" || mimeType === "application/rtf" || mimeType === "application/vnd.ms-excel" || mimeType === "application/vnd.ms-powerpoint" || mimeType.startsWith("application/vnd.openxmlformats-officedocument.");
913
+ }
914
+ function isArchiveMime(mimeType) {
915
+ return mimeType === "application/zip" || mimeType === "application/gzip" || mimeType === "application/x-tar" || mimeType === "application/x-7z-compressed" || mimeType === "application/x-rar-compressed" || mimeType === "application/vnd.rar";
916
+ }
917
+ function readString$1(value) {
918
+ return typeof value === "string" ? value : null;
919
+ }
920
+ function isRecord$1(value) {
921
+ return typeof value === "object" && value !== null && !Array.isArray(value);
922
+ }
923
+
924
+ //#endregion
925
+ //#region src/media/usage/source-key.ts
926
+ const MEDIA_USAGE_CONTENT_SOURCE_VARIANTS = ["columns", "draft_overlay"];
927
+ function buildContentMediaUsageSourceKey(input) {
928
+ return `content:${input.collectionSlug}:${input.contentId}:${input.sourceVariant}`;
929
+ }
930
+
931
+ //#endregion
932
+ //#region src/media/usage/content-snapshots.ts
933
+ const CONTENT_SOURCE_SCHEMA_VERSION = 1;
934
+ const CONTENT_SYSTEM_COLUMNS = [
935
+ "id",
936
+ "slug",
937
+ "status",
938
+ "created_at",
939
+ "updated_at",
940
+ "published_at",
941
+ "scheduled_at",
942
+ "deleted_at",
943
+ "version",
944
+ "live_revision_id",
945
+ "draft_revision_id",
946
+ "locale",
947
+ "translation_group"
948
+ ];
949
+ async function loadContentMediaUsageSnapshots(db, collectionSlug, contentId, fieldDiscovery) {
950
+ validateIdentifier(collectionSlug, "collection slug");
951
+ const discovery = fieldDiscovery ?? await loadContentMediaUsageFields(db, collectionSlug);
952
+ const row = await loadContentRow(db, collectionSlug, contentId, [...discovery.extractionFields.map((field) => field.slug), ...discovery.displayFieldSlugs]);
953
+ if (!row) return {
954
+ success: false,
955
+ error: "CONTENT_NOT_FOUND"
956
+ };
957
+ const columnsData = projectData(row, discovery.extractionFields.map((field) => field.slug));
958
+ const displayData = projectRawData(row, discovery.displayFieldSlugs);
959
+ const occurrences = extractMediaUsageOccurrences({
960
+ fields: discovery.extractionFields,
961
+ data: columnsData
962
+ });
963
+ const columnsRevisionId = readNullableString(row.live_revision_id);
964
+ const snapshots = [{
965
+ source: buildContentSource({
966
+ collectionSlug,
967
+ row,
968
+ displayData,
969
+ sourceVariant: "columns",
970
+ revisionId: columnsRevisionId,
971
+ sourceFingerprint: await buildSourceFingerprint({
972
+ collectionSlug,
973
+ sourceVariant: "columns",
974
+ revisionId: columnsRevisionId,
975
+ fields: discovery.extractionFields,
976
+ data: columnsData
977
+ })
978
+ }),
979
+ occurrences,
980
+ fields: discovery.extractionFields
981
+ }];
982
+ const draftRevisionId = readNullableString(row.draft_revision_id);
983
+ if (draftRevisionId) {
984
+ const attemptedDraftSource = buildContentSource({
985
+ collectionSlug,
986
+ row,
987
+ displayData,
988
+ sourceVariant: "draft_overlay",
989
+ revisionId: draftRevisionId
990
+ });
991
+ const revisionResult = await loadRevisionRow(db, draftRevisionId);
992
+ if (!revisionResult) return {
993
+ success: false,
994
+ error: "DRAFT_REVISION_NOT_FOUND",
995
+ source: attemptedDraftSource,
996
+ snapshots
997
+ };
998
+ if (!revisionResult.success) return {
999
+ success: false,
1000
+ error: "DRAFT_REVISION_INVALID",
1001
+ source: attemptedDraftSource,
1002
+ snapshots
1003
+ };
1004
+ const revision = revisionResult.revision;
1005
+ if (revision.collection !== collectionSlug || revision.entryId !== row.id) return {
1006
+ success: false,
1007
+ error: "DRAFT_REVISION_MISMATCH",
1008
+ source: attemptedDraftSource,
1009
+ snapshots
1010
+ };
1011
+ const revisionData = stripRevisionMetadata(revision.data);
1012
+ const draftOverlayData = {
1013
+ ...columnsData,
1014
+ ...revisionData
1015
+ };
1016
+ const draftDisplayData = {
1017
+ ...displayData,
1018
+ ...projectPresentData(revisionData, discovery.displayFieldSlugs)
1019
+ };
1020
+ const draftContentSlug = readNullableString(revision.data._slug) ?? readNullableString(row.slug);
1021
+ const draftFingerprint = await buildSourceFingerprint({
1022
+ collectionSlug,
1023
+ sourceVariant: "draft_overlay",
1024
+ revisionId: draftRevisionId,
1025
+ fields: discovery.extractionFields,
1026
+ data: draftOverlayData
1027
+ });
1028
+ snapshots.push({
1029
+ source: buildContentSource({
1030
+ collectionSlug,
1031
+ row,
1032
+ displayData: draftDisplayData,
1033
+ sourceVariant: "draft_overlay",
1034
+ revisionId: draftRevisionId,
1035
+ contentSlug: draftContentSlug,
1036
+ sourceFingerprint: draftFingerprint
1037
+ }),
1038
+ occurrences: extractMediaUsageOccurrences({
1039
+ fields: discovery.extractionFields,
1040
+ data: draftOverlayData
1041
+ }),
1042
+ fields: discovery.extractionFields
1043
+ });
1044
+ }
1045
+ return {
1046
+ success: true,
1047
+ snapshots
1048
+ };
1049
+ }
1050
+ async function loadContentRow(db, collectionSlug, contentId, fieldSlugs) {
1051
+ const tableName = getContentTableName(collectionSlug);
1052
+ const columnRefs = uniqueColumns([...CONTENT_SYSTEM_COLUMNS, ...fieldSlugs]).map((column) => sql.ref(column));
1053
+ return (await sql`
1054
+ SELECT ${sql.join(columnRefs, sql`, `)}
1055
+ FROM ${sql.ref(tableName)}
1056
+ WHERE id = ${contentId}
1057
+ LIMIT 1
1058
+ `.execute(db)).rows[0] ?? null;
1059
+ }
1060
+ async function loadRevisionRow(db, revisionId) {
1061
+ const row = await db.selectFrom("revisions").select([
1062
+ "id",
1063
+ "collection",
1064
+ "entry_id",
1065
+ "data"
1066
+ ]).where("id", "=", revisionId).executeTakeFirst();
1067
+ if (!row) return null;
1068
+ const data = parseRevisionData(row.data);
1069
+ if (!data) return { success: false };
1070
+ return {
1071
+ success: true,
1072
+ revision: {
1073
+ id: row.id,
1074
+ collection: row.collection,
1075
+ entryId: row.entry_id,
1076
+ data
1077
+ }
1078
+ };
1079
+ }
1080
+ function buildContentSource(input) {
1081
+ const { collectionSlug, row, displayData, sourceVariant, revisionId } = input;
1082
+ const contentId = readString(row.id) ?? "";
1083
+ const contentSlug = input.contentSlug ?? readNullableString(row.slug);
1084
+ const source = {
1085
+ sourceKey: buildContentMediaUsageSourceKey({
1086
+ collectionSlug,
1087
+ contentId,
1088
+ sourceVariant
1089
+ }),
1090
+ sourceType: "content",
1091
+ collectionSlug,
1092
+ contentId,
1093
+ sourceVariant,
1094
+ locale: readNullableString(row.locale),
1095
+ translationGroup: readNullableString(row.translation_group),
1096
+ contentSlug,
1097
+ contentTitle: deriveContentTitle(displayData, contentSlug, contentId),
1098
+ contentStatus: readNullableString(row.status),
1099
+ contentScheduledAt: readNullableString(row.scheduled_at),
1100
+ contentDeletedAt: readNullableString(row.deleted_at),
1101
+ revisionId,
1102
+ schemaVersion: CONTENT_SOURCE_SCHEMA_VERSION,
1103
+ sourceUpdatedAt: readNullableString(row.updated_at),
1104
+ sourceVersion: readNumber(row.version)
1105
+ };
1106
+ if (input.sourceFingerprint !== void 0) source.sourceFingerprint = input.sourceFingerprint;
1107
+ return source;
1108
+ }
1109
+ async function buildSourceFingerprint(input) {
1110
+ return hashString(canonicalJson({
1111
+ schemaVersion: CONTENT_SOURCE_SCHEMA_VERSION,
1112
+ collectionSlug: input.collectionSlug,
1113
+ sourceVariant: input.sourceVariant,
1114
+ fields: normalizeFingerprintFields(input.fields),
1115
+ values: projectFingerprintData(input.data, input.fields),
1116
+ revisionId: input.sourceVariant === "draft_overlay" ? input.revisionId : null
1117
+ }));
1118
+ }
1119
+ function normalizeFingerprintFields(fields) {
1120
+ return fields.map((field) => {
1121
+ if (field.type !== "repeater") return {
1122
+ slug: field.slug,
1123
+ type: field.type
1124
+ };
1125
+ return {
1126
+ slug: field.slug,
1127
+ type: field.type,
1128
+ subFields: (field.validation?.subFields ?? []).map((subField) => ({
1129
+ slug: subField.slug,
1130
+ type: subField.type
1131
+ })).toSorted((a, b) => a.slug.localeCompare(b.slug))
1132
+ };
1133
+ }).toSorted((a, b) => String(a.slug).localeCompare(String(b.slug)));
1134
+ }
1135
+ function projectFingerprintData(data, fields) {
1136
+ const projected = {};
1137
+ for (const field of fields) projected[field.slug] = Object.hasOwn(data, field.slug) ? data[field.slug] : null;
1138
+ return projected;
1139
+ }
1140
+ function canonicalJson(value) {
1141
+ return JSON.stringify(canonicalize(value));
1142
+ }
1143
+ function canonicalize(value) {
1144
+ if (value === void 0) return null;
1145
+ if (typeof value === "bigint") return value.toString();
1146
+ if (typeof value === "number") return Number.isFinite(value) ? value : null;
1147
+ if (Array.isArray(value)) return value.map((item) => canonicalize(item));
1148
+ if (!isRecord(value)) return value;
1149
+ const canonical = {};
1150
+ for (const key of Object.keys(value).toSorted()) canonical[key] = canonicalize(value[key]);
1151
+ return canonical;
1152
+ }
1153
+ function projectData(row, fieldSlugs) {
1154
+ const data = {};
1155
+ for (const fieldSlug of fieldSlugs) data[fieldSlug] = deserializeValue(row[fieldSlug] ?? null);
1156
+ return data;
1157
+ }
1158
+ function projectRawData(row, fieldSlugs) {
1159
+ const data = {};
1160
+ for (const fieldSlug of fieldSlugs) data[fieldSlug] = row[fieldSlug] ?? null;
1161
+ return data;
1162
+ }
1163
+ function projectPresentData(row, fieldSlugs) {
1164
+ const data = {};
1165
+ for (const fieldSlug of fieldSlugs) if (Object.hasOwn(row, fieldSlug)) data[fieldSlug] = row[fieldSlug];
1166
+ return data;
1167
+ }
1168
+ function uniqueColumns(columns) {
1169
+ const unique = [...new Set(columns)];
1170
+ for (const column of unique) validateIdentifier(column, "content media usage column");
1171
+ return unique;
1172
+ }
1173
+ function getContentTableName(collectionSlug) {
1174
+ validateIdentifier(collectionSlug, "collection slug");
1175
+ return `ec_${collectionSlug}`;
1176
+ }
1177
+ function deserializeValue(value) {
1178
+ if (typeof value === "string" && (value.startsWith("{") || value.startsWith("["))) try {
1179
+ return JSON.parse(value);
1180
+ } catch {
1181
+ return value;
1182
+ }
1183
+ return value;
1184
+ }
1185
+ function parseRevisionData(value) {
1186
+ if (typeof value === "string") try {
1187
+ const parsed = JSON.parse(value);
1188
+ return isRecord(parsed) ? parsed : null;
1189
+ } catch {
1190
+ return null;
1191
+ }
1192
+ return isRecord(value) ? value : null;
1193
+ }
1194
+ function stripRevisionMetadata(data) {
1195
+ const stripped = {};
1196
+ for (const [key, value] of Object.entries(data)) if (!key.startsWith("_")) stripped[key] = value;
1197
+ return stripped;
1198
+ }
1199
+ function deriveContentTitle(displayData, contentSlug, contentId) {
1200
+ for (const fieldSlug of ["title", "name"]) {
1201
+ const value = displayData[fieldSlug];
1202
+ if (typeof value === "string" && value.trim()) return value;
1203
+ }
1204
+ return contentSlug ?? contentId;
1205
+ }
1206
+ function readString(value) {
1207
+ return typeof value === "string" ? value : null;
1208
+ }
1209
+ function readNullableString(value) {
1210
+ return value === null || value === void 0 ? null : readString(value);
1211
+ }
1212
+ function readNumber(value) {
1213
+ if (typeof value === "number" && Number.isFinite(value)) return value;
1214
+ if (typeof value === "bigint") return Number(value);
1215
+ if (typeof value === "string" && value) {
1216
+ const parsed = Number(value);
1217
+ return Number.isFinite(parsed) ? parsed : null;
1218
+ }
1219
+ return null;
1220
+ }
1221
+ function isRecord(value) {
1222
+ return typeof value === "object" && value !== null && !Array.isArray(value);
1223
+ }
1224
+
1225
+ //#endregion
1226
+ //#region src/media/usage/content-refresh.ts
1227
+ const CONTENT_MEDIA_USAGE_ADAPTER_ID = "content-media";
1228
+ const CONTENT_MEDIA_USAGE_COLLECTION_SCOPE = "collection";
1229
+ const CONTENT_USAGE_LOCKS_KEY = Symbol.for("emdash.mediaUsage.contentLocks");
1230
+ const CONTENT_USAGE_COLLECTION_LOCKS_KEY = Symbol.for("emdash.mediaUsage.collectionLocks");
1231
+ const CONTENT_USAGE_REFRESH_MAX_ATTEMPTS = 2;
1232
+ const ZERO_RESULT = {
1233
+ success: true,
1234
+ refreshedSourceCount: 0,
1235
+ deletedSourceCount: 0,
1236
+ failedSourceCount: 0
1237
+ };
1238
+ async function refreshContentMediaUsage(db, collectionSlug, contentId) {
1239
+ validateIdentifier(collectionSlug, "collection slug");
1240
+ return withContentUsageCollectionLock(collectionSlug, () => withContentUsageLock(collectionSlug, contentId, () => refreshContentMediaUsageUnlocked(db, collectionSlug, contentId)));
1241
+ }
1242
+ async function refreshContentMediaUsageUnlocked(db, collectionSlug, contentId) {
1243
+ try {
1244
+ let conflictResult = null;
1245
+ for (let attempt = 0; attempt < CONTENT_USAGE_REFRESH_MAX_ATTEMPTS; attempt++) {
1246
+ const result = await refreshContentMediaUsageAttempt(db, collectionSlug, contentId);
1247
+ if (result.errorCode !== "CONTENT_USAGE_GENERATION_CONFLICT") return result;
1248
+ conflictResult = result;
1249
+ }
1250
+ return markGenerationConflict(db, collectionSlug, {
1251
+ refreshedSourceCount: conflictResult?.refreshedSourceCount ?? 0,
1252
+ deletedSourceCount: conflictResult?.deletedSourceCount ?? 0
1253
+ });
1254
+ } catch (error) {
1255
+ console.error(`[media-usage] Failed to refresh ${collectionSlug}/${contentId}:`, error);
1256
+ await markContentMediaUsageCollectionStaleSafely(db, collectionSlug, "CONTENT_USAGE_REFRESH_ERROR");
1257
+ return {
1258
+ success: false,
1259
+ refreshedSourceCount: 0,
1260
+ deletedSourceCount: 0,
1261
+ failedSourceCount: 0,
1262
+ errorCode: "CONTENT_USAGE_REFRESH_ERROR"
1263
+ };
1264
+ }
1265
+ }
1266
+ async function refreshContentMediaUsageAttempt(db, collectionSlug, contentId) {
1267
+ const repo = new MediaUsageRepository(db);
1268
+ const observedGenerations = await loadObservedContentSourceGenerations(db, collectionSlug, contentId);
1269
+ const snapshotsResult = await loadContentMediaUsageSnapshots(db, collectionSlug, contentId);
1270
+ if (!snapshotsResult.success) return markSnapshotFailure(db, collectionSlug, snapshotsResult);
1271
+ if (!await contentCollectionExists(db, collectionSlug)) {
1272
+ const deletedSourceCount = await repo.deleteContentSources(collectionSlug, contentId);
1273
+ return {
1274
+ ...ZERO_RESULT,
1275
+ deletedSourceCount
1276
+ };
1277
+ }
1278
+ let refreshedSourceCount = 0;
1279
+ for (const snapshot of snapshotsResult.snapshots) {
1280
+ if (!(await repo.replaceSourceIfCurrent(snapshot.source, snapshot.occurrences, observedGenerations.get(snapshot.source.sourceKey) ?? null)).replaced) return generationConflictResult({
1281
+ refreshedSourceCount,
1282
+ deletedSourceCount: 0
1283
+ });
1284
+ refreshedSourceCount++;
1285
+ }
1286
+ if (!await contentCollectionExists(db, collectionSlug)) {
1287
+ const deletedSourceCount = await repo.deleteContentSources(collectionSlug, contentId);
1288
+ return {
1289
+ ...ZERO_RESULT,
1290
+ deletedSourceCount
1291
+ };
1292
+ }
1293
+ const expectedSourceKeys = new Set(snapshotsResult.snapshots.map((snapshot) => snapshot.source.sourceKey));
1294
+ const absentSourceKeys = MEDIA_USAGE_CONTENT_SOURCE_VARIANTS.map((sourceVariant) => buildContentMediaUsageSourceKey({
1295
+ collectionSlug,
1296
+ contentId,
1297
+ sourceVariant
1298
+ })).filter((sourceKey) => !expectedSourceKeys.has(sourceKey));
1299
+ let deletedSourceCount = 0;
1300
+ for (const sourceKey of absentSourceKeys) {
1301
+ const expectedGeneration = observedGenerations.get(sourceKey) ?? null;
1302
+ if (expectedGeneration === null) continue;
1303
+ const result = await repo.deleteSourceIfCurrent(sourceKey, expectedGeneration);
1304
+ if (result.deleted) {
1305
+ deletedSourceCount++;
1306
+ continue;
1307
+ }
1308
+ if (result.source) return generationConflictResult({
1309
+ refreshedSourceCount,
1310
+ deletedSourceCount
1311
+ });
1312
+ }
1313
+ return {
1314
+ success: true,
1315
+ refreshedSourceCount,
1316
+ deletedSourceCount,
1317
+ failedSourceCount: 0
1318
+ };
1319
+ }
1320
+ async function loadObservedContentSourceGenerations(db, collectionSlug, contentId) {
1321
+ const generations = /* @__PURE__ */ new Map();
1322
+ const sourceKeys = MEDIA_USAGE_CONTENT_SOURCE_VARIANTS.map((sourceVariant) => buildContentMediaUsageSourceKey({
1323
+ collectionSlug,
1324
+ contentId,
1325
+ sourceVariant
1326
+ }));
1327
+ for (const sourceKey of sourceKeys) generations.set(sourceKey, null);
1328
+ const rows = await db.selectFrom("_emdash_media_usage_sources").select(["source_key", "current_generation"]).where("source_key", "in", sourceKeys).execute();
1329
+ for (const row of rows) generations.set(row.source_key, row.current_generation);
1330
+ return generations;
1331
+ }
1332
+ async function markGenerationConflict(db, collectionSlug, counts) {
1333
+ await markContentMediaUsageCollectionStaleSafely(db, collectionSlug, "CONTENT_USAGE_GENERATION_CONFLICT");
1334
+ return {
1335
+ success: false,
1336
+ refreshedSourceCount: counts.refreshedSourceCount,
1337
+ deletedSourceCount: counts.deletedSourceCount,
1338
+ failedSourceCount: 0,
1339
+ errorCode: "CONTENT_USAGE_GENERATION_CONFLICT"
1340
+ };
1341
+ }
1342
+ function generationConflictResult(counts) {
1343
+ return {
1344
+ success: false,
1345
+ refreshedSourceCount: counts.refreshedSourceCount,
1346
+ deletedSourceCount: counts.deletedSourceCount,
1347
+ failedSourceCount: 0,
1348
+ errorCode: "CONTENT_USAGE_GENERATION_CONFLICT"
1349
+ };
1350
+ }
1351
+ async function contentCollectionExists(db, collectionSlug) {
1352
+ return await db.selectFrom("_emdash_collections").select("id").where("slug", "=", collectionSlug).executeTakeFirst() !== void 0;
1353
+ }
1354
+ async function deleteContentMediaUsage(db, collectionSlug, contentId) {
1355
+ validateIdentifier(collectionSlug, "collection slug");
1356
+ return withContentUsageCollectionLock(collectionSlug, () => withContentUsageLock(collectionSlug, contentId, () => deleteContentMediaUsageUnlocked(db, collectionSlug, contentId)));
1357
+ }
1358
+ async function deleteContentMediaUsageUnlocked(db, collectionSlug, contentId) {
1359
+ try {
1360
+ const deletedSourceCount = await new MediaUsageRepository(db).deleteContentSources(collectionSlug, contentId);
1361
+ return {
1362
+ ...ZERO_RESULT,
1363
+ deletedSourceCount
1364
+ };
1365
+ } catch (error) {
1366
+ console.error(`[media-usage] Failed to delete usage for ${collectionSlug}/${contentId}:`, error);
1367
+ await markContentMediaUsageCollectionStaleSafely(db, collectionSlug, "CONTENT_USAGE_DELETE_ERROR");
1368
+ return {
1369
+ success: false,
1370
+ refreshedSourceCount: 0,
1371
+ deletedSourceCount: 0,
1372
+ failedSourceCount: 0,
1373
+ errorCode: "CONTENT_USAGE_DELETE_ERROR"
1374
+ };
1375
+ }
1376
+ }
1377
+ async function deleteContentMediaUsageCollection(db, collectionSlug) {
1378
+ validateIdentifier(collectionSlug, "collection slug");
1379
+ return withContentUsageCollectionLock(collectionSlug, () => deleteContentMediaUsageCollectionUnlocked(db, collectionSlug));
1380
+ }
1381
+ async function deleteContentMediaUsageCollectionUnlocked(db, collectionSlug) {
1382
+ try {
1383
+ const repo = new MediaUsageRepository(db);
1384
+ const deletedSourceCount = await repo.deleteCollectionSources(collectionSlug);
1385
+ await repo.deleteIndexStatus({
1386
+ adapterId: CONTENT_MEDIA_USAGE_ADAPTER_ID,
1387
+ scopeType: CONTENT_MEDIA_USAGE_COLLECTION_SCOPE,
1388
+ scopeKey: collectionSlug
1389
+ });
1390
+ return {
1391
+ ...ZERO_RESULT,
1392
+ deletedSourceCount
1393
+ };
1394
+ } catch (error) {
1395
+ console.error(`[media-usage] Failed to delete usage for collection ${collectionSlug}:`, error);
1396
+ try {
1397
+ await new MediaUsageRepository(db).deleteIndexStatus({
1398
+ adapterId: CONTENT_MEDIA_USAGE_ADAPTER_ID,
1399
+ scopeType: CONTENT_MEDIA_USAGE_COLLECTION_SCOPE,
1400
+ scopeKey: collectionSlug
1401
+ });
1402
+ } catch (statusError) {
1403
+ console.error(`[media-usage] Failed to clear usage status for deleted collection ${collectionSlug}:`, statusError);
1404
+ }
1405
+ return {
1406
+ success: false,
1407
+ refreshedSourceCount: 0,
1408
+ deletedSourceCount: 0,
1409
+ failedSourceCount: 0,
1410
+ errorCode: "CONTENT_USAGE_DELETE_ERROR"
1411
+ };
1412
+ }
1413
+ }
1414
+ async function refreshContentMediaUsageAfterWrite(db, collectionSlug, contentId) {
1415
+ const result = await refreshContentMediaUsage(db, collectionSlug, contentId);
1416
+ if (!result.success) console.error(`[media-usage] Usage refresh for ${collectionSlug}/${contentId} finished with ${result.errorCode}`);
1417
+ }
1418
+ async function markContentMediaUsageCollectionStale(db, collectionSlug, lastErrorCode) {
1419
+ validateIdentifier(collectionSlug, "collection slug");
1420
+ const repo = new MediaUsageRepository(db);
1421
+ const identity = {
1422
+ adapterId: CONTENT_MEDIA_USAGE_ADAPTER_ID,
1423
+ scopeType: CONTENT_MEDIA_USAGE_COLLECTION_SCOPE,
1424
+ scopeKey: collectionSlug
1425
+ };
1426
+ const existing = await repo.findIndexStatus(identity);
1427
+ await repo.upsertIndexStatus({
1428
+ ...identity,
1429
+ status: "stale",
1430
+ schemaVersion: existing?.schemaVersion ?? CONTENT_SOURCE_SCHEMA_VERSION,
1431
+ startedAt: existing?.startedAt ?? null,
1432
+ completedAt: existing?.completedAt ?? null,
1433
+ cursor: existing?.cursor ?? null,
1434
+ indexedSourceCount: existing?.indexedSourceCount ?? 0,
1435
+ failedSourceCount: existing?.failedSourceCount ?? 0,
1436
+ lastErrorCode
1437
+ });
1438
+ }
1439
+ async function findNonTranslatableSiblingContentIds(db, collectionSlug, updatedContentId, translationGroup, updatedData) {
1440
+ if (!isI18nEnabled() || !updatedData || !translationGroup) return [];
1441
+ validateIdentifier(collectionSlug, "collection slug");
1442
+ const collection = await db.selectFrom("_emdash_collections").select("id").where("slug", "=", collectionSlug).executeTakeFirst();
1443
+ if (!collection) return [];
1444
+ const touchedNonTranslatableSlugs = (await db.selectFrom("_emdash_fields").select("slug").where("collection_id", "=", collection.id).where("translatable", "=", 0).execute()).filter((field) => field.slug in updatedData).map((field) => field.slug);
1445
+ if (touchedNonTranslatableSlugs.length === 0) return [];
1446
+ const usageFields = await loadContentMediaUsageFields(db, collectionSlug);
1447
+ const usageRelevantSlugs = new Set([...usageFields.extractionFields.map((field) => field.slug), ...usageFields.displayFieldSlugs]);
1448
+ if (!touchedNonTranslatableSlugs.some((slug) => usageRelevantSlugs.has(slug))) return [];
1449
+ const tableName = `ec_${collectionSlug}`;
1450
+ return (await sql`
1451
+ SELECT id
1452
+ FROM ${sql.ref(tableName)}
1453
+ WHERE translation_group = ${translationGroup}
1454
+ AND id != ${updatedContentId}
1455
+ ORDER BY id ASC
1456
+ `.execute(db)).rows.map((row) => row.id);
1457
+ }
1458
+ async function markSnapshotFailure(db, collectionSlug, result) {
1459
+ const repo = new MediaUsageRepository(db);
1460
+ if (result.source) await repo.markSourceAttempted({
1461
+ ...result.source,
1462
+ sourceCompleteness: "failed",
1463
+ lastErrorCode: result.error
1464
+ });
1465
+ await markContentMediaUsageCollectionStale(db, collectionSlug, result.error);
1466
+ return {
1467
+ success: false,
1468
+ refreshedSourceCount: 0,
1469
+ deletedSourceCount: 0,
1470
+ failedSourceCount: result.source ? 1 : 0,
1471
+ errorCode: result.error
1472
+ };
1473
+ }
1474
+ async function markContentMediaUsageCollectionStaleSafely(db, collectionSlug, lastErrorCode) {
1475
+ try {
1476
+ await markContentMediaUsageCollectionStale(db, collectionSlug, lastErrorCode);
1477
+ return true;
1478
+ } catch (error) {
1479
+ console.error(`[media-usage] Failed to mark ${collectionSlug} stale:`, error);
1480
+ return false;
1481
+ }
1482
+ }
1483
+ async function withContentUsageLock(collectionSlug, contentId, fn) {
1484
+ const locks = getContentUsageLocks();
1485
+ const lockKey = `${collectionSlug}\0${contentId}`;
1486
+ const previous = locks.get(lockKey) ?? Promise.resolve();
1487
+ let releaseCurrent;
1488
+ const current = new Promise((resolve) => {
1489
+ releaseCurrent = resolve;
1490
+ });
1491
+ const next = previous.catch(() => {}).then(() => current);
1492
+ locks.set(lockKey, next);
1493
+ try {
1494
+ await previous.catch(() => {});
1495
+ return await fn();
1496
+ } finally {
1497
+ releaseCurrent();
1498
+ if (locks.get(lockKey) === next) locks.delete(lockKey);
1499
+ }
1500
+ }
1501
+ async function withContentUsageCollectionLock(collectionSlug, fn) {
1502
+ const locks = getContentUsageCollectionLocks();
1503
+ const previous = locks.get(collectionSlug) ?? Promise.resolve();
1504
+ let releaseCurrent;
1505
+ const current = new Promise((resolve) => {
1506
+ releaseCurrent = resolve;
1507
+ });
1508
+ const next = previous.catch(() => {}).then(() => current);
1509
+ locks.set(collectionSlug, next);
1510
+ try {
1511
+ await previous.catch(() => {});
1512
+ return await fn();
1513
+ } finally {
1514
+ releaseCurrent();
1515
+ if (locks.get(collectionSlug) === next) locks.delete(collectionSlug);
1516
+ }
1517
+ }
1518
+ function getContentUsageLocks() {
1519
+ const global = globalThis;
1520
+ const existing = global[CONTENT_USAGE_LOCKS_KEY];
1521
+ if (existing instanceof Map) return existing;
1522
+ const locks = /* @__PURE__ */ new Map();
1523
+ global[CONTENT_USAGE_LOCKS_KEY] = locks;
1524
+ return locks;
1525
+ }
1526
+ function getContentUsageCollectionLocks() {
1527
+ const global = globalThis;
1528
+ const existing = global[CONTENT_USAGE_COLLECTION_LOCKS_KEY];
1529
+ if (existing instanceof Map) return existing;
1530
+ const locks = /* @__PURE__ */ new Map();
1531
+ global[CONTENT_USAGE_COLLECTION_LOCKS_KEY] = locks;
1532
+ return locks;
1533
+ }
1534
+
1535
+ //#endregion
1536
+ export { markContentMediaUsageCollectionStaleSafely as a, markContentMediaUsageCollectionStale as i, deleteContentMediaUsageCollection as n, refreshContentMediaUsageAfterWrite as o, findNonTranslatableSiblingContentIds as r, deleteContentMediaUsage as t };
1537
+ //# sourceMappingURL=content-refresh-Br4gMzh8.mjs.map