emdash 0.26.0 → 0.28.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (564) hide show
  1. package/dist/{adapters-DAAjOID4.d.mts → adapters-hUy8vOB-.d.mts} +1 -1
  2. package/dist/{adapters-DAAjOID4.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-BMfveMoB.mjs → api-BFURZn1i.mjs} +104 -38
  11. package/dist/api-BFURZn1i.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--IVNSdXn.mjs → apply-Bu-8nYHL.mjs} +113 -76
  15. package/dist/apply-Bu-8nYHL.mjs.map +1 -0
  16. package/dist/astro/index.d.mts +12 -11
  17. package/dist/astro/index.d.mts.map +1 -1
  18. package/dist/astro/index.mjs +13 -5
  19. package/dist/astro/index.mjs.map +1 -1
  20. package/dist/astro/middleware/auth.d.mts +10 -9
  21. package/dist/astro/middleware/auth.d.mts.map +1 -1
  22. package/dist/astro/middleware/auth.mjs +52 -12
  23. package/dist/astro/middleware/auth.mjs.map +1 -1
  24. package/dist/astro/middleware/redirect.mjs +5 -5
  25. package/dist/astro/middleware/request-context.mjs +2 -2
  26. package/dist/astro/middleware/setup.mjs +1 -1
  27. package/dist/astro/middleware.d.mts +2 -9
  28. package/dist/astro/middleware.d.mts.map +1 -1
  29. package/dist/astro/middleware.mjs +125 -71
  30. package/dist/astro/middleware.mjs.map +1 -1
  31. package/dist/astro/routes/api/admin/allowed-domains/_domain_.mjs +6 -6
  32. package/dist/astro/routes/api/admin/allowed-domains/index.mjs +6 -6
  33. package/dist/astro/routes/api/admin/api-tokens/_id_.mjs +4 -4
  34. package/dist/astro/routes/api/admin/api-tokens/index.mjs +5 -5
  35. package/dist/astro/routes/api/admin/byline-fields/_slug_/usage.mjs +4 -4
  36. package/dist/astro/routes/api/admin/byline-fields/_slug_.mjs +8 -8
  37. package/dist/astro/routes/api/admin/byline-fields/index.mjs +8 -8
  38. package/dist/astro/routes/api/admin/byline-fields/reorder.mjs +8 -8
  39. package/dist/astro/routes/api/admin/bylines/_id_/index.mjs +14 -14
  40. package/dist/astro/routes/api/admin/bylines/_id_/translations.mjs +14 -14
  41. package/dist/astro/routes/api/admin/bylines/index.mjs +14 -14
  42. package/dist/astro/routes/api/admin/comments/_id_/status.mjs +12 -12
  43. package/dist/astro/routes/api/admin/comments/_id_.mjs +6 -6
  44. package/dist/astro/routes/api/admin/comments/bulk.mjs +10 -10
  45. package/dist/astro/routes/api/admin/comments/counts.mjs +6 -6
  46. package/dist/astro/routes/api/admin/comments/index.mjs +10 -10
  47. package/dist/astro/routes/api/admin/hooks/exclusive/_hookName_.mjs +4 -4
  48. package/dist/astro/routes/api/admin/hooks/exclusive/index.mjs +3 -3
  49. package/dist/astro/routes/api/admin/oauth-clients/_id_.mjs +4 -4
  50. package/dist/astro/routes/api/admin/oauth-clients/index.mjs +4 -4
  51. package/dist/astro/routes/api/admin/plugins/_id_/disable.mjs +38 -37
  52. package/dist/astro/routes/api/admin/plugins/_id_/disable.mjs.map +1 -1
  53. package/dist/astro/routes/api/admin/plugins/_id_/enable.mjs +38 -37
  54. package/dist/astro/routes/api/admin/plugins/_id_/enable.mjs.map +1 -1
  55. package/dist/astro/routes/api/admin/plugins/_id_/index.mjs +37 -36
  56. package/dist/astro/routes/api/admin/plugins/_id_/index.mjs.map +1 -1
  57. package/dist/astro/routes/api/admin/plugins/_id_/uninstall.mjs +36 -35
  58. package/dist/astro/routes/api/admin/plugins/_id_/uninstall.mjs.map +1 -1
  59. package/dist/astro/routes/api/admin/plugins/_id_/update.mjs +36 -35
  60. package/dist/astro/routes/api/admin/plugins/_id_/update.mjs.map +1 -1
  61. package/dist/astro/routes/api/admin/plugins/index.mjs +37 -36
  62. package/dist/astro/routes/api/admin/plugins/index.mjs.map +1 -1
  63. package/dist/astro/routes/api/admin/plugins/marketplace/_id_/icon.mjs +3 -3
  64. package/dist/astro/routes/api/admin/plugins/marketplace/_id_/index.mjs +36 -35
  65. package/dist/astro/routes/api/admin/plugins/marketplace/_id_/index.mjs.map +1 -1
  66. package/dist/astro/routes/api/admin/plugins/marketplace/_id_/install.mjs +36 -35
  67. package/dist/astro/routes/api/admin/plugins/marketplace/_id_/install.mjs.map +1 -1
  68. package/dist/astro/routes/api/admin/plugins/marketplace/index.mjs +36 -35
  69. package/dist/astro/routes/api/admin/plugins/marketplace/index.mjs.map +1 -1
  70. package/dist/astro/routes/api/admin/plugins/registry/_id_/uninstall.mjs +36 -35
  71. package/dist/astro/routes/api/admin/plugins/registry/_id_/uninstall.mjs.map +1 -1
  72. package/dist/astro/routes/api/admin/plugins/registry/_id_/update.mjs +37 -36
  73. package/dist/astro/routes/api/admin/plugins/registry/_id_/update.mjs.map +1 -1
  74. package/dist/astro/routes/api/admin/plugins/registry/artifact.mjs +36 -35
  75. package/dist/astro/routes/api/admin/plugins/registry/artifact.mjs.map +1 -1
  76. package/dist/astro/routes/api/admin/plugins/registry/install.mjs +37 -36
  77. package/dist/astro/routes/api/admin/plugins/registry/install.mjs.map +1 -1
  78. package/dist/astro/routes/api/admin/plugins/updates.mjs +36 -35
  79. package/dist/astro/routes/api/admin/plugins/updates.mjs.map +1 -1
  80. package/dist/astro/routes/api/admin/themes/marketplace/_id_/index.mjs +36 -35
  81. package/dist/astro/routes/api/admin/themes/marketplace/_id_/index.mjs.map +1 -1
  82. package/dist/astro/routes/api/admin/themes/marketplace/_id_/thumbnail.mjs +3 -3
  83. package/dist/astro/routes/api/admin/themes/marketplace/index.mjs +36 -35
  84. package/dist/astro/routes/api/admin/themes/marketplace/index.mjs.map +1 -1
  85. package/dist/astro/routes/api/admin/users/_id_/disable.mjs +2 -2
  86. package/dist/astro/routes/api/admin/users/_id_/enable.mjs +2 -2
  87. package/dist/astro/routes/api/admin/users/_id_/index.mjs +6 -6
  88. package/dist/astro/routes/api/admin/users/_id_/send-recovery.mjs +3 -3
  89. package/dist/astro/routes/api/admin/users/index.mjs +6 -6
  90. package/dist/astro/routes/api/auth/dev-bypass.mjs +5 -5
  91. package/dist/astro/routes/api/auth/invite/accept.mjs +2 -2
  92. package/dist/astro/routes/api/auth/invite/complete.mjs +10 -10
  93. package/dist/astro/routes/api/auth/invite/index.mjs +7 -7
  94. package/dist/astro/routes/api/auth/invite/register-options.mjs +9 -9
  95. package/dist/astro/routes/api/auth/logout.mjs +3 -3
  96. package/dist/astro/routes/api/auth/magic-link/send.mjs +9 -9
  97. package/dist/astro/routes/api/auth/magic-link/verify.mjs +3 -3
  98. package/dist/astro/routes/api/auth/me.mjs +7 -7
  99. package/dist/astro/routes/api/auth/mode.mjs +1 -1
  100. package/dist/astro/routes/api/auth/oauth/_provider_/callback.mjs +3 -3
  101. package/dist/astro/routes/api/auth/oauth/_provider_.mjs +2 -2
  102. package/dist/astro/routes/api/auth/passkey/_id_.mjs +6 -6
  103. package/dist/astro/routes/api/auth/passkey/index.mjs +2 -2
  104. package/dist/astro/routes/api/auth/passkey/options.mjs +11 -11
  105. package/dist/astro/routes/api/auth/passkey/register/options.mjs +9 -9
  106. package/dist/astro/routes/api/auth/passkey/register/verify.mjs +10 -10
  107. package/dist/astro/routes/api/auth/passkey/verify.mjs +10 -10
  108. package/dist/astro/routes/api/auth/signup/complete.mjs +10 -10
  109. package/dist/astro/routes/api/auth/signup/request.mjs +9 -9
  110. package/dist/astro/routes/api/auth/signup/verify.mjs +2 -2
  111. package/dist/astro/routes/api/comments/_collection_/_contentId_/index.mjs +13 -13
  112. package/dist/astro/routes/api/comments/_collection_/_contentId_/reactions.mjs +12 -12
  113. package/dist/astro/routes/api/content/_collection_/_id_/compare.mjs +3 -3
  114. package/dist/astro/routes/api/content/_collection_/_id_/discard-draft.mjs +3 -3
  115. package/dist/astro/routes/api/content/_collection_/_id_/duplicate.mjs +3 -3
  116. package/dist/astro/routes/api/content/_collection_/_id_/permanent.mjs +3 -3
  117. package/dist/astro/routes/api/content/_collection_/_id_/preview-url.mjs +10 -10
  118. package/dist/astro/routes/api/content/_collection_/_id_/publish.mjs +7 -7
  119. package/dist/astro/routes/api/content/_collection_/_id_/restore.mjs +3 -3
  120. package/dist/astro/routes/api/content/_collection_/_id_/revisions.mjs +3 -3
  121. package/dist/astro/routes/api/content/_collection_/_id_/schedule.mjs +7 -7
  122. package/dist/astro/routes/api/content/_collection_/_id_/terms/_taxonomy_.mjs +13 -13
  123. package/dist/astro/routes/api/content/_collection_/_id_/translations.mjs +3 -3
  124. package/dist/astro/routes/api/content/_collection_/_id_/unpublish.mjs +3 -3
  125. package/dist/astro/routes/api/content/_collection_/_id_.mjs +7 -7
  126. package/dist/astro/routes/api/content/_collection_/authors.mjs +3 -3
  127. package/dist/astro/routes/api/content/_collection_/index.mjs +7 -7
  128. package/dist/astro/routes/api/content/_collection_/trash.mjs +7 -7
  129. package/dist/astro/routes/api/dashboard.mjs +8 -8
  130. package/dist/astro/routes/api/dev/emails.mjs +3 -3
  131. package/dist/astro/routes/api/import/probe.d.mts +3 -3
  132. package/dist/astro/routes/api/import/probe.mjs +19 -11
  133. package/dist/astro/routes/api/import/probe.mjs.map +1 -1
  134. package/dist/astro/routes/api/import/wordpress/analyze.mjs +3 -3
  135. package/dist/astro/routes/api/import/wordpress/execute.d.mts +11 -40
  136. package/dist/astro/routes/api/import/wordpress/execute.d.mts.map +1 -1
  137. package/dist/astro/routes/api/import/wordpress/execute.mjs +12 -407
  138. package/dist/astro/routes/api/import/wordpress/execute.mjs.map +1 -1
  139. package/dist/astro/routes/api/import/wordpress/media.d.mts +10 -9
  140. package/dist/astro/routes/api/import/wordpress/media.d.mts.map +1 -1
  141. package/dist/astro/routes/api/import/wordpress/media.mjs +9 -9
  142. package/dist/astro/routes/api/import/wordpress/prepare.mjs +9 -9
  143. package/dist/astro/routes/api/import/wordpress/rewrite-urls.d.mts +19 -1
  144. package/dist/astro/routes/api/import/wordpress/rewrite-urls.d.mts.map +1 -1
  145. package/dist/astro/routes/api/import/wordpress/rewrite-urls.mjs +97 -79
  146. package/dist/astro/routes/api/import/wordpress/rewrite-urls.mjs.map +1 -1
  147. package/dist/astro/routes/api/import/wordpress-plugin/analyze.d.mts +1 -1
  148. package/dist/astro/routes/api/import/wordpress-plugin/analyze.mjs +19 -11
  149. package/dist/astro/routes/api/import/wordpress-plugin/analyze.mjs.map +1 -1
  150. package/dist/astro/routes/api/import/wordpress-plugin/execute.d.mts +40 -2
  151. package/dist/astro/routes/api/import/wordpress-plugin/execute.d.mts.map +1 -1
  152. package/dist/astro/routes/api/import/wordpress-plugin/execute.mjs +519 -39
  153. package/dist/astro/routes/api/import/wordpress-plugin/execute.mjs.map +1 -1
  154. package/dist/astro/routes/api/manifest.d.mts.map +1 -1
  155. package/dist/astro/routes/api/manifest.mjs +14 -5
  156. package/dist/astro/routes/api/manifest.mjs.map +1 -1
  157. package/dist/astro/routes/api/mcp.mjs +39 -39
  158. package/dist/astro/routes/api/media/_id_/confirm.mjs +7 -7
  159. package/dist/astro/routes/api/media/_id_.mjs +7 -7
  160. package/dist/astro/routes/api/media/file/_...key_.mjs +2 -2
  161. package/dist/astro/routes/api/media/providers/_providerId_/_itemId_.mjs +3 -3
  162. package/dist/astro/routes/api/media/providers/_providerId_/index.mjs +3 -3
  163. package/dist/astro/routes/api/media/providers/index.mjs +3 -3
  164. package/dist/astro/routes/api/media/upload-url.mjs +8 -8
  165. package/dist/astro/routes/api/media.mjs +9 -9
  166. package/dist/astro/routes/api/menus/_name_/items/_id_.mjs +9 -9
  167. package/dist/astro/routes/api/menus/_name_/items.mjs +9 -9
  168. package/dist/astro/routes/api/menus/_name_/reorder.mjs +9 -9
  169. package/dist/astro/routes/api/menus/_name_/translations.mjs +9 -9
  170. package/dist/astro/routes/api/menus/_name_.mjs +9 -9
  171. package/dist/astro/routes/api/menus/index.mjs +9 -9
  172. package/dist/astro/routes/api/oauth/authorize.mjs +6 -6
  173. package/dist/astro/routes/api/oauth/device/authorize.mjs +6 -6
  174. package/dist/astro/routes/api/oauth/device/code.mjs +9 -9
  175. package/dist/astro/routes/api/oauth/device/token.mjs +8 -8
  176. package/dist/astro/routes/api/oauth/register.mjs +3 -3
  177. package/dist/astro/routes/api/oauth/token/refresh.mjs +6 -6
  178. package/dist/astro/routes/api/oauth/token/revoke.mjs +6 -6
  179. package/dist/astro/routes/api/oauth/token.mjs +6 -6
  180. package/dist/astro/routes/api/openapi.json.mjs +4 -4
  181. package/dist/astro/routes/api/plugins/_pluginId_/_...path_.mjs +4 -4
  182. package/dist/astro/routes/api/redirects/404s/index.mjs +9 -9
  183. package/dist/astro/routes/api/redirects/404s/summary.mjs +9 -9
  184. package/dist/astro/routes/api/redirects/_id_.mjs +10 -10
  185. package/dist/astro/routes/api/redirects/index.mjs +10 -10
  186. package/dist/astro/routes/api/revisions/_revisionId_/index.mjs +3 -3
  187. package/dist/astro/routes/api/revisions/_revisionId_/restore.mjs +3 -3
  188. package/dist/astro/routes/api/schema/collections/_slug_/fields/_fieldSlug_.mjs +36 -35
  189. package/dist/astro/routes/api/schema/collections/_slug_/fields/_fieldSlug_.mjs.map +1 -1
  190. package/dist/astro/routes/api/schema/collections/_slug_/fields/index.mjs +36 -35
  191. package/dist/astro/routes/api/schema/collections/_slug_/fields/index.mjs.map +1 -1
  192. package/dist/astro/routes/api/schema/collections/_slug_/fields/reorder.mjs +36 -35
  193. package/dist/astro/routes/api/schema/collections/_slug_/fields/reorder.mjs.map +1 -1
  194. package/dist/astro/routes/api/schema/collections/_slug_/index.mjs +36 -35
  195. package/dist/astro/routes/api/schema/collections/_slug_/index.mjs.map +1 -1
  196. package/dist/astro/routes/api/schema/collections/index.mjs +36 -35
  197. package/dist/astro/routes/api/schema/collections/index.mjs.map +1 -1
  198. package/dist/astro/routes/api/schema/index.mjs +7 -6
  199. package/dist/astro/routes/api/schema/index.mjs.map +1 -1
  200. package/dist/astro/routes/api/schema/orphans/_slug_.mjs +36 -35
  201. package/dist/astro/routes/api/schema/orphans/_slug_.mjs.map +1 -1
  202. package/dist/astro/routes/api/schema/orphans/index.mjs +36 -35
  203. package/dist/astro/routes/api/schema/orphans/index.mjs.map +1 -1
  204. package/dist/astro/routes/api/search/enable.mjs +10 -10
  205. package/dist/astro/routes/api/search/index.mjs +9 -9
  206. package/dist/astro/routes/api/search/rebuild.mjs +10 -10
  207. package/dist/astro/routes/api/search/stats.mjs +6 -6
  208. package/dist/astro/routes/api/search/suggest.mjs +9 -9
  209. package/dist/astro/routes/api/sections/_slug_.mjs +9 -9
  210. package/dist/astro/routes/api/sections/index.mjs +9 -9
  211. package/dist/astro/routes/api/settings/email.mjs +4 -4
  212. package/dist/astro/routes/api/settings.mjs +12 -12
  213. package/dist/astro/routes/api/setup/admin-verify.mjs +11 -11
  214. package/dist/astro/routes/api/setup/admin.mjs +10 -10
  215. package/dist/astro/routes/api/setup/dev-bypass.d.mts.map +1 -1
  216. package/dist/astro/routes/api/setup/dev-bypass.mjs +28 -25
  217. package/dist/astro/routes/api/setup/dev-bypass.mjs.map +1 -1
  218. package/dist/astro/routes/api/setup/dev-reset.mjs +2 -2
  219. package/dist/astro/routes/api/setup/index.mjs +26 -25
  220. package/dist/astro/routes/api/setup/index.mjs.map +1 -1
  221. package/dist/astro/routes/api/setup/status.mjs +4 -4
  222. package/dist/astro/routes/api/snapshot.mjs +6 -6
  223. package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_/translations.mjs +13 -13
  224. package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_.mjs +13 -13
  225. package/dist/astro/routes/api/taxonomies/_name_/terms/index.mjs +13 -13
  226. package/dist/astro/routes/api/taxonomies/index.mjs +13 -13
  227. package/dist/astro/routes/api/themes/preview.mjs +5 -5
  228. package/dist/astro/routes/api/typegen.mjs +5 -5
  229. package/dist/astro/routes/api/well-known/auth.mjs +1 -1
  230. package/dist/astro/routes/api/well-known/oauth-authorization-server.mjs +2 -2
  231. package/dist/astro/routes/api/well-known/oauth-protected-resource.mjs +2 -2
  232. package/dist/astro/routes/api/widget-areas/_name_/reorder.mjs +7 -7
  233. package/dist/astro/routes/api/widget-areas/_name_/widgets/_id_.mjs +9 -9
  234. package/dist/astro/routes/api/widget-areas/_name_/widgets.mjs +9 -9
  235. package/dist/astro/routes/api/widget-areas/_name_.mjs +5 -5
  236. package/dist/astro/routes/api/widget-areas/index.mjs +9 -9
  237. package/dist/astro/routes/api/widget-components.mjs +3 -3
  238. package/dist/astro/routes/robots.txt.mjs +6 -6
  239. package/dist/astro/routes/sitemap-_collection_.xml.mjs +9 -9
  240. package/dist/astro/routes/sitemap.xml.mjs +7 -7
  241. package/dist/astro/types.d.mts +14 -12
  242. package/dist/astro/types.d.mts.map +1 -1
  243. package/dist/auth/providers/github.d.mts +1 -1
  244. package/dist/auth/providers/google.d.mts +1 -1
  245. package/dist/{authorize-BZnOGJFo.mjs → authorize-Dz88F_Fw.mjs} +2 -2
  246. package/dist/{authorize-BZnOGJFo.mjs.map → authorize-Dz88F_Fw.mjs.map} +1 -1
  247. package/dist/{byline-LL8lyqdb.mjs → byline-Bm8ZgUP9.mjs} +6 -6
  248. package/dist/{byline-LL8lyqdb.mjs.map → byline-Bm8ZgUP9.mjs.map} +1 -1
  249. package/dist/{byline-fields-eyJMblSr.mjs → byline-fields-2Lp5Hbgf.mjs} +18 -3
  250. package/dist/byline-fields-2Lp5Hbgf.mjs.map +1 -0
  251. package/dist/{byline-fields-DaMKzkhO.mjs → byline-fields-CIx_GuN4.mjs} +1 -1
  252. package/dist/{byline-fields-DaMKzkhO.mjs.map → byline-fields-CIx_GuN4.mjs.map} +1 -1
  253. package/dist/{byline-fields-KD3JFRuH.d.mts → byline-fields-Cgrt9-aL.d.mts} +18 -3
  254. package/dist/{byline-fields-KD3JFRuH.d.mts.map → byline-fields-Cgrt9-aL.d.mts.map} +1 -1
  255. package/dist/{bylines-BmJ7Vg7J.mjs → bylines-6tm9mgQb.mjs} +4 -4
  256. package/dist/{bylines-BmJ7Vg7J.mjs.map → bylines-6tm9mgQb.mjs.map} +1 -1
  257. package/dist/{bylines-DE47vP8d.mjs → bylines-Woq87129.mjs} +6 -6
  258. package/dist/{bylines-DE47vP8d.mjs.map → bylines-Woq87129.mjs.map} +1 -1
  259. package/dist/{cache-D9jF5bYw.mjs → cache-CEBAZjir.mjs} +2 -2
  260. package/dist/{cache-D9jF5bYw.mjs.map → cache-CEBAZjir.mjs.map} +1 -1
  261. package/dist/{challenge-store-LhiqMccz.mjs → challenge-store-anhwVER0.mjs} +1 -1
  262. package/dist/{challenge-store-LhiqMccz.mjs.map → challenge-store-anhwVER0.mjs.map} +1 -1
  263. package/dist/{chunks-OCG163rN.mjs → chunks-B2isWQhr.mjs} +2 -2
  264. package/dist/{chunks-OCG163rN.mjs.map → chunks-B2isWQhr.mjs.map} +1 -1
  265. package/dist/cli/index.mjs +23 -22
  266. package/dist/cli/index.mjs.map +1 -1
  267. package/dist/client/cf-access.d.mts +1 -1
  268. package/dist/client/index.d.mts +1 -1
  269. package/dist/client/index.mjs +2 -2
  270. package/dist/{comment-D9BLDpZI.mjs → comment-CzeatwBV.mjs} +3 -3
  271. package/dist/{comment-D9BLDpZI.mjs.map → comment-CzeatwBV.mjs.map} +1 -1
  272. package/dist/{comment-reaction-Drl9SkNu.mjs → comment-reaction-Cj9QJY7I.mjs} +2 -2
  273. package/dist/{comment-reaction-Drl9SkNu.mjs.map → comment-reaction-Cj9QJY7I.mjs.map} +1 -1
  274. package/dist/{comments-BjJ9SKGU.mjs → comments-BLE-jv5k.mjs} +3 -3
  275. package/dist/{comments-BjJ9SKGU.mjs.map → comments-BLE-jv5k.mjs.map} +1 -1
  276. package/dist/{components-CYt4uVK9.mjs → components-B_sATNUc.mjs} +1 -1
  277. package/dist/{components-CYt4uVK9.mjs.map → components-B_sATNUc.mjs.map} +1 -1
  278. package/dist/{content-ncUWWjna.mjs → content-DhgEth4k.mjs} +4 -4
  279. package/dist/{content-ncUWWjna.mjs.map → content-DhgEth4k.mjs.map} +1 -1
  280. package/dist/content-refresh-CA4uKwzH.mjs +1531 -0
  281. package/dist/content-refresh-CA4uKwzH.mjs.map +1 -0
  282. package/dist/{context-C_g-iJVA.mjs → context-CUsR9dXL.mjs} +76 -54
  283. package/dist/context-CUsR9dXL.mjs.map +1 -0
  284. package/dist/{cron-C5LVoNmP.mjs → cron-v4FTEFR_.mjs} +1 -1
  285. package/dist/{cron-C5LVoNmP.mjs.map → cron-v4FTEFR_.mjs.map} +1 -1
  286. package/dist/{dashboard-CotyqQrW.mjs → dashboard-EvEKF5en.mjs} +4 -4
  287. package/dist/{dashboard-CotyqQrW.mjs.map → dashboard-EvEKF5en.mjs.map} +1 -1
  288. package/dist/db/index.d.mts +3 -3
  289. package/dist/db/index.mjs +1 -1
  290. package/dist/db/libsql.d.mts +1 -1
  291. package/dist/db/postgres.d.mts +1 -1
  292. package/dist/db/sqlite.d.mts +1 -1
  293. package/dist/{default-CeRG-Ot4.mjs → default-CM_D83Mg.mjs} +1 -1
  294. package/dist/{default-CeRG-Ot4.mjs.map → default-CM_D83Mg.mjs.map} +1 -1
  295. package/dist/{device-flow-DENDCQ9F.mjs → device-flow-CfGP18Uw.mjs} +4 -4
  296. package/dist/{device-flow-DENDCQ9F.mjs.map → device-flow-CfGP18Uw.mjs.map} +1 -1
  297. package/dist/{email-console-DJP32ucW.mjs → email-console-CIf4Lfvv.mjs} +1 -1
  298. package/dist/{email-console-DJP32ucW.mjs.map → email-console-CIf4Lfvv.mjs.map} +1 -1
  299. package/dist/{error-rVGiqWDt.mjs → error-CkAseSqZ.mjs} +2 -2
  300. package/dist/{error-rVGiqWDt.mjs.map → error-CkAseSqZ.mjs.map} +1 -1
  301. package/dist/{escape-Bjio4ZsM.mjs → escape-DqD0aCKu.mjs} +1 -1
  302. package/dist/{escape-Bjio4ZsM.mjs.map → escape-DqD0aCKu.mjs.map} +1 -1
  303. package/dist/{field-defs-cache-ljXzJCfc.mjs → field-defs-cache-WUI88LX5.mjs} +2 -2
  304. package/dist/{field-defs-cache-ljXzJCfc.mjs.map → field-defs-cache-WUI88LX5.mjs.map} +1 -1
  305. package/dist/{fts-manager-BbCCbEKA.mjs → fts-manager-BbFaF_V8.mjs} +2 -2
  306. package/dist/{fts-manager-BbCCbEKA.mjs.map → fts-manager-BbFaF_V8.mjs.map} +1 -1
  307. package/dist/{import-Bb1T9WJS.mjs → import-fYLf14Co.mjs} +514 -25
  308. package/dist/import-fYLf14Co.mjs.map +1 -0
  309. package/dist/{index-BRNabKrx.d.mts → index-B9sIxwe4.d.mts} +2420 -2379
  310. package/dist/index-B9sIxwe4.d.mts.map +1 -0
  311. package/dist/{index-Dt0OKJB4.d.mts → index-Bm-Gy8Mh.d.mts} +25 -4
  312. package/dist/index-Bm-Gy8Mh.d.mts.map +1 -0
  313. package/dist/index.d.mts +18 -17
  314. package/dist/index.mjs +54 -53
  315. package/dist/{load-DMjXghbZ.mjs → load-Djn3HWQS.mjs} +2 -2
  316. package/dist/{load-DMjXghbZ.mjs.map → load-Djn3HWQS.mjs.map} +1 -1
  317. package/dist/{loader-BA_zhkS_.mjs → loader-CB6YHeul.mjs} +6 -5
  318. package/dist/loader-CB6YHeul.mjs.map +1 -0
  319. package/dist/{manifest-schema-kPGX7VS-.mjs → manifest-schema-BHlgZM1W.mjs} +1 -1
  320. package/dist/{manifest-schema-kPGX7VS-.mjs.map → manifest-schema-BHlgZM1W.mjs.map} +1 -1
  321. package/dist/media/index.d.mts +1 -1
  322. package/dist/media/local-runtime.d.mts +12 -11
  323. package/dist/media/local-runtime.d.mts.map +1 -1
  324. package/dist/media/local-runtime.mjs +5 -5
  325. package/dist/{media-C5t_eCnk.mjs → media-BrXIaMFN.mjs} +2 -2
  326. package/dist/{media-C5t_eCnk.mjs.map → media-BrXIaMFN.mjs.map} +1 -1
  327. package/dist/{media-allowlist-Du8t1u6a.mjs → media-allowlist-CRHEeJ_i.mjs} +1 -1
  328. package/dist/{media-allowlist-Du8t1u6a.mjs.map → media-allowlist-CRHEeJ_i.mjs.map} +1 -1
  329. package/dist/{media-url-O4rm9-SQ.mjs → media-url-CKi5XSw4.mjs} +1 -1
  330. package/dist/{media-url-O4rm9-SQ.mjs.map → media-url-CKi5XSw4.mjs.map} +1 -1
  331. package/dist/{menus-CBb6UrMU.mjs → menus-Cfivc2Ad.mjs} +3 -3
  332. package/dist/{menus-CBb6UrMU.mjs.map → menus-Cfivc2Ad.mjs.map} +1 -1
  333. package/dist/{menus-CYH09a41.mjs → menus-CsZ2ZEK2.mjs} +16 -12
  334. package/dist/{menus-CYH09a41.mjs.map → menus-CsZ2ZEK2.mjs.map} +1 -1
  335. package/dist/{mode-BB0F8xTC.mjs → mode-BM9QgEmt.mjs} +1 -1
  336. package/dist/{mode-BB0F8xTC.mjs.map → mode-BM9QgEmt.mjs.map} +1 -1
  337. package/dist/{oauth-authorization-CsvzIp_F.mjs → oauth-authorization-CXWkIGT4.mjs} +4 -4
  338. package/dist/{oauth-authorization-CsvzIp_F.mjs.map → oauth-authorization-CXWkIGT4.mjs.map} +1 -1
  339. package/dist/{oauth-clients-C9SYwEbZ.mjs → oauth-clients-BmTI5rsl.mjs} +1 -1
  340. package/dist/{oauth-clients-C9SYwEbZ.mjs.map → oauth-clients-BmTI5rsl.mjs.map} +1 -1
  341. package/dist/{oauth-state-store---zrApfB.mjs → oauth-state-store-YLFLcH5F.mjs} +1 -1
  342. package/dist/{oauth-state-store---zrApfB.mjs.map → oauth-state-store-YLFLcH5F.mjs.map} +1 -1
  343. package/dist/{oauth-user-lookup-SHsWRlG9.mjs → oauth-user-lookup-Bsc_GsX-.mjs} +1 -1
  344. package/dist/{oauth-user-lookup-SHsWRlG9.mjs.map → oauth-user-lookup-Bsc_GsX-.mjs.map} +1 -1
  345. package/dist/object-cache/memory.d.mts +1 -1
  346. package/dist/{object-cache-CHbHv83-.mjs → object-cache-Bok5j2ae.mjs} +43 -3
  347. package/dist/object-cache-Bok5j2ae.mjs.map +1 -0
  348. package/dist/{options-41nCWqi9.d.mts → options-iMpRRxIe.d.mts} +3 -3
  349. package/dist/{options-41nCWqi9.d.mts.map → options-iMpRRxIe.d.mts.map} +1 -1
  350. package/dist/page/index.d.mts +2 -2
  351. package/dist/{parse-BwAdS7FZ.mjs → parse-GmjecGct.mjs} +2 -2
  352. package/dist/{parse-BwAdS7FZ.mjs.map → parse-GmjecGct.mjs.map} +1 -1
  353. package/dist/{passkey-config-C0YfSBko.mjs → passkey-config-De0ahnRg.mjs} +1 -1
  354. package/dist/{passkey-config-C0YfSBko.mjs.map → passkey-config-De0ahnRg.mjs.map} +1 -1
  355. package/dist/{placeholder-Cuce9U-m.d.mts → placeholder-BSKwzRe4.d.mts} +1 -1
  356. package/dist/{placeholder-Cuce9U-m.d.mts.map → placeholder-BSKwzRe4.d.mts.map} +1 -1
  357. package/dist/plugin-types.d.mts +1 -1
  358. package/dist/plugin-utils.d.mts +10 -9
  359. package/dist/plugin-utils.d.mts.map +1 -1
  360. package/dist/plugins/adapt-sandbox-entry.d.mts +10 -9
  361. package/dist/plugins/adapt-sandbox-entry.d.mts.map +1 -1
  362. package/dist/plugins/adapt-sandbox-entry.mjs +2 -2
  363. package/dist/{portable-text-BICg8bTk.mjs → portable-text-cCa0cGV6.mjs} +1 -1
  364. package/dist/{portable-text-BICg8bTk.mjs.map → portable-text-cCa0cGV6.mjs.map} +1 -1
  365. package/dist/{preview-DKGCt2_p.mjs → preview-SSXNVPAC.mjs} +2 -2
  366. package/dist/{preview-DKGCt2_p.mjs.map → preview-SSXNVPAC.mjs.map} +1 -1
  367. package/dist/{public-url-CTVqgMmg.mjs → public-url-Danv47cS.mjs} +1 -1
  368. package/dist/{public-url-CTVqgMmg.mjs.map → public-url-Danv47cS.mjs.map} +1 -1
  369. package/dist/{query-BpQb-blG.mjs → query-ByGq6ver.mjs} +14 -14
  370. package/dist/{query-BpQb-blG.mjs.map → query-ByGq6ver.mjs.map} +1 -1
  371. package/dist/{rate-limit-Dap6HMNM.mjs → rate-limit-C_Lf63Dd.mjs} +2 -2
  372. package/dist/{rate-limit-Dap6HMNM.mjs.map → rate-limit-C_Lf63Dd.mjs.map} +1 -1
  373. package/dist/{redirect-CS-PHtNh.mjs → redirect-CoW3G-0U.mjs} +1 -1
  374. package/dist/{redirect-CS-PHtNh.mjs.map → redirect-CoW3G-0U.mjs.map} +1 -1
  375. package/dist/{redirect-_M0trWoo.mjs → redirect-IyfNirgS.mjs} +2 -2
  376. package/dist/{redirect-_M0trWoo.mjs.map → redirect-IyfNirgS.mjs.map} +1 -1
  377. package/dist/{redirects-w0V9vj_j.mjs → redirects-Bs1g42Ri.mjs} +4 -4
  378. package/dist/{redirects-w0V9vj_j.mjs.map → redirects-Bs1g42Ri.mjs.map} +1 -1
  379. package/dist/{redirects-Dcbuisoj.mjs → redirects-DXEXBAII.mjs} +2 -2
  380. package/dist/{redirects-Dcbuisoj.mjs.map → redirects-DXEXBAII.mjs.map} +1 -1
  381. package/dist/{registry-g8yYt4cC.mjs → registry-B65mUtPa.mjs} +122 -79
  382. package/dist/registry-B65mUtPa.mjs.map +1 -0
  383. package/dist/{request-meta-CmS1tDFf.mjs → request-meta-DbvXaAvU.mjs} +2 -2
  384. package/dist/{request-meta-CmS1tDFf.mjs.map → request-meta-DbvXaAvU.mjs.map} +1 -1
  385. package/dist/{resolve-C7I0qiR0.mjs → resolve-DR3wqMTy.mjs} +1 -1
  386. package/dist/{resolve-C7I0qiR0.mjs.map → resolve-DR3wqMTy.mjs.map} +1 -1
  387. package/dist/{runner-BbR3DfrL.d.mts → runner-DvFWoz8-.d.mts} +2 -2
  388. package/dist/{runner-BbR3DfrL.d.mts.map → runner-DvFWoz8-.d.mts.map} +1 -1
  389. package/dist/{runner-DPdt_Wpa.mjs → runner-K8XK101B.mjs} +351 -199
  390. package/dist/runner-K8XK101B.mjs.map +1 -0
  391. package/dist/runtime.d.mts +11 -10
  392. package/dist/runtime.d.mts.map +1 -1
  393. package/dist/runtime.mjs +2 -2
  394. package/dist/scheduled-publish-Drffrf2a.d.mts +11 -0
  395. package/dist/scheduled-publish-Drffrf2a.d.mts.map +1 -0
  396. package/dist/{schema-DoLd3j2e.mjs → schema-Blhoxp3P.mjs} +5 -5
  397. package/dist/{schema-DoLd3j2e.mjs.map → schema-Blhoxp3P.mjs.map} +1 -1
  398. package/dist/{search-BR0ZeZmh.mjs → search-DZN2HZ-V.mjs} +6 -4
  399. package/dist/search-DZN2HZ-V.mjs.map +1 -0
  400. package/dist/{secrets-BSf9pRRY.mjs → secrets-kp760LlD.mjs} +2 -2
  401. package/dist/{secrets-BSf9pRRY.mjs.map → secrets-kp760LlD.mjs.map} +1 -1
  402. package/dist/{sections-5J2YJPqJ.mjs → sections-CpF5SaGr.mjs} +3 -3
  403. package/dist/{sections-5J2YJPqJ.mjs.map → sections-CpF5SaGr.mjs.map} +1 -1
  404. package/dist/seed/index.d.mts +2 -2
  405. package/dist/seed/index.mjs +19 -18
  406. package/dist/seo/index.d.mts +1 -1
  407. package/dist/seo/index.mjs +1 -1
  408. package/dist/{seo-BkhuuaaE.mjs → seo-89-53DDs.mjs} +1 -1
  409. package/dist/{seo-BkhuuaaE.mjs.map → seo-89-53DDs.mjs.map} +1 -1
  410. package/dist/{seo-DKeXHkzE.mjs → seo-DXu2UQnC.mjs} +3 -3
  411. package/dist/{seo-DKeXHkzE.mjs.map → seo-DXu2UQnC.mjs.map} +1 -1
  412. package/dist/{service-BbO2s8gT.mjs → service-DQmiBMzt.mjs} +3 -3
  413. package/dist/{service-BbO2s8gT.mjs.map → service-DQmiBMzt.mjs.map} +1 -1
  414. package/dist/{session-user-B8aLtKAH.mjs → session-user-Cascbax7.mjs} +1 -1
  415. package/dist/{session-user-B8aLtKAH.mjs.map → session-user-Cascbax7.mjs.map} +1 -1
  416. package/dist/{settings-BMNr9Dmi.mjs → settings-rZyHEcNT.mjs} +3 -3
  417. package/dist/{settings-BMNr9Dmi.mjs.map → settings-rZyHEcNT.mjs.map} +1 -1
  418. package/dist/{settings-DJeki-97.mjs → settings-zhmdKyJQ.mjs} +5 -5
  419. package/dist/{settings-DJeki-97.mjs.map → settings-zhmdKyJQ.mjs.map} +1 -1
  420. package/dist/{setup-complete-gEiySUc-.mjs → setup-complete-Cb3LRyzy.mjs} +1 -1
  421. package/dist/{setup-complete-gEiySUc-.mjs.map → setup-complete-Cb3LRyzy.mjs.map} +1 -1
  422. package/dist/{setup-nonce-DzS50zme.mjs → setup-nonce-Z8x0tHf8.mjs} +1 -1
  423. package/dist/{setup-nonce-DzS50zme.mjs.map → setup-nonce-Z8x0tHf8.mjs.map} +1 -1
  424. package/dist/{single-flight-cache-Cdfkic3t.mjs → single-flight-cache-BG3B_GhN.mjs} +1 -1
  425. package/dist/{single-flight-cache-Cdfkic3t.mjs.map → single-flight-cache-BG3B_GhN.mjs.map} +1 -1
  426. package/dist/{site-url-BLebyON8.mjs → site-url-BBfDTgZB.mjs} +1 -1
  427. package/dist/{site-url-BLebyON8.mjs.map → site-url-BBfDTgZB.mjs.map} +1 -1
  428. package/dist/{ssrf-BRKb343l.mjs → ssrf-1g7usGBg.mjs} +1 -1
  429. package/dist/{ssrf-BRKb343l.mjs.map → ssrf-1g7usGBg.mjs.map} +1 -1
  430. package/dist/{status-vUK0SA17.mjs → status-CqJQX1QN.mjs} +1 -1
  431. package/dist/{status-vUK0SA17.mjs.map → status-CqJQX1QN.mjs.map} +1 -1
  432. package/dist/storage/local.d.mts +1 -1
  433. package/dist/storage/local.mjs +1 -1
  434. package/dist/storage/s3.d.mts +1 -1
  435. package/dist/storage/s3.mjs +1 -1
  436. package/dist/{taxonomies-CM_fUqLU.mjs → taxonomies-BGBd16Eu.mjs} +4 -4
  437. package/dist/{taxonomies-CM_fUqLU.mjs.map → taxonomies-BGBd16Eu.mjs.map} +1 -1
  438. package/dist/{taxonomies-D13i2ctt.mjs → taxonomies-Cnb4F-Pb.mjs} +7 -7
  439. package/dist/{taxonomies-D13i2ctt.mjs.map → taxonomies-Cnb4F-Pb.mjs.map} +1 -1
  440. package/dist/{taxonomy-BU0LjdVb.mjs → taxonomy-BxGxZZdu.mjs} +4 -4
  441. package/dist/{taxonomy-BU0LjdVb.mjs.map → taxonomy-BxGxZZdu.mjs.map} +1 -1
  442. package/dist/{tokens-LeuXF9gG.mjs → tokens-BGT0TUUo.mjs} +1 -1
  443. package/dist/{tokens-LeuXF9gG.mjs.map → tokens-BGT0TUUo.mjs.map} +1 -1
  444. package/dist/{transport-BZ-03aFT.d.mts → transport-BMDWHSgZ.d.mts} +1 -1
  445. package/dist/{transport-BZ-03aFT.d.mts.map → transport-BMDWHSgZ.d.mts.map} +1 -1
  446. package/dist/{transport-_2nBz7e9.mjs → transport-DPefPMcz.mjs} +1 -1
  447. package/dist/{transport-_2nBz7e9.mjs.map → transport-DPefPMcz.mjs.map} +1 -1
  448. package/dist/{trusted-proxy-DZY5WCn2.mjs → trusted-proxy-VTPRiX2s.mjs} +1 -1
  449. package/dist/{trusted-proxy-DZY5WCn2.mjs.map → trusted-proxy-VTPRiX2s.mjs.map} +1 -1
  450. package/dist/{types-ETmO_jQr.d.mts → types-BcLUUbbR.d.mts} +2 -2
  451. package/dist/{types-ETmO_jQr.d.mts.map → types-BcLUUbbR.d.mts.map} +1 -1
  452. package/dist/{types-BYnDBVwe.d.mts → types-CGbYowGQ.d.mts} +2 -2
  453. package/dist/{types-BYnDBVwe.d.mts.map → types-CGbYowGQ.d.mts.map} +1 -1
  454. package/dist/{types-BWqGVhFn.d.mts → types-CgvhU-hF.d.mts} +1 -1
  455. package/dist/{types-BWqGVhFn.d.mts.map → types-CgvhU-hF.d.mts.map} +1 -1
  456. package/dist/{types-fS7-VTdR.d.mts → types-ClUkdbWb.d.mts} +1 -1
  457. package/dist/{types-fS7-VTdR.d.mts.map → types-ClUkdbWb.d.mts.map} +1 -1
  458. package/dist/{types-CZgK3EMW.mjs → types-CuW0zWDA.mjs} +2 -2
  459. package/dist/{types-CZgK3EMW.mjs.map → types-CuW0zWDA.mjs.map} +1 -1
  460. package/dist/{types-BG8_XTLj.d.mts → types-DmHk7vAt.d.mts} +1 -1
  461. package/dist/{types-BG8_XTLj.d.mts.map → types-DmHk7vAt.d.mts.map} +1 -1
  462. package/dist/{types-CQAugunJ.mjs → types-Jo3UYd6b.mjs} +1 -1
  463. package/dist/{types-CQAugunJ.mjs.map → types-Jo3UYd6b.mjs.map} +1 -1
  464. package/dist/{types-xIfVRNLp.d.mts → types-_HFLRzTn.d.mts} +22 -1
  465. package/dist/types-_HFLRzTn.d.mts.map +1 -0
  466. package/dist/{types-DrYMm9s5.d.mts → types-ea9sAPck.d.mts} +1 -1
  467. package/dist/{types-DrYMm9s5.d.mts.map → types-ea9sAPck.d.mts.map} +1 -1
  468. package/dist/{types-CNlaBFzx.d.mts → types-g_aFIdW0.d.mts} +1 -1
  469. package/dist/{types-CNlaBFzx.d.mts.map → types-g_aFIdW0.d.mts.map} +1 -1
  470. package/dist/{types-CUsXGRVj.d.mts → types-vgEWF18A.d.mts} +19 -1
  471. package/dist/{types-CUsXGRVj.d.mts.map → types-vgEWF18A.d.mts.map} +1 -1
  472. package/dist/{user-DkG2jKCp.mjs → user-BjAOvU3Z.mjs} +3 -3
  473. package/dist/{user-DkG2jKCp.mjs.map → user-BjAOvU3Z.mjs.map} +1 -1
  474. package/dist/{utils-B7A57fm9.mjs → utils-BJXElxdw.mjs} +156 -7
  475. package/dist/utils-BJXElxdw.mjs.map +1 -0
  476. package/dist/{validate-CuJ1Ps9j.mjs → validate-CWSnKVIJ.mjs} +2 -2
  477. package/dist/{validate-CuJ1Ps9j.mjs.map → validate-CWSnKVIJ.mjs.map} +1 -1
  478. package/dist/{validate-CG0V0wNR.d.mts → validate-Z1b86_3B.d.mts} +11 -6
  479. package/dist/{validate-CG0V0wNR.d.mts.map → validate-Z1b86_3B.d.mts.map} +1 -1
  480. package/dist/{validation-CwUfTdGF.mjs → validation-c8WjhH8z.mjs} +8 -5
  481. package/dist/{validation-CwUfTdGF.mjs.map → validation-c8WjhH8z.mjs.map} +1 -1
  482. package/dist/version-CaccU7DM.mjs +7 -0
  483. package/dist/{version-BoNBItP_.mjs.map → version-CaccU7DM.mjs.map} +1 -1
  484. package/dist/{widgets-BfOZ-ajY.mjs → widgets-hWcIicX8.mjs} +3 -3
  485. package/dist/{widgets-BfOZ-ajY.mjs.map → widgets-hWcIicX8.mjs.map} +1 -1
  486. package/dist/wxr-taxonomies-0_uxSrmf.d.mts +34 -0
  487. package/dist/wxr-taxonomies-0_uxSrmf.d.mts.map +1 -0
  488. package/dist/wxr-taxonomies-BC3OYpvx.mjs +425 -0
  489. package/dist/wxr-taxonomies-BC3OYpvx.mjs.map +1 -0
  490. package/dist/{zod-generator-gFsRuNNy.mjs → zod-generator-CacrR-i8.mjs} +2 -2
  491. package/dist/{zod-generator-gFsRuNNy.mjs.map → zod-generator-CacrR-i8.mjs.map} +1 -1
  492. package/package.json +6 -6
  493. package/src/api/handlers/content.ts +69 -23
  494. package/src/api/handlers/plugins.ts +77 -10
  495. package/src/api/schemas/import.ts +19 -0
  496. package/src/astro/integration/runtime.ts +3 -6
  497. package/src/astro/integration/vite-config.ts +19 -1
  498. package/src/astro/middleware/auth.ts +10 -3
  499. package/src/astro/middleware/csp.ts +54 -3
  500. package/src/astro/middleware.ts +1 -0
  501. package/src/astro/routes/admin.astro +9 -0
  502. package/src/astro/routes/api/admin/plugins/[id]/disable.ts +6 -1
  503. package/src/astro/routes/api/admin/plugins/[id]/enable.ts +6 -1
  504. package/src/astro/routes/api/admin/plugins/[id]/index.ts +1 -0
  505. package/src/astro/routes/api/admin/plugins/index.ts +1 -0
  506. package/src/astro/routes/api/import/wordpress/rewrite-urls.ts +122 -98
  507. package/src/astro/routes/api/import/wordpress-plugin/execute.ts +794 -44
  508. package/src/astro/routes/api/manifest.ts +20 -1
  509. package/src/astro/routes/api/setup/dev-bypass.ts +7 -2
  510. package/src/astro/types.ts +4 -0
  511. package/src/cli/commands/seed.ts +1 -1
  512. package/src/components/EmDashImage.astro +59 -23
  513. package/src/components/Image.astro +36 -35
  514. package/src/components/LiveSearch.astro +40 -4
  515. package/src/components/live-search-routing.ts +30 -0
  516. package/src/database/migrations/036_i18n_menus_and_taxonomies.ts +23 -18
  517. package/src/database/migrations/048_restore_content_taxonomies_term_index.ts +32 -0
  518. package/src/database/migrations/049_taxonomies_name_locale_index.ts +42 -0
  519. package/src/database/migrations/050_media_usage_index_status.ts +142 -0
  520. package/src/database/migrations/runner.ts +6 -0
  521. package/src/database/repositories/media-usage.ts +932 -58
  522. package/src/database/types.ts +22 -0
  523. package/src/emdash-runtime.ts +123 -3
  524. package/src/import/comments.ts +159 -0
  525. package/src/import/index.ts +8 -1
  526. package/src/import/settings.ts +65 -189
  527. package/src/import/sources/wordpress-plugin.ts +338 -42
  528. package/src/import/sources/wxr.ts +4 -1
  529. package/src/import/types.ts +12 -0
  530. package/src/import/utils.ts +207 -0
  531. package/src/import/wxr-taxonomies.ts +39 -0
  532. package/src/loader.ts +13 -2
  533. package/src/media/usage/content-fields.ts +119 -0
  534. package/src/media/usage/content-refresh.ts +524 -0
  535. package/src/media/usage/content-repair.ts +491 -0
  536. package/src/media/usage/content-snapshots.ts +435 -0
  537. package/src/media/usage/extractor.ts +4 -4
  538. package/src/media/usage/source-key.ts +22 -0
  539. package/src/menus/index.ts +17 -1
  540. package/src/object-cache/index.ts +82 -7
  541. package/src/plugins/context.ts +100 -71
  542. package/src/schema/registry.ts +240 -154
  543. package/src/search/query.ts +3 -0
  544. package/src/search/types.ts +2 -0
  545. package/src/seed/apply.ts +158 -101
  546. package/src/seed/types.ts +6 -1
  547. package/dist/api-BMfveMoB.mjs.map +0 -1
  548. package/dist/apply--IVNSdXn.mjs.map +0 -1
  549. package/dist/byline-fields-eyJMblSr.mjs.map +0 -1
  550. package/dist/context-C_g-iJVA.mjs.map +0 -1
  551. package/dist/import-Bb1T9WJS.mjs.map +0 -1
  552. package/dist/index-BRNabKrx.d.mts.map +0 -1
  553. package/dist/index-Dt0OKJB4.d.mts.map +0 -1
  554. package/dist/loader-BA_zhkS_.mjs.map +0 -1
  555. package/dist/object-cache-CHbHv83-.mjs.map +0 -1
  556. package/dist/registry-g8yYt4cC.mjs.map +0 -1
  557. package/dist/runner-DPdt_Wpa.mjs.map +0 -1
  558. package/dist/search-BR0ZeZmh.mjs.map +0 -1
  559. package/dist/types-xIfVRNLp.d.mts.map +0 -1
  560. package/dist/utils-B7A57fm9.mjs.map +0 -1
  561. package/dist/version-BoNBItP_.mjs +0 -7
  562. /package/dist/{api-tokens-B4BQybOp.mjs → api-tokens-DsvvCtdh.mjs} +0 -0
  563. /package/dist/{ssrf-CcX9zvMK.mjs → ssrf-CmuGgCq3.mjs} +0 -0
  564. /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,106 @@ 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) => {
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;
202
499
  await trx.deleteFrom("_emdash_media_usage").where("source_key", "=", sourceKey).execute();
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) => {
514
+ const result = await trx
515
+ .deleteFrom("_emdash_media_usage_sources")
516
+ .where("source_key", "=", sourceKey)
517
+ .where(this.sourceMatchExpression(expectedSource))
518
+ .executeTakeFirst();
519
+ deleted = Number(result.numDeletedRows ?? 0) > 0;
520
+ if (!deleted) return;
521
+ await trx.deleteFrom("_emdash_media_usage").where("source_key", "=", sourceKey).execute();
522
+ });
523
+
524
+ return {
525
+ deleted,
526
+ source: await this.findSource(sourceKey),
527
+ };
528
+ }
529
+
530
+ async deleteSourceIfMatchingContentAbsent(
531
+ sourceKey: string,
532
+ expectedSource: MediaUsageSource,
533
+ collectionSlug: string,
534
+ contentId: string,
535
+ ): Promise<MediaUsageGuardedAbsentDeleteResult> {
536
+ validateIdentifier(collectionSlug, "collection slug");
537
+ const tableName = `ec_${collectionSlug}`;
538
+ let deleted = false;
539
+ await withTransaction(this.db, async (trx) => {
203
540
  const result = await trx
204
541
  .deleteFrom("_emdash_media_usage_sources")
205
542
  .where("source_key", "=", sourceKey)
543
+ .where(this.sourceMatchExpression(expectedSource))
544
+ .where(
545
+ sql<boolean>`NOT EXISTS (SELECT 1 FROM ${sql.ref(tableName)} WHERE id = ${contentId})`,
546
+ )
206
547
  .executeTakeFirst();
207
- return Number(result.numDeletedRows ?? 0);
548
+ deleted = Number(result.numDeletedRows ?? 0) > 0;
549
+ if (!deleted) return;
550
+ await trx.deleteFrom("_emdash_media_usage").where("source_key", "=", sourceKey).execute();
208
551
  });
552
+ const contentPresent = deleted ? false : await this.contentRowExists(tableName, contentId);
553
+
554
+ return {
555
+ deleted,
556
+ contentPresent,
557
+ source: deleted || contentPresent ? null : await this.findSource(sourceKey),
558
+ };
559
+ }
560
+
561
+ async deleteSources(sourceKeys: readonly string[]): Promise<number> {
562
+ return this.deleteSourceKeys(sourceKeys);
209
563
  }
