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