emdash 0.35.0 → 0.37.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-BDQwg236.d.mts} +6 -4
- package/dist/{adapters-Bb1vG41D.d.mts.map → adapters-BDQwg236.d.mts.map} +1 -1
- package/dist/{allowed-origins-DW7sYyqg.mjs → allowed-origins-BGglilcs.mjs} +2 -2
- package/dist/{allowed-origins-DW7sYyqg.mjs.map → allowed-origins-BGglilcs.mjs.map} +1 -1
- package/dist/api/route-utils.d.mts +3 -3
- package/dist/api/route-utils.mjs +23 -21
- 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-Dz6rgoa3.mjs +10040 -0
- package/dist/api-Dz6rgoa3.mjs.map +1 -0
- package/dist/{api-tokens-KO24G1Fd.mjs → api-tokens-BSsQACNe.mjs} +2 -2
- package/dist/{api-tokens-KO24G1Fd.mjs.map → api-tokens-BSsQACNe.mjs.map} +1 -1
- package/dist/{apply-kUDt80-G.mjs → apply-B4SIOxR1.mjs} +34 -35
- package/dist/{apply-kUDt80-G.mjs.map → apply-B4SIOxR1.mjs.map} +1 -1
- package/dist/astro/image-endpoint.mjs +2 -2
- package/dist/astro/image-endpoint.mjs.map +1 -1
- package/dist/astro/index.d.mts +12 -12
- package/dist/astro/index.d.mts.map +1 -1
- package/dist/astro/index.mjs +128 -44
- 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 +237 -1412
- 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.d.mts.map +1 -1
- package/dist/astro/routes/api/admin/api-tokens/index.mjs +5 -5
- package/dist/astro/routes/api/admin/api-tokens/index.mjs.map +1 -1
- 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 +16 -16
- package/dist/astro/routes/api/admin/bylines/_id_/translations.mjs +16 -16
- package/dist/astro/routes/api/admin/bylines/index.mjs +16 -16
- package/dist/astro/routes/api/admin/comments/_id_/status.mjs +13 -13
- package/dist/astro/routes/api/admin/comments/_id_.mjs +5 -5
- package/dist/astro/routes/api/admin/comments/bulk.mjs +10 -10
- package/dist/astro/routes/api/admin/comments/counts.mjs +5 -5
- package/dist/astro/routes/api/admin/comments/index.mjs +10 -10
- 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 +4 -4
- package/dist/astro/routes/api/admin/oauth-clients/_id_.mjs.map +1 -1
- package/dist/astro/routes/api/admin/oauth-clients/index.mjs +4 -4
- package/dist/astro/routes/api/admin/oauth-clients/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/_id_/disable.mjs +55 -49
- package/dist/astro/routes/api/admin/plugins/_id_/disable.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/_id_/enable.mjs +55 -49
- package/dist/astro/routes/api/admin/plugins/_id_/enable.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/_id_/index.mjs +53 -47
- 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 +53 -47
- package/dist/astro/routes/api/admin/plugins/_id_/settings.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/_id_/uninstall.mjs +54 -48
- package/dist/astro/routes/api/admin/plugins/_id_/uninstall.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/_id_/update.mjs +54 -48
- package/dist/astro/routes/api/admin/plugins/_id_/update.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/index.mjs +53 -47
- 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 +53 -47
- 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 +54 -48
- package/dist/astro/routes/api/admin/plugins/marketplace/_id_/install.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/marketplace/index.mjs +53 -47
- package/dist/astro/routes/api/admin/plugins/marketplace/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/registry/_id_/uninstall.mjs +54 -48
- package/dist/astro/routes/api/admin/plugins/registry/_id_/uninstall.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/registry/_id_/update.d.mts.map +1 -1
- package/dist/astro/routes/api/admin/plugins/registry/_id_/update.mjs +60 -50
- 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 +179 -139
- package/dist/astro/routes/api/admin/plugins/registry/artifact.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/registry/install.d.mts.map +1 -1
- package/dist/astro/routes/api/admin/plugins/registry/install.mjs +61 -51
- package/dist/astro/routes/api/admin/plugins/registry/install.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/registry/verify.d.mts +8 -0
- package/dist/astro/routes/api/admin/plugins/registry/verify.d.mts.map +1 -0
- package/dist/astro/routes/api/admin/plugins/registry/verify.mjs +93 -0
- package/dist/astro/routes/api/admin/plugins/registry/verify.mjs.map +1 -0
- package/dist/astro/routes/api/admin/plugins/updates.mjs +53 -47
- package/dist/astro/routes/api/admin/plugins/updates.mjs.map +1 -1
- package/dist/astro/routes/api/admin/themes/marketplace/_id_/index.mjs +53 -47
- 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 +53 -47
- 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 +14 -14
- package/dist/astro/routes/api/comments/_collection_/_contentId_/reactions.mjs +13 -13
- package/dist/astro/routes/api/content/_collection_/_id_/compare.mjs +2 -2
- package/dist/astro/routes/api/content/_collection_/_id_/discard-draft.d.mts.map +1 -1
- package/dist/astro/routes/api/content/_collection_/_id_/discard-draft.mjs +14 -5
- package/dist/astro/routes/api/content/_collection_/_id_/discard-draft.mjs.map +1 -1
- 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 +13 -10
- package/dist/astro/routes/api/content/_collection_/_id_/publish.mjs.map +1 -1
- package/dist/astro/routes/api/content/_collection_/_id_/references/_relation_/children.mjs +17 -15
- 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 +17 -15
- 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 +14 -14
- package/dist/astro/routes/api/content/_collection_/_id_/translations.mjs +2 -2
- package/dist/astro/routes/api/content/_collection_/_id_/unpublish.d.mts.map +1 -1
- package/dist/astro/routes/api/content/_collection_/_id_/unpublish.mjs +14 -5
- package/dist/astro/routes/api/content/_collection_/_id_/unpublish.mjs.map +1 -1
- 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 +8 -8
- 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 +17 -17
- 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 +13 -13
- 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 +17 -17
- package/dist/astro/routes/api/import/wordpress-plugin/execute.d.mts +11 -11
- package/dist/astro/routes/api/import/wordpress-plugin/execute.mjs +27 -27
- package/dist/astro/routes/api/manifest.mjs +4 -4
- package/dist/astro/routes/api/manifest.mjs.map +1 -1
- package/dist/astro/routes/api/mcp.mjs +188 -65
- package/dist/astro/routes/api/mcp.mjs.map +1 -1
- package/dist/astro/routes/api/media/_id_/confirm.mjs +11 -11
- package/dist/astro/routes/api/media/_id_/replace.d.mts +8 -0
- package/dist/astro/routes/api/media/_id_/replace.d.mts.map +1 -0
- package/dist/astro/routes/api/media/_id_/replace.mjs +91 -0
- package/dist/astro/routes/api/media/_id_/replace.mjs.map +1 -0
- 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_.d.mts.map +1 -1
- package/dist/astro/routes/api/media/file/_...key_.mjs +3 -2
- package/dist/astro/routes/api/media/file/_...key_.mjs.map +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 +16 -14
- package/dist/astro/routes/api/media/upload-url.mjs.map +1 -1
- package/dist/astro/routes/api/media.d.mts.map +1 -1
- package/dist/astro/routes/api/media.mjs +59 -27
- package/dist/astro/routes/api/media.mjs.map +1 -1
- package/dist/astro/routes/api/menus/_name_/items/_id_.d.mts.map +1 -1
- package/dist/astro/routes/api/menus/_name_/items/_id_.mjs +20 -13
- package/dist/astro/routes/api/menus/_name_/items/_id_.mjs.map +1 -1
- package/dist/astro/routes/api/menus/_name_/items.d.mts.map +1 -1
- package/dist/astro/routes/api/menus/_name_/items.mjs +15 -11
- package/dist/astro/routes/api/menus/_name_/items.mjs.map +1 -1
- package/dist/astro/routes/api/menus/_name_/reorder.d.mts.map +1 -1
- package/dist/astro/routes/api/menus/_name_/reorder.mjs +15 -11
- package/dist/astro/routes/api/menus/_name_/reorder.mjs.map +1 -1
- package/dist/astro/routes/api/menus/_name_/translations.d.mts.map +1 -1
- package/dist/astro/routes/api/menus/_name_/translations.mjs +16 -12
- package/dist/astro/routes/api/menus/_name_/translations.mjs.map +1 -1
- package/dist/astro/routes/api/menus/_name_.d.mts.map +1 -1
- package/dist/astro/routes/api/menus/_name_.mjs +21 -14
- package/dist/astro/routes/api/menus/_name_.mjs.map +1 -1
- package/dist/astro/routes/api/menus/index.d.mts.map +1 -1
- package/dist/astro/routes/api/menus/index.mjs +15 -11
- package/dist/astro/routes/api/menus/index.mjs.map +1 -1
- 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 +253 -40
- 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 +17 -15
- package/dist/astro/routes/api/relations/_id_/index.mjs.map +1 -1
- package/dist/astro/routes/api/relations/_id_/translations.mjs +12 -10
- package/dist/astro/routes/api/relations/_id_/translations.mjs.map +1 -1
- package/dist/astro/routes/api/relations/index.mjs +17 -15
- 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 +53 -47
- 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 +53 -47
- 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 +53 -47
- package/dist/astro/routes/api/schema/collections/_slug_/fields/reorder.mjs.map +1 -1
- package/dist/astro/routes/api/schema/collections/_slug_/index.mjs +53 -47
- package/dist/astro/routes/api/schema/collections/_slug_/index.mjs.map +1 -1
- package/dist/astro/routes/api/schema/collections/index.mjs +53 -47
- package/dist/astro/routes/api/schema/collections/index.mjs.map +1 -1
- package/dist/astro/routes/api/schema/collections/reorder.mjs +53 -47
- 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 +53 -47
- package/dist/astro/routes/api/schema/orphans/_slug_.mjs.map +1 -1
- package/dist/astro/routes/api/schema/orphans/index.mjs +53 -47
- 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 +5 -5
- package/dist/astro/routes/api/settings/email.mjs.map +1 -1
- package/dist/astro/routes/api/settings.d.mts.map +1 -1
- package/dist/astro/routes/api/settings.mjs +20 -16
- package/dist/astro/routes/api/settings.mjs.map +1 -1
- 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 +35 -28
- 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 +32 -30
- 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.d.mts.map +1 -1
- package/dist/astro/routes/api/taxonomies/_name_/reorder.mjs +20 -16
- package/dist/astro/routes/api/taxonomies/_name_/reorder.mjs.map +1 -1
- package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_/translations.d.mts.map +1 -1
- package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_/translations.mjs +21 -17
- package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_/translations.mjs.map +1 -1
- package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_.d.mts.map +1 -1
- package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_.mjs +25 -18
- package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_.mjs.map +1 -1
- package/dist/astro/routes/api/taxonomies/_name_/terms/index.d.mts.map +1 -1
- package/dist/astro/routes/api/taxonomies/_name_/terms/index.mjs +20 -16
- package/dist/astro/routes/api/taxonomies/_name_/terms/index.mjs.map +1 -1
- package/dist/astro/routes/api/taxonomies/_name_/translations.mjs +14 -14
- package/dist/astro/routes/api/taxonomies/_name_.d.mts.map +1 -1
- package/dist/astro/routes/api/taxonomies/_name_.mjs +26 -19
- package/dist/astro/routes/api/taxonomies/_name_.mjs.map +1 -1
- package/dist/astro/routes/api/taxonomies/index.d.mts.map +1 -1
- package/dist/astro/routes/api/taxonomies/index.mjs +20 -16
- package/dist/astro/routes/api/taxonomies/index.mjs.map +1 -1
- 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.d.mts.map +1 -1
- package/dist/astro/routes/api/widget-areas/_name_/reorder.mjs +10 -8
- package/dist/astro/routes/api/widget-areas/_name_/reorder.mjs.map +1 -1
- package/dist/astro/routes/api/widget-areas/_name_/widgets/_id_.d.mts.map +1 -1
- package/dist/astro/routes/api/widget-areas/_name_/widgets/_id_.mjs +17 -13
- package/dist/astro/routes/api/widget-areas/_name_/widgets/_id_.mjs.map +1 -1
- package/dist/astro/routes/api/widget-areas/_name_/widgets.d.mts.map +1 -1
- package/dist/astro/routes/api/widget-areas/_name_/widgets.mjs +15 -12
- package/dist/astro/routes/api/widget-areas/_name_/widgets.mjs.map +1 -1
- package/dist/astro/routes/api/widget-areas/_name_.d.mts.map +1 -1
- package/dist/astro/routes/api/widget-areas/_name_.mjs +8 -6
- package/dist/astro/routes/api/widget-areas/_name_.mjs.map +1 -1
- package/dist/astro/routes/api/widget-areas/index.d.mts.map +1 -1
- package/dist/astro/routes/api/widget-areas/index.mjs +15 -12
- package/dist/astro/routes/api/widget-areas/index.mjs.map +1 -1
- package/dist/astro/routes/api/widget-components.mjs +2 -2
- package/dist/astro/routes/robots.txt.mjs +7 -7
- package/dist/astro/routes/sitemap-_collection_.xml.mjs +10 -10
- package/dist/astro/routes/sitemap.xml.mjs +8 -8
- package/dist/astro/types.d.mts +37 -17
- 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-Bkf_UHhD.mjs} +2 -2
- package/dist/{authorize-DUElxgOQ.mjs.map → authorize-Bkf_UHhD.mjs.map} +1 -1
- package/dist/{backup-DWYpJlLj.mjs → backup-rwVAl9NI.mjs} +5 -5
- package/dist/{backup-DWYpJlLj.mjs.map → backup-rwVAl9NI.mjs.map} +1 -1
- package/dist/{bundle-vn56sLos.mjs → bundle-C8S2Zl6U.mjs} +4 -4
- package/dist/{bundle-vn56sLos.mjs.map → bundle-C8S2Zl6U.mjs.map} +1 -1
- package/dist/{byline-yjvWq4ip.mjs → byline-DuhF7NWl.mjs} +27 -14
- package/dist/byline-DuhF7NWl.mjs.map +1 -0
- package/dist/{byline-fields-txaLGoME.mjs → byline-fields-BovY4KYM.mjs} +2 -2
- package/dist/{byline-fields-txaLGoME.mjs.map → byline-fields-BovY4KYM.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-CJ5nd6Lw.mjs} +7 -7
- package/dist/{bylines-DjXS5p0P.mjs.map → bylines-CJ5nd6Lw.mjs.map} +1 -1
- package/dist/{bylines-Bu7pchQ4.mjs → bylines-RwBAeOF1.mjs} +3 -3
- package/dist/{bylines-Bu7pchQ4.mjs.map → bylines-RwBAeOF1.mjs.map} +1 -1
- package/dist/{cache-C46-3Irl.mjs → cache-BF5Kvn59.mjs} +4 -4
- package/dist/{cache-C46-3Irl.mjs.map → cache-BF5Kvn59.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-DQN_Yrck.mjs} +5 -3
- package/dist/challenge-store-DQN_Yrck.mjs.map +1 -0
- package/dist/chrome-tags-D8fiZG94.mjs +24 -0
- package/dist/chrome-tags-D8fiZG94.mjs.map +1 -0
- package/dist/{chunks-fiZ8G9RJ.mjs → chunks-C4szrD8o.mjs} +2 -2
- package/dist/{chunks-fiZ8G9RJ.mjs.map → chunks-C4szrD8o.mjs.map} +1 -1
- package/dist/cli/index.mjs +37 -53
- 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-Bj07NHbj.mjs} +13 -356
- package/dist/collection-deletion-Bj07NHbj.mjs.map +1 -0
- package/dist/{comment-reaction-D-2J84UE.mjs → comment-reaction-BhrvSHml.mjs} +2 -2
- package/dist/{comment-reaction-D-2J84UE.mjs.map → comment-reaction-BhrvSHml.mjs.map} +1 -1
- package/dist/{comment-Dxlep6cE.mjs → comment-vxOzWbZN.mjs} +2 -2
- package/dist/{comment-Dxlep6cE.mjs.map → comment-vxOzWbZN.mjs.map} +1 -1
- package/dist/{comments-CTfZtLmM.mjs → comments-Ct4ensnf.mjs} +2 -2
- package/dist/{comments-CTfZtLmM.mjs.map → comments-Ct4ensnf.mjs.map} +1 -1
- package/dist/{components-CQy3lh9x.mjs → components-DJbo1z0S.mjs} +1 -1
- package/dist/{components-CQy3lh9x.mjs.map → components-DJbo1z0S.mjs.map} +1 -1
- package/dist/{config-COQzTe5Q.d.mts → config-B9eZ340f.d.mts} +1 -1
- package/dist/{config-COQzTe5Q.d.mts.map → config-B9eZ340f.d.mts.map} +1 -1
- package/dist/config-it29yDLA.mjs +1163 -0
- package/dist/config-it29yDLA.mjs.map +1 -0
- package/dist/{content-ZHCc1ngN.mjs → content-DjvM0T92.mjs} +86 -45
- package/dist/content-DjvM0T92.mjs.map +1 -0
- package/dist/{content-list-query-wJ2WN8Vp.d.mts → content-list-query-Btqd4uV2.d.mts} +1 -1
- package/dist/{content-list-query-wJ2WN8Vp.d.mts.map → content-list-query-Btqd4uV2.d.mts.map} +1 -1
- package/dist/{content-refresh-B_8SJzuU.mjs → content-refresh-Bwp-8yGy.mjs} +1139 -111
- package/dist/content-refresh-Bwp-8yGy.mjs.map +1 -0
- package/dist/{media-usage-BZCydfvu.mjs → content-repair-Czdp7jz5.mjs} +5 -196
- package/dist/content-repair-Czdp7jz5.mjs.map +1 -0
- package/dist/{context-ZldbZcle.mjs → context-CX6gxOLW.mjs} +55 -20
- package/dist/context-CX6gxOLW.mjs.map +1 -0
- package/dist/{cron-Y9aLtgrA.mjs → cron-C6o7VppJ.mjs} +1 -1
- package/dist/{cron-Y9aLtgrA.mjs.map → cron-C6o7VppJ.mjs.map} +1 -1
- package/dist/{dashboard-DvHbk_cv.mjs → dashboard-C2kTeeRI.mjs} +5 -5
- package/dist/{dashboard-DvHbk_cv.mjs.map → dashboard-C2kTeeRI.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/postgres.d.mts.map +1 -1
- package/dist/db/postgres.mjs +19 -3
- package/dist/db/postgres.mjs.map +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-Clra32mw.mjs} +1 -1
- package/dist/{default-DdDl3fxv.mjs.map → default-Clra32mw.mjs.map} +1 -1
- package/dist/{deferred-tasks-SDWxrgzJ.d.mts → deferred-tasks-CvDETTJO.d.mts} +1 -1
- package/dist/{deferred-tasks-SDWxrgzJ.d.mts.map → deferred-tasks-CvDETTJO.d.mts.map} +1 -1
- package/dist/dev-typegen-DzOPfsNj.mjs +29 -0
- package/dist/dev-typegen-DzOPfsNj.mjs.map +1 -0
- package/dist/{device-flow-C0GdD_z8.mjs → device-flow-D2oCWvLJ.mjs} +5 -5
- package/dist/{device-flow-C0GdD_z8.mjs.map → device-flow-D2oCWvLJ.mjs.map} +1 -1
- package/dist/{direct-executor-CDXeJCSs.mjs → direct-executor-Bfa5_ToE.mjs} +3 -3
- package/dist/{direct-executor-CDXeJCSs.mjs.map → direct-executor-Bfa5_ToE.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-Dzb6uGYa.mjs} +1 -1
- package/dist/{email-console-BHNjIwiB.mjs.map → email-console-Dzb6uGYa.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-DFrQjppn.mjs} +2 -2
- package/dist/{error-DupyJZE2.mjs.map → error-DFrQjppn.mjs.map} +1 -1
- package/dist/{errors-CLUPm7aD.mjs → errors-DsVoDUjJ.mjs} +24 -2
- package/dist/errors-DsVoDUjJ.mjs.map +1 -0
- package/dist/{escape-DUY2r2Zs.mjs → escape-HmHTC1Is.mjs} +1 -1
- package/dist/{escape-DUY2r2Zs.mjs.map → escape-HmHTC1Is.mjs.map} +1 -1
- package/dist/{field-defs-cache-BzwBlJrR.mjs → field-defs-cache-BM4SIRqH.mjs} +5 -5
- package/dist/{field-defs-cache-BzwBlJrR.mjs.map → field-defs-cache-BM4SIRqH.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-Do1BlW2r.mjs} +3 -3
- package/dist/{fts-manager-DyZEohZC.mjs.map → fts-manager-Do1BlW2r.mjs.map} +1 -1
- package/dist/{hash-Cg0TXJPV.mjs → hash-3JJPlHF2.mjs} +1 -1
- package/dist/{hash-Cg0TXJPV.mjs.map → hash-3JJPlHF2.mjs.map} +1 -1
- package/dist/hook-result-DCh2WUpe.d.mts +31 -0
- package/dist/hook-result-DCh2WUpe.d.mts.map +1 -0
- package/dist/{hreflang-DwT2E0Sa.d.mts → hreflang-B6hbAuuO.d.mts} +2 -2
- package/dist/{hreflang-DwT2E0Sa.d.mts.map → hreflang-B6hbAuuO.d.mts.map} +1 -1
- package/dist/{hreflang-BBe83kKa.mjs → hreflang-DQbPZliA.mjs} +7 -7
- package/dist/{hreflang-BBe83kKa.mjs.map → hreflang-DQbPZliA.mjs.map} +1 -1
- package/dist/{identity-Ys6Dlc9C.mjs → identity-DksvEazf.mjs} +3 -3
- package/dist/{identity-Ys6Dlc9C.mjs.map → identity-DksvEazf.mjs.map} +1 -1
- package/dist/{import-DPkLmeXO.mjs → import-CJpaBBBT.mjs} +6 -6
- package/dist/{import-DPkLmeXO.mjs.map → import-CJpaBBBT.mjs.map} +1 -1
- package/dist/{index-BVBZj4-7.d.mts → index-BJNMCWmu.d.mts} +267 -82
- package/dist/index-BJNMCWmu.d.mts.map +1 -0
- package/dist/{index-C9KuQyO-.d.mts → index-Du8K7bWa.d.mts} +3 -3
- package/dist/{index-C9KuQyO-.d.mts.map → index-Du8K7bWa.d.mts.map} +1 -1
- package/dist/index.d.mts +22 -21
- package/dist/index.mjs +79 -73
- 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-CawHjTOH.mjs} +2 -2
- package/dist/{load-YJ2xl3ra.mjs.map → load-CawHjTOH.mjs.map} +1 -1
- package/dist/{loader-CdG_Ci3H.mjs → loader-Z8vl7zTq.mjs} +48 -13
- package/dist/loader-Z8vl7zTq.mjs.map +1 -0
- package/dist/{manifest-builder-B252yQUf.mjs → manifest-builder-COtzuca2.mjs} +2 -2
- package/dist/{manifest-builder-B252yQUf.mjs.map → manifest-builder-COtzuca2.mjs.map} +1 -1
- package/dist/{manifest-schema-BXbUAHod.mjs → manifest-schema-BNWwR8Vd.mjs} +5 -5
- package/dist/manifest-schema-BNWwR8Vd.mjs.map +1 -0
- package/dist/media/image-endpoint.d.mts +4 -2
- package/dist/media/image-endpoint.d.mts.map +1 -1
- package/dist/media/image-endpoint.mjs +6 -4
- package/dist/media/image-endpoint.mjs.map +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 +12 -6
- package/dist/media/local-runtime.mjs.map +1 -1
- package/dist/{media-CzhAn2--.mjs → media-BBm8Wg3f.mjs} +69 -12
- package/dist/media-BBm8Wg3f.mjs.map +1 -0
- package/dist/{media-BWWWb8kg.mjs → media-BHjus86Y.mjs} +133 -9
- package/dist/media-BHjus86Y.mjs.map +1 -0
- package/dist/{media-allowlist-D6x-Us02.mjs → media-allowlist-CoTBWoDp.mjs} +3 -2
- package/dist/media-allowlist-CoTBWoDp.mjs.map +1 -0
- package/dist/media-folders-BGkATs8n.mjs +210 -0
- package/dist/media-folders-BGkATs8n.mjs.map +1 -0
- package/dist/{media-upload-CHBVn6m-.mjs → media-upload-BCidR-EY.mjs} +9 -9
- package/dist/{media-upload-CHBVn6m-.mjs.map → media-upload-BCidR-EY.mjs.map} +1 -1
- package/dist/{media-url-BvoX88FA.mjs → media-url-DHoPr0hq.mjs} +1 -1
- package/dist/{media-url-BvoX88FA.mjs.map → media-url-DHoPr0hq.mjs.map} +1 -1
- package/dist/media-usage-CdY5jhSR.mjs +1833 -0
- package/dist/media-usage-CdY5jhSR.mjs.map +1 -0
- package/dist/media-usage-activation-BgeMtK5C.mjs +78 -0
- package/dist/media-usage-activation-BgeMtK5C.mjs.map +1 -0
- package/dist/{media-usage-work-CLo_6tct.mjs → media-usage-work-CnGCdHxx.mjs} +4 -4
- package/dist/{media-usage-work-CLo_6tct.mjs.map → media-usage-work-CnGCdHxx.mjs.map} +1 -1
- package/dist/{media-usage-work-DrCbqBcl.mjs → media-usage-work-D6D9sMCA.mjs} +221 -59
- package/dist/media-usage-work-D6D9sMCA.mjs.map +1 -0
- package/dist/{media-usage-write-fence-aHEgN1zB.mjs → media-usage-write-fence-hjeD4u7s.mjs} +2 -2
- package/dist/{media-usage-write-fence-aHEgN1zB.mjs.map → media-usage-write-fence-hjeD4u7s.mjs.map} +1 -1
- package/dist/{menus-DSo5QeW0.mjs → menus-6qSwTNxG.mjs} +375 -107
- package/dist/menus-6qSwTNxG.mjs.map +1 -0
- package/dist/{menus-TCNSd2vp.mjs → menus-uvPLXMZf.mjs} +4 -4
- package/dist/{menus-TCNSd2vp.mjs.map → menus-uvPLXMZf.mjs.map} +1 -1
- 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-DN_WneRx.mjs} +1 -1
- package/dist/{mode-BDoH_WcF.mjs.map → mode-DN_WneRx.mjs.map} +1 -1
- package/dist/node-sqlite-compat-BuJXIeMz.mjs +46 -0
- package/dist/node-sqlite-compat-BuJXIeMz.mjs.map +1 -0
- package/dist/{normalize-Bc-s_r-a.mjs → normalize-C2xNjTSG.mjs} +36 -5
- package/dist/normalize-C2xNjTSG.mjs.map +1 -0
- package/dist/{oauth-authorization-iOikmrJd.mjs → oauth-authorization-Dj6Kwc21.mjs} +5 -5
- package/dist/{oauth-authorization-iOikmrJd.mjs.map → oauth-authorization-Dj6Kwc21.mjs.map} +1 -1
- package/dist/{oauth-clients-CvI0nHMJ.mjs → oauth-clients-FD7I0J8m.mjs} +1 -1
- package/dist/{oauth-clients-CvI0nHMJ.mjs.map → oauth-clients-FD7I0J8m.mjs.map} +1 -1
- package/dist/{oauth-state-store-Ba8KZlwW.mjs → oauth-state-store-DkmDOmHs.mjs} +1 -1
- package/dist/{oauth-state-store-Ba8KZlwW.mjs.map → oauth-state-store-DkmDOmHs.mjs.map} +1 -1
- package/dist/{oauth-user-lookup-C5SQwGYC.mjs → oauth-user-lookup-CvIwGpYd.mjs} +1 -1
- package/dist/{oauth-user-lookup-C5SQwGYC.mjs.map → oauth-user-lookup-CvIwGpYd.mjs.map} +1 -1
- package/dist/object-cache/memory.d.mts +1 -1
- package/dist/{object-cache-71tPfV4A.mjs → object-cache-DVKnyOfy.mjs} +19 -3
- package/dist/object-cache-DVKnyOfy.mjs.map +1 -0
- 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-CYb4y7hM.d.mts} +24 -11
- package/dist/options-CYb4y7hM.d.mts.map +1 -0
- package/dist/page/index.d.mts +2 -2
- package/dist/{parse-DFbuc-Fh.mjs → parse-Ckpg-Qfp.mjs} +2 -2
- package/dist/{parse-DFbuc-Fh.mjs.map → parse-Ckpg-Qfp.mjs.map} +1 -1
- package/dist/{passkey-config-DFAmUyuE.mjs → passkey-config-O_lj3y0k.mjs} +1 -1
- package/dist/{passkey-config-DFAmUyuE.mjs.map → passkey-config-O_lj3y0k.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-4X9BrRrp.d.mts} +7 -1
- package/dist/placeholder-4X9BrRrp.d.mts.map +1 -0
- package/dist/plugin-types.d.mts +8 -3
- package/dist/plugin-types.d.mts.map +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-Dhtwntrt.mjs} +2 -2
- package/dist/{policy-TluUIxuu.mjs.map → policy-Dhtwntrt.mjs.map} +1 -1
- package/dist/{portable-text-imBW5cHK.mjs → portable-text-U85hOafW.mjs} +1 -1
- package/dist/{portable-text-imBW5cHK.mjs.map → portable-text-U85hOafW.mjs.map} +1 -1
- package/dist/{preview-PW-nOnq4.mjs → preview-B_vJLvf8.mjs} +2 -2
- package/dist/{preview-PW-nOnq4.mjs.map → preview-B_vJLvf8.mjs.map} +1 -1
- package/dist/{protocol-DjsJHTlK.d.mts → protocol-JdD2YhY9.d.mts} +2 -2
- package/dist/{protocol-DjsJHTlK.d.mts.map → protocol-JdD2YhY9.d.mts.map} +1 -1
- package/dist/{public-url-CWoFhQT8.mjs → public-url-CarhZJgf.mjs} +1 -1
- package/dist/{public-url-CWoFhQT8.mjs.map → public-url-CarhZJgf.mjs.map} +1 -1
- package/dist/{query-zTVAR1Sl.mjs → query-BZKZcG5b.mjs} +15 -15
- package/dist/{query-zTVAR1Sl.mjs.map → query-BZKZcG5b.mjs.map} +1 -1
- package/dist/{query-BWs7O5Il.mjs → query-BndaFxxp.mjs} +5 -5
- package/dist/{query-BWs7O5Il.mjs.map → query-BndaFxxp.mjs.map} +1 -1
- package/dist/{rate-limit-Bx4g9m3p.mjs → rate-limit-BZmATC6W.mjs} +2 -2
- package/dist/{rate-limit-Bx4g9m3p.mjs.map → rate-limit-BZmATC6W.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-CzqnLxK-.mjs} +1 -1
- package/dist/{redirect-BgAOGHDq.mjs.map → redirect-CzqnLxK-.mjs.map} +1 -1
- package/dist/{redirects-DTDHWH31.mjs → redirects-BLNOWQTn.mjs} +64 -29
- package/dist/redirects-BLNOWQTn.mjs.map +1 -0
- package/dist/{redirects-DyChwDkG.mjs → redirects-CqzNM0KM.mjs} +5 -5
- package/dist/{redirects-DyChwDkG.mjs.map → redirects-CqzNM0KM.mjs.map} +1 -1
- package/dist/{registry-Cqa2I749.mjs → registry-AZAsRsor.mjs} +30 -126
- package/dist/registry-AZAsRsor.mjs.map +1 -0
- package/dist/{relation-BnHB0T4J.mjs → relation-04DfKRTO.mjs} +2 -2
- package/dist/{relation-BnHB0T4J.mjs.map → relation-04DfKRTO.mjs.map} +1 -1
- package/dist/{relations-BBApI4e2.mjs → relations-C4htk5sb.mjs} +7 -7
- package/dist/relations-C4htk5sb.mjs.map +1 -0
- package/dist/{relations-D5sM5fW0.mjs → relations-CcFwDJdJ.mjs} +4 -4
- package/dist/{relations-D5sM5fW0.mjs.map → relations-CcFwDJdJ.mjs.map} +1 -1
- package/dist/{relations-BHo5A8Zf.d.mts → relations-DnRK4YIT.d.mts} +347 -54
- package/dist/relations-DnRK4YIT.d.mts.map +1 -0
- 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-DYxLlnmz.mjs} +2 -2
- package/dist/{request-meta-DgZJh3zG.mjs.map → request-meta-DYxLlnmz.mjs.map} +1 -1
- package/dist/{resolve-DOhVEvty.mjs → resolve-prZ3mP7l.mjs} +1 -1
- package/dist/{resolve-DOhVEvty.mjs.map → resolve-prZ3mP7l.mjs.map} +1 -1
- package/dist/{runner-C1T11CfC.mjs → runner-BLIDKpmA.mjs} +471 -290
- package/dist/runner-BLIDKpmA.mjs.map +1 -0
- package/dist/{runner-BYHZn3Jy.d.mts → runner-YKfIMnaF.d.mts} +3 -2
- package/dist/runner-YKfIMnaF.d.mts.map +1 -0
- package/dist/runtime.d.mts +11 -11
- package/dist/runtime.mjs +1 -1
- package/dist/{schema-DZ5YVVZj.mjs → schema-CGnBeLiW.mjs} +3 -3
- package/dist/{schema-DZ5YVVZj.mjs.map → schema-CGnBeLiW.mjs.map} +1 -1
- package/dist/{schema-2AOsSn2v.mjs → schema-DYr-Vd-L.mjs} +36 -6
- package/dist/{schema-2AOsSn2v.mjs.map → schema-DYr-Vd-L.mjs.map} +1 -1
- package/dist/{scopes-8ClPF2bC.mjs → scopes-BhWvBavj.mjs} +3 -3
- package/dist/{scopes-8ClPF2bC.mjs.map → scopes-BhWvBavj.mjs.map} +1 -1
- package/dist/{search-u1QYdOCG.mjs → search-C-qDk4kx.mjs} +4 -4
- package/dist/{search-u1QYdOCG.mjs.map → search-C-qDk4kx.mjs.map} +1 -1
- package/dist/{secrets-BEgsAQEU.mjs → secrets-rEtHt-6z.mjs} +3 -3
- package/dist/{secrets-BEgsAQEU.mjs.map → secrets-rEtHt-6z.mjs.map} +1 -1
- package/dist/{sections-DmHviGyM.mjs → sections-B_nYvlwn.mjs} +2 -2
- package/dist/{sections-DmHviGyM.mjs.map → sections-B_nYvlwn.mjs.map} +1 -1
- package/dist/seed/index.d.mts +2 -2
- package/dist/seed/index.mjs +25 -23
- package/dist/seo/index.d.mts +3 -3
- package/dist/seo/index.mjs +17 -15
- package/dist/seo/index.mjs.map +1 -1
- package/dist/{seo-Dq4G-RrO.mjs → seo-926NRIgt.mjs} +3 -3
- package/dist/{seo-Dq4G-RrO.mjs.map → seo-926NRIgt.mjs.map} +1 -1
- package/dist/{seo-AFpVvTqr.mjs → seo-CVWkdv6x.mjs} +1 -1
- package/dist/{seo-AFpVvTqr.mjs.map → seo-CVWkdv6x.mjs.map} +1 -1
- package/dist/{service-BpArayPr.mjs → service-CJl3ZAYs.mjs} +3 -3
- package/dist/{service-BpArayPr.mjs.map → service-CJl3ZAYs.mjs.map} +1 -1
- package/dist/{session-user-BEorKVT-.mjs → session-user-BlMgqCHS.mjs} +1 -1
- package/dist/{session-user-BEorKVT-.mjs.map → session-user-BlMgqCHS.mjs.map} +1 -1
- package/dist/{settings-xRdoUZr0.mjs → settings--wobrkkC.mjs} +21 -8
- package/dist/settings--wobrkkC.mjs.map +1 -0
- package/dist/{settings-DE9xtzqd.mjs → settings-Cwm6o2jY.mjs} +3 -3
- package/dist/{settings-DE9xtzqd.mjs.map → settings-Cwm6o2jY.mjs.map} +1 -1
- package/dist/{setup-complete-BnT8pq_C.mjs → setup-complete-DQbClIN2.mjs} +2 -2
- package/dist/{setup-complete-BnT8pq_C.mjs.map → setup-complete-DQbClIN2.mjs.map} +1 -1
- package/dist/{setup-nonce-CBitf_oQ.mjs → setup-nonce-DZCFS2sn.mjs} +1 -1
- package/dist/{setup-nonce-CBitf_oQ.mjs.map → setup-nonce-DZCFS2sn.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-BrxA_E9H.mjs} +3 -3
- package/dist/{site-url-DjpIXMXJ.mjs.map → site-url-BrxA_E9H.mjs.map} +1 -1
- package/dist/{snapshot-BBlGkb2q.mjs → snapshot--OCDTqdb.mjs} +1 -1
- package/dist/{snapshot-BBlGkb2q.mjs.map → snapshot--OCDTqdb.mjs.map} +1 -1
- package/dist/{ssrf-Cpvg_n3A.mjs → ssrf-5sIM5jzl.mjs} +23 -6
- package/dist/{ssrf-Cpvg_n3A.mjs.map → ssrf-5sIM5jzl.mjs.map} +1 -1
- package/dist/{state-DYwPue40.mjs → state-BpFVsJZB.mjs} +12 -4
- package/dist/state-BpFVsJZB.mjs.map +1 -0
- package/dist/{status-CWVYpbD8.mjs → status-B777-dXz.mjs} +1 -1
- package/dist/{status-CWVYpbD8.mjs.map → status-B777-dXz.mjs.map} +1 -1
- package/dist/storage/local.d.mts +2 -1
- package/dist/storage/local.d.mts.map +1 -1
- package/dist/storage/local.mjs +1 -1
- package/dist/storage/local.mjs.map +1 -1
- package/dist/storage/s3.d.mts +2 -1
- package/dist/storage/s3.d.mts.map +1 -1
- package/dist/storage/s3.mjs +3 -2
- package/dist/storage/s3.mjs.map +1 -1
- package/dist/{target-DixqqV5i.mjs → target-BmR0iTwz.mjs} +1 -1
- package/dist/{target-DixqqV5i.mjs.map → target-BmR0iTwz.mjs.map} +1 -1
- package/dist/{taxonomies-OHUIiIpI.mjs → taxonomies-DkAkMupr.mjs} +17 -14
- package/dist/taxonomies-DkAkMupr.mjs.map +1 -0
- package/dist/{taxonomies-BlrncHi9.mjs → taxonomies-Wfy_Lg12.mjs} +43 -17
- package/dist/taxonomies-Wfy_Lg12.mjs.map +1 -0
- package/dist/{taxonomy-BqCZ1TdU.mjs → taxonomy-tJepplLL.mjs} +5 -5
- package/dist/{taxonomy-BqCZ1TdU.mjs.map → taxonomy-tJepplLL.mjs.map} +1 -1
- package/dist/{tokens-C39klX8R.mjs → tokens-BCO1oruF.mjs} +1 -1
- package/dist/{tokens-C39klX8R.mjs.map → tokens-BCO1oruF.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-DBJwa-Si.mjs → transport-Dr3qtwXC.mjs} +4 -3
- package/dist/{transport-DBJwa-Si.mjs.map → transport-Dr3qtwXC.mjs.map} +1 -1
- package/dist/{transport-RQE36APG.d.mts → transport-xh6YKW2G.d.mts} +1 -1
- package/dist/{transport-RQE36APG.d.mts.map → transport-xh6YKW2G.d.mts.map} +1 -1
- package/dist/{trusted-proxy-CEVekpby.mjs → trusted-proxy-BR5F1Otp.mjs} +1 -1
- package/dist/{trusted-proxy-CEVekpby.mjs.map → trusted-proxy-BR5F1Otp.mjs.map} +1 -1
- package/dist/{types-BW1syrlw.mjs → types-3qNFPlci.mjs} +1 -1
- package/dist/{types-BW1syrlw.mjs.map → types-3qNFPlci.mjs.map} +1 -1
- package/dist/types-75KIqzL9.mjs.map +1 -1
- package/dist/{types-DrJrVCT1.d.mts → types-B6GrPic4.d.mts} +9 -3
- package/dist/{types-DrJrVCT1.d.mts.map → types-B6GrPic4.d.mts.map} +1 -1
- package/dist/{types-DN64_zzZ.d.mts → types-BuHW4xDE.d.mts} +11 -10
- package/dist/types-BuHW4xDE.d.mts.map +1 -0
- package/dist/{types-DWRhk9xZ.d.mts → types-C00oyCZp.d.mts} +1 -1
- package/dist/{types-DWRhk9xZ.d.mts.map → types-C00oyCZp.d.mts.map} +1 -1
- package/dist/{types-BntycPTF.d.mts → types-CDtkNSFQ.d.mts} +1 -1
- package/dist/{types-BntycPTF.d.mts.map → types-CDtkNSFQ.d.mts.map} +1 -1
- package/dist/{types-Dfk8KI5R.d.mts → types-CPeXo1wF.d.mts} +1 -1
- package/dist/{types-Dfk8KI5R.d.mts.map → types-CPeXo1wF.d.mts.map} +1 -1
- package/dist/types-CQPWhPxE.mjs.map +1 -1
- package/dist/{types-BcqdcT-r.d.mts → types-CXFkwEGC.d.mts} +3 -2
- package/dist/types-CXFkwEGC.d.mts.map +1 -0
- 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-CXnOzDe1.d.mts → types-DczELMop.d.mts} +1 -1
- package/dist/{types-CXnOzDe1.d.mts.map → types-DczELMop.d.mts.map} +1 -1
- package/dist/types-DfuTR6dL.mjs +3 -0
- package/dist/{types-DQIDRKF2.d.mts → types-FV23hEoW.d.mts} +10 -1
- package/dist/types-FV23hEoW.d.mts.map +1 -0
- package/dist/{types-C2pMvO62.d.mts → types-xDMtUFnO.d.mts} +2 -1
- package/dist/types-xDMtUFnO.d.mts.map +1 -0
- package/dist/{upload-attempts-D4FS8LT6.mjs → upload-attempts-BsqoQ1fn.mjs} +1 -1
- package/dist/{upload-attempts-D4FS8LT6.mjs.map → upload-attempts-BsqoQ1fn.mjs.map} +1 -1
- package/dist/{url-pattern-BHS0V5Ng.mjs → url-pattern-D4c2czpJ.mjs} +1 -1
- package/dist/{url-pattern-BHS0V5Ng.mjs.map → url-pattern-D4c2czpJ.mjs.map} +1 -1
- package/dist/{user-DJZfUJVE.mjs → user-BTZ40aq6.mjs} +2 -2
- package/dist/{user-DJZfUJVE.mjs.map → user-BTZ40aq6.mjs.map} +1 -1
- package/dist/{utils-D4vD_Y98.mjs → utils-BKvNjjhY.mjs} +1 -1
- package/dist/{utils-D4vD_Y98.mjs.map → utils-BKvNjjhY.mjs.map} +1 -1
- package/dist/{validate-BMLBvxOC.mjs → validate-DE_LRwo9.mjs} +2 -2
- package/dist/{validate-BMLBvxOC.mjs.map → validate-DE_LRwo9.mjs.map} +1 -1
- package/dist/{validate-CTqt5nuE.d.mts → validate-DUP27OYD.d.mts} +5 -5
- package/dist/{validate-CTqt5nuE.d.mts.map → validate-DUP27OYD.d.mts.map} +1 -1
- package/dist/{validation-npvENUCB.mjs → validation-BMImFJ11.mjs} +10 -8
- package/dist/{validation-npvENUCB.mjs.map → validation-BMImFJ11.mjs.map} +1 -1
- package/dist/version-Bii3suaO.mjs +7 -0
- package/dist/{version-DB_fqCSI.mjs.map → version-Bii3suaO.mjs.map} +1 -1
- package/dist/{widgets-BD3ho7Rq.mjs → widgets-D3gJ10xU.mjs} +18 -5
- package/dist/widgets-D3gJ10xU.mjs.map +1 -0
- package/dist/{wxr-taxonomies-Ca68766D.d.mts → wxr-taxonomies-B2Og_6rU.d.mts} +1 -1
- package/dist/{wxr-taxonomies-Ca68766D.d.mts.map → wxr-taxonomies-B2Og_6rU.d.mts.map} +1 -1
- package/dist/{wxr-taxonomies-B1R3vBoD.mjs → wxr-taxonomies-Cxngsjwo.mjs} +4 -4
- package/dist/{wxr-taxonomies-B1R3vBoD.mjs.map → wxr-taxonomies-Cxngsjwo.mjs.map} +1 -1
- package/dist/{zod-generator-LC-on_Vb.mjs → zod-generator-BuYSQJB7.mjs} +32 -22
- package/dist/zod-generator-BuYSQJB7.mjs.map +1 -0
- package/package.json +20 -9
- package/src/api/errors.ts +22 -0
- package/src/api/handlers/content.ts +49 -11
- package/src/api/handlers/index.ts +18 -0
- package/src/api/handlers/manifest.ts +161 -12
- 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 +92 -2
- package/src/api/handlers/registry.ts +483 -561
- package/src/api/handlers/taxonomies.ts +16 -9
- package/src/api/openapi/document.ts +277 -7
- package/src/api/parse.ts +1 -1
- package/src/api/schemas/auth.ts +4 -4
- package/src/api/schemas/bylines.ts +3 -3
- package/src/api/schemas/comments.ts +1 -1
- package/src/api/schemas/common.ts +3 -2
- package/src/api/schemas/content.ts +78 -22
- package/src/api/schemas/media-usage.ts +77 -0
- package/src/api/schemas/media.ts +121 -0
- package/src/api/schemas/redirects.ts +6 -1
- package/src/api/schemas/schema.ts +4 -0
- package/src/api/schemas/setup.ts +1 -1
- package/src/api/schemas/taxonomies.ts +2 -2
- package/src/api/schemas/users.ts +1 -1
- package/src/api/types.ts +23 -10
- package/src/astro/dev-typegen.ts +35 -0
- package/src/astro/image-endpoint.ts +2 -2
- package/src/astro/integration/dev-typegen.ts +91 -0
- package/src/astro/integration/index.ts +9 -44
- package/src/astro/integration/routes.ts +23 -0
- package/src/astro/integration/vite-config.ts +23 -9
- package/src/astro/middleware/auth.ts +4 -0
- package/src/astro/middleware.ts +5 -7
- package/src/astro/routes/api/admin/api-tokens/index.ts +4 -1
- 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/oauth-clients/[id].ts +1 -1
- package/src/astro/routes/api/admin/oauth-clients/index.ts +1 -1
- package/src/astro/routes/api/admin/plugins/registry/[id]/update.ts +4 -0
- package/src/astro/routes/api/admin/plugins/registry/artifact.ts +247 -101
- package/src/astro/routes/api/admin/plugins/registry/install.ts +4 -0
- package/src/astro/routes/api/admin/plugins/registry/verify.ts +60 -0
- package/src/astro/routes/api/auth/me.ts +14 -2
- package/src/astro/routes/api/content/[collection]/[id]/discard-draft.ts +8 -2
- package/src/astro/routes/api/content/[collection]/[id]/publish.ts +2 -1
- package/src/astro/routes/api/content/[collection]/[id]/unpublish.ts +6 -2
- package/src/astro/routes/api/manifest.ts +1 -1
- package/src/astro/routes/api/media/[id]/replace.ts +114 -0
- package/src/astro/routes/api/media/[id].ts +3 -0
- package/src/astro/routes/api/media/file/[...key].ts +4 -1
- 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/upload-url.ts +8 -4
- package/src/astro/routes/api/media.ts +66 -10
- package/src/astro/routes/api/menus/[name]/items/[id].ts +7 -2
- package/src/astro/routes/api/menus/[name]/items.ts +4 -1
- package/src/astro/routes/api/menus/[name]/reorder.ts +4 -1
- package/src/astro/routes/api/menus/[name]/translations.ts +4 -1
- package/src/astro/routes/api/menus/[name].ts +7 -2
- package/src/astro/routes/api/menus/index.ts +4 -1
- package/src/astro/routes/api/settings/email.ts +1 -1
- package/src/astro/routes/api/settings.ts +4 -1
- package/src/astro/routes/api/setup/dev-bypass.ts +12 -0
- package/src/astro/routes/api/taxonomies/[name]/reorder.ts +4 -1
- package/src/astro/routes/api/taxonomies/[name]/terms/[slug]/translations.ts +4 -1
- package/src/astro/routes/api/taxonomies/[name]/terms/[slug].ts +7 -2
- package/src/astro/routes/api/taxonomies/[name]/terms/index.ts +4 -1
- package/src/astro/routes/api/taxonomies/[name].ts +7 -2
- package/src/astro/routes/api/taxonomies/index.ts +4 -1
- package/src/astro/routes/api/widget-areas/[name]/reorder.ts +3 -1
- package/src/astro/routes/api/widget-areas/[name]/widgets/[id].ts +5 -2
- package/src/astro/routes/api/widget-areas/[name]/widgets.ts +3 -1
- package/src/astro/routes/api/widget-areas/[name].ts +3 -1
- package/src/astro/routes/api/widget-areas/index.ts +3 -1
- package/src/astro/types.ts +34 -6
- package/src/auth/challenge-store.ts +3 -1
- package/src/aws-sdk.d.ts +1 -0
- package/src/cache/chrome-tags.ts +24 -0
- package/src/client/index.ts +140 -2
- package/src/client/transport.ts +6 -2
- package/src/components/EmDashImage.astro +156 -51
- package/src/components/EmDashMedia.astro +2 -1
- package/src/components/Gallery.astro +7 -0
- package/src/components/InlinePortableTextEditor.tsx +136 -2
- package/src/components/LiveSearch.astro +23 -0
- package/src/components/inline-code-block.tsx +180 -49
- package/src/components/widgets/Archives.astro +2 -37
- package/src/content/converters/gallery.ts +2 -0
- package/src/content/converters/index.ts +2 -0
- package/src/content/converters/mark-safety.ts +1 -0
- package/src/content/converters/portable-text-identity.ts +139 -0
- package/src/content/converters/portable-text-to-prosemirror.ts +202 -69
- package/src/content/converters/prosemirror-to-portable-text.ts +96 -25
- package/src/content/converters/types.ts +3 -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/017_authorization_codes.ts +14 -4
- 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/074_content_deleted_scheduled_index.ts +55 -0
- package/src/database/migrations/runner.ts +11 -3
- package/src/database/repositories/byline.ts +32 -16
- package/src/database/repositories/content.ts +119 -51
- 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 +1104 -47
- package/src/database/repositories/media.ts +156 -29
- package/src/database/repositories/plugin-storage.ts +74 -9
- package/src/database/repositories/types.ts +8 -7
- package/src/database/transaction.ts +1 -0
- package/src/database/types.ts +13 -0
- package/src/db/adapters.ts +10 -3
- package/src/db/node-sqlite-compat.ts +78 -0
- package/src/db/postgres.ts +23 -0
- package/src/db/sqlite.ts +3 -3
- package/src/emdash-runtime.ts +186 -251
- package/src/fields/boolean.ts +1 -1
- package/src/fields/datetime.ts +1 -1
- package/src/fields/file.ts +1 -1
- package/src/fields/image.ts +7 -1
- package/src/fields/integer.ts +1 -1
- package/src/fields/json.ts +1 -1
- package/src/fields/multiselect.ts +1 -1
- package/src/fields/number.ts +1 -1
- package/src/fields/portable-text.ts +1 -1
- package/src/fields/richtext.ts +1 -1
- package/src/fields/select.ts +1 -1
- package/src/fields/slug.ts +1 -1
- package/src/fields/text.ts +1 -1
- package/src/fields/textarea.ts +1 -1
- package/src/fields/types.ts +8 -4
- package/src/index.ts +30 -3
- package/src/loader.ts +63 -10
- package/src/mcp/server.ts +228 -24
- package/src/media/focal-point.ts +37 -0
- package/src/media/image-endpoint.ts +5 -2
- package/src/media/local-runtime.ts +8 -0
- package/src/media/mime.ts +1 -0
- package/src/media/normalize.ts +25 -4
- 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/cleanup.ts +9 -8
- 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/menus/index.ts +16 -0
- package/src/object-cache/index.ts +44 -2
- package/src/plugin-types.ts +18 -1
- package/src/plugins/hooks.ts +4 -1
- package/src/plugins/index.ts +7 -0
- package/src/plugins/manager.ts +2 -1
- package/src/plugins/manifest-schema.ts +1 -1
- package/src/plugins/routes.ts +3 -1
- package/src/plugins/sandbox/hook-result.ts +52 -0
- package/src/plugins/sandbox/index.ts +10 -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/plugins/types.ts +6 -0
- package/src/registry/artifact-checksum.ts +15 -0
- package/src/registry/artifact-fetch.ts +530 -0
- package/src/registry/artifact-verification.ts +85 -0
- package/src/registry/authoritative-records.ts +180 -0
- package/src/registry/config.ts +24 -6
- package/src/registry/record-labels.ts +28 -0
- package/src/registry/types.ts +12 -15
- package/src/schema/registry.ts +26 -3
- package/src/schema/types.ts +1 -0
- package/src/schema/zod-generator.ts +28 -17
- package/src/security/ssrf.ts +26 -4
- package/src/seed/apply.ts +4 -4
- package/src/settings/index.ts +16 -0
- package/src/storage/local.ts +1 -0
- package/src/storage/s3.ts +2 -0
- package/src/storage/types.ts +2 -0
- package/src/taxonomies/index.ts +40 -20
- package/src/ui.ts +2 -0
- package/src/widgets/archives.ts +67 -0
- package/src/widgets/index.ts +16 -0
- package/dist/api-BeBglVxU.mjs +0 -4695
- package/dist/api-BeBglVxU.mjs.map +0 -1
- package/dist/byline-yjvWq4ip.mjs.map +0 -1
- package/dist/challenge-store-SIL5DsF2.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/context-ZldbZcle.mjs.map +0 -1
- package/dist/errors-CLUPm7aD.mjs.map +0 -1
- package/dist/index-BVBZj4-7.d.mts.map +0 -1
- package/dist/loader-CdG_Ci3H.mjs.map +0 -1
- package/dist/manifest-schema-BXbUAHod.mjs.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/object-cache-71tPfV4A.mjs.map +0 -1
- package/dist/options--hhz-jZ1.d.mts.map +0 -1
- package/dist/placeholder-Dp0K3RkD.d.mts.map +0 -1
- package/dist/redirects-DTDHWH31.mjs.map +0 -1
- package/dist/registry-Cqa2I749.mjs.map +0 -1
- package/dist/relations-BBApI4e2.mjs.map +0 -1
- package/dist/relations-BHo5A8Zf.d.mts.map +0 -1
- package/dist/runner-BYHZn3Jy.d.mts.map +0 -1
- package/dist/runner-C1T11CfC.mjs.map +0 -1
- package/dist/settings-xRdoUZr0.mjs.map +0 -1
- package/dist/state-DYwPue40.mjs.map +0 -1
- package/dist/taxonomies-BlrncHi9.mjs.map +0 -1
- package/dist/taxonomies-OHUIiIpI.mjs.map +0 -1
- package/dist/types-BcqdcT-r.d.mts.map +0 -1
- package/dist/types-C2pMvO62.d.mts.map +0 -1
- package/dist/types-CP1CflWf.mjs +0 -3
- package/dist/types-DN64_zzZ.d.mts.map +0 -1
- package/dist/types-DQIDRKF2.d.mts.map +0 -1
- package/dist/version-DB_fqCSI.mjs +0 -7
- package/dist/widgets-BD3ho7Rq.mjs.map +0 -1
- package/dist/zod-generator-LC-on_Vb.mjs.map +0 -1
- /package/dist/{api-tokens-rIXC6LdE.mjs → api-tokens-BfYts-sq.mjs} +0 -0
- /package/dist/{ssrf-DpXgKsna.mjs → ssrf-Dg3cIT-b.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-C4szrD8o.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-C2xNjTSG.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;
|
|
@@ -469,7 +1020,14 @@ var MediaUsageRepository = class {
|
|
|
469
1020
|
consecutiveFailures: row.consecutive_failures
|
|
470
1021
|
};
|
|
471
1022
|
}
|
|
1023
|
+
/**
|
|
1024
|
+
* Scans for reclaimable occurrences, or resolves to `null` when the sweep was
|
|
1025
|
+
* never issued because the lease is gone or the tick is out of budget. An
|
|
1026
|
+
* empty array means the scan ran and found nothing, which lets the caller
|
|
1027
|
+
* retire the sweep window; `null` must leave the cursor where it was.
|
|
1028
|
+
*/
|
|
472
1029
|
async findMediaUsageCleanupCandidates(input) {
|
|
1030
|
+
if (!await this.admitCleanupScan(input.cleanupLease, input.canIssueStatement)) return null;
|
|
473
1031
|
let query = this.db.selectFrom("_emdash_media_usage as u").leftJoin("_emdash_media_usage_sources as s", "s.source_key", "u.source_key").leftJoin("_emdash_media_usage_generation_writes as writer", (join) => join.onRef("writer.source_key", "=", "u.source_key").onRef("writer.generation", "=", "u.generation")).select([
|
|
474
1032
|
"u.id as id",
|
|
475
1033
|
"u.source_key as source_key",
|
|
@@ -479,8 +1037,10 @@ var MediaUsageRepository = class {
|
|
|
479
1037
|
"s.indexed_at as indexed_at",
|
|
480
1038
|
"writer.expires_at as write_lease_expires_at"
|
|
481
1039
|
]).where("u.created_at", "<", input.cutoff).orderBy("u.created_at", "asc").orderBy("u.id", "asc").limit(Math.max(0, Math.floor(input.limit)));
|
|
482
|
-
if (input.
|
|
483
|
-
|
|
1040
|
+
if (input.cursor) {
|
|
1041
|
+
const cursor = input.cursor;
|
|
1042
|
+
query = query.where((eb) => eb(eb.refTuple("u.created_at", "u.id"), ">", eb.tuple(cursor.createdAt, cursor.id)));
|
|
1043
|
+
}
|
|
484
1044
|
return (await query.execute()).map((row) => ({
|
|
485
1045
|
id: row.id,
|
|
486
1046
|
sourceKey: row.source_key,
|
|
@@ -532,38 +1092,31 @@ var MediaUsageRepository = class {
|
|
|
532
1092
|
const batchLimit = Math.floor(limit);
|
|
533
1093
|
if (batchLimit <= 0) return 0;
|
|
534
1094
|
if (options.candidateIds) return this.deleteOrphanCandidateIds(options.candidateIds.slice(0, batchLimit), cutoff, options.cleanupLease, options.canIssueStatement);
|
|
535
|
-
if (!
|
|
536
|
-
|
|
537
|
-
if (options.cleanupLease) query = query.where(this.activeCleanupLeaseExpression(options.cleanupLease));
|
|
538
|
-
const rows = await query.execute();
|
|
1095
|
+
if (!await this.admitCleanupScan(options.cleanupLease, options.canIssueStatement)) return 0;
|
|
1096
|
+
const rows = await this.db.selectFrom("_emdash_media_usage as u").leftJoin("_emdash_media_usage_sources as s", (join) => join.onRef("s.source_key", "=", "u.source_key")).leftJoin("_emdash_media_usage_generation_writes as writer", (join) => join.onRef("writer.source_key", "=", "u.source_key").onRef("writer.generation", "=", "u.generation")).select("u.id").where("s.source_key", "is", null).where("u.created_at", "<", cutoff).where(this.noActiveGenerationWriteExpression("u")).orderBy("u.created_at", "asc").orderBy("u.id", "asc").limit(batchLimit).execute();
|
|
539
1097
|
return this.deleteOrphanCandidateIds(rows.map((row) => row.id), cutoff, options.cleanupLease, options.canIssueStatement);
|
|
540
1098
|
}
|
|
541
1099
|
async deleteStaleGenerationsOlderThan(cutoff, limit, options = {}) {
|
|
542
1100
|
const batchLimit = Math.floor(limit);
|
|
543
1101
|
if (batchLimit <= 0) return 0;
|
|
544
1102
|
if (options.candidateIds) return this.deleteStaleCandidateIds(options.candidateIds.slice(0, batchLimit), cutoff, options.cleanupLease, options.canIssueStatement);
|
|
545
|
-
if (!
|
|
546
|
-
|
|
547
|
-
if (options.cleanupLease) query = query.where(this.activeCleanupLeaseExpression(options.cleanupLease));
|
|
548
|
-
const rows = await query.execute();
|
|
1103
|
+
if (!await this.admitCleanupScan(options.cleanupLease, options.canIssueStatement)) return 0;
|
|
1104
|
+
const rows = await this.db.selectFrom("_emdash_media_usage as u").innerJoin("_emdash_media_usage_sources as s", (join) => join.onRef("s.source_key", "=", "u.source_key")).leftJoin("_emdash_media_usage_generation_writes as writer", (join) => join.onRef("writer.source_key", "=", "u.source_key").onRef("writer.generation", "=", "u.generation")).select("u.id").where("u.created_at", "<", cutoff).whereRef("u.generation", "!=", "s.current_generation").whereRef("u.created_at", "<", "s.indexed_at").where(this.noActiveGenerationWriteExpression("u")).orderBy("u.created_at", "asc").orderBy("u.id", "asc").limit(batchLimit).execute();
|
|
549
1105
|
return this.deleteStaleCandidateIds(rows.map((row) => row.id), cutoff, options.cleanupLease, options.canIssueStatement);
|
|
550
1106
|
}
|
|
551
1107
|
async deleteAbandonedGenerationsOlderThan(cutoff, limit, options = {}) {
|
|
552
1108
|
const batchLimit = Math.floor(limit);
|
|
553
1109
|
if (batchLimit <= 0) return 0;
|
|
554
1110
|
if (options.candidateIds) return this.deleteAbandonedCandidateIds(options.candidateIds.slice(0, batchLimit), cutoff, options.cleanupLease, options.canIssueStatement);
|
|
555
|
-
if (!
|
|
556
|
-
|
|
557
|
-
if (options.cleanupLease) query = query.where(this.activeCleanupLeaseExpression(options.cleanupLease));
|
|
558
|
-
const rows = await query.execute();
|
|
1111
|
+
if (!await this.admitCleanupScan(options.cleanupLease, options.canIssueStatement)) return 0;
|
|
1112
|
+
const rows = await this.db.selectFrom("_emdash_media_usage as u").innerJoin("_emdash_media_usage_sources as s", (join) => join.onRef("s.source_key", "=", "u.source_key")).leftJoin("_emdash_media_usage_generation_writes as writer", (join) => join.onRef("writer.source_key", "=", "u.source_key").onRef("writer.generation", "=", "u.generation")).select("u.id").where("u.created_at", "<", cutoff).whereRef("u.generation", "!=", "s.current_generation").whereRef("u.created_at", ">=", "s.indexed_at").where(this.noActiveGenerationWriteExpression("u")).orderBy("u.created_at", "asc").orderBy("u.id", "asc").limit(batchLimit).execute();
|
|
559
1113
|
return this.deleteAbandonedCandidateIds(rows.map((row) => row.id), cutoff, options.cleanupLease, options.canIssueStatement);
|
|
560
1114
|
}
|
|
561
1115
|
async deleteExpiredGenerationWriteLeases(limit, cleanupLease, canIssueStatement) {
|
|
562
1116
|
const batchLimit = Math.floor(limit);
|
|
563
|
-
if (batchLimit <= 0
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
const rows = await query.execute();
|
|
1117
|
+
if (batchLimit <= 0) return 0;
|
|
1118
|
+
if (!await this.admitCleanupScan(cleanupLease, canIssueStatement)) return 0;
|
|
1119
|
+
const rows = await this.db.selectFrom("_emdash_media_usage_generation_writes").select("lease_token").where(this.generationWriteLeaseHasExpired("expires_at")).orderBy("expires_at", "asc").orderBy("lease_token", "asc").limit(batchLimit).execute();
|
|
567
1120
|
if (rows.length === 0 || !canIssueCleanupStatement(canIssueStatement)) return 0;
|
|
568
1121
|
let deleteQuery = this.db.deleteFrom("_emdash_media_usage_generation_writes").where("lease_token", "in", rows.map((row) => row.lease_token)).where(this.generationWriteLeaseHasExpired("expires_at"));
|
|
569
1122
|
if (cleanupLease) deleteQuery = deleteQuery.where(this.activeCleanupLeaseExpression(cleanupLease));
|
|
@@ -746,6 +1299,7 @@ var MediaUsageRepository = class {
|
|
|
746
1299
|
status: sql`CASE WHEN ${canComplete} THEN 'complete' ELSE status END`,
|
|
747
1300
|
completed_at: sql`CASE WHEN ${canComplete} THEN ${now} ELSE completed_at END`,
|
|
748
1301
|
last_error_code: sql`CASE WHEN ${canComplete} THEN NULL ELSE last_error_code END`,
|
|
1302
|
+
cursor: sql`CASE WHEN ${canComplete} THEN NULL ELSE cursor END`,
|
|
749
1303
|
last_incremental_success_at: now,
|
|
750
1304
|
updated_at: now
|
|
751
1305
|
}).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 +1310,65 @@ var MediaUsageRepository = class {
|
|
|
756
1310
|
)`).executeTakeFirst();
|
|
757
1311
|
return Number(result.numUpdatedRows ?? 0) > 0;
|
|
758
1312
|
}
|
|
1313
|
+
async prepareIncrementalFinalization(input) {
|
|
1314
|
+
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();
|
|
1315
|
+
if (!observed) return { outcome: "lost" };
|
|
1316
|
+
if (observed.reconciliation_required !== 0) return { outcome: "not_required" };
|
|
1317
|
+
const marker = `incremental-finalize:${String(observed.change_epoch)}:${ulid()}`;
|
|
1318
|
+
const result = await this.db.updateTable("_emdash_media_usage_index_status").set({
|
|
1319
|
+
cursor: marker,
|
|
1320
|
+
updated_at: this.sortableUtcTimestamp()
|
|
1321
|
+
}).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 (
|
|
1322
|
+
SELECT 1
|
|
1323
|
+
FROM _emdash_collections AS collection
|
|
1324
|
+
WHERE collection.id = ${input.collectionId}
|
|
1325
|
+
AND collection.slug = ${input.collectionSlug}
|
|
1326
|
+
)`).where(sql`NOT EXISTS (
|
|
1327
|
+
SELECT 1
|
|
1328
|
+
FROM _emdash_media_usage_collection_deletions AS deletion
|
|
1329
|
+
WHERE deletion.collection_id = ${input.collectionId}
|
|
1330
|
+
)`).executeTakeFirst();
|
|
1331
|
+
return Number(result.numUpdatedRows ?? 0) > 0 ? {
|
|
1332
|
+
outcome: "marked",
|
|
1333
|
+
marker
|
|
1334
|
+
} : { outcome: "lost" };
|
|
1335
|
+
}
|
|
1336
|
+
async recoverIncrementalFinalizations() {
|
|
1337
|
+
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) || ':%')`;
|
|
1338
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
1339
|
+
return (await sql`
|
|
1340
|
+
UPDATE _emdash_media_usage_index_status AS status
|
|
1341
|
+
SET status = 'complete',
|
|
1342
|
+
completed_at = ${now},
|
|
1343
|
+
cursor = NULL,
|
|
1344
|
+
last_error_code = NULL,
|
|
1345
|
+
last_incremental_success_at = ${now},
|
|
1346
|
+
updated_at = ${now}
|
|
1347
|
+
WHERE status.adapter_id = 'content-media'
|
|
1348
|
+
AND status.scope_type = 'collection'
|
|
1349
|
+
AND status.capture_state = 'active'
|
|
1350
|
+
AND status.reconciliation_required = 0
|
|
1351
|
+
AND status.cursor IS NOT NULL
|
|
1352
|
+
AND ${markerMatchesEpoch}
|
|
1353
|
+
AND EXISTS (
|
|
1354
|
+
SELECT 1
|
|
1355
|
+
FROM _emdash_collections AS collection
|
|
1356
|
+
WHERE collection.id = status.collection_id
|
|
1357
|
+
AND collection.slug = status.scope_key
|
|
1358
|
+
)
|
|
1359
|
+
AND NOT EXISTS (
|
|
1360
|
+
SELECT 1
|
|
1361
|
+
FROM _emdash_media_usage_collection_deletions AS deletion
|
|
1362
|
+
WHERE deletion.collection_id = status.collection_id
|
|
1363
|
+
)
|
|
1364
|
+
AND NOT EXISTS (
|
|
1365
|
+
SELECT 1
|
|
1366
|
+
FROM _emdash_media_usage_work AS work
|
|
1367
|
+
WHERE work.collection_id = status.collection_id
|
|
1368
|
+
)
|
|
1369
|
+
RETURNING collection_id
|
|
1370
|
+
`.execute(this.db)).rows.length;
|
|
1371
|
+
}
|
|
759
1372
|
async recordIncrementalFailure(input) {
|
|
760
1373
|
const now = this.sortableUtcTimestamp();
|
|
761
1374
|
const automaticRunOwnsCoverage = sql`EXISTS (
|
|
@@ -799,6 +1412,67 @@ var MediaUsageRepository = class {
|
|
|
799
1412
|
)`).executeTakeFirst();
|
|
800
1413
|
return Number(result.numUpdatedRows ?? 0) > 0;
|
|
801
1414
|
}
|
|
1415
|
+
async recordIncrementalFailuresByCollection(input) {
|
|
1416
|
+
const collectionIds = [...new Set(input.collectionIds)];
|
|
1417
|
+
if (collectionIds.length === 0) return /* @__PURE__ */ new Set();
|
|
1418
|
+
const collections = jsonTextValues(this.db, collectionIds);
|
|
1419
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
1420
|
+
const result = await sql`
|
|
1421
|
+
WITH failed_collections AS (${collections})
|
|
1422
|
+
UPDATE _emdash_media_usage_index_status AS status
|
|
1423
|
+
SET status = CASE
|
|
1424
|
+
WHEN EXISTS (
|
|
1425
|
+
SELECT 1
|
|
1426
|
+
FROM _emdash_media_usage_reconciliations AS reconciliation
|
|
1427
|
+
WHERE reconciliation.collection_id = status.collection_id
|
|
1428
|
+
AND reconciliation.run_token = status.cursor
|
|
1429
|
+
) THEN status.status
|
|
1430
|
+
WHEN status.reconciliation_required = 0 THEN 'partial'
|
|
1431
|
+
WHEN status.status = 'running' THEN 'stale'
|
|
1432
|
+
ELSE status.status
|
|
1433
|
+
END,
|
|
1434
|
+
completed_at = CASE
|
|
1435
|
+
WHEN EXISTS (
|
|
1436
|
+
SELECT 1
|
|
1437
|
+
FROM _emdash_media_usage_reconciliations AS reconciliation
|
|
1438
|
+
WHERE reconciliation.collection_id = status.collection_id
|
|
1439
|
+
AND reconciliation.run_token = status.cursor
|
|
1440
|
+
) THEN status.completed_at
|
|
1441
|
+
WHEN status.reconciliation_required = 0 OR status.status = 'running' THEN NULL
|
|
1442
|
+
ELSE status.completed_at
|
|
1443
|
+
END,
|
|
1444
|
+
cursor = CASE
|
|
1445
|
+
WHEN EXISTS (
|
|
1446
|
+
SELECT 1
|
|
1447
|
+
FROM _emdash_media_usage_reconciliations AS reconciliation
|
|
1448
|
+
WHERE reconciliation.collection_id = status.collection_id
|
|
1449
|
+
AND reconciliation.run_token = status.cursor
|
|
1450
|
+
) THEN status.cursor
|
|
1451
|
+
WHEN status.status = 'running' THEN NULL
|
|
1452
|
+
ELSE status.cursor
|
|
1453
|
+
END,
|
|
1454
|
+
last_error_code = ${input.errorCode},
|
|
1455
|
+
updated_at = ${now}
|
|
1456
|
+
WHERE status.adapter_id = 'content-media'
|
|
1457
|
+
AND status.scope_type = 'collection'
|
|
1458
|
+
AND status.collection_id IN (SELECT value FROM failed_collections)
|
|
1459
|
+
AND EXISTS (
|
|
1460
|
+
SELECT 1
|
|
1461
|
+
FROM _emdash_media_usage_work AS work
|
|
1462
|
+
WHERE work.collection_id = status.collection_id
|
|
1463
|
+
AND work.state = 'failed'
|
|
1464
|
+
AND work.last_error_code = ${input.errorCode}
|
|
1465
|
+
)
|
|
1466
|
+
AND EXISTS (
|
|
1467
|
+
SELECT 1
|
|
1468
|
+
FROM _emdash_collections AS collection
|
|
1469
|
+
WHERE collection.id = status.collection_id
|
|
1470
|
+
AND collection.slug = status.scope_key
|
|
1471
|
+
)
|
|
1472
|
+
RETURNING collection_id
|
|
1473
|
+
`.execute(this.db);
|
|
1474
|
+
return new Set(result.rows.map((row) => row.collection_id));
|
|
1475
|
+
}
|
|
802
1476
|
async findIndexStatus(identity) {
|
|
803
1477
|
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
1478
|
return row ? rowToIndexStatus(row) : null;
|
|
@@ -901,6 +1575,31 @@ var MediaUsageRepository = class {
|
|
|
901
1575
|
AND ${this.generationWriteLeaseExpiryIsInFuture("writer.expires_at")}
|
|
902
1576
|
)`;
|
|
903
1577
|
}
|
|
1578
|
+
/**
|
|
1579
|
+
* Gates a bounded cleanup scan on the lease and the tick's statement budget.
|
|
1580
|
+
*
|
|
1581
|
+
* The budget is re-read after the lease row because that read is itself a
|
|
1582
|
+
* statement: an isolate suspended across it can resume with the budget spent.
|
|
1583
|
+
*/
|
|
1584
|
+
async admitCleanupScan(cleanupLease, canIssueStatement) {
|
|
1585
|
+
if (!canIssueCleanupStatement(canIssueStatement)) return false;
|
|
1586
|
+
if (!cleanupLease) return true;
|
|
1587
|
+
return await this.holdsCleanupLease(cleanupLease) && canIssueCleanupStatement(canIssueStatement);
|
|
1588
|
+
}
|
|
1589
|
+
/**
|
|
1590
|
+
* Reads the lease row on its own so a lost lease can short-circuit a sweep.
|
|
1591
|
+
*
|
|
1592
|
+
* As a row-level `EXISTS` inside a `LIMIT`ed scan this predicate is constant
|
|
1593
|
+
* across every candidate row: when it is false the limit is unreachable and
|
|
1594
|
+
* the scan reads the whole `created_at` range before returning nothing.
|
|
1595
|
+
* Mutating statements still carry {@link activeCleanupLeaseExpression},
|
|
1596
|
+
* which is what actually fences a displaced owner.
|
|
1597
|
+
*/
|
|
1598
|
+
async holdsCleanupLease(cleanupLease) {
|
|
1599
|
+
let query = this.db.selectFrom("_emdash_media_usage_cleanup").select("task_key").where("task_key", "=", "projection_gc").where("lease_token", "=", cleanupLease.leaseToken).where(this.cleanupLeaseExpiryIsInFuture("_emdash_media_usage_cleanup.lease_expires_at"));
|
|
1600
|
+
if (isPostgres(this.db)) query = query.forUpdate();
|
|
1601
|
+
return await query.executeTakeFirst() !== void 0;
|
|
1602
|
+
}
|
|
904
1603
|
activeCleanupLeaseExpression(cleanupLease) {
|
|
905
1604
|
const rowLock = isPostgres(this.db) ? sql` FOR UPDATE` : sql``;
|
|
906
1605
|
return sql`EXISTS (
|
|
@@ -982,6 +1681,180 @@ var MediaUsageRepository = class {
|
|
|
982
1681
|
}));
|
|
983
1682
|
for (const rowBatch of chunks(rows, OCCURRENCE_INSERT_BATCH_SIZE)) await db.insertInto("_emdash_media_usage").values(rowBatch).execute();
|
|
984
1683
|
}
|
|
1684
|
+
async insertBatchOccurrences(rows) {
|
|
1685
|
+
for (const rowBatch of chunkJsonRows(rows)) await sql`
|
|
1686
|
+
WITH input AS (${this.occurrenceBatchInput(JSON.stringify(rowBatch))})
|
|
1687
|
+
INSERT INTO _emdash_media_usage (
|
|
1688
|
+
id, source_key, generation, field_slug, field_path, occurrence_index,
|
|
1689
|
+
reference_type, media_id, provider, provider_asset_id, media_kind,
|
|
1690
|
+
mime_type, created_at
|
|
1691
|
+
)
|
|
1692
|
+
SELECT
|
|
1693
|
+
id, source_key, generation, field_slug, field_path, occurrence_index,
|
|
1694
|
+
reference_type, media_id, provider, provider_asset_id, media_kind,
|
|
1695
|
+
mime_type, created_at
|
|
1696
|
+
FROM input
|
|
1697
|
+
WHERE EXISTS (
|
|
1698
|
+
SELECT 1
|
|
1699
|
+
FROM _emdash_media_usage_generation_writes AS writer
|
|
1700
|
+
WHERE writer.source_key = input.source_key
|
|
1701
|
+
AND writer.generation = input.generation
|
|
1702
|
+
AND writer.lease_token = input.lease_token
|
|
1703
|
+
AND ${this.generationWriteLeaseExpiryIsInFuture("writer.expires_at")}
|
|
1704
|
+
)
|
|
1705
|
+
`.execute(this.db);
|
|
1706
|
+
}
|
|
1707
|
+
occurrenceBatchInput(payload) {
|
|
1708
|
+
if (isPostgres(this.db)) return sql`
|
|
1709
|
+
SELECT
|
|
1710
|
+
entry.value ->> 'id' AS id,
|
|
1711
|
+
entry.value ->> 'source_key' AS source_key,
|
|
1712
|
+
entry.value ->> 'generation' AS generation,
|
|
1713
|
+
entry.value ->> 'field_slug' AS field_slug,
|
|
1714
|
+
entry.value ->> 'field_path' AS field_path,
|
|
1715
|
+
CAST(entry.value ->> 'occurrence_index' AS integer) AS occurrence_index,
|
|
1716
|
+
entry.value ->> 'reference_type' AS reference_type,
|
|
1717
|
+
entry.value ->> 'media_id' AS media_id,
|
|
1718
|
+
entry.value ->> 'provider' AS provider,
|
|
1719
|
+
entry.value ->> 'provider_asset_id' AS provider_asset_id,
|
|
1720
|
+
entry.value ->> 'media_kind' AS media_kind,
|
|
1721
|
+
entry.value ->> 'mime_type' AS mime_type,
|
|
1722
|
+
entry.value ->> 'created_at' AS created_at,
|
|
1723
|
+
entry.value ->> 'lease_token' AS lease_token
|
|
1724
|
+
FROM jsonb_array_elements(${payload}::jsonb) AS entry(value)
|
|
1725
|
+
`;
|
|
1726
|
+
return sql`
|
|
1727
|
+
SELECT
|
|
1728
|
+
json_extract(entry.value, '$.id') AS id,
|
|
1729
|
+
json_extract(entry.value, '$.source_key') AS source_key,
|
|
1730
|
+
json_extract(entry.value, '$.generation') AS generation,
|
|
1731
|
+
json_extract(entry.value, '$.field_slug') AS field_slug,
|
|
1732
|
+
json_extract(entry.value, '$.field_path') AS field_path,
|
|
1733
|
+
CAST(json_extract(entry.value, '$.occurrence_index') AS integer) AS occurrence_index,
|
|
1734
|
+
json_extract(entry.value, '$.reference_type') AS reference_type,
|
|
1735
|
+
json_extract(entry.value, '$.media_id') AS media_id,
|
|
1736
|
+
json_extract(entry.value, '$.provider') AS provider,
|
|
1737
|
+
json_extract(entry.value, '$.provider_asset_id') AS provider_asset_id,
|
|
1738
|
+
json_extract(entry.value, '$.media_kind') AS media_kind,
|
|
1739
|
+
json_extract(entry.value, '$.mime_type') AS mime_type,
|
|
1740
|
+
json_extract(entry.value, '$.created_at') AS created_at,
|
|
1741
|
+
json_extract(entry.value, '$.lease_token') AS lease_token
|
|
1742
|
+
FROM json_each(${payload}) AS entry
|
|
1743
|
+
`;
|
|
1744
|
+
}
|
|
1745
|
+
sourceBatchInput(payload) {
|
|
1746
|
+
if (isPostgres(this.db)) return sql`
|
|
1747
|
+
SELECT
|
|
1748
|
+
entry.value ->> 'source_key' AS source_key,
|
|
1749
|
+
entry.value ->> 'source_type' AS source_type,
|
|
1750
|
+
entry.value ->> 'collection_id' AS collection_id,
|
|
1751
|
+
entry.value ->> 'collection_slug' AS collection_slug,
|
|
1752
|
+
entry.value ->> 'content_id' AS content_id,
|
|
1753
|
+
entry.value ->> 'source_variant' AS source_variant,
|
|
1754
|
+
entry.value ->> 'locale' AS locale,
|
|
1755
|
+
entry.value ->> 'translation_group' AS translation_group,
|
|
1756
|
+
entry.value ->> 'content_slug' AS content_slug,
|
|
1757
|
+
entry.value ->> 'content_title' AS content_title,
|
|
1758
|
+
entry.value ->> 'content_status' AS content_status,
|
|
1759
|
+
entry.value ->> 'content_scheduled_at' AS content_scheduled_at,
|
|
1760
|
+
entry.value ->> 'content_deleted_at' AS content_deleted_at,
|
|
1761
|
+
entry.value ->> 'revision_id' AS revision_id,
|
|
1762
|
+
entry.value ->> 'current_generation' AS current_generation,
|
|
1763
|
+
CAST(entry.value ->> 'schema_version' AS integer) AS schema_version,
|
|
1764
|
+
entry.value ->> 'source_updated_at' AS source_updated_at,
|
|
1765
|
+
CAST(entry.value ->> 'source_version' AS bigint) AS source_version,
|
|
1766
|
+
entry.value ->> 'source_fingerprint' AS source_fingerprint,
|
|
1767
|
+
CAST(entry.value ->> 'identity_version' AS integer) AS identity_version,
|
|
1768
|
+
entry.value ->> 'source_completeness' AS source_completeness,
|
|
1769
|
+
entry.value ->> 'last_attempted_at' AS last_attempted_at,
|
|
1770
|
+
entry.value ->> 'last_error_code' AS last_error_code,
|
|
1771
|
+
entry.value ->> 'indexed_at' AS indexed_at,
|
|
1772
|
+
entry.value ->> 'updated_at' AS updated_at,
|
|
1773
|
+
entry.value ->> 'lease_token' AS lease_token,
|
|
1774
|
+
entry.value ->> 'expected_generation' AS expected_generation,
|
|
1775
|
+
entry.value ->> 'expected_collection_id' AS expected_collection_id,
|
|
1776
|
+
entry.value ->> 'expected_updated_at' AS expected_updated_at,
|
|
1777
|
+
entry.value ->> 'expected_source_fingerprint' AS expected_source_fingerprint,
|
|
1778
|
+
entry.value ->> 'expected_source_updated_at' AS expected_source_updated_at,
|
|
1779
|
+
CAST(entry.value ->> 'expected_source_version' AS bigint) AS expected_source_version,
|
|
1780
|
+
CAST(entry.value ->> 'expected_identity_version' AS integer) AS expected_identity_version,
|
|
1781
|
+
entry.value ->> 'expected_revision_id' AS expected_revision_id,
|
|
1782
|
+
entry.value ->> 'expected_source_completeness' AS expected_source_completeness,
|
|
1783
|
+
entry.value ->> 'expected_last_attempted_at' AS expected_last_attempted_at,
|
|
1784
|
+
entry.value ->> 'expected_last_error_code' AS expected_last_error_code
|
|
1785
|
+
FROM jsonb_array_elements(${payload}::jsonb) AS entry(value)
|
|
1786
|
+
`;
|
|
1787
|
+
return sql`
|
|
1788
|
+
SELECT
|
|
1789
|
+
json_extract(entry.value, '$.source_key') AS source_key,
|
|
1790
|
+
json_extract(entry.value, '$.source_type') AS source_type,
|
|
1791
|
+
json_extract(entry.value, '$.collection_id') AS collection_id,
|
|
1792
|
+
json_extract(entry.value, '$.collection_slug') AS collection_slug,
|
|
1793
|
+
json_extract(entry.value, '$.content_id') AS content_id,
|
|
1794
|
+
json_extract(entry.value, '$.source_variant') AS source_variant,
|
|
1795
|
+
json_extract(entry.value, '$.locale') AS locale,
|
|
1796
|
+
json_extract(entry.value, '$.translation_group') AS translation_group,
|
|
1797
|
+
json_extract(entry.value, '$.content_slug') AS content_slug,
|
|
1798
|
+
json_extract(entry.value, '$.content_title') AS content_title,
|
|
1799
|
+
json_extract(entry.value, '$.content_status') AS content_status,
|
|
1800
|
+
json_extract(entry.value, '$.content_scheduled_at') AS content_scheduled_at,
|
|
1801
|
+
json_extract(entry.value, '$.content_deleted_at') AS content_deleted_at,
|
|
1802
|
+
json_extract(entry.value, '$.revision_id') AS revision_id,
|
|
1803
|
+
json_extract(entry.value, '$.current_generation') AS current_generation,
|
|
1804
|
+
CAST(json_extract(entry.value, '$.schema_version') AS integer) AS schema_version,
|
|
1805
|
+
json_extract(entry.value, '$.source_updated_at') AS source_updated_at,
|
|
1806
|
+
CAST(json_extract(entry.value, '$.source_version') AS integer) AS source_version,
|
|
1807
|
+
json_extract(entry.value, '$.source_fingerprint') AS source_fingerprint,
|
|
1808
|
+
CAST(json_extract(entry.value, '$.identity_version') AS integer) AS identity_version,
|
|
1809
|
+
json_extract(entry.value, '$.source_completeness') AS source_completeness,
|
|
1810
|
+
json_extract(entry.value, '$.last_attempted_at') AS last_attempted_at,
|
|
1811
|
+
json_extract(entry.value, '$.last_error_code') AS last_error_code,
|
|
1812
|
+
json_extract(entry.value, '$.indexed_at') AS indexed_at,
|
|
1813
|
+
json_extract(entry.value, '$.updated_at') AS updated_at,
|
|
1814
|
+
json_extract(entry.value, '$.lease_token') AS lease_token,
|
|
1815
|
+
json_extract(entry.value, '$.expected_generation') AS expected_generation,
|
|
1816
|
+
json_extract(entry.value, '$.expected_collection_id') AS expected_collection_id,
|
|
1817
|
+
json_extract(entry.value, '$.expected_updated_at') AS expected_updated_at,
|
|
1818
|
+
json_extract(entry.value, '$.expected_source_fingerprint') AS expected_source_fingerprint,
|
|
1819
|
+
json_extract(entry.value, '$.expected_source_updated_at') AS expected_source_updated_at,
|
|
1820
|
+
CAST(json_extract(entry.value, '$.expected_source_version') AS integer) AS expected_source_version,
|
|
1821
|
+
CAST(json_extract(entry.value, '$.expected_identity_version') AS integer) AS expected_identity_version,
|
|
1822
|
+
json_extract(entry.value, '$.expected_revision_id') AS expected_revision_id,
|
|
1823
|
+
json_extract(entry.value, '$.expected_source_completeness') AS expected_source_completeness,
|
|
1824
|
+
json_extract(entry.value, '$.expected_last_attempted_at') AS expected_last_attempted_at,
|
|
1825
|
+
json_extract(entry.value, '$.expected_last_error_code') AS expected_last_error_code
|
|
1826
|
+
FROM json_each(${payload}) AS entry
|
|
1827
|
+
`;
|
|
1828
|
+
}
|
|
1829
|
+
generationWriteBatchInput(payload) {
|
|
1830
|
+
if (isPostgres(this.db)) return sql`
|
|
1831
|
+
SELECT
|
|
1832
|
+
entry.value ->> 'source_key' AS source_key,
|
|
1833
|
+
entry.value ->> 'collection_id' AS collection_id,
|
|
1834
|
+
entry.value ->> 'collection_slug' AS collection_slug,
|
|
1835
|
+
entry.value ->> 'generation' AS generation,
|
|
1836
|
+
entry.value ->> 'lease_token' AS lease_token,
|
|
1837
|
+
entry.value ->> 'expires_at' AS expires_at,
|
|
1838
|
+
entry.value ->> 'created_at' AS created_at
|
|
1839
|
+
FROM jsonb_array_elements(${payload}::jsonb) AS entry(value)
|
|
1840
|
+
`;
|
|
1841
|
+
return sql`
|
|
1842
|
+
SELECT
|
|
1843
|
+
json_extract(entry.value, '$.source_key') AS source_key,
|
|
1844
|
+
json_extract(entry.value, '$.collection_id') AS collection_id,
|
|
1845
|
+
json_extract(entry.value, '$.collection_slug') AS collection_slug,
|
|
1846
|
+
json_extract(entry.value, '$.generation') AS generation,
|
|
1847
|
+
json_extract(entry.value, '$.lease_token') AS lease_token,
|
|
1848
|
+
json_extract(entry.value, '$.expires_at') AS expires_at,
|
|
1849
|
+
json_extract(entry.value, '$.created_at') AS created_at
|
|
1850
|
+
FROM json_each(${payload}) AS entry
|
|
1851
|
+
`;
|
|
1852
|
+
}
|
|
1853
|
+
batchRefsMatch(left, right) {
|
|
1854
|
+
const leftRef = sql.ref(left);
|
|
1855
|
+
const rightRef = sql.ref(right);
|
|
1856
|
+
return isPostgres(this.db) ? sql`${leftRef} IS NOT DISTINCT FROM ${rightRef}` : sql`${leftRef} IS ${rightRef}`;
|
|
1857
|
+
}
|
|
985
1858
|
async lockCanonicalSourceCollection(db, source) {
|
|
986
1859
|
if (source.collectionId === void 0 || source.collectionId === null) return true;
|
|
987
1860
|
if (!source.collectionSlug) return false;
|
|
@@ -1507,10 +2380,6 @@ function rowToIndexStatus(row) {
|
|
|
1507
2380
|
};
|
|
1508
2381
|
}
|
|
1509
2382
|
|
|
1510
|
-
//#endregion
|
|
1511
|
-
//#region src/media/usage/types.ts
|
|
1512
|
-
const CONTENT_SOURCE_SCHEMA_VERSION = 1;
|
|
1513
|
-
|
|
1514
2383
|
//#endregion
|
|
1515
2384
|
//#region src/media/usage/content-fields.ts
|
|
1516
2385
|
async function buildContentMediaUsageFieldFingerprint(discovery) {
|
|
@@ -1627,13 +2496,7 @@ function extractMediaUsageOccurrences({ fields, data }) {
|
|
|
1627
2496
|
for (const field of fields) {
|
|
1628
2497
|
const value = data[field.slug];
|
|
1629
2498
|
if (field.type === "image") {
|
|
1630
|
-
|
|
1631
|
-
fieldSlug: field.slug,
|
|
1632
|
-
fieldPath: field.slug,
|
|
1633
|
-
referenceType: "image_field",
|
|
1634
|
-
value,
|
|
1635
|
-
fallbackKind: "image"
|
|
1636
|
-
});
|
|
2499
|
+
addImageOccurrences(occurrences, seen, field.slug, field.slug, value);
|
|
1637
2500
|
continue;
|
|
1638
2501
|
}
|
|
1639
2502
|
if (field.type === "file") {
|
|
@@ -1660,16 +2523,26 @@ function extractRepeaterOccurrences(occurrences, seen, fieldSlug, value, subFiel
|
|
|
1660
2523
|
if (!isRecord$1(item)) continue;
|
|
1661
2524
|
for (const subField of subFields) {
|
|
1662
2525
|
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
|
-
});
|
|
2526
|
+
addImageOccurrences(occurrences, seen, fieldSlug, `${fieldSlug}[${itemIndex}].${subField.slug}`, item[subField.slug]);
|
|
1670
2527
|
}
|
|
1671
2528
|
}
|
|
1672
2529
|
}
|
|
2530
|
+
function addImageOccurrences(occurrences, seen, fieldSlug, fieldPath, value) {
|
|
2531
|
+
addOccurrence(occurrences, seen, {
|
|
2532
|
+
fieldSlug,
|
|
2533
|
+
fieldPath,
|
|
2534
|
+
referenceType: "image_field",
|
|
2535
|
+
value,
|
|
2536
|
+
fallbackKind: "image"
|
|
2537
|
+
});
|
|
2538
|
+
if (isRecord$1(value) && value.darkVariant != null) addOccurrence(occurrences, seen, {
|
|
2539
|
+
fieldSlug,
|
|
2540
|
+
fieldPath: `${fieldPath}.darkVariant`,
|
|
2541
|
+
referenceType: "image_field",
|
|
2542
|
+
value: value.darkVariant,
|
|
2543
|
+
fallbackKind: "image"
|
|
2544
|
+
});
|
|
2545
|
+
}
|
|
1673
2546
|
function extractPortableTextOccurrences(occurrences, seen, fieldSlug, value) {
|
|
1674
2547
|
if (!Array.isArray(value)) return;
|
|
1675
2548
|
for (const [blockIndex, block] of value.entries()) {
|
|
@@ -1844,14 +2717,38 @@ const CONTENT_SYSTEM_COLUMNS = [
|
|
|
1844
2717
|
"translation_group"
|
|
1845
2718
|
];
|
|
1846
2719
|
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 {
|
|
2720
|
+
return (await loadContentMediaUsageSnapshotsBatch(db, collectionSlug, [contentId], fieldDiscovery, options)).get(contentId) ?? {
|
|
1852
2721
|
success: false,
|
|
1853
2722
|
error: "CONTENT_NOT_FOUND"
|
|
1854
2723
|
};
|
|
2724
|
+
}
|
|
2725
|
+
async function loadContentMediaUsageSnapshotsBatch(db, collectionSlug, contentIds, fieldDiscovery, options = {}, control = {}) {
|
|
2726
|
+
validateIdentifier(collectionSlug, "collection slug");
|
|
2727
|
+
if (options.identityVersion !== void 0 && !options.collectionId) throw new Error("Canonical media usage snapshots require a collection identity");
|
|
2728
|
+
const discovery = fieldDiscovery ?? await loadContentMediaUsageFields(db, collectionSlug);
|
|
2729
|
+
const rows = await loadContentRows(db, collectionSlug, contentIds, [...discovery.extractionFields.map((field) => field.slug), ...discovery.displayFieldSlugs], options.collectionId);
|
|
2730
|
+
const revisions = await loadRevisionRows(db, Array.from(rows.values(), (row) => readNullableString(row.draft_revision_id)).filter((revisionId) => revisionId !== null));
|
|
2731
|
+
const results = /* @__PURE__ */ new Map();
|
|
2732
|
+
let occurrenceCount = 0;
|
|
2733
|
+
let projectionBytes = 0;
|
|
2734
|
+
for (const contentId of new Set(contentIds)) {
|
|
2735
|
+
if (control.shouldContinue && !control.shouldContinue()) break;
|
|
2736
|
+
const row = rows.get(contentId);
|
|
2737
|
+
const result = row ? await buildContentMediaUsageSnapshots(row, collectionSlug, discovery, options, revisions) : {
|
|
2738
|
+
success: false,
|
|
2739
|
+
error: "CONTENT_NOT_FOUND"
|
|
2740
|
+
};
|
|
2741
|
+
const snapshots = result.success ? result.snapshots : result.snapshots ?? [];
|
|
2742
|
+
const itemOccurrenceCount = snapshots.reduce((total, snapshot) => total + snapshot.occurrences.length, 0);
|
|
2743
|
+
const itemProjectionBytes = snapshots.reduce((total, snapshot) => total + snapshot.projectionByteLength, 0);
|
|
2744
|
+
if (results.size > 0 && (control.maxOccurrenceCount !== void 0 && occurrenceCount + itemOccurrenceCount > control.maxOccurrenceCount || control.maxProjectionBytes !== void 0 && projectionBytes + itemProjectionBytes > control.maxProjectionBytes)) break;
|
|
2745
|
+
results.set(contentId, result);
|
|
2746
|
+
occurrenceCount += itemOccurrenceCount;
|
|
2747
|
+
projectionBytes += itemProjectionBytes;
|
|
2748
|
+
}
|
|
2749
|
+
return results;
|
|
2750
|
+
}
|
|
2751
|
+
async function buildContentMediaUsageSnapshots(row, collectionSlug, discovery, options, revisions) {
|
|
1855
2752
|
const collectionId = readString(row[CONTENT_COLLECTION_ID_RESULT]);
|
|
1856
2753
|
if (!collectionId) throw new Error("Media usage snapshot query did not return a collection identity");
|
|
1857
2754
|
const columnsData = projectData(row, discovery.extractionFields.map((field) => field.slug));
|
|
@@ -1894,7 +2791,7 @@ async function loadContentMediaUsageSnapshots(db, collectionSlug, contentId, fie
|
|
|
1894
2791
|
sourceVariant: "draft_overlay",
|
|
1895
2792
|
revisionId: draftRevisionId
|
|
1896
2793
|
});
|
|
1897
|
-
const revisionResult =
|
|
2794
|
+
const revisionResult = revisions.get(draftRevisionId);
|
|
1898
2795
|
if (!revisionResult) return {
|
|
1899
2796
|
success: false,
|
|
1900
2797
|
error: "DRAFT_REVISION_NOT_FOUND",
|
|
@@ -1957,40 +2854,52 @@ async function loadContentMediaUsageSnapshots(db, collectionSlug, contentId, fie
|
|
|
1957
2854
|
snapshots
|
|
1958
2855
|
};
|
|
1959
2856
|
}
|
|
1960
|
-
async function
|
|
2857
|
+
async function loadContentRows(db, collectionSlug, contentIds, fieldSlugs, expectedCollectionId) {
|
|
1961
2858
|
const tableName = getContentTableName(collectionSlug);
|
|
1962
2859
|
const columnRefs = uniqueColumns([...CONTENT_SYSTEM_COLUMNS, ...fieldSlugs]).map((column) => sql.ref(`content.${column}`));
|
|
1963
|
-
|
|
2860
|
+
const rows = /* @__PURE__ */ new Map();
|
|
2861
|
+
const uniqueContentIds = [...new Set(contentIds)];
|
|
2862
|
+
if (uniqueContentIds.length === 0) return rows;
|
|
2863
|
+
const result = await sql`
|
|
2864
|
+
WITH requested AS (${jsonTextValues(db, uniqueContentIds)})
|
|
1964
2865
|
SELECT
|
|
1965
2866
|
${sql.join(columnRefs, sql`, `)},
|
|
1966
2867
|
collection.id AS __emdash_media_usage_collection_id
|
|
1967
2868
|
FROM ${sql.ref(tableName)} AS content
|
|
2869
|
+
INNER JOIN requested ON requested.value = content.id
|
|
1968
2870
|
INNER JOIN _emdash_collections AS collection
|
|
1969
2871
|
ON collection.slug = ${collectionSlug}
|
|
1970
2872
|
${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
|
-
|
|
2873
|
+
`.execute(db);
|
|
2874
|
+
for (const row of result.rows) {
|
|
2875
|
+
const contentId = readString(row.id);
|
|
2876
|
+
if (contentId) rows.set(contentId, row);
|
|
2877
|
+
}
|
|
2878
|
+
return rows;
|
|
2879
|
+
}
|
|
2880
|
+
async function loadRevisionRows(db, revisionIds) {
|
|
2881
|
+
const revisions = /* @__PURE__ */ new Map();
|
|
2882
|
+
const uniqueRevisionIds = [...new Set(revisionIds)];
|
|
2883
|
+
if (uniqueRevisionIds.length === 0) return revisions;
|
|
2884
|
+
const rows = await sql`
|
|
2885
|
+
WITH requested AS (${jsonTextValues(db, uniqueRevisionIds)})
|
|
2886
|
+
SELECT revision.id, revision.collection, revision.entry_id, revision.data
|
|
2887
|
+
FROM revisions AS revision
|
|
2888
|
+
INNER JOIN requested ON requested.value = revision.id
|
|
2889
|
+
`.execute(db);
|
|
2890
|
+
for (const row of rows.rows) {
|
|
2891
|
+
const data = parseRevisionData(row.data);
|
|
2892
|
+
revisions.set(row.id, data ? {
|
|
2893
|
+
success: true,
|
|
2894
|
+
revision: {
|
|
2895
|
+
id: row.id,
|
|
2896
|
+
collection: row.collection,
|
|
2897
|
+
entryId: row.entry_id,
|
|
2898
|
+
data
|
|
2899
|
+
}
|
|
2900
|
+
} : { success: false });
|
|
2901
|
+
}
|
|
2902
|
+
return revisions;
|
|
1994
2903
|
}
|
|
1995
2904
|
function buildContentSource(input) {
|
|
1996
2905
|
const { collectionId, collectionSlug, identityVersion, row, displayData, sourceVariant, revisionId } = input;
|
|
@@ -2102,8 +3011,11 @@ const CONTENT_USAGE_LOCKS_KEY = Symbol.for("emdash.mediaUsage.contentLocks");
|
|
|
2102
3011
|
const CONTENT_USAGE_COLLECTION_LOCKS_KEY = Symbol.for("emdash.mediaUsage.collectionLocks");
|
|
2103
3012
|
const CONTENT_USAGE_REFRESH_MAX_ATTEMPTS = 2;
|
|
2104
3013
|
const MEDIA_USAGE_PROJECTION_ADMISSION_LIMITS = Object.freeze({
|
|
2105
|
-
maxOccurrenceMutationUnitsPerClaim:
|
|
2106
|
-
|
|
3014
|
+
maxOccurrenceMutationUnitsPerClaim: 500,
|
|
3015
|
+
maxProjectionMutationBytesPerVariant: 2e6,
|
|
3016
|
+
maxProjectionMutationBytesPerClaim: 4e6,
|
|
3017
|
+
maxOccurrenceMutationUnitsPerBatch: 5e4,
|
|
3018
|
+
maxProjectionMutationBytesPerBatch: 16e6
|
|
2107
3019
|
});
|
|
2108
3020
|
const ZERO_RESULT = {
|
|
2109
3021
|
success: true,
|
|
@@ -2111,10 +3023,10 @@ const ZERO_RESULT = {
|
|
|
2111
3023
|
deletedSourceCount: 0,
|
|
2112
3024
|
failedSourceCount: 0
|
|
2113
3025
|
};
|
|
2114
|
-
function createContentMediaUsageAdmissionBudget() {
|
|
3026
|
+
function createContentMediaUsageAdmissionBudget(limits = {}) {
|
|
2115
3027
|
return {
|
|
2116
|
-
remainingOccurrenceMutationUnits: MEDIA_USAGE_PROJECTION_ADMISSION_LIMITS.maxOccurrenceMutationUnitsPerClaim,
|
|
2117
|
-
remainingProjectionMutationBytes: MEDIA_USAGE_PROJECTION_ADMISSION_LIMITS.maxProjectionMutationBytesPerClaim,
|
|
3028
|
+
remainingOccurrenceMutationUnits: limits.maxOccurrenceMutationUnits ?? MEDIA_USAGE_PROJECTION_ADMISSION_LIMITS.maxOccurrenceMutationUnitsPerClaim,
|
|
3029
|
+
remainingProjectionMutationBytes: limits.maxProjectionMutationBytes ?? MEDIA_USAGE_PROJECTION_ADMISSION_LIMITS.maxProjectionMutationBytesPerClaim,
|
|
2118
3030
|
hasReservedMutation: false
|
|
2119
3031
|
};
|
|
2120
3032
|
}
|
|
@@ -2123,20 +3035,23 @@ async function planContentMediaUsageProjectionAdmission(repo, snapshots, observe
|
|
|
2123
3035
|
const absentSources = canonicalSourceKeys.filter((sourceKey) => !snapshotSourceKeys.has(sourceKey)).map((sourceKey) => observedSources.get(sourceKey)).filter((source) => source !== void 0);
|
|
2124
3036
|
let deletionOccurrenceUnits = 0;
|
|
2125
3037
|
let deletionBytes = 0;
|
|
3038
|
+
let largestDeletionBytes = 0;
|
|
2126
3039
|
for (const source of absentSources) {
|
|
2127
3040
|
const measurement = await repo.measureSourceGenerationDeletion(source.sourceKey, source.currentGeneration, MEDIA_USAGE_PROJECTION_ADMISSION_LIMITS.maxOccurrenceMutationUnitsPerClaim);
|
|
2128
3041
|
if (measurement.exceedsOccurrenceLimit) return budget.hasReservedMutation ? { outcome: "claim_budget_deferred" } : { outcome: "intrinsic_resource_limit" };
|
|
2129
3042
|
deletionOccurrenceUnits += measurement.occurrenceCount;
|
|
2130
|
-
|
|
3043
|
+
const sourceDeletionBytes = storedMediaUsageSourceByteLength(source) + measurement.occurrenceBytes * 2;
|
|
3044
|
+
deletionBytes += sourceDeletionBytes;
|
|
3045
|
+
largestDeletionBytes = Math.max(largestDeletionBytes, sourceDeletionBytes);
|
|
2131
3046
|
}
|
|
2132
3047
|
const noOpSourceKeys = /* @__PURE__ */ new Set();
|
|
2133
|
-
let cost = projectionAdmissionCost(snapshots, noOpSourceKeys, deletionOccurrenceUnits, deletionBytes);
|
|
3048
|
+
let cost = projectionAdmissionCost(snapshots, noOpSourceKeys, deletionOccurrenceUnits, deletionBytes, largestDeletionBytes);
|
|
2134
3049
|
if (exceedsProjectionAdmissionLimits(cost)) {
|
|
2135
3050
|
for (const snapshot of snapshots) {
|
|
2136
3051
|
const expectedSource = observedSources.get(snapshot.source.sourceKey);
|
|
2137
3052
|
if (expectedSource && await repo.projectionMatchesExpectedSource(snapshot.source, expectedSource)) noOpSourceKeys.add(snapshot.source.sourceKey);
|
|
2138
3053
|
}
|
|
2139
|
-
cost = projectionAdmissionCost(snapshots, noOpSourceKeys, deletionOccurrenceUnits, deletionBytes);
|
|
3054
|
+
cost = projectionAdmissionCost(snapshots, noOpSourceKeys, deletionOccurrenceUnits, deletionBytes, largestDeletionBytes);
|
|
2140
3055
|
}
|
|
2141
3056
|
if (exceedsProjectionAdmissionLimits(cost)) return budget.hasReservedMutation ? { outcome: "claim_budget_deferred" } : { outcome: "intrinsic_resource_limit" };
|
|
2142
3057
|
if (cost.occurrenceMutationUnits > budget.remainingOccurrenceMutationUnits || cost.projectionMutationBytes > budget.remainingProjectionMutationBytes) return { outcome: "claim_budget_deferred" };
|
|
@@ -2150,19 +3065,21 @@ async function planContentMediaUsageProjectionAdmission(repo, snapshots, observe
|
|
|
2150
3065
|
...cost
|
|
2151
3066
|
};
|
|
2152
3067
|
}
|
|
2153
|
-
function projectionAdmissionCost(snapshots, noOpSourceKeys, deletionOccurrenceUnits, deletionBytes) {
|
|
3068
|
+
function projectionAdmissionCost(snapshots, noOpSourceKeys, deletionOccurrenceUnits, deletionBytes, largestDeletionBytes) {
|
|
2154
3069
|
return snapshots.reduce((cost, snapshot) => {
|
|
2155
3070
|
if (noOpSourceKeys.has(snapshot.source.sourceKey)) return cost;
|
|
2156
3071
|
cost.occurrenceMutationUnits += snapshot.occurrences.length;
|
|
2157
3072
|
cost.projectionMutationBytes += snapshot.projectionByteLength;
|
|
3073
|
+
cost.largestProjectionMutationBytes = Math.max(cost.largestProjectionMutationBytes, snapshot.projectionByteLength);
|
|
2158
3074
|
return cost;
|
|
2159
3075
|
}, {
|
|
2160
3076
|
occurrenceMutationUnits: deletionOccurrenceUnits,
|
|
2161
|
-
projectionMutationBytes: deletionBytes
|
|
3077
|
+
projectionMutationBytes: deletionBytes,
|
|
3078
|
+
largestProjectionMutationBytes: largestDeletionBytes
|
|
2162
3079
|
});
|
|
2163
3080
|
}
|
|
2164
3081
|
function exceedsProjectionAdmissionLimits(cost) {
|
|
2165
|
-
return cost.occurrenceMutationUnits > MEDIA_USAGE_PROJECTION_ADMISSION_LIMITS.maxOccurrenceMutationUnitsPerClaim || cost.projectionMutationBytes > MEDIA_USAGE_PROJECTION_ADMISSION_LIMITS.maxProjectionMutationBytesPerClaim;
|
|
3082
|
+
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
3083
|
}
|
|
2167
3084
|
function storedMediaUsageSourceByteLength(source) {
|
|
2168
3085
|
return new TextEncoder().encode(JSON.stringify(source)).byteLength;
|
|
@@ -2171,13 +3088,133 @@ async function refreshContentMediaUsage(db, collectionSlug, contentId) {
|
|
|
2171
3088
|
validateIdentifier(collectionSlug, "collection slug");
|
|
2172
3089
|
return withContentUsageCollectionLock(collectionSlug, () => withContentUsageLock(collectionSlug, contentId, () => refreshContentMediaUsageUnlocked(db, collectionSlug, contentId, {})));
|
|
2173
3090
|
}
|
|
2174
|
-
async function
|
|
2175
|
-
|
|
2176
|
-
|
|
2177
|
-
|
|
2178
|
-
|
|
2179
|
-
|
|
2180
|
-
|
|
3091
|
+
async function refreshContentMediaUsageForWorkBatch(db, items, options = {}) {
|
|
3092
|
+
const results = /* @__PURE__ */ new Map();
|
|
3093
|
+
const batchBudget = createContentMediaUsageAdmissionBudget({
|
|
3094
|
+
maxOccurrenceMutationUnits: MEDIA_USAGE_PROJECTION_ADMISSION_LIMITS.maxOccurrenceMutationUnitsPerBatch,
|
|
3095
|
+
maxProjectionMutationBytes: MEDIA_USAGE_PROJECTION_ADMISSION_LIMITS.maxProjectionMutationBytesPerBatch
|
|
3096
|
+
});
|
|
3097
|
+
const collections = /* @__PURE__ */ new Map();
|
|
3098
|
+
for (const item of items) {
|
|
3099
|
+
const key = `${item.collectionId}\u0000${item.collectionSlug}`;
|
|
3100
|
+
const collectionItems = collections.get(key) ?? [];
|
|
3101
|
+
collectionItems.push(item);
|
|
3102
|
+
collections.set(key, collectionItems);
|
|
3103
|
+
}
|
|
3104
|
+
for (const collectionItems of collections.values()) {
|
|
3105
|
+
if (options.shouldContinue && !options.shouldContinue()) break;
|
|
3106
|
+
const first = collectionItems[0];
|
|
3107
|
+
if (!first) continue;
|
|
3108
|
+
validateIdentifier(first.collectionSlug, "collection slug");
|
|
3109
|
+
if (!first.collectionId) throw new Error("Durable media usage work requires a collection identity");
|
|
3110
|
+
await withContentUsageCollectionLock(first.collectionSlug, async () => {
|
|
3111
|
+
const fieldDiscovery = await loadContentMediaUsageFields(db, first.collectionSlug, first.collectionId);
|
|
3112
|
+
const sourceKeys = collectionItems.flatMap((item) => contentSourceKeys(item.collectionSlug, item.contentId, item.collectionId));
|
|
3113
|
+
const repo = new MediaUsageRepository(db);
|
|
3114
|
+
const observedSources = await repo.findSources(sourceKeys);
|
|
3115
|
+
const snapshots = await loadContentMediaUsageSnapshotsBatch(db, first.collectionSlug, collectionItems.map((item) => item.contentId), fieldDiscovery, {
|
|
3116
|
+
collectionId: first.collectionId,
|
|
3117
|
+
identityVersion: 1
|
|
3118
|
+
}, {
|
|
3119
|
+
shouldContinue: options.shouldContinue,
|
|
3120
|
+
maxOccurrenceCount: MEDIA_USAGE_PROJECTION_ADMISSION_LIMITS.maxOccurrenceMutationUnitsPerBatch,
|
|
3121
|
+
maxProjectionBytes: MEDIA_USAGE_PROJECTION_ADMISSION_LIMITS.maxProjectionMutationBytesPerBatch
|
|
3122
|
+
});
|
|
3123
|
+
const newSourceProjections = [];
|
|
3124
|
+
const newSourceKeys = /* @__PURE__ */ new Map();
|
|
3125
|
+
const existingSourceProjections = [];
|
|
3126
|
+
const unchangedSourceProjections = [];
|
|
3127
|
+
const existingSourceKeys = /* @__PURE__ */ new Map();
|
|
3128
|
+
for (const item of collectionItems) {
|
|
3129
|
+
if (options.shouldContinue && !options.shouldContinue()) break;
|
|
3130
|
+
const snapshotsResult = snapshots.get(item.contentId);
|
|
3131
|
+
const itemSourceKeys = contentSourceKeys(item.collectionSlug, item.contentId, item.collectionId);
|
|
3132
|
+
if (!snapshotsResult?.success) continue;
|
|
3133
|
+
const snapshotsByKey = new Map(snapshotsResult.snapshots.map((snapshot) => [snapshot.source.sourceKey, snapshot]));
|
|
3134
|
+
const existing = itemSourceKeys.map((sourceKey) => observedSources.get(sourceKey)).filter((source) => source !== void 0);
|
|
3135
|
+
const allNew = existing.length === 0;
|
|
3136
|
+
const allExisting = existing.length === snapshotsResult.snapshots.length && existing.every((source) => snapshotsByKey.has(source.sourceKey));
|
|
3137
|
+
if (!allNew && !allExisting) continue;
|
|
3138
|
+
const admission = await planContentMediaUsageProjectionAdmission(repo, snapshotsResult.snapshots, observedSources, itemSourceKeys, batchBudget);
|
|
3139
|
+
if (admission.outcome === "claim_budget_deferred") break;
|
|
3140
|
+
if (admission.outcome !== "admitted") {
|
|
3141
|
+
results.set(contentRefreshKey(item.collectionId, item.contentId), admissionFailureResult(admission.outcome));
|
|
3142
|
+
continue;
|
|
3143
|
+
}
|
|
3144
|
+
const key = contentRefreshKey(item.collectionId, item.contentId);
|
|
3145
|
+
if (allNew) {
|
|
3146
|
+
newSourceProjections.push(...snapshotsResult.snapshots.map((snapshot) => ({
|
|
3147
|
+
source: snapshot.source,
|
|
3148
|
+
occurrences: snapshot.occurrences
|
|
3149
|
+
})));
|
|
3150
|
+
newSourceKeys.set(key, snapshotsResult.snapshots.map((snapshot) => snapshot.source.sourceKey));
|
|
3151
|
+
continue;
|
|
3152
|
+
}
|
|
3153
|
+
const changed = [];
|
|
3154
|
+
const unchanged = [];
|
|
3155
|
+
for (const snapshot of snapshotsResult.snapshots) {
|
|
3156
|
+
const expectedSource = observedSources.get(snapshot.source.sourceKey);
|
|
3157
|
+
if (!expectedSource) continue;
|
|
3158
|
+
if (expectedSource.sourceFingerprint === snapshot.source.sourceFingerprint && expectedSource.sourceCompleteness === (snapshot.source.sourceCompleteness ?? "complete") && expectedSource.lastErrorCode === null) {
|
|
3159
|
+
unchanged.push(snapshot.source.sourceKey);
|
|
3160
|
+
unchangedSourceProjections.push({
|
|
3161
|
+
source: snapshot.source,
|
|
3162
|
+
occurrences: snapshot.occurrences,
|
|
3163
|
+
expectedSource
|
|
3164
|
+
});
|
|
3165
|
+
continue;
|
|
3166
|
+
}
|
|
3167
|
+
changed.push(snapshot.source.sourceKey);
|
|
3168
|
+
existingSourceProjections.push({
|
|
3169
|
+
source: snapshot.source,
|
|
3170
|
+
occurrences: snapshot.occurrences,
|
|
3171
|
+
expectedSource
|
|
3172
|
+
});
|
|
3173
|
+
}
|
|
3174
|
+
existingSourceKeys.set(key, {
|
|
3175
|
+
allCount: snapshotsResult.snapshots.length,
|
|
3176
|
+
changed,
|
|
3177
|
+
unchanged
|
|
3178
|
+
});
|
|
3179
|
+
}
|
|
3180
|
+
const insertedSourceKeys = await repo.replaceNewSourcesBatch(newSourceProjections);
|
|
3181
|
+
const replacedSourceKeys = await repo.replaceExistingSourcesBatch(existingSourceProjections);
|
|
3182
|
+
const matchedSourceKeys = await repo.matchingExistingSourcesBatch(unchangedSourceProjections);
|
|
3183
|
+
for (const [key, expectedSourceKeys] of newSourceKeys) results.set(key, expectedSourceKeys.every((sourceKey) => insertedSourceKeys.has(sourceKey)) ? {
|
|
3184
|
+
success: true,
|
|
3185
|
+
refreshedSourceCount: expectedSourceKeys.length,
|
|
3186
|
+
deletedSourceCount: 0,
|
|
3187
|
+
failedSourceCount: 0
|
|
3188
|
+
} : generationConflictResult({
|
|
3189
|
+
refreshedSourceCount: 0,
|
|
3190
|
+
deletedSourceCount: 0
|
|
3191
|
+
}));
|
|
3192
|
+
for (const [key, expected] of existingSourceKeys) results.set(key, expected.changed.every((sourceKey) => replacedSourceKeys.has(sourceKey)) && expected.unchanged.every((sourceKey) => matchedSourceKeys.has(sourceKey)) ? {
|
|
3193
|
+
success: true,
|
|
3194
|
+
refreshedSourceCount: expected.allCount,
|
|
3195
|
+
deletedSourceCount: 0,
|
|
3196
|
+
failedSourceCount: 0
|
|
3197
|
+
} : generationConflictResult({
|
|
3198
|
+
refreshedSourceCount: 0,
|
|
3199
|
+
deletedSourceCount: 0
|
|
3200
|
+
}));
|
|
3201
|
+
for (const item of collectionItems) {
|
|
3202
|
+
if (options.shouldContinue && !options.shouldContinue()) break;
|
|
3203
|
+
const key = contentRefreshKey(item.collectionId, item.contentId);
|
|
3204
|
+
if (!snapshots.has(item.contentId)) continue;
|
|
3205
|
+
if (results.has(key)) continue;
|
|
3206
|
+
const result = await withContentUsageLock(item.collectionSlug, item.contentId, () => refreshContentMediaUsageUnlocked(db, item.collectionSlug, item.contentId, {
|
|
3207
|
+
collectionId: item.collectionId,
|
|
3208
|
+
durableWork: true,
|
|
3209
|
+
fieldDiscovery,
|
|
3210
|
+
observedSources,
|
|
3211
|
+
snapshotsResult: snapshots.get(item.contentId)
|
|
3212
|
+
}));
|
|
3213
|
+
results.set(key, result);
|
|
3214
|
+
}
|
|
3215
|
+
});
|
|
3216
|
+
}
|
|
3217
|
+
return results;
|
|
2181
3218
|
}
|
|
2182
3219
|
async function refreshContentMediaUsageUnlocked(db, collectionSlug, contentId, options) {
|
|
2183
3220
|
try {
|
|
@@ -2212,17 +3249,13 @@ async function refreshContentMediaUsageUnlocked(db, collectionSlug, contentId, o
|
|
|
2212
3249
|
async function refreshContentMediaUsageAttempt(db, collectionSlug, contentId, options) {
|
|
2213
3250
|
const repo = new MediaUsageRepository(db);
|
|
2214
3251
|
const canonicalSourceKeys = contentSourceKeys(collectionSlug, contentId, options.collectionId);
|
|
2215
|
-
const observedSources = await repo.findSources(canonicalSourceKeys);
|
|
2216
|
-
const snapshotsResult = await loadContentMediaUsageSnapshots(db, collectionSlug, contentId,
|
|
3252
|
+
const observedSources = options.observedSources ?? await repo.findSources(canonicalSourceKeys);
|
|
3253
|
+
const snapshotsResult = options.snapshotsResult ?? await loadContentMediaUsageSnapshots(db, collectionSlug, contentId, options.fieldDiscovery, options.collectionId ? {
|
|
2217
3254
|
collectionId: options.collectionId,
|
|
2218
3255
|
identityVersion: 1
|
|
2219
3256
|
} : void 0);
|
|
2220
3257
|
if (!snapshotsResult.success) {
|
|
2221
3258
|
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
3259
|
if (!options.admissionBudget) throw new Error("Durable media usage work requires an admission budget");
|
|
2227
3260
|
const admission = await planContentMediaUsageProjectionAdmission(repo, [], observedSources, canonicalSourceKeys, options.admissionBudget);
|
|
2228
3261
|
if (admission.outcome !== "admitted") return admissionFailureResult(admission.outcome);
|
|
@@ -2237,11 +3270,7 @@ async function refreshContentMediaUsageAttempt(db, collectionSlug, contentId, op
|
|
|
2237
3270
|
}
|
|
2238
3271
|
return options.durableWork ? snapshotFailureResult(snapshotsResult) : markSnapshotFailure(db, collectionSlug, snapshotsResult);
|
|
2239
3272
|
}
|
|
2240
|
-
if (!await contentCollectionExists(db, collectionSlug
|
|
2241
|
-
if (options.collectionId) return generationConflictResult({
|
|
2242
|
-
refreshedSourceCount: 0,
|
|
2243
|
-
deletedSourceCount: 0
|
|
2244
|
-
});
|
|
3273
|
+
if (!options.collectionId && !await contentCollectionExists(db, collectionSlug)) {
|
|
2245
3274
|
const deletedSourceCount = await repo.deleteContentSources(collectionSlug, contentId);
|
|
2246
3275
|
return {
|
|
2247
3276
|
...ZERO_RESULT,
|
|
@@ -2267,11 +3296,7 @@ async function refreshContentMediaUsageAttempt(db, collectionSlug, contentId, op
|
|
|
2267
3296
|
});
|
|
2268
3297
|
refreshedSourceCount++;
|
|
2269
3298
|
}
|
|
2270
|
-
if (!await contentCollectionExists(db, collectionSlug
|
|
2271
|
-
if (options.collectionId) return generationConflictResult({
|
|
2272
|
-
refreshedSourceCount,
|
|
2273
|
-
deletedSourceCount: 0
|
|
2274
|
-
});
|
|
3299
|
+
if (!options.collectionId && !await contentCollectionExists(db, collectionSlug)) {
|
|
2275
3300
|
const deletedSourceCount = await repo.deleteContentSources(collectionSlug, contentId);
|
|
2276
3301
|
return {
|
|
2277
3302
|
...ZERO_RESULT,
|
|
@@ -2299,6 +3324,9 @@ async function refreshContentMediaUsageAttempt(db, collectionSlug, contentId, op
|
|
|
2299
3324
|
failedSourceCount: 0
|
|
2300
3325
|
};
|
|
2301
3326
|
}
|
|
3327
|
+
function contentRefreshKey(collectionId, contentId) {
|
|
3328
|
+
return `${collectionId}\u0000${contentId}`;
|
|
3329
|
+
}
|
|
2302
3330
|
function contentSourceKeys(collectionSlug, contentId, collectionId) {
|
|
2303
3331
|
return MEDIA_USAGE_CONTENT_SOURCE_VARIANTS.map((sourceVariant) => buildContentMediaUsageSourceKey({
|
|
2304
3332
|
collectionId,
|
|
@@ -2556,5 +3584,5 @@ function getContentUsageCollectionLocks() {
|
|
|
2556
3584
|
}
|
|
2557
3585
|
|
|
2558
3586
|
//#endregion
|
|
2559
|
-
export {
|
|
2560
|
-
//# sourceMappingURL=content-refresh-
|
|
3587
|
+
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 };
|
|
3588
|
+
//# sourceMappingURL=content-refresh-Bwp-8yGy.mjs.map
|