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
@@ -1,14 +1,37 @@
1
- import type { Kysely, Selectable, Transaction } from "kysely";
1
+ import {
2
+ sql,
3
+ type ExpressionBuilder,
4
+ type Insertable,
5
+ type Kysely,
6
+ type Selectable,
7
+ type Transaction,
8
+ type Updateable,
9
+ } from "kysely";
2
10
  import { ulid } from "ulidx";
3
11
 
12
+ import type { MediaUsageContentSourceVariant } from "../../media/usage/source-key.js";
4
13
  import type { MediaKind, MediaUsageReferenceType } from "../../media/usage/types.js";
5
14
  import { chunks, SQL_BATCH_SIZE } from "../../utils/chunks.js";
6
15
  import { withTransaction } from "../transaction.js";
7
- import type { Database, MediaUsageSourceTable, MediaUsageTable } from "../types.js";
16
+ import type {
17
+ Database,
18
+ MediaUsageIndexStatusTable,
19
+ MediaUsageSourceTable,
20
+ MediaUsageTable,
21
+ } from "../types.js";
22
+ import { validateIdentifier } from "../validate.js";
23
+ import { decodeCursor, encodeCursor, type FindManyResult } from "./types.js";
8
24
 
9
25
  type DatabaseExecutor = Kysely<Database> | Transaction<Database>;
26
+ type MediaUsageSourceNullableStringColumn =
27
+ | "source_fingerprint"
28
+ | "source_updated_at"
29
+ | "revision_id"
30
+ | "updated_at"
31
+ | "last_attempted_at"
32
+ | "last_error_code";
10
33
 
