emdash 0.35.0 → 0.36.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/activation-K0kGBWuJ.mjs +382 -0
- package/dist/activation-K0kGBWuJ.mjs.map +1 -0
- package/dist/{adapters-Bb1vG41D.d.mts → adapters-CzL3H752.d.mts} +3 -3
- package/dist/{adapters-Bb1vG41D.d.mts.map → adapters-CzL3H752.d.mts.map} +1 -1
- package/dist/{allowed-origins-DW7sYyqg.mjs → allowed-origins-maylGaHv.mjs} +2 -2
- package/dist/{allowed-origins-DW7sYyqg.mjs.map → allowed-origins-maylGaHv.mjs.map} +1 -1
- package/dist/api/route-utils.d.mts +3 -3
- package/dist/api/route-utils.mjs +22 -20
- package/dist/api/route-utils.mjs.map +1 -1
- package/dist/api/schemas/index.d.mts +2 -2
- package/dist/api/schemas/index.mjs +5 -5
- package/dist/api-B0w3uBiG.mjs +2269 -0
- package/dist/api-B0w3uBiG.mjs.map +1 -0
- package/dist/{api-tokens-KO24G1Fd.mjs → api-tokens-9YrrCoE6.mjs} +2 -2
- package/dist/{api-tokens-KO24G1Fd.mjs.map → api-tokens-9YrrCoE6.mjs.map} +1 -1
- package/dist/{apply-kUDt80-G.mjs → apply-B_VMpJ2P.mjs} +34 -35
- package/dist/{apply-kUDt80-G.mjs.map → apply-B_VMpJ2P.mjs.map} +1 -1
- package/dist/astro/index.d.mts +12 -12
- package/dist/astro/index.mjs +26 -15
- package/dist/astro/index.mjs.map +1 -1
- package/dist/astro/middleware/auth.d.mts +10 -10
- package/dist/astro/middleware/auth.d.mts.map +1 -1
- package/dist/astro/middleware/auth.mjs +10 -7
- package/dist/astro/middleware/auth.mjs.map +1 -1
- package/dist/astro/middleware/media-usage-write-fence.mjs +2 -2
- package/dist/astro/middleware/redirect.mjs +4 -4
- package/dist/astro/middleware/request-context.mjs +3 -3
- package/dist/astro/middleware/setup.mjs +1 -1
- package/dist/astro/middleware.d.mts +11 -12
- package/dist/astro/middleware.d.mts.map +1 -1
- package/dist/astro/middleware.mjs +168 -1305
- package/dist/astro/middleware.mjs.map +1 -1
- package/dist/astro/routes/api/admin/allowed-domains/_domain_.mjs +6 -6
- package/dist/astro/routes/api/admin/allowed-domains/index.mjs +6 -6
- package/dist/astro/routes/api/admin/api-tokens/_id_.mjs +3 -3
- package/dist/astro/routes/api/admin/api-tokens/index.mjs +4 -4
- package/dist/astro/routes/api/admin/byline-fields/_slug_/usage.mjs +4 -4
- package/dist/astro/routes/api/admin/byline-fields/_slug_.mjs +9 -9
- package/dist/astro/routes/api/admin/byline-fields/index.mjs +9 -9
- package/dist/astro/routes/api/admin/byline-fields/reorder.mjs +9 -9
- package/dist/astro/routes/api/admin/bylines/_id_/index.mjs +15 -15
- package/dist/astro/routes/api/admin/bylines/_id_/translations.mjs +15 -15
- package/dist/astro/routes/api/admin/bylines/index.mjs +15 -15
- package/dist/astro/routes/api/admin/comments/_id_/status.mjs +12 -12
- package/dist/astro/routes/api/admin/comments/_id_.mjs +4 -4
- package/dist/astro/routes/api/admin/comments/bulk.mjs +9 -9
- package/dist/astro/routes/api/admin/comments/counts.mjs +4 -4
- package/dist/astro/routes/api/admin/comments/index.mjs +9 -9
- package/dist/astro/routes/api/admin/hooks/exclusive/_hookName_.mjs +4 -4
- package/dist/astro/routes/api/admin/hooks/exclusive/index.mjs +3 -3
- package/dist/astro/routes/api/admin/media-usage/activation.d.mts +9 -0
- package/dist/astro/routes/api/admin/media-usage/activation.d.mts.map +1 -0
- package/dist/astro/routes/api/admin/media-usage/activation.mjs +46 -0
- package/dist/astro/routes/api/admin/media-usage/activation.mjs.map +1 -0
- package/dist/astro/routes/api/admin/media-usage/collection-deletions/index.mjs +14 -13
- package/dist/astro/routes/api/admin/media-usage/collection-deletions/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/media-usage/collection-deletions/retry.mjs +14 -13
- package/dist/astro/routes/api/admin/media-usage/collection-deletions/retry.mjs.map +1 -1
- package/dist/astro/routes/api/admin/media-usage/progress.d.mts +9 -0
- package/dist/astro/routes/api/admin/media-usage/progress.d.mts.map +1 -0
- package/dist/astro/routes/api/admin/media-usage/progress.mjs +44 -0
- package/dist/astro/routes/api/admin/media-usage/progress.mjs.map +1 -0
- package/dist/astro/routes/api/admin/media-usage/repair.mjs +16 -11
- package/dist/astro/routes/api/admin/media-usage/repair.mjs.map +1 -1
- package/dist/astro/routes/api/admin/media-usage/work/index.mjs +14 -13
- package/dist/astro/routes/api/admin/media-usage/work/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/media-usage/work/retry.mjs +14 -13
- package/dist/astro/routes/api/admin/media-usage/work/retry.mjs.map +1 -1
- package/dist/astro/routes/api/admin/oauth-clients/_id_.mjs +3 -3
- package/dist/astro/routes/api/admin/oauth-clients/index.mjs +3 -3
- package/dist/astro/routes/api/admin/plugins/_id_/disable.mjs +54 -48
- package/dist/astro/routes/api/admin/plugins/_id_/disable.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/_id_/enable.mjs +54 -48
- package/dist/astro/routes/api/admin/plugins/_id_/enable.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/_id_/index.mjs +52 -46
- package/dist/astro/routes/api/admin/plugins/_id_/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/_id_/mcp.mjs +4 -4
- package/dist/astro/routes/api/admin/plugins/_id_/settings.mjs +52 -46
- package/dist/astro/routes/api/admin/plugins/_id_/settings.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/_id_/uninstall.mjs +53 -47
- package/dist/astro/routes/api/admin/plugins/_id_/uninstall.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/_id_/update.mjs +53 -47
- package/dist/astro/routes/api/admin/plugins/_id_/update.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/index.mjs +52 -46
- package/dist/astro/routes/api/admin/plugins/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/marketplace/_id_/icon.mjs +2 -2
- package/dist/astro/routes/api/admin/plugins/marketplace/_id_/index.mjs +52 -46
- package/dist/astro/routes/api/admin/plugins/marketplace/_id_/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/marketplace/_id_/install.mjs +53 -47
- package/dist/astro/routes/api/admin/plugins/marketplace/_id_/install.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/marketplace/index.mjs +52 -46
- package/dist/astro/routes/api/admin/plugins/marketplace/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/registry/_id_/uninstall.mjs +53 -47
- package/dist/astro/routes/api/admin/plugins/registry/_id_/uninstall.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/registry/_id_/update.mjs +54 -48
- package/dist/astro/routes/api/admin/plugins/registry/_id_/update.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/registry/artifact.d.mts.map +1 -1
- package/dist/astro/routes/api/admin/plugins/registry/artifact.mjs +172 -133
- package/dist/astro/routes/api/admin/plugins/registry/artifact.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/registry/install.mjs +54 -48
- package/dist/astro/routes/api/admin/plugins/registry/install.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/updates.mjs +52 -46
- package/dist/astro/routes/api/admin/plugins/updates.mjs.map +1 -1
- package/dist/astro/routes/api/admin/themes/marketplace/_id_/index.mjs +52 -46
- package/dist/astro/routes/api/admin/themes/marketplace/_id_/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/themes/marketplace/_id_/thumbnail.mjs +2 -2
- package/dist/astro/routes/api/admin/themes/marketplace/index.mjs +52 -46
- package/dist/astro/routes/api/admin/themes/marketplace/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/users/_id_/disable.mjs +2 -2
- package/dist/astro/routes/api/admin/users/_id_/enable.mjs +1 -1
- package/dist/astro/routes/api/admin/users/_id_/index.mjs +7 -7
- package/dist/astro/routes/api/admin/users/_id_/send-recovery.mjs +3 -3
- package/dist/astro/routes/api/admin/users/index.mjs +6 -6
- package/dist/astro/routes/api/auth/dev-bypass.mjs +3 -3
- package/dist/astro/routes/api/auth/invite/accept.mjs +1 -1
- package/dist/astro/routes/api/auth/invite/complete.mjs +11 -11
- package/dist/astro/routes/api/auth/invite/index.mjs +8 -8
- package/dist/astro/routes/api/auth/invite/register-options.mjs +10 -10
- package/dist/astro/routes/api/auth/logout.mjs +2 -2
- package/dist/astro/routes/api/auth/magic-link/send.mjs +10 -10
- package/dist/astro/routes/api/auth/magic-link/verify.mjs +2 -2
- package/dist/astro/routes/api/auth/me.d.mts.map +1 -1
- package/dist/astro/routes/api/auth/me.mjs +19 -9
- package/dist/astro/routes/api/auth/me.mjs.map +1 -1
- package/dist/astro/routes/api/auth/mode.mjs +2 -2
- package/dist/astro/routes/api/auth/oauth/_provider_/callback.mjs +4 -4
- package/dist/astro/routes/api/auth/oauth/_provider_.mjs +2 -2
- package/dist/astro/routes/api/auth/passkey/_id_.mjs +6 -6
- package/dist/astro/routes/api/auth/passkey/index.mjs +1 -1
- package/dist/astro/routes/api/auth/passkey/options.mjs +12 -12
- package/dist/astro/routes/api/auth/passkey/register/options.mjs +10 -10
- package/dist/astro/routes/api/auth/passkey/register/verify.mjs +11 -11
- package/dist/astro/routes/api/auth/passkey/verify.mjs +11 -11
- package/dist/astro/routes/api/auth/signup/complete.mjs +11 -11
- package/dist/astro/routes/api/auth/signup/request.mjs +10 -10
- package/dist/astro/routes/api/auth/signup/verify.mjs +1 -1
- package/dist/astro/routes/api/comments/_collection_/_contentId_/index.mjs +13 -13
- package/dist/astro/routes/api/comments/_collection_/_contentId_/reactions.mjs +12 -12
- package/dist/astro/routes/api/content/_collection_/_id_/compare.mjs +2 -2
- package/dist/astro/routes/api/content/_collection_/_id_/discard-draft.mjs +3 -3
- package/dist/astro/routes/api/content/_collection_/_id_/duplicate.mjs +3 -3
- package/dist/astro/routes/api/content/_collection_/_id_/permanent.mjs +2 -2
- package/dist/astro/routes/api/content/_collection_/_id_/preview-url.mjs +11 -11
- package/dist/astro/routes/api/content/_collection_/_id_/publish.mjs +8 -8
- package/dist/astro/routes/api/content/_collection_/_id_/references/_relation_/children.mjs +16 -14
- package/dist/astro/routes/api/content/_collection_/_id_/references/_relation_/children.mjs.map +1 -1
- package/dist/astro/routes/api/content/_collection_/_id_/references/_relation_/parents.mjs +16 -14
- package/dist/astro/routes/api/content/_collection_/_id_/references/_relation_/parents.mjs.map +1 -1
- package/dist/astro/routes/api/content/_collection_/_id_/restore.mjs +3 -3
- package/dist/astro/routes/api/content/_collection_/_id_/revisions.mjs +2 -2
- package/dist/astro/routes/api/content/_collection_/_id_/schedule.mjs +8 -8
- package/dist/astro/routes/api/content/_collection_/_id_/terms/_taxonomy_.mjs +13 -13
- package/dist/astro/routes/api/content/_collection_/_id_/translations.mjs +2 -2
- package/dist/astro/routes/api/content/_collection_/_id_/unpublish.mjs +3 -3
- package/dist/astro/routes/api/content/_collection_/_id_.mjs +8 -8
- package/dist/astro/routes/api/content/_collection_/authors.mjs +2 -2
- package/dist/astro/routes/api/content/_collection_/index.mjs +8 -8
- package/dist/astro/routes/api/content/_collection_/trash.mjs +7 -7
- package/dist/astro/routes/api/dashboard.mjs +7 -7
- package/dist/astro/routes/api/dev/emails.mjs +2 -2
- package/dist/astro/routes/api/import/probe.d.mts +3 -3
- package/dist/astro/routes/api/import/probe.mjs +16 -16
- package/dist/astro/routes/api/import/wordpress/analyze.mjs +2 -2
- package/dist/astro/routes/api/import/wordpress/execute.d.mts +11 -11
- package/dist/astro/routes/api/import/wordpress/execute.mjs +12 -12
- package/dist/astro/routes/api/import/wordpress/media.d.mts +10 -10
- package/dist/astro/routes/api/import/wordpress/media.mjs +11 -11
- package/dist/astro/routes/api/import/wordpress/prepare.mjs +9 -9
- package/dist/astro/routes/api/import/wordpress/rewrite-urls.d.mts +11 -11
- package/dist/astro/routes/api/import/wordpress/rewrite-urls.mjs +12 -10
- package/dist/astro/routes/api/import/wordpress/rewrite-urls.mjs.map +1 -1
- package/dist/astro/routes/api/import/wordpress-plugin/analyze.d.mts +1 -1
- package/dist/astro/routes/api/import/wordpress-plugin/analyze.mjs +16 -16
- package/dist/astro/routes/api/import/wordpress-plugin/execute.d.mts +11 -11
- package/dist/astro/routes/api/import/wordpress-plugin/execute.mjs +26 -26
- package/dist/astro/routes/api/manifest.mjs +4 -4
- package/dist/astro/routes/api/mcp.mjs +42 -42
- package/dist/astro/routes/api/media/_id_/confirm.mjs +11 -11
- package/dist/astro/routes/api/media/_id_/upload.mjs +6 -6
- package/dist/astro/routes/api/media/_id_/usage.mjs +18 -13
- package/dist/astro/routes/api/media/_id_/usage.mjs.map +1 -1
- package/dist/astro/routes/api/media/_id_.d.mts.map +1 -1
- package/dist/astro/routes/api/media/_id_.mjs +21 -13
- package/dist/astro/routes/api/media/_id_.mjs.map +1 -1
- package/dist/astro/routes/api/media/file/_...key_.mjs +1 -1
- package/dist/astro/routes/api/media/folders/_id_.d.mts +10 -0
- package/dist/astro/routes/api/media/folders/_id_.d.mts.map +1 -0
- package/dist/astro/routes/api/media/folders/_id_.mjs +52 -0
- package/dist/astro/routes/api/media/folders/_id_.mjs.map +1 -0
- package/dist/astro/routes/api/media/folders/index.d.mts +9 -0
- package/dist/astro/routes/api/media/folders/index.d.mts.map +1 -0
- package/dist/astro/routes/api/media/folders/index.mjs +41 -0
- package/dist/astro/routes/api/media/folders/index.mjs.map +1 -0
- package/dist/astro/routes/api/media/providers/_providerId_/_itemId_.mjs +2 -2
- package/dist/astro/routes/api/media/providers/_providerId_/index.mjs +2 -2
- package/dist/astro/routes/api/media/providers/index.mjs +2 -2
- package/dist/astro/routes/api/media/upload-url.mjs +9 -9
- package/dist/astro/routes/api/media.d.mts.map +1 -1
- package/dist/astro/routes/api/media.mjs +28 -19
- package/dist/astro/routes/api/media.mjs.map +1 -1
- package/dist/astro/routes/api/menus/_name_/items/_id_.mjs +8 -8
- package/dist/astro/routes/api/menus/_name_/items.mjs +8 -8
- package/dist/astro/routes/api/menus/_name_/reorder.mjs +8 -8
- package/dist/astro/routes/api/menus/_name_/translations.mjs +8 -8
- package/dist/astro/routes/api/menus/_name_.mjs +8 -8
- package/dist/astro/routes/api/menus/index.mjs +8 -8
- package/dist/astro/routes/api/oauth/authorize.mjs +6 -6
- package/dist/astro/routes/api/oauth/device/authorize.mjs +5 -5
- package/dist/astro/routes/api/oauth/device/code.mjs +8 -8
- package/dist/astro/routes/api/oauth/device/token.mjs +7 -7
- package/dist/astro/routes/api/oauth/register.mjs +2 -2
- package/dist/astro/routes/api/oauth/token/refresh.mjs +5 -5
- package/dist/astro/routes/api/oauth/token/revoke.mjs +5 -5
- package/dist/astro/routes/api/oauth/token.mjs +5 -5
- package/dist/astro/routes/api/openapi.json.mjs +153 -6
- package/dist/astro/routes/api/openapi.json.mjs.map +1 -1
- package/dist/astro/routes/api/plugins/_pluginId_/_...path_.mjs +4 -4
- package/dist/astro/routes/api/redirects/404s/index.mjs +10 -10
- package/dist/astro/routes/api/redirects/404s/summary.mjs +10 -10
- package/dist/astro/routes/api/redirects/_id_.mjs +11 -11
- package/dist/astro/routes/api/redirects/index.mjs +11 -11
- package/dist/astro/routes/api/relations/_id_/index.mjs +16 -14
- package/dist/astro/routes/api/relations/_id_/index.mjs.map +1 -1
- package/dist/astro/routes/api/relations/_id_/translations.mjs +11 -9
- package/dist/astro/routes/api/relations/_id_/translations.mjs.map +1 -1
- package/dist/astro/routes/api/relations/index.mjs +16 -14
- package/dist/astro/routes/api/relations/index.mjs.map +1 -1
- package/dist/astro/routes/api/revisions/_revisionId_/index.mjs +2 -2
- package/dist/astro/routes/api/revisions/_revisionId_/restore.mjs +3 -3
- package/dist/astro/routes/api/schema/collections/_slug_/fields/_fieldSlug_.mjs +52 -46
- package/dist/astro/routes/api/schema/collections/_slug_/fields/_fieldSlug_.mjs.map +1 -1
- package/dist/astro/routes/api/schema/collections/_slug_/fields/index.mjs +52 -46
- package/dist/astro/routes/api/schema/collections/_slug_/fields/index.mjs.map +1 -1
- package/dist/astro/routes/api/schema/collections/_slug_/fields/reorder.mjs +52 -46
- package/dist/astro/routes/api/schema/collections/_slug_/fields/reorder.mjs.map +1 -1
- package/dist/astro/routes/api/schema/collections/_slug_/index.mjs +52 -46
- package/dist/astro/routes/api/schema/collections/_slug_/index.mjs.map +1 -1
- package/dist/astro/routes/api/schema/collections/index.mjs +52 -46
- package/dist/astro/routes/api/schema/collections/index.mjs.map +1 -1
- package/dist/astro/routes/api/schema/collections/reorder.mjs +52 -46
- package/dist/astro/routes/api/schema/collections/reorder.mjs.map +1 -1
- package/dist/astro/routes/api/schema/index.mjs +10 -8
- package/dist/astro/routes/api/schema/index.mjs.map +1 -1
- package/dist/astro/routes/api/schema/orphans/_slug_.mjs +52 -46
- package/dist/astro/routes/api/schema/orphans/_slug_.mjs.map +1 -1
- package/dist/astro/routes/api/schema/orphans/index.mjs +52 -46
- package/dist/astro/routes/api/schema/orphans/index.mjs.map +1 -1
- package/dist/astro/routes/api/search/enable.mjs +10 -10
- package/dist/astro/routes/api/search/index.mjs +9 -9
- package/dist/astro/routes/api/search/rebuild.mjs +10 -10
- package/dist/astro/routes/api/search/stats.mjs +5 -5
- package/dist/astro/routes/api/search/suggest.mjs +9 -9
- package/dist/astro/routes/api/sections/_slug_.mjs +9 -9
- package/dist/astro/routes/api/sections/index.mjs +9 -9
- package/dist/astro/routes/api/settings/backups/archives/_name_.mjs +6 -6
- package/dist/astro/routes/api/settings/backups/archives/index.mjs +5 -5
- package/dist/astro/routes/api/settings/backups/export.mjs +6 -6
- package/dist/astro/routes/api/settings/backups/index.mjs +7 -7
- package/dist/astro/routes/api/settings/email.mjs +4 -4
- package/dist/astro/routes/api/settings.mjs +13 -13
- package/dist/astro/routes/api/setup/admin-verify.mjs +12 -12
- package/dist/astro/routes/api/setup/admin.mjs +11 -11
- package/dist/astro/routes/api/setup/dev-bypass.d.mts.map +1 -1
- package/dist/astro/routes/api/setup/dev-bypass.mjs +34 -27
- package/dist/astro/routes/api/setup/dev-bypass.mjs.map +1 -1
- package/dist/astro/routes/api/setup/dev-reset.mjs +2 -2
- package/dist/astro/routes/api/setup/index.mjs +31 -29
- package/dist/astro/routes/api/setup/index.mjs.map +1 -1
- package/dist/astro/routes/api/setup/status.mjs +3 -3
- package/dist/astro/routes/api/snapshot.mjs +7 -7
- package/dist/astro/routes/api/taxonomies/_name_/reorder.mjs +13 -13
- package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_/translations.mjs +13 -13
- package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_.mjs +13 -13
- package/dist/astro/routes/api/taxonomies/_name_/terms/index.mjs +13 -13
- package/dist/astro/routes/api/taxonomies/_name_/translations.mjs +13 -13
- package/dist/astro/routes/api/taxonomies/_name_.mjs +13 -13
- package/dist/astro/routes/api/taxonomies/index.mjs +13 -13
- package/dist/astro/routes/api/themes/preview.mjs +5 -5
- package/dist/astro/routes/api/typegen.mjs +4 -4
- package/dist/astro/routes/api/well-known/auth.mjs +2 -2
- package/dist/astro/routes/api/well-known/oauth-authorization-server.mjs +2 -2
- package/dist/astro/routes/api/well-known/oauth-protected-resource.mjs +2 -2
- package/dist/astro/routes/api/widget-areas/_name_/reorder.mjs +7 -7
- package/dist/astro/routes/api/widget-areas/_name_/widgets/_id_.mjs +10 -10
- package/dist/astro/routes/api/widget-areas/_name_/widgets.mjs +10 -10
- package/dist/astro/routes/api/widget-areas/_name_.mjs +5 -5
- package/dist/astro/routes/api/widget-areas/index.mjs +10 -10
- package/dist/astro/routes/api/widget-components.mjs +2 -2
- package/dist/astro/routes/robots.txt.mjs +6 -6
- package/dist/astro/routes/sitemap-_collection_.xml.mjs +9 -9
- package/dist/astro/routes/sitemap.xml.mjs +7 -7
- package/dist/astro/types.d.mts +19 -14
- package/dist/astro/types.d.mts.map +1 -1
- package/dist/auth/providers/github.d.mts +1 -1
- package/dist/auth/providers/google.d.mts +1 -1
- package/dist/{authorize-DUElxgOQ.mjs → authorize-ByYs-Uxs.mjs} +2 -2
- package/dist/{authorize-DUElxgOQ.mjs.map → authorize-ByYs-Uxs.mjs.map} +1 -1
- package/dist/{backup-DWYpJlLj.mjs → backup-ChyHfIoX.mjs} +5 -5
- package/dist/{backup-DWYpJlLj.mjs.map → backup-ChyHfIoX.mjs.map} +1 -1
- package/dist/{bundle-vn56sLos.mjs → bundle-DZFhFurR.mjs} +4 -4
- package/dist/{bundle-vn56sLos.mjs.map → bundle-DZFhFurR.mjs.map} +1 -1
- package/dist/{byline-yjvWq4ip.mjs → byline-Cpnwrje1.mjs} +6 -6
- package/dist/{byline-yjvWq4ip.mjs.map → byline-Cpnwrje1.mjs.map} +1 -1
- package/dist/{byline-fields-txaLGoME.mjs → byline-fields-CAyA_Umd.mjs} +2 -2
- package/dist/{byline-fields-txaLGoME.mjs.map → byline-fields-CAyA_Umd.mjs.map} +1 -1
- package/dist/{byline-registry-DDun8sxh.mjs → byline-registry-Bpu9-MVs.mjs} +2 -2
- package/dist/{byline-registry-DDun8sxh.mjs.map → byline-registry-Bpu9-MVs.mjs.map} +1 -1
- package/dist/{bylines-DjXS5p0P.mjs → bylines-BSo9B9RX.mjs} +7 -7
- package/dist/{bylines-DjXS5p0P.mjs.map → bylines-BSo9B9RX.mjs.map} +1 -1
- package/dist/{bylines-Bu7pchQ4.mjs → bylines-CHjvehVX.mjs} +3 -3
- package/dist/{bylines-Bu7pchQ4.mjs.map → bylines-CHjvehVX.mjs.map} +1 -1
- package/dist/{cache-C46-3Irl.mjs → cache-5VirJ2Cn.mjs} +4 -4
- package/dist/{cache-C46-3Irl.mjs.map → cache-5VirJ2Cn.mjs.map} +1 -1
- package/dist/capture-triggers-CNW1q3HK.mjs +362 -0
- package/dist/capture-triggers-CNW1q3HK.mjs.map +1 -0
- package/dist/{challenge-store-SIL5DsF2.mjs → challenge-store-D5pSY2S1.mjs} +1 -1
- package/dist/{challenge-store-SIL5DsF2.mjs.map → challenge-store-D5pSY2S1.mjs.map} +1 -1
- package/dist/{chunks-fiZ8G9RJ.mjs → chunks-bNiX6_DR.mjs} +2 -2
- package/dist/{chunks-fiZ8G9RJ.mjs.map → chunks-bNiX6_DR.mjs.map} +1 -1
- package/dist/cli/index.mjs +36 -52
- package/dist/cli/index.mjs.map +1 -1
- package/dist/client/cf-access.d.mts +1 -1
- package/dist/client/index.d.mts +74 -4
- package/dist/client/index.d.mts.map +1 -1
- package/dist/client/index.mjs +54 -2
- package/dist/client/index.mjs.map +1 -1
- package/dist/{collection-deletion-DQPvMD8R.mjs → collection-deletion-m_oi2c0N.mjs} +13 -356
- package/dist/collection-deletion-m_oi2c0N.mjs.map +1 -0
- package/dist/{comment-Dxlep6cE.mjs → comment-DhvLEdhQ.mjs} +1 -1
- package/dist/{comment-Dxlep6cE.mjs.map → comment-DhvLEdhQ.mjs.map} +1 -1
- package/dist/{comment-reaction-D-2J84UE.mjs → comment-reaction-CRuItEjt.mjs} +2 -2
- package/dist/{comment-reaction-D-2J84UE.mjs.map → comment-reaction-CRuItEjt.mjs.map} +1 -1
- package/dist/{comments-CTfZtLmM.mjs → comments-CLj4bi8I.mjs} +2 -2
- package/dist/{comments-CTfZtLmM.mjs.map → comments-CLj4bi8I.mjs.map} +1 -1
- package/dist/{components-CQy3lh9x.mjs → components-v4U4DT2y.mjs} +1 -1
- package/dist/{components-CQy3lh9x.mjs.map → components-v4U4DT2y.mjs.map} +1 -1
- package/dist/{config-COQzTe5Q.d.mts → config-DrfghTPe.d.mts} +1 -1
- package/dist/{config-COQzTe5Q.d.mts.map → config-DrfghTPe.d.mts.map} +1 -1
- package/dist/{content-ZHCc1ngN.mjs → content-CP-SeXNa.mjs} +5 -4
- package/dist/content-CP-SeXNa.mjs.map +1 -0
- package/dist/{content-list-query-wJ2WN8Vp.d.mts → content-list-query-BhejKVqb.d.mts} +1 -1
- package/dist/{content-list-query-wJ2WN8Vp.d.mts.map → content-list-query-BhejKVqb.d.mts.map} +1 -1
- package/dist/{content-refresh-B_8SJzuU.mjs → content-refresh-DLOfIhYc.mjs} +1094 -93
- package/dist/content-refresh-DLOfIhYc.mjs.map +1 -0
- package/dist/{media-usage-BZCydfvu.mjs → content-repair-BCxzy0r4.mjs} +5 -196
- package/dist/content-repair-BCxzy0r4.mjs.map +1 -0
- package/dist/{context-ZldbZcle.mjs → context-BR5hRWiK.mjs} +13 -13
- package/dist/{context-ZldbZcle.mjs.map → context-BR5hRWiK.mjs.map} +1 -1
- package/dist/{cron-Y9aLtgrA.mjs → cron-CWfWrWKG.mjs} +1 -1
- package/dist/{cron-Y9aLtgrA.mjs.map → cron-CWfWrWKG.mjs.map} +1 -1
- package/dist/{dashboard-DvHbk_cv.mjs → dashboard-CkIV2rnQ.mjs} +5 -5
- package/dist/{dashboard-DvHbk_cv.mjs.map → dashboard-CkIV2rnQ.mjs.map} +1 -1
- package/dist/db/index.d.mts +3 -3
- package/dist/db/index.mjs +3 -3
- package/dist/db/index.mjs.map +1 -1
- package/dist/db/libsql-migrations.d.mts +1 -1
- package/dist/db/libsql-migrations.mjs +4 -4
- package/dist/db/libsql.d.mts +1 -1
- package/dist/db/postgres-migrations.d.mts +1 -1
- package/dist/db/postgres-migrations.mjs +4 -4
- package/dist/db/postgres.d.mts +1 -1
- package/dist/db/sqlite-migrations.d.mts +1 -1
- package/dist/db/sqlite-migrations.mjs +4 -4
- package/dist/db/sqlite.d.mts +1 -1
- package/dist/db/sqlite.mjs +3 -3
- package/dist/db/sqlite.mjs.map +1 -1
- package/dist/{default-DdDl3fxv.mjs → default-YMEfcQUx.mjs} +1 -1
- package/dist/{default-DdDl3fxv.mjs.map → default-YMEfcQUx.mjs.map} +1 -1
- package/dist/{deferred-tasks-SDWxrgzJ.d.mts → deferred-tasks-DfqxH5Xf.d.mts} +1 -1
- package/dist/{deferred-tasks-SDWxrgzJ.d.mts.map → deferred-tasks-DfqxH5Xf.d.mts.map} +1 -1
- package/dist/{device-flow-C0GdD_z8.mjs → device-flow-CojjSBwb.mjs} +5 -5
- package/dist/{device-flow-C0GdD_z8.mjs.map → device-flow-CojjSBwb.mjs.map} +1 -1
- package/dist/{direct-executor-CDXeJCSs.mjs → direct-executor-BWeWiRYB.mjs} +3 -3
- package/dist/{direct-executor-CDXeJCSs.mjs.map → direct-executor-BWeWiRYB.mjs.map} +1 -1
- package/dist/{dist-D_6CKR8z.mjs → dist-89xCrGqi.mjs} +1 -1
- package/dist/{dist-D_6CKR8z.mjs.map → dist-89xCrGqi.mjs.map} +1 -1
- package/dist/{email-console-BHNjIwiB.mjs → email-console-CEJgR_LB.mjs} +1 -1
- package/dist/{email-console-BHNjIwiB.mjs.map → email-console-CEJgR_LB.mjs.map} +1 -1
- package/dist/{enrich-_ySMEvEE.mjs → enrich-BX0IDp4z.mjs} +3 -3
- package/dist/{enrich-_ySMEvEE.mjs.map → enrich-BX0IDp4z.mjs.map} +1 -1
- package/dist/{error-DupyJZE2.mjs → error-D9w94fjV.mjs} +2 -2
- package/dist/{error-DupyJZE2.mjs.map → error-D9w94fjV.mjs.map} +1 -1
- package/dist/{errors-CLUPm7aD.mjs → errors-n2j49uNf.mjs} +22 -2
- package/dist/errors-n2j49uNf.mjs.map +1 -0
- package/dist/{escape-DUY2r2Zs.mjs → escape-DN4Qmjsl.mjs} +1 -1
- package/dist/{escape-DUY2r2Zs.mjs.map → escape-DN4Qmjsl.mjs.map} +1 -1
- package/dist/{field-defs-cache-BzwBlJrR.mjs → field-defs-cache-Bh4q6oar.mjs} +5 -5
- package/dist/{field-defs-cache-BzwBlJrR.mjs.map → field-defs-cache-Bh4q6oar.mjs.map} +1 -1
- package/dist/focal-point-BeWFo6Xx.mjs +23 -0
- package/dist/focal-point-BeWFo6Xx.mjs.map +1 -0
- package/dist/{fts-manager-DyZEohZC.mjs → fts-manager-BhOdW0bi.mjs} +3 -3
- package/dist/{fts-manager-DyZEohZC.mjs.map → fts-manager-BhOdW0bi.mjs.map} +1 -1
- package/dist/{hash-Cg0TXJPV.mjs → hash-CTcngWvj.mjs} +1 -1
- package/dist/{hash-Cg0TXJPV.mjs.map → hash-CTcngWvj.mjs.map} +1 -1
- package/dist/{hreflang-DwT2E0Sa.d.mts → hreflang-7pTHsLZJ.d.mts} +2 -2
- package/dist/{hreflang-DwT2E0Sa.d.mts.map → hreflang-7pTHsLZJ.d.mts.map} +1 -1
- package/dist/{hreflang-BBe83kKa.mjs → hreflang-Huc6O5wa.mjs} +7 -7
- package/dist/{hreflang-BBe83kKa.mjs.map → hreflang-Huc6O5wa.mjs.map} +1 -1
- package/dist/{identity-Ys6Dlc9C.mjs → identity-DXmb4aVp.mjs} +3 -3
- package/dist/{identity-Ys6Dlc9C.mjs.map → identity-DXmb4aVp.mjs.map} +1 -1
- package/dist/{import-DPkLmeXO.mjs → import-C4_O3KXU.mjs} +5 -5
- package/dist/{import-DPkLmeXO.mjs.map → import-C4_O3KXU.mjs.map} +1 -1
- package/dist/{index-C9KuQyO-.d.mts → index-6bRee8zb.d.mts} +3 -3
- package/dist/{index-C9KuQyO-.d.mts.map → index-6bRee8zb.d.mts.map} +1 -1
- package/dist/{index-BVBZj4-7.d.mts → index-DWbJrsAg.d.mts} +128 -52
- package/dist/index-DWbJrsAg.d.mts.map +1 -0
- package/dist/index.d.mts +21 -21
- package/dist/index.mjs +78 -72
- package/dist/{init-lock-6b309ZrF.mjs → init-lock-DJkX6Hto.mjs} +1 -1
- package/dist/{init-lock-6b309ZrF.mjs.map → init-lock-DJkX6Hto.mjs.map} +1 -1
- package/dist/{load-YJ2xl3ra.mjs → load-Bo7fZAbg.mjs} +2 -2
- package/dist/{load-YJ2xl3ra.mjs.map → load-Bo7fZAbg.mjs.map} +1 -1
- package/dist/{loader-CdG_Ci3H.mjs → loader-ZsjE4paL.mjs} +2 -2
- package/dist/{loader-CdG_Ci3H.mjs.map → loader-ZsjE4paL.mjs.map} +1 -1
- package/dist/{manifest-builder-B252yQUf.mjs → manifest-builder-QXuqvVMP.mjs} +2 -2
- package/dist/{manifest-builder-B252yQUf.mjs.map → manifest-builder-QXuqvVMP.mjs.map} +1 -1
- package/dist/{manifest-schema-BXbUAHod.mjs → manifest-schema-CUYPfCEH.mjs} +1 -1
- package/dist/{manifest-schema-BXbUAHod.mjs.map → manifest-schema-CUYPfCEH.mjs.map} +1 -1
- package/dist/media/image-endpoint.mjs +1 -1
- package/dist/media/index.d.mts +1 -1
- package/dist/media/index.mjs +13 -3
- package/dist/media/index.mjs.map +1 -1
- package/dist/media/local-runtime.d.mts +14 -12
- package/dist/media/local-runtime.d.mts.map +1 -1
- package/dist/media/local-runtime.mjs +11 -5
- package/dist/media/local-runtime.mjs.map +1 -1
- package/dist/{media-BWWWb8kg.mjs → media-BjwNuLEu.mjs} +100 -6
- package/dist/media-BjwNuLEu.mjs.map +1 -0
- package/dist/{media-CzhAn2--.mjs → media-D6SeAfBl.mjs} +41 -12
- package/dist/media-D6SeAfBl.mjs.map +1 -0
- package/dist/{media-allowlist-D6x-Us02.mjs → media-allowlist-D35v7bmL.mjs} +3 -2
- package/dist/media-allowlist-D35v7bmL.mjs.map +1 -0
- package/dist/media-folders-D-0CmRZj.mjs +210 -0
- package/dist/media-folders-D-0CmRZj.mjs.map +1 -0
- package/dist/{media-upload-CHBVn6m-.mjs → media-upload-C7bLXGcI.mjs} +9 -9
- package/dist/{media-upload-CHBVn6m-.mjs.map → media-upload-C7bLXGcI.mjs.map} +1 -1
- package/dist/{media-url-BvoX88FA.mjs → media-url-DH7giMx_.mjs} +1 -1
- package/dist/{media-url-BvoX88FA.mjs.map → media-url-DH7giMx_.mjs.map} +1 -1
- package/dist/media-usage-BTRJvS6V.mjs +1833 -0
- package/dist/media-usage-BTRJvS6V.mjs.map +1 -0
- package/dist/media-usage-activation-Dx0kPV6b.mjs +78 -0
- package/dist/media-usage-activation-Dx0kPV6b.mjs.map +1 -0
- package/dist/{media-usage-work-DrCbqBcl.mjs → media-usage-work-C-fhM30c.mjs} +221 -59
- package/dist/media-usage-work-C-fhM30c.mjs.map +1 -0
- package/dist/{media-usage-work-CLo_6tct.mjs → media-usage-work-DWb2XPMI.mjs} +4 -4
- package/dist/{media-usage-work-CLo_6tct.mjs.map → media-usage-work-DWb2XPMI.mjs.map} +1 -1
- package/dist/{media-usage-write-fence-aHEgN1zB.mjs → media-usage-write-fence-BwoJVRDC.mjs} +2 -2
- package/dist/{media-usage-write-fence-aHEgN1zB.mjs.map → media-usage-write-fence-BwoJVRDC.mjs.map} +1 -1
- package/dist/{menus-TCNSd2vp.mjs → menus-CD7EFLwz.mjs} +3 -3
- package/dist/{menus-TCNSd2vp.mjs.map → menus-CD7EFLwz.mjs.map} +1 -1
- package/dist/{menus-DSo5QeW0.mjs → menus-CNg0QlDt.mjs} +42 -26
- package/dist/menus-CNg0QlDt.mjs.map +1 -0
- package/dist/migrations/index.d.mts +1 -1
- package/dist/migrations/index.mjs +3 -3
- package/dist/{mime-DfIVjNkr.mjs → mime-CUIG6x84.mjs} +1 -1
- package/dist/mime-CUIG6x84.mjs.map +1 -0
- package/dist/{mode-BDoH_WcF.mjs → mode-DaUM_MB2.mjs} +1 -1
- package/dist/{mode-BDoH_WcF.mjs.map → mode-DaUM_MB2.mjs.map} +1 -1
- package/dist/node-sqlite-compat-Udb4Y-rs.mjs +46 -0
- package/dist/node-sqlite-compat-Udb4Y-rs.mjs.map +1 -0
- package/dist/{normalize-Bc-s_r-a.mjs → normalize-CSxdKBVa.mjs} +22 -1
- package/dist/normalize-CSxdKBVa.mjs.map +1 -0
- package/dist/{oauth-authorization-iOikmrJd.mjs → oauth-authorization-Dpsb-fMJ.mjs} +5 -5
- package/dist/{oauth-authorization-iOikmrJd.mjs.map → oauth-authorization-Dpsb-fMJ.mjs.map} +1 -1
- package/dist/{oauth-clients-CvI0nHMJ.mjs → oauth-clients-Bxnoe_67.mjs} +1 -1
- package/dist/{oauth-clients-CvI0nHMJ.mjs.map → oauth-clients-Bxnoe_67.mjs.map} +1 -1
- package/dist/{oauth-state-store-Ba8KZlwW.mjs → oauth-state-store-0C4s0K6w.mjs} +1 -1
- package/dist/{oauth-state-store-Ba8KZlwW.mjs.map → oauth-state-store-0C4s0K6w.mjs.map} +1 -1
- package/dist/{oauth-user-lookup-C5SQwGYC.mjs → oauth-user-lookup-wlGYSeqX.mjs} +1 -1
- package/dist/{oauth-user-lookup-C5SQwGYC.mjs.map → oauth-user-lookup-wlGYSeqX.mjs.map} +1 -1
- package/dist/object-cache/memory.d.mts +1 -1
- package/dist/{options-CBXIHUoT.mjs → options-BHPeIbBd.mjs} +1 -1
- package/dist/{options-CBXIHUoT.mjs.map → options-BHPeIbBd.mjs.map} +1 -1
- package/dist/{options--hhz-jZ1.d.mts → options-BhZIeFY1.d.mts} +3 -3
- package/dist/{options--hhz-jZ1.d.mts.map → options-BhZIeFY1.d.mts.map} +1 -1
- package/dist/page/index.d.mts +2 -2
- package/dist/{parse-DFbuc-Fh.mjs → parse-BRJg1kz8.mjs} +2 -2
- package/dist/{parse-DFbuc-Fh.mjs.map → parse-BRJg1kz8.mjs.map} +1 -1
- package/dist/{passkey-config-DFAmUyuE.mjs → passkey-config-B3P0nHRR.mjs} +1 -1
- package/dist/{passkey-config-DFAmUyuE.mjs.map → passkey-config-B3P0nHRR.mjs.map} +1 -1
- package/dist/{patterns-CiyXeDgr.mjs → patterns-D9iDO3j8.mjs} +1 -1
- package/dist/{patterns-CiyXeDgr.mjs.map → patterns-D9iDO3j8.mjs.map} +1 -1
- package/dist/{placeholder-Dp0K3RkD.d.mts → placeholder-BR4ZhVJl.d.mts} +7 -1
- package/dist/placeholder-BR4ZhVJl.d.mts.map +1 -0
- package/dist/plugin-types.d.mts +1 -1
- package/dist/plugin-utils.d.mts +10 -10
- package/dist/plugins/adapt-sandbox-entry.d.mts +10 -10
- package/dist/plugins/adapt-sandbox-entry.mjs +2 -2
- package/dist/{policy-TluUIxuu.mjs → policy-BVRganJQ.mjs} +2 -2
- package/dist/{policy-TluUIxuu.mjs.map → policy-BVRganJQ.mjs.map} +1 -1
- package/dist/{portable-text-imBW5cHK.mjs → portable-text-C8Tvp4_g.mjs} +1 -1
- package/dist/{portable-text-imBW5cHK.mjs.map → portable-text-C8Tvp4_g.mjs.map} +1 -1
- package/dist/{preview-PW-nOnq4.mjs → preview-dn2dUyM0.mjs} +2 -2
- package/dist/{preview-PW-nOnq4.mjs.map → preview-dn2dUyM0.mjs.map} +1 -1
- package/dist/{protocol-DjsJHTlK.d.mts → protocol-CuBEsqgE.d.mts} +2 -2
- package/dist/{protocol-DjsJHTlK.d.mts.map → protocol-CuBEsqgE.d.mts.map} +1 -1
- package/dist/{public-url-CWoFhQT8.mjs → public-url-DRz_AinV.mjs} +1 -1
- package/dist/{public-url-CWoFhQT8.mjs.map → public-url-DRz_AinV.mjs.map} +1 -1
- package/dist/{query-zTVAR1Sl.mjs → query-D18vTdha.mjs} +14 -14
- package/dist/{query-zTVAR1Sl.mjs.map → query-D18vTdha.mjs.map} +1 -1
- package/dist/{query-BWs7O5Il.mjs → query-tZDEdtCN.mjs} +4 -4
- package/dist/{query-BWs7O5Il.mjs.map → query-tZDEdtCN.mjs.map} +1 -1
- package/dist/{rate-limit-Bx4g9m3p.mjs → rate-limit-on7KPo-v.mjs} +2 -2
- package/dist/{rate-limit-Bx4g9m3p.mjs.map → rate-limit-on7KPo-v.mjs.map} +1 -1
- package/dist/{redirect-COsS6SWJ.mjs → redirect-CZkbozu9.mjs} +2 -2
- package/dist/{redirect-COsS6SWJ.mjs.map → redirect-CZkbozu9.mjs.map} +1 -1
- package/dist/{redirect-BgAOGHDq.mjs → redirect-DrbEmU9a.mjs} +1 -1
- package/dist/{redirect-BgAOGHDq.mjs.map → redirect-DrbEmU9a.mjs.map} +1 -1
- package/dist/{redirects-DyChwDkG.mjs → redirects-BahWiu8Z.mjs} +5 -5
- package/dist/{redirects-DyChwDkG.mjs.map → redirects-BahWiu8Z.mjs.map} +1 -1
- package/dist/{redirects-DTDHWH31.mjs → redirects-CRIM55KH.mjs} +6 -6
- package/dist/{redirects-DTDHWH31.mjs.map → redirects-CRIM55KH.mjs.map} +1 -1
- package/dist/{api-BeBglVxU.mjs → registry-BiO5WwPq.mjs} +483 -2462
- package/dist/registry-BiO5WwPq.mjs.map +1 -0
- package/dist/{registry-Cqa2I749.mjs → registry-Cx-jEJOS.mjs} +9 -123
- package/dist/registry-Cx-jEJOS.mjs.map +1 -0
- package/dist/{relation-BnHB0T4J.mjs → relation-A6wLF_DS.mjs} +2 -2
- package/dist/{relation-BnHB0T4J.mjs.map → relation-A6wLF_DS.mjs.map} +1 -1
- package/dist/{relations-BBApI4e2.mjs → relations-BTPM2saV.mjs} +2 -2
- package/dist/{relations-BBApI4e2.mjs.map → relations-BTPM2saV.mjs.map} +1 -1
- package/dist/{relations-BHo5A8Zf.d.mts → relations-C7B46bcU.d.mts} +192 -33
- package/dist/relations-C7B46bcU.d.mts.map +1 -0
- package/dist/{relations-D5sM5fW0.mjs → relations-Cj5hZ6Zg.mjs} +4 -4
- package/dist/{relations-D5sM5fW0.mjs.map → relations-Cj5hZ6Zg.mjs.map} +1 -1
- package/dist/{request-cache-BSUptuJR.mjs → request-cache-DH9zdCOD.mjs} +1 -1
- package/dist/{request-cache-BSUptuJR.mjs.map → request-cache-DH9zdCOD.mjs.map} +1 -1
- package/dist/request-context.d.mts +1 -1
- package/dist/{request-meta-DgZJh3zG.mjs → request-meta-DRp5ENd_.mjs} +2 -2
- package/dist/{request-meta-DgZJh3zG.mjs.map → request-meta-DRp5ENd_.mjs.map} +1 -1
- package/dist/{resolve-DOhVEvty.mjs → resolve-DxUpTMmE.mjs} +1 -1
- package/dist/{resolve-DOhVEvty.mjs.map → resolve-DxUpTMmE.mjs.map} +1 -1
- package/dist/{runner-C1T11CfC.mjs → runner-77GOZCnH.mjs} +410 -286
- package/dist/runner-77GOZCnH.mjs.map +1 -0
- package/dist/{runner-BYHZn3Jy.d.mts → runner-zgqA_CqP.d.mts} +2 -2
- package/dist/{runner-BYHZn3Jy.d.mts.map → runner-zgqA_CqP.d.mts.map} +1 -1
- package/dist/runtime.d.mts +11 -11
- package/dist/runtime.mjs +1 -1
- package/dist/{schema-DZ5YVVZj.mjs → schema-BY-oVntF.mjs} +3 -3
- package/dist/{schema-DZ5YVVZj.mjs.map → schema-BY-oVntF.mjs.map} +1 -1
- package/dist/{schema-2AOsSn2v.mjs → schema-Cw9kVK0I.mjs} +35 -5
- package/dist/{schema-2AOsSn2v.mjs.map → schema-Cw9kVK0I.mjs.map} +1 -1
- package/dist/{scopes-8ClPF2bC.mjs → scopes-vMR1uIbt.mjs} +3 -3
- package/dist/{scopes-8ClPF2bC.mjs.map → scopes-vMR1uIbt.mjs.map} +1 -1
- package/dist/{search-u1QYdOCG.mjs → search-CfT3KxO5.mjs} +4 -4
- package/dist/{search-u1QYdOCG.mjs.map → search-CfT3KxO5.mjs.map} +1 -1
- package/dist/{secrets-BEgsAQEU.mjs → secrets-BH2Qow1-.mjs} +3 -3
- package/dist/{secrets-BEgsAQEU.mjs.map → secrets-BH2Qow1-.mjs.map} +1 -1
- package/dist/{sections-DmHviGyM.mjs → sections-DTfjyf1z.mjs} +2 -2
- package/dist/{sections-DmHviGyM.mjs.map → sections-DTfjyf1z.mjs.map} +1 -1
- package/dist/seed/index.d.mts +2 -2
- package/dist/seed/index.mjs +24 -22
- package/dist/seo/index.d.mts +3 -3
- package/dist/seo/index.mjs +16 -14
- package/dist/seo/index.mjs.map +1 -1
- package/dist/{seo-AFpVvTqr.mjs → seo-BSiTIXzd.mjs} +1 -1
- package/dist/{seo-AFpVvTqr.mjs.map → seo-BSiTIXzd.mjs.map} +1 -1
- package/dist/{seo-Dq4G-RrO.mjs → seo-Cm-dtvgk.mjs} +2 -2
- package/dist/{seo-Dq4G-RrO.mjs.map → seo-Cm-dtvgk.mjs.map} +1 -1
- package/dist/{service-BpArayPr.mjs → service-DYsDHEKe.mjs} +3 -3
- package/dist/{service-BpArayPr.mjs.map → service-DYsDHEKe.mjs.map} +1 -1
- package/dist/{session-user-BEorKVT-.mjs → session-user-CNAfvsdw.mjs} +1 -1
- package/dist/{session-user-BEorKVT-.mjs.map → session-user-CNAfvsdw.mjs.map} +1 -1
- package/dist/{settings-xRdoUZr0.mjs → settings-BgN-0DT-.mjs} +6 -6
- package/dist/{settings-xRdoUZr0.mjs.map → settings-BgN-0DT-.mjs.map} +1 -1
- package/dist/{settings-DE9xtzqd.mjs → settings-DjtkUo__.mjs} +3 -3
- package/dist/{settings-DE9xtzqd.mjs.map → settings-DjtkUo__.mjs.map} +1 -1
- package/dist/{setup-complete-BnT8pq_C.mjs → setup-complete-CcpXaPU7.mjs} +2 -2
- package/dist/{setup-complete-BnT8pq_C.mjs.map → setup-complete-CcpXaPU7.mjs.map} +1 -1
- package/dist/{setup-nonce-CBitf_oQ.mjs → setup-nonce-Reyw30jg.mjs} +1 -1
- package/dist/{setup-nonce-CBitf_oQ.mjs.map → setup-nonce-Reyw30jg.mjs.map} +1 -1
- package/dist/{single-flight-cache-B0eLKS6K.mjs → single-flight-cache-BPuGPdcN.mjs} +2 -2
- package/dist/{single-flight-cache-B0eLKS6K.mjs.map → single-flight-cache-BPuGPdcN.mjs.map} +1 -1
- package/dist/{site-url-DjpIXMXJ.mjs → site-url-Cs_V9n3V.mjs} +3 -3
- package/dist/{site-url-DjpIXMXJ.mjs.map → site-url-Cs_V9n3V.mjs.map} +1 -1
- package/dist/{snapshot-BBlGkb2q.mjs → snapshot-DSB8P7Lm.mjs} +1 -1
- package/dist/{snapshot-BBlGkb2q.mjs.map → snapshot-DSB8P7Lm.mjs.map} +1 -1
- package/dist/{ssrf-Cpvg_n3A.mjs → ssrf-DqebVE34.mjs} +21 -5
- package/dist/{ssrf-Cpvg_n3A.mjs.map → ssrf-DqebVE34.mjs.map} +1 -1
- package/dist/{state-DYwPue40.mjs → state-BJfU9Uzw.mjs} +12 -4
- package/dist/state-BJfU9Uzw.mjs.map +1 -0
- package/dist/{status-CWVYpbD8.mjs → status-DDu8HIQl.mjs} +1 -1
- package/dist/{status-CWVYpbD8.mjs.map → status-DDu8HIQl.mjs.map} +1 -1
- package/dist/storage/local.d.mts +1 -1
- package/dist/storage/local.mjs +1 -1
- package/dist/storage/s3.d.mts +1 -1
- package/dist/storage/s3.mjs +1 -1
- package/dist/{target-DixqqV5i.mjs → target-D0o26Azo.mjs} +1 -1
- package/dist/{target-DixqqV5i.mjs.map → target-D0o26Azo.mjs.map} +1 -1
- package/dist/{taxonomies-OHUIiIpI.mjs → taxonomies-CPGxo-bn.mjs} +5 -5
- package/dist/{taxonomies-OHUIiIpI.mjs.map → taxonomies-CPGxo-bn.mjs.map} +1 -1
- package/dist/{taxonomies-BlrncHi9.mjs → taxonomies-kmyudNGP.mjs} +7 -7
- package/dist/{taxonomies-BlrncHi9.mjs.map → taxonomies-kmyudNGP.mjs.map} +1 -1
- package/dist/{taxonomy-BqCZ1TdU.mjs → taxonomy-8X09dLN5.mjs} +4 -4
- package/dist/{taxonomy-BqCZ1TdU.mjs.map → taxonomy-8X09dLN5.mjs.map} +1 -1
- package/dist/{tokens-C39klX8R.mjs → tokens-gTS-IVUp.mjs} +1 -1
- package/dist/{tokens-C39klX8R.mjs.map → tokens-gTS-IVUp.mjs.map} +1 -1
- package/dist/{transaction-NQj4VJ7Z.mjs → transaction-0KOpOyMu.mjs} +2 -1
- package/dist/{transaction-NQj4VJ7Z.mjs.map → transaction-0KOpOyMu.mjs.map} +1 -1
- package/dist/{transport-RQE36APG.d.mts → transport-_6R1ub7t.d.mts} +1 -1
- package/dist/{transport-RQE36APG.d.mts.map → transport-_6R1ub7t.d.mts.map} +1 -1
- package/dist/{transport-DBJwa-Si.mjs → transport-fX59xaJz.mjs} +4 -3
- package/dist/{transport-DBJwa-Si.mjs.map → transport-fX59xaJz.mjs.map} +1 -1
- package/dist/{trusted-proxy-CEVekpby.mjs → trusted-proxy-fe6nEgR4.mjs} +1 -1
- package/dist/{trusted-proxy-CEVekpby.mjs.map → trusted-proxy-fe6nEgR4.mjs.map} +1 -1
- package/dist/types-75KIqzL9.mjs.map +1 -1
- package/dist/{types-BW1syrlw.mjs → types-BXUmsINL.mjs} +1 -1
- package/dist/{types-BW1syrlw.mjs.map → types-BXUmsINL.mjs.map} +1 -1
- package/dist/{types-BntycPTF.d.mts → types-Blb-MRC3.d.mts} +1 -1
- package/dist/{types-BntycPTF.d.mts.map → types-Blb-MRC3.d.mts.map} +1 -1
- package/dist/{types-C2pMvO62.d.mts → types-Br-ERaxh.d.mts} +2 -1
- package/dist/types-Br-ERaxh.d.mts.map +1 -0
- package/dist/{types-DWRhk9xZ.d.mts → types-BzBd3PeX.d.mts} +1 -1
- package/dist/{types-DWRhk9xZ.d.mts.map → types-BzBd3PeX.d.mts.map} +1 -1
- package/dist/{types-CXnOzDe1.d.mts → types-CLqvnd05.d.mts} +1 -1
- package/dist/{types-CXnOzDe1.d.mts.map → types-CLqvnd05.d.mts.map} +1 -1
- package/dist/{types-Dfk8KI5R.d.mts → types-D5VVLr7J.d.mts} +1 -1
- package/dist/{types-Dfk8KI5R.d.mts.map → types-D5VVLr7J.d.mts.map} +1 -1
- package/dist/{types-DQIDRKF2.d.mts → types-DHxzBjbD.d.mts} +10 -1
- package/dist/types-DHxzBjbD.d.mts.map +1 -0
- package/dist/{types-DN64_zzZ.d.mts → types-DJQxln7q.d.mts} +3 -3
- package/dist/{types-DN64_zzZ.d.mts.map → types-DJQxln7q.d.mts.map} +1 -1
- package/dist/{types-CtzytVXn.mjs → types-DM3vioBY.mjs} +1 -1
- package/dist/{types-CtzytVXn.mjs.map → types-DM3vioBY.mjs.map} +1 -1
- package/dist/{types-BcqdcT-r.d.mts → types-D_DWe7k9.d.mts} +1 -1
- package/dist/{types-BcqdcT-r.d.mts.map → types-D_DWe7k9.d.mts.map} +1 -1
- package/dist/{types-DrJrVCT1.d.mts → types-Vg6f5i3s.d.mts} +3 -3
- package/dist/{types-DrJrVCT1.d.mts.map → types-Vg6f5i3s.d.mts.map} +1 -1
- package/dist/{upload-attempts-D4FS8LT6.mjs → upload-attempts-CNyGSepg.mjs} +1 -1
- package/dist/{upload-attempts-D4FS8LT6.mjs.map → upload-attempts-CNyGSepg.mjs.map} +1 -1
- package/dist/{url-pattern-BHS0V5Ng.mjs → url-pattern-K-KdXcSe.mjs} +1 -1
- package/dist/{url-pattern-BHS0V5Ng.mjs.map → url-pattern-K-KdXcSe.mjs.map} +1 -1
- package/dist/{user-DJZfUJVE.mjs → user-CtYY0tp2.mjs} +2 -2
- package/dist/{user-DJZfUJVE.mjs.map → user-CtYY0tp2.mjs.map} +1 -1
- package/dist/{utils-D4vD_Y98.mjs → utils-HztC73hq.mjs} +1 -1
- package/dist/{utils-D4vD_Y98.mjs.map → utils-HztC73hq.mjs.map} +1 -1
- package/dist/{validate-BMLBvxOC.mjs → validate-Dd-IUjnZ.mjs} +2 -2
- package/dist/{validate-BMLBvxOC.mjs.map → validate-Dd-IUjnZ.mjs.map} +1 -1
- package/dist/{validate-CTqt5nuE.d.mts → validate-DlqdOZXB.d.mts} +5 -5
- package/dist/{validate-CTqt5nuE.d.mts.map → validate-DlqdOZXB.d.mts.map} +1 -1
- package/dist/{validation-npvENUCB.mjs → validation-D83n7Npi.mjs} +10 -8
- package/dist/{validation-npvENUCB.mjs.map → validation-D83n7Npi.mjs.map} +1 -1
- package/dist/version-ri-sCyAp.mjs +7 -0
- package/dist/{version-DB_fqCSI.mjs.map → version-ri-sCyAp.mjs.map} +1 -1
- package/dist/{widgets-BD3ho7Rq.mjs → widgets-CpmZd9Q-.mjs} +4 -4
- package/dist/{widgets-BD3ho7Rq.mjs.map → widgets-CpmZd9Q-.mjs.map} +1 -1
- package/dist/{wxr-taxonomies-Ca68766D.d.mts → wxr-taxonomies-BFd0y72_.d.mts} +1 -1
- package/dist/{wxr-taxonomies-Ca68766D.d.mts.map → wxr-taxonomies-BFd0y72_.d.mts.map} +1 -1
- package/dist/{wxr-taxonomies-B1R3vBoD.mjs → wxr-taxonomies-Df4vxWcU.mjs} +4 -4
- package/dist/{wxr-taxonomies-B1R3vBoD.mjs.map → wxr-taxonomies-Df4vxWcU.mjs.map} +1 -1
- package/dist/{zod-generator-LC-on_Vb.mjs → zod-generator-DylzusHh.mjs} +24 -18
- package/dist/zod-generator-DylzusHh.mjs.map +1 -0
- package/package.json +16 -8
- package/src/api/errors.ts +20 -0
- package/src/api/handlers/index.ts +17 -0
- package/src/api/handlers/media-allowlist.ts +1 -0
- package/src/api/handlers/media-folders.ts +130 -0
- package/src/api/handlers/media-usage-activation.ts +102 -0
- package/src/api/handlers/media-usage.ts +108 -0
- package/src/api/handlers/media.ts +62 -2
- package/src/api/handlers/registry.ts +134 -316
- package/src/api/openapi/document.ts +192 -2
- package/src/api/schemas/media-usage.ts +77 -0
- package/src/api/schemas/media.ts +69 -0
- package/src/astro/integration/routes.ts +18 -0
- package/src/astro/integration/vite-config.ts +2 -7
- package/src/astro/middleware/auth.ts +4 -0
- package/src/astro/middleware.ts +0 -7
- package/src/astro/routes/api/admin/media-usage/activation.ts +42 -0
- package/src/astro/routes/api/admin/media-usage/progress.ts +37 -0
- package/src/astro/routes/api/admin/plugins/registry/artifact.ts +246 -96
- package/src/astro/routes/api/auth/me.ts +14 -2
- package/src/astro/routes/api/media/[id].ts +3 -0
- package/src/astro/routes/api/media/folders/[id].ts +55 -0
- package/src/astro/routes/api/media/folders/index.ts +37 -0
- package/src/astro/routes/api/media.ts +12 -2
- package/src/astro/routes/api/setup/dev-bypass.ts +12 -0
- package/src/astro/types.ts +11 -1
- package/src/client/index.ts +140 -2
- package/src/client/transport.ts +6 -2
- package/src/components/EmDashImage.astro +154 -50
- package/src/components/Gallery.astro +7 -0
- package/src/components/InlinePortableTextEditor.tsx +130 -1
- package/src/components/LiveSearch.astro +23 -0
- package/src/components/inline-code-block.tsx +180 -49
- package/src/content/converters/gallery.ts +2 -0
- package/src/content/converters/types.ts +2 -0
- package/src/database/connection.ts +2 -31
- package/src/database/index.ts +1 -1
- package/src/database/json-recordset.ts +16 -0
- package/src/database/migrations/019_i18n.ts +1 -1
- package/src/database/migrations/071_restore_content_bylines_table.ts +43 -0
- package/src/database/migrations/072_media_folders.ts +72 -0
- package/src/database/migrations/073_media_focal_point.ts +57 -0
- package/src/database/migrations/runner.ts +8 -2
- package/src/database/repositories/content.ts +5 -4
- package/src/database/repositories/media-folders.ts +115 -0
- package/src/database/repositories/media-usage-work.ts +395 -111
- package/src/database/repositories/media-usage.ts +1038 -10
- package/src/database/repositories/media.ts +97 -29
- package/src/database/transaction.ts +1 -0
- package/src/database/types.ts +13 -0
- package/src/db/adapters.ts +2 -2
- package/src/db/node-sqlite-compat.ts +78 -0
- package/src/db/sqlite.ts +3 -3
- package/src/emdash-runtime.ts +110 -105
- package/src/fields/image.ts +7 -1
- package/src/fields/types.ts +6 -2
- package/src/index.ts +5 -0
- package/src/media/focal-point.ts +37 -0
- package/src/media/local-runtime.ts +8 -0
- package/src/media/mime.ts +1 -0
- package/src/media/normalize.ts +10 -0
- package/src/media/types.ts +10 -0
- package/src/media/usage/activation.ts +162 -35
- package/src/media/usage/capture-triggers.ts +19 -3
- package/src/media/usage/collection-deletion-processor.ts +7 -3
- package/src/media/usage/collection-deletion.ts +10 -0
- package/src/media/usage/content-refresh.ts +258 -39
- package/src/media/usage/content-snapshots.ts +128 -31
- package/src/media/usage/extractor.ts +32 -13
- package/src/media/usage/maintenance-engine.ts +166 -0
- package/src/media/usage/reconciliation-processor.ts +106 -29
- package/src/media/usage/reconciliation.ts +90 -7
- package/src/media/usage/work-processor.ts +342 -101
- package/src/plugins/index.ts +1 -0
- package/src/plugins/save-rejection.ts +20 -0
- package/src/plugins/scheduler/node.ts +1 -13
- package/src/plugins/scheduler/types.ts +0 -2
- package/src/plugins/state.ts +13 -3
- package/src/registry/artifact-fetch.ts +530 -0
- package/src/registry/config.ts +24 -6
- package/src/registry/types.ts +12 -15
- package/src/schema/types.ts +1 -0
- package/src/schema/zod-generator.ts +12 -4
- package/src/security/ssrf.ts +21 -2
- package/src/seed/apply.ts +4 -4
- package/src/ui.ts +2 -0
- package/dist/api-BeBglVxU.mjs.map +0 -1
- package/dist/collection-deletion-DQPvMD8R.mjs.map +0 -1
- package/dist/content-ZHCc1ngN.mjs.map +0 -1
- package/dist/content-refresh-B_8SJzuU.mjs.map +0 -1
- package/dist/errors-CLUPm7aD.mjs.map +0 -1
- package/dist/index-BVBZj4-7.d.mts.map +0 -1
- package/dist/media-BWWWb8kg.mjs.map +0 -1
- package/dist/media-CzhAn2--.mjs.map +0 -1
- package/dist/media-allowlist-D6x-Us02.mjs.map +0 -1
- package/dist/media-usage-BZCydfvu.mjs.map +0 -1
- package/dist/media-usage-work-DrCbqBcl.mjs.map +0 -1
- package/dist/menus-DSo5QeW0.mjs.map +0 -1
- package/dist/mime-DfIVjNkr.mjs.map +0 -1
- package/dist/normalize-Bc-s_r-a.mjs.map +0 -1
- package/dist/placeholder-Dp0K3RkD.d.mts.map +0 -1
- package/dist/registry-Cqa2I749.mjs.map +0 -1
- package/dist/relations-BHo5A8Zf.d.mts.map +0 -1
- package/dist/runner-C1T11CfC.mjs.map +0 -1
- package/dist/state-DYwPue40.mjs.map +0 -1
- package/dist/types-C2pMvO62.d.mts.map +0 -1
- package/dist/types-DQIDRKF2.d.mts.map +0 -1
- package/dist/version-DB_fqCSI.mjs +0 -7
- package/dist/zod-generator-LC-on_Vb.mjs.map +0 -1
- /package/dist/{api-tokens-rIXC6LdE.mjs → api-tokens-B5NHLNUN.mjs} +0 -0
- /package/dist/{ssrf-DpXgKsna.mjs → ssrf-BPKzkm6O.mjs} +0 -0
- /package/dist/{types-CP1CflWf.mjs → types-D6OcIp2P.mjs} +0 -0
|
@@ -9,11 +9,21 @@ import {
|
|
|
9
9
|
} from "kysely";
|
|
10
10
|
import { ulid } from "ulidx";
|
|
11
11
|
|
|
12
|
+
import {
|
|
13
|
+
MEDIA_USAGE_ACTIVATION_RUNTIME_GENERATION,
|
|
14
|
+
MediaUsageActivationVersionMismatchError,
|
|
15
|
+
} from "../../media/usage/activation.js";
|
|
12
16
|
import { isMediaUsageProjectionFingerprint } from "../../media/usage/projection-fingerprint.js";
|
|
13
17
|
import type { MediaUsageContentSourceVariant } from "../../media/usage/source-key.js";
|
|
14
|
-
import
|
|
18
|
+
import {
|
|
19
|
+
CONTENT_SOURCE_SCHEMA_VERSION,
|
|
20
|
+
type MediaKind,
|
|
21
|
+
type MediaUsageReferenceType,
|
|
22
|
+
} from "../../media/usage/types.js";
|
|
23
|
+
import { getRequestContext } from "../../request-context.js";
|
|
15
24
|
import { chunks, SQL_BATCH_SIZE } from "../../utils/chunks.js";
|
|
16
25
|
import { isPostgres } from "../dialect-helpers.js";
|
|
26
|
+
import { jsonTextValues } from "../json-recordset.js";
|
|
17
27
|
import { withTransaction } from "../transaction.js";
|
|
18
28
|
import type {
|
|
19
29
|
Database,
|
|
@@ -33,11 +43,30 @@ type MediaUsageSourceNullableStringColumn =
|
|
|
33
43
|
| "updated_at"
|
|
34
44
|
| "last_attempted_at"
|
|
35
45
|
| "last_error_code";
|
|
46
|
+
type BatchSourceExpectedColumn =
|
|
47
|
+
| "source.collection_id"
|
|
48
|
+
| "source.source_fingerprint"
|
|
49
|
+
| "source.source_updated_at"
|
|
50
|
+
| "source.source_version"
|
|
51
|
+
| "source.identity_version"
|
|
52
|
+
| "source.revision_id"
|
|
53
|
+
| "source.last_attempted_at"
|
|
54
|
+
| "source.last_error_code";
|
|
55
|
+
type BatchInputExpectedColumn =
|
|
56
|
+
| "input.expected_collection_id"
|
|
57
|
+
| "input.expected_source_fingerprint"
|
|
58
|
+
| "input.expected_source_updated_at"
|
|
59
|
+
| "input.expected_source_version"
|
|
60
|
+
| "input.expected_identity_version"
|
|
61
|
+
| "input.expected_revision_id"
|
|
62
|
+
| "input.expected_last_attempted_at"
|
|
63
|
+
| "input.expected_last_error_code";
|
|
36
64
|
const OCCURRENCE_BIND_COLUMNS = 13;
|
|
65
|
+
const D1_MAX_BOUND_PARAMETERS = 100;
|
|
37
66
|
export const MEDIA_USAGE_GENERATION_WRITE_LEASE_MS = 60 * 60 * 1000;
|
|
38
67
|
const OCCURRENCE_INSERT_BATCH_SIZE = Math.max(
|
|
39
68
|
1,
|
|
40
|
-
Math.floor(
|
|
69
|
+
Math.floor(D1_MAX_BOUND_PARAMETERS / OCCURRENCE_BIND_COLUMNS),
|
|
41
70
|
);
|
|
42
71
|
|
|
43
72
|
function cleanupDeleteBatchSize(cleanupLease: MediaUsageCleanupLease | undefined): number {
|
|
@@ -48,6 +77,84 @@ function canIssueCleanupStatement(canIssueStatement: (() => boolean) | undefined
|
|
|
48
77
|
return canIssueStatement?.() ?? true;
|
|
49
78
|
}
|
|
50
79
|
|
|
80
|
+
function nullableRefMatch(
|
|
81
|
+
left: "content.live_revision_id" | "content.draft_revision_id",
|
|
82
|
+
right: "input.revision_id",
|
|
83
|
+
): RawBuilder<boolean> {
|
|
84
|
+
const leftRef = sql.ref(left);
|
|
85
|
+
const rightRef = sql.ref(right);
|
|
86
|
+
return sql<boolean>`(
|
|
87
|
+
(${leftRef} IS NULL AND ${rightRef} IS NULL)
|
|
88
|
+
OR ${leftRef} = ${rightRef}
|
|
89
|
+
)`;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const MAX_JSON_BIND_BYTES = 1_900_000;
|
|
93
|
+
const MEDIA_USAGE_EVENT_QUERY_CEILING = 900;
|
|
94
|
+
const MEDIA_USAGE_QUERY_RESERVE = 150;
|
|
95
|
+
|
|
96
|
+
function chunkJsonRows<T>(rows: readonly T[]): T[][] {
|
|
97
|
+
const batches: T[][] = [];
|
|
98
|
+
let batch: T[] = [];
|
|
99
|
+
let batchBytes = 2;
|
|
100
|
+
for (const row of rows) {
|
|
101
|
+
const rowBytes =
|
|
102
|
+
new TextEncoder().encode(JSON.stringify(row)).byteLength + (batch.length > 0 ? 1 : 0);
|
|
103
|
+
if (batch.length > 0 && batchBytes + rowBytes > MAX_JSON_BIND_BYTES) {
|
|
104
|
+
batches.push(batch);
|
|
105
|
+
batch = [];
|
|
106
|
+
batchBytes = 2;
|
|
107
|
+
}
|
|
108
|
+
batch.push(row);
|
|
109
|
+
batchBytes += rowBytes;
|
|
110
|
+
}
|
|
111
|
+
if (batch.length > 0) batches.push(batch);
|
|
112
|
+
return batches;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function mediaUsageQueryBudgetAllows(queries: number): boolean {
|
|
116
|
+
const metrics = getRequestContext()?.metrics;
|
|
117
|
+
return (
|
|
118
|
+
!metrics ||
|
|
119
|
+
metrics.dbCount + queries + MEDIA_USAGE_QUERY_RESERVE <= MEDIA_USAGE_EVENT_QUERY_CEILING
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function mergeInto<T>(target: Set<T>, source: ReadonlySet<T>): void {
|
|
124
|
+
for (const value of source) target.add(value);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
function batchOccurrenceRows(
|
|
128
|
+
prepared: readonly {
|
|
129
|
+
projection: { occurrences: readonly MediaUsageOccurrenceInput[] };
|
|
130
|
+
generation: string;
|
|
131
|
+
leaseToken: string;
|
|
132
|
+
row: { source_key: string };
|
|
133
|
+
}[],
|
|
134
|
+
now: string,
|
|
135
|
+
) {
|
|
136
|
+
return prepared.flatMap((item) =>
|
|
137
|
+
item.projection.occurrences.map((occurrence) => ({
|
|
138
|
+
id: ulid(),
|
|
139
|
+
source_key: item.row.source_key,
|
|
140
|
+
generation: item.generation,
|
|
141
|
+
field_slug: occurrence.fieldSlug,
|
|
142
|
+
field_path: occurrence.fieldPath,
|
|
143
|
+
occurrence_index: occurrence.occurrenceIndex ?? 0,
|
|
144
|
+
reference_type: occurrence.referenceType,
|
|
145
|
+
media_id: occurrence.mediaId,
|
|
146
|
+
provider: occurrence.provider,
|
|
147
|
+
provider_asset_id: occurrence.providerAssetId,
|
|
148
|
+
media_kind: occurrence.mediaKind ?? null,
|
|
149
|
+
mime_type: occurrence.mimeType ?? null,
|
|
150
|
+
created_at: now,
|
|
151
|
+
lease_token: item.leaseToken,
|
|
152
|
+
})),
|
|
153
|
+
);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
type BatchOccurrenceRow = ReturnType<typeof batchOccurrenceRows>[number];
|
|
157
|
+
|
|
51
158
|
function cleanupDurationSeconds(value: number): number {
|
|
52
159
|
if (!Number.isSafeInteger(value) || value < 0) {
|
|
53
160
|
throw new Error("Media usage cleanup duration must be a non-negative whole number of seconds");
|
|
@@ -168,6 +275,15 @@ export interface MediaUsageGuardedReplaceResult {
|
|
|
168
275
|
source: MediaUsageSource | null;
|
|
169
276
|
}
|
|
170
277
|
|
|
278
|
+
export interface MediaUsageNewSourceProjection {
|
|
279
|
+
source: MediaUsageSourceInput;
|
|
280
|
+
occurrences: readonly MediaUsageOccurrenceInput[];
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
export interface MediaUsageExistingSourceProjection extends MediaUsageNewSourceProjection {
|
|
284
|
+
expectedSource: MediaUsageSource;
|
|
285
|
+
}
|
|
286
|
+
|
|
171
287
|
export interface MediaUsageGuardedDeleteResult {
|
|
172
288
|
deleted: boolean;
|
|
173
289
|
source: MediaUsageSource | null;
|
|
@@ -340,6 +456,12 @@ export interface MediaUsageCollectionIndexStatusScope {
|
|
|
340
456
|
reconciliationRequired: boolean;
|
|
341
457
|
}
|
|
342
458
|
|
|
459
|
+
export interface MediaUsageCollectionProgress {
|
|
460
|
+
status: "indexing" | "ready" | "needs_attention";
|
|
461
|
+
readyCollections: number;
|
|
462
|
+
totalCollections: number;
|
|
463
|
+
}
|
|
464
|
+
|
|
343
465
|
export interface MediaUsageEntrySource {
|
|
344
466
|
source: MediaUsageSource;
|
|
345
467
|
occurrences: MediaUsageOccurrence[];
|
|
@@ -537,14 +659,15 @@ export class MediaUsageRepository {
|
|
|
537
659
|
const uniqueSourceKeys = [...new Set(sourceKeys)];
|
|
538
660
|
const sources = new Map<string, MediaUsageSource>();
|
|
539
661
|
if (uniqueSourceKeys.length === 0) return sources;
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
const
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
.
|
|
547
|
-
|
|
662
|
+
for (const sourceKeyBatch of chunkJsonRows(uniqueSourceKeys)) {
|
|
663
|
+
const input = jsonTextValues(this.db, sourceKeyBatch);
|
|
664
|
+
const result = await sql<Selectable<MediaUsageSourceTable>>`
|
|
665
|
+
WITH requested AS (${input})
|
|
666
|
+
SELECT source.*
|
|
667
|
+
FROM _emdash_media_usage_sources AS source
|
|
668
|
+
INNER JOIN requested ON requested.value = source.source_key
|
|
669
|
+
`.execute(this.db);
|
|
670
|
+
for (const row of result.rows) {
|
|
548
671
|
const source = rowToSource(row);
|
|
549
672
|
sources.set(source.sourceKey, source);
|
|
550
673
|
}
|
|
@@ -619,6 +742,441 @@ export class MediaUsageRepository {
|
|
|
619
742
|
};
|
|
620
743
|
}
|
|
621
744
|
|
|
745
|
+
async replaceNewSourcesBatch(
|
|
746
|
+
projections: readonly MediaUsageNewSourceProjection[],
|
|
747
|
+
): Promise<Set<string>> {
|
|
748
|
+
const unique = [
|
|
749
|
+
...new Map(
|
|
750
|
+
projections.map((projection) => [projection.source.sourceKey, projection]),
|
|
751
|
+
).values(),
|
|
752
|
+
];
|
|
753
|
+
if (unique.length === 0) return new Set();
|
|
754
|
+
const collectionSlug = unique[0]?.source.collectionSlug;
|
|
755
|
+
const collectionId = unique[0]?.source.collectionId;
|
|
756
|
+
if (!collectionSlug || !collectionId) {
|
|
757
|
+
throw new Error("Canonical media usage batch requires collection identity");
|
|
758
|
+
}
|
|
759
|
+
validateIdentifier(collectionSlug, "collection slug");
|
|
760
|
+
if (
|
|
761
|
+
unique.some(
|
|
762
|
+
(projection) =>
|
|
763
|
+
projection.source.collectionSlug !== collectionSlug ||
|
|
764
|
+
projection.source.collectionId !== collectionId,
|
|
765
|
+
)
|
|
766
|
+
) {
|
|
767
|
+
throw new Error("Canonical media usage batch must contain one collection");
|
|
768
|
+
}
|
|
769
|
+
|
|
770
|
+
const now = new Date().toISOString();
|
|
771
|
+
const expiresAt = new Date(Date.now() + MEDIA_USAGE_GENERATION_WRITE_LEASE_MS).toISOString();
|
|
772
|
+
const prepared = unique.map((projection) => {
|
|
773
|
+
const generation = ulid();
|
|
774
|
+
return {
|
|
775
|
+
projection,
|
|
776
|
+
generation,
|
|
777
|
+
leaseToken: ulid(),
|
|
778
|
+
row: this.buildSourceRow(projection.source, generation, now),
|
|
779
|
+
};
|
|
780
|
+
});
|
|
781
|
+
const sourceRows = prepared.map((item) => ({
|
|
782
|
+
...item.row,
|
|
783
|
+
lease_token: item.leaseToken,
|
|
784
|
+
}));
|
|
785
|
+
const occurrenceRows = batchOccurrenceRows(prepared, now);
|
|
786
|
+
const estimatedQueries =
|
|
787
|
+
2 + chunkJsonRows(occurrenceRows).length + chunkJsonRows(sourceRows).length;
|
|
788
|
+
if (!mediaUsageQueryBudgetAllows(estimatedQueries)) {
|
|
789
|
+
if (unique.length === 1) return new Set();
|
|
790
|
+
const midpoint = Math.ceil(unique.length / 2);
|
|
791
|
+
const inserted = new Set<string>();
|
|
792
|
+
mergeInto(inserted, await this.replaceNewSourcesBatch(unique.slice(0, midpoint)));
|
|
793
|
+
mergeInto(inserted, await this.replaceNewSourcesBatch(unique.slice(midpoint)));
|
|
794
|
+
return inserted;
|
|
795
|
+
}
|
|
796
|
+
|
|
797
|
+
const leasesPayload = JSON.stringify(
|
|
798
|
+
prepared.map((item) => ({
|
|
799
|
+
source_key: item.row.source_key,
|
|
800
|
+
collection_id: item.row.collection_id,
|
|
801
|
+
collection_slug: item.row.collection_slug,
|
|
802
|
+
generation: item.generation,
|
|
803
|
+
lease_token: item.leaseToken,
|
|
804
|
+
expires_at: expiresAt,
|
|
805
|
+
created_at: now,
|
|
806
|
+
})),
|
|
807
|
+
);
|
|
808
|
+
const leases = this.generationWriteBatchInput(leasesPayload);
|
|
809
|
+
await sql`
|
|
810
|
+
WITH input AS (${leases})
|
|
811
|
+
INSERT INTO _emdash_media_usage_generation_writes (
|
|
812
|
+
source_key, generation, lease_token, expires_at, created_at
|
|
813
|
+
)
|
|
814
|
+
SELECT source_key, generation, lease_token, expires_at, created_at
|
|
815
|
+
FROM input
|
|
816
|
+
WHERE EXISTS (
|
|
817
|
+
SELECT 1
|
|
818
|
+
FROM _emdash_collections AS collection
|
|
819
|
+
INNER JOIN _emdash_media_usage_index_status AS status
|
|
820
|
+
ON status.collection_id = collection.id
|
|
821
|
+
AND status.scope_key = collection.slug
|
|
822
|
+
WHERE collection.id = input.collection_id
|
|
823
|
+
AND collection.slug = input.collection_slug
|
|
824
|
+
AND status.adapter_id = 'content-media'
|
|
825
|
+
AND status.scope_type = 'collection'
|
|
826
|
+
AND status.capture_state = 'active'
|
|
827
|
+
AND NOT EXISTS (
|
|
828
|
+
SELECT 1 FROM _emdash_media_usage_collection_deletions AS deletion
|
|
829
|
+
WHERE deletion.collection_id = input.collection_id
|
|
830
|
+
)
|
|
831
|
+
)
|
|
832
|
+
`.execute(this.db);
|
|
833
|
+
|
|
834
|
+
try {
|
|
835
|
+
await this.insertBatchOccurrences(occurrenceRows);
|
|
836
|
+
const tableName = `ec_${collectionSlug}`;
|
|
837
|
+
validateIdentifier(tableName, "content table");
|
|
838
|
+
const inserted = new Set<string>();
|
|
839
|
+
for (const sourceRowBatch of chunkJsonRows(sourceRows)) {
|
|
840
|
+
const input = this.sourceBatchInput(JSON.stringify(sourceRowBatch));
|
|
841
|
+
const result = await sql<{ source_key: string }>`
|
|
842
|
+
WITH input AS (${input})
|
|
843
|
+
INSERT INTO _emdash_media_usage_sources (
|
|
844
|
+
source_key, source_type, collection_id, collection_slug, content_id,
|
|
845
|
+
source_variant, locale, translation_group, content_slug, content_title,
|
|
846
|
+
content_status, content_scheduled_at, content_deleted_at, revision_id,
|
|
847
|
+
current_generation, schema_version, source_updated_at, source_version,
|
|
848
|
+
source_fingerprint, identity_version, source_completeness,
|
|
849
|
+
last_attempted_at, last_error_code, indexed_at, updated_at
|
|
850
|
+
)
|
|
851
|
+
SELECT
|
|
852
|
+
input.source_key, input.source_type, input.collection_id, input.collection_slug,
|
|
853
|
+
input.content_id, input.source_variant, input.locale, input.translation_group,
|
|
854
|
+
input.content_slug, input.content_title, input.content_status,
|
|
855
|
+
input.content_scheduled_at, input.content_deleted_at, input.revision_id,
|
|
856
|
+
input.current_generation, input.schema_version, input.source_updated_at,
|
|
857
|
+
input.source_version, input.source_fingerprint, input.identity_version,
|
|
858
|
+
input.source_completeness, input.last_attempted_at, input.last_error_code,
|
|
859
|
+
input.indexed_at, input.updated_at
|
|
860
|
+
FROM input
|
|
861
|
+
WHERE EXISTS (
|
|
862
|
+
SELECT 1
|
|
863
|
+
FROM _emdash_media_usage_generation_writes AS writer
|
|
864
|
+
WHERE writer.source_key = input.source_key
|
|
865
|
+
AND writer.generation = input.current_generation
|
|
866
|
+
AND writer.lease_token = input.lease_token
|
|
867
|
+
AND ${this.generationWriteLeaseExpiryIsInFuture("writer.expires_at")}
|
|
868
|
+
)
|
|
869
|
+
AND EXISTS (
|
|
870
|
+
SELECT 1
|
|
871
|
+
FROM _emdash_collections AS collection
|
|
872
|
+
INNER JOIN _emdash_media_usage_index_status AS status
|
|
873
|
+
ON status.collection_id = collection.id
|
|
874
|
+
AND status.scope_key = collection.slug
|
|
875
|
+
WHERE collection.id = input.collection_id
|
|
876
|
+
AND collection.slug = input.collection_slug
|
|
877
|
+
AND status.adapter_id = 'content-media'
|
|
878
|
+
AND status.scope_type = 'collection'
|
|
879
|
+
AND status.capture_state = 'active'
|
|
880
|
+
AND NOT EXISTS (
|
|
881
|
+
SELECT 1
|
|
882
|
+
FROM _emdash_media_usage_collection_deletions AS deletion
|
|
883
|
+
WHERE deletion.collection_id = input.collection_id
|
|
884
|
+
)
|
|
885
|
+
)
|
|
886
|
+
AND EXISTS (
|
|
887
|
+
SELECT 1
|
|
888
|
+
FROM ${sql.ref(tableName)} AS content
|
|
889
|
+
WHERE content.id = input.content_id
|
|
890
|
+
AND content.version = input.source_version
|
|
891
|
+
AND content.updated_at = input.source_updated_at
|
|
892
|
+
AND (
|
|
893
|
+
(input.source_variant = 'columns' AND ${nullableRefMatch("content.live_revision_id", "input.revision_id")})
|
|
894
|
+
OR
|
|
895
|
+
(input.source_variant = 'draft_overlay' AND ${nullableRefMatch("content.draft_revision_id", "input.revision_id")})
|
|
896
|
+
)
|
|
897
|
+
)
|
|
898
|
+
ON CONFLICT (source_key) DO NOTHING
|
|
899
|
+
RETURNING source_key
|
|
900
|
+
`.execute(this.db);
|
|
901
|
+
for (const row of result.rows) inserted.add(row.source_key);
|
|
902
|
+
}
|
|
903
|
+
return inserted;
|
|
904
|
+
} finally {
|
|
905
|
+
await sql`
|
|
906
|
+
WITH input AS (${leases})
|
|
907
|
+
DELETE FROM _emdash_media_usage_generation_writes AS writer
|
|
908
|
+
WHERE EXISTS (
|
|
909
|
+
SELECT 1
|
|
910
|
+
FROM input
|
|
911
|
+
WHERE input.source_key = writer.source_key
|
|
912
|
+
AND input.generation = writer.generation
|
|
913
|
+
AND input.lease_token = writer.lease_token
|
|
914
|
+
)
|
|
915
|
+
`.execute(this.db);
|
|
916
|
+
}
|
|
917
|
+
}
|
|
918
|
+
|
|
919
|
+
async replaceExistingSourcesBatch(
|
|
920
|
+
projections: readonly MediaUsageExistingSourceProjection[],
|
|
921
|
+
): Promise<Set<string>> {
|
|
922
|
+
const unique = [
|
|
923
|
+
...new Map(
|
|
924
|
+
projections.map((projection) => [projection.source.sourceKey, projection]),
|
|
925
|
+
).values(),
|
|
926
|
+
];
|
|
927
|
+
if (unique.length === 0) return new Set();
|
|
928
|
+
const collectionSlug = unique[0]?.source.collectionSlug;
|
|
929
|
+
const collectionId = unique[0]?.source.collectionId;
|
|
930
|
+
if (!collectionSlug || !collectionId) {
|
|
931
|
+
throw new Error("Canonical media usage batch requires collection identity");
|
|
932
|
+
}
|
|
933
|
+
validateIdentifier(collectionSlug, "collection slug");
|
|
934
|
+
if (
|
|
935
|
+
unique.some(
|
|
936
|
+
(projection) =>
|
|
937
|
+
projection.source.collectionSlug !== collectionSlug ||
|
|
938
|
+
projection.source.collectionId !== collectionId,
|
|
939
|
+
)
|
|
940
|
+
) {
|
|
941
|
+
throw new Error("Canonical media usage batch must contain one collection");
|
|
942
|
+
}
|
|
943
|
+
|
|
944
|
+
const now = new Date().toISOString();
|
|
945
|
+
const expiresAt = new Date(Date.now() + MEDIA_USAGE_GENERATION_WRITE_LEASE_MS).toISOString();
|
|
946
|
+
const prepared = unique.map((projection) => {
|
|
947
|
+
const generation = ulid();
|
|
948
|
+
return {
|
|
949
|
+
projection,
|
|
950
|
+
generation,
|
|
951
|
+
leaseToken: ulid(),
|
|
952
|
+
row: this.buildSourceRow(projection.source, generation, now),
|
|
953
|
+
};
|
|
954
|
+
});
|
|
955
|
+
const sourceRows = prepared.map((item) => ({
|
|
956
|
+
...item.row,
|
|
957
|
+
lease_token: item.leaseToken,
|
|
958
|
+
expected_generation: item.projection.expectedSource.currentGeneration,
|
|
959
|
+
expected_collection_id: item.projection.expectedSource.collectionId,
|
|
960
|
+
expected_updated_at: item.projection.expectedSource.updatedAt,
|
|
961
|
+
expected_source_fingerprint: item.projection.expectedSource.sourceFingerprint,
|
|
962
|
+
expected_source_updated_at: item.projection.expectedSource.sourceUpdatedAt,
|
|
963
|
+
expected_source_version: item.projection.expectedSource.sourceVersion,
|
|
964
|
+
expected_identity_version: item.projection.expectedSource.identityVersion,
|
|
965
|
+
expected_revision_id: item.projection.expectedSource.revisionId,
|
|
966
|
+
expected_source_completeness: item.projection.expectedSource.sourceCompleteness,
|
|
967
|
+
expected_last_attempted_at: item.projection.expectedSource.lastAttemptedAt,
|
|
968
|
+
expected_last_error_code: item.projection.expectedSource.lastErrorCode,
|
|
969
|
+
}));
|
|
970
|
+
const occurrenceRows = batchOccurrenceRows(prepared, now);
|
|
971
|
+
const estimatedQueries =
|
|
972
|
+
2 + chunkJsonRows(occurrenceRows).length + chunkJsonRows(sourceRows).length;
|
|
973
|
+
if (!mediaUsageQueryBudgetAllows(estimatedQueries)) {
|
|
974
|
+
if (unique.length === 1) return new Set();
|
|
975
|
+
const midpoint = Math.ceil(unique.length / 2);
|
|
976
|
+
const replaced = new Set<string>();
|
|
977
|
+
mergeInto(replaced, await this.replaceExistingSourcesBatch(unique.slice(0, midpoint)));
|
|
978
|
+
mergeInto(replaced, await this.replaceExistingSourcesBatch(unique.slice(midpoint)));
|
|
979
|
+
return replaced;
|
|
980
|
+
}
|
|
981
|
+
const leasesPayload = JSON.stringify(
|
|
982
|
+
prepared.map((item) => ({
|
|
983
|
+
source_key: item.row.source_key,
|
|
984
|
+
collection_id: item.row.collection_id,
|
|
985
|
+
collection_slug: item.row.collection_slug,
|
|
986
|
+
generation: item.generation,
|
|
987
|
+
lease_token: item.leaseToken,
|
|
988
|
+
expires_at: expiresAt,
|
|
989
|
+
created_at: now,
|
|
990
|
+
})),
|
|
991
|
+
);
|
|
992
|
+
const leases = this.generationWriteBatchInput(leasesPayload);
|
|
993
|
+
await sql`
|
|
994
|
+
WITH input AS (${leases})
|
|
995
|
+
INSERT INTO _emdash_media_usage_generation_writes (
|
|
996
|
+
source_key, generation, lease_token, expires_at, created_at
|
|
997
|
+
)
|
|
998
|
+
SELECT source_key, generation, lease_token, expires_at, created_at
|
|
999
|
+
FROM input
|
|
1000
|
+
WHERE EXISTS (
|
|
1001
|
+
SELECT 1
|
|
1002
|
+
FROM _emdash_collections AS collection
|
|
1003
|
+
INNER JOIN _emdash_media_usage_index_status AS status
|
|
1004
|
+
ON status.collection_id = collection.id
|
|
1005
|
+
AND status.scope_key = collection.slug
|
|
1006
|
+
WHERE collection.id = input.collection_id
|
|
1007
|
+
AND collection.slug = input.collection_slug
|
|
1008
|
+
AND status.adapter_id = 'content-media'
|
|
1009
|
+
AND status.scope_type = 'collection'
|
|
1010
|
+
AND status.capture_state = 'active'
|
|
1011
|
+
AND NOT EXISTS (
|
|
1012
|
+
SELECT 1 FROM _emdash_media_usage_collection_deletions AS deletion
|
|
1013
|
+
WHERE deletion.collection_id = input.collection_id
|
|
1014
|
+
)
|
|
1015
|
+
)
|
|
1016
|
+
`.execute(this.db);
|
|
1017
|
+
|
|
1018
|
+
try {
|
|
1019
|
+
await this.insertBatchOccurrences(occurrenceRows);
|
|
1020
|
+
const tableName = `ec_${collectionSlug}`;
|
|
1021
|
+
validateIdentifier(tableName, "content table");
|
|
1022
|
+
const replaced = new Set<string>();
|
|
1023
|
+
for (const sourceRowBatch of chunkJsonRows(sourceRows)) {
|
|
1024
|
+
const input = this.sourceBatchInput(JSON.stringify(sourceRowBatch));
|
|
1025
|
+
const result = await sql<{ source_key: string }>`
|
|
1026
|
+
WITH input AS (${input})
|
|
1027
|
+
UPDATE _emdash_media_usage_sources AS source
|
|
1028
|
+
SET source_type = input.source_type,
|
|
1029
|
+
collection_id = input.collection_id,
|
|
1030
|
+
collection_slug = input.collection_slug,
|
|
1031
|
+
content_id = input.content_id,
|
|
1032
|
+
source_variant = input.source_variant,
|
|
1033
|
+
locale = input.locale,
|
|
1034
|
+
translation_group = input.translation_group,
|
|
1035
|
+
content_slug = input.content_slug,
|
|
1036
|
+
content_title = input.content_title,
|
|
1037
|
+
content_status = input.content_status,
|
|
1038
|
+
content_scheduled_at = input.content_scheduled_at,
|
|
1039
|
+
content_deleted_at = input.content_deleted_at,
|
|
1040
|
+
revision_id = input.revision_id,
|
|
1041
|
+
current_generation = input.current_generation,
|
|
1042
|
+
schema_version = input.schema_version,
|
|
1043
|
+
source_updated_at = input.source_updated_at,
|
|
1044
|
+
source_version = input.source_version,
|
|
1045
|
+
source_fingerprint = input.source_fingerprint,
|
|
1046
|
+
identity_version = input.identity_version,
|
|
1047
|
+
source_completeness = input.source_completeness,
|
|
1048
|
+
last_attempted_at = input.last_attempted_at,
|
|
1049
|
+
last_error_code = input.last_error_code,
|
|
1050
|
+
indexed_at = input.indexed_at,
|
|
1051
|
+
updated_at = input.updated_at
|
|
1052
|
+
FROM input
|
|
1053
|
+
WHERE source.source_key = input.source_key
|
|
1054
|
+
AND source.current_generation = input.expected_generation
|
|
1055
|
+
AND ${this.batchRefsMatch("source.collection_id", "input.expected_collection_id")}
|
|
1056
|
+
AND source.updated_at = input.expected_updated_at
|
|
1057
|
+
AND ${this.batchRefsMatch("source.source_fingerprint", "input.expected_source_fingerprint")}
|
|
1058
|
+
AND ${this.batchRefsMatch("source.source_updated_at", "input.expected_source_updated_at")}
|
|
1059
|
+
AND ${this.batchRefsMatch("source.source_version", "input.expected_source_version")}
|
|
1060
|
+
AND ${this.batchRefsMatch("source.identity_version", "input.expected_identity_version")}
|
|
1061
|
+
AND ${this.batchRefsMatch("source.revision_id", "input.expected_revision_id")}
|
|
1062
|
+
AND source.source_completeness = input.expected_source_completeness
|
|
1063
|
+
AND ${this.batchRefsMatch("source.last_attempted_at", "input.expected_last_attempted_at")}
|
|
1064
|
+
AND ${this.batchRefsMatch("source.last_error_code", "input.expected_last_error_code")}
|
|
1065
|
+
AND EXISTS (
|
|
1066
|
+
SELECT 1
|
|
1067
|
+
FROM _emdash_media_usage_generation_writes AS writer
|
|
1068
|
+
WHERE writer.source_key = input.source_key
|
|
1069
|
+
AND writer.generation = input.current_generation
|
|
1070
|
+
AND writer.lease_token = input.lease_token
|
|
1071
|
+
AND ${this.generationWriteLeaseExpiryIsInFuture("writer.expires_at")}
|
|
1072
|
+
)
|
|
1073
|
+
AND EXISTS (
|
|
1074
|
+
SELECT 1
|
|
1075
|
+
FROM _emdash_collections AS collection
|
|
1076
|
+
INNER JOIN _emdash_media_usage_index_status AS status
|
|
1077
|
+
ON status.collection_id = collection.id
|
|
1078
|
+
AND status.scope_key = collection.slug
|
|
1079
|
+
WHERE collection.id = input.collection_id
|
|
1080
|
+
AND collection.slug = input.collection_slug
|
|
1081
|
+
AND status.adapter_id = 'content-media'
|
|
1082
|
+
AND status.scope_type = 'collection'
|
|
1083
|
+
AND status.capture_state = 'active'
|
|
1084
|
+
AND NOT EXISTS (
|
|
1085
|
+
SELECT 1
|
|
1086
|
+
FROM _emdash_media_usage_collection_deletions AS deletion
|
|
1087
|
+
WHERE deletion.collection_id = input.collection_id
|
|
1088
|
+
)
|
|
1089
|
+
)
|
|
1090
|
+
AND EXISTS (
|
|
1091
|
+
SELECT 1
|
|
1092
|
+
FROM ${sql.ref(tableName)} AS content
|
|
1093
|
+
WHERE content.id = input.content_id
|
|
1094
|
+
AND content.version = input.source_version
|
|
1095
|
+
AND content.updated_at = input.source_updated_at
|
|
1096
|
+
AND (
|
|
1097
|
+
(input.source_variant = 'columns' AND ${nullableRefMatch("content.live_revision_id", "input.revision_id")})
|
|
1098
|
+
OR
|
|
1099
|
+
(input.source_variant = 'draft_overlay' AND ${nullableRefMatch("content.draft_revision_id", "input.revision_id")})
|
|
1100
|
+
)
|
|
1101
|
+
)
|
|
1102
|
+
RETURNING ${isPostgres(this.db) ? sql`source.source_key` : sql`source_key`} AS source_key
|
|
1103
|
+
`.execute(this.db);
|
|
1104
|
+
for (const row of result.rows) replaced.add(row.source_key);
|
|
1105
|
+
}
|
|
1106
|
+
return replaced;
|
|
1107
|
+
} finally {
|
|
1108
|
+
await sql`
|
|
1109
|
+
WITH input AS (${leases})
|
|
1110
|
+
DELETE FROM _emdash_media_usage_generation_writes AS writer
|
|
1111
|
+
WHERE EXISTS (
|
|
1112
|
+
SELECT 1
|
|
1113
|
+
FROM input
|
|
1114
|
+
WHERE input.source_key = writer.source_key
|
|
1115
|
+
AND input.generation = writer.generation
|
|
1116
|
+
AND input.lease_token = writer.lease_token
|
|
1117
|
+
)
|
|
1118
|
+
`.execute(this.db);
|
|
1119
|
+
}
|
|
1120
|
+
}
|
|
1121
|
+
|
|
1122
|
+
async matchingExistingSourcesBatch(
|
|
1123
|
+
projections: readonly MediaUsageExistingSourceProjection[],
|
|
1124
|
+
): Promise<Set<string>> {
|
|
1125
|
+
if (projections.length === 0) return new Set();
|
|
1126
|
+
const now = new Date().toISOString();
|
|
1127
|
+
const rows = projections.map((projection) => ({
|
|
1128
|
+
...this.buildSourceRow(projection.source, projection.expectedSource.currentGeneration, now),
|
|
1129
|
+
expected_generation: projection.expectedSource.currentGeneration,
|
|
1130
|
+
expected_collection_id: projection.expectedSource.collectionId,
|
|
1131
|
+
expected_updated_at: projection.expectedSource.updatedAt,
|
|
1132
|
+
expected_source_fingerprint: projection.expectedSource.sourceFingerprint,
|
|
1133
|
+
expected_source_updated_at: projection.expectedSource.sourceUpdatedAt,
|
|
1134
|
+
expected_source_version: projection.expectedSource.sourceVersion,
|
|
1135
|
+
expected_identity_version: projection.expectedSource.identityVersion,
|
|
1136
|
+
expected_revision_id: projection.expectedSource.revisionId,
|
|
1137
|
+
expected_source_completeness: projection.expectedSource.sourceCompleteness,
|
|
1138
|
+
expected_last_attempted_at: projection.expectedSource.lastAttemptedAt,
|
|
1139
|
+
expected_last_error_code: projection.expectedSource.lastErrorCode,
|
|
1140
|
+
}));
|
|
1141
|
+
if (!mediaUsageQueryBudgetAllows(chunkJsonRows(rows).length)) {
|
|
1142
|
+
if (projections.length === 1) return new Set();
|
|
1143
|
+
const midpoint = Math.ceil(projections.length / 2);
|
|
1144
|
+
const matched = new Set<string>();
|
|
1145
|
+
mergeInto(matched, await this.matchingExistingSourcesBatch(projections.slice(0, midpoint)));
|
|
1146
|
+
mergeInto(matched, await this.matchingExistingSourcesBatch(projections.slice(midpoint)));
|
|
1147
|
+
return matched;
|
|
1148
|
+
}
|
|
1149
|
+
const matched = new Set<string>();
|
|
1150
|
+
for (const batch of chunkJsonRows(rows)) {
|
|
1151
|
+
const input = this.sourceBatchInput(JSON.stringify(batch));
|
|
1152
|
+
const result = await sql<{ source_key: string }>`
|
|
1153
|
+
WITH input AS (${input})
|
|
1154
|
+
SELECT source.source_key
|
|
1155
|
+
FROM _emdash_media_usage_sources AS source
|
|
1156
|
+
INNER JOIN input ON input.source_key = source.source_key
|
|
1157
|
+
WHERE source.current_generation = input.expected_generation
|
|
1158
|
+
AND ${this.batchRefsMatch("source.collection_id", "input.expected_collection_id")}
|
|
1159
|
+
AND source.updated_at = input.expected_updated_at
|
|
1160
|
+
AND ${this.batchRefsMatch("source.source_fingerprint", "input.expected_source_fingerprint")}
|
|
1161
|
+
AND ${this.batchRefsMatch("source.source_updated_at", "input.expected_source_updated_at")}
|
|
1162
|
+
AND ${this.batchRefsMatch("source.source_version", "input.expected_source_version")}
|
|
1163
|
+
AND ${this.batchRefsMatch("source.identity_version", "input.expected_identity_version")}
|
|
1164
|
+
AND ${this.batchRefsMatch("source.revision_id", "input.expected_revision_id")}
|
|
1165
|
+
AND source.source_completeness = input.expected_source_completeness
|
|
1166
|
+
AND ${this.batchRefsMatch("source.last_attempted_at", "input.expected_last_attempted_at")}
|
|
1167
|
+
AND ${this.batchRefsMatch("source.last_error_code", "input.expected_last_error_code")}
|
|
1168
|
+
AND EXISTS (
|
|
1169
|
+
SELECT 1
|
|
1170
|
+
FROM _emdash_collections AS collection
|
|
1171
|
+
WHERE collection.id = source.collection_id
|
|
1172
|
+
AND collection.slug = source.collection_slug
|
|
1173
|
+
)
|
|
1174
|
+
`.execute(this.db);
|
|
1175
|
+
for (const row of result.rows) matched.add(row.source_key);
|
|
1176
|
+
}
|
|
1177
|
+
return matched;
|
|
1178
|
+
}
|
|
1179
|
+
|
|
622
1180
|
async markSourceAttempted(source: MediaUsageSourceInput): Promise<MediaUsageSource> {
|
|
623
1181
|
if (source.collectionId !== undefined && source.collectionId !== null) {
|
|
624
1182
|
const expectedSource = await this.findSource(source.sourceKey);
|
|
@@ -762,6 +1320,129 @@ export class MediaUsageRepository {
|
|
|
762
1320
|
}));
|
|
763
1321
|
}
|
|
764
1322
|
|
|
1323
|
+
async findCollectionProgress(): Promise<MediaUsageCollectionProgress | null> {
|
|
1324
|
+
const result = await sql<{
|
|
1325
|
+
activation_active: boolean | number;
|
|
1326
|
+
activation_generation: number | string | null;
|
|
1327
|
+
needs_attention: boolean | number;
|
|
1328
|
+
ready_collections: number | string;
|
|
1329
|
+
total_collections: number | string;
|
|
1330
|
+
cleanup_pending: boolean | number;
|
|
1331
|
+
}>`
|
|
1332
|
+
WITH collection_progress AS (
|
|
1333
|
+
SELECT
|
|
1334
|
+
CASE WHEN status.status = 'complete'
|
|
1335
|
+
AND status.schema_version = ${CONTENT_SOURCE_SCHEMA_VERSION}
|
|
1336
|
+
AND status.reconciliation_required = 0
|
|
1337
|
+
AND status.capture_state = 'active'
|
|
1338
|
+
AND NOT EXISTS (
|
|
1339
|
+
SELECT 1 FROM _emdash_media_usage_work AS work
|
|
1340
|
+
WHERE work.collection_id = collection.id
|
|
1341
|
+
AND work.collection_slug = collection.slug
|
|
1342
|
+
)
|
|
1343
|
+
THEN 1 ELSE 0 END AS is_ready,
|
|
1344
|
+
CASE WHEN status.collection_id IS NULL
|
|
1345
|
+
OR COALESCE(status.capture_state, '') <> 'active'
|
|
1346
|
+
OR status.status NOT IN ('complete', 'never', 'running', 'partial', 'failed', 'stale')
|
|
1347
|
+
OR status.status = 'failed'
|
|
1348
|
+
OR (
|
|
1349
|
+
status.reconciliation_required = 0
|
|
1350
|
+
AND (
|
|
1351
|
+
status.status <> 'complete'
|
|
1352
|
+
OR COALESCE(status.schema_version, -1) <> ${CONTENT_SOURCE_SCHEMA_VERSION}
|
|
1353
|
+
)
|
|
1354
|
+
AND NOT EXISTS (
|
|
1355
|
+
SELECT 1 FROM _emdash_media_usage_work AS work
|
|
1356
|
+
WHERE work.collection_id = collection.id
|
|
1357
|
+
AND work.collection_slug = collection.slug
|
|
1358
|
+
)
|
|
1359
|
+
)
|
|
1360
|
+
OR EXISTS (
|
|
1361
|
+
SELECT 1 FROM _emdash_media_usage_work AS work
|
|
1362
|
+
WHERE work.collection_id = collection.id
|
|
1363
|
+
AND work.collection_slug = collection.slug
|
|
1364
|
+
AND work.state = 'failed'
|
|
1365
|
+
)
|
|
1366
|
+
OR EXISTS (
|
|
1367
|
+
SELECT 1 FROM _emdash_media_usage_reconciliations AS reconciliation
|
|
1368
|
+
WHERE reconciliation.collection_id = collection.id
|
|
1369
|
+
AND reconciliation.collection_slug = collection.slug
|
|
1370
|
+
AND reconciliation.state = 'failed'
|
|
1371
|
+
AND status.reconciliation_required = 1
|
|
1372
|
+
AND (
|
|
1373
|
+
reconciliation.target_epoch IS NULL
|
|
1374
|
+
OR reconciliation.target_epoch >= status.change_epoch
|
|
1375
|
+
)
|
|
1376
|
+
)
|
|
1377
|
+
THEN 1 ELSE 0 END AS needs_attention
|
|
1378
|
+
FROM _emdash_collections AS collection
|
|
1379
|
+
LEFT JOIN _emdash_media_usage_index_status AS status
|
|
1380
|
+
ON status.adapter_id = 'content-media'
|
|
1381
|
+
AND status.scope_type = 'collection'
|
|
1382
|
+
AND status.collection_id = collection.id
|
|
1383
|
+
AND status.scope_key = collection.slug
|
|
1384
|
+
WHERE NOT EXISTS (
|
|
1385
|
+
SELECT 1 FROM _emdash_media_usage_collection_deletions AS deletion
|
|
1386
|
+
WHERE deletion.collection_id = collection.id
|
|
1387
|
+
AND deletion.collection_slug = collection.slug
|
|
1388
|
+
)
|
|
1389
|
+
)
|
|
1390
|
+
SELECT
|
|
1391
|
+
(
|
|
1392
|
+
SELECT activation.runtime_generation
|
|
1393
|
+
FROM _emdash_media_usage_activation AS activation
|
|
1394
|
+
WHERE activation.task_key = 'incremental_capture'
|
|
1395
|
+
) AS activation_generation,
|
|
1396
|
+
EXISTS (
|
|
1397
|
+
SELECT 1 FROM _emdash_media_usage_activation AS activation
|
|
1398
|
+
WHERE activation.task_key = 'incremental_capture'
|
|
1399
|
+
AND activation.state = 'active'
|
|
1400
|
+
) AS activation_active,
|
|
1401
|
+
COUNT(*) AS total_collections,
|
|
1402
|
+
COALESCE(SUM(is_ready), 0) AS ready_collections,
|
|
1403
|
+
EXISTS (
|
|
1404
|
+
SELECT 1 FROM _emdash_media_usage_collection_deletions AS deletion
|
|
1405
|
+
WHERE deletion.state IN ('pending', 'retry', 'leased')
|
|
1406
|
+
) AS cleanup_pending,
|
|
1407
|
+
CASE WHEN COALESCE(MAX(needs_attention), 0) = 1 OR EXISTS (
|
|
1408
|
+
SELECT 1 FROM _emdash_media_usage_collection_deletions AS deletion
|
|
1409
|
+
WHERE deletion.state = 'failed'
|
|
1410
|
+
) THEN 1 ELSE 0 END AS needs_attention
|
|
1411
|
+
FROM collection_progress
|
|
1412
|
+
`.execute(this.db);
|
|
1413
|
+
const row = result.rows[0];
|
|
1414
|
+
if (!row) throw new Error("Media usage progress query returned no result");
|
|
1415
|
+
if (!row.activation_active) return null;
|
|
1416
|
+
if (Number(row.activation_generation) !== MEDIA_USAGE_ACTIVATION_RUNTIME_GENERATION) {
|
|
1417
|
+
throw new MediaUsageActivationVersionMismatchError(
|
|
1418
|
+
"Media usage activation runtime generation is incompatible",
|
|
1419
|
+
);
|
|
1420
|
+
}
|
|
1421
|
+
const readyCollections = Number(row.ready_collections);
|
|
1422
|
+
const totalCollections = Number(row.total_collections);
|
|
1423
|
+
const cleanupPending = Number(row.cleanup_pending);
|
|
1424
|
+
const needsAttention = Number(row.needs_attention);
|
|
1425
|
+
if (
|
|
1426
|
+
!Number.isSafeInteger(readyCollections) ||
|
|
1427
|
+
!Number.isSafeInteger(totalCollections) ||
|
|
1428
|
+
readyCollections < 0 ||
|
|
1429
|
+
totalCollections < readyCollections ||
|
|
1430
|
+
(cleanupPending !== 0 && cleanupPending !== 1) ||
|
|
1431
|
+
(needsAttention !== 0 && needsAttention !== 1)
|
|
1432
|
+
) {
|
|
1433
|
+
throw new Error("Media usage progress query returned invalid counts");
|
|
1434
|
+
}
|
|
1435
|
+
return {
|
|
1436
|
+
status: needsAttention
|
|
1437
|
+
? "needs_attention"
|
|
1438
|
+
: readyCollections === totalCollections && cleanupPending === 0
|
|
1439
|
+
? "ready"
|
|
1440
|
+
: "indexing",
|
|
1441
|
+
readyCollections,
|
|
1442
|
+
totalCollections,
|
|
1443
|
+
};
|
|
1444
|
+
}
|
|
1445
|
+
|
|
765
1446
|
async findCurrentEntryUsagePageByMediaId(
|
|
766
1447
|
mediaId: string,
|
|
767
1448
|
options: FindMediaUsageOptions = {},
|
|
@@ -1694,6 +2375,7 @@ export class MediaUsageRepository {
|
|
|
1694
2375
|
last_error_code: sql<
|
|
1695
2376
|
string | null
|
|
1696
2377
|
>`CASE WHEN ${canComplete} THEN NULL ELSE last_error_code END`,
|
|
2378
|
+
cursor: sql<string | null>`CASE WHEN ${canComplete} THEN NULL ELSE cursor END`,
|
|
1697
2379
|
last_incremental_success_at: now,
|
|
1698
2380
|
updated_at: now,
|
|
1699
2381
|
})
|
|
@@ -1715,6 +2397,94 @@ export class MediaUsageRepository {
|
|
|
1715
2397
|
return Number(result.numUpdatedRows ?? 0) > 0;
|
|
1716
2398
|
}
|
|
1717
2399
|
|
|
2400
|
+
async prepareIncrementalFinalization(
|
|
2401
|
+
input: MediaUsageIncrementalStatusIdentity,
|
|
2402
|
+
): Promise<
|
|
2403
|
+
{ outcome: "marked"; marker: string } | { outcome: "not_required" } | { outcome: "lost" }
|
|
2404
|
+
> {
|
|
2405
|
+
const observed = await this.db
|
|
2406
|
+
.selectFrom("_emdash_media_usage_index_status")
|
|
2407
|
+
.select(["change_epoch", "reconciliation_required"])
|
|
2408
|
+
.where("adapter_id", "=", "content-media")
|
|
2409
|
+
.where("scope_type", "=", "collection")
|
|
2410
|
+
.where("scope_key", "=", input.collectionSlug)
|
|
2411
|
+
.where("collection_id", "=", input.collectionId)
|
|
2412
|
+
.where("capture_state", "=", "active")
|
|
2413
|
+
.executeTakeFirst();
|
|
2414
|
+
if (!observed) return { outcome: "lost" };
|
|
2415
|
+
if (observed.reconciliation_required !== 0) return { outcome: "not_required" };
|
|
2416
|
+
const marker = `incremental-finalize:${String(observed.change_epoch)}:${ulid()}`;
|
|
2417
|
+
const result = await this.db
|
|
2418
|
+
.updateTable("_emdash_media_usage_index_status")
|
|
2419
|
+
.set({ cursor: marker, updated_at: this.sortableUtcTimestamp() })
|
|
2420
|
+
.where("adapter_id", "=", "content-media")
|
|
2421
|
+
.where("scope_type", "=", "collection")
|
|
2422
|
+
.where("scope_key", "=", input.collectionSlug)
|
|
2423
|
+
.where("collection_id", "=", input.collectionId)
|
|
2424
|
+
.where("capture_state", "=", "active")
|
|
2425
|
+
.where("reconciliation_required", "=", 0)
|
|
2426
|
+
.where("change_epoch", "=", observed.change_epoch)
|
|
2427
|
+
.where(
|
|
2428
|
+
sql<boolean>`EXISTS (
|
|
2429
|
+
SELECT 1
|
|
2430
|
+
FROM _emdash_collections AS collection
|
|
2431
|
+
WHERE collection.id = ${input.collectionId}
|
|
2432
|
+
AND collection.slug = ${input.collectionSlug}
|
|
2433
|
+
)`,
|
|
2434
|
+
)
|
|
2435
|
+
.where(
|
|
2436
|
+
sql<boolean>`NOT EXISTS (
|
|
2437
|
+
SELECT 1
|
|
2438
|
+
FROM _emdash_media_usage_collection_deletions AS deletion
|
|
2439
|
+
WHERE deletion.collection_id = ${input.collectionId}
|
|
2440
|
+
)`,
|
|
2441
|
+
)
|
|
2442
|
+
.executeTakeFirst();
|
|
2443
|
+
return Number(result.numUpdatedRows ?? 0) > 0
|
|
2444
|
+
? { outcome: "marked", marker }
|
|
2445
|
+
: { outcome: "lost" };
|
|
2446
|
+
}
|
|
2447
|
+
|
|
2448
|
+
async recoverIncrementalFinalizations(): Promise<number> {
|
|
2449
|
+
const markerMatchesEpoch = isPostgres(this.db)
|
|
2450
|
+
? sql<boolean>`status.cursor LIKE ('incremental-finalize:' || status.change_epoch::text || ':%')`
|
|
2451
|
+
: sql<boolean>`status.cursor LIKE ('incremental-finalize:' || CAST(status.change_epoch AS text) || ':%')`;
|
|
2452
|
+
const now = new Date().toISOString();
|
|
2453
|
+
const result = await sql<{ collection_id: string }>`
|
|
2454
|
+
UPDATE _emdash_media_usage_index_status AS status
|
|
2455
|
+
SET status = 'complete',
|
|
2456
|
+
completed_at = ${now},
|
|
2457
|
+
cursor = NULL,
|
|
2458
|
+
last_error_code = NULL,
|
|
2459
|
+
last_incremental_success_at = ${now},
|
|
2460
|
+
updated_at = ${now}
|
|
2461
|
+
WHERE status.adapter_id = 'content-media'
|
|
2462
|
+
AND status.scope_type = 'collection'
|
|
2463
|
+
AND status.capture_state = 'active'
|
|
2464
|
+
AND status.reconciliation_required = 0
|
|
2465
|
+
AND status.cursor IS NOT NULL
|
|
2466
|
+
AND ${markerMatchesEpoch}
|
|
2467
|
+
AND EXISTS (
|
|
2468
|
+
SELECT 1
|
|
2469
|
+
FROM _emdash_collections AS collection
|
|
2470
|
+
WHERE collection.id = status.collection_id
|
|
2471
|
+
AND collection.slug = status.scope_key
|
|
2472
|
+
)
|
|
2473
|
+
AND NOT EXISTS (
|
|
2474
|
+
SELECT 1
|
|
2475
|
+
FROM _emdash_media_usage_collection_deletions AS deletion
|
|
2476
|
+
WHERE deletion.collection_id = status.collection_id
|
|
2477
|
+
)
|
|
2478
|
+
AND NOT EXISTS (
|
|
2479
|
+
SELECT 1
|
|
2480
|
+
FROM _emdash_media_usage_work AS work
|
|
2481
|
+
WHERE work.collection_id = status.collection_id
|
|
2482
|
+
)
|
|
2483
|
+
RETURNING collection_id
|
|
2484
|
+
`.execute(this.db);
|
|
2485
|
+
return result.rows.length;
|
|
2486
|
+
}
|
|
2487
|
+
|
|
1718
2488
|
async recordIncrementalFailure(
|
|
1719
2489
|
input: MediaUsageIncrementalStatusIdentity & {
|
|
1720
2490
|
contentId: string;
|
|
@@ -1778,6 +2548,71 @@ export class MediaUsageRepository {
|
|
|
1778
2548
|
return Number(result.numUpdatedRows ?? 0) > 0;
|
|
1779
2549
|
}
|
|
1780
2550
|
|
|
2551
|
+
async recordIncrementalFailuresByCollection(input: {
|
|
2552
|
+
collectionIds: readonly string[];
|
|
2553
|
+
errorCode: string;
|
|
2554
|
+
}): Promise<Set<string>> {
|
|
2555
|
+
const collectionIds = [...new Set(input.collectionIds)];
|
|
2556
|
+
if (collectionIds.length === 0) return new Set();
|
|
2557
|
+
const collections = jsonTextValues(this.db, collectionIds);
|
|
2558
|
+
const now = new Date().toISOString();
|
|
2559
|
+
const result = await sql<{ collection_id: string }>`
|
|
2560
|
+
WITH failed_collections AS (${collections})
|
|
2561
|
+
UPDATE _emdash_media_usage_index_status AS status
|
|
2562
|
+
SET status = CASE
|
|
2563
|
+
WHEN EXISTS (
|
|
2564
|
+
SELECT 1
|
|
2565
|
+
FROM _emdash_media_usage_reconciliations AS reconciliation
|
|
2566
|
+
WHERE reconciliation.collection_id = status.collection_id
|
|
2567
|
+
AND reconciliation.run_token = status.cursor
|
|
2568
|
+
) THEN status.status
|
|
2569
|
+
WHEN status.reconciliation_required = 0 THEN 'partial'
|
|
2570
|
+
WHEN status.status = 'running' THEN 'stale'
|
|
2571
|
+
ELSE status.status
|
|
2572
|
+
END,
|
|
2573
|
+
completed_at = CASE
|
|
2574
|
+
WHEN EXISTS (
|
|
2575
|
+
SELECT 1
|
|
2576
|
+
FROM _emdash_media_usage_reconciliations AS reconciliation
|
|
2577
|
+
WHERE reconciliation.collection_id = status.collection_id
|
|
2578
|
+
AND reconciliation.run_token = status.cursor
|
|
2579
|
+
) THEN status.completed_at
|
|
2580
|
+
WHEN status.reconciliation_required = 0 OR status.status = 'running' THEN NULL
|
|
2581
|
+
ELSE status.completed_at
|
|
2582
|
+
END,
|
|
2583
|
+
cursor = CASE
|
|
2584
|
+
WHEN EXISTS (
|
|
2585
|
+
SELECT 1
|
|
2586
|
+
FROM _emdash_media_usage_reconciliations AS reconciliation
|
|
2587
|
+
WHERE reconciliation.collection_id = status.collection_id
|
|
2588
|
+
AND reconciliation.run_token = status.cursor
|
|
2589
|
+
) THEN status.cursor
|
|
2590
|
+
WHEN status.status = 'running' THEN NULL
|
|
2591
|
+
ELSE status.cursor
|
|
2592
|
+
END,
|
|
2593
|
+
last_error_code = ${input.errorCode},
|
|
2594
|
+
updated_at = ${now}
|
|
2595
|
+
WHERE status.adapter_id = 'content-media'
|
|
2596
|
+
AND status.scope_type = 'collection'
|
|
2597
|
+
AND status.collection_id IN (SELECT value FROM failed_collections)
|
|
2598
|
+
AND EXISTS (
|
|
2599
|
+
SELECT 1
|
|
2600
|
+
FROM _emdash_media_usage_work AS work
|
|
2601
|
+
WHERE work.collection_id = status.collection_id
|
|
2602
|
+
AND work.state = 'failed'
|
|
2603
|
+
AND work.last_error_code = ${input.errorCode}
|
|
2604
|
+
)
|
|
2605
|
+
AND EXISTS (
|
|
2606
|
+
SELECT 1
|
|
2607
|
+
FROM _emdash_collections AS collection
|
|
2608
|
+
WHERE collection.id = status.collection_id
|
|
2609
|
+
AND collection.slug = status.scope_key
|
|
2610
|
+
)
|
|
2611
|
+
RETURNING collection_id
|
|
2612
|
+
`.execute(this.db);
|
|
2613
|
+
return new Set(result.rows.map((row) => row.collection_id));
|
|
2614
|
+
}
|
|
2615
|
+
|
|
1781
2616
|
async findIndexStatus(
|
|
1782
2617
|
identity: MediaUsageIndexStatusIdentity,
|
|
1783
2618
|
): Promise<MediaUsageIndexStatus | null> {
|
|
@@ -2204,6 +3039,199 @@ export class MediaUsageRepository {
|
|
|
2204
3039
|
}
|
|
2205
3040
|
}
|
|
2206
3041
|
|
|
3042
|
+
private async insertBatchOccurrences(rows: readonly BatchOccurrenceRow[]): Promise<void> {
|
|
3043
|
+
for (const rowBatch of chunkJsonRows(rows)) {
|
|
3044
|
+
const input = this.occurrenceBatchInput(JSON.stringify(rowBatch));
|
|
3045
|
+
await sql`
|
|
3046
|
+
WITH input AS (${input})
|
|
3047
|
+
INSERT INTO _emdash_media_usage (
|
|
3048
|
+
id, source_key, generation, field_slug, field_path, occurrence_index,
|
|
3049
|
+
reference_type, media_id, provider, provider_asset_id, media_kind,
|
|
3050
|
+
mime_type, created_at
|
|
3051
|
+
)
|
|
3052
|
+
SELECT
|
|
3053
|
+
id, source_key, generation, field_slug, field_path, occurrence_index,
|
|
3054
|
+
reference_type, media_id, provider, provider_asset_id, media_kind,
|
|
3055
|
+
mime_type, created_at
|
|
3056
|
+
FROM input
|
|
3057
|
+
WHERE EXISTS (
|
|
3058
|
+
SELECT 1
|
|
3059
|
+
FROM _emdash_media_usage_generation_writes AS writer
|
|
3060
|
+
WHERE writer.source_key = input.source_key
|
|
3061
|
+
AND writer.generation = input.generation
|
|
3062
|
+
AND writer.lease_token = input.lease_token
|
|
3063
|
+
AND ${this.generationWriteLeaseExpiryIsInFuture("writer.expires_at")}
|
|
3064
|
+
)
|
|
3065
|
+
`.execute(this.db);
|
|
3066
|
+
}
|
|
3067
|
+
}
|
|
3068
|
+
|
|
3069
|
+
private occurrenceBatchInput(payload: string): RawBuilder<unknown> {
|
|
3070
|
+
if (isPostgres(this.db)) {
|
|
3071
|
+
return sql`
|
|
3072
|
+
SELECT
|
|
3073
|
+
entry.value ->> 'id' AS id,
|
|
3074
|
+
entry.value ->> 'source_key' AS source_key,
|
|
3075
|
+
entry.value ->> 'generation' AS generation,
|
|
3076
|
+
entry.value ->> 'field_slug' AS field_slug,
|
|
3077
|
+
entry.value ->> 'field_path' AS field_path,
|
|
3078
|
+
CAST(entry.value ->> 'occurrence_index' AS integer) AS occurrence_index,
|
|
3079
|
+
entry.value ->> 'reference_type' AS reference_type,
|
|
3080
|
+
entry.value ->> 'media_id' AS media_id,
|
|
3081
|
+
entry.value ->> 'provider' AS provider,
|
|
3082
|
+
entry.value ->> 'provider_asset_id' AS provider_asset_id,
|
|
3083
|
+
entry.value ->> 'media_kind' AS media_kind,
|
|
3084
|
+
entry.value ->> 'mime_type' AS mime_type,
|
|
3085
|
+
entry.value ->> 'created_at' AS created_at,
|
|
3086
|
+
entry.value ->> 'lease_token' AS lease_token
|
|
3087
|
+
FROM jsonb_array_elements(${payload}::jsonb) AS entry(value)
|
|
3088
|
+
`;
|
|
3089
|
+
}
|
|
3090
|
+
return sql`
|
|
3091
|
+
SELECT
|
|
3092
|
+
json_extract(entry.value, '$.id') AS id,
|
|
3093
|
+
json_extract(entry.value, '$.source_key') AS source_key,
|
|
3094
|
+
json_extract(entry.value, '$.generation') AS generation,
|
|
3095
|
+
json_extract(entry.value, '$.field_slug') AS field_slug,
|
|
3096
|
+
json_extract(entry.value, '$.field_path') AS field_path,
|
|
3097
|
+
CAST(json_extract(entry.value, '$.occurrence_index') AS integer) AS occurrence_index,
|
|
3098
|
+
json_extract(entry.value, '$.reference_type') AS reference_type,
|
|
3099
|
+
json_extract(entry.value, '$.media_id') AS media_id,
|
|
3100
|
+
json_extract(entry.value, '$.provider') AS provider,
|
|
3101
|
+
json_extract(entry.value, '$.provider_asset_id') AS provider_asset_id,
|
|
3102
|
+
json_extract(entry.value, '$.media_kind') AS media_kind,
|
|
3103
|
+
json_extract(entry.value, '$.mime_type') AS mime_type,
|
|
3104
|
+
json_extract(entry.value, '$.created_at') AS created_at,
|
|
3105
|
+
json_extract(entry.value, '$.lease_token') AS lease_token
|
|
3106
|
+
FROM json_each(${payload}) AS entry
|
|
3107
|
+
`;
|
|
3108
|
+
}
|
|
3109
|
+
|
|
3110
|
+
private sourceBatchInput(payload: string): RawBuilder<unknown> {
|
|
3111
|
+
if (isPostgres(this.db)) {
|
|
3112
|
+
return sql`
|
|
3113
|
+
SELECT
|
|
3114
|
+
entry.value ->> 'source_key' AS source_key,
|
|
3115
|
+
entry.value ->> 'source_type' AS source_type,
|
|
3116
|
+
entry.value ->> 'collection_id' AS collection_id,
|
|
3117
|
+
entry.value ->> 'collection_slug' AS collection_slug,
|
|
3118
|
+
entry.value ->> 'content_id' AS content_id,
|
|
3119
|
+
entry.value ->> 'source_variant' AS source_variant,
|
|
3120
|
+
entry.value ->> 'locale' AS locale,
|
|
3121
|
+
entry.value ->> 'translation_group' AS translation_group,
|
|
3122
|
+
entry.value ->> 'content_slug' AS content_slug,
|
|
3123
|
+
entry.value ->> 'content_title' AS content_title,
|
|
3124
|
+
entry.value ->> 'content_status' AS content_status,
|
|
3125
|
+
entry.value ->> 'content_scheduled_at' AS content_scheduled_at,
|
|
3126
|
+
entry.value ->> 'content_deleted_at' AS content_deleted_at,
|
|
3127
|
+
entry.value ->> 'revision_id' AS revision_id,
|
|
3128
|
+
entry.value ->> 'current_generation' AS current_generation,
|
|
3129
|
+
CAST(entry.value ->> 'schema_version' AS integer) AS schema_version,
|
|
3130
|
+
entry.value ->> 'source_updated_at' AS source_updated_at,
|
|
3131
|
+
CAST(entry.value ->> 'source_version' AS bigint) AS source_version,
|
|
3132
|
+
entry.value ->> 'source_fingerprint' AS source_fingerprint,
|
|
3133
|
+
CAST(entry.value ->> 'identity_version' AS integer) AS identity_version,
|
|
3134
|
+
entry.value ->> 'source_completeness' AS source_completeness,
|
|
3135
|
+
entry.value ->> 'last_attempted_at' AS last_attempted_at,
|
|
3136
|
+
entry.value ->> 'last_error_code' AS last_error_code,
|
|
3137
|
+
entry.value ->> 'indexed_at' AS indexed_at,
|
|
3138
|
+
entry.value ->> 'updated_at' AS updated_at,
|
|
3139
|
+
entry.value ->> 'lease_token' AS lease_token,
|
|
3140
|
+
entry.value ->> 'expected_generation' AS expected_generation,
|
|
3141
|
+
entry.value ->> 'expected_collection_id' AS expected_collection_id,
|
|
3142
|
+
entry.value ->> 'expected_updated_at' AS expected_updated_at,
|
|
3143
|
+
entry.value ->> 'expected_source_fingerprint' AS expected_source_fingerprint,
|
|
3144
|
+
entry.value ->> 'expected_source_updated_at' AS expected_source_updated_at,
|
|
3145
|
+
CAST(entry.value ->> 'expected_source_version' AS bigint) AS expected_source_version,
|
|
3146
|
+
CAST(entry.value ->> 'expected_identity_version' AS integer) AS expected_identity_version,
|
|
3147
|
+
entry.value ->> 'expected_revision_id' AS expected_revision_id,
|
|
3148
|
+
entry.value ->> 'expected_source_completeness' AS expected_source_completeness,
|
|
3149
|
+
entry.value ->> 'expected_last_attempted_at' AS expected_last_attempted_at,
|
|
3150
|
+
entry.value ->> 'expected_last_error_code' AS expected_last_error_code
|
|
3151
|
+
FROM jsonb_array_elements(${payload}::jsonb) AS entry(value)
|
|
3152
|
+
`;
|
|
3153
|
+
}
|
|
3154
|
+
return sql`
|
|
3155
|
+
SELECT
|
|
3156
|
+
json_extract(entry.value, '$.source_key') AS source_key,
|
|
3157
|
+
json_extract(entry.value, '$.source_type') AS source_type,
|
|
3158
|
+
json_extract(entry.value, '$.collection_id') AS collection_id,
|
|
3159
|
+
json_extract(entry.value, '$.collection_slug') AS collection_slug,
|
|
3160
|
+
json_extract(entry.value, '$.content_id') AS content_id,
|
|
3161
|
+
json_extract(entry.value, '$.source_variant') AS source_variant,
|
|
3162
|
+
json_extract(entry.value, '$.locale') AS locale,
|
|
3163
|
+
json_extract(entry.value, '$.translation_group') AS translation_group,
|
|
3164
|
+
json_extract(entry.value, '$.content_slug') AS content_slug,
|
|
3165
|
+
json_extract(entry.value, '$.content_title') AS content_title,
|
|
3166
|
+
json_extract(entry.value, '$.content_status') AS content_status,
|
|
3167
|
+
json_extract(entry.value, '$.content_scheduled_at') AS content_scheduled_at,
|
|
3168
|
+
json_extract(entry.value, '$.content_deleted_at') AS content_deleted_at,
|
|
3169
|
+
json_extract(entry.value, '$.revision_id') AS revision_id,
|
|
3170
|
+
json_extract(entry.value, '$.current_generation') AS current_generation,
|
|
3171
|
+
CAST(json_extract(entry.value, '$.schema_version') AS integer) AS schema_version,
|
|
3172
|
+
json_extract(entry.value, '$.source_updated_at') AS source_updated_at,
|
|
3173
|
+
CAST(json_extract(entry.value, '$.source_version') AS integer) AS source_version,
|
|
3174
|
+
json_extract(entry.value, '$.source_fingerprint') AS source_fingerprint,
|
|
3175
|
+
CAST(json_extract(entry.value, '$.identity_version') AS integer) AS identity_version,
|
|
3176
|
+
json_extract(entry.value, '$.source_completeness') AS source_completeness,
|
|
3177
|
+
json_extract(entry.value, '$.last_attempted_at') AS last_attempted_at,
|
|
3178
|
+
json_extract(entry.value, '$.last_error_code') AS last_error_code,
|
|
3179
|
+
json_extract(entry.value, '$.indexed_at') AS indexed_at,
|
|
3180
|
+
json_extract(entry.value, '$.updated_at') AS updated_at,
|
|
3181
|
+
json_extract(entry.value, '$.lease_token') AS lease_token,
|
|
3182
|
+
json_extract(entry.value, '$.expected_generation') AS expected_generation,
|
|
3183
|
+
json_extract(entry.value, '$.expected_collection_id') AS expected_collection_id,
|
|
3184
|
+
json_extract(entry.value, '$.expected_updated_at') AS expected_updated_at,
|
|
3185
|
+
json_extract(entry.value, '$.expected_source_fingerprint') AS expected_source_fingerprint,
|
|
3186
|
+
json_extract(entry.value, '$.expected_source_updated_at') AS expected_source_updated_at,
|
|
3187
|
+
CAST(json_extract(entry.value, '$.expected_source_version') AS integer) AS expected_source_version,
|
|
3188
|
+
CAST(json_extract(entry.value, '$.expected_identity_version') AS integer) AS expected_identity_version,
|
|
3189
|
+
json_extract(entry.value, '$.expected_revision_id') AS expected_revision_id,
|
|
3190
|
+
json_extract(entry.value, '$.expected_source_completeness') AS expected_source_completeness,
|
|
3191
|
+
json_extract(entry.value, '$.expected_last_attempted_at') AS expected_last_attempted_at,
|
|
3192
|
+
json_extract(entry.value, '$.expected_last_error_code') AS expected_last_error_code
|
|
3193
|
+
FROM json_each(${payload}) AS entry
|
|
3194
|
+
`;
|
|
3195
|
+
}
|
|
3196
|
+
|
|
3197
|
+
private generationWriteBatchInput(payload: string): RawBuilder<unknown> {
|
|
3198
|
+
if (isPostgres(this.db)) {
|
|
3199
|
+
return sql`
|
|
3200
|
+
SELECT
|
|
3201
|
+
entry.value ->> 'source_key' AS source_key,
|
|
3202
|
+
entry.value ->> 'collection_id' AS collection_id,
|
|
3203
|
+
entry.value ->> 'collection_slug' AS collection_slug,
|
|
3204
|
+
entry.value ->> 'generation' AS generation,
|
|
3205
|
+
entry.value ->> 'lease_token' AS lease_token,
|
|
3206
|
+
entry.value ->> 'expires_at' AS expires_at,
|
|
3207
|
+
entry.value ->> 'created_at' AS created_at
|
|
3208
|
+
FROM jsonb_array_elements(${payload}::jsonb) AS entry(value)
|
|
3209
|
+
`;
|
|
3210
|
+
}
|
|
3211
|
+
return sql`
|
|
3212
|
+
SELECT
|
|
3213
|
+
json_extract(entry.value, '$.source_key') AS source_key,
|
|
3214
|
+
json_extract(entry.value, '$.collection_id') AS collection_id,
|
|
3215
|
+
json_extract(entry.value, '$.collection_slug') AS collection_slug,
|
|
3216
|
+
json_extract(entry.value, '$.generation') AS generation,
|
|
3217
|
+
json_extract(entry.value, '$.lease_token') AS lease_token,
|
|
3218
|
+
json_extract(entry.value, '$.expires_at') AS expires_at,
|
|
3219
|
+
json_extract(entry.value, '$.created_at') AS created_at
|
|
3220
|
+
FROM json_each(${payload}) AS entry
|
|
3221
|
+
`;
|
|
3222
|
+
}
|
|
3223
|
+
|
|
3224
|
+
private batchRefsMatch(
|
|
3225
|
+
left: BatchSourceExpectedColumn,
|
|
3226
|
+
right: BatchInputExpectedColumn,
|
|
3227
|
+
): RawBuilder<boolean> {
|
|
3228
|
+
const leftRef = sql.ref(left);
|
|
3229
|
+
const rightRef = sql.ref(right);
|
|
3230
|
+
return isPostgres(this.db)
|
|
3231
|
+
? sql<boolean>`${leftRef} IS NOT DISTINCT FROM ${rightRef}`
|
|
3232
|
+
: sql<boolean>`${leftRef} IS ${rightRef}`;
|
|
3233
|
+
}
|
|
3234
|
+
|
|
2207
3235
|
private async lockCanonicalSourceCollection(
|
|
2208
3236
|
db: DatabaseExecutor,
|
|
2209
3237
|
source: MediaUsageSourceInput,
|