210
564
 
211
565
  async deleteContentSources(collectionSlug: string, contentId: string): Promise<number> {
@@ -217,20 +571,333 @@ export class MediaUsageRepository {
217
571
  .where("content_id", "=", contentId)
218
572
  .execute();
219
573
  const sourceKeys = sourceRows.map((row) => row.source_key);
220
- if (sourceKeys.length === 0) return 0;
574
+ return this.deleteSourceKeys(sourceKeys);
575
+ }
576
+
577
+ async deleteCollectionSources(collectionSlug: string): Promise<number> {
578
+ let deleted = 0;
579
+ while (true) {
580
+ const sourceRows = await this.db
581
+ .selectFrom("_emdash_media_usage_sources")
582
+ .select("source_key")
583
+ .where("source_type", "=", "content")
584
+ .where("collection_slug", "=", collectionSlug)
585
+ .orderBy("source_key", "asc")
586
+ .limit(SQL_BATCH_SIZE)
587
+ .execute();
588
+ if (sourceRows.length === 0) break;
589
+
590
+ deleted += await this.deleteSourceKeys(sourceRows.map((row) => row.source_key));
591
+ }
592
+ return deleted;
593
+ }
594
+
595
+ async findCollectionContentSources(collectionSlug: string): Promise<MediaUsageSource[]> {
596
+ const rows = await this.db
597
+ .selectFrom("_emdash_media_usage_sources")
598
+ .selectAll()
599
+ .where("source_type", "=", "content")
600
+ .where("collection_slug", "=", collectionSlug)
601
+ .orderBy("source_key", "asc")
602
+ .execute();
603
+ return rows.map((row) => rowToSource(row));
604
+ }
605
+
606
+ async deleteOrphanOccurrencesOlderThan(cutoff: string, limit: number): Promise<number> {
607
+ const batchLimit = Math.floor(limit);
608
+ if (batchLimit <= 0) return 0;
609
+
610
+ const rows = await this.db
611
+ .selectFrom("_emdash_media_usage as u")
612
+ .leftJoin("_emdash_media_usage_sources as s", (join) =>
613
+ join.onRef("s.source_key", "=", "u.source_key"),
614
+ )
615
+ .select("u.id")
616
+ .where("s.source_key", "is", null)
617
+ .where("u.created_at", "<", cutoff)
618
+ .orderBy("u.created_at", "asc")
619
+ .orderBy("u.id", "asc")
620
+ .limit(batchLimit)
621
+ .execute();
622
+
623
+ let deleted = 0;
624
+ for (const idBatch of chunks(
625
+ rows.map((row) => row.id),
626
+ SQL_BATCH_SIZE,
627
+ )) {
628
+ const result = await this.db
629
+ .deleteFrom("_emdash_media_usage")
630
+ .where("id", "in", idBatch)
631
+ .where("created_at", "<", cutoff)
632
+ .where(
633
+ sql<boolean>`NOT EXISTS (SELECT 1 FROM _emdash_media_usage_sources s WHERE s.source_key = _emdash_media_usage.source_key)`,
634
+ )
635
+ .executeTakeFirst();
636
+ deleted += Number(result.numDeletedRows ?? 0);
637
+ }
638
+ return deleted;
639
+ }
640
+
641
+ async deleteStaleGenerationsOlderThan(cutoff: string, limit: number): Promise<number> {
642
+ const batchLimit = Math.floor(limit);
643
+ if (batchLimit <= 0) return 0;
644
+
645
+ const rows = await this.db
646
+ .selectFrom("_emdash_media_usage as u")
647
+ .innerJoin("_emdash_media_usage_sources as s", (join) =>
648
+ join.onRef("s.source_key", "=", "u.source_key"),
649
+ )
650
+ .select("u.id")
651
+ .where("u.created_at", "<", cutoff)
652
+ .whereRef("u.generation", "!=", "s.current_generation")
653
+ .whereRef("u.created_at", "<", "s.indexed_at")
654
+ .orderBy("u.created_at", "asc")
655
+ .orderBy("u.id", "asc")
656
+ .limit(batchLimit)
657
+ .execute();
658
+
659
+ const ids = rows.map((row) => row.id);
660
+ if (ids.length === 0) return 0;
661
+
662
+ let deleted = 0;
663
+ for (const idBatch of chunks(ids, SQL_BATCH_SIZE)) {
664
+ const result = await this.db
665
+ .deleteFrom("_emdash_media_usage")
666
+ .where("id", "in", idBatch)
667
+ .where("created_at", "<", cutoff)
668
+ .where((eb) =>
669
+ eb.exists(
670
+ eb
671
+ .selectFrom("_emdash_media_usage_sources as s")
672
+ .select("s.source_key")
673
+ .whereRef("s.source_key", "=", "_emdash_media_usage.source_key")
674
+ .whereRef("s.current_generation", "!=", "_emdash_media_usage.generation")
675
+ .whereRef("_emdash_media_usage.created_at", "<", "s.indexed_at"),
676
+ ),
677
+ )
678
+ .executeTakeFirst();
679
+ deleted += Number(result.numDeletedRows ?? 0);
680
+ }
681
+ return deleted;
682
+ }
683
+
684
+ async deleteAbandonedGenerationsOlderThan(cutoff: string, limit: number): Promise<number> {
685
+ const batchLimit = Math.floor(limit);
686
+ if (batchLimit <= 0) return 0;
687
+
688
+ const rows = await this.db
689
+ .selectFrom("_emdash_media_usage as u")
690
+ .innerJoin("_emdash_media_usage_sources as s", (join) =>
691
+ join.onRef("s.source_key", "=", "u.source_key"),
692
+ )
693
+ .select("u.id")
694
+ .where("u.created_at", "<", cutoff)
695
+ .whereRef("u.generation", "!=", "s.current_generation")
696
+ .whereRef("u.created_at", ">=", "s.indexed_at")
697
+ .orderBy("u.created_at", "asc")
698
+ .orderBy("u.id", "asc")
699
+ .limit(batchLimit)
700
+ .execute();
701
+
702
+ let deleted = 0;
703
+ for (const idBatch of chunks(
704
+ rows.map((row) => row.id),
705
+ SQL_BATCH_SIZE,
706
+ )) {
707
+ const result = await this.db
708
+ .deleteFrom("_emdash_media_usage")
709
+ .where("id", "in", idBatch)
710
+ .where("created_at", "<", cutoff)
711
+ .where((eb) =>
712
+ eb.exists(
713
+ eb
714
+ .selectFrom("_emdash_media_usage_sources as s")
715
+ .select("s.source_key")
716
+ .whereRef("s.source_key", "=", "_emdash_media_usage.source_key")
717
+ .whereRef("s.current_generation", "!=", "_emdash_media_usage.generation")
718
+ .whereRef("_emdash_media_usage.created_at", ">=", "s.indexed_at"),
719
+ ),
720
+ )
721
+ .executeTakeFirst();
722
+ deleted += Number(result.numDeletedRows ?? 0);
723
+ }
724
+ return deleted;
725
+ }
726
+
727
+ async upsertIndexStatus(input: MediaUsageIndexStatusInput): Promise<MediaUsageIndexStatus> {
728
+ const now = input.updatedAt ?? new Date().toISOString();
729
+ const row = {
730
+ adapter_id: input.adapterId,
731
+ scope_type: input.scopeType,
732
+ scope_key: input.scopeKey,
733
+ status: input.status,
734
+ schema_version: input.schemaVersion ?? 1,
735
+ started_at: input.startedAt ?? null,
736
+ completed_at: input.completedAt ?? null,
737
+ cursor: input.cursor ?? null,
738
+ indexed_source_count: input.indexedSourceCount ?? 0,
739
+ failed_source_count: input.failedSourceCount ?? 0,
740
+ last_error_code: input.lastErrorCode ?? null,
741
+ updated_at: now,
742
+ };
743
+
744
+ await this.db
745
+ .insertInto("_emdash_media_usage_index_status")
746
+ .values(row)
747
+ .onConflict((oc) =>
748
+ oc.columns(["adapter_id", "scope_type", "scope_key"]).doUpdateSet({
749
+ status: row.status,
750
+ schema_version: row.schema_version,
751
+ started_at: row.started_at,
752
+ completed_at: row.completed_at,
753
+ cursor: row.cursor,
754
+ indexed_source_count: row.indexed_source_count,
755
+ failed_source_count: row.failed_source_count,
756
+ last_error_code: row.last_error_code,
757
+ updated_at: row.updated_at,
758
+ }),
759
+ )
760
+ .execute();
761
+
762
+ const status = await this.findIndexStatus(input);
763
+ if (!status) {
764
+ throw new Error(
765
+ `Media usage index status ${input.adapterId}:${input.scopeType}:${input.scopeKey} was not persisted`,
766
+ );
767
+ }
768
+ return status;
769
+ }
770
+
771
+ async beginIndexStatusRepair(
772
+ input: MediaUsageIndexStatusRepairInput,
773
+ ): Promise<MediaUsageIndexStatus> {
774
+ return this.upsertIndexStatus({
775
+ adapterId: input.adapterId,
776
+ scopeType: input.scopeType,
777
+ scopeKey: input.scopeKey,
778
+ status: "running",
779
+ schemaVersion: input.schemaVersion,
780
+ startedAt: input.startedAt,
781
+ completedAt: null,
782
+ cursor: input.runToken,
783
+ indexedSourceCount: 0,
784
+ failedSourceCount: 0,
785
+ lastErrorCode: null,
786
+ updatedAt: input.updatedAt,
787
+ });
788
+ }
789
+
790
+ async finalizeIndexStatusRepairIfRunning(
791
+ input: MediaUsageIndexStatusFinalizeInput,
792
+ ): Promise<MediaUsageGuardedIndexStatusResult> {
793
+ const updates: Updateable<MediaUsageIndexStatusTable> = {
794
+ status: input.status,
795
+ completed_at: input.completedAt,
796
+ cursor: null,
797
+ indexed_source_count: input.indexedSourceCount ?? 0,
798
+ failed_source_count: input.failedSourceCount ?? 0,
799
+ last_error_code: input.lastErrorCode ?? null,
800
+ updated_at: input.updatedAt ?? new Date().toISOString(),
801
+ };
802
+ if (input.schemaVersion !== undefined) updates.schema_version = input.schemaVersion;
803
+
804
+ const result = await this.db
805
+ .updateTable("_emdash_media_usage_index_status")
806
+ .set(updates)
807
+ .where("adapter_id", "=", input.adapterId)
808
+ .where("scope_type", "=", input.scopeType)
809
+ .where("scope_key", "=", input.scopeKey)
810
+ .where("status", "=", "running")
811
+ .where("cursor", "=", input.runToken)
812
+ .executeTakeFirst();
813
+ const finalized = Number(result.numUpdatedRows ?? 0) > 0;
814
+
815
+ return {
816
+ finalized,
817
+ status: await this.findIndexStatus(input),
818
+ };
819
+ }
820
+
821
+ async findIndexStatus(
822
+ identity: MediaUsageIndexStatusIdentity,
823
+ ): Promise<MediaUsageIndexStatus | null> {
824
+ const row = await this.db
825
+ .selectFrom("_emdash_media_usage_index_status")
826
+ .selectAll()
827
+ .where("adapter_id", "=", identity.adapterId)
828
+ .where("scope_type", "=", identity.scopeType)
829
+ .where("scope_key", "=", identity.scopeKey)
830
+ .executeTakeFirst();
831
+
832
+ return row ? rowToIndexStatus(row) : null;
833
+ }
834
+
835
+ async deleteIndexStatus(identity: MediaUsageIndexStatusIdentity): Promise<number> {
836
+ const result = await this.db
837
+ .deleteFrom("_emdash_media_usage_index_status")
838
+ .where("adapter_id", "=", identity.adapterId)
839
+ .where("scope_type", "=", identity.scopeType)
840
+ .where("scope_key", "=", identity.scopeKey)
841
+ .executeTakeFirst();
842
+ return Number(result.numDeletedRows ?? 0);
843
+ }
844
+
845
+ private async findCurrentUsagePage(
846
+ applyFilter: (
847
+ query: ReturnType<MediaUsageRepository["currentUsageBaseQuery"]>,
848
+ ) => ReturnType<MediaUsageRepository["currentUsageBaseQuery"]>,
849
+ options: FindMediaUsageOptions,
850
+ ): Promise<FindManyResult<MediaUsageRecord>> {
851
+ const limit = Math.min(Math.max(1, options.limit ?? 50), 100);
852
+ let query = applyFilter(this.currentUsageBaseQuery())
853
+ .orderBy("u.id", "asc")
854
+ .limit(limit + 1);
855
+
856
+ if (options.cursor) {
857
+ const { id } = decodeCursor(options.cursor);
858
+ query = query.where("u.id", ">", id);
859
+ }
860
+
861
+ const rows = await query.execute();
862
+ const items = rows.slice(0, limit).map(rowToUsageRecord);
863
+ const result: FindManyResult<MediaUsageRecord> = { items };
864
+
865
+ if (rows.length > limit && items.length > 0) {
866
+ const last = items.at(-1)!;
867
+ result.nextCursor = encodeCursor(last.occurrence.id, last.occurrence.id);
868
+ }
869
+
870
+ return result;
871
+ }
872
+
873
+ private currentUsageBaseQuery() {
874
+ return this.db
875
+ .selectFrom("_emdash_media_usage_sources as s")
876
+ .innerJoin("_emdash_media_usage as u", (join) =>
877
+ join
878
+ .onRef("u.source_key", "=", "s.source_key")
879
+ .onRef("u.generation", "=", "s.current_generation"),
880
+ )
881
+ .select(currentUsageSelect);
882
+ }
883
+
884
+ private async deleteSourceKeys(sourceKeys: readonly string[]): Promise<number> {
885
+ const uniqueSourceKeys = [...new Set(sourceKeys)];
886
+ if (uniqueSourceKeys.length === 0) return 0;
221
887
 
222
888
  return withTransaction(this.db, async (trx) => {
223
889
  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();
890
+ for (const sourceKeyBatch of chunks(uniqueSourceKeys, SQL_BATCH_SIZE)) {
229
891
  const result = await trx
230
892
  .deleteFrom("_emdash_media_usage_sources")
231
893
  .where("source_key", "in", sourceKeyBatch)
232
894
  .executeTakeFirst();
233
895
  deleted += Number(result.numDeletedRows ?? 0);
896
+
897
+ await trx
898
+ .deleteFrom("_emdash_media_usage")
899
+ .where("source_key", "in", sourceKeyBatch)
900
+ .execute();
234
901
  }
235
902
  return deleted;
236
903
  });
@@ -241,6 +908,7 @@ export class MediaUsageRepository {
241
908
  sourceKey: string,
242
909
  generation: string,
243
910
  occurrences: readonly MediaUsageOccurrenceInput[],
911
+ now: string,
244
912
  ): Promise<void> {
245
913
  if (occurrences.length === 0) return;
246
914
 
@@ -257,6 +925,7 @@ export class MediaUsageRepository {
257
925
  provider_asset_id: occurrence.providerAssetId,
258
926
  media_kind: occurrence.mediaKind ?? null,
259
927
  mime_type: occurrence.mimeType ?? null,
928
+ created_at: now,
260
929
  }));
261
930
 
262
931
  for (const rowBatch of chunks(rows, OCCURRENCE_INSERT_BATCH_SIZE)) {
@@ -270,7 +939,113 @@ export class MediaUsageRepository {
270
939
  generation: string,
271
940
  now: string,
272
941
  ): Promise<void> {
273
- const row = {
942
+ const row = this.buildSourceRow(source, generation, now);
943
+
944
+ await db
945
+ .insertInto("_emdash_media_usage_sources")
946
+ .values(row)
947
+ .onConflict((oc) => oc.column("source_key").doUpdateSet(this.sourceUpdateSet(row)))
948
+ .execute();
949
+ }
950
+
951
+ private async insertSourceIfAbsent(
952
+ db: DatabaseExecutor,
953
+ row: Insertable<MediaUsageSourceTable>,
954
+ ): Promise<boolean> {
955
+ const result = await db
956
+ .insertInto("_emdash_media_usage_sources")
957
+ .values(row)
958
+ .onConflict((oc) => oc.column("source_key").doNothing())
959
+ .executeTakeFirst();
960
+ return (result.numInsertedOrUpdatedRows ?? 0n) > 0n;
961
+ }
962
+
963
+ private async updateSourceIfGeneration(
964
+ db: DatabaseExecutor,
965
+ row: ReturnType<MediaUsageRepository["buildSourceRow"]>,
966
+ expectedCurrentGeneration: string,
967
+ ): Promise<boolean> {
968
+ const result = await db
969
+ .updateTable("_emdash_media_usage_sources")
970
+ .set(this.sourceUpdateSet(row))
971
+ .where("source_key", "=", row.source_key)
972
+ .where("current_generation", "=", expectedCurrentGeneration)
973
+ .executeTakeFirst();
974
+ return Number(result.numUpdatedRows ?? 0) > 0;
975
+ }
976
+
977
+ private async updateSourceIfMatching(
978
+ db: DatabaseExecutor,
979
+ row: ReturnType<MediaUsageRepository["buildSourceRow"]>,
980
+ expectedSource: MediaUsageSource,
981
+ ): Promise<boolean> {
982
+ const result = await db
983
+ .updateTable("_emdash_media_usage_sources")
984
+ .set(this.sourceUpdateSet(row))
985
+ .where("source_key", "=", row.source_key)
986
+ .where(this.sourceMatchExpression(expectedSource))
987
+ .executeTakeFirst();
988
+ return Number(result.numUpdatedRows ?? 0) > 0;
989
+ }
990
+
991
+ private async updateAttemptedSourceIfMatching(
992
+ db: DatabaseExecutor,
993
+ source: MediaUsageSourceInput,
994
+ row: ReturnType<MediaUsageRepository["buildAttemptedSourceRow"]>,
995
+ expectedSource: MediaUsageSource,
996
+ ): Promise<boolean> {
997
+ const result = await db
998
+ .updateTable("_emdash_media_usage_sources")
999
+ .set(this.attemptedSourceUpdateSet(source, row))
1000
+ .where("source_key", "=", row.source_key)
1001
+ .where(this.sourceMatchExpression(expectedSource))
1002
+ .executeTakeFirst();
1003
+ return Number(result.numUpdatedRows ?? 0) > 0;
1004
+ }
1005
+
1006
+ private sourceMatchExpression(expectedSource: MediaUsageSource) {
1007
+ return (eb: ExpressionBuilder<Database, "_emdash_media_usage_sources">) =>
1008
+ eb.and([
1009
+ eb("current_generation", "=", expectedSource.currentGeneration),
1010
+ eb("source_completeness", "=", expectedSource.sourceCompleteness),
1011
+ this.nullableStringExpression(eb, "updated_at", expectedSource.updatedAt),
1012
+ this.nullableStringExpression(eb, "source_fingerprint", expectedSource.sourceFingerprint),
1013
+ this.nullableStringExpression(eb, "source_updated_at", expectedSource.sourceUpdatedAt),
1014
+ this.nullableNumberExpression(eb, "source_version", expectedSource.sourceVersion),
1015
+ this.nullableStringExpression(eb, "revision_id", expectedSource.revisionId),
1016
+ this.nullableStringExpression(eb, "last_attempted_at", expectedSource.lastAttemptedAt),
1017
+ this.nullableStringExpression(eb, "last_error_code", expectedSource.lastErrorCode),
1018
+ ]);
1019
+ }
1020
+
1021
+ private nullableStringExpression(
1022
+ eb: ExpressionBuilder<Database, "_emdash_media_usage_sources">,
1023
+ column: MediaUsageSourceNullableStringColumn,
1024
+ value: string | null,
1025
+ ) {
1026
+ return value === null ? eb(column, "is", null) : eb(column, "=", value);
1027
+ }
1028
+
1029
+ private nullableNumberExpression(
1030
+ eb: ExpressionBuilder<Database, "_emdash_media_usage_sources">,
1031
+ column: "source_version",
1032
+ value: number | null,
1033
+ ) {
1034
+ return value === null ? eb(column, "is", null) : eb(column, "=", value);
1035
+ }
1036
+
1037
+ private async contentRowExists(tableName: string, contentId: string): Promise<boolean> {
1038
+ const result = await sql<{ id: string }>`
1039
+ SELECT id
1040
+ FROM ${sql.ref(tableName)}
1041
+ WHERE id = ${contentId}
1042
+ LIMIT 1
1043
+ `.execute(this.db);
1044
+ return result.rows.length > 0;
1045
+ }
1046
+
1047
+ private buildSourceRow(source: MediaUsageSourceInput, generation: string, now: string) {
1048
+ return {
274
1049
  source_key: source.sourceKey,
275
1050
  source_type: source.sourceType,
276
1051
  collection_slug: source.collectionSlug ?? null,
@@ -286,46 +1061,110 @@ export class MediaUsageRepository {
286
1061
  revision_id: source.revisionId ?? null,
287
1062
  current_generation: generation,
288
1063
  schema_version: source.schemaVersion ?? 1,
1064
+ source_updated_at: source.sourceUpdatedAt ?? null,
1065
+ source_version: source.sourceVersion ?? null,
1066
+ source_fingerprint: source.sourceFingerprint ?? null,
1067
+ // Complete means this source was fully refreshed for the extractor's current
1068
+ // schema/version coverage, not that every possible reference shape is known.
1069
+ source_completeness: source.sourceCompleteness ?? "complete",
1070
+ last_attempted_at: source.lastAttemptedAt ?? now,
1071
+ last_error_code: null,
289
1072
  indexed_at: now,
290
1073
  updated_at: now,
291
1074
  };
1075
+ }
292
1076
 
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();
1077
+ private buildAttemptedSourceRow(source: MediaUsageSourceInput, now: string) {
1078
+ return {
1079
+ source_key: source.sourceKey,
1080
+ source_type: source.sourceType,
1081
+ collection_slug: source.collectionSlug ?? null,
1082
+ content_id: source.contentId ?? null,
1083
+ source_variant: source.sourceVariant,
1084
+ locale: source.locale ?? null,
1085
+ translation_group: source.translationGroup ?? null,
1086
+ content_slug: source.contentSlug ?? null,
1087
+ content_title: source.contentTitle ?? null,
1088
+ content_status: source.contentStatus ?? null,
1089
+ content_scheduled_at: source.contentScheduledAt ?? null,
1090
+ content_deleted_at: source.contentDeletedAt ?? null,
1091
+ revision_id: source.revisionId ?? null,
1092
+ current_generation: ulid(),
1093
+ schema_version: source.schemaVersion ?? 1,
1094
+ source_updated_at: source.sourceUpdatedAt ?? null,
1095
+ source_version: source.sourceVersion ?? null,
1096
+ source_fingerprint: source.sourceFingerprint ?? null,
1097
+ source_completeness:
1098
+ source.sourceCompleteness ?? (source.lastErrorCode ? "failed" : "unknown"),
1099
+ last_attempted_at: source.lastAttemptedAt ?? now,
1100
+ last_error_code: source.lastErrorCode ?? null,
1101
+ indexed_at: now,
1102
+ updated_at: now,
1103
+ };
317
1104
  }
318
1105
 
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();
1106
+ private attemptedSourceUpdateSet(
1107
+ source: MediaUsageSourceInput,
1108
+ row: ReturnType<MediaUsageRepository["buildAttemptedSourceRow"]>,
1109
+ ): Updateable<MediaUsageSourceTable> {
1110
+ const updates: Updateable<MediaUsageSourceTable> = {
1111
+ source_type: row.source_type,
1112
+ source_variant: row.source_variant,
1113
+ source_completeness: row.source_completeness,
1114
+ last_attempted_at: row.last_attempted_at,
1115
+ last_error_code: row.last_error_code,
1116
+ updated_at: row.updated_at,
1117
+ };
1118
+
1119
+ if (source.collectionSlug !== undefined) updates.collection_slug = row.collection_slug;
1120
+ if (source.contentId !== undefined) updates.content_id = row.content_id;
1121
+ if (source.locale !== undefined) updates.locale = row.locale;
1122
+ if (source.translationGroup !== undefined) updates.translation_group = row.translation_group;
1123
+ if (source.contentSlug !== undefined) updates.content_slug = row.content_slug;
1124
+ if (source.contentTitle !== undefined) updates.content_title = row.content_title;
1125
+ if (source.contentStatus !== undefined) updates.content_status = row.content_status;
1126
+ if (source.contentScheduledAt !== undefined) {
1127
+ updates.content_scheduled_at = row.content_scheduled_at;
1128
+ }
1129
+ if (source.contentDeletedAt !== undefined) updates.content_deleted_at = row.content_deleted_at;
1130
+ if (source.revisionId !== undefined) updates.revision_id = row.revision_id;
1131
+ if (source.schemaVersion !== undefined) updates.schema_version = row.schema_version;
1132
+ if (source.sourceUpdatedAt !== undefined) updates.source_updated_at = row.source_updated_at;
1133
+ if (source.sourceVersion !== undefined) updates.source_version = row.source_version;
1134
+ if (source.sourceFingerprint !== undefined) {
1135
+ updates.source_fingerprint = row.source_fingerprint;
1136
+ }
1137
+
1138
+ return updates;
1139
+ }
1140
+
1141
+ private sourceUpdateSet(
1142
+ row: ReturnType<MediaUsageRepository["buildSourceRow"]>,
1143
+ ): Updateable<MediaUsageSourceTable> {
1144
+ return {
1145
+ source_type: row.source_type,
1146
+ collection_slug: row.collection_slug,
1147
+ content_id: row.content_id,
1148
+ source_variant: row.source_variant,
1149
+ locale: row.locale,
1150
+ translation_group: row.translation_group,
1151
+ content_slug: row.content_slug,
1152
+ content_title: row.content_title,
1153
+ content_status: row.content_status,
1154
+ content_scheduled_at: row.content_scheduled_at,
1155
+ content_deleted_at: row.content_deleted_at,
1156
+ revision_id: row.revision_id,
1157
+ current_generation: row.current_generation,
1158
+ schema_version: row.schema_version,
1159
+ source_updated_at: row.source_updated_at,
1160
+ source_version: row.source_version,
1161
+ source_fingerprint: row.source_fingerprint,
1162
+ source_completeness: row.source_completeness,
1163
+ last_attempted_at: row.last_attempted_at,
1164
+ last_error_code: row.last_error_code,
1165
+ indexed_at: row.indexed_at,
1166
+ updated_at: row.updated_at,
1167
+ };
329
1168
  }
330
1169
  }
331
1170
 
@@ -345,9 +1184,15 @@ const currentUsageSelect = [
345
1184
  "s.revision_id as revision_id",
346
1185
  "s.current_generation as current_generation",
347
1186
  "s.schema_version as schema_version",
1187
+ "s.source_updated_at as source_updated_at",
1188
+ "s.source_version as source_version",
1189
+ "s.source_fingerprint as source_fingerprint",
1190
+ "s.source_completeness as source_completeness",
1191
+ "s.last_attempted_at as last_attempted_at",
1192
+ "s.last_error_code as last_error_code",
348
1193
  "s.indexed_at as indexed_at",
349
1194
  "s.created_at as source_created_at",
350
- "s.updated_at as source_updated_at",
1195
+ "s.updated_at as source_row_updated_at",
351
1196
  "u.id as occurrence_id",
352
1197
  "u.generation as generation",
353
1198
  "u.field_slug as field_slug",
@@ -362,7 +1207,7 @@ const currentUsageSelect = [
362
1207
  "u.created_at as occurrence_created_at",
363
1208
  ] as const;
364
1209
 
365
- function rowToSource(row: Selectable<MediaUsageSourceTable>): MediaUsageSource {
1210
+ function rowToSource(row: MediaUsageSourceRow): MediaUsageSource {
366
1211
  return {
367
1212
  sourceKey: row.source_key,
368
1213
  sourceType: row.source_type,
@@ -379,6 +1224,12 @@ function rowToSource(row: Selectable<MediaUsageSourceTable>): MediaUsageSource {
379
1224
  revisionId: row.revision_id,
380
1225
  currentGeneration: row.current_generation,
381
1226
  schemaVersion: Number(row.schema_version),
1227
+ sourceUpdatedAt: row.source_updated_at,
1228
+ sourceVersion: row.source_version === null ? null : Number(row.source_version),
1229
+ sourceFingerprint: row.source_fingerprint,
1230
+ sourceCompleteness: row.source_completeness,
1231
+ lastAttemptedAt: row.last_attempted_at,
1232
+ lastErrorCode: row.last_error_code,
382
1233
  indexedAt: row.indexed_at,
383
1234
  createdAt: row.created_at,
384
1235
  updatedAt: row.updated_at,
@@ -421,9 +1272,15 @@ function rowToUsageRecord(row: JoinedUsageRow): MediaUsageRecord {
421
1272
  revision_id: row.revision_id,
422
1273
  current_generation: row.current_generation,
423
1274
  schema_version: row.schema_version,
1275
+ source_updated_at: row.source_updated_at,
1276
+ source_version: row.source_version,
1277
+ source_fingerprint: row.source_fingerprint,
1278
+ source_completeness: row.source_completeness,
1279
+ last_attempted_at: row.last_attempted_at,
1280
+ last_error_code: row.last_error_code,
424
1281
  indexed_at: row.indexed_at,
425
1282
  created_at: row.source_created_at,
426
- updated_at: row.source_updated_at,
1283
+ updated_at: row.source_row_updated_at,
427
1284
  }),
428
1285
  occurrence: rowToOccurrence({
429
1286
  id: row.occurrence_id,
@@ -442,3 +1299,20 @@ function rowToUsageRecord(row: JoinedUsageRow): MediaUsageRecord {
442
1299
  }),
443
1300
  };
444
1301
  }
1302
+
1303
+ function rowToIndexStatus(row: Selectable<MediaUsageIndexStatusTable>): MediaUsageIndexStatus {
1304
+ return {
1305
+ adapterId: row.adapter_id,
1306
+ scopeType: row.scope_type,
1307
+ scopeKey: row.scope_key,
1308
+ status: row.status,
1309
+ schemaVersion: Number(row.schema_version),
1310
+ startedAt: row.started_at,
1311
+ completedAt: row.completed_at,
1312
+ cursor: row.cursor,
1313
+ indexedSourceCount: Number(row.indexed_source_count),
1314
+ failedSourceCount: Number(row.failed_source_count),
1315
+ lastErrorCode: row.last_error_code,
1316
+ updatedAt: row.updated_at,
1317
+ };
1318
+ }