11
- const OCCURRENCE_BIND_COLUMNS = 12;
34
+ const OCCURRENCE_BIND_COLUMNS = 13;
12
35
  const OCCURRENCE_INSERT_BATCH_SIZE = Math.max(
13
36
  1,
14
37
  Math.floor(SQL_BATCH_SIZE / OCCURRENCE_BIND_COLUMNS),
@@ -19,7 +42,7 @@ export interface MediaUsageSourceInput {
19
42
  sourceType: string;
20
43
  collectionSlug?: string | null;
21
44
  contentId?: string | null;
22
- sourceVariant: string;
45
+ sourceVariant: MediaUsageContentSourceVariant;
23
46
  locale?: string | null;
24
47
  translationGroup?: string | null;
25
48
  contentSlug?: string | null;
@@ -29,6 +52,12 @@ export interface MediaUsageSourceInput {
29
52
  contentDeletedAt?: string | null;
30
53
  revisionId?: string | null;
31
54
  schemaVersion?: number;
55
+ sourceUpdatedAt?: string | null;
56
+ sourceVersion?: number | null;
57
+ sourceFingerprint?: string | null;
58
+ sourceCompleteness?: MediaUsageSourceCompleteness;
59
+ lastAttemptedAt?: string | null;
60
+ lastErrorCode?: string | null;
32
61
  }
33
62
 
34
63
  export interface MediaUsageOccurrenceInput {
@@ -59,11 +88,138 @@ export interface MediaUsageSource {
59
88
  revisionId: string | null;
60
89
  currentGeneration: string;
61
90
  schemaVersion: number;
91
+ sourceUpdatedAt: string | null;
92
+ sourceVersion: number | null;
93
+ sourceFingerprint: string | null;
94
+ sourceCompleteness: string;
95
+ lastAttemptedAt: string | null;
96
+ lastErrorCode: string | null;
62
97
  indexedAt: string;
63
98
  createdAt: string;
64
99
  updatedAt: string;
65
100
  }
66
101
 
102
+ export interface MediaUsageGuardedReplaceResult {
103
+ replaced: boolean;
104
+ /** Populated only when a guarded replacement did not win the current source row. */
105
+ source: MediaUsageSource | null;
106
+ }
107
+
108
+ export interface MediaUsageGuardedDeleteResult {
109
+ deleted: boolean;
110
+ source: MediaUsageSource | null;
111
+ }
112
+
113
+ export interface MediaUsageGuardedAbsentDeleteResult extends MediaUsageGuardedDeleteResult {
114
+ contentPresent: boolean;
115
+ }
116
+
117
+ export interface MediaUsageGuardedAttemptResult {
118
+ attempted: boolean;
119
+ /** Populated only when a guarded attempted mark did not win the current source row. */
120
+ source: MediaUsageSource | null;
121
+ }
122
+
123
+ export interface MediaUsageIndexStatusRepairInput extends MediaUsageIndexStatusIdentity {
124
+ runToken: string;
125
+ schemaVersion?: number;
126
+ startedAt: string;
127
+ updatedAt?: string;
128
+ }
129
+
130
+ export interface MediaUsageIndexStatusFinalizeInput extends MediaUsageIndexStatusIdentity {
131
+ runToken: string;
132
+ status: Exclude<MediaUsageIndexStatusValue, "never" | "running" | "stale">;
133
+ schemaVersion?: number;
134
+ completedAt: string;
135
+ indexedSourceCount?: number;
136
+ failedSourceCount?: number;
137
+ lastErrorCode?: string | null;
138
+ updatedAt?: string;
139
+ }
140
+
141
+ export interface MediaUsageGuardedIndexStatusResult {
142
+ finalized: boolean;
143
+ status: MediaUsageIndexStatus | null;
144
+ }
145
+
146
+ export type MediaUsageSourceCompleteness =
147
+ | "unknown"
148
+ | "complete"
149
+ | "partial"
150
+ | "failed"
151
+ | "unsupported";
152
+
153
+ export type MediaUsageIndexStatusValue =
154
+ | "never"
155
+ | "running"
156
+ | "complete"
157
+ | "partial"
158
+ | "failed"
159
+ | "stale";
160
+
161
+ export interface MediaUsageIndexStatusIdentity {
162
+ adapterId: string;
163
+ scopeType: string;
164
+ scopeKey: string;
165
+ }
166
+
167
+ export interface MediaUsageIndexStatusInput extends MediaUsageIndexStatusIdentity {
168
+ status: MediaUsageIndexStatusValue;
169
+ schemaVersion?: number;
170
+ startedAt?: string | null;
171
+ completedAt?: string | null;
172
+ cursor?: string | null;
173
+ indexedSourceCount?: number;
174
+ failedSourceCount?: number;
175
+ lastErrorCode?: string | null;
176
+ updatedAt?: string;
177
+ }
178
+
179
+ export interface MediaUsageIndexStatus extends MediaUsageIndexStatusIdentity {
180
+ status: string;
181
+ schemaVersion: number;
182
+ startedAt: string | null;
183
+ completedAt: string | null;
184
+ cursor: string | null;
185
+ indexedSourceCount: number;
186
+ failedSourceCount: number;
187
+ lastErrorCode: string | null;
188
+ updatedAt: string;
189
+ }
190
+
191
+ export interface FindMediaUsageOptions {
192
+ limit?: number;
193
+ cursor?: string;
194
+ }
195
+
196
+ interface MediaUsageSourceRow {
197
+ source_key: string;
198
+ source_type: string;
199
+ collection_slug: string | null;
200
+ content_id: string | null;
201
+ source_variant: string;
202
+ locale: string | null;
203
+ translation_group: string | null;
204
+ content_slug: string | null;
205
+ content_title: string | null;
206
+ content_status: string | null;
207
+ content_scheduled_at: string | null;
208
+ content_deleted_at: string | null;
209
+ revision_id: string | null;
210
+ current_generation: string;
211
+ schema_version: number;
212
+ source_updated_at: string | null;
213
+ source_version: number | null;
214
+ source_fingerprint: string | null;
215
+ source_completeness: string;
216
+ last_attempted_at: string | null;
217
+ last_error_code: string | null;
218
+ indexed_at: string;
219
+ created_at: string;
220
+ updated_at: string;
221
+ }
222
+
67
223
  export interface MediaUsageOccurrence {
68
224
  id: string;
69
225
  sourceKey: string;
@@ -101,9 +257,15 @@ interface JoinedUsageRow {
101
257
  revision_id: string | null;
102
258
  current_generation: string;
103
259
  schema_version: number;
260
+ source_updated_at: string | null;
261
+ source_version: number | null;
262
+ source_fingerprint: string | null;
263
+ source_completeness: string;
264
+ last_attempted_at: string | null;
265
+ last_error_code: string | null;
104
266
  indexed_at: string;
105
267
  source_created_at: string;
106
- source_updated_at: string;
268
+ source_row_updated_at: string;
107
269
  occurrence_id: string;
108
270
  generation: string;
109
271
  field_slug: string;
@@ -130,14 +292,8 @@ export class MediaUsageRepository {
130
292
  const now = new Date().toISOString();
131
293
 
132
294
  await withTransaction(this.db, async (trx) => {
133
- await this.insertOccurrences(trx, source.sourceKey, generation, occurrences);
295
+ await this.insertOccurrences(trx, source.sourceKey, generation, occurrences, now);
134
296
  await this.upsertSource(trx, source, generation, now);
135
-
136
- try {
137
- await this.deleteStaleGenerations(trx, source.sourceKey, generation);
138
- } catch (error) {
139
- console.error("[media-usage] failed to delete stale generations:", error);
140
- }
141
297
  });
142
298
 
143
299
  const replaced = await this.findSource(source.sourceKey);
@@ -146,6 +302,30 @@ export class MediaUsageRepository {
146
302
  }
147
303
  return replaced;
148
304
  }
305
+ async replaceSourceIfCurrent(
306
+ source: MediaUsageSourceInput,
307
+ occurrences: readonly MediaUsageOccurrenceInput[],
308
+ expectedCurrentGeneration: string | null,
309
+ ): Promise<MediaUsageGuardedReplaceResult> {
310
+ const generation = ulid();
311
+ const now = new Date().toISOString();
312
+ const row = this.buildSourceRow(source, generation, now);
313
+ let replaced = false;
314
+
315
+ await withTransaction(this.db, async (trx) => {
316
+ await this.insertOccurrences(trx, source.sourceKey, generation, occurrences, now);
317
+ if (expectedCurrentGeneration === null) {
318
+ replaced = await this.insertSourceIfAbsent(trx, row);
319
+ return;
320
+ }
321
+ replaced = await this.updateSourceIfGeneration(trx, row, expectedCurrentGeneration);
322
+ });
323
+
324
+ return {
325
+ replaced,
326
+ source: replaced ? null : await this.findSource(source.sourceKey),
327
+ };
328
+ }
149
329
 
150
330
  async findSource(sourceKey: string): Promise<MediaUsageSource | null> {
151
331
  const row = await this.db
@@ -157,6 +337,89 @@ export class MediaUsageRepository {
157
337
  return row ? rowToSource(row) : null;
158
338
  }
159
339
 
340
+ async findSources(sourceKeys: readonly string[]): Promise<Map<string, MediaUsageSource>> {
341
+ const uniqueSourceKeys = [...new Set(sourceKeys)];
342
+ const sources = new Map<string, MediaUsageSource>();
343
+ if (uniqueSourceKeys.length === 0) return sources;
344
+
345
+ for (const sourceKeyBatch of chunks(uniqueSourceKeys, SQL_BATCH_SIZE)) {
346
+ const rows = await this.db
347
+ .selectFrom("_emdash_media_usage_sources")
348
+ .selectAll()
349
+ .where("source_key", "in", sourceKeyBatch)
350
+ .execute();
351
+ for (const row of rows) {
352
+ const source = rowToSource(row);
353
+ sources.set(source.sourceKey, source);
354
+ }
355
+ }
356
+
357
+ return sources;
358
+ }
359
+
360
+ async replaceSourceIfMatching(
361
+ source: MediaUsageSourceInput,
362
+ occurrences: readonly MediaUsageOccurrenceInput[],
363
+ expectedSource: MediaUsageSource | null,
364
+ ): Promise<MediaUsageGuardedReplaceResult> {
365
+ const generation = ulid();
366
+ const now = new Date().toISOString();
367
+ const row = this.buildSourceRow(source, generation, now);
368
+ let replaced = false;
369
+
370
+ await withTransaction(this.db, async (trx) => {
371
+ await this.insertOccurrences(trx, source.sourceKey, generation, occurrences, now);
372
+ if (expectedSource === null) {
373
+ replaced = await this.insertSourceIfAbsent(trx, row);
374
+ return;
375
+ }
376
+ replaced = await this.updateSourceIfMatching(trx, row, expectedSource);
377
+ });
378
+
379
+ return {
380
+ replaced,
381
+ source: replaced ? null : await this.findSource(source.sourceKey),
382
+ };
383
+ }
384
+
385
+ async markSourceAttempted(source: MediaUsageSourceInput): Promise<MediaUsageSource> {
386
+ const now = new Date().toISOString();
387
+ const row = this.buildAttemptedSourceRow(source, now);
388
+ const updates = this.attemptedSourceUpdateSet(source, row);
389
+
390
+ await this.db
391
+ .insertInto("_emdash_media_usage_sources")
392
+ .values(row)
393
+ .onConflict((oc) => oc.column("source_key").doUpdateSet(updates))
394
+ .execute();
395
+
396
+ const attempted = await this.findSource(source.sourceKey);
397
+ if (!attempted) {
398
+ throw new Error(`Media usage source ${source.sourceKey} was not persisted`);
399
+ }
400
+ return attempted;
401
+ }
402
+
403
+ async markSourceAttemptedIfMatching(
404
+ source: MediaUsageSourceInput,
405
+ expectedSource: MediaUsageSource | null,
406
+ ): Promise<MediaUsageGuardedAttemptResult> {
407
+ const now = new Date().toISOString();
408
+ const row = this.buildAttemptedSourceRow(source, now);
409
+ let attempted = false;
410
+
411
+ if (expectedSource === null) {
412
+ attempted = await this.insertSourceIfAbsent(this.db, row);
413
+ } else {
414
+ attempted = await this.updateAttemptedSourceIfMatching(this.db, source, row, expectedSource);
415
+ }
416
+
417
+ return {
418
+ attempted,
419
+ source: attempted ? null : await this.findSource(source.sourceKey),
420
+ };
421
+ }
422
+
160
423
  async findCurrentUsageByMediaId(mediaId: string): Promise<MediaUsageRecord[]> {
161
424
  const rows = await this.db
162
425
  .selectFrom("_emdash_media_usage_sources as s")
@@ -197,15 +460,114 @@ export class MediaUsageRepository {
197
460
  return rows.map(rowToUsageRecord);
198
461
  }
199
462
 
463
+ async findCurrentUsagePageByMediaId(
464
+ mediaId: string,
465
+ options: FindMediaUsageOptions = {},
466
+ ): Promise<FindManyResult<MediaUsageRecord>> {
467
+ return this.findCurrentUsagePage((query) => query.where("u.media_id", "=", mediaId), options);
468
+ }
469
+
470
+ async findCurrentUsagePageByProviderAsset(
471
+ provider: string,
472
+ providerAssetId: string,
473
+ options: FindMediaUsageOptions = {},
474
+ ): Promise<FindManyResult<MediaUsageRecord>> {
475
+ return this.findCurrentUsagePage(
476
+ (query) =>
477
+ query.where("u.provider", "=", provider).where("u.provider_asset_id", "=", providerAssetId),
478
+ options,
479
+ );
480
+ }
481
+
200
482
  async deleteSource(sourceKey: string): Promise<number> {
201
- return withTransaction(this.db, async (trx) => {
202
- await trx.deleteFrom("_emdash_media_usage").where("source_key", "=", sourceKey).execute();
483
+ return this.deleteSources([sourceKey]);
484
+ }
485
+
486
+ async deleteSourceIfCurrent(
487
+ sourceKey: string,
488
+ expectedCurrentGeneration: string,
489
+ ): Promise<MediaUsageGuardedDeleteResult> {
490
+ let deleted = false;
491
+ await withTransaction(this.db, async (trx) => {
492
+ const result = await trx
493
+ .deleteFrom("_emdash_media_usage_sources")
494
+ .where("source_key", "=", sourceKey)
495
+ .where("current_generation", "=", expectedCurrentGeneration)
496
+ .executeTakeFirst();
497
+ deleted = Number(result.numDeletedRows ?? 0) > 0;
498
+ if (!deleted) return;
499
+ await this.deleteSourceGenerationOccurrences(trx, sourceKey, expectedCurrentGeneration);
500
+ });
501
+
502
+ return {
503
+ deleted,
504
+ source: await this.findSource(sourceKey),
505
+ };
506
+ }
507
+
508
+ async deleteSourceIfMatching(
509
+ sourceKey: string,
510
+ expectedSource: MediaUsageSource,
511
+ ): Promise<MediaUsageGuardedDeleteResult> {
512
+ let deleted = false;
513
+ await withTransaction(this.db, async (trx) => {
203
514
  const result = await trx
204
515
  .deleteFrom("_emdash_media_usage_sources")
205
516
  .where("source_key", "=", sourceKey)
517
+ .where(this.sourceMatchExpression(expectedSource))
206
518
  .executeTakeFirst();
207
- return Number(result.numDeletedRows ?? 0);
519
+ deleted = Number(result.numDeletedRows ?? 0) > 0;
520
+ if (!deleted) return;
521
+ await this.deleteSourceGenerationOccurrences(
522
+ trx,
523
+ sourceKey,
524
+ expectedSource.currentGeneration,
525
+ );
208
526
  });
527
+
528
+ return {
529
+ deleted,
530
+ source: await this.findSource(sourceKey),
531
+ };
532
+ }
533
+
534
+ async deleteSourceIfMatchingContentAbsent(
535
+ sourceKey: string,
536
+ expectedSource: MediaUsageSource,
537
+ collectionSlug: string,
538
+ contentId: string,
539
+ ): Promise<MediaUsageGuardedAbsentDeleteResult> {
540
+ validateIdentifier(collectionSlug, "collection slug");
541
+ const tableName = `ec_${collectionSlug}`;
542
+ let deleted = false;
543
+ await withTransaction(this.db, async (trx) => {
544
+ const result = await trx
545
+ .deleteFrom("_emdash_media_usage_sources")
546
+ .where("source_key", "=", sourceKey)
547
+ .where(this.sourceMatchExpression(expectedSource))
548
+ .where(
549
+ sql<boolean>`NOT EXISTS (SELECT 1 FROM ${sql.ref(tableName)} WHERE id = ${contentId})`,
550
+ )
551
+ .executeTakeFirst();
552
+ deleted = Number(result.numDeletedRows ?? 0) > 0;
553
+ if (!deleted) return;
554
+ await this.deleteSourceGenerationOccurrences(
555
+ trx,
556
+ sourceKey,
557
+ expectedSource.currentGeneration,
558
+ );
559
+ });
560
+ const contentPresent = deleted ? false : await this.contentRowExists(tableName, contentId);
561
+
562
+ return {
563
+ deleted,
564
+ contentPresent,
565
+ source: deleted || contentPresent ? null : await this.findSource(sourceKey),
566
+ };
567
+ }
568
+
569
+ async deleteSources(sourceKeys: readonly string[]): Promise<number> {
570
+ return this.deleteSourceKeys(sourceKeys);
209
571
  }
210
572
 
211
573
  async deleteContentSources(collectionSlug: string, contentId: string): Promise<number> {
@@ -217,30 +579,358 @@ export class MediaUsageRepository {
217
579
  .where("content_id", "=", contentId)
218
580
  .execute();
219
581
  const sourceKeys = sourceRows.map((row) => row.source_key);
220
- if (sourceKeys.length === 0) return 0;
582
+ return this.deleteSourceKeys(sourceKeys);
583
+ }
584
+
585
+ async deleteCollectionSources(collectionSlug: string): Promise<number> {
586
+ let deleted = 0;
587
+ while (true) {
588
+ const sourceRows = await this.db
589
+ .selectFrom("_emdash_media_usage_sources")
590
+ .select("source_key")
591
+ .where("source_type", "=", "content")
592
+ .where("collection_slug", "=", collectionSlug)
593
+ .orderBy("source_key", "asc")
594
+ .limit(SQL_BATCH_SIZE)
595
+ .execute();
596
+ if (sourceRows.length === 0) break;
597
+
598
+ deleted += await this.deleteSourceKeys(sourceRows.map((row) => row.source_key));
599
+ }
600
+ return deleted;
601
+ }
602
+
603
+ async findCollectionContentSources(collectionSlug: string): Promise<MediaUsageSource[]> {
604
+ const rows = await this.db
605
+ .selectFrom("_emdash_media_usage_sources")
606
+ .selectAll()
607
+ .where("source_type", "=", "content")
608
+ .where("collection_slug", "=", collectionSlug)
609
+ .orderBy("source_key", "asc")
610
+ .execute();
611
+ return rows.map((row) => rowToSource(row));
612
+ }
613
+
614
+ async deleteOrphanOccurrencesOlderThan(cutoff: string, limit: number): Promise<number> {
615
+ const batchLimit = Math.floor(limit);
616
+ if (batchLimit <= 0) return 0;
617
+
618
+ const rows = await this.db
619
+ .selectFrom("_emdash_media_usage as u")
620
+ .leftJoin("_emdash_media_usage_sources as s", (join) =>
621
+ join.onRef("s.source_key", "=", "u.source_key"),
622
+ )
623
+ .select("u.id")
624
+ .where("s.source_key", "is", null)
625
+ .where("u.created_at", "<", cutoff)
626
+ .orderBy("u.created_at", "asc")
627
+ .orderBy("u.id", "asc")
628
+ .limit(batchLimit)
629
+ .execute();
630
+
631
+ let deleted = 0;
632
+ for (const idBatch of chunks(
633
+ rows.map((row) => row.id),
634
+ SQL_BATCH_SIZE,
635
+ )) {
636
+ const result = await this.db
637
+ .deleteFrom("_emdash_media_usage")
638
+ .where("id", "in", idBatch)
639
+ .where("created_at", "<", cutoff)
640
+ .where(
641
+ sql<boolean>`NOT EXISTS (SELECT 1 FROM _emdash_media_usage_sources s WHERE s.source_key = _emdash_media_usage.source_key)`,
642
+ )
643
+ .executeTakeFirst();
644
+ deleted += Number(result.numDeletedRows ?? 0);
645
+ }
646
+ return deleted;
647
+ }
648
+
649
+ async deleteStaleGenerationsOlderThan(cutoff: string, limit: number): Promise<number> {
650
+ const batchLimit = Math.floor(limit);
651
+ if (batchLimit <= 0) return 0;
652
+
653
+ const rows = await this.db
654
+ .selectFrom("_emdash_media_usage as u")
655
+ .innerJoin("_emdash_media_usage_sources as s", (join) =>
656
+ join.onRef("s.source_key", "=", "u.source_key"),
657
+ )
658
+ .select("u.id")
659
+ .where("u.created_at", "<", cutoff)
660
+ .whereRef("u.generation", "!=", "s.current_generation")
661
+ .whereRef("u.created_at", "<", "s.indexed_at")
662
+ .orderBy("u.created_at", "asc")
663
+ .orderBy("u.id", "asc")
664
+ .limit(batchLimit)
665
+ .execute();
666
+
667
+ const ids = rows.map((row) => row.id);
668
+ if (ids.length === 0) return 0;
669
+
670
+ let deleted = 0;
671
+ for (const idBatch of chunks(ids, SQL_BATCH_SIZE)) {
672
+ const result = await this.db
673
+ .deleteFrom("_emdash_media_usage")
674
+ .where("id", "in", idBatch)
675
+ .where("created_at", "<", cutoff)
676
+ .where((eb) =>
677
+ eb.exists(
678
+ eb
679
+ .selectFrom("_emdash_media_usage_sources as s")
680
+ .select("s.source_key")
681
+ .whereRef("s.source_key", "=", "_emdash_media_usage.source_key")
682
+ .whereRef("s.current_generation", "!=", "_emdash_media_usage.generation")
683
+ .whereRef("_emdash_media_usage.created_at", "<", "s.indexed_at"),
684
+ ),
685
+ )
686
+ .executeTakeFirst();
687
+ deleted += Number(result.numDeletedRows ?? 0);
688
+ }
689
+ return deleted;
690
+ }
691
+
692
+ async deleteAbandonedGenerationsOlderThan(cutoff: string, limit: number): Promise<number> {
693
+ const batchLimit = Math.floor(limit);
694
+ if (batchLimit <= 0) return 0;
695
+
696
+ const rows = await this.db
697
+ .selectFrom("_emdash_media_usage as u")
698
+ .innerJoin("_emdash_media_usage_sources as s", (join) =>
699
+ join.onRef("s.source_key", "=", "u.source_key"),
700
+ )
701
+ .select("u.id")
702
+ .where("u.created_at", "<", cutoff)
703
+ .whereRef("u.generation", "!=", "s.current_generation")
704
+ .whereRef("u.created_at", ">=", "s.indexed_at")
705
+ .orderBy("u.created_at", "asc")
706
+ .orderBy("u.id", "asc")
707
+ .limit(batchLimit)
708
+ .execute();
709
+
710
+ let deleted = 0;
711
+ for (const idBatch of chunks(
712
+ rows.map((row) => row.id),
713
+ SQL_BATCH_SIZE,
714
+ )) {
715
+ const result = await this.db
716
+ .deleteFrom("_emdash_media_usage")
717
+ .where("id", "in", idBatch)
718
+ .where("created_at", "<", cutoff)
719
+ .where((eb) =>
720
+ eb.exists(
721
+ eb
722
+ .selectFrom("_emdash_media_usage_sources as s")
723
+ .select("s.source_key")
724
+ .whereRef("s.source_key", "=", "_emdash_media_usage.source_key")
725
+ .whereRef("s.current_generation", "!=", "_emdash_media_usage.generation")
726
+ .whereRef("_emdash_media_usage.created_at", ">=", "s.indexed_at"),
727
+ ),
728
+ )
729
+ .executeTakeFirst();
730
+ deleted += Number(result.numDeletedRows ?? 0);
731
+ }
732
+ return deleted;
733
+ }
734
+
735
+ async upsertIndexStatus(input: MediaUsageIndexStatusInput): Promise<MediaUsageIndexStatus> {
736
+ const now = input.updatedAt ?? new Date().toISOString();
737
+ const row = {
738
+ adapter_id: input.adapterId,
739
+ scope_type: input.scopeType,
740
+ scope_key: input.scopeKey,
741
+ status: input.status,
742
+ schema_version: input.schemaVersion ?? 1,
743
+ started_at: input.startedAt ?? null,
744
+ completed_at: input.completedAt ?? null,
745
+ cursor: input.cursor ?? null,
746
+ indexed_source_count: input.indexedSourceCount ?? 0,
747
+ failed_source_count: input.failedSourceCount ?? 0,
748
+ last_error_code: input.lastErrorCode ?? null,
749
+ updated_at: now,
750
+ };
751
+
752
+ await this.db
753
+ .insertInto("_emdash_media_usage_index_status")
754
+ .values(row)
755
+ .onConflict((oc) =>
756
+ oc.columns(["adapter_id", "scope_type", "scope_key"]).doUpdateSet({
757
+ status: row.status,
758
+ schema_version: row.schema_version,
759
+ started_at: row.started_at,
760
+ completed_at: row.completed_at,
761
+ cursor: row.cursor,
762
+ indexed_source_count: row.indexed_source_count,
763
+ failed_source_count: row.failed_source_count,
764
+ last_error_code: row.last_error_code,
765
+ updated_at: row.updated_at,
766
+ }),
767
+ )
768
+ .execute();
769
+
770
+ const status = await this.findIndexStatus(input);
771
+ if (!status) {
772
+ throw new Error(
773
+ `Media usage index status ${input.adapterId}:${input.scopeType}:${input.scopeKey} was not persisted`,
774
+ );
775
+ }
776
+ return status;
777
+ }
778
+
779
+ async beginIndexStatusRepair(
780
+ input: MediaUsageIndexStatusRepairInput,
781
+ ): Promise<MediaUsageIndexStatus> {
782
+ return this.upsertIndexStatus({
783
+ adapterId: input.adapterId,
784
+ scopeType: input.scopeType,
785
+ scopeKey: input.scopeKey,
786
+ status: "running",
787
+ schemaVersion: input.schemaVersion,
788
+ startedAt: input.startedAt,
789
+ completedAt: null,
790
+ cursor: input.runToken,
791
+ indexedSourceCount: 0,
792
+ failedSourceCount: 0,
793
+ lastErrorCode: null,
794
+ updatedAt: input.updatedAt,
795
+ });
796
+ }
797
+
798
+ async finalizeIndexStatusRepairIfRunning(
799
+ input: MediaUsageIndexStatusFinalizeInput,
800
+ ): Promise<MediaUsageGuardedIndexStatusResult> {
801
+ const updates: Updateable<MediaUsageIndexStatusTable> = {
802
+ status: input.status,
803
+ completed_at: input.completedAt,
804
+ cursor: null,
805
+ indexed_source_count: input.indexedSourceCount ?? 0,
806
+ failed_source_count: input.failedSourceCount ?? 0,
807
+ last_error_code: input.lastErrorCode ?? null,
808
+ updated_at: input.updatedAt ?? new Date().toISOString(),
809
+ };
810
+ if (input.schemaVersion !== undefined) updates.schema_version = input.schemaVersion;
811
+
812
+ const result = await this.db
813
+ .updateTable("_emdash_media_usage_index_status")
814
+ .set(updates)
815
+ .where("adapter_id", "=", input.adapterId)
816
+ .where("scope_type", "=", input.scopeType)
817
+ .where("scope_key", "=", input.scopeKey)
818
+ .where("status", "=", "running")
819
+ .where("cursor", "=", input.runToken)
820
+ .executeTakeFirst();
821
+ const finalized = Number(result.numUpdatedRows ?? 0) > 0;
822
+
823
+ return {
824
+ finalized,
825
+ status: await this.findIndexStatus(input),
826
+ };
827
+ }
828
+
829
+ async findIndexStatus(
830
+ identity: MediaUsageIndexStatusIdentity,
831
+ ): Promise<MediaUsageIndexStatus | null> {
832
+ const row = await this.db
833
+ .selectFrom("_emdash_media_usage_index_status")
834
+ .selectAll()
835
+ .where("adapter_id", "=", identity.adapterId)
836
+ .where("scope_type", "=", identity.scopeType)
837
+ .where("scope_key", "=", identity.scopeKey)
838
+ .executeTakeFirst();
839
+
840
+ return row ? rowToIndexStatus(row) : null;
841
+ }
842
+
843
+ async deleteIndexStatus(identity: MediaUsageIndexStatusIdentity): Promise<number> {
844
+ const result = await this.db
845
+ .deleteFrom("_emdash_media_usage_index_status")
846
+ .where("adapter_id", "=", identity.adapterId)
847
+ .where("scope_type", "=", identity.scopeType)
848
+ .where("scope_key", "=", identity.scopeKey)
849
+ .executeTakeFirst();
850
+ return Number(result.numDeletedRows ?? 0);
851
+ }
852
+
853
+ private async findCurrentUsagePage(
854
+ applyFilter: (
855
+ query: ReturnType<MediaUsageRepository["currentUsageBaseQuery"]>,
856
+ ) => ReturnType<MediaUsageRepository["currentUsageBaseQuery"]>,
857
+ options: FindMediaUsageOptions,
858
+ ): Promise<FindManyResult<MediaUsageRecord>> {
859
+ const limit = Math.min(Math.max(1, options.limit ?? 50), 100);
860
+ let query = applyFilter(this.currentUsageBaseQuery())
861
+ .orderBy("u.id", "asc")
862
+ .limit(limit + 1);
863
+
864
+ if (options.cursor) {
865
+ const { id } = decodeCursor(options.cursor);
866
+ query = query.where("u.id", ">", id);
867
+ }
868
+
869
+ const rows = await query.execute();
870
+ const items = rows.slice(0, limit).map(rowToUsageRecord);
871
+ const result: FindManyResult<MediaUsageRecord> = { items };
872
+
873
+ if (rows.length > limit && items.length > 0) {
874
+ const last = items.at(-1)!;
875
+ result.nextCursor = encodeCursor(last.occurrence.id, last.occurrence.id);
876
+ }
877
+
878
+ return result;
879
+ }
880
+
881
+ private currentUsageBaseQuery() {
882
+ return this.db
883
+ .selectFrom("_emdash_media_usage_sources as s")
884
+ .innerJoin("_emdash_media_usage as u", (join) =>
885
+ join
886
+ .onRef("u.source_key", "=", "s.source_key")
887
+ .onRef("u.generation", "=", "s.current_generation"),
888
+ )
889
+ .select(currentUsageSelect);
890
+ }
891
+
892
+ private async deleteSourceKeys(sourceKeys: readonly string[]): Promise<number> {
893
+ const uniqueSourceKeys = [...new Set(sourceKeys)];
894
+ if (uniqueSourceKeys.length === 0) return 0;
221
895
 
222
896
  return withTransaction(this.db, async (trx) => {
223
897
  let deleted = 0;
224
- for (const sourceKeyBatch of chunks(sourceKeys, SQL_BATCH_SIZE)) {
225
- await trx
226
- .deleteFrom("_emdash_media_usage")
227
- .where("source_key", "in", sourceKeyBatch)
228
- .execute();
898
+ for (const sourceKeyBatch of chunks(uniqueSourceKeys, SQL_BATCH_SIZE)) {
229
899
  const result = await trx
230
900
  .deleteFrom("_emdash_media_usage_sources")
231
901
  .where("source_key", "in", sourceKeyBatch)
232
902
  .executeTakeFirst();
233
903
  deleted += Number(result.numDeletedRows ?? 0);
904
+
905
+ await trx
906
+ .deleteFrom("_emdash_media_usage")
907
+ .where("source_key", "in", sourceKeyBatch)
908
+ .execute();
234
909
  }
235
910
  return deleted;
236
911
  });
237
912
  }
238
913
 
914
+ private async deleteSourceGenerationOccurrences(
915
+ db: DatabaseExecutor,
916
+ sourceKey: string,
917
+ generation: string,
918
+ ): Promise<void> {
919
+ // Guarded source deletes remove only the generation that won the source CAS;
920
+ // unmatched generations become invisible orphans reclaimed by age-gated cleanup.
921
+ await db
922
+ .deleteFrom("_emdash_media_usage")
923
+ .where("source_key", "=", sourceKey)
924
+ .where("generation", "=", generation)
925
+ .execute();
926
+ }
927
+
239
928
  private async insertOccurrences(
240
929
  db: DatabaseExecutor,
241
930
  sourceKey: string,
242
931
  generation: string,
243
932
  occurrences: readonly MediaUsageOccurrenceInput[],
933
+ now: string,
244
934
  ): Promise<void> {
245
935
  if (occurrences.length === 0) return;
246
936
 
@@ -257,6 +947,7 @@ export class MediaUsageRepository {
257
947
  provider_asset_id: occurrence.providerAssetId,
258
948
  media_kind: occurrence.mediaKind ?? null,
259
949
  mime_type: occurrence.mimeType ?? null,
950
+ created_at: now,
260
951
  }));
261
952
 
262
953
  for (const rowBatch of chunks(rows, OCCURRENCE_INSERT_BATCH_SIZE)) {
@@ -270,7 +961,113 @@ export class MediaUsageRepository {
270
961
  generation: string,
271
962
  now: string,
272
963
  ): Promise<void> {
273
- const row = {
964
+ const row = this.buildSourceRow(source, generation, now);
965
+
966
+ await db
967
+ .insertInto("_emdash_media_usage_sources")
968
+ .values(row)
969
+ .onConflict((oc) => oc.column("source_key").doUpdateSet(this.sourceUpdateSet(row)))
970
+ .execute();
971
+ }
972
+
973
+ private async insertSourceIfAbsent(
974
+ db: DatabaseExecutor,
975
+ row: Insertable<MediaUsageSourceTable>,
976
+ ): Promise<boolean> {
977
+ const result = await db
978
+ .insertInto("_emdash_media_usage_sources")
979
+ .values(row)
980
+ .onConflict((oc) => oc.column("source_key").doNothing())
981
+ .executeTakeFirst();
982
+ return (result.numInsertedOrUpdatedRows ?? 0n) > 0n;
983
+ }
984
+
985
+ private async updateSourceIfGeneration(
986
+ db: DatabaseExecutor,
987
+ row: ReturnType<MediaUsageRepository["buildSourceRow"]>,
988
+ expectedCurrentGeneration: string,
989
+ ): Promise<boolean> {
990
+ const result = await db
991
+ .updateTable("_emdash_media_usage_sources")
992
+ .set(this.sourceUpdateSet(row))
993
+ .where("source_key", "=", row.source_key)
994
+ .where("current_generation", "=", expectedCurrentGeneration)
995
+ .executeTakeFirst();
996
+ return Number(result.numUpdatedRows ?? 0) > 0;
997
+ }
998
+
999
+ private async updateSourceIfMatching(
1000
+ db: DatabaseExecutor,
1001
+ row: ReturnType<MediaUsageRepository["buildSourceRow"]>,
1002
+ expectedSource: MediaUsageSource,
1003
+ ): Promise<boolean> {
1004
+ const result = await db
1005
+ .updateTable("_emdash_media_usage_sources")
1006
+ .set(this.sourceUpdateSet(row))
1007
+ .where("source_key", "=", row.source_key)
1008
+ .where(this.sourceMatchExpression(expectedSource))
1009
+ .executeTakeFirst();
1010
+ return Number(result.numUpdatedRows ?? 0) > 0;
1011
+ }
1012
+
1013
+ private async updateAttemptedSourceIfMatching(
1014
+ db: DatabaseExecutor,
1015
+ source: MediaUsageSourceInput,
1016
+ row: ReturnType<MediaUsageRepository["buildAttemptedSourceRow"]>,
1017
+ expectedSource: MediaUsageSource,
1018
+ ): Promise<boolean> {
1019
+ const result = await db
1020
+ .updateTable("_emdash_media_usage_sources")
1021
+ .set(this.attemptedSourceUpdateSet(source, row))
1022
+ .where("source_key", "=", row.source_key)
1023
+ .where(this.sourceMatchExpression(expectedSource))
1024
+ .executeTakeFirst();
1025
+ return Number(result.numUpdatedRows ?? 0) > 0;
1026
+ }
1027
+
1028
+ private sourceMatchExpression(expectedSource: MediaUsageSource) {
1029
+ return (eb: ExpressionBuilder<Database, "_emdash_media_usage_sources">) =>
1030
+ eb.and([
1031
+ eb("current_generation", "=", expectedSource.currentGeneration),
1032
+ eb("source_completeness", "=", expectedSource.sourceCompleteness),
1033
+ this.nullableStringExpression(eb, "updated_at", expectedSource.updatedAt),
1034
+ this.nullableStringExpression(eb, "source_fingerprint", expectedSource.sourceFingerprint),
1035
+ this.nullableStringExpression(eb, "source_updated_at", expectedSource.sourceUpdatedAt),
1036
+ this.nullableNumberExpression(eb, "source_version", expectedSource.sourceVersion),
1037
+ this.nullableStringExpression(eb, "revision_id", expectedSource.revisionId),
1038
+ this.nullableStringExpression(eb, "last_attempted_at", expectedSource.lastAttemptedAt),
1039
+ this.nullableStringExpression(eb, "last_error_code", expectedSource.lastErrorCode),
1040
+ ]);
1041
+ }
1042
+
1043
+ private nullableStringExpression(
1044
+ eb: ExpressionBuilder<Database, "_emdash_media_usage_sources">,
1045
+ column: MediaUsageSourceNullableStringColumn,
1046
+ value: string | null,
1047
+ ) {
1048
+ return value === null ? eb(column, "is", null) : eb(column, "=", value);
1049
+ }
1050
+
1051
+ private nullableNumberExpression(
1052
+ eb: ExpressionBuilder<Database, "_emdash_media_usage_sources">,
1053
+ column: "source_version",
1054
+ value: number | null,
1055
+ ) {
1056
+ return value === null ? eb(column, "is", null) : eb(column, "=", value);
1057
+ }
1058
+
1059
+ private async contentRowExists(tableName: string, contentId: string): Promise<boolean> {
1060
+ const result = await sql<{ id: string }>`
1061
+ SELECT id
1062
+ FROM ${sql.ref(tableName)}
1063
+ WHERE id = ${contentId}
1064
+ LIMIT 1
1065
+ `.execute(this.db);
1066
+ return result.rows.length > 0;
1067
+ }
1068
+
1069
+ private buildSourceRow(source: MediaUsageSourceInput, generation: string, now: string) {
1070
+ return {
274
1071
  source_key: source.sourceKey,
275
1072
  source_type: source.sourceType,
276
1073
  collection_slug: source.collectionSlug ?? null,
@@ -286,46 +1083,110 @@ export class MediaUsageRepository {
286
1083
  revision_id: source.revisionId ?? null,
287
1084
  current_generation: generation,
288
1085
  schema_version: source.schemaVersion ?? 1,
1086
+ source_updated_at: source.sourceUpdatedAt ?? null,
1087
+ source_version: source.sourceVersion ?? null,
1088
+ source_fingerprint: source.sourceFingerprint ?? null,
1089
+ // Complete means this source was fully refreshed for the extractor's current
1090
+ // schema/version coverage, not that every possible reference shape is known.
1091
+ source_completeness: source.sourceCompleteness ?? "complete",
1092
+ last_attempted_at: source.lastAttemptedAt ?? now,
1093
+ last_error_code: null,
289
1094
  indexed_at: now,
290
1095
  updated_at: now,
291
1096
  };
1097
+ }
292
1098
 
293
- await db
294
- .insertInto("_emdash_media_usage_sources")
295
- .values(row)
296
- .onConflict((oc) =>
297
- oc.column("source_key").doUpdateSet({
298
- source_type: row.source_type,
299
- collection_slug: row.collection_slug,
300
- content_id: row.content_id,
301
- source_variant: row.source_variant,
302
- locale: row.locale,
303
- translation_group: row.translation_group,
304
- content_slug: row.content_slug,
305
- content_title: row.content_title,
306
- content_status: row.content_status,
307
- content_scheduled_at: row.content_scheduled_at,
308
- content_deleted_at: row.content_deleted_at,
309
- revision_id: row.revision_id,
310
- current_generation: row.current_generation,
311
- schema_version: row.schema_version,
312
- indexed_at: row.indexed_at,
313
- updated_at: row.updated_at,
314
- }),
315
- )
316
- .execute();
1099
+ private buildAttemptedSourceRow(source: MediaUsageSourceInput, now: string) {
1100
+ return {
1101
+ source_key: source.sourceKey,
1102
+ source_type: source.sourceType,
1103
+ collection_slug: source.collectionSlug ?? null,
1104
+ content_id: source.contentId ?? null,
1105
+ source_variant: source.sourceVariant,
1106
+ locale: source.locale ?? null,
1107
+ translation_group: source.translationGroup ?? null,
1108
+ content_slug: source.contentSlug ?? null,
1109
+ content_title: source.contentTitle ?? null,
1110
+ content_status: source.contentStatus ?? null,
1111
+ content_scheduled_at: source.contentScheduledAt ?? null,
1112
+ content_deleted_at: source.contentDeletedAt ?? null,
1113
+ revision_id: source.revisionId ?? null,
1114
+ current_generation: ulid(),
1115
+ schema_version: source.schemaVersion ?? 1,
1116
+ source_updated_at: source.sourceUpdatedAt ?? null,
1117
+ source_version: source.sourceVersion ?? null,
1118
+ source_fingerprint: source.sourceFingerprint ?? null,
1119
+ source_completeness:
1120
+ source.sourceCompleteness ?? (source.lastErrorCode ? "failed" : "unknown"),
1121
+ last_attempted_at: source.lastAttemptedAt ?? now,
1122
+ last_error_code: source.lastErrorCode ?? null,
1123
+ indexed_at: now,
1124
+ updated_at: now,
1125
+ };
317
1126
  }
318
1127
 
319
- private async deleteStaleGenerations(
320
- db: DatabaseExecutor,
321
- sourceKey: string,
322
- currentGeneration: string,
323
- ): Promise<void> {
324
- await db
325
- .deleteFrom("_emdash_media_usage")
326
- .where("source_key", "=", sourceKey)
327
- .where("generation", "!=", currentGeneration)
328
- .execute();
1128
+ private attemptedSourceUpdateSet(
1129
+ source: MediaUsageSourceInput,
1130
+ row: ReturnType<MediaUsageRepository["buildAttemptedSourceRow"]>,
1131
+ ): Updateable<MediaUsageSourceTable> {
1132
+ const updates: Updateable<MediaUsageSourceTable> = {
1133
+ source_type: row.source_type,
1134
+ source_variant: row.source_variant,
1135
+ source_completeness: row.source_completeness,
1136
+ last_attempted_at: row.last_attempted_at,
1137
+ last_error_code: row.last_error_code,
1138
+ updated_at: row.updated_at,
1139
+ };
1140
+
1141
+ if (source.collectionSlug !== undefined) updates.collection_slug = row.collection_slug;
1142
+ if (source.contentId !== undefined) updates.content_id = row.content_id;
1143
+ if (source.locale !== undefined) updates.locale = row.locale;
1144
+ if (source.translationGroup !== undefined) updates.translation_group = row.translation_group;
1145
+ if (source.contentSlug !== undefined) updates.content_slug = row.content_slug;
1146
+ if (source.contentTitle !== undefined) updates.content_title = row.content_title;
1147
+ if (source.contentStatus !== undefined) updates.content_status = row.content_status;
1148
+ if (source.contentScheduledAt !== undefined) {
1149
+ updates.content_scheduled_at = row.content_scheduled_at;
1150
+ }
1151
+ if (source.contentDeletedAt !== undefined) updates.content_deleted_at = row.content_deleted_at;
1152
+ if (source.revisionId !== undefined) updates.revision_id = row.revision_id;
1153
+ if (source.schemaVersion !== undefined) updates.schema_version = row.schema_version;
1154
+ if (source.sourceUpdatedAt !== undefined) updates.source_updated_at = row.source_updated_at;
1155
+ if (source.sourceVersion !== undefined) updates.source_version = row.source_version;
1156
+ if (source.sourceFingerprint !== undefined) {
1157
+ updates.source_fingerprint = row.source_fingerprint;
1158
+ }
1159
+
1160
+ return updates;
1161
+ }
1162
+
1163
+ private sourceUpdateSet(
1164
+ row: ReturnType<MediaUsageRepository["buildSourceRow"]>,
1165
+ ): Updateable<MediaUsageSourceTable> {
1166
+ return {
1167
+ source_type: row.source_type,
1168
+ collection_slug: row.collection_slug,
1169
+ content_id: row.content_id,
1170
+ source_variant: row.source_variant,
1171
+ locale: row.locale,
1172
+ translation_group: row.translation_group,
1173
+ content_slug: row.content_slug,
1174
+ content_title: row.content_title,
1175
+ content_status: row.content_status,
1176
+ content_scheduled_at: row.content_scheduled_at,
1177
+ content_deleted_at: row.content_deleted_at,
1178
+ revision_id: row.revision_id,
1179
+ current_generation: row.current_generation,
1180
+ schema_version: row.schema_version,
1181
+ source_updated_at: row.source_updated_at,
1182
+ source_version: row.source_version,
1183
+ source_fingerprint: row.source_fingerprint,
1184
+ source_completeness: row.source_completeness,
1185
+ last_attempted_at: row.last_attempted_at,
1186
+ last_error_code: row.last_error_code,
1187
+ indexed_at: row.indexed_at,
1188
+ updated_at: row.updated_at,
1189
+ };
329
1190
  }
330
1191
  }
331
1192
 
@@ -345,9 +1206,15 @@ const currentUsageSelect = [
345
1206
  "s.revision_id as revision_id",
346
1207
  "s.current_generation as current_generation",
347
1208
  "s.schema_version as schema_version",
1209
+ "s.source_updated_at as source_updated_at",
1210
+ "s.source_version as source_version",
1211
+ "s.source_fingerprint as source_fingerprint",
1212
+ "s.source_completeness as source_completeness",
1213
+ "s.last_attempted_at as last_attempted_at",
1214
+ "s.last_error_code as last_error_code",
348
1215
  "s.indexed_at as indexed_at",
349
1216
  "s.created_at as source_created_at",
350
- "s.updated_at as source_updated_at",
1217
+ "s.updated_at as source_row_updated_at",
351
1218
  "u.id as occurrence_id",
352
1219
  "u.generation as generation",
353
1220
  "u.field_slug as field_slug",
@@ -362,7 +1229,7 @@ const currentUsageSelect = [
362
1229
  "u.created_at as occurrence_created_at",
363
1230
  ] as const;
364
1231
 
365
- function rowToSource(row: Selectable<MediaUsageSourceTable>): MediaUsageSource {
1232
+ function rowToSource(row: MediaUsageSourceRow): MediaUsageSource {
366
1233
  return {
367
1234
  sourceKey: row.source_key,
368
1235
  sourceType: row.source_type,
@@ -379,6 +1246,12 @@ function rowToSource(row: Selectable<MediaUsageSourceTable>): MediaUsageSource {
379
1246
  revisionId: row.revision_id,
380
1247
  currentGeneration: row.current_generation,
381
1248
  schemaVersion: Number(row.schema_version),
1249
+ sourceUpdatedAt: row.source_updated_at,
1250
+ sourceVersion: row.source_version === null ? null : Number(row.source_version),
1251
+ sourceFingerprint: row.source_fingerprint,
1252
+ sourceCompleteness: row.source_completeness,
1253
+ lastAttemptedAt: row.last_attempted_at,
1254
+ lastErrorCode: row.last_error_code,
382
1255
  indexedAt: row.indexed_at,
383
1256
  createdAt: row.created_at,
384
1257
  updatedAt: row.updated_at,
@@ -421,9 +1294,15 @@ function rowToUsageRecord(row: JoinedUsageRow): MediaUsageRecord {
421
1294
  revision_id: row.revision_id,
422
1295
  current_generation: row.current_generation,
423
1296
  schema_version: row.schema_version,
1297
+ source_updated_at: row.source_updated_at,
1298
+ source_version: row.source_version,
1299
+ source_fingerprint: row.source_fingerprint,
1300
+ source_completeness: row.source_completeness,
1301
+ last_attempted_at: row.last_attempted_at,
1302
+ last_error_code: row.last_error_code,
424
1303
  indexed_at: row.indexed_at,
425
1304
  created_at: row.source_created_at,
426
- updated_at: row.source_updated_at,
1305
+ updated_at: row.source_row_updated_at,
427
1306
  }),
428
1307
  occurrence: rowToOccurrence({
429
1308
  id: row.occurrence_id,
@@ -442,3 +1321,20 @@ function rowToUsageRecord(row: JoinedUsageRow): MediaUsageRecord {
442
1321
  }),
443
1322
  };
444
1323
  }
1324
+
1325
+ function rowToIndexStatus(row: Selectable<MediaUsageIndexStatusTable>): MediaUsageIndexStatus {
1326
+ return {
1327
+ adapterId: row.adapter_id,
1328
+ scopeType: row.scope_type,
1329
+ scopeKey: row.scope_key,
1330
+ status: row.status,
1331
+ schemaVersion: Number(row.schema_version),
1332
+ startedAt: row.started_at,
1333
+ completedAt: row.completed_at,
1334
+ cursor: row.cursor,
1335
+ indexedSourceCount: Number(row.indexed_source_count),
1336
+ failedSourceCount: Number(row.failed_source_count),
1337
+ lastErrorCode: row.last_error_code,
1338
+ updatedAt: row.updated_at,
1339
+ };
1340
+ }