emdash 0.40.1 → 0.41.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/action-token-CbKDcPJi.mjs +26 -0
- package/dist/action-token-CbKDcPJi.mjs.map +1 -0
- package/dist/activation-PtniBLt9.mjs +382 -0
- package/dist/activation-PtniBLt9.mjs.map +1 -0
- package/dist/adapters-C_Tf5x90.d.mts +171 -0
- package/dist/adapters-C_Tf5x90.d.mts.map +1 -0
- package/dist/allowed-origins-U1z4TdEZ.mjs +116 -0
- package/dist/allowed-origins-U1z4TdEZ.mjs.map +1 -0
- package/dist/api/route-utils.d.mts +4 -4
- package/dist/api/route-utils.mjs +46 -45
- package/dist/api/route-utils.mjs.map +1 -1
- package/dist/api/schemas/index.d.mts +2 -2
- package/dist/api/schemas/index.mjs +10 -10
- package/dist/api-CXwQkV_m.mjs +5122 -0
- package/dist/api-CXwQkV_m.mjs.map +1 -0
- package/dist/api-tokens-89WlohEN.mjs +166 -0
- package/dist/api-tokens-89WlohEN.mjs.map +1 -0
- package/dist/apply-Do3KNnUk.mjs +1659 -0
- package/dist/apply-Do3KNnUk.mjs.map +1 -0
- package/dist/approvals-CAX9Yw33.mjs +460 -0
- package/dist/approvals-CAX9Yw33.mjs.map +1 -0
- package/dist/artifact-fetch-B9W4CEST.mjs +659 -0
- package/dist/artifact-fetch-B9W4CEST.mjs.map +1 -0
- package/dist/astro/index.d.mts +14 -14
- package/dist/astro/index.mjs +20 -24
- package/dist/astro/index.mjs.map +1 -1
- package/dist/astro/middleware/auth.d.mts +12 -12
- package/dist/astro/middleware/auth.mjs +10 -10
- package/dist/astro/middleware/media-usage-write-fence.mjs +5 -5
- package/dist/astro/middleware/redirect.mjs +7 -7
- package/dist/astro/middleware/request-context.mjs +3 -3
- package/dist/astro/middleware/setup.mjs +1 -1
- package/dist/astro/middleware.d.mts +12 -12
- package/dist/astro/middleware.mjs +109 -106
- package/dist/astro/middleware.mjs.map +1 -1
- package/dist/astro/routes/api/admin/allowed-domains/_domain_.mjs +14 -14
- package/dist/astro/routes/api/admin/allowed-domains/index.mjs +14 -14
- package/dist/astro/routes/api/admin/api-tokens/_id_.mjs +6 -6
- package/dist/astro/routes/api/admin/api-tokens/index.mjs +7 -7
- package/dist/astro/routes/api/admin/byline-fields/_slug_/usage.mjs +7 -7
- package/dist/astro/routes/api/admin/byline-fields/_slug_.mjs +17 -17
- package/dist/astro/routes/api/admin/byline-fields/index.mjs +17 -17
- package/dist/astro/routes/api/admin/byline-fields/reorder.mjs +17 -17
- package/dist/astro/routes/api/admin/bylines/_id_/index.mjs +23 -23
- package/dist/astro/routes/api/admin/bylines/_id_/translations.mjs +23 -23
- package/dist/astro/routes/api/admin/bylines/index.mjs +23 -23
- package/dist/astro/routes/api/admin/comments/_id_/status.mjs +18 -18
- package/dist/astro/routes/api/admin/comments/_id_.mjs +7 -7
- package/dist/astro/routes/api/admin/comments/bulk.mjs +17 -17
- package/dist/astro/routes/api/admin/comments/counts.mjs +7 -7
- package/dist/astro/routes/api/admin/comments/index.mjs +17 -17
- package/dist/astro/routes/api/admin/hooks/exclusive/_hookName_.mjs +6 -6
- package/dist/astro/routes/api/admin/hooks/exclusive/index.mjs +5 -5
- package/dist/astro/routes/api/admin/media-usage/activation.mjs +20 -20
- package/dist/astro/routes/api/admin/media-usage/collection-deletions/index.mjs +22 -22
- package/dist/astro/routes/api/admin/media-usage/collection-deletions/retry.mjs +22 -22
- package/dist/astro/routes/api/admin/media-usage/progress.mjs +25 -25
- package/dist/astro/routes/api/admin/media-usage/repair.mjs +31 -31
- package/dist/astro/routes/api/admin/media-usage/work/index.mjs +22 -22
- package/dist/astro/routes/api/admin/media-usage/work/retry.mjs +22 -22
- package/dist/astro/routes/api/admin/oauth-clients/_id_.mjs +6 -6
- package/dist/astro/routes/api/admin/oauth-clients/index.mjs +6 -6
- package/dist/astro/routes/api/admin/plugins/_id_/disable.mjs +8 -8
- package/dist/astro/routes/api/admin/plugins/_id_/enable.mjs +8 -8
- package/dist/astro/routes/api/admin/plugins/_id_/index.mjs +72 -68
- package/dist/astro/routes/api/admin/plugins/_id_/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/_id_/mcp.mjs +7 -7
- package/dist/astro/routes/api/admin/plugins/_id_/settings.mjs +71 -67
- package/dist/astro/routes/api/admin/plugins/_id_/settings.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/_id_/uninstall.mjs +72 -68
- package/dist/astro/routes/api/admin/plugins/_id_/uninstall.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/_id_/update.mjs +82 -78
- package/dist/astro/routes/api/admin/plugins/_id_/update.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/index.mjs +72 -68
- package/dist/astro/routes/api/admin/plugins/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/marketplace/_id_/icon.mjs +5 -5
- package/dist/astro/routes/api/admin/plugins/marketplace/_id_/index.mjs +71 -67
- 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 +81 -77
- package/dist/astro/routes/api/admin/plugins/marketplace/_id_/install.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/marketplace/index.mjs +71 -67
- package/dist/astro/routes/api/admin/plugins/marketplace/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/registry/_id_/uninstall.mjs +72 -68
- package/dist/astro/routes/api/admin/plugins/registry/_id_/uninstall.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/registry/_id_/update.mjs +83 -79
- package/dist/astro/routes/api/admin/plugins/registry/_id_/update.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/registry/artifact.mjs +9 -9
- package/dist/astro/routes/api/admin/plugins/registry/install.mjs +74 -70
- package/dist/astro/routes/api/admin/plugins/registry/install.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/registry/publisher-handle.mjs +7 -7
- package/dist/astro/routes/api/admin/plugins/registry/verify.mjs +72 -68
- package/dist/astro/routes/api/admin/plugins/registry/verify.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/updates.mjs +71 -67
- package/dist/astro/routes/api/admin/plugins/updates.mjs.map +1 -1
- package/dist/astro/routes/api/admin/scheduled-policy-rejections/_collection_/_id_.mjs +6 -6
- package/dist/astro/routes/api/admin/themes/marketplace/_id_/index.mjs +71 -67
- 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 +5 -5
- package/dist/astro/routes/api/admin/themes/marketplace/index.mjs +71 -67
- package/dist/astro/routes/api/admin/themes/marketplace/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/transfer/_...path_.mjs +4 -4
- package/dist/astro/routes/api/admin/transfer/approvals/_id_/approve.mjs +40 -40
- package/dist/astro/routes/api/admin/transfer/approvals/_id_/deny.mjs +40 -40
- package/dist/astro/routes/api/admin/transfer/approvals/index.mjs +42 -42
- package/dist/astro/routes/api/admin/transfer/capabilities.mjs +42 -42
- package/dist/astro/routes/api/admin/transfer/exports/_id_/advance.mjs +42 -42
- package/dist/astro/routes/api/admin/transfer/exports/_id_/archive.mjs +43 -43
- package/dist/astro/routes/api/admin/transfer/exports/_id_/files/_...path_.mjs +43 -43
- package/dist/astro/routes/api/admin/transfer/exports/_id_/index.mjs +42 -42
- package/dist/astro/routes/api/admin/transfer/exports/_id_/manifest.mjs +43 -43
- package/dist/astro/routes/api/admin/transfer/exports/index.mjs +44 -44
- package/dist/astro/routes/api/admin/transfer/imports/_id_/abandon.mjs +42 -42
- package/dist/astro/routes/api/admin/transfer/imports/_id_/advance.mjs +42 -42
- package/dist/astro/routes/api/admin/transfer/imports/_id_/analyze.mjs +44 -44
- package/dist/astro/routes/api/admin/transfer/imports/_id_/cancel.mjs +42 -42
- package/dist/astro/routes/api/admin/transfer/imports/_id_/execute.mjs +44 -44
- package/dist/astro/routes/api/admin/transfer/imports/_id_/files/_...path_.mjs +42 -42
- package/dist/astro/routes/api/admin/transfer/imports/_id_/index.mjs +42 -42
- package/dist/astro/routes/api/admin/transfer/imports/_id_/missing.mjs +44 -44
- package/dist/astro/routes/api/admin/transfer/imports/_id_/plan.mjs +42 -42
- package/dist/astro/routes/api/admin/transfer/imports/_id_/receipt.mjs +42 -42
- package/dist/astro/routes/api/admin/transfer/imports/index.mjs +44 -44
- package/dist/astro/routes/api/admin/users/_id_/disable.mjs +5 -5
- package/dist/astro/routes/api/admin/users/_id_/enable.mjs +4 -4
- package/dist/astro/routes/api/admin/users/_id_/index.mjs +15 -15
- package/dist/astro/routes/api/admin/users/_id_/send-recovery.mjs +6 -6
- package/dist/astro/routes/api/admin/users/index.mjs +14 -14
- package/dist/astro/routes/api/auth/dev-bypass.mjs +6 -6
- package/dist/astro/routes/api/auth/invite/accept.mjs +4 -4
- package/dist/astro/routes/api/auth/invite/complete.mjs +18 -18
- package/dist/astro/routes/api/auth/invite/index.mjs +16 -16
- package/dist/astro/routes/api/auth/invite/register-options.mjs +17 -17
- package/dist/astro/routes/api/auth/logout.mjs +5 -5
- package/dist/astro/routes/api/auth/magic-link/send.mjs +18 -18
- package/dist/astro/routes/api/auth/magic-link/verify.mjs +14 -14
- package/dist/astro/routes/api/auth/me.mjs +15 -15
- package/dist/astro/routes/api/auth/mode.mjs +5 -5
- package/dist/astro/routes/api/auth/oauth/_provider_/callback.mjs +3 -3
- package/dist/astro/routes/api/auth/oauth/_provider_.mjs +2 -2
- package/dist/astro/routes/api/auth/passkey/_id_.mjs +14 -14
- package/dist/astro/routes/api/auth/passkey/index.mjs +4 -4
- package/dist/astro/routes/api/auth/passkey/options.mjs +19 -19
- package/dist/astro/routes/api/auth/passkey/register/options.mjs +17 -17
- package/dist/astro/routes/api/auth/passkey/register/verify.mjs +18 -18
- package/dist/astro/routes/api/auth/passkey/verify.mjs +18 -18
- package/dist/astro/routes/api/auth/signup/complete.mjs +18 -18
- package/dist/astro/routes/api/auth/signup/request.mjs +17 -17
- package/dist/astro/routes/api/auth/signup/verify.mjs +4 -4
- package/dist/astro/routes/api/comments/_collection_/_contentId_/index.mjs +12 -12
- package/dist/astro/routes/api/comments/_collection_/_contentId_/reactions.mjs +18 -18
- package/dist/astro/routes/api/content/_collection_/_id_/compare.mjs +5 -5
- package/dist/astro/routes/api/content/_collection_/_id_/discard-draft.mjs +17 -17
- package/dist/astro/routes/api/content/_collection_/_id_/duplicate.mjs +5 -5
- package/dist/astro/routes/api/content/_collection_/_id_/lock.mjs +17 -17
- package/dist/astro/routes/api/content/_collection_/_id_/permanent.mjs +5 -5
- package/dist/astro/routes/api/content/_collection_/_id_/plugin-extensions/_pluginId_/_kind_/_extensionId_.mjs +11 -11
- package/dist/astro/routes/api/content/_collection_/_id_/preview-url.mjs +31 -31
- package/dist/astro/routes/api/content/_collection_/_id_/publish.mjs +17 -17
- package/dist/astro/routes/api/content/_collection_/_id_/references/_relation_/children.d.mts +1 -2
- package/dist/astro/routes/api/content/_collection_/_id_/references/_relation_/children.d.mts.map +1 -1
- package/dist/astro/routes/api/content/_collection_/_id_/references/_relation_/children.mjs +42 -53
- 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 +34 -29
- 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 +5 -5
- package/dist/astro/routes/api/content/_collection_/_id_/revisions.mjs +5 -5
- package/dist/astro/routes/api/content/_collection_/_id_/schedule.mjs +17 -17
- package/dist/astro/routes/api/content/_collection_/_id_/terms/_taxonomy_.mjs +25 -24
- package/dist/astro/routes/api/content/_collection_/_id_/terms/_taxonomy_.mjs.map +1 -1
- package/dist/astro/routes/api/content/_collection_/_id_/translations.mjs +5 -5
- package/dist/astro/routes/api/content/_collection_/_id_/unpublish.mjs +17 -17
- package/dist/astro/routes/api/content/_collection_/_id_.d.mts.map +1 -1
- package/dist/astro/routes/api/content/_collection_/_id_.mjs +18 -18
- package/dist/astro/routes/api/content/_collection_/_id_.mjs.map +1 -1
- package/dist/astro/routes/api/content/_collection_/authors.mjs +5 -5
- package/dist/astro/routes/api/content/_collection_/index.mjs +15 -15
- package/dist/astro/routes/api/content/_collection_/trash.mjs +15 -15
- package/dist/astro/routes/api/dashboard.mjs +10 -9
- package/dist/astro/routes/api/dashboard.mjs.map +1 -1
- package/dist/astro/routes/api/dev/emails.mjs +5 -5
- package/dist/astro/routes/api/health.mjs +6 -6
- package/dist/astro/routes/api/import/probe.d.mts +3 -3
- package/dist/astro/routes/api/import/probe.mjs +23 -23
- package/dist/astro/routes/api/import/wordpress/analyze.mjs +6 -6
- package/dist/astro/routes/api/import/wordpress/execute.d.mts +13 -13
- package/dist/astro/routes/api/import/wordpress/execute.mjs +16 -16
- package/dist/astro/routes/api/import/wordpress/media.d.mts +12 -12
- package/dist/astro/routes/api/import/wordpress/media.mjs +19 -19
- package/dist/astro/routes/api/import/wordpress/prepare.mjs +18 -18
- package/dist/astro/routes/api/import/wordpress/rewrite-urls.d.mts +13 -13
- package/dist/astro/routes/api/import/wordpress/rewrite-urls.mjs +28 -28
- package/dist/astro/routes/api/import/wordpress-plugin/analyze.d.mts +1 -1
- package/dist/astro/routes/api/import/wordpress-plugin/analyze.mjs +23 -23
- package/dist/astro/routes/api/import/wordpress-plugin/execute.d.mts +13 -13
- package/dist/astro/routes/api/import/wordpress-plugin/execute.mjs +34 -34
- package/dist/astro/routes/api/manifest.mjs +6 -6
- package/dist/astro/routes/api/mcp.mjs +91 -91
- package/dist/astro/routes/api/media/_id_/confirm.mjs +19 -19
- package/dist/astro/routes/api/media/_id_/replace.mjs +16 -16
- package/dist/astro/routes/api/media/_id_/upload.mjs +9 -9
- package/dist/astro/routes/api/media/_id_/usage.mjs +33 -33
- package/dist/astro/routes/api/media/_id_.mjs +31 -31
- package/dist/astro/routes/api/media/asset/_id_/_filename_.mjs +6 -6
- package/dist/astro/routes/api/media/file/_...key_.mjs +9 -9
- package/dist/astro/routes/api/media/folders/_id_.mjs +16 -16
- package/dist/astro/routes/api/media/folders/index.mjs +16 -16
- package/dist/astro/routes/api/media/providers/_providerId_/_itemId_.mjs +5 -5
- package/dist/astro/routes/api/media/providers/_providerId_/index.mjs +5 -5
- package/dist/astro/routes/api/media/providers/index.mjs +5 -5
- package/dist/astro/routes/api/media/upload-url.mjs +18 -18
- package/dist/astro/routes/api/media.mjs +35 -35
- package/dist/astro/routes/api/menus/_name_/items/_id_.mjs +17 -17
- package/dist/astro/routes/api/menus/_name_/items.mjs +17 -17
- package/dist/astro/routes/api/menus/_name_/reorder.mjs +17 -17
- package/dist/astro/routes/api/menus/_name_/translations.mjs +17 -17
- package/dist/astro/routes/api/menus/_name_.mjs +17 -17
- package/dist/astro/routes/api/menus/index.mjs +17 -17
- package/dist/astro/routes/api/oauth/authorize.mjs +6 -6
- package/dist/astro/routes/api/oauth/device/authorize.d.mts +2 -1
- package/dist/astro/routes/api/oauth/device/authorize.d.mts.map +1 -1
- package/dist/astro/routes/api/oauth/device/authorize.mjs +23 -9
- package/dist/astro/routes/api/oauth/device/authorize.mjs.map +1 -1
- package/dist/astro/routes/api/oauth/device/code.mjs +11 -11
- package/dist/astro/routes/api/oauth/device/token.mjs +10 -10
- package/dist/astro/routes/api/oauth/register.mjs +5 -5
- package/dist/astro/routes/api/oauth/token/refresh.mjs +8 -8
- package/dist/astro/routes/api/oauth/token/revoke.mjs +8 -8
- package/dist/astro/routes/api/oauth/token.mjs +8 -8
- package/dist/astro/routes/api/openapi.json.mjs +20 -20
- package/dist/astro/routes/api/plugins/_pluginId_/_...path_.mjs +11 -11
- package/dist/astro/routes/api/redirects/404s/index.mjs +19 -19
- package/dist/astro/routes/api/redirects/404s/summary.mjs +19 -19
- package/dist/astro/routes/api/redirects/_id_.mjs +19 -19
- package/dist/astro/routes/api/redirects/index.mjs +19 -19
- package/dist/astro/routes/api/relations/_id_/index.mjs +34 -29
- package/dist/astro/routes/api/relations/_id_/index.mjs.map +1 -1
- package/dist/astro/routes/api/relations/index.mjs +36 -31
- package/dist/astro/routes/api/relations/index.mjs.map +1 -1
- package/dist/astro/routes/api/revisions/_revisionId_/index.mjs +5 -5
- package/dist/astro/routes/api/revisions/_revisionId_/restore.mjs +5 -5
- package/dist/astro/routes/api/schema/block-types/_slug_/index.mjs +71 -67
- package/dist/astro/routes/api/schema/block-types/_slug_/index.mjs.map +1 -1
- package/dist/astro/routes/api/schema/block-types/_slug_/versions/_version_/activate.mjs +71 -67
- package/dist/astro/routes/api/schema/block-types/_slug_/versions/_version_/activate.mjs.map +1 -1
- package/dist/astro/routes/api/schema/block-types/index.mjs +71 -67
- package/dist/astro/routes/api/schema/block-types/index.mjs.map +1 -1
- package/dist/astro/routes/api/schema/collections/_slug_/fields/_fieldSlug_.mjs +73 -69
- 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 +71 -67
- 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 +71 -67
- package/dist/astro/routes/api/schema/collections/_slug_/fields/reorder.mjs.map +1 -1
- package/dist/astro/routes/api/schema/collections/_slug_/index.mjs +71 -67
- package/dist/astro/routes/api/schema/collections/_slug_/index.mjs.map +1 -1
- package/dist/astro/routes/api/schema/collections/index.mjs +71 -67
- package/dist/astro/routes/api/schema/collections/index.mjs.map +1 -1
- package/dist/astro/routes/api/schema/collections/reorder.mjs +71 -67
- package/dist/astro/routes/api/schema/collections/reorder.mjs.map +1 -1
- package/dist/astro/routes/api/schema/index.mjs +16 -16
- package/dist/astro/routes/api/schema/orphans/_slug_.mjs +71 -67
- package/dist/astro/routes/api/schema/orphans/_slug_.mjs.map +1 -1
- package/dist/astro/routes/api/schema/orphans/index.mjs +71 -67
- package/dist/astro/routes/api/schema/orphans/index.mjs.map +1 -1
- package/dist/astro/routes/api/search/enable.mjs +19 -19
- package/dist/astro/routes/api/search/index.mjs +18 -18
- package/dist/astro/routes/api/search/rebuild.mjs +19 -19
- package/dist/astro/routes/api/search/stats.mjs +9 -9
- package/dist/astro/routes/api/search/suggest.mjs +18 -18
- package/dist/astro/routes/api/sections/_slug_.mjs +18 -18
- package/dist/astro/routes/api/sections/index.mjs +18 -18
- package/dist/astro/routes/api/settings/backups/archives/_name_.mjs +7 -7
- package/dist/astro/routes/api/settings/backups/archives/index.mjs +7 -7
- package/dist/astro/routes/api/settings/backups/export.mjs +7 -7
- package/dist/astro/routes/api/settings/backups/index.mjs +8 -8
- package/dist/astro/routes/api/settings/email.mjs +6 -6
- package/dist/astro/routes/api/settings.mjs +21 -21
- package/dist/astro/routes/api/setup/admin-verify.mjs +19 -19
- package/dist/astro/routes/api/setup/admin.mjs +18 -18
- package/dist/astro/routes/api/setup/dev-bypass.mjs +45 -39
- package/dist/astro/routes/api/setup/dev-bypass.mjs.map +1 -1
- package/dist/astro/routes/api/setup/dev-reset.mjs +4 -4
- package/dist/astro/routes/api/setup/index.mjs +50 -44
- package/dist/astro/routes/api/setup/index.mjs.map +1 -1
- package/dist/astro/routes/api/setup/status.mjs +6 -6
- package/dist/astro/routes/api/snapshot.mjs +8 -8
- package/dist/astro/routes/api/taxonomies/_name_/reorder.mjs +23 -23
- package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_/translations.mjs +23 -23
- package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_.mjs +23 -23
- package/dist/astro/routes/api/taxonomies/_name_/terms/index.mjs +23 -23
- package/dist/astro/routes/api/taxonomies/_name_/translations.mjs +22 -22
- package/dist/astro/routes/api/taxonomies/_name_.mjs +23 -23
- package/dist/astro/routes/api/taxonomies/bulk-tag.mjs +36 -35
- package/dist/astro/routes/api/taxonomies/bulk-tag.mjs.map +1 -1
- package/dist/astro/routes/api/taxonomies/index.mjs +23 -23
- package/dist/astro/routes/api/themes/preview.mjs +6 -6
- package/dist/astro/routes/api/typegen.mjs +8 -8
- package/dist/astro/routes/api/visual-editing/action-token.mjs +6 -6
- package/dist/astro/routes/api/visual-editing/content/_collection_/_id_/publish.mjs +19 -19
- package/dist/astro/routes/api/visual-editing/toolbar-labels.mjs +4 -4
- package/dist/astro/routes/api/well-known/auth.mjs +1 -1
- package/dist/astro/routes/api/well-known/oauth-authorization-server.mjs +2 -2
- package/dist/astro/routes/api/well-known/oauth-protected-resource.mjs +2 -2
- package/dist/astro/routes/api/widget-areas/_name_/reorder.mjs +16 -16
- package/dist/astro/routes/api/widget-areas/_name_/widgets/_id_.mjs +19 -19
- package/dist/astro/routes/api/widget-areas/_name_/widgets.mjs +19 -19
- package/dist/astro/routes/api/widget-areas/_name_.mjs +9 -9
- package/dist/astro/routes/api/widget-areas/index.mjs +19 -19
- package/dist/astro/routes/api/widget-components.mjs +5 -5
- package/dist/astro/routes/robots.txt.mjs +6 -6
- package/dist/astro/routes/sitemap-_collection_.xml.mjs +9 -9
- package/dist/astro/routes/sitemap.xml.mjs +7 -7
- package/dist/astro/types.d.mts +24 -18
- package/dist/astro/types.d.mts.map +1 -1
- package/dist/audit-CrgmE9LE.mjs +127 -0
- package/dist/audit-CrgmE9LE.mjs.map +1 -0
- package/dist/auth/providers/github.d.mts +1 -1
- package/dist/auth/providers/google.d.mts +1 -1
- package/dist/authoritative-records-C2YzIdbu.mjs +5172 -0
- package/dist/authoritative-records-C2YzIdbu.mjs.map +1 -0
- package/dist/authorize-WgdKF8QY.mjs +49 -0
- package/dist/authorize-WgdKF8QY.mjs.map +1 -0
- package/dist/backup-Ck8_lMO3.mjs +246 -0
- package/dist/backup-Ck8_lMO3.mjs.map +1 -0
- package/dist/block-types-BQ90asVI.mjs +132 -0
- package/dist/block-types-BQ90asVI.mjs.map +1 -0
- package/dist/block-values-ACFqgB1D.mjs +175 -0
- package/dist/block-values-ACFqgB1D.mjs.map +1 -0
- package/dist/bundle-Db1iNMv_.mjs +667 -0
- package/dist/bundle-Db1iNMv_.mjs.map +1 -0
- package/dist/byline-BayaYGoj.mjs +909 -0
- package/dist/byline-BayaYGoj.mjs.map +1 -0
- package/dist/byline-fields-B8HH-35f.mjs +254 -0
- package/dist/byline-fields-B8HH-35f.mjs.map +1 -0
- package/dist/byline-fields-hMPjf6Eu.mjs +123 -0
- package/dist/byline-fields-hMPjf6Eu.mjs.map +1 -0
- package/dist/byline-registry-B_EK_TQf.mjs +406 -0
- package/dist/byline-registry-B_EK_TQf.mjs.map +1 -0
- package/dist/bylines-DFAaFXWi.mjs +214 -0
- package/dist/bylines-DFAaFXWi.mjs.map +1 -0
- package/dist/bylines-DkIxUxmr.mjs +232 -0
- package/dist/bylines-DkIxUxmr.mjs.map +1 -0
- package/dist/cache-DkvhQ8XE.mjs +108 -0
- package/dist/cache-DkvhQ8XE.mjs.map +1 -0
- package/dist/canonical-CcSuuTlH.mjs +174 -0
- package/dist/canonical-CcSuuTlH.mjs.map +1 -0
- package/dist/capture-triggers-DJEoOTOq.mjs +362 -0
- package/dist/capture-triggers-DJEoOTOq.mjs.map +1 -0
- package/dist/challenge-store-CvBl81AQ.mjs +51 -0
- package/dist/challenge-store-CvBl81AQ.mjs.map +1 -0
- package/dist/checksum-CClweQzI.mjs +162 -0
- package/dist/checksum-CClweQzI.mjs.map +1 -0
- package/dist/chrome-tags-D5caJwwp.mjs +24 -0
- package/dist/chrome-tags-D5caJwwp.mjs.map +1 -0
- package/dist/chunks-DwBaj8aT.mjs +25 -0
- package/dist/chunks-DwBaj8aT.mjs.map +1 -0
- package/dist/cli/index.mjs +374 -761
- package/dist/cli/index.mjs.map +1 -1
- package/dist/client/cf-access.d.mts +1 -1
- package/dist/client/index.d.mts +32 -32
- package/dist/client/index.mjs +2 -2
- package/dist/collection-deletion-CLCdXsnV.mjs +436 -0
- package/dist/collection-deletion-CLCdXsnV.mjs.map +1 -0
- package/dist/collection-deletion-processor-hNw8x01F.mjs +217 -0
- package/dist/collection-deletion-processor-hNw8x01F.mjs.map +1 -0
- package/dist/collection-slugs-cache-CUuiduLq.mjs +85 -0
- package/dist/collection-slugs-cache-CUuiduLq.mjs.map +1 -0
- package/dist/comment-D2uvL63j.mjs +313 -0
- package/dist/comment-D2uvL63j.mjs.map +1 -0
- package/dist/comment-reaction-DevUuzg4.mjs +85 -0
- package/dist/comment-reaction-DevUuzg4.mjs.map +1 -0
- package/dist/comments-Cq0s7_hO.mjs +195 -0
- package/dist/comments-Cq0s7_hO.mjs.map +1 -0
- package/dist/comments-M4EDYAHw.mjs +99 -0
- package/dist/comments-M4EDYAHw.mjs.map +1 -0
- package/dist/components-CuIGwXMs.mjs +108 -0
- package/dist/components-CuIGwXMs.mjs.map +1 -0
- package/dist/config-52Ea5IWt.d.mts +39 -0
- package/dist/config-52Ea5IWt.d.mts.map +1 -0
- package/dist/config-CCz3xOLc.mjs +242 -0
- package/dist/config-CCz3xOLc.mjs.map +1 -0
- package/dist/config-D3d5Qudq.d.mts +6669 -0
- package/dist/config-D3d5Qudq.d.mts.map +1 -0
- package/dist/content-CbnufDsM.mjs +2018 -0
- package/dist/content-CbnufDsM.mjs.map +1 -0
- package/dist/content-list-query-D_7B1FE5.d.mts +26 -0
- package/dist/content-list-query-D_7B1FE5.d.mts.map +1 -0
- package/dist/content-policy-CYu6K1KB.mjs +46 -0
- package/dist/content-policy-CYu6K1KB.mjs.map +1 -0
- package/dist/content-repair-DlDUgFGp.mjs +442 -0
- package/dist/content-repair-DlDUgFGp.mjs.map +1 -0
- package/dist/context-CGQLA1-a.mjs +1922 -0
- package/dist/context-CGQLA1-a.mjs.map +1 -0
- package/dist/cron-c4D5C5Fx.mjs +284 -0
- package/dist/cron-c4D5C5Fx.mjs.map +1 -0
- package/dist/dashboard-CBq9kmOn.mjs +151 -0
- package/dist/dashboard-CBq9kmOn.mjs.map +1 -0
- package/dist/db/index.d.mts +3 -3
- package/dist/db/index.mjs +1 -1
- package/dist/db/libsql-migrations.d.mts +1 -1
- package/dist/db/libsql-migrations.mjs +4 -4
- package/dist/db/libsql.d.mts +1 -1
- package/dist/db/postgres-migrations.d.mts +1 -1
- package/dist/db/postgres-migrations.mjs +4 -4
- package/dist/db/postgres.d.mts +1 -1
- package/dist/db/sqlite-migrations.d.mts +1 -1
- package/dist/db/sqlite-migrations.mjs +4 -4
- package/dist/db/sqlite.d.mts +1 -1
- package/dist/db/sqlite.mjs +1 -1
- package/dist/default-DPsys51U.mjs +81 -0
- package/dist/default-DPsys51U.mjs.map +1 -0
- package/dist/deferred-tasks-CZ7rzBdo.d.mts +9 -0
- package/dist/deferred-tasks-CZ7rzBdo.d.mts.map +1 -0
- package/dist/dev-typegen-HRxwLRcT.mjs +29 -0
- package/dist/dev-typegen-HRxwLRcT.mjs.map +1 -0
- package/dist/device-flow-OcSqE9uY.mjs +521 -0
- package/dist/device-flow-OcSqE9uY.mjs.map +1 -0
- package/dist/digest-DVZ--cE9.mjs +194 -0
- package/dist/digest-DVZ--cE9.mjs.map +1 -0
- package/dist/direct-executor-DyjAqkpT.mjs +104 -0
- package/dist/direct-executor-DyjAqkpT.mjs.map +1 -0
- package/dist/dist-FPR93_xf.mjs +810 -0
- package/dist/dist-FPR93_xf.mjs.map +1 -0
- package/dist/email-console-DyQIgEnz.mjs +50 -0
- package/dist/email-console-DyQIgEnz.mjs.map +1 -0
- package/dist/email-locale-BYb16rVd.mjs +25 -0
- package/dist/email-locale-BYb16rVd.mjs.map +1 -0
- package/dist/emdash-runtime-CrzxJFmF.mjs +4214 -0
- package/dist/emdash-runtime-CrzxJFmF.mjs.map +1 -0
- package/dist/enrich-DBtCncE2.mjs +194 -0
- package/dist/enrich-DBtCncE2.mjs.map +1 -0
- package/dist/entry-lock-BN5y4YbO.d.mts +4481 -0
- package/dist/entry-lock-BN5y4YbO.d.mts.map +1 -0
- package/dist/entry-lock-BaRBHCsH.mjs +1173 -0
- package/dist/entry-lock-BaRBHCsH.mjs.map +1 -0
- package/dist/entry-lock-C6NcnZPV.mjs +163 -0
- package/dist/entry-lock-C6NcnZPV.mjs.map +1 -0
- package/dist/entry-locks-BTyQLdbC.mjs +167 -0
- package/dist/entry-locks-BTyQLdbC.mjs.map +1 -0
- package/dist/error-BfsNNrIE.mjs +90 -0
- package/dist/error-BfsNNrIE.mjs.map +1 -0
- package/dist/errors-BN1QAnEY.mjs +460 -0
- package/dist/errors-BN1QAnEY.mjs.map +1 -0
- package/dist/errors-Bt3goF8I.mjs +120 -0
- package/dist/errors-Bt3goF8I.mjs.map +1 -0
- package/dist/escape-BveidMa2.mjs +9 -0
- package/dist/escape-BveidMa2.mjs.map +1 -0
- package/dist/fence-Bb_IbCxI.mjs +162 -0
- package/dist/fence-Bb_IbCxI.mjs.map +1 -0
- package/dist/field-defs-cache-CsZctvbu.mjs +77 -0
- package/dist/field-defs-cache-CsZctvbu.mjs.map +1 -0
- package/dist/field-map-6m9rF49t.mjs +83 -0
- package/dist/field-map-6m9rF49t.mjs.map +1 -0
- package/dist/focal-point-CZ3d1wK5.mjs +23 -0
- package/dist/focal-point-CZ3d1wK5.mjs.map +1 -0
- package/dist/fts-manager-CCaZTp8y.mjs +443 -0
- package/dist/fts-manager-CCaZTp8y.mjs.map +1 -0
- package/dist/gc-xowRjczI.mjs +75 -0
- package/dist/gc-xowRjczI.mjs.map +1 -0
- package/dist/hash-COVK27Pc.mjs +37 -0
- package/dist/hash-COVK27Pc.mjs.map +1 -0
- package/dist/hook-result-CYSk0XFe.d.mts +31 -0
- package/dist/hook-result-CYSk0XFe.d.mts.map +1 -0
- package/dist/hreflang-CChPV7jx.mjs +105 -0
- package/dist/hreflang-CChPV7jx.mjs.map +1 -0
- package/dist/hreflang-DRslq3QI.d.mts +50 -0
- package/dist/hreflang-DRslq3QI.d.mts.map +1 -0
- package/dist/http-route-dispatch-CAdp2onn.mjs +339 -0
- package/dist/http-route-dispatch-CAdp2onn.mjs.map +1 -0
- package/dist/identity-NVTOOQyq.mjs +35 -0
- package/dist/identity-NVTOOQyq.mjs.map +1 -0
- package/dist/import-wpSO2N0x.mjs +2020 -0
- package/dist/import-wpSO2N0x.mjs.map +1 -0
- package/dist/index-CDs2wq4X.d.mts +623 -0
- package/dist/index-CDs2wq4X.d.mts.map +1 -0
- package/dist/index.d.mts +24 -24
- package/dist/index.mjs +103 -101
- package/dist/install-finalization-D9R9R-W8.mjs +58 -0
- package/dist/install-finalization-D9R9R-W8.mjs.map +1 -0
- package/dist/keys-Bck6LBfF.mjs +61 -0
- package/dist/keys-Bck6LBfF.mjs.map +1 -0
- package/dist/kinds-CYmRESWj.mjs +974 -0
- package/dist/kinds-CYmRESWj.mjs.map +1 -0
- package/dist/lifecycle-C815ZQfV.mjs +25 -0
- package/dist/lifecycle-C815ZQfV.mjs.map +1 -0
- package/dist/load-D99axixL.mjs +28 -0
- package/dist/load-D99axixL.mjs.map +1 -0
- package/dist/loader-CrRPfkHS.mjs +1197 -0
- package/dist/loader-CrRPfkHS.mjs.map +1 -0
- package/dist/loops-DMKlygqX.mjs +203 -0
- package/dist/loops-DMKlygqX.mjs.map +1 -0
- package/dist/manifest-builder-BQzCHNgB.mjs +189 -0
- package/dist/manifest-builder-BQzCHNgB.mjs.map +1 -0
- package/dist/manifest-schema-Ci2gmd0u.mjs +492 -0
- package/dist/manifest-schema-Ci2gmd0u.mjs.map +1 -0
- package/dist/media/image-endpoint.mjs +1 -1
- package/dist/media/index.d.mts +1 -1
- package/dist/media/index.mjs +4 -4
- package/dist/media/local-runtime.d.mts +14 -14
- package/dist/media/local-runtime.mjs +6 -6
- package/dist/media-BUQePMxP.mjs +373 -0
- package/dist/media-BUQePMxP.mjs.map +1 -0
- package/dist/media-DH8ibNlY.mjs +294 -0
- package/dist/media-DH8ibNlY.mjs.map +1 -0
- package/dist/media-OEIQ3bVc.mjs +408 -0
- package/dist/media-OEIQ3bVc.mjs.map +1 -0
- package/dist/media-allowlist-pYtaBA95.mjs +44 -0
- package/dist/media-allowlist-pYtaBA95.mjs.map +1 -0
- package/dist/media-folders-Bf8_s4de.mjs +210 -0
- package/dist/media-folders-Bf8_s4de.mjs.map +1 -0
- package/dist/media-url-C6klEuNd.mjs +43 -0
- package/dist/media-url-C6klEuNd.mjs.map +1 -0
- package/dist/media-usage-D7Y64m6v.mjs +1629 -0
- package/dist/media-usage-D7Y64m6v.mjs.map +1 -0
- package/dist/media-usage-activation-DrqbmgLA.mjs +78 -0
- package/dist/media-usage-activation-DrqbmgLA.mjs.map +1 -0
- package/dist/media-usage-work-DommYhYA.mjs +152 -0
- package/dist/media-usage-work-DommYhYA.mjs.map +1 -0
- package/dist/media-usage-work-HU63hNDu.mjs +586 -0
- package/dist/media-usage-work-HU63hNDu.mjs.map +1 -0
- package/dist/menus-BQfusWEC.mjs +3608 -0
- package/dist/menus-BQfusWEC.mjs.map +1 -0
- package/dist/menus-BtwjQt5s.mjs +753 -0
- package/dist/menus-BtwjQt5s.mjs.map +1 -0
- package/dist/menus-p_M1V7J_.mjs +139 -0
- package/dist/menus-p_M1V7J_.mjs.map +1 -0
- package/dist/migrations/index.d.mts +1 -1
- package/dist/migrations/index.mjs +3 -3
- package/dist/mime-C94qBG-P.mjs +36 -0
- package/dist/mime-C94qBG-P.mjs.map +1 -0
- package/dist/mode-DpYW3w6U.mjs +23 -0
- package/dist/mode-DpYW3w6U.mjs.map +1 -0
- package/dist/node-sqlite-compat-pWFw0lcc.mjs +46 -0
- package/dist/node-sqlite-compat-pWFw0lcc.mjs.map +1 -0
- package/dist/normalize-DduyxBjf.mjs +191 -0
- package/dist/normalize-DduyxBjf.mjs.map +1 -0
- package/dist/oauth-authorization-DAXsH1H9.mjs +274 -0
- package/dist/oauth-authorization-DAXsH1H9.mjs.map +1 -0
- package/dist/oauth-clients-DENiDQri.mjs +266 -0
- package/dist/oauth-clients-DENiDQri.mjs.map +1 -0
- package/dist/oauth-state-store-y8mEYVq9.mjs +50 -0
- package/dist/oauth-state-store-y8mEYVq9.mjs.map +1 -0
- package/dist/oauth-user-lookup-CtTYAy-O.mjs +26 -0
- package/dist/oauth-user-lookup-CtTYAy-O.mjs.map +1 -0
- package/dist/object-cache/memory.d.mts +1 -1
- package/dist/options-BYa1FgIM.d.mts +81 -0
- package/dist/options-BYa1FgIM.d.mts.map +1 -0
- package/dist/page/index.d.mts +2 -2
- package/dist/page/index.mjs +5 -5
- package/dist/parse-CORGGhHf.mjs +81 -0
- package/dist/parse-CORGGhHf.mjs.map +1 -0
- package/dist/parse-avNM1xWV.d.mts +168 -0
- package/dist/parse-avNM1xWV.d.mts.map +1 -0
- package/dist/passkey-config-Dih5YeIS.mjs +46 -0
- package/dist/passkey-config-Dih5YeIS.mjs.map +1 -0
- package/dist/paths-d51RFm8M.mjs +77 -0
- package/dist/paths-d51RFm8M.mjs.map +1 -0
- package/dist/patterns-CoqlXUvk.mjs +145 -0
- package/dist/patterns-CoqlXUvk.mjs.map +1 -0
- package/dist/placeholder-D2aksPMF.d.mts +306 -0
- package/dist/placeholder-D2aksPMF.d.mts.map +1 -0
- package/dist/plan-DqeZKuaR.mjs +135 -0
- package/dist/plan-DqeZKuaR.mjs.map +1 -0
- package/dist/plugin-test-runtime.d.mts +14 -14
- package/dist/plugin-test-runtime.mjs +110 -107
- package/dist/plugin-types.d.mts +2 -2
- package/dist/plugin-utils.d.mts +12 -12
- package/dist/plugins/adapt-sandbox-entry.d.mts +12 -12
- package/dist/plugins/adapt-sandbox-entry.mjs +3 -3
- package/dist/plugins/host.d.mts +5 -5
- package/dist/plugins/host.mjs +42 -41
- package/dist/plugins-Bb7oqjQA.mjs +277 -0
- package/dist/plugins-Bb7oqjQA.mjs.map +1 -0
- package/dist/policy-BcEqut3n.mjs +45 -0
- package/dist/policy-BcEqut3n.mjs.map +1 -0
- package/dist/portable-text-DXE8ymtD.mjs +307 -0
- package/dist/portable-text-DXE8ymtD.mjs.map +1 -0
- package/dist/preview-DEDWbwA_.mjs +107 -0
- package/dist/preview-DEDWbwA_.mjs.map +1 -0
- package/dist/protocol-BJbTzvwl.d.mts +61 -0
- package/dist/protocol-BJbTzvwl.d.mts.map +1 -0
- package/dist/public-submission-D9c9S14m.mjs +250 -0
- package/dist/public-submission-D9c9S14m.mjs.map +1 -0
- package/dist/public-url-CIRe-2T6.mjs +101 -0
- package/dist/public-url-CIRe-2T6.mjs.map +1 -0
- package/dist/query-BzifXlPS.mjs +1156 -0
- package/dist/query-BzifXlPS.mjs.map +1 -0
- package/dist/query-OzMJ6vJP.mjs +41 -0
- package/dist/query-OzMJ6vJP.mjs.map +1 -0
- package/dist/rate-limit-Csp60Vik.mjs +120 -0
- package/dist/rate-limit-Csp60Vik.mjs.map +1 -0
- package/dist/receipt-B-aU4hpJ.mjs +43 -0
- package/dist/receipt-B-aU4hpJ.mjs.map +1 -0
- package/dist/redirect-CDSw1sU3.mjs +17 -0
- package/dist/redirect-CDSw1sU3.mjs.map +1 -0
- package/dist/redirect-D1ArbO85.mjs +411 -0
- package/dist/redirect-D1ArbO85.mjs.map +1 -0
- package/dist/redirects-BjTwDTsV.mjs +148 -0
- package/dist/redirects-BjTwDTsV.mjs.map +1 -0
- package/dist/redirects-Ck50kH3n.mjs +446 -0
- package/dist/redirects-Ck50kH3n.mjs.map +1 -0
- package/dist/registry/testing.mjs +3 -3
- package/dist/registry-CFcNCayZ.mjs +6754 -0
- package/dist/registry-CFcNCayZ.mjs.map +1 -0
- package/dist/relations-Cfaa1fDl.mjs +776 -0
- package/dist/relations-Cfaa1fDl.mjs.map +1 -0
- package/dist/request-cache-iHRlHx1d.mjs +104 -0
- package/dist/request-cache-iHRlHx1d.mjs.map +1 -0
- package/dist/request-context.d.mts +1 -1
- package/dist/request-meta-D47mqyev.mjs +141 -0
- package/dist/request-meta-D47mqyev.mjs.map +1 -0
- package/dist/resolve-BPE8sMvx.mjs +99 -0
- package/dist/resolve-BPE8sMvx.mjs.map +1 -0
- package/dist/resolve-C0s1E_fH.mjs +199 -0
- package/dist/resolve-C0s1E_fH.mjs.map +1 -0
- package/dist/revision-j1p4-bOj.mjs +302 -0
- package/dist/revision-j1p4-bOj.mjs.map +1 -0
- package/dist/route-wire-C9PJV9aL.mjs +197 -0
- package/dist/route-wire-C9PJV9aL.mjs.map +1 -0
- package/dist/routes-lyYw0mMf.mjs +272 -0
- package/dist/routes-lyYw0mMf.mjs.map +1 -0
- package/dist/runner-B3eyB9Gb.mjs +6121 -0
- package/dist/runner-B3eyB9Gb.mjs.map +1 -0
- package/dist/runner-DoYH2Jcu.d.mts +68 -0
- package/dist/runner-DoYH2Jcu.d.mts.map +1 -0
- package/dist/runtime.d.mts +13 -13
- package/dist/runtime.mjs +3 -3
- package/dist/schema-BAayK46S.mjs +13 -0
- package/dist/schema-BAayK46S.mjs.map +1 -0
- package/dist/schema-Gqcl-8G4.mjs +815 -0
- package/dist/schema-Gqcl-8G4.mjs.map +1 -0
- package/dist/scopes-BqPOKoKf.mjs +34 -0
- package/dist/scopes-BqPOKoKf.mjs.map +1 -0
- package/dist/search-YJKPIEV6.mjs +448 -0
- package/dist/search-YJKPIEV6.mjs.map +1 -0
- package/dist/sections-BR_e-wK5.mjs +346 -0
- package/dist/sections-BR_e-wK5.mjs.map +1 -0
- package/dist/seed/index.d.mts +2 -2
- package/dist/seed/index.mjs +37 -31
- package/dist/seo/index.d.mts +3 -3
- package/dist/seo/index.mjs +22 -21
- package/dist/seo/index.mjs.map +1 -1
- package/dist/seo-Dsj8hy3j.mjs +114 -0
- package/dist/seo-Dsj8hy3j.mjs.map +1 -0
- package/dist/seo-XvH4LNNp.mjs +133 -0
- package/dist/seo-XvH4LNNp.mjs.map +1 -0
- package/dist/service-BsVG05gS.mjs +150 -0
- package/dist/service-BsVG05gS.mjs.map +1 -0
- package/dist/session-user-DgKbYrlj.mjs +51 -0
- package/dist/session-user-DgKbYrlj.mjs.map +1 -0
- package/dist/settings-CNPUntkh.mjs +51 -0
- package/dist/settings-CNPUntkh.mjs.map +1 -0
- package/dist/settings-D5EHi0Tk.mjs +439 -0
- package/dist/settings-D5EHi0Tk.mjs.map +1 -0
- package/dist/settings-DSfE7wOa.mjs +61 -0
- package/dist/settings-DSfE7wOa.mjs.map +1 -0
- package/dist/setup-complete-B8W8sJ9v.mjs +26 -0
- package/dist/setup-complete-B8W8sJ9v.mjs.map +1 -0
- package/dist/setup-nonce-DnSBP260.mjs +25 -0
- package/dist/setup-nonce-DnSBP260.mjs.map +1 -0
- package/dist/site-settings-NGzdrt7O.mjs +50 -0
- package/dist/site-settings-NGzdrt7O.mjs.map +1 -0
- package/dist/site-url-D6JB7tLW.mjs +16 -0
- package/dist/site-url-D6JB7tLW.mjs.map +1 -0
- package/dist/snapshot-CdcwwWAf.mjs +414 -0
- package/dist/snapshot-CdcwwWAf.mjs.map +1 -0
- package/dist/ssrf-Dv0_tRpo.mjs +406 -0
- package/dist/ssrf-Dv0_tRpo.mjs.map +1 -0
- package/dist/stage-CUjhED3P.mjs +662 -0
- package/dist/stage-CUjhED3P.mjs.map +1 -0
- package/dist/staged-C36IWXff.mjs +659 -0
- package/dist/staged-C36IWXff.mjs.map +1 -0
- package/dist/state-CKouMCSY.mjs +153 -0
- package/dist/state-CKouMCSY.mjs.map +1 -0
- package/dist/status-lzyj4Uu7.mjs +30 -0
- package/dist/status-lzyj4Uu7.mjs.map +1 -0
- package/dist/storage/local.d.mts +1 -1
- package/dist/storage/local.mjs +1 -1
- package/dist/storage/s3.d.mts +1 -1
- package/dist/storage/s3.mjs +1 -1
- package/dist/storage-query-B-cWcTjJ.d.mts +1594 -0
- package/dist/storage-query-B-cWcTjJ.d.mts.map +1 -0
- package/dist/tar-DsTXX6ch.mjs +449 -0
- package/dist/tar-DsTXX6ch.mjs.map +1 -0
- package/dist/target-DLQCwp_Z.mjs +27 -0
- package/dist/target-DLQCwp_Z.mjs.map +1 -0
- package/dist/taxonomies-BlAjr4BL.mjs +697 -0
- package/dist/taxonomies-BlAjr4BL.mjs.map +1 -0
- package/dist/taxonomies-Byyo7LOZ.mjs +939 -0
- package/dist/taxonomies-Byyo7LOZ.mjs.map +1 -0
- package/dist/taxonomy-CKDwM61Y.mjs +525 -0
- package/dist/taxonomy-CKDwM61Y.mjs.map +1 -0
- package/dist/tokens-BojXlk49.mjs +171 -0
- package/dist/tokens-BojXlk49.mjs.map +1 -0
- package/dist/transaction-DLPQWik1.mjs +29 -0
- package/dist/transaction-DLPQWik1.mjs.map +1 -0
- package/dist/transfer-XSTh2BCr.mjs +8706 -0
- package/dist/transfer-XSTh2BCr.mjs.map +1 -0
- package/dist/transfer-download-DkoCDA9d.mjs +33 -0
- package/dist/transfer-download-DkoCDA9d.mjs.map +1 -0
- package/dist/transfer-iQ26J-RT.mjs +166 -0
- package/dist/transfer-iQ26J-RT.mjs.map +1 -0
- package/dist/transformations-C7RQabKQ.mjs +196 -0
- package/dist/transformations-C7RQabKQ.mjs.map +1 -0
- package/dist/transport-D3RulfD6.mjs +136 -0
- package/dist/transport-D3RulfD6.mjs.map +1 -0
- package/dist/transport-DhlZlf4D.d.mts +42 -0
- package/dist/transport-DhlZlf4D.d.mts.map +1 -0
- package/dist/trusted-proxy-B6ECOZJc.mjs +51 -0
- package/dist/trusted-proxy-B6ECOZJc.mjs.map +1 -0
- package/dist/turnstile-lqUiY7lP.mjs +53 -0
- package/dist/turnstile-lqUiY7lP.mjs.map +1 -0
- package/dist/types-4Dn9bZhu.mjs +77 -0
- package/dist/types-4Dn9bZhu.mjs.map +1 -0
- package/dist/types-5LSo7PPx.d.mts +85 -0
- package/dist/types-5LSo7PPx.d.mts.map +1 -0
- package/dist/types-BQ3hwYJT.d.mts +896 -0
- package/dist/types-BQ3hwYJT.d.mts.map +1 -0
- package/dist/types-BYEk7qo3.d.mts +198 -0
- package/dist/types-BYEk7qo3.d.mts.map +1 -0
- package/dist/types-CJKsWVFR.mjs +199 -0
- package/dist/types-CJKsWVFR.mjs.map +1 -0
- package/dist/types-Ca_w8mmY.d.mts +363 -0
- package/dist/types-Ca_w8mmY.d.mts.map +1 -0
- package/dist/types-CkE41ZAG.mjs +18 -0
- package/dist/types-CkE41ZAG.mjs.map +1 -0
- package/dist/types-D0aJW2uR.d.mts +1641 -0
- package/dist/types-D0aJW2uR.d.mts.map +1 -0
- package/dist/types-DbpN4Qto.d.mts +372 -0
- package/dist/types-DbpN4Qto.d.mts.map +1 -0
- package/dist/types-ILDI1sdY.mjs +16 -0
- package/dist/types-ILDI1sdY.mjs.map +1 -0
- package/dist/types-OC5c-edM.mjs +22 -0
- package/dist/types-OC5c-edM.mjs.map +1 -0
- package/dist/types-aOOxRSx6.mjs +103 -0
- package/dist/types-aOOxRSx6.mjs.map +1 -0
- package/dist/types-m1WbUffD.d.mts +198 -0
- package/dist/types-m1WbUffD.d.mts.map +1 -0
- package/dist/types-uxLoPBio.d.mts +124 -0
- package/dist/types-uxLoPBio.d.mts.map +1 -0
- package/dist/types-we5uR-tV.d.mts +287 -0
- package/dist/types-we5uR-tV.d.mts.map +1 -0
- package/dist/upload-attempts-DduMy6B0.mjs +32 -0
- package/dist/upload-attempts-DduMy6B0.mjs.map +1 -0
- package/dist/url-pattern-B3EwxAAk.mjs +33 -0
- package/dist/url-pattern-B3EwxAAk.mjs.map +1 -0
- package/dist/user-ElwQjTQT.mjs +171 -0
- package/dist/user-ElwQjTQT.mjs.map +1 -0
- package/dist/utils-BlAXmfOG.mjs +439 -0
- package/dist/utils-BlAXmfOG.mjs.map +1 -0
- package/dist/validate-CH0X5b2c.d.mts +468 -0
- package/dist/validate-CH0X5b2c.d.mts.map +1 -0
- package/dist/validate-CfgRpcjA.mjs +492 -0
- package/dist/validate-CfgRpcjA.mjs.map +1 -0
- package/dist/validation-DvYJtv4k.mjs +218 -0
- package/dist/validation-DvYJtv4k.mjs.map +1 -0
- package/dist/version-DgYjhTud.mjs +9 -0
- package/dist/version-DgYjhTud.mjs.map +1 -0
- package/dist/version-Dq71scUb.mjs +7 -0
- package/dist/version-Dq71scUb.mjs.map +1 -0
- package/dist/widgets-ChFIj0be.mjs +126 -0
- package/dist/widgets-ChFIj0be.mjs.map +1 -0
- package/dist/wxr-taxonomies-CBZMp2YX.mjs +372 -0
- package/dist/wxr-taxonomies-CBZMp2YX.mjs.map +1 -0
- package/dist/wxr-taxonomies-DlKDpWN1.d.mts +34 -0
- package/dist/wxr-taxonomies-DlKDpWN1.d.mts.map +1 -0
- package/dist/zod-generator-DmTKI-Ig.mjs +426 -0
- package/dist/zod-generator-DmTKI-Ig.mjs.map +1 -0
- package/package.json +7 -6
- package/src/api/handlers/content.ts +593 -16
- package/src/api/handlers/device-flow.ts +74 -21
- package/src/api/handlers/manifest.ts +79 -5
- package/src/api/handlers/relations.ts +638 -157
- package/src/api/handlers/revision.ts +30 -0
- package/src/api/handlers/schema.ts +403 -1
- package/src/api/handlers/staged-references.ts +142 -0
- package/src/api/handlers/validate-references.ts +146 -0
- package/src/api/schemas/content.ts +13 -0
- package/src/api/schemas/relations.ts +54 -44
- package/src/api/schemas/schema.ts +14 -0
- package/src/astro/integration/routes.ts +15 -19
- package/src/astro/routes/api/content/[collection]/[id]/references/[relation]/children.ts +11 -54
- package/src/astro/routes/api/content/[collection]/[id].ts +3 -1
- package/src/astro/routes/api/oauth/device/authorize.ts +33 -4
- package/src/astro/routes/api/relations/index.ts +4 -4
- package/src/astro/routes/api/schema/collections/[slug]/fields/[fieldSlug].ts +6 -2
- package/src/astro/types.ts +5 -0
- package/src/cli/commands/export-seed.ts +510 -89
- package/src/components/WidgetArea.astro +3 -2
- package/src/database/migrations/086_relations_structural.ts +197 -0
- package/src/database/migrations/087_reference_field_relations.ts +407 -0
- package/src/database/migrations/runner.ts +4 -0
- package/src/database/reference-backfill.ts +141 -0
- package/src/database/repositories/content.ts +43 -8
- package/src/database/repositories/relation.ts +620 -208
- package/src/database/repositories/revision.ts +16 -0
- package/src/database/repositories/types.ts +38 -0
- package/src/database/transaction.ts +12 -1
- package/src/database/types.ts +14 -5
- package/src/emdash-runtime.ts +86 -11
- package/src/index.ts +10 -0
- package/src/loader.ts +169 -22
- package/src/query.ts +455 -25
- package/src/references/field-map.ts +115 -0
- package/src/references/resolve.ts +160 -0
- package/src/references/staged.ts +117 -0
- package/src/references/types.ts +16 -0
- package/src/registry/artifact-fetch.ts +45 -271
- package/src/schema/registry.ts +99 -24
- package/src/schema/types.ts +58 -0
- package/src/schema/zod-generator.ts +67 -1
- package/src/seed/apply.ts +519 -62
- package/src/seed/types.ts +36 -2
- package/src/seed/validate.ts +78 -2
- package/src/transfer/analyze/unique-keys.ts +3 -12
- package/src/transfer/analyze/validate.ts +65 -39
- package/src/transfer/analyze/values.ts +12 -1
- package/src/transfer/export/readers.ts +12 -8
- package/src/transfer/format/columns.ts +26 -6
- package/src/transfer/format/kinds.ts +21 -5
- package/src/transfer/import/context.ts +8 -1
- package/src/transfer/ops/package-index.ts +1 -1
- package/dist/action-token-DYwe4Pk0.mjs +0 -26
- package/dist/action-token-DYwe4Pk0.mjs.map +0 -1
- package/dist/activation-LOkDM5WT.mjs +0 -382
- package/dist/activation-LOkDM5WT.mjs.map +0 -1
- package/dist/adapters-B64LbYcB.d.mts +0 -171
- package/dist/adapters-B64LbYcB.d.mts.map +0 -1
- package/dist/allowed-origins-CHB8oZNM.mjs +0 -116
- package/dist/allowed-origins-CHB8oZNM.mjs.map +0 -1
- package/dist/api-CuyNEHZG.mjs +0 -4718
- package/dist/api-CuyNEHZG.mjs.map +0 -1
- package/dist/api-tokens-s4i4aUp_.mjs +0 -166
- package/dist/api-tokens-s4i4aUp_.mjs.map +0 -1
- package/dist/apply-npY1TAhG.mjs +0 -1366
- package/dist/apply-npY1TAhG.mjs.map +0 -1
- package/dist/approvals-CqMfNxak.mjs +0 -460
- package/dist/approvals-CqMfNxak.mjs.map +0 -1
- package/dist/artifact-fetch-DZMOGZ3-.mjs +0 -818
- package/dist/artifact-fetch-DZMOGZ3-.mjs.map +0 -1
- package/dist/astro/routes/api/relations/_id_/translations.d.mts +0 -8
- package/dist/astro/routes/api/relations/_id_/translations.d.mts.map +0 -1
- package/dist/astro/routes/api/relations/_id_/translations.mjs +0 -47
- package/dist/astro/routes/api/relations/_id_/translations.mjs.map +0 -1
- package/dist/audit-RfCugiSB.mjs +0 -127
- package/dist/audit-RfCugiSB.mjs.map +0 -1
- package/dist/authoritative-records-CoJvBXAD.mjs +0 -5172
- package/dist/authoritative-records-CoJvBXAD.mjs.map +0 -1
- package/dist/authorize-seCifOMJ.mjs +0 -49
- package/dist/authorize-seCifOMJ.mjs.map +0 -1
- package/dist/backup-BQRj3afm.mjs +0 -246
- package/dist/backup-BQRj3afm.mjs.map +0 -1
- package/dist/block-type-registry-DUI_3KxT.mjs +0 -6709
- package/dist/block-type-registry-DUI_3KxT.mjs.map +0 -1
- package/dist/block-types-BmZmLmAD.mjs +0 -132
- package/dist/block-types-BmZmLmAD.mjs.map +0 -1
- package/dist/block-values-C_VIPr5t.mjs +0 -175
- package/dist/block-values-C_VIPr5t.mjs.map +0 -1
- package/dist/byline-DYmkXqvo.mjs +0 -909
- package/dist/byline-DYmkXqvo.mjs.map +0 -1
- package/dist/byline-fields-D28AT-Fh.mjs +0 -123
- package/dist/byline-fields-D28AT-Fh.mjs.map +0 -1
- package/dist/byline-registry-gnKscbQX.mjs +0 -406
- package/dist/byline-registry-gnKscbQX.mjs.map +0 -1
- package/dist/bylines-BPwJqoYH.mjs +0 -232
- package/dist/bylines-BPwJqoYH.mjs.map +0 -1
- package/dist/bylines-ukLaYpVZ.mjs +0 -214
- package/dist/bylines-ukLaYpVZ.mjs.map +0 -1
- package/dist/cache-m7UEkRFV.mjs +0 -108
- package/dist/cache-m7UEkRFV.mjs.map +0 -1
- package/dist/canonical-YhEQezjg.mjs +0 -174
- package/dist/canonical-YhEQezjg.mjs.map +0 -1
- package/dist/capture-triggers-kJyl_yyM.mjs +0 -362
- package/dist/capture-triggers-kJyl_yyM.mjs.map +0 -1
- package/dist/challenge-store-ppU6Uv13.mjs +0 -51
- package/dist/challenge-store-ppU6Uv13.mjs.map +0 -1
- package/dist/checksum-B2IINIlN.mjs +0 -162
- package/dist/checksum-B2IINIlN.mjs.map +0 -1
- package/dist/chrome-tags-DApCQSIk.mjs +0 -24
- package/dist/chrome-tags-DApCQSIk.mjs.map +0 -1
- package/dist/chunks-Dms7Uxbt.mjs +0 -25
- package/dist/chunks-Dms7Uxbt.mjs.map +0 -1
- package/dist/collection-deletion-BIm28mo3.mjs +0 -436
- package/dist/collection-deletion-BIm28mo3.mjs.map +0 -1
- package/dist/collection-deletion-processor-Br6rxs3u.mjs +0 -217
- package/dist/collection-deletion-processor-Br6rxs3u.mjs.map +0 -1
- package/dist/collection-slugs-cache-CjGk__zp.mjs +0 -85
- package/dist/collection-slugs-cache-CjGk__zp.mjs.map +0 -1
- package/dist/comment-CrBl22OF.mjs +0 -313
- package/dist/comment-CrBl22OF.mjs.map +0 -1
- package/dist/comment-reaction-JEQ2Fpd8.mjs +0 -85
- package/dist/comment-reaction-JEQ2Fpd8.mjs.map +0 -1
- package/dist/comments-2ah9du9y.mjs +0 -195
- package/dist/comments-2ah9du9y.mjs.map +0 -1
- package/dist/comments-fHZ8ON9O.mjs +0 -99
- package/dist/comments-fHZ8ON9O.mjs.map +0 -1
- package/dist/components-CXbq7CSM.mjs +0 -108
- package/dist/components-CXbq7CSM.mjs.map +0 -1
- package/dist/config-BjEm_3xL.d.mts +0 -6537
- package/dist/config-BjEm_3xL.d.mts.map +0 -1
- package/dist/config-IhybvkIQ.mjs +0 -242
- package/dist/config-IhybvkIQ.mjs.map +0 -1
- package/dist/config-Py43JK9r.d.mts +0 -39
- package/dist/config-Py43JK9r.d.mts.map +0 -1
- package/dist/content-DFaIEDj9.mjs +0 -2281
- package/dist/content-DFaIEDj9.mjs.map +0 -1
- package/dist/content-list-query-Dra4Dalc.d.mts +0 -26
- package/dist/content-list-query-Dra4Dalc.d.mts.map +0 -1
- package/dist/content-policy-DFNw91-d.mjs +0 -46
- package/dist/content-policy-DFNw91-d.mjs.map +0 -1
- package/dist/content-repair-Q8IUrpLL.mjs +0 -442
- package/dist/content-repair-Q8IUrpLL.mjs.map +0 -1
- package/dist/context-BV_7t-Ua.mjs +0 -1921
- package/dist/context-BV_7t-Ua.mjs.map +0 -1
- package/dist/cron-7DCJwPXq.mjs +0 -284
- package/dist/cron-7DCJwPXq.mjs.map +0 -1
- package/dist/dashboard-BP-iJqpd.mjs +0 -151
- package/dist/dashboard-BP-iJqpd.mjs.map +0 -1
- package/dist/default-DQ6vsviu.mjs +0 -81
- package/dist/default-DQ6vsviu.mjs.map +0 -1
- package/dist/deferred-tasks-BPxXUB4x.d.mts +0 -9
- package/dist/deferred-tasks-BPxXUB4x.d.mts.map +0 -1
- package/dist/dev-typegen-CZaPLl3V.mjs +0 -29
- package/dist/dev-typegen-CZaPLl3V.mjs.map +0 -1
- package/dist/device-flow-CRd6DXmW.mjs +0 -466
- package/dist/device-flow-CRd6DXmW.mjs.map +0 -1
- package/dist/digest-BarSh-pN.mjs +0 -194
- package/dist/digest-BarSh-pN.mjs.map +0 -1
- package/dist/direct-executor-D2lNadwo.mjs +0 -104
- package/dist/direct-executor-D2lNadwo.mjs.map +0 -1
- package/dist/dist-BNwANFJR.mjs +0 -810
- package/dist/dist-BNwANFJR.mjs.map +0 -1
- package/dist/email-console-bJn3ctqA.mjs +0 -50
- package/dist/email-console-bJn3ctqA.mjs.map +0 -1
- package/dist/email-locale-CN6WAMx0.mjs +0 -25
- package/dist/email-locale-CN6WAMx0.mjs.map +0 -1
- package/dist/emdash-runtime-CtfnZmPi.mjs +0 -4186
- package/dist/emdash-runtime-CtfnZmPi.mjs.map +0 -1
- package/dist/enrich-Dl3kZ-lP.mjs +0 -194
- package/dist/enrich-Dl3kZ-lP.mjs.map +0 -1
- package/dist/entry-lock-BJYdBfXb.mjs +0 -1097
- package/dist/entry-lock-BJYdBfXb.mjs.map +0 -1
- package/dist/entry-lock-Cf5OoIgN.d.mts +0 -4368
- package/dist/entry-lock-Cf5OoIgN.d.mts.map +0 -1
- package/dist/entry-lock-DHQOxN7R.mjs +0 -163
- package/dist/entry-lock-DHQOxN7R.mjs.map +0 -1
- package/dist/entry-locks-D0foLdjQ.mjs +0 -167
- package/dist/entry-locks-D0foLdjQ.mjs.map +0 -1
- package/dist/error-CfvOHP0M.mjs +0 -90
- package/dist/error-CfvOHP0M.mjs.map +0 -1
- package/dist/errors-BF0_LFhW.mjs +0 -460
- package/dist/errors-BF0_LFhW.mjs.map +0 -1
- package/dist/errors-DgE1zJGG.mjs +0 -120
- package/dist/errors-DgE1zJGG.mjs.map +0 -1
- package/dist/escape-CuaZhZvL.mjs +0 -9
- package/dist/escape-CuaZhZvL.mjs.map +0 -1
- package/dist/fence-CMDXJYc_.mjs +0 -162
- package/dist/fence-CMDXJYc_.mjs.map +0 -1
- package/dist/field-defs-cache-HIgBbqZZ.mjs +0 -77
- package/dist/field-defs-cache-HIgBbqZZ.mjs.map +0 -1
- package/dist/focal-point-Gr34o-4o.mjs +0 -23
- package/dist/focal-point-Gr34o-4o.mjs.map +0 -1
- package/dist/fts-manager-S-K0laoS.mjs +0 -443
- package/dist/fts-manager-S-K0laoS.mjs.map +0 -1
- package/dist/gc-DjKY0Ay1.mjs +0 -75
- package/dist/gc-DjKY0Ay1.mjs.map +0 -1
- package/dist/hash-SDAW6zC-.mjs +0 -37
- package/dist/hash-SDAW6zC-.mjs.map +0 -1
- package/dist/hook-result-B5bXDgS2.d.mts +0 -31
- package/dist/hook-result-B5bXDgS2.d.mts.map +0 -1
- package/dist/hreflang-CbVI4paR.mjs +0 -105
- package/dist/hreflang-CbVI4paR.mjs.map +0 -1
- package/dist/hreflang-D5uNnsGJ.d.mts +0 -50
- package/dist/hreflang-D5uNnsGJ.d.mts.map +0 -1
- package/dist/http-route-dispatch-BitqzwMy.mjs +0 -339
- package/dist/http-route-dispatch-BitqzwMy.mjs.map +0 -1
- package/dist/identity-Be5kzutJ.mjs +0 -35
- package/dist/identity-Be5kzutJ.mjs.map +0 -1
- package/dist/import-YzfKCaco.mjs +0 -2020
- package/dist/import-YzfKCaco.mjs.map +0 -1
- package/dist/index-D-hdtLe8.d.mts +0 -623
- package/dist/index-D-hdtLe8.d.mts.map +0 -1
- package/dist/install-finalization-DfM1fj5x.mjs +0 -58
- package/dist/install-finalization-DfM1fj5x.mjs.map +0 -1
- package/dist/keys-yxLm5l35.mjs +0 -61
- package/dist/keys-yxLm5l35.mjs.map +0 -1
- package/dist/kinds-CRu_T5T5.mjs +0 -961
- package/dist/kinds-CRu_T5T5.mjs.map +0 -1
- package/dist/lifecycle-BzeGPeQ-.mjs +0 -25
- package/dist/lifecycle-BzeGPeQ-.mjs.map +0 -1
- package/dist/load-XgJiE6_3.mjs +0 -28
- package/dist/load-XgJiE6_3.mjs.map +0 -1
- package/dist/loader-BzqeR1ZN.mjs +0 -1086
- package/dist/loader-BzqeR1ZN.mjs.map +0 -1
- package/dist/loops-BQSzv5Zn.mjs +0 -203
- package/dist/loops-BQSzv5Zn.mjs.map +0 -1
- package/dist/manifest-builder-BmSAOOEF.mjs +0 -189
- package/dist/manifest-builder-BmSAOOEF.mjs.map +0 -1
- package/dist/manifest-schema-CY3zng_M.mjs +0 -492
- package/dist/manifest-schema-CY3zng_M.mjs.map +0 -1
- package/dist/media-CPXTbb1R.mjs +0 -373
- package/dist/media-CPXTbb1R.mjs.map +0 -1
- package/dist/media-JXRWDhw3.mjs +0 -294
- package/dist/media-JXRWDhw3.mjs.map +0 -1
- package/dist/media-Pu1L6xir.mjs +0 -408
- package/dist/media-Pu1L6xir.mjs.map +0 -1
- package/dist/media-allowlist-BSoa9Vvm.mjs +0 -44
- package/dist/media-allowlist-BSoa9Vvm.mjs.map +0 -1
- package/dist/media-folders-BE0oo2eX.mjs +0 -210
- package/dist/media-folders-BE0oo2eX.mjs.map +0 -1
- package/dist/media-url-jArBpzIG.mjs +0 -43
- package/dist/media-url-jArBpzIG.mjs.map +0 -1
- package/dist/media-usage-De-zeR9E.mjs +0 -1629
- package/dist/media-usage-De-zeR9E.mjs.map +0 -1
- package/dist/media-usage-activation-HKp7zk7W.mjs +0 -78
- package/dist/media-usage-activation-HKp7zk7W.mjs.map +0 -1
- package/dist/media-usage-work-C2OZLCAd.mjs +0 -586
- package/dist/media-usage-work-C2OZLCAd.mjs.map +0 -1
- package/dist/media-usage-work-DwUNbgvS.mjs +0 -152
- package/dist/media-usage-work-DwUNbgvS.mjs.map +0 -1
- package/dist/menus-BM7BPLOb.mjs +0 -139
- package/dist/menus-BM7BPLOb.mjs.map +0 -1
- package/dist/menus-Cm68rsAq.mjs +0 -3608
- package/dist/menus-Cm68rsAq.mjs.map +0 -1
- package/dist/menus-ITeAbcIF.mjs +0 -753
- package/dist/menus-ITeAbcIF.mjs.map +0 -1
- package/dist/mime-ChLqYwDk.mjs +0 -36
- package/dist/mime-ChLqYwDk.mjs.map +0 -1
- package/dist/mode-CCuKXUci.mjs +0 -23
- package/dist/mode-CCuKXUci.mjs.map +0 -1
- package/dist/node-sqlite-compat-CONMsl-x.mjs +0 -46
- package/dist/node-sqlite-compat-CONMsl-x.mjs.map +0 -1
- package/dist/normalize-CO2P8-iE.mjs +0 -191
- package/dist/normalize-CO2P8-iE.mjs.map +0 -1
- package/dist/oauth-authorization-DlMIL5_h.mjs +0 -274
- package/dist/oauth-authorization-DlMIL5_h.mjs.map +0 -1
- package/dist/oauth-clients-Djq9r_KP.mjs +0 -266
- package/dist/oauth-clients-Djq9r_KP.mjs.map +0 -1
- package/dist/oauth-state-store-BbjnZXNC.mjs +0 -50
- package/dist/oauth-state-store-BbjnZXNC.mjs.map +0 -1
- package/dist/oauth-user-lookup-vue9a64A.mjs +0 -26
- package/dist/oauth-user-lookup-vue9a64A.mjs.map +0 -1
- package/dist/options-SQCHQCPH.d.mts +0 -81
- package/dist/options-SQCHQCPH.d.mts.map +0 -1
- package/dist/parse-CVgO-Qai.d.mts +0 -168
- package/dist/parse-CVgO-Qai.d.mts.map +0 -1
- package/dist/parse-DY6OD1j_.mjs +0 -81
- package/dist/parse-DY6OD1j_.mjs.map +0 -1
- package/dist/passkey-config-X_H8128a.mjs +0 -46
- package/dist/passkey-config-X_H8128a.mjs.map +0 -1
- package/dist/paths-JxokKIbr.mjs +0 -77
- package/dist/paths-JxokKIbr.mjs.map +0 -1
- package/dist/patterns-BhAvqO0S.mjs +0 -145
- package/dist/patterns-BhAvqO0S.mjs.map +0 -1
- package/dist/placeholder-MSEd8gty.d.mts +0 -306
- package/dist/placeholder-MSEd8gty.d.mts.map +0 -1
- package/dist/plan-xjcWrAah.mjs +0 -135
- package/dist/plan-xjcWrAah.mjs.map +0 -1
- package/dist/plugins-DUXUt8B9.mjs +0 -277
- package/dist/plugins-DUXUt8B9.mjs.map +0 -1
- package/dist/policy-CUvwAARc.mjs +0 -45
- package/dist/policy-CUvwAARc.mjs.map +0 -1
- package/dist/portable-text-5O_ZGUjB.mjs +0 -307
- package/dist/portable-text-5O_ZGUjB.mjs.map +0 -1
- package/dist/preview-CIUcPYr6.mjs +0 -107
- package/dist/preview-CIUcPYr6.mjs.map +0 -1
- package/dist/protocol-B97DZaFr.d.mts +0 -61
- package/dist/protocol-B97DZaFr.d.mts.map +0 -1
- package/dist/public-submission-BFBUrqst.mjs +0 -250
- package/dist/public-submission-BFBUrqst.mjs.map +0 -1
- package/dist/public-url-Bn7U0D7-.mjs +0 -101
- package/dist/public-url-Bn7U0D7-.mjs.map +0 -1
- package/dist/query-B48peoRT.mjs +0 -890
- package/dist/query-B48peoRT.mjs.map +0 -1
- package/dist/query-C4IH0uhR.mjs +0 -41
- package/dist/query-C4IH0uhR.mjs.map +0 -1
- package/dist/rate-limit-BZ6nybgc.mjs +0 -120
- package/dist/rate-limit-BZ6nybgc.mjs.map +0 -1
- package/dist/receipt-B4wJj5Jq.mjs +0 -43
- package/dist/receipt-B4wJj5Jq.mjs.map +0 -1
- package/dist/redirect-B29UjdUn.mjs +0 -411
- package/dist/redirect-B29UjdUn.mjs.map +0 -1
- package/dist/redirect-Cd1E7VUt.mjs +0 -17
- package/dist/redirect-Cd1E7VUt.mjs.map +0 -1
- package/dist/redirects-Ca2MPfEG.mjs +0 -446
- package/dist/redirects-Ca2MPfEG.mjs.map +0 -1
- package/dist/redirects-Cv9apQKj.mjs +0 -148
- package/dist/redirects-Cv9apQKj.mjs.map +0 -1
- package/dist/relation-M4NUCb0b.mjs +0 -334
- package/dist/relation-M4NUCb0b.mjs.map +0 -1
- package/dist/relations-CCif47Oq.mjs +0 -403
- package/dist/relations-CCif47Oq.mjs.map +0 -1
- package/dist/relations-CK9CYUyr.mjs +0 -310
- package/dist/relations-CK9CYUyr.mjs.map +0 -1
- package/dist/request-cache-DzLYKm_x.mjs +0 -104
- package/dist/request-cache-DzLYKm_x.mjs.map +0 -1
- package/dist/request-meta-sZXt3sRo.mjs +0 -141
- package/dist/request-meta-sZXt3sRo.mjs.map +0 -1
- package/dist/resolve-2WbQsCvT.mjs +0 -199
- package/dist/resolve-2WbQsCvT.mjs.map +0 -1
- package/dist/route-wire--1hLuACz.mjs +0 -197
- package/dist/route-wire--1hLuACz.mjs.map +0 -1
- package/dist/routes-vrR95WR6.mjs +0 -272
- package/dist/routes-vrR95WR6.mjs.map +0 -1
- package/dist/runner-1y4J9fJB.mjs +0 -5742
- package/dist/runner-1y4J9fJB.mjs.map +0 -1
- package/dist/runner-D5_LzKXI.d.mts +0 -68
- package/dist/runner-D5_LzKXI.d.mts.map +0 -1
- package/dist/schema-BABiRdsH.mjs +0 -13
- package/dist/schema-BABiRdsH.mjs.map +0 -1
- package/dist/schema-Du3MzCG0.mjs +0 -446
- package/dist/schema-Du3MzCG0.mjs.map +0 -1
- package/dist/scopes-Dbk-ElhT.mjs +0 -34
- package/dist/scopes-Dbk-ElhT.mjs.map +0 -1
- package/dist/search-Bt1PL1jf.mjs +0 -448
- package/dist/search-Bt1PL1jf.mjs.map +0 -1
- package/dist/sections-Ddptx_o9.mjs +0 -346
- package/dist/sections-Ddptx_o9.mjs.map +0 -1
- package/dist/seo-CZT2oLtT.mjs +0 -114
- package/dist/seo-CZT2oLtT.mjs.map +0 -1
- package/dist/seo-D5w3-Azy.mjs +0 -133
- package/dist/seo-D5w3-Azy.mjs.map +0 -1
- package/dist/service-DuykXPyW.mjs +0 -150
- package/dist/service-DuykXPyW.mjs.map +0 -1
- package/dist/session-user-BhaVp8w0.mjs +0 -51
- package/dist/session-user-BhaVp8w0.mjs.map +0 -1
- package/dist/settings-B4vDl1fK.mjs +0 -439
- package/dist/settings-B4vDl1fK.mjs.map +0 -1
- package/dist/settings-DYidIB26.mjs +0 -61
- package/dist/settings-DYidIB26.mjs.map +0 -1
- package/dist/settings-Dyj6v8C4.mjs +0 -51
- package/dist/settings-Dyj6v8C4.mjs.map +0 -1
- package/dist/setup-complete-bOogcHWG.mjs +0 -26
- package/dist/setup-complete-bOogcHWG.mjs.map +0 -1
- package/dist/setup-nonce-0EGuKM4s.mjs +0 -25
- package/dist/setup-nonce-0EGuKM4s.mjs.map +0 -1
- package/dist/site-settings-DOgRUoFX.mjs +0 -50
- package/dist/site-settings-DOgRUoFX.mjs.map +0 -1
- package/dist/site-url-BU_bbxwj.mjs +0 -16
- package/dist/site-url-BU_bbxwj.mjs.map +0 -1
- package/dist/snapshot-PawoX-WG.mjs +0 -414
- package/dist/snapshot-PawoX-WG.mjs.map +0 -1
- package/dist/ssrf-CJUnJymJ.mjs +0 -406
- package/dist/ssrf-CJUnJymJ.mjs.map +0 -1
- package/dist/stage-DgrBz_du.mjs +0 -662
- package/dist/stage-DgrBz_du.mjs.map +0 -1
- package/dist/state-DDiPySSG.mjs +0 -153
- package/dist/state-DDiPySSG.mjs.map +0 -1
- package/dist/status-DZKIG4a9.mjs +0 -30
- package/dist/status-DZKIG4a9.mjs.map +0 -1
- package/dist/storage-query-FXJH5pI8.d.mts +0 -1581
- package/dist/storage-query-FXJH5pI8.d.mts.map +0 -1
- package/dist/tar-_1AgTYFu.mjs +0 -449
- package/dist/tar-_1AgTYFu.mjs.map +0 -1
- package/dist/target-_7pn2Gbg.mjs +0 -27
- package/dist/target-_7pn2Gbg.mjs.map +0 -1
- package/dist/taxonomies-C1IwNe8Q.mjs +0 -697
- package/dist/taxonomies-C1IwNe8Q.mjs.map +0 -1
- package/dist/taxonomies-C_XMoRcX.mjs +0 -939
- package/dist/taxonomies-C_XMoRcX.mjs.map +0 -1
- package/dist/taxonomy-C3Fu1YeH.mjs +0 -525
- package/dist/taxonomy-C3Fu1YeH.mjs.map +0 -1
- package/dist/tokens-u78jETkX.mjs +0 -171
- package/dist/tokens-u78jETkX.mjs.map +0 -1
- package/dist/transaction-BcJO4Tmc.mjs +0 -29
- package/dist/transaction-BcJO4Tmc.mjs.map +0 -1
- package/dist/transfer-DIGvR9Af.mjs +0 -166
- package/dist/transfer-DIGvR9Af.mjs.map +0 -1
- package/dist/transfer-DgeCvHnj.mjs +0 -8675
- package/dist/transfer-DgeCvHnj.mjs.map +0 -1
- package/dist/transfer-download-Pml7RMio.mjs +0 -33
- package/dist/transfer-download-Pml7RMio.mjs.map +0 -1
- package/dist/transformations-9gfpwY65.mjs +0 -196
- package/dist/transformations-9gfpwY65.mjs.map +0 -1
- package/dist/transport-BIfH7_hx.d.mts +0 -42
- package/dist/transport-BIfH7_hx.d.mts.map +0 -1
- package/dist/transport-DKWIq53q.mjs +0 -136
- package/dist/transport-DKWIq53q.mjs.map +0 -1
- package/dist/trusted-proxy-tKiVtyTD.mjs +0 -51
- package/dist/trusted-proxy-tKiVtyTD.mjs.map +0 -1
- package/dist/turnstile-DpsoyOfg.mjs +0 -53
- package/dist/turnstile-DpsoyOfg.mjs.map +0 -1
- package/dist/types-B4sUC2p1.d.mts +0 -198
- package/dist/types-B4sUC2p1.d.mts.map +0 -1
- package/dist/types-B7Lmsh1E.d.mts +0 -887
- package/dist/types-B7Lmsh1E.d.mts.map +0 -1
- package/dist/types-BZakh7Ym.mjs +0 -22
- package/dist/types-BZakh7Ym.mjs.map +0 -1
- package/dist/types-B_CppEmv.d.mts +0 -264
- package/dist/types-B_CppEmv.d.mts.map +0 -1
- package/dist/types-BcrBrE6-.mjs +0 -159
- package/dist/types-BcrBrE6-.mjs.map +0 -1
- package/dist/types-BkUg2yHx.mjs +0 -92
- package/dist/types-BkUg2yHx.mjs.map +0 -1
- package/dist/types-CAZgq9fO.d.mts +0 -124
- package/dist/types-CAZgq9fO.d.mts.map +0 -1
- package/dist/types-Cd-O03VG.d.mts +0 -363
- package/dist/types-Cd-O03VG.d.mts.map +0 -1
- package/dist/types-Cr-Kg-3D.d.mts +0 -1641
- package/dist/types-Cr-Kg-3D.d.mts.map +0 -1
- package/dist/types-D2fvWd1i.d.mts +0 -359
- package/dist/types-D2fvWd1i.d.mts.map +0 -1
- package/dist/types-D7HUsguf.mjs +0 -77
- package/dist/types-D7HUsguf.mjs.map +0 -1
- package/dist/types-DA1Te3Oy.d.mts +0 -198
- package/dist/types-DA1Te3Oy.d.mts.map +0 -1
- package/dist/types-DhV6Q5bP.mjs +0 -18
- package/dist/types-DhV6Q5bP.mjs.map +0 -1
- package/dist/types-DnnVSl6Y.d.mts +0 -85
- package/dist/types-DnnVSl6Y.d.mts.map +0 -1
- package/dist/types-VT4-BugW.mjs +0 -16
- package/dist/types-VT4-BugW.mjs.map +0 -1
- package/dist/upload-attempts-B68ZGNu9.mjs +0 -32
- package/dist/upload-attempts-B68ZGNu9.mjs.map +0 -1
- package/dist/url-pattern-CCeZMGOh.mjs +0 -33
- package/dist/url-pattern-CCeZMGOh.mjs.map +0 -1
- package/dist/user-DDSL-sGw.mjs +0 -171
- package/dist/user-DDSL-sGw.mjs.map +0 -1
- package/dist/utils-DdhmO9w9.mjs +0 -439
- package/dist/utils-DdhmO9w9.mjs.map +0 -1
- package/dist/validate-CHosPEhs.mjs +0 -453
- package/dist/validate-CHosPEhs.mjs.map +0 -1
- package/dist/validate-CM79QXYE.d.mts +0 -432
- package/dist/validate-CM79QXYE.d.mts.map +0 -1
- package/dist/validation-BFecQczG.mjs +0 -218
- package/dist/validation-BFecQczG.mjs.map +0 -1
- package/dist/version-BRZXVifl.mjs +0 -9
- package/dist/version-BRZXVifl.mjs.map +0 -1
- package/dist/version-DXsxRrob.mjs +0 -7
- package/dist/version-DXsxRrob.mjs.map +0 -1
- package/dist/widgets-WdV72brA.mjs +0 -126
- package/dist/widgets-WdV72brA.mjs.map +0 -1
- package/dist/wxr-taxonomies-BHTdqkmZ.d.mts +0 -34
- package/dist/wxr-taxonomies-BHTdqkmZ.d.mts.map +0 -1
- package/dist/wxr-taxonomies-DP6ESgMN.mjs +0 -372
- package/dist/wxr-taxonomies-DP6ESgMN.mjs.map +0 -1
- package/dist/zod-generator-D6uE4WiS.mjs +0 -389
- package/dist/zod-generator-D6uE4WiS.mjs.map +0 -1
- package/src/astro/routes/api/relations/[id]/translations.ts +0 -33
- /package/dist/{api-tokens-CE1ECIg0.mjs → api-tokens-FaG1zPsj.mjs} +0 -0
- /package/dist/{ssrf-DpBH7aOt.mjs → ssrf-DZOt8Qof.mjs} +0 -0
|
@@ -1,1629 +0,0 @@
|
|
|
1
|
-
import { u as __exportAll } from "./runner-1y4J9fJB.mjs";
|
|
2
|
-
import { t as validateIdentifier } from "./validate-DANX1-Qi.mjs";
|
|
3
|
-
import { u as isPostgres } from "./dialect-helpers-7_IqPdh9.mjs";
|
|
4
|
-
import { getRequestContext } from "./request-context.mjs";
|
|
5
|
-
import { i as InvalidCursorError } from "./types-BkUg2yHx.mjs";
|
|
6
|
-
import { t as withTransaction } from "./transaction-BcJO4Tmc.mjs";
|
|
7
|
-
import { t as MediaRepository } from "./media-CPXTbb1R.mjs";
|
|
8
|
-
import { a as continueMediaUsageActivation, n as MediaUsageActivationVersionMismatchError, s as getMediaUsageActivationStatus, t as MEDIA_USAGE_ACTIVATION_RUNTIME_GENERATION } from "./activation-LOkDM5WT.mjs";
|
|
9
|
-
import { B as CONTENT_MEDIA_USAGE_ADAPTER_ID, D as contentRefreshKey, G as jsonTextValues, K as CONTENT_SOURCE_SCHEMA_VERSION, R as buildContentMediaUsageFieldFingerprint, V as CONTENT_MEDIA_USAGE_COLLECTION_SCOPE, W as MediaUsageRepository, j as refreshContentMediaUsageForWorkBatch, z as loadContentMediaUsageFields } from "./block-type-registry-DUI_3KxT.mjs";
|
|
10
|
-
import { t as MediaUsageWorkRepository } from "./media-usage-work-C2OZLCAd.mjs";
|
|
11
|
-
import { n as repairContentMediaUsageCollection, t as repairContentMediaUsageAll } from "./content-repair-Q8IUrpLL.mjs";
|
|
12
|
-
import { t as processDueMediaUsageCollectionDeletions } from "./collection-deletion-processor-Br6rxs3u.mjs";
|
|
13
|
-
import { n as MEDIA_USAGE_SITE_SETTING_OPTIONS, r as groupSiteSettingMediaUsage } from "./site-settings-DOgRUoFX.mjs";
|
|
14
|
-
import { t as ErrorCode } from "./errors-BF0_LFhW.mjs";
|
|
15
|
-
import { sql } from "kysely";
|
|
16
|
-
import { ulid } from "ulidx";
|
|
17
|
-
|
|
18
|
-
//#region src/media/usage/reconciliation.ts
|
|
19
|
-
const ACTIVATION_KEY = "incremental_capture";
|
|
20
|
-
const CONTENT_ADAPTER_ID = "content-media";
|
|
21
|
-
const COLLECTION_SCOPE = "collection";
|
|
22
|
-
const MAX_CANDIDATES = 100;
|
|
23
|
-
const MAX_PORTABLE_DURATION_SECONDS = 365 * 24 * 60 * 60;
|
|
24
|
-
const STABLE_ERROR_CODE_PATTERN = /^[A-Z][A-Z0-9_]{0,63}$/;
|
|
25
|
-
var MediaUsageReconciliationRepository = class {
|
|
26
|
-
constructor(db) {
|
|
27
|
-
this.db = db;
|
|
28
|
-
}
|
|
29
|
-
async findByIdentity(collectionId, runToken) {
|
|
30
|
-
assertIdentity({
|
|
31
|
-
collectionId,
|
|
32
|
-
runToken
|
|
33
|
-
});
|
|
34
|
-
const row = await this.db.selectFrom("_emdash_media_usage_reconciliations").selectAll().where("collection_id", "=", collectionId).where("run_token", "=", runToken).executeTakeFirst();
|
|
35
|
-
return row ? rowToRecord(row) : null;
|
|
36
|
-
}
|
|
37
|
-
async beginRun(claim) {
|
|
38
|
-
const now = timestampOffset(this.db, 0);
|
|
39
|
-
const sameRun = sql`status = 'running' AND cursor = ${claim.runToken}`;
|
|
40
|
-
return (await this.db.updateTable("_emdash_media_usage_index_status as status").set({
|
|
41
|
-
status: "running",
|
|
42
|
-
started_at: sql`CASE WHEN ${sameRun} THEN started_at ELSE ${now} END`,
|
|
43
|
-
completed_at: null,
|
|
44
|
-
cursor: claim.runToken,
|
|
45
|
-
indexed_source_count: 0,
|
|
46
|
-
failed_source_count: 0,
|
|
47
|
-
last_error_code: null,
|
|
48
|
-
change_epoch: sql`CASE WHEN ${sameRun} THEN change_epoch ELSE change_epoch + 1 END`,
|
|
49
|
-
reconciliation_required: 1,
|
|
50
|
-
updated_at: now
|
|
51
|
-
}).where("status.adapter_id", "=", CONTENT_ADAPTER_ID).where("status.scope_type", "=", COLLECTION_SCOPE).where("status.collection_id", "=", claim.collectionId).where("status.scope_key", "=", claim.collectionSlug).where("status.capture_state", "=", "active").where("status.reconciliation_required", "=", 1).where((eb) => eb.or([eb("status.status", "!=", "running"), eb("status.cursor", "=", claim.runToken)])).where(this.liveClaimExists(claim)).returning("change_epoch").executeTakeFirst())?.change_epoch ?? null;
|
|
52
|
-
}
|
|
53
|
-
async findScanUpperId(claim) {
|
|
54
|
-
const tableName = contentTableName(claim.collectionSlug);
|
|
55
|
-
return (await sql`
|
|
56
|
-
SELECT content.id
|
|
57
|
-
FROM ${sql.ref(tableName)} AS content
|
|
58
|
-
WHERE ${this.liveClaimExistsSql(claim)}
|
|
59
|
-
ORDER BY content.id DESC
|
|
60
|
-
LIMIT 1
|
|
61
|
-
`.execute(this.db)).rows[0]?.id ?? null;
|
|
62
|
-
}
|
|
63
|
-
async initializeScan(input) {
|
|
64
|
-
const result = await this.db.updateTable("_emdash_media_usage_reconciliations as reconciliation").set({
|
|
65
|
-
target_epoch: input.targetEpoch,
|
|
66
|
-
field_fingerprint: input.fieldFingerprint,
|
|
67
|
-
phase: "scan",
|
|
68
|
-
scan_cursor: null,
|
|
69
|
-
scan_upper_id: input.scanUpperId,
|
|
70
|
-
source_cursor: null,
|
|
71
|
-
source_upper_key: null,
|
|
72
|
-
attempt_count: 0,
|
|
73
|
-
last_error_code: null,
|
|
74
|
-
updated_at: timestampOffset(this.db, 0)
|
|
75
|
-
}).where("reconciliation.collection_id", "=", input.claim.collectionId).where("reconciliation.run_token", "=", input.claim.runToken).where("reconciliation.target_epoch", "is", null).where("reconciliation.state", "=", "leased").where("reconciliation.lease_token", "=", input.claim.leaseToken).where(liveLease(this.db)).where(this.statusOwnsRun(input.claim, input.targetEpoch)).executeTakeFirst();
|
|
76
|
-
return Number(result.numUpdatedRows ?? 0) === 1;
|
|
77
|
-
}
|
|
78
|
-
async findScanPage(reconciliation, limit) {
|
|
79
|
-
if (!Number.isSafeInteger(limit) || limit < 1 || limit > 1e3) throw new Error("Reconciliation scan page limit must be from 1 to 1000");
|
|
80
|
-
if (!reconciliation.leaseToken || reconciliation.targetEpoch === null) return [];
|
|
81
|
-
const tableName = contentTableName(reconciliation.collectionSlug);
|
|
82
|
-
const lowerBound = reconciliation.scanCursor ? sql`AND content.id > ${reconciliation.scanCursor}` : sql``;
|
|
83
|
-
const upperBound = reconciliation.scanUpperId ? sql`AND content.id <= ${reconciliation.scanUpperId}` : sql`AND 1 = 0`;
|
|
84
|
-
return (await sql`
|
|
85
|
-
SELECT content.id
|
|
86
|
-
FROM ${sql.ref(tableName)} AS content
|
|
87
|
-
WHERE 1 = 1
|
|
88
|
-
${lowerBound}
|
|
89
|
-
${upperBound}
|
|
90
|
-
AND ${this.liveClaimExistsSql(reconciliation)}
|
|
91
|
-
ORDER BY content.id ASC
|
|
92
|
-
LIMIT ${limit}
|
|
93
|
-
`.execute(this.db)).rows.map((row) => row.id);
|
|
94
|
-
}
|
|
95
|
-
async checkpointScan(input) {
|
|
96
|
-
let query = this.db.updateTable("_emdash_media_usage_reconciliations as reconciliation").set({
|
|
97
|
-
scan_cursor: input.nextCursor,
|
|
98
|
-
attempt_count: 0,
|
|
99
|
-
last_error_code: null,
|
|
100
|
-
updated_at: timestampOffset(this.db, 0)
|
|
101
|
-
}).where("reconciliation.collection_id", "=", input.claim.collectionId).where("reconciliation.run_token", "=", input.claim.runToken).where("reconciliation.target_epoch", "=", input.targetEpoch).where("reconciliation.state", "=", "leased").where("reconciliation.phase", "=", "scan").where("reconciliation.lease_token", "=", input.claim.leaseToken).where(liveLease(this.db)).where(this.statusOwnsRun(input.claim, input.targetEpoch));
|
|
102
|
-
query = input.previousCursor ? query.where("reconciliation.scan_cursor", "=", input.previousCursor) : query.where("reconciliation.scan_cursor", "is", null);
|
|
103
|
-
const result = await query.executeTakeFirst();
|
|
104
|
-
return Number(result.numUpdatedRows ?? 0) === 1;
|
|
105
|
-
}
|
|
106
|
-
async ownsRun(claim, targetEpoch) {
|
|
107
|
-
const result = await sql`
|
|
108
|
-
SELECT ${this.statusOwnsRun(claim, targetEpoch)} AS owned
|
|
109
|
-
`.execute(this.db);
|
|
110
|
-
return Boolean(result.rows[0]?.owned);
|
|
111
|
-
}
|
|
112
|
-
async restartRun(claim, previousEpoch) {
|
|
113
|
-
const now = timestampOffset(this.db, 0);
|
|
114
|
-
const interruptedRestart = sql`status = 'running'
|
|
115
|
-
AND cursor = ${claim.runToken}
|
|
116
|
-
AND change_epoch > ${previousEpoch}`;
|
|
117
|
-
return (await this.db.updateTable("_emdash_media_usage_index_status as status").set({
|
|
118
|
-
status: "running",
|
|
119
|
-
started_at: sql`CASE WHEN ${interruptedRestart} THEN started_at ELSE ${now} END`,
|
|
120
|
-
completed_at: null,
|
|
121
|
-
cursor: claim.runToken,
|
|
122
|
-
last_error_code: null,
|
|
123
|
-
change_epoch: sql`CASE WHEN ${interruptedRestart} THEN change_epoch ELSE change_epoch + 1 END`,
|
|
124
|
-
reconciliation_required: 1,
|
|
125
|
-
updated_at: now
|
|
126
|
-
}).where("status.adapter_id", "=", CONTENT_ADAPTER_ID).where("status.scope_type", "=", COLLECTION_SCOPE).where("status.collection_id", "=", claim.collectionId).where("status.scope_key", "=", claim.collectionSlug).where("status.capture_state", "=", "active").where("status.reconciliation_required", "=", 1).where((eb) => eb.or([eb("status.status", "!=", "running"), eb("status.cursor", "=", claim.runToken)])).where(this.liveClaimExists(claim)).returning("change_epoch").executeTakeFirst())?.change_epoch ?? null;
|
|
127
|
-
}
|
|
128
|
-
async restartScan(input) {
|
|
129
|
-
const result = await this.db.updateTable("_emdash_media_usage_reconciliations as reconciliation").set({
|
|
130
|
-
target_epoch: input.targetEpoch,
|
|
131
|
-
field_fingerprint: input.fieldFingerprint,
|
|
132
|
-
phase: "scan",
|
|
133
|
-
scan_cursor: null,
|
|
134
|
-
scan_upper_id: input.scanUpperId,
|
|
135
|
-
source_cursor: null,
|
|
136
|
-
source_upper_key: null,
|
|
137
|
-
attempt_count: 0,
|
|
138
|
-
next_attempt_at: timestampOffset(this.db, 0),
|
|
139
|
-
last_error_code: null,
|
|
140
|
-
updated_at: timestampOffset(this.db, 0)
|
|
141
|
-
}).where("reconciliation.collection_id", "=", input.claim.collectionId).where("reconciliation.run_token", "=", input.claim.runToken).where("reconciliation.target_epoch", "=", input.previousEpoch).where("reconciliation.state", "=", "leased").where("reconciliation.lease_token", "=", input.claim.leaseToken).where(liveLease(this.db)).where(this.statusOwnsRun(input.claim, input.targetEpoch)).executeTakeFirst();
|
|
142
|
-
return Number(result.numUpdatedRows ?? 0) === 1;
|
|
143
|
-
}
|
|
144
|
-
async findWorkBarrier(collectionId) {
|
|
145
|
-
if (!collectionId) throw new Error("Reconciliation work barrier requires a collection ID");
|
|
146
|
-
const failed = await this.db.selectFrom("_emdash_media_usage_work").select("last_error_code").where("collection_id", "=", collectionId).where("state", "=", "failed").orderBy("content_id").limit(1).executeTakeFirst();
|
|
147
|
-
if (failed) return {
|
|
148
|
-
state: "failed",
|
|
149
|
-
errorCode: failed.last_error_code ?? "MEDIA_USAGE_PROCESSING_FAILED"
|
|
150
|
-
};
|
|
151
|
-
return await this.db.selectFrom("_emdash_media_usage_work").select("content_id").where("collection_id", "=", collectionId).limit(1).executeTakeFirst() ? { state: "pending" } : { state: "empty" };
|
|
152
|
-
}
|
|
153
|
-
async findSourceUpperKey(claim, targetEpoch) {
|
|
154
|
-
return (await this.db.selectFrom("_emdash_media_usage_sources as source").select("source.source_key").where("source.source_type", "=", "content").where("source.collection_id", "=", claim.collectionId).where("source.identity_version", "=", 1).where(this.liveClaimExists(claim)).where(this.statusOwnsRun(claim, targetEpoch)).orderBy("source.source_key", "desc").limit(1).executeTakeFirst())?.source_key ?? null;
|
|
155
|
-
}
|
|
156
|
-
async transitionToSources(input) {
|
|
157
|
-
const result = await this.db.updateTable("_emdash_media_usage_reconciliations as reconciliation").set({
|
|
158
|
-
phase: "sources",
|
|
159
|
-
source_cursor: null,
|
|
160
|
-
source_upper_key: input.sourceUpperKey,
|
|
161
|
-
attempt_count: 0,
|
|
162
|
-
last_error_code: null,
|
|
163
|
-
updated_at: timestampOffset(this.db, 0)
|
|
164
|
-
}).where("reconciliation.collection_id", "=", input.claim.collectionId).where("reconciliation.run_token", "=", input.claim.runToken).where("reconciliation.target_epoch", "=", input.targetEpoch).where("reconciliation.field_fingerprint", "=", input.fieldFingerprint).where("reconciliation.state", "=", "leased").where("reconciliation.phase", "=", "scan").where("reconciliation.lease_token", "=", input.claim.leaseToken).where(liveLease(this.db)).where(this.statusOwnsRun(input.claim, input.targetEpoch)).where((eb) => eb.not(eb.exists(eb.selectFrom("_emdash_media_usage_work as work").select("work.content_id").where("work.collection_id", "=", input.claim.collectionId)))).executeTakeFirst();
|
|
165
|
-
return Number(result.numUpdatedRows ?? 0) === 1;
|
|
166
|
-
}
|
|
167
|
-
async findSourcePage(reconciliation, limit) {
|
|
168
|
-
if (!Number.isSafeInteger(limit) || limit < 1 || limit > 1e3) throw new Error("Reconciliation source page limit must be from 1 to 1000");
|
|
169
|
-
if (!reconciliation.leaseToken || reconciliation.targetEpoch === null) return [];
|
|
170
|
-
let query = this.db.selectFrom("_emdash_media_usage_sources as source").select([
|
|
171
|
-
"source.source_key",
|
|
172
|
-
"source.content_id",
|
|
173
|
-
"source.source_variant"
|
|
174
|
-
]).where("source.source_type", "=", "content").where("source.collection_id", "=", reconciliation.collectionId).where("source.identity_version", "=", 1).where(this.liveClaimExists(reconciliation)).where(this.statusOwnsRun(reconciliation, reconciliation.targetEpoch));
|
|
175
|
-
if (reconciliation.sourceCursor) query = query.where("source.source_key", ">", reconciliation.sourceCursor);
|
|
176
|
-
if (reconciliation.sourceUpperKey) query = query.where("source.source_key", "<=", reconciliation.sourceUpperKey);
|
|
177
|
-
else query = query.where(sql`1 = 0`);
|
|
178
|
-
return (await query.orderBy("source.source_key").limit(limit).execute()).map((row) => ({
|
|
179
|
-
sourceKey: row.source_key,
|
|
180
|
-
contentId: row.content_id,
|
|
181
|
-
sourceVariant: row.source_variant
|
|
182
|
-
}));
|
|
183
|
-
}
|
|
184
|
-
async findMissingContentIds(collectionSlug, contentIds) {
|
|
185
|
-
const unique = [...new Set(contentIds)];
|
|
186
|
-
if (unique.length === 0) return [];
|
|
187
|
-
if (unique.length > 1e3 || unique.some((contentId) => !contentId)) throw new Error("Reconciliation source page has invalid content identity");
|
|
188
|
-
const tableName = contentTableName(collectionSlug);
|
|
189
|
-
const existing = await sql`
|
|
190
|
-
WITH requested AS (${jsonTextValues(this.db, unique)})
|
|
191
|
-
SELECT content.id
|
|
192
|
-
FROM ${sql.ref(tableName)} AS content
|
|
193
|
-
INNER JOIN requested ON requested.value = content.id
|
|
194
|
-
`.execute(this.db);
|
|
195
|
-
const present = new Set(existing.rows.map((row) => row.id));
|
|
196
|
-
return unique.filter((contentId) => !present.has(contentId));
|
|
197
|
-
}
|
|
198
|
-
async checkpointSources(input) {
|
|
199
|
-
let query = this.db.updateTable("_emdash_media_usage_reconciliations as reconciliation").set({
|
|
200
|
-
source_cursor: input.nextCursor,
|
|
201
|
-
attempt_count: 0,
|
|
202
|
-
last_error_code: null,
|
|
203
|
-
updated_at: timestampOffset(this.db, 0)
|
|
204
|
-
}).where("reconciliation.collection_id", "=", input.claim.collectionId).where("reconciliation.run_token", "=", input.claim.runToken).where("reconciliation.target_epoch", "=", input.targetEpoch).where("reconciliation.state", "=", "leased").where("reconciliation.phase", "=", "sources").where("reconciliation.lease_token", "=", input.claim.leaseToken).where(liveLease(this.db)).where(this.statusOwnsRun(input.claim, input.targetEpoch));
|
|
205
|
-
query = input.previousCursor ? query.where("reconciliation.source_cursor", "=", input.previousCursor) : query.where("reconciliation.source_cursor", "is", null);
|
|
206
|
-
const result = await query.executeTakeFirst();
|
|
207
|
-
return Number(result.numUpdatedRows ?? 0) === 1;
|
|
208
|
-
}
|
|
209
|
-
async finishFailedCoverage(collectionId, runToken) {
|
|
210
|
-
assertIdentity({
|
|
211
|
-
collectionId,
|
|
212
|
-
runToken
|
|
213
|
-
});
|
|
214
|
-
const now = timestampOffset(this.db, 0);
|
|
215
|
-
const result = await this.db.updateTable("_emdash_media_usage_index_status as status").set({
|
|
216
|
-
status: sql`CASE WHEN EXISTS (
|
|
217
|
-
SELECT 1 FROM _emdash_media_usage_sources AS source
|
|
218
|
-
WHERE source.source_type = 'content'
|
|
219
|
-
AND source.collection_id = ${collectionId}
|
|
220
|
-
AND source.identity_version = 1
|
|
221
|
-
LIMIT 1
|
|
222
|
-
) THEN 'partial' ELSE 'failed' END`,
|
|
223
|
-
completed_at: null,
|
|
224
|
-
cursor: null,
|
|
225
|
-
last_error_code: sql`CASE WHEN (
|
|
226
|
-
SELECT reconciliation.last_error_code
|
|
227
|
-
FROM _emdash_media_usage_reconciliations AS reconciliation
|
|
228
|
-
WHERE reconciliation.collection_id = ${collectionId}
|
|
229
|
-
AND reconciliation.run_token = ${runToken}
|
|
230
|
-
) = 'MEDIA_USAGE_RECONCILIATION_ENTRY_FAILED'
|
|
231
|
-
THEN COALESCE(
|
|
232
|
-
(SELECT work.last_error_code
|
|
233
|
-
FROM _emdash_media_usage_work AS work
|
|
234
|
-
WHERE work.collection_id = ${collectionId} AND work.state = 'failed'
|
|
235
|
-
ORDER BY work.content_id LIMIT 1),
|
|
236
|
-
'MEDIA_USAGE_RECONCILIATION_ENTRY_FAILED'
|
|
237
|
-
)
|
|
238
|
-
ELSE (
|
|
239
|
-
SELECT reconciliation.last_error_code
|
|
240
|
-
FROM _emdash_media_usage_reconciliations AS reconciliation
|
|
241
|
-
WHERE reconciliation.collection_id = ${collectionId}
|
|
242
|
-
AND reconciliation.run_token = ${runToken}
|
|
243
|
-
) END`,
|
|
244
|
-
reconciliation_required: 1,
|
|
245
|
-
updated_at: now
|
|
246
|
-
}).where("status.adapter_id", "=", CONTENT_ADAPTER_ID).where("status.scope_type", "=", COLLECTION_SCOPE).where("status.collection_id", "=", collectionId).where("status.status", "=", "running").where("status.cursor", "=", runToken).where(sql`status.change_epoch = (
|
|
247
|
-
SELECT reconciliation.target_epoch
|
|
248
|
-
FROM _emdash_media_usage_reconciliations AS reconciliation
|
|
249
|
-
WHERE reconciliation.collection_id = ${collectionId}
|
|
250
|
-
AND reconciliation.run_token = ${runToken}
|
|
251
|
-
)`).where((eb) => eb.exists(eb.selectFrom("_emdash_media_usage_reconciliations as reconciliation").select("reconciliation.collection_id").where("reconciliation.collection_id", "=", collectionId).where("reconciliation.run_token", "=", runToken).where("reconciliation.state", "=", "failed"))).executeTakeFirst();
|
|
252
|
-
return Number(result.numUpdatedRows ?? 0) === 1;
|
|
253
|
-
}
|
|
254
|
-
async finalizeCoverage(input) {
|
|
255
|
-
const now = timestampOffset(this.db, 0);
|
|
256
|
-
const result = await this.db.updateTable("_emdash_media_usage_index_status as status").set({
|
|
257
|
-
status: "complete",
|
|
258
|
-
schema_version: input.schemaVersion,
|
|
259
|
-
completed_at: now,
|
|
260
|
-
cursor: null,
|
|
261
|
-
last_error_code: null,
|
|
262
|
-
reconciliation_required: 0,
|
|
263
|
-
updated_at: now
|
|
264
|
-
}).where("status.adapter_id", "=", CONTENT_ADAPTER_ID).where("status.scope_type", "=", COLLECTION_SCOPE).where("status.collection_id", "=", input.claim.collectionId).where("status.scope_key", "=", input.claim.collectionSlug).where("status.capture_state", "=", "active").where("status.reconciliation_required", "=", 1).where("status.status", "=", "running").where("status.cursor", "=", input.claim.runToken).where("status.change_epoch", "=", input.targetEpoch).where((eb) => eb.not(eb.exists(eb.selectFrom("_emdash_media_usage_work as work").select("work.content_id").where("work.collection_id", "=", input.claim.collectionId)))).where((eb) => eb.exists(eb.selectFrom("_emdash_media_usage_reconciliations as reconciliation").innerJoin("_emdash_collections as collection", (join) => join.onRef("collection.id", "=", "reconciliation.collection_id").onRef("collection.slug", "=", "reconciliation.collection_slug")).select("reconciliation.collection_id").where("reconciliation.collection_id", "=", input.claim.collectionId).where("reconciliation.run_token", "=", input.claim.runToken).where("reconciliation.target_epoch", "=", input.targetEpoch).where("reconciliation.field_fingerprint", "=", input.fieldFingerprint).where("reconciliation.state", "=", "leased").where("reconciliation.phase", "=", "sources").where("reconciliation.lease_token", "=", input.claim.leaseToken).where(liveLease(this.db, "reconciliation.lease_expires_at")).where((inner) => inner.not(inner.exists(inner.selectFrom("_emdash_media_usage_collection_deletions as deletion").select("deletion.collection_id").where("deletion.collection_id", "=", input.claim.collectionId)))))).where((eb) => eb.exists(eb.selectFrom("_emdash_media_usage_activation as activation").select("activation.task_key").where("activation.task_key", "=", ACTIVATION_KEY).where("activation.state", "=", "active"))).executeTakeFirst();
|
|
265
|
-
return Number(result.numUpdatedRows ?? 0) === 1;
|
|
266
|
-
}
|
|
267
|
-
async deleteFinalized(claim) {
|
|
268
|
-
const result = await this.db.deleteFrom("_emdash_media_usage_reconciliations as reconciliation").where("reconciliation.collection_id", "=", claim.collectionId).where("reconciliation.run_token", "=", claim.runToken).where("reconciliation.state", "=", "leased").where("reconciliation.lease_token", "=", claim.leaseToken).where((eb) => eb.exists(eb.selectFrom("_emdash_media_usage_index_status as status").select("status.collection_id").where("status.collection_id", "=", claim.collectionId).where("status.scope_key", "=", claim.collectionSlug).where("status.status", "=", "complete").where("status.reconciliation_required", "=", 0))).executeTakeFirst();
|
|
269
|
-
return Number(result.numDeletedRows ?? 0) === 1;
|
|
270
|
-
}
|
|
271
|
-
async deleteOneObsolete() {
|
|
272
|
-
return (await sql`
|
|
273
|
-
DELETE FROM _emdash_media_usage_reconciliations
|
|
274
|
-
WHERE (collection_id, run_token) IN (
|
|
275
|
-
SELECT reconciliation.collection_id, reconciliation.run_token
|
|
276
|
-
FROM _emdash_media_usage_reconciliations AS reconciliation
|
|
277
|
-
INNER JOIN _emdash_media_usage_index_status AS status
|
|
278
|
-
ON status.collection_id = reconciliation.collection_id
|
|
279
|
-
AND status.scope_key = reconciliation.collection_slug
|
|
280
|
-
WHERE status.adapter_id = ${CONTENT_ADAPTER_ID}
|
|
281
|
-
AND status.scope_type = ${COLLECTION_SCOPE}
|
|
282
|
-
AND status.reconciliation_required = 0
|
|
283
|
-
ORDER BY reconciliation.updated_at, reconciliation.collection_id
|
|
284
|
-
LIMIT 1
|
|
285
|
-
)
|
|
286
|
-
RETURNING collection_id
|
|
287
|
-
`.execute(this.db)).rows.length === 1;
|
|
288
|
-
}
|
|
289
|
-
liveClaimExists(claim) {
|
|
290
|
-
return this.liveClaimExistsSql(claim);
|
|
291
|
-
}
|
|
292
|
-
liveClaimExistsSql(claim) {
|
|
293
|
-
return sql`EXISTS (
|
|
294
|
-
SELECT 1
|
|
295
|
-
FROM _emdash_media_usage_reconciliations AS reconciliation
|
|
296
|
-
INNER JOIN _emdash_collections AS collection
|
|
297
|
-
ON collection.id = reconciliation.collection_id
|
|
298
|
-
AND collection.slug = reconciliation.collection_slug
|
|
299
|
-
WHERE reconciliation.collection_id = ${claim.collectionId}
|
|
300
|
-
AND reconciliation.collection_slug = ${claim.collectionSlug}
|
|
301
|
-
AND reconciliation.run_token = ${claim.runToken}
|
|
302
|
-
AND reconciliation.state = 'leased'
|
|
303
|
-
AND reconciliation.lease_token = ${claim.leaseToken}
|
|
304
|
-
AND ${liveLease(this.db, "reconciliation.lease_expires_at")}
|
|
305
|
-
AND EXISTS (
|
|
306
|
-
SELECT 1 FROM _emdash_media_usage_activation AS activation
|
|
307
|
-
WHERE activation.task_key = ${ACTIVATION_KEY}
|
|
308
|
-
AND activation.state = 'active'
|
|
309
|
-
)
|
|
310
|
-
AND NOT EXISTS (
|
|
311
|
-
SELECT 1 FROM _emdash_media_usage_collection_deletions AS deletion
|
|
312
|
-
WHERE deletion.collection_id = reconciliation.collection_id
|
|
313
|
-
)
|
|
314
|
-
)`;
|
|
315
|
-
}
|
|
316
|
-
statusOwnsRun(claim, targetEpoch) {
|
|
317
|
-
return sql`EXISTS (
|
|
318
|
-
SELECT 1 FROM _emdash_media_usage_index_status AS status
|
|
319
|
-
WHERE status.adapter_id = ${CONTENT_ADAPTER_ID}
|
|
320
|
-
AND status.scope_type = ${COLLECTION_SCOPE}
|
|
321
|
-
AND status.collection_id = ${claim.collectionId}
|
|
322
|
-
AND status.scope_key = ${claim.collectionSlug}
|
|
323
|
-
AND status.capture_state = 'active'
|
|
324
|
-
AND status.reconciliation_required = 1
|
|
325
|
-
AND status.status = 'running'
|
|
326
|
-
AND status.cursor = ${claim.runToken}
|
|
327
|
-
AND status.change_epoch = ${targetEpoch}
|
|
328
|
-
)`;
|
|
329
|
-
}
|
|
330
|
-
async seedNextCandidate() {
|
|
331
|
-
const runToken = ulid();
|
|
332
|
-
const now = timestampOffset(this.db, 0);
|
|
333
|
-
return (await sql`
|
|
334
|
-
INSERT INTO _emdash_media_usage_reconciliations (
|
|
335
|
-
collection_id,
|
|
336
|
-
collection_slug,
|
|
337
|
-
run_token,
|
|
338
|
-
next_attempt_at,
|
|
339
|
-
updated_at
|
|
340
|
-
)
|
|
341
|
-
SELECT status.collection_id, status.scope_key, ${runToken}, ${now}, ${now}
|
|
342
|
-
FROM _emdash_media_usage_index_status AS status
|
|
343
|
-
INNER JOIN _emdash_collections AS collection
|
|
344
|
-
ON collection.id = status.collection_id
|
|
345
|
-
AND collection.slug = status.scope_key
|
|
346
|
-
WHERE status.adapter_id = ${CONTENT_ADAPTER_ID}
|
|
347
|
-
AND status.scope_type = ${COLLECTION_SCOPE}
|
|
348
|
-
AND status.capture_state = 'active'
|
|
349
|
-
AND status.reconciliation_required = 1
|
|
350
|
-
AND status.collection_id IS NOT NULL
|
|
351
|
-
AND EXISTS (
|
|
352
|
-
SELECT 1 FROM _emdash_media_usage_activation AS activation
|
|
353
|
-
WHERE activation.task_key = ${ACTIVATION_KEY}
|
|
354
|
-
AND activation.state = 'active'
|
|
355
|
-
)
|
|
356
|
-
AND NOT EXISTS (
|
|
357
|
-
SELECT 1 FROM _emdash_media_usage_reconciliations AS existing
|
|
358
|
-
WHERE existing.collection_id = status.collection_id
|
|
359
|
-
)
|
|
360
|
-
AND NOT EXISTS (
|
|
361
|
-
SELECT 1 FROM _emdash_media_usage_collection_deletions AS deletion
|
|
362
|
-
WHERE deletion.collection_id = status.collection_id
|
|
363
|
-
)
|
|
364
|
-
ORDER BY status.collection_id
|
|
365
|
-
LIMIT 1
|
|
366
|
-
ON CONFLICT (collection_id) DO NOTHING
|
|
367
|
-
RETURNING collection_id
|
|
368
|
-
`.execute(this.db)).rows.length === 1;
|
|
369
|
-
}
|
|
370
|
-
async findDue(limit) {
|
|
371
|
-
assertLimit(limit);
|
|
372
|
-
const nextAttemptIsDue = timestampIsDue(this.db, "next_attempt_at");
|
|
373
|
-
return (await sql`
|
|
374
|
-
WITH pending_candidates AS (
|
|
375
|
-
SELECT * FROM _emdash_media_usage_reconciliations
|
|
376
|
-
WHERE state = 'pending' AND ${nextAttemptIsDue}
|
|
377
|
-
ORDER BY next_attempt_at, updated_at, collection_id
|
|
378
|
-
LIMIT ${limit}
|
|
379
|
-
), retry_candidates AS (
|
|
380
|
-
SELECT * FROM _emdash_media_usage_reconciliations
|
|
381
|
-
WHERE state = 'retry' AND ${nextAttemptIsDue}
|
|
382
|
-
ORDER BY next_attempt_at, updated_at, collection_id
|
|
383
|
-
LIMIT ${limit}
|
|
384
|
-
), leased_candidates AS (
|
|
385
|
-
SELECT * FROM _emdash_media_usage_reconciliations
|
|
386
|
-
WHERE state = 'leased' AND ${timestampIsDue(this.db, "lease_expires_at")}
|
|
387
|
-
ORDER BY lease_expires_at, updated_at, collection_id
|
|
388
|
-
LIMIT ${limit}
|
|
389
|
-
), candidates AS (
|
|
390
|
-
SELECT * FROM pending_candidates
|
|
391
|
-
UNION ALL SELECT * FROM retry_candidates
|
|
392
|
-
UNION ALL SELECT * FROM leased_candidates
|
|
393
|
-
)
|
|
394
|
-
SELECT * FROM candidates
|
|
395
|
-
ORDER BY CASE WHEN state = 'leased' THEN lease_expires_at ELSE next_attempt_at END,
|
|
396
|
-
updated_at,
|
|
397
|
-
collection_id
|
|
398
|
-
LIMIT ${limit}
|
|
399
|
-
`.execute(this.db)).rows.map(rowToRecord);
|
|
400
|
-
}
|
|
401
|
-
async hasDeferredCandidate() {
|
|
402
|
-
return await this.db.selectFrom("_emdash_media_usage_reconciliations").select("collection_id").where("state", "in", [
|
|
403
|
-
"pending",
|
|
404
|
-
"retry",
|
|
405
|
-
"leased"
|
|
406
|
-
]).limit(1).executeTakeFirst() !== void 0;
|
|
407
|
-
}
|
|
408
|
-
async wakeDrainedBarrierCandidate() {
|
|
409
|
-
const now = timestampOffset(this.db, 0);
|
|
410
|
-
return (await sql`
|
|
411
|
-
UPDATE _emdash_media_usage_reconciliations
|
|
412
|
-
SET next_attempt_at = ${now}, updated_at = ${now}
|
|
413
|
-
WHERE collection_id = (
|
|
414
|
-
SELECT reconciliation.collection_id
|
|
415
|
-
FROM _emdash_media_usage_reconciliations AS reconciliation
|
|
416
|
-
INNER JOIN _emdash_media_usage_index_status AS status
|
|
417
|
-
ON status.collection_id = reconciliation.collection_id
|
|
418
|
-
AND status.scope_key = reconciliation.collection_slug
|
|
419
|
-
WHERE reconciliation.state = 'pending'
|
|
420
|
-
AND reconciliation.target_epoch IS NOT NULL
|
|
421
|
-
AND NOT ${timestampIsDue(this.db, "reconciliation.next_attempt_at")}
|
|
422
|
-
AND status.adapter_id = ${CONTENT_ADAPTER_ID}
|
|
423
|
-
AND status.scope_type = ${COLLECTION_SCOPE}
|
|
424
|
-
AND status.capture_state = 'active'
|
|
425
|
-
AND status.reconciliation_required = 1
|
|
426
|
-
AND status.status = 'running'
|
|
427
|
-
AND status.cursor = reconciliation.run_token
|
|
428
|
-
AND status.change_epoch = reconciliation.target_epoch
|
|
429
|
-
AND NOT EXISTS (
|
|
430
|
-
SELECT 1 FROM _emdash_media_usage_work AS work
|
|
431
|
-
WHERE work.collection_id = reconciliation.collection_id
|
|
432
|
-
)
|
|
433
|
-
AND NOT EXISTS (
|
|
434
|
-
SELECT 1 FROM _emdash_media_usage_collection_deletions AS deletion
|
|
435
|
-
WHERE deletion.collection_id = reconciliation.collection_id
|
|
436
|
-
)
|
|
437
|
-
ORDER BY reconciliation.next_attempt_at, reconciliation.updated_at,
|
|
438
|
-
reconciliation.collection_id
|
|
439
|
-
LIMIT 1
|
|
440
|
-
)
|
|
441
|
-
AND state = 'pending'
|
|
442
|
-
AND NOT ${timestampIsDue(this.db, "_emdash_media_usage_reconciliations.next_attempt_at")}
|
|
443
|
-
AND EXISTS (
|
|
444
|
-
SELECT 1 FROM _emdash_media_usage_activation AS activation
|
|
445
|
-
WHERE activation.task_key = ${ACTIVATION_KEY}
|
|
446
|
-
AND activation.state = 'active'
|
|
447
|
-
)
|
|
448
|
-
AND NOT EXISTS (
|
|
449
|
-
SELECT 1 FROM _emdash_media_usage_work AS work
|
|
450
|
-
WHERE work.collection_id = _emdash_media_usage_reconciliations.collection_id
|
|
451
|
-
)
|
|
452
|
-
RETURNING collection_id
|
|
453
|
-
`.execute(this.db)).rows.length === 1;
|
|
454
|
-
}
|
|
455
|
-
async findFailed(limit) {
|
|
456
|
-
assertLimit(limit);
|
|
457
|
-
return (await this.db.selectFrom("_emdash_media_usage_reconciliations as reconciliation").innerJoin("_emdash_media_usage_index_status as status", (join) => join.onRef("status.collection_id", "=", "reconciliation.collection_id").onRef("status.scope_key", "=", "reconciliation.collection_slug")).selectAll("reconciliation").where("reconciliation.state", "=", "failed").where("status.adapter_id", "=", CONTENT_ADAPTER_ID).where("status.scope_type", "=", COLLECTION_SCOPE).where((eb) => eb.or([
|
|
458
|
-
eb("status.reconciliation_required", "=", 0),
|
|
459
|
-
eb.and([eb("status.status", "=", "running"), eb("status.cursor", "=", eb.ref("reconciliation.run_token"))]),
|
|
460
|
-
eb.and([eb("status.cursor", "is", null), eb("status.change_epoch", ">", eb.ref("reconciliation.target_epoch"))])
|
|
461
|
-
])).orderBy("reconciliation.updated_at").orderBy("reconciliation.collection_id").limit(limit).execute()).map(rowToRecord);
|
|
462
|
-
}
|
|
463
|
-
async claim(input) {
|
|
464
|
-
assertIdentity(input);
|
|
465
|
-
assertDuration(input.leaseDurationSeconds, "lease duration");
|
|
466
|
-
const leaseToken = ulid();
|
|
467
|
-
const row = await this.db.updateTable("_emdash_media_usage_reconciliations as reconciliation").set({
|
|
468
|
-
state: "leased",
|
|
469
|
-
lease_token: leaseToken,
|
|
470
|
-
lease_expires_at: timestampOffset(this.db, input.leaseDurationSeconds),
|
|
471
|
-
updated_at: timestampOffset(this.db, 0)
|
|
472
|
-
}).where("reconciliation.collection_id", "=", input.collectionId).where("reconciliation.run_token", "=", input.runToken).where((eb) => eb.or([eb.and([eb("reconciliation.state", "in", ["pending", "retry"]), timestampIsDue(this.db, "reconciliation.next_attempt_at")]), eb.and([eb("reconciliation.state", "=", "leased"), timestampIsDue(this.db, "reconciliation.lease_expires_at")])])).where((eb) => eb.exists(eb.selectFrom("_emdash_media_usage_activation as activation").select("activation.task_key").where("activation.task_key", "=", ACTIVATION_KEY).where("activation.state", "=", "active"))).where((eb) => eb.exists(eb.selectFrom("_emdash_media_usage_index_status as status").innerJoin("_emdash_collections as collection", (join) => join.onRef("collection.id", "=", "status.collection_id").onRef("collection.slug", "=", "status.scope_key")).select("status.collection_id").whereRef("status.collection_id", "=", "reconciliation.collection_id").whereRef("status.scope_key", "=", "reconciliation.collection_slug").where("status.adapter_id", "=", CONTENT_ADAPTER_ID).where("status.scope_type", "=", COLLECTION_SCOPE).where("status.capture_state", "=", "active").where("status.reconciliation_required", "=", 1))).where((eb) => eb.not(eb.exists(eb.selectFrom("_emdash_media_usage_collection_deletions as deletion").select("deletion.collection_id").whereRef("deletion.collection_id", "=", "reconciliation.collection_id")))).returningAll().executeTakeFirst();
|
|
473
|
-
return row ? {
|
|
474
|
-
...rowToRecord(row),
|
|
475
|
-
leaseToken
|
|
476
|
-
} : null;
|
|
477
|
-
}
|
|
478
|
-
async release(input) {
|
|
479
|
-
assertLeaseIdentity(input);
|
|
480
|
-
assertDuration(input.delaySeconds, "release delay", true);
|
|
481
|
-
const result = await this.db.updateTable("_emdash_media_usage_reconciliations").set({
|
|
482
|
-
state: "pending",
|
|
483
|
-
next_attempt_at: timestampOffset(this.db, input.delaySeconds),
|
|
484
|
-
lease_token: null,
|
|
485
|
-
lease_expires_at: null,
|
|
486
|
-
updated_at: timestampOffset(this.db, 0)
|
|
487
|
-
}).where("collection_id", "=", input.collectionId).where("run_token", "=", input.runToken).where("state", "=", "leased").where("lease_token", "=", input.leaseToken).where(liveLease(this.db)).executeTakeFirst();
|
|
488
|
-
return Number(result.numUpdatedRows ?? 0) === 1;
|
|
489
|
-
}
|
|
490
|
-
async recordFailure(input) {
|
|
491
|
-
assertLeaseIdentity(input);
|
|
492
|
-
if (!STABLE_ERROR_CODE_PATTERN.test(input.errorCode)) throw new Error("Reconciliation failure requires a stable error code");
|
|
493
|
-
assertDuration(input.retryDelaySeconds, "retry delay", true);
|
|
494
|
-
const result = await this.db.updateTable("_emdash_media_usage_reconciliations").set({
|
|
495
|
-
state: input.terminal ? "failed" : sql`CASE WHEN attempt_count >= 4 THEN 'failed' ELSE 'retry' END`,
|
|
496
|
-
...input.terminal ? { target_epoch: sql`COALESCE(
|
|
497
|
-
target_epoch,
|
|
498
|
-
(SELECT status.change_epoch
|
|
499
|
-
FROM _emdash_media_usage_index_status AS status
|
|
500
|
-
WHERE status.adapter_id = ${CONTENT_ADAPTER_ID}
|
|
501
|
-
AND status.scope_type = ${COLLECTION_SCOPE}
|
|
502
|
-
AND status.collection_id = ${input.collectionId}
|
|
503
|
-
AND status.status = 'running'
|
|
504
|
-
AND status.cursor = ${input.runToken})
|
|
505
|
-
)` } : {},
|
|
506
|
-
attempt_count: sql`attempt_count + 1`,
|
|
507
|
-
next_attempt_at: timestampOffset(this.db, input.retryDelaySeconds),
|
|
508
|
-
lease_token: null,
|
|
509
|
-
lease_expires_at: null,
|
|
510
|
-
last_error_code: input.errorCode,
|
|
511
|
-
updated_at: timestampOffset(this.db, 0)
|
|
512
|
-
}).where("collection_id", "=", input.collectionId).where("run_token", "=", input.runToken).where("state", "=", "leased").where("lease_token", "=", input.leaseToken).where(liveLease(this.db)).executeTakeFirst();
|
|
513
|
-
return Number(result.numUpdatedRows ?? 0) === 1;
|
|
514
|
-
}
|
|
515
|
-
async recordEntryFailure(claim) {
|
|
516
|
-
const result = await this.db.updateTable("_emdash_media_usage_reconciliations as reconciliation").set({
|
|
517
|
-
state: "failed",
|
|
518
|
-
attempt_count: sql`attempt_count + 1`,
|
|
519
|
-
next_attempt_at: timestampOffset(this.db, 0),
|
|
520
|
-
lease_token: null,
|
|
521
|
-
lease_expires_at: null,
|
|
522
|
-
last_error_code: "MEDIA_USAGE_RECONCILIATION_ENTRY_FAILED",
|
|
523
|
-
updated_at: timestampOffset(this.db, 0)
|
|
524
|
-
}).where("reconciliation.collection_id", "=", claim.collectionId).where("reconciliation.run_token", "=", claim.runToken).where("reconciliation.state", "=", "leased").where("reconciliation.lease_token", "=", claim.leaseToken).where(liveLease(this.db)).where((eb) => eb.exists(eb.selectFrom("_emdash_media_usage_work as work").select("work.content_id").where("work.collection_id", "=", claim.collectionId).where("work.state", "=", "failed"))).executeTakeFirst();
|
|
525
|
-
return Number(result.numUpdatedRows ?? 0) === 1;
|
|
526
|
-
}
|
|
527
|
-
async resetFailedForNewEpoch(observed) {
|
|
528
|
-
const collectionId = "collection_id" in observed ? observed.collection_id : observed.collectionId;
|
|
529
|
-
const runToken = "run_token" in observed ? observed.run_token : observed.runToken;
|
|
530
|
-
const targetEpoch = "target_epoch" in observed ? observed.target_epoch : observed.targetEpoch;
|
|
531
|
-
if (targetEpoch === null) return false;
|
|
532
|
-
const now = timestampOffset(this.db, 0);
|
|
533
|
-
const result = await this.db.updateTable("_emdash_media_usage_reconciliations as reconciliation").set({
|
|
534
|
-
state: "pending",
|
|
535
|
-
phase: "scan",
|
|
536
|
-
target_epoch: null,
|
|
537
|
-
field_fingerprint: null,
|
|
538
|
-
scan_cursor: null,
|
|
539
|
-
scan_upper_id: null,
|
|
540
|
-
source_cursor: null,
|
|
541
|
-
source_upper_key: null,
|
|
542
|
-
attempt_count: 0,
|
|
543
|
-
next_attempt_at: now,
|
|
544
|
-
lease_token: null,
|
|
545
|
-
lease_expires_at: null,
|
|
546
|
-
last_error_code: null,
|
|
547
|
-
updated_at: now
|
|
548
|
-
}).where("reconciliation.collection_id", "=", collectionId).where("reconciliation.run_token", "=", runToken).where("reconciliation.state", "=", "failed").where("reconciliation.target_epoch", "=", targetEpoch).where((eb) => eb.exists(eb.selectFrom("_emdash_media_usage_index_status as status").select("status.collection_id").whereRef("status.collection_id", "=", "reconciliation.collection_id").whereRef("status.scope_key", "=", "reconciliation.collection_slug").where("status.adapter_id", "=", CONTENT_ADAPTER_ID).where("status.scope_type", "=", COLLECTION_SCOPE).where("status.capture_state", "=", "active").where("status.reconciliation_required", "=", 1).where((status) => status.or([status("status.cursor", "is", null), status.and([status("status.status", "=", "running"), status("status.cursor", "=", runToken)])])).where("status.change_epoch", ">", targetEpoch))).executeTakeFirst();
|
|
549
|
-
return Number(result.numUpdatedRows ?? 0) === 1;
|
|
550
|
-
}
|
|
551
|
-
};
|
|
552
|
-
function rowToRecord(row) {
|
|
553
|
-
if (!isState(row.state) || !isPhase(row.phase) || !Number.isSafeInteger(row.attempt_count)) throw new Error("Invalid media usage reconciliation lifecycle");
|
|
554
|
-
return {
|
|
555
|
-
collectionId: row.collection_id,
|
|
556
|
-
collectionSlug: row.collection_slug,
|
|
557
|
-
runToken: row.run_token,
|
|
558
|
-
targetEpoch: row.target_epoch,
|
|
559
|
-
fieldFingerprint: row.field_fingerprint,
|
|
560
|
-
state: row.state,
|
|
561
|
-
phase: row.phase,
|
|
562
|
-
scanCursor: row.scan_cursor,
|
|
563
|
-
scanUpperId: row.scan_upper_id,
|
|
564
|
-
sourceCursor: row.source_cursor,
|
|
565
|
-
sourceUpperKey: row.source_upper_key,
|
|
566
|
-
attemptCount: row.attempt_count,
|
|
567
|
-
nextAttemptAt: row.next_attempt_at,
|
|
568
|
-
leaseToken: row.lease_token,
|
|
569
|
-
leaseExpiresAt: row.lease_expires_at,
|
|
570
|
-
lastErrorCode: row.last_error_code,
|
|
571
|
-
createdAt: row.created_at,
|
|
572
|
-
updatedAt: row.updated_at
|
|
573
|
-
};
|
|
574
|
-
}
|
|
575
|
-
function isState(state) {
|
|
576
|
-
return state === "pending" || state === "retry" || state === "leased" || state === "failed";
|
|
577
|
-
}
|
|
578
|
-
function isPhase(phase) {
|
|
579
|
-
return phase === "scan" || phase === "sources";
|
|
580
|
-
}
|
|
581
|
-
function assertLimit(limit) {
|
|
582
|
-
if (!Number.isSafeInteger(limit) || limit < 1 || limit > MAX_CANDIDATES) throw new Error("Reconciliation candidate limit must be from 1 to 100");
|
|
583
|
-
}
|
|
584
|
-
function assertIdentity(input) {
|
|
585
|
-
if (!input.collectionId || !input.runToken) throw new Error("Reconciliation requires an exact collection and run token");
|
|
586
|
-
}
|
|
587
|
-
function assertLeaseIdentity(input) {
|
|
588
|
-
assertIdentity(input);
|
|
589
|
-
if (!input.leaseToken) throw new Error("Reconciliation requires a lease token");
|
|
590
|
-
}
|
|
591
|
-
function assertDuration(value, label, allowZero = false) {
|
|
592
|
-
if (!Number.isSafeInteger(value) || value < (allowZero ? 0 : 1) || value > MAX_PORTABLE_DURATION_SECONDS) throw new Error(`Reconciliation ${label} is outside the portable range`);
|
|
593
|
-
}
|
|
594
|
-
function liveLease(db, column = "lease_expires_at") {
|
|
595
|
-
const expiry = sql.ref(column);
|
|
596
|
-
return isPostgres(db) ? sql`${expiry} > to_char(statement_timestamp() AT TIME ZONE 'UTC', 'YYYY-MM-DD"T"HH24:MI:SS.MS"Z"')` : sql`${expiry} > strftime('%Y-%m-%dT%H:%M:%fZ', 'now')`;
|
|
597
|
-
}
|
|
598
|
-
function timestampIsDue(db, column) {
|
|
599
|
-
const value = sql.ref(column);
|
|
600
|
-
return isPostgres(db) ? sql`${value} <= to_char(statement_timestamp() AT TIME ZONE 'UTC', 'YYYY-MM-DD"T"HH24:MI:SS.MS"Z"')` : sql`${value} <= strftime('%Y-%m-%dT%H:%M:%fZ', 'now')`;
|
|
601
|
-
}
|
|
602
|
-
function timestampOffset(db, offsetSeconds) {
|
|
603
|
-
if (isPostgres(db)) return sql`to_char(
|
|
604
|
-
(clock_timestamp() AT TIME ZONE 'UTC') + (${offsetSeconds} * INTERVAL '1 second'),
|
|
605
|
-
'YYYY-MM-DD"T"HH24:MI:SS.MS"Z"'
|
|
606
|
-
)`;
|
|
607
|
-
return sql`strftime(
|
|
608
|
-
'%Y-%m-%dT%H:%M:%fZ',
|
|
609
|
-
'now',
|
|
610
|
-
${`${offsetSeconds >= 0 ? "+" : ""}${offsetSeconds} seconds`}
|
|
611
|
-
)`;
|
|
612
|
-
}
|
|
613
|
-
function contentTableName(collectionSlug) {
|
|
614
|
-
validateIdentifier(collectionSlug, "collection slug");
|
|
615
|
-
const tableName = `ec_${collectionSlug}`;
|
|
616
|
-
validateIdentifier(tableName, "content table");
|
|
617
|
-
return tableName;
|
|
618
|
-
}
|
|
619
|
-
|
|
620
|
-
//#endregion
|
|
621
|
-
//#region src/media/usage/reconciliation-processor.ts
|
|
622
|
-
const MEDIA_USAGE_RECONCILIATION_LIMITS = Object.freeze({
|
|
623
|
-
candidatesPerTick: 4,
|
|
624
|
-
scanPageSize: 1e3,
|
|
625
|
-
sourcePageSize: 1e3,
|
|
626
|
-
leaseDurationSeconds: 60,
|
|
627
|
-
maxAttempts: 5,
|
|
628
|
-
retryBaseSeconds: 30,
|
|
629
|
-
retryMaxSeconds: 900,
|
|
630
|
-
retryJitterRatio: .25
|
|
631
|
-
});
|
|
632
|
-
async function processDueMediaUsageReconciliationDetailed(db, options = {}) {
|
|
633
|
-
if (!options.activationKnownActive) {
|
|
634
|
-
if ((await db.selectFrom("_emdash_media_usage_activation").select("state").where("task_key", "=", "incremental_capture").executeTakeFirst())?.state !== "active") return {
|
|
635
|
-
outcome: "inactive",
|
|
636
|
-
consumedUnit: false,
|
|
637
|
-
hasDeferredCandidate: false
|
|
638
|
-
};
|
|
639
|
-
}
|
|
640
|
-
const reconciliation = new MediaUsageReconciliationRepository(db);
|
|
641
|
-
if (await reconciliation.deleteOneObsolete()) return {
|
|
642
|
-
outcome: "completed",
|
|
643
|
-
consumedUnit: true,
|
|
644
|
-
hasDeferredCandidate: false
|
|
645
|
-
};
|
|
646
|
-
const [failed] = await reconciliation.findFailed(1);
|
|
647
|
-
if (failed) {
|
|
648
|
-
if (await reconciliation.finishFailedCoverage(failed.collectionId, failed.runToken)) return {
|
|
649
|
-
outcome: "failed",
|
|
650
|
-
consumedUnit: true,
|
|
651
|
-
hasDeferredCandidate: false
|
|
652
|
-
};
|
|
653
|
-
if (await reconciliation.resetFailedForNewEpoch(failed)) return {
|
|
654
|
-
outcome: "advanced",
|
|
655
|
-
consumedUnit: true,
|
|
656
|
-
hasDeferredCandidate: false
|
|
657
|
-
};
|
|
658
|
-
}
|
|
659
|
-
const seeded = await reconciliation.seedNextCandidate();
|
|
660
|
-
const candidates = await reconciliation.findDue(MEDIA_USAGE_RECONCILIATION_LIMITS.candidatesPerTick);
|
|
661
|
-
let claim = null;
|
|
662
|
-
for (const candidate of candidates) {
|
|
663
|
-
claim = await reconciliation.claim({
|
|
664
|
-
collectionId: candidate.collectionId,
|
|
665
|
-
runToken: candidate.runToken,
|
|
666
|
-
leaseDurationSeconds: MEDIA_USAGE_RECONCILIATION_LIMITS.leaseDurationSeconds
|
|
667
|
-
});
|
|
668
|
-
if (claim) break;
|
|
669
|
-
}
|
|
670
|
-
if (!claim) return {
|
|
671
|
-
outcome: candidates.length === 0 ? "not_due" : "claim_lost",
|
|
672
|
-
consumedUnit: seeded,
|
|
673
|
-
hasDeferredCandidate: candidates.length === 0 && await reconciliation.hasDeferredCandidate()
|
|
674
|
-
};
|
|
675
|
-
try {
|
|
676
|
-
return {
|
|
677
|
-
outcome: await processClaimedReconciliation(db, claim),
|
|
678
|
-
consumedUnit: true,
|
|
679
|
-
hasDeferredCandidate: false
|
|
680
|
-
};
|
|
681
|
-
} catch (error) {
|
|
682
|
-
const terminal = claim.attemptCount + 1 >= MEDIA_USAGE_RECONCILIATION_LIMITS.maxAttempts;
|
|
683
|
-
if (!await reconciliation.recordFailure({
|
|
684
|
-
collectionId: claim.collectionId,
|
|
685
|
-
runToken: claim.runToken,
|
|
686
|
-
leaseToken: claim.leaseToken,
|
|
687
|
-
errorCode: "MEDIA_USAGE_RECONCILIATION_FAILED",
|
|
688
|
-
retryDelaySeconds: retryDelaySeconds$1(claim.attemptCount),
|
|
689
|
-
terminal
|
|
690
|
-
})) return {
|
|
691
|
-
outcome: "claim_lost",
|
|
692
|
-
consumedUnit: true,
|
|
693
|
-
hasDeferredCandidate: false
|
|
694
|
-
};
|
|
695
|
-
if (terminal) await reconciliation.finishFailedCoverage(claim.collectionId, claim.runToken);
|
|
696
|
-
console.error("[media-usage:reconciliation] Processing failed:", error);
|
|
697
|
-
return {
|
|
698
|
-
outcome: terminal ? "failed" : "retry",
|
|
699
|
-
consumedUnit: true,
|
|
700
|
-
hasDeferredCandidate: false
|
|
701
|
-
};
|
|
702
|
-
}
|
|
703
|
-
}
|
|
704
|
-
async function processClaimedMediaUsageReconciliationScan(db, claim, options = {}, knownCurrent) {
|
|
705
|
-
const reconciliation = new MediaUsageReconciliationRepository(db);
|
|
706
|
-
let current = knownCurrent ?? await reconciliation.findByIdentity(claim.collectionId, claim.runToken);
|
|
707
|
-
if (!current || current.leaseToken !== claim.leaseToken || current.phase !== "scan") return "deferred";
|
|
708
|
-
let fields;
|
|
709
|
-
let fieldFingerprint;
|
|
710
|
-
if (current.targetEpoch === null) {
|
|
711
|
-
const targetEpoch = await reconciliation.beginRun(claim);
|
|
712
|
-
if (targetEpoch === null) {
|
|
713
|
-
await reconciliation.release({
|
|
714
|
-
...claim,
|
|
715
|
-
delaySeconds: 30
|
|
716
|
-
});
|
|
717
|
-
return "deferred";
|
|
718
|
-
}
|
|
719
|
-
fields = await loadContentMediaUsageFields(db, claim.collectionSlug, claim.collectionId);
|
|
720
|
-
fieldFingerprint = await buildContentMediaUsageFieldFingerprint(fields);
|
|
721
|
-
const scanUpperId = fields.extractionFields.length === 0 ? null : await reconciliation.findScanUpperId(claim);
|
|
722
|
-
if (!await reconciliation.initializeScan({
|
|
723
|
-
claim,
|
|
724
|
-
targetEpoch,
|
|
725
|
-
fieldFingerprint,
|
|
726
|
-
scanUpperId
|
|
727
|
-
})) return "deferred";
|
|
728
|
-
current = {
|
|
729
|
-
...current,
|
|
730
|
-
targetEpoch,
|
|
731
|
-
fieldFingerprint,
|
|
732
|
-
scanCursor: null,
|
|
733
|
-
scanUpperId,
|
|
734
|
-
sourceCursor: null,
|
|
735
|
-
sourceUpperKey: null
|
|
736
|
-
};
|
|
737
|
-
} else {
|
|
738
|
-
fields = await loadContentMediaUsageFields(db, claim.collectionSlug, claim.collectionId);
|
|
739
|
-
fieldFingerprint = await buildContentMediaUsageFieldFingerprint(fields);
|
|
740
|
-
}
|
|
741
|
-
if (current.fieldFingerprint !== fieldFingerprint || current.targetEpoch === null) return "restart_required";
|
|
742
|
-
const contentIds = await reconciliation.findScanPage(current, MEDIA_USAGE_RECONCILIATION_LIMITS.scanPageSize);
|
|
743
|
-
if (contentIds.length === 0) {
|
|
744
|
-
if (options.releaseOnExhausted ?? true) await reconciliation.release({
|
|
745
|
-
...claim,
|
|
746
|
-
delaySeconds: 30
|
|
747
|
-
});
|
|
748
|
-
return "exhausted";
|
|
749
|
-
}
|
|
750
|
-
await new MediaUsageWorkRepository(db).enqueueReconciliationPage({
|
|
751
|
-
collectionId: claim.collectionId,
|
|
752
|
-
collectionSlug: claim.collectionSlug,
|
|
753
|
-
runToken: claim.runToken,
|
|
754
|
-
leaseToken: claim.leaseToken,
|
|
755
|
-
changeEpoch: current.targetEpoch,
|
|
756
|
-
phase: "scan",
|
|
757
|
-
contentIds
|
|
758
|
-
});
|
|
759
|
-
const nextCursor = contentIds.at(-1);
|
|
760
|
-
if (!await reconciliation.checkpointScan({
|
|
761
|
-
claim,
|
|
762
|
-
targetEpoch: current.targetEpoch,
|
|
763
|
-
previousCursor: current.scanCursor,
|
|
764
|
-
nextCursor
|
|
765
|
-
})) return "deferred";
|
|
766
|
-
if (!await reconciliation.release({
|
|
767
|
-
...claim,
|
|
768
|
-
delaySeconds: 0
|
|
769
|
-
})) return "deferred";
|
|
770
|
-
return "advanced";
|
|
771
|
-
}
|
|
772
|
-
async function processClaimedReconciliation(db, claim) {
|
|
773
|
-
const reconciliation = new MediaUsageReconciliationRepository(db);
|
|
774
|
-
let current = claim;
|
|
775
|
-
if (current.targetEpoch !== null && !await reconciliation.ownsRun(claim, current.targetEpoch)) return restartReconciliation(db, reconciliation, claim, current);
|
|
776
|
-
if (current.targetEpoch !== null) await new MediaUsageWorkRepository(db).deleteObsoleteReconciliationWork({
|
|
777
|
-
collectionId: claim.collectionId,
|
|
778
|
-
collectionSlug: claim.collectionSlug,
|
|
779
|
-
runToken: claim.runToken,
|
|
780
|
-
leaseToken: claim.leaseToken,
|
|
781
|
-
targetEpoch: current.targetEpoch
|
|
782
|
-
});
|
|
783
|
-
if (current.phase === "scan") {
|
|
784
|
-
const outcome = await processClaimedMediaUsageReconciliationScan(db, claim, { releaseOnExhausted: false }, current);
|
|
785
|
-
if (outcome === "restart_required") {
|
|
786
|
-
current = await reconciliation.findByIdentity(claim.collectionId, claim.runToken) ?? current;
|
|
787
|
-
return restartReconciliation(db, reconciliation, claim, current);
|
|
788
|
-
}
|
|
789
|
-
if (outcome !== "exhausted") return outcome;
|
|
790
|
-
if (current.targetEpoch === null || current.fieldFingerprint === null) current = await reconciliation.findByIdentity(claim.collectionId, claim.runToken) ?? current;
|
|
791
|
-
const barrier = await reconciliation.findWorkBarrier(claim.collectionId);
|
|
792
|
-
if (barrier.state === "failed") return failReconciliation(reconciliation, claim, barrier.errorCode, true);
|
|
793
|
-
if (barrier.state === "pending") {
|
|
794
|
-
await reconciliation.release({
|
|
795
|
-
...claim,
|
|
796
|
-
delaySeconds: 30
|
|
797
|
-
});
|
|
798
|
-
return "deferred";
|
|
799
|
-
}
|
|
800
|
-
if (current.targetEpoch === null || current.fieldFingerprint === null) return "claim_lost";
|
|
801
|
-
const sourceUpperKey = await reconciliation.findSourceUpperKey(claim, current.targetEpoch);
|
|
802
|
-
if (!await reconciliation.transitionToSources({
|
|
803
|
-
claim,
|
|
804
|
-
targetEpoch: current.targetEpoch,
|
|
805
|
-
fieldFingerprint: current.fieldFingerprint,
|
|
806
|
-
sourceUpperKey
|
|
807
|
-
})) return "claim_lost";
|
|
808
|
-
if (!await reconciliation.release({
|
|
809
|
-
...claim,
|
|
810
|
-
delaySeconds: 0
|
|
811
|
-
})) return "claim_lost";
|
|
812
|
-
return "advanced";
|
|
813
|
-
}
|
|
814
|
-
return processSourcePhase(db, reconciliation, claim, current);
|
|
815
|
-
}
|
|
816
|
-
async function processSourcePhase(db, reconciliation, claim, current) {
|
|
817
|
-
if (current.targetEpoch === null || current.fieldFingerprint === null) return "claim_lost";
|
|
818
|
-
const fields = await loadContentMediaUsageFields(db, claim.collectionSlug, claim.collectionId);
|
|
819
|
-
const fieldFingerprint = await buildContentMediaUsageFieldFingerprint(fields);
|
|
820
|
-
if (fieldFingerprint !== current.fieldFingerprint) return restartReconciliation(db, reconciliation, claim, current, fields, fieldFingerprint);
|
|
821
|
-
const page = await reconciliation.findSourcePage(current, MEDIA_USAGE_RECONCILIATION_LIMITS.sourcePageSize);
|
|
822
|
-
if (page.length > 0) {
|
|
823
|
-
let enqueuedMissingContent = false;
|
|
824
|
-
if (page.some((source) => !source.contentId || source.sourceVariant !== "columns" && source.sourceVariant !== "draft_overlay")) return failReconciliation(reconciliation, claim, "MEDIA_USAGE_RECONCILIATION_INVALID_SOURCE", false);
|
|
825
|
-
const contentIds = [...new Set(page.map((source) => source.contentId))];
|
|
826
|
-
const enqueueIds = fields.extractionFields.length === 0 ? contentIds : await reconciliation.findMissingContentIds(claim.collectionSlug, contentIds);
|
|
827
|
-
if (enqueueIds.length > 0) {
|
|
828
|
-
await new MediaUsageWorkRepository(db).enqueueReconciliationPage({
|
|
829
|
-
collectionId: claim.collectionId,
|
|
830
|
-
collectionSlug: claim.collectionSlug,
|
|
831
|
-
runToken: claim.runToken,
|
|
832
|
-
leaseToken: claim.leaseToken,
|
|
833
|
-
changeEpoch: current.targetEpoch,
|
|
834
|
-
phase: "sources",
|
|
835
|
-
contentIds: enqueueIds
|
|
836
|
-
});
|
|
837
|
-
enqueuedMissingContent = true;
|
|
838
|
-
}
|
|
839
|
-
if (!await reconciliation.checkpointSources({
|
|
840
|
-
claim,
|
|
841
|
-
targetEpoch: current.targetEpoch,
|
|
842
|
-
previousCursor: current.sourceCursor,
|
|
843
|
-
nextCursor: page.at(-1).sourceKey
|
|
844
|
-
})) return "claim_lost";
|
|
845
|
-
if (enqueuedMissingContent || page.length === MEDIA_USAGE_RECONCILIATION_LIMITS.sourcePageSize) {
|
|
846
|
-
if (!await reconciliation.release({
|
|
847
|
-
...claim,
|
|
848
|
-
delaySeconds: 0
|
|
849
|
-
})) return "claim_lost";
|
|
850
|
-
return "advanced";
|
|
851
|
-
}
|
|
852
|
-
}
|
|
853
|
-
const barrier = await reconciliation.findWorkBarrier(claim.collectionId);
|
|
854
|
-
if (barrier.state === "failed") return failReconciliation(reconciliation, claim, barrier.errorCode, true);
|
|
855
|
-
if (barrier.state === "pending") {
|
|
856
|
-
await reconciliation.release({
|
|
857
|
-
...claim,
|
|
858
|
-
delaySeconds: 30
|
|
859
|
-
});
|
|
860
|
-
return "deferred";
|
|
861
|
-
}
|
|
862
|
-
if (!await reconciliation.finalizeCoverage({
|
|
863
|
-
claim,
|
|
864
|
-
targetEpoch: current.targetEpoch,
|
|
865
|
-
fieldFingerprint,
|
|
866
|
-
schemaVersion: CONTENT_SOURCE_SCHEMA_VERSION
|
|
867
|
-
})) return "claim_lost";
|
|
868
|
-
if (!await reconciliation.deleteFinalized(claim)) return "claim_lost";
|
|
869
|
-
return "completed";
|
|
870
|
-
}
|
|
871
|
-
async function restartReconciliation(db, reconciliation, claim, current, fields, fieldFingerprint) {
|
|
872
|
-
if (current.targetEpoch === null) return "claim_lost";
|
|
873
|
-
const discoveredFields = fields ?? await loadContentMediaUsageFields(db, claim.collectionSlug, claim.collectionId);
|
|
874
|
-
const fingerprint = fieldFingerprint ?? await buildContentMediaUsageFieldFingerprint(discoveredFields);
|
|
875
|
-
const targetEpoch = await reconciliation.restartRun(claim, current.targetEpoch);
|
|
876
|
-
if (targetEpoch === null) {
|
|
877
|
-
await reconciliation.release({
|
|
878
|
-
...claim,
|
|
879
|
-
delaySeconds: 30
|
|
880
|
-
});
|
|
881
|
-
return "deferred";
|
|
882
|
-
}
|
|
883
|
-
const scanUpperId = discoveredFields.extractionFields.length === 0 ? null : await reconciliation.findScanUpperId(claim);
|
|
884
|
-
if (!await reconciliation.restartScan({
|
|
885
|
-
claim,
|
|
886
|
-
previousEpoch: current.targetEpoch,
|
|
887
|
-
targetEpoch,
|
|
888
|
-
fieldFingerprint: fingerprint,
|
|
889
|
-
scanUpperId
|
|
890
|
-
})) return "claim_lost";
|
|
891
|
-
if (!await reconciliation.release({
|
|
892
|
-
...claim,
|
|
893
|
-
delaySeconds: 0
|
|
894
|
-
})) return "claim_lost";
|
|
895
|
-
return "advanced";
|
|
896
|
-
}
|
|
897
|
-
async function failReconciliation(reconciliation, claim, errorCode, entryFailure) {
|
|
898
|
-
if (!(entryFailure ? await reconciliation.recordEntryFailure(claim) : await reconciliation.recordFailure({
|
|
899
|
-
collectionId: claim.collectionId,
|
|
900
|
-
runToken: claim.runToken,
|
|
901
|
-
leaseToken: claim.leaseToken,
|
|
902
|
-
errorCode,
|
|
903
|
-
retryDelaySeconds: 0,
|
|
904
|
-
terminal: true
|
|
905
|
-
}))) return "claim_lost";
|
|
906
|
-
await reconciliation.finishFailedCoverage(claim.collectionId, claim.runToken);
|
|
907
|
-
return "failed";
|
|
908
|
-
}
|
|
909
|
-
function retryDelaySeconds$1(attemptCount) {
|
|
910
|
-
const exponential = Math.min(MEDIA_USAGE_RECONCILIATION_LIMITS.retryMaxSeconds, MEDIA_USAGE_RECONCILIATION_LIMITS.retryBaseSeconds * 2 ** attemptCount);
|
|
911
|
-
const jitter = Math.floor(exponential * MEDIA_USAGE_RECONCILIATION_LIMITS.retryJitterRatio * Math.random());
|
|
912
|
-
return Math.min(MEDIA_USAGE_RECONCILIATION_LIMITS.retryMaxSeconds, exponential + jitter);
|
|
913
|
-
}
|
|
914
|
-
|
|
915
|
-
//#endregion
|
|
916
|
-
//#region src/media/usage/work-processor.ts
|
|
917
|
-
const MEDIA_USAGE_WORK_PROCESSING_LIMITS = Object.freeze({
|
|
918
|
-
candidatesPerTick: 1e3,
|
|
919
|
-
leaseDurationSeconds: 1200,
|
|
920
|
-
maxAttempts: 5,
|
|
921
|
-
retryBaseSeconds: 30,
|
|
922
|
-
retryMaxSeconds: 900,
|
|
923
|
-
retryJitterRatio: .25
|
|
924
|
-
});
|
|
925
|
-
async function processMediaUsageWorkAfterWrite(db, collectionSlug, contentId) {
|
|
926
|
-
if (!await isIncrementalCaptureActive(db)) return {
|
|
927
|
-
outcome: "inactive",
|
|
928
|
-
claimed: false
|
|
929
|
-
};
|
|
930
|
-
await new MediaUsageRepository(db).recoverIncrementalFinalizations();
|
|
931
|
-
const repo = new MediaUsageWorkRepository(db);
|
|
932
|
-
const work = await repo.findWorkForContent(collectionSlug, contentId);
|
|
933
|
-
if (!work) return {
|
|
934
|
-
outcome: "not_due",
|
|
935
|
-
claimed: false
|
|
936
|
-
};
|
|
937
|
-
const claimed = await repo.claimWork({
|
|
938
|
-
collectionId: work.collectionId,
|
|
939
|
-
contentId: work.contentId,
|
|
940
|
-
workVersion: work.workVersion,
|
|
941
|
-
leaseDurationSeconds: MEDIA_USAGE_WORK_PROCESSING_LIMITS.leaseDurationSeconds
|
|
942
|
-
});
|
|
943
|
-
if (!claimed) return {
|
|
944
|
-
outcome: "claim_lost",
|
|
945
|
-
claimed: false
|
|
946
|
-
};
|
|
947
|
-
try {
|
|
948
|
-
return (await runClaimedBatch(db, [claimed])).get(workResultKey(claimed)) ?? {
|
|
949
|
-
outcome: "claim_lost",
|
|
950
|
-
claimed: false
|
|
951
|
-
};
|
|
952
|
-
} catch (error) {
|
|
953
|
-
const outcome = (await repo.retryClaimedWorkBatch({
|
|
954
|
-
work: [workLease(claimed)],
|
|
955
|
-
errorCode: "MEDIA_USAGE_PROCESSING_FAILED",
|
|
956
|
-
retryDelaySeconds: MEDIA_USAGE_WORK_PROCESSING_LIMITS.retryBaseSeconds,
|
|
957
|
-
maxAttempts: MEDIA_USAGE_WORK_PROCESSING_LIMITS.maxAttempts
|
|
958
|
-
})).get(workIdentityKey(claimed)) ?? "superseded";
|
|
959
|
-
if (outcome === "failed") await new MediaUsageRepository(db).recordIncrementalFailure({
|
|
960
|
-
collectionId: claimed.collectionId,
|
|
961
|
-
collectionSlug: claimed.collectionSlug,
|
|
962
|
-
contentId: claimed.contentId,
|
|
963
|
-
workVersion: claimed.workVersion,
|
|
964
|
-
errorCode: "MEDIA_USAGE_PROCESSING_FAILED"
|
|
965
|
-
});
|
|
966
|
-
console.error("[media-usage:work] Immediate processing failed:", error);
|
|
967
|
-
return {
|
|
968
|
-
outcome,
|
|
969
|
-
claimed: true
|
|
970
|
-
};
|
|
971
|
-
}
|
|
972
|
-
}
|
|
973
|
-
async function processDueMediaUsageWork(db, options = {}) {
|
|
974
|
-
const startedAt = Date.now();
|
|
975
|
-
const result = {
|
|
976
|
-
candidateCount: 0,
|
|
977
|
-
claimedCount: 0,
|
|
978
|
-
completedCount: 0,
|
|
979
|
-
retryCount: 0,
|
|
980
|
-
failedCount: 0,
|
|
981
|
-
supersededCount: 0,
|
|
982
|
-
obsoleteCount: 0,
|
|
983
|
-
durationMs: 0
|
|
984
|
-
};
|
|
985
|
-
if (!options.activationKnownActive && !await isIncrementalCaptureActive(db)) {
|
|
986
|
-
result.durationMs = Date.now() - startedAt;
|
|
987
|
-
return result;
|
|
988
|
-
}
|
|
989
|
-
await new MediaUsageRepository(db).recoverIncrementalFinalizations();
|
|
990
|
-
const repo = new MediaUsageWorkRepository(db);
|
|
991
|
-
const candidates = await repo.claimDueWorkBatch({
|
|
992
|
-
limit: MEDIA_USAGE_WORK_PROCESSING_LIMITS.candidatesPerTick,
|
|
993
|
-
leaseDurationSeconds: MEDIA_USAGE_WORK_PROCESSING_LIMITS.leaseDurationSeconds
|
|
994
|
-
});
|
|
995
|
-
result.candidateCount = candidates.length > 0 || !await repo.hasNonterminalWork() ? candidates.length : 1;
|
|
996
|
-
const processedBatch = await processClaimedCollections(db, candidates);
|
|
997
|
-
for (const candidate of candidates) {
|
|
998
|
-
const processed = processedBatch.get(workResultKey(candidate)) ?? {
|
|
999
|
-
outcome: "claim_lost",
|
|
1000
|
-
claimed: false
|
|
1001
|
-
};
|
|
1002
|
-
if (processed.claimed) result.claimedCount++;
|
|
1003
|
-
if (processed.outcome === "completed") result.completedCount++;
|
|
1004
|
-
if (processed.outcome === "retry") result.retryCount++;
|
|
1005
|
-
if (processed.outcome === "failed") result.failedCount++;
|
|
1006
|
-
if (processed.outcome === "superseded") result.supersededCount++;
|
|
1007
|
-
if (processed.outcome === "obsolete") result.obsoleteCount++;
|
|
1008
|
-
}
|
|
1009
|
-
result.durationMs = Date.now() - startedAt;
|
|
1010
|
-
return result;
|
|
1011
|
-
}
|
|
1012
|
-
async function processClaimedCollections(db, candidates) {
|
|
1013
|
-
const processed = /* @__PURE__ */ new Map();
|
|
1014
|
-
const byCollection = /* @__PURE__ */ new Map();
|
|
1015
|
-
for (const candidate of candidates) {
|
|
1016
|
-
const key = collectionResultKey(candidate);
|
|
1017
|
-
const collection = byCollection.get(key) ?? [];
|
|
1018
|
-
collection.push(candidate);
|
|
1019
|
-
byCollection.set(key, collection);
|
|
1020
|
-
}
|
|
1021
|
-
for (const collection of byCollection.values()) try {
|
|
1022
|
-
for (const [key, result] of await runClaimedBatch(db, collection)) processed.set(key, result);
|
|
1023
|
-
} catch (error) {
|
|
1024
|
-
for (const [key, result] of await retryFailedClaimedCollection(db, collection)) processed.set(key, result);
|
|
1025
|
-
console.error("[media-usage:work] Collection processing failed:", error);
|
|
1026
|
-
}
|
|
1027
|
-
return processed;
|
|
1028
|
-
}
|
|
1029
|
-
async function retryFailedClaimedCollection(db, candidates) {
|
|
1030
|
-
const transitioned = await new MediaUsageWorkRepository(db).retryClaimedWorkBatch({
|
|
1031
|
-
work: candidates.map(workLease),
|
|
1032
|
-
errorCode: "MEDIA_USAGE_PROCESSING_FAILED",
|
|
1033
|
-
retryDelaySeconds: MEDIA_USAGE_WORK_PROCESSING_LIMITS.retryBaseSeconds,
|
|
1034
|
-
maxAttempts: MEDIA_USAGE_WORK_PROCESSING_LIMITS.maxAttempts
|
|
1035
|
-
});
|
|
1036
|
-
const processed = /* @__PURE__ */ new Map();
|
|
1037
|
-
const failedCollectionIds = /* @__PURE__ */ new Set();
|
|
1038
|
-
for (const candidate of candidates) {
|
|
1039
|
-
const state = transitioned.get(workIdentityKey(candidate));
|
|
1040
|
-
if (state === "failed") failedCollectionIds.add(candidate.collectionId);
|
|
1041
|
-
processed.set(workResultKey(candidate), {
|
|
1042
|
-
outcome: state ?? "superseded",
|
|
1043
|
-
claimed: true
|
|
1044
|
-
});
|
|
1045
|
-
}
|
|
1046
|
-
await new MediaUsageRepository(db).recordIncrementalFailuresByCollection({
|
|
1047
|
-
collectionIds: [...failedCollectionIds],
|
|
1048
|
-
errorCode: "MEDIA_USAGE_PROCESSING_FAILED"
|
|
1049
|
-
});
|
|
1050
|
-
return processed;
|
|
1051
|
-
}
|
|
1052
|
-
async function runClaimedBatch(db, candidates) {
|
|
1053
|
-
return isPostgres(db) ? withTransaction(db, (trx) => processClaimedBatch(trx, new MediaUsageWorkRepository(trx), candidates)) : processClaimedBatch(db, new MediaUsageWorkRepository(db), candidates);
|
|
1054
|
-
}
|
|
1055
|
-
async function processClaimedBatch(db, repo, candidates) {
|
|
1056
|
-
const results = /* @__PURE__ */ new Map();
|
|
1057
|
-
const locked = await repo.lockClaimedWorkBatch(candidates.map(workLease));
|
|
1058
|
-
const owned = [];
|
|
1059
|
-
for (const candidate of candidates) if (locked.has(workIdentityKey(candidate))) owned.push(candidate);
|
|
1060
|
-
else results.set(workResultKey(candidate), {
|
|
1061
|
-
outcome: "superseded",
|
|
1062
|
-
claimed: true
|
|
1063
|
-
});
|
|
1064
|
-
const currentCollections = await findCurrentCollectionIdentities(db, owned);
|
|
1065
|
-
const current = [];
|
|
1066
|
-
const obsolete = [];
|
|
1067
|
-
for (const candidate of owned) if (currentCollections.has(collectionResultKey(candidate))) current.push(candidate);
|
|
1068
|
-
else obsolete.push(candidate);
|
|
1069
|
-
const obsoleteCompleted = await repo.completeWorkBatch(obsolete.map(workLease));
|
|
1070
|
-
for (const candidate of obsolete) results.set(workResultKey(candidate), {
|
|
1071
|
-
outcome: obsoleteCompleted.has(workIdentityKey(candidate)) ? "obsolete" : "superseded",
|
|
1072
|
-
claimed: true
|
|
1073
|
-
});
|
|
1074
|
-
if (current.length === 0) return results;
|
|
1075
|
-
const refreshes = await refreshContentMediaUsageForWorkBatch(db, current, { shouldContinue: canContinueBulkWork });
|
|
1076
|
-
const successful = [];
|
|
1077
|
-
const unstarted = [];
|
|
1078
|
-
const failedRefreshes = [];
|
|
1079
|
-
for (const candidate of current) {
|
|
1080
|
-
const refresh = refreshes.get(contentRefreshKey(candidate.collectionId, candidate.contentId));
|
|
1081
|
-
if (refresh?.success) successful.push(candidate);
|
|
1082
|
-
else if (!refresh) unstarted.push(candidate);
|
|
1083
|
-
else failedRefreshes.push({
|
|
1084
|
-
candidate,
|
|
1085
|
-
refresh
|
|
1086
|
-
});
|
|
1087
|
-
}
|
|
1088
|
-
const terminalFailureCollections = /* @__PURE__ */ new Map();
|
|
1089
|
-
const failureGroups = /* @__PURE__ */ new Map();
|
|
1090
|
-
for (const failure of failedRefreshes) {
|
|
1091
|
-
const errorCode = processingErrorCode(failure.refresh.errorCode);
|
|
1092
|
-
const terminal = errorCode === "MEDIA_USAGE_RESOURCE_LIMIT" || failure.candidate.attemptCount + 1 >= MEDIA_USAGE_WORK_PROCESSING_LIMITS.maxAttempts;
|
|
1093
|
-
const delay = retryDelaySeconds(failure.candidate.attemptCount);
|
|
1094
|
-
const key = `${errorCode}\u0000${terminal ? "terminal" : String(delay)}`;
|
|
1095
|
-
const group = failureGroups.get(key) ?? {
|
|
1096
|
-
errorCode,
|
|
1097
|
-
retryDelaySeconds: delay,
|
|
1098
|
-
terminal,
|
|
1099
|
-
candidates: []
|
|
1100
|
-
};
|
|
1101
|
-
group.candidates.push(failure.candidate);
|
|
1102
|
-
failureGroups.set(key, group);
|
|
1103
|
-
}
|
|
1104
|
-
for (const group of failureGroups.values()) {
|
|
1105
|
-
const transitioned = await repo.retryClaimedWorkBatch({
|
|
1106
|
-
work: group.candidates.map(workLease),
|
|
1107
|
-
errorCode: group.errorCode,
|
|
1108
|
-
retryDelaySeconds: group.retryDelaySeconds,
|
|
1109
|
-
maxAttempts: group.terminal ? 1 : MEDIA_USAGE_WORK_PROCESSING_LIMITS.maxAttempts
|
|
1110
|
-
});
|
|
1111
|
-
for (const candidate of group.candidates) {
|
|
1112
|
-
const state = transitioned.get(workIdentityKey(candidate));
|
|
1113
|
-
if (state === "failed") {
|
|
1114
|
-
const collections = terminalFailureCollections.get(group.errorCode) ?? /* @__PURE__ */ new Set();
|
|
1115
|
-
collections.add(candidate.collectionId);
|
|
1116
|
-
terminalFailureCollections.set(group.errorCode, collections);
|
|
1117
|
-
}
|
|
1118
|
-
results.set(workResultKey(candidate), {
|
|
1119
|
-
outcome: state ?? "superseded",
|
|
1120
|
-
claimed: true
|
|
1121
|
-
});
|
|
1122
|
-
}
|
|
1123
|
-
}
|
|
1124
|
-
for (const [errorCode, collectionIds] of terminalFailureCollections) await new MediaUsageRepository(db).recordIncrementalFailuresByCollection({
|
|
1125
|
-
collectionIds: [...collectionIds],
|
|
1126
|
-
errorCode
|
|
1127
|
-
});
|
|
1128
|
-
const released = await repo.releaseClaimedWorkBatch(unstarted.map(workLease));
|
|
1129
|
-
for (const candidate of unstarted) results.set(workResultKey(candidate), {
|
|
1130
|
-
outcome: released.has(workIdentityKey(candidate)) ? "not_due" : "superseded",
|
|
1131
|
-
claimed: true
|
|
1132
|
-
});
|
|
1133
|
-
const usage = new MediaUsageRepository(db);
|
|
1134
|
-
const successfulByCollection = /* @__PURE__ */ new Map();
|
|
1135
|
-
for (const candidate of successful) {
|
|
1136
|
-
const key = collectionResultKey(candidate);
|
|
1137
|
-
const collection = successfulByCollection.get(key) ?? [];
|
|
1138
|
-
collection.push(candidate);
|
|
1139
|
-
successfulByCollection.set(key, collection);
|
|
1140
|
-
}
|
|
1141
|
-
const readyToComplete = [];
|
|
1142
|
-
const deferredCompletion = [];
|
|
1143
|
-
const lostFinalization = [];
|
|
1144
|
-
let pendingFinalizationQueries = 2;
|
|
1145
|
-
for (const collection of successfulByCollection.values()) {
|
|
1146
|
-
const first = collection[0];
|
|
1147
|
-
if (!first) continue;
|
|
1148
|
-
const metrics = getRequestContext()?.metrics;
|
|
1149
|
-
if (metrics && metrics.dbCount + pendingFinalizationQueries + 4 > 900) {
|
|
1150
|
-
deferredCompletion.push(...collection);
|
|
1151
|
-
continue;
|
|
1152
|
-
}
|
|
1153
|
-
if ((await usage.prepareIncrementalFinalization({
|
|
1154
|
-
collectionId: first.collectionId,
|
|
1155
|
-
collectionSlug: first.collectionSlug
|
|
1156
|
-
})).outcome !== "lost") {
|
|
1157
|
-
readyToComplete.push(...collection);
|
|
1158
|
-
pendingFinalizationQueries += 2;
|
|
1159
|
-
continue;
|
|
1160
|
-
}
|
|
1161
|
-
lostFinalization.push(...collection);
|
|
1162
|
-
pendingFinalizationQueries += 2;
|
|
1163
|
-
}
|
|
1164
|
-
const lostTransitions = await repo.retryClaimedWorkBatch({
|
|
1165
|
-
work: lostFinalization.map(workLease),
|
|
1166
|
-
errorCode: "MEDIA_USAGE_GENERATION_CONFLICT",
|
|
1167
|
-
retryDelaySeconds: MEDIA_USAGE_WORK_PROCESSING_LIMITS.retryBaseSeconds,
|
|
1168
|
-
maxAttempts: MEDIA_USAGE_WORK_PROCESSING_LIMITS.maxAttempts
|
|
1169
|
-
});
|
|
1170
|
-
const lostFailedCollections = /* @__PURE__ */ new Set();
|
|
1171
|
-
for (const candidate of lostFinalization) {
|
|
1172
|
-
const state = lostTransitions.get(workIdentityKey(candidate));
|
|
1173
|
-
if (state === "failed") lostFailedCollections.add(candidate.collectionId);
|
|
1174
|
-
results.set(workResultKey(candidate), {
|
|
1175
|
-
outcome: state ?? "superseded",
|
|
1176
|
-
claimed: true
|
|
1177
|
-
});
|
|
1178
|
-
}
|
|
1179
|
-
await usage.recordIncrementalFailuresByCollection({
|
|
1180
|
-
collectionIds: [...lostFailedCollections],
|
|
1181
|
-
errorCode: "MEDIA_USAGE_GENERATION_CONFLICT"
|
|
1182
|
-
});
|
|
1183
|
-
const deferred = await repo.releaseClaimedWorkBatch(deferredCompletion.map(workLease));
|
|
1184
|
-
for (const candidate of deferredCompletion) results.set(workResultKey(candidate), {
|
|
1185
|
-
outcome: deferred.has(workIdentityKey(candidate)) ? "not_due" : "superseded",
|
|
1186
|
-
claimed: true
|
|
1187
|
-
});
|
|
1188
|
-
const completed = await repo.completeWorkBatch(readyToComplete.map(workLease));
|
|
1189
|
-
const completedCollections = /* @__PURE__ */ new Map();
|
|
1190
|
-
for (const candidate of readyToComplete) {
|
|
1191
|
-
const didComplete = completed.has(workIdentityKey(candidate));
|
|
1192
|
-
results.set(workResultKey(candidate), {
|
|
1193
|
-
outcome: didComplete ? "completed" : "superseded",
|
|
1194
|
-
claimed: true
|
|
1195
|
-
});
|
|
1196
|
-
if (didComplete) completedCollections.set(collectionResultKey(candidate), candidate);
|
|
1197
|
-
}
|
|
1198
|
-
for (const collection of completedCollections.values()) await usage.recordIncrementalSuccess({
|
|
1199
|
-
collectionId: collection.collectionId,
|
|
1200
|
-
collectionSlug: collection.collectionSlug
|
|
1201
|
-
});
|
|
1202
|
-
return results;
|
|
1203
|
-
}
|
|
1204
|
-
async function findCurrentCollectionIdentities(db, candidates) {
|
|
1205
|
-
const identities = new Map(candidates.map((candidate) => [collectionResultKey(candidate), candidate]));
|
|
1206
|
-
const current = /* @__PURE__ */ new Set();
|
|
1207
|
-
for (const batch of chunkCollectionIds(Array.from(identities.values(), (item) => item.collectionId))) {
|
|
1208
|
-
const rows = await db.selectFrom("_emdash_collections").select(["id", "slug"]).where("id", "in", batch).execute();
|
|
1209
|
-
for (const row of rows) current.add(`${row.id}\u0000${row.slug}`);
|
|
1210
|
-
}
|
|
1211
|
-
return current;
|
|
1212
|
-
}
|
|
1213
|
-
function workLease(work) {
|
|
1214
|
-
if (!work.leaseToken) throw new Error("Claimed media usage work requires a lease token");
|
|
1215
|
-
return {
|
|
1216
|
-
collectionId: work.collectionId,
|
|
1217
|
-
contentId: work.contentId,
|
|
1218
|
-
workVersion: work.workVersion,
|
|
1219
|
-
leaseToken: work.leaseToken
|
|
1220
|
-
};
|
|
1221
|
-
}
|
|
1222
|
-
function workIdentityKey(work) {
|
|
1223
|
-
return `${work.collectionId}\u0000${work.contentId}\u0000${String(work.workVersion)}`;
|
|
1224
|
-
}
|
|
1225
|
-
function workResultKey(work) {
|
|
1226
|
-
return workIdentityKey(work);
|
|
1227
|
-
}
|
|
1228
|
-
function collectionResultKey(work) {
|
|
1229
|
-
return `${work.collectionId}\u0000${work.collectionSlug}`;
|
|
1230
|
-
}
|
|
1231
|
-
function chunkCollectionIds(ids) {
|
|
1232
|
-
const unique = [...new Set(ids)];
|
|
1233
|
-
const batches = [];
|
|
1234
|
-
for (let index = 0; index < unique.length; index += 50) batches.push(unique.slice(index, index + 50));
|
|
1235
|
-
return batches;
|
|
1236
|
-
}
|
|
1237
|
-
function canContinueBulkWork() {
|
|
1238
|
-
const metrics = getRequestContext()?.metrics;
|
|
1239
|
-
return !metrics || metrics.dbCount + 150 <= 900;
|
|
1240
|
-
}
|
|
1241
|
-
async function isIncrementalCaptureActive(db) {
|
|
1242
|
-
return (await db.selectFrom("_emdash_media_usage_activation").select("state").where("task_key", "=", "incremental_capture").executeTakeFirst())?.state === "active";
|
|
1243
|
-
}
|
|
1244
|
-
function retryDelaySeconds(attemptCount) {
|
|
1245
|
-
const exponential = Math.min(MEDIA_USAGE_WORK_PROCESSING_LIMITS.retryMaxSeconds, MEDIA_USAGE_WORK_PROCESSING_LIMITS.retryBaseSeconds * 2 ** attemptCount);
|
|
1246
|
-
const jitter = Math.floor(exponential * MEDIA_USAGE_WORK_PROCESSING_LIMITS.retryJitterRatio * Math.random());
|
|
1247
|
-
return Math.min(MEDIA_USAGE_WORK_PROCESSING_LIMITS.retryMaxSeconds, exponential + jitter);
|
|
1248
|
-
}
|
|
1249
|
-
function processingErrorCode(errorCode) {
|
|
1250
|
-
if (errorCode === "DRAFT_REVISION_NOT_FOUND" || errorCode === "DRAFT_REVISION_MISMATCH" || errorCode === "DRAFT_REVISION_INVALID") return "MEDIA_USAGE_SNAPSHOT_FAILED";
|
|
1251
|
-
if (errorCode === "CONTENT_USAGE_GENERATION_CONFLICT") return "MEDIA_USAGE_GENERATION_CONFLICT";
|
|
1252
|
-
if (errorCode === "CONTENT_USAGE_RESOURCE_LIMIT") return "MEDIA_USAGE_RESOURCE_LIMIT";
|
|
1253
|
-
return "MEDIA_USAGE_PROCESSING_FAILED";
|
|
1254
|
-
}
|
|
1255
|
-
|
|
1256
|
-
//#endregion
|
|
1257
|
-
//#region src/media/usage/maintenance-engine.ts
|
|
1258
|
-
const MEDIA_USAGE_MAINTENANCE_LIMITS = Object.freeze({
|
|
1259
|
-
eventQueryCeiling: 900,
|
|
1260
|
-
maxStepQueries: 150
|
|
1261
|
-
});
|
|
1262
|
-
const TASK_CLASSES = [
|
|
1263
|
-
"collection_deletion",
|
|
1264
|
-
"entry_work",
|
|
1265
|
-
"reconciliation"
|
|
1266
|
-
];
|
|
1267
|
-
async function runMediaUsageMaintenanceStep(db) {
|
|
1268
|
-
const activation = await db.selectFrom("_emdash_media_usage_activation").select(["state", "runtime_generation"]).where("task_key", "=", "incremental_capture").executeTakeFirst();
|
|
1269
|
-
if (activation?.state !== "active" || activation.runtime_generation !== MEDIA_USAGE_ACTIVATION_RUNTIME_GENERATION) return runActivationStep(db);
|
|
1270
|
-
let blocked = false;
|
|
1271
|
-
let blockedReconciliation = false;
|
|
1272
|
-
let madeProgress = false;
|
|
1273
|
-
for (const taskClass of TASK_CLASSES) {
|
|
1274
|
-
const metrics = getRequestContext()?.metrics;
|
|
1275
|
-
if (metrics && !canStartMediaUsageMaintenanceStep(metrics)) return madeProgress ? {
|
|
1276
|
-
state: "progress",
|
|
1277
|
-
continuation: { kind: "immediate" }
|
|
1278
|
-
} : {
|
|
1279
|
-
state: "blocked",
|
|
1280
|
-
continuation: { kind: "immediate" }
|
|
1281
|
-
};
|
|
1282
|
-
const outcome = await runTaskClass(db, taskClass);
|
|
1283
|
-
if (outcome === "inactive") return inactiveResult();
|
|
1284
|
-
if (outcome === "progress") madeProgress = true;
|
|
1285
|
-
if (outcome === "blocked") {
|
|
1286
|
-
blocked = true;
|
|
1287
|
-
if (taskClass === "reconciliation") blockedReconciliation = true;
|
|
1288
|
-
}
|
|
1289
|
-
}
|
|
1290
|
-
if (madeProgress) return {
|
|
1291
|
-
state: "progress",
|
|
1292
|
-
continuation: { kind: "immediate" }
|
|
1293
|
-
};
|
|
1294
|
-
if (blockedReconciliation && await new MediaUsageReconciliationRepository(db).wakeDrainedBarrierCandidate()) return {
|
|
1295
|
-
state: "progress",
|
|
1296
|
-
continuation: { kind: "immediate" }
|
|
1297
|
-
};
|
|
1298
|
-
if (blocked) return {
|
|
1299
|
-
state: "blocked",
|
|
1300
|
-
continuation: {
|
|
1301
|
-
kind: "delayed",
|
|
1302
|
-
delaySeconds: 30
|
|
1303
|
-
}
|
|
1304
|
-
};
|
|
1305
|
-
return {
|
|
1306
|
-
state: "idle",
|
|
1307
|
-
continuation: { kind: "none" }
|
|
1308
|
-
};
|
|
1309
|
-
}
|
|
1310
|
-
async function runActivationStep(db) {
|
|
1311
|
-
try {
|
|
1312
|
-
const result = await continueMediaUsageActivation(db);
|
|
1313
|
-
if (result.outcome === "activating" || result.outcome === "active") return {
|
|
1314
|
-
state: "progress",
|
|
1315
|
-
continuation: { kind: "immediate" }
|
|
1316
|
-
};
|
|
1317
|
-
if (result.outcome === "lease_active" || result.outcome === "conflict") return {
|
|
1318
|
-
state: "blocked",
|
|
1319
|
-
continuation: {
|
|
1320
|
-
kind: "delayed",
|
|
1321
|
-
delaySeconds: 30
|
|
1322
|
-
}
|
|
1323
|
-
};
|
|
1324
|
-
return inactiveResult();
|
|
1325
|
-
} catch (error) {
|
|
1326
|
-
if (error instanceof MediaUsageActivationVersionMismatchError) return inactiveResult();
|
|
1327
|
-
throw error;
|
|
1328
|
-
}
|
|
1329
|
-
}
|
|
1330
|
-
async function runTaskClass(db, taskClass) {
|
|
1331
|
-
if (taskClass === "entry_work") {
|
|
1332
|
-
const result = await processDueMediaUsageWork(db, { activationKnownActive: true });
|
|
1333
|
-
if (result.claimedCount > 0) return "progress";
|
|
1334
|
-
return result.candidateCount > 0 ? "blocked" : "idle";
|
|
1335
|
-
}
|
|
1336
|
-
if (taskClass === "collection_deletion") {
|
|
1337
|
-
const result = await processDueMediaUsageCollectionDeletions(db);
|
|
1338
|
-
if (result.claimedCount > 0) return "progress";
|
|
1339
|
-
return result.candidateCount > 0 ? "blocked" : "idle";
|
|
1340
|
-
}
|
|
1341
|
-
const result = await processDueMediaUsageReconciliationDetailed(db, { activationKnownActive: true });
|
|
1342
|
-
if (result.outcome === "inactive") return "inactive";
|
|
1343
|
-
if (result.consumedUnit) return "progress";
|
|
1344
|
-
return result.outcome === "claim_lost" || result.hasDeferredCandidate ? "blocked" : "idle";
|
|
1345
|
-
}
|
|
1346
|
-
function inactiveResult() {
|
|
1347
|
-
return {
|
|
1348
|
-
state: "inactive",
|
|
1349
|
-
continuation: { kind: "none" }
|
|
1350
|
-
};
|
|
1351
|
-
}
|
|
1352
|
-
function canStartMediaUsageMaintenanceStep(metrics) {
|
|
1353
|
-
return metrics.dbCount + MEDIA_USAGE_MAINTENANCE_LIMITS.maxStepQueries <= MEDIA_USAGE_MAINTENANCE_LIMITS.eventQueryCeiling;
|
|
1354
|
-
}
|
|
1355
|
-
|
|
1356
|
-
//#endregion
|
|
1357
|
-
//#region src/api/handlers/media-usage.ts
|
|
1358
|
-
var media_usage_exports = /* @__PURE__ */ __exportAll({
|
|
1359
|
-
aggregateMediaUsageCoverageStatus: () => aggregateMediaUsageCoverageStatus,
|
|
1360
|
-
handleMediaUsageDetails: () => handleMediaUsageDetails,
|
|
1361
|
-
handleMediaUsageProgress: () => handleMediaUsageProgress,
|
|
1362
|
-
handleMediaUsageProgressAdvance: () => handleMediaUsageProgressAdvance,
|
|
1363
|
-
handleMediaUsageRepair: () => handleMediaUsageRepair,
|
|
1364
|
-
handleMediaUsageSummaries: () => handleMediaUsageSummaries,
|
|
1365
|
-
toMediaUsageRepairResponse: () => toMediaUsageRepairResponse
|
|
1366
|
-
});
|
|
1367
|
-
async function handleMediaUsageProgress(db) {
|
|
1368
|
-
try {
|
|
1369
|
-
const progress = await new MediaUsageRepository(db).findCollectionProgress();
|
|
1370
|
-
if (!progress) return {
|
|
1371
|
-
success: false,
|
|
1372
|
-
error: {
|
|
1373
|
-
code: ErrorCode.MEDIA_USAGE_PROGRESS_NOT_ACTIVE,
|
|
1374
|
-
message: "Media Usage is not active"
|
|
1375
|
-
}
|
|
1376
|
-
};
|
|
1377
|
-
return {
|
|
1378
|
-
success: true,
|
|
1379
|
-
data: progress
|
|
1380
|
-
};
|
|
1381
|
-
} catch (error) {
|
|
1382
|
-
if (error instanceof MediaUsageActivationVersionMismatchError) return {
|
|
1383
|
-
success: false,
|
|
1384
|
-
error: {
|
|
1385
|
-
code: ErrorCode.MEDIA_USAGE_ACTIVATION_VERSION_MISMATCH,
|
|
1386
|
-
message: "Media Usage activation version does not match this runtime"
|
|
1387
|
-
}
|
|
1388
|
-
};
|
|
1389
|
-
console.error("[media-usage] progress read failed:", error);
|
|
1390
|
-
return {
|
|
1391
|
-
success: false,
|
|
1392
|
-
error: {
|
|
1393
|
-
code: ErrorCode.MEDIA_USAGE_PROGRESS_READ_ERROR,
|
|
1394
|
-
message: "Failed to read media usage progress"
|
|
1395
|
-
}
|
|
1396
|
-
};
|
|
1397
|
-
}
|
|
1398
|
-
}
|
|
1399
|
-
async function handleMediaUsageProgressAdvance(db) {
|
|
1400
|
-
try {
|
|
1401
|
-
const step = await runMediaUsageMaintenanceStep(db);
|
|
1402
|
-
const activation = await getMediaUsageActivationStatus(db);
|
|
1403
|
-
if (activation.state === "expanded") return {
|
|
1404
|
-
success: false,
|
|
1405
|
-
error: {
|
|
1406
|
-
code: ErrorCode.MEDIA_USAGE_PROGRESS_NOT_ACTIVE,
|
|
1407
|
-
message: "Media Usage activation has not started"
|
|
1408
|
-
}
|
|
1409
|
-
};
|
|
1410
|
-
const progress = activation.state === "active" ? await new MediaUsageRepository(db).findCollectionProgress() : null;
|
|
1411
|
-
return {
|
|
1412
|
-
success: true,
|
|
1413
|
-
data: {
|
|
1414
|
-
activation,
|
|
1415
|
-
progress,
|
|
1416
|
-
nextRequestInMs: continuationDelayMs(step.continuation, progress)
|
|
1417
|
-
}
|
|
1418
|
-
};
|
|
1419
|
-
} catch (error) {
|
|
1420
|
-
if (error instanceof MediaUsageActivationVersionMismatchError) return {
|
|
1421
|
-
success: false,
|
|
1422
|
-
error: {
|
|
1423
|
-
code: ErrorCode.MEDIA_USAGE_ACTIVATION_VERSION_MISMATCH,
|
|
1424
|
-
message: "Media Usage activation version does not match this runtime"
|
|
1425
|
-
}
|
|
1426
|
-
};
|
|
1427
|
-
console.error("[media-usage] progress advance failed:", error);
|
|
1428
|
-
return {
|
|
1429
|
-
success: false,
|
|
1430
|
-
error: {
|
|
1431
|
-
code: ErrorCode.MEDIA_USAGE_PROGRESS_ADVANCE_ERROR,
|
|
1432
|
-
message: "Failed to advance media usage progress"
|
|
1433
|
-
}
|
|
1434
|
-
};
|
|
1435
|
-
}
|
|
1436
|
-
}
|
|
1437
|
-
function continuationDelayMs(continuation, progress) {
|
|
1438
|
-
if (progress?.status === "needs_attention") return null;
|
|
1439
|
-
if (continuation.kind === "immediate") return 0;
|
|
1440
|
-
if (continuation.kind === "delayed") return 3e4;
|
|
1441
|
-
if (progress?.status === "indexing") return 0;
|
|
1442
|
-
return null;
|
|
1443
|
-
}
|
|
1444
|
-
function aggregateMediaUsageCoverageStatus(scopes) {
|
|
1445
|
-
const statuses = scopes.map(normalizeMediaUsageCoverageStatus);
|
|
1446
|
-
if (statuses.every((status) => status === "complete")) return "complete";
|
|
1447
|
-
if (statuses.includes("unknown")) return "unknown";
|
|
1448
|
-
if (statuses.includes("running")) return "running";
|
|
1449
|
-
if (statuses.includes("stale")) return "stale";
|
|
1450
|
-
if (statuses.includes("partial")) return "partial";
|
|
1451
|
-
if (statuses.every((status) => status === "never")) return "never";
|
|
1452
|
-
if (statuses.every((status) => status === "failed")) return "failed";
|
|
1453
|
-
return "partial";
|
|
1454
|
-
}
|
|
1455
|
-
async function handleMediaUsageSummaries(db, mediaIds, options) {
|
|
1456
|
-
if (mediaIds.length === 0) return {
|
|
1457
|
-
success: true,
|
|
1458
|
-
data: {}
|
|
1459
|
-
};
|
|
1460
|
-
try {
|
|
1461
|
-
const repository = new MediaUsageRepository(db);
|
|
1462
|
-
const { coverage, siteSettings } = await loadMediaUsageCoverage(repository);
|
|
1463
|
-
const counts = options.includeCount && coverage.status === "complete" ? await repository.findActiveEntryCountsByMediaIds(mediaIds) : null;
|
|
1464
|
-
const summaries = {};
|
|
1465
|
-
for (const mediaId of new Set(mediaIds)) summaries[mediaId] = {
|
|
1466
|
-
count: counts ? (counts.get(mediaId) ?? 0) + (siteSettings.get(mediaId)?.length ?? 0) : null,
|
|
1467
|
-
coverage
|
|
1468
|
-
};
|
|
1469
|
-
return {
|
|
1470
|
-
success: true,
|
|
1471
|
-
data: summaries
|
|
1472
|
-
};
|
|
1473
|
-
} catch (error) {
|
|
1474
|
-
console.error("[media-usage] summary read failed:", error);
|
|
1475
|
-
return {
|
|
1476
|
-
success: false,
|
|
1477
|
-
error: {
|
|
1478
|
-
code: ErrorCode.MEDIA_USAGE_READ_ERROR,
|
|
1479
|
-
message: "Failed to read media usage"
|
|
1480
|
-
}
|
|
1481
|
-
};
|
|
1482
|
-
}
|
|
1483
|
-
}
|
|
1484
|
-
async function handleMediaUsageDetails(db, mediaId, options) {
|
|
1485
|
-
try {
|
|
1486
|
-
if (!await new MediaRepository(db).findById(mediaId)) return {
|
|
1487
|
-
success: false,
|
|
1488
|
-
error: {
|
|
1489
|
-
code: ErrorCode.NOT_FOUND,
|
|
1490
|
-
message: `Media item not found: ${mediaId}`
|
|
1491
|
-
}
|
|
1492
|
-
};
|
|
1493
|
-
const repository = new MediaUsageRepository(db);
|
|
1494
|
-
const { coverage, siteSettings } = await loadMediaUsageCoverage(repository);
|
|
1495
|
-
const page = await repository.findCurrentEntryUsagePageByMediaId(mediaId, options);
|
|
1496
|
-
return {
|
|
1497
|
-
success: true,
|
|
1498
|
-
data: {
|
|
1499
|
-
items: page.items.map(toMediaUsageEntryDetail),
|
|
1500
|
-
...page.nextCursor ? { nextCursor: page.nextCursor } : {},
|
|
1501
|
-
siteSettings: (siteSettings.get(mediaId) ?? []).map((setting) => ({ setting })),
|
|
1502
|
-
coverage
|
|
1503
|
-
}
|
|
1504
|
-
};
|
|
1505
|
-
} catch (error) {
|
|
1506
|
-
if (error instanceof InvalidCursorError) return {
|
|
1507
|
-
success: false,
|
|
1508
|
-
error: {
|
|
1509
|
-
code: ErrorCode.INVALID_CURSOR,
|
|
1510
|
-
message: error.message
|
|
1511
|
-
}
|
|
1512
|
-
};
|
|
1513
|
-
console.error("[media-usage] detail read failed:", error);
|
|
1514
|
-
return {
|
|
1515
|
-
success: false,
|
|
1516
|
-
error: {
|
|
1517
|
-
code: ErrorCode.MEDIA_USAGE_READ_ERROR,
|
|
1518
|
-
message: "Failed to read media usage"
|
|
1519
|
-
}
|
|
1520
|
-
};
|
|
1521
|
-
}
|
|
1522
|
-
}
|
|
1523
|
-
async function handleMediaUsageRepair(db, input) {
|
|
1524
|
-
try {
|
|
1525
|
-
let result;
|
|
1526
|
-
if (input.scope === "collection") result = await repairContentMediaUsageCollection(db, { collectionSlug: input.collection });
|
|
1527
|
-
else if (input.scope === "all") result = await repairContentMediaUsageAll(db);
|
|
1528
|
-
else return {
|
|
1529
|
-
success: false,
|
|
1530
|
-
error: {
|
|
1531
|
-
code: ErrorCode.VALIDATION_ERROR,
|
|
1532
|
-
message: "Invalid media usage repair request"
|
|
1533
|
-
}
|
|
1534
|
-
};
|
|
1535
|
-
return {
|
|
1536
|
-
success: true,
|
|
1537
|
-
data: toMediaUsageRepairResponse(result)
|
|
1538
|
-
};
|
|
1539
|
-
} catch (error) {
|
|
1540
|
-
console.error("[media-usage] repair failed:", error);
|
|
1541
|
-
return {
|
|
1542
|
-
success: false,
|
|
1543
|
-
error: {
|
|
1544
|
-
code: ErrorCode.MEDIA_USAGE_REPAIR_ERROR,
|
|
1545
|
-
message: "Failed to repair media usage"
|
|
1546
|
-
}
|
|
1547
|
-
};
|
|
1548
|
-
}
|
|
1549
|
-
}
|
|
1550
|
-
function toMediaUsageRepairResponse(result) {
|
|
1551
|
-
const collections = "collections" in result ? result.collections : [result];
|
|
1552
|
-
return {
|
|
1553
|
-
status: result.status,
|
|
1554
|
-
indexedSourceCount: result.indexedSourceCount,
|
|
1555
|
-
failedSourceCount: result.failedSourceCount,
|
|
1556
|
-
skippedSourceCount: result.skippedSourceCount,
|
|
1557
|
-
deletedSourceCount: result.deletedSourceCount,
|
|
1558
|
-
collections: collections.map(toMediaUsageRepairCollectionSummary)
|
|
1559
|
-
};
|
|
1560
|
-
}
|
|
1561
|
-
function toMediaUsageRepairCollectionSummary(result) {
|
|
1562
|
-
return {
|
|
1563
|
-
collection: result.scope.scopeKey,
|
|
1564
|
-
status: result.status,
|
|
1565
|
-
indexedSourceCount: result.indexedSourceCount,
|
|
1566
|
-
failedSourceCount: result.failedSourceCount,
|
|
1567
|
-
skippedSourceCount: result.skippedSourceCount,
|
|
1568
|
-
deletedSourceCount: result.deletedSourceCount,
|
|
1569
|
-
lastErrorCode: result.lastErrorCode,
|
|
1570
|
-
startedAt: result.startedAt,
|
|
1571
|
-
completedAt: result.completedAt
|
|
1572
|
-
};
|
|
1573
|
-
}
|
|
1574
|
-
function normalizeMediaUsageCoverageStatus(scope) {
|
|
1575
|
-
if (scope.status === null) return "never";
|
|
1576
|
-
if (scope.status === "complete") {
|
|
1577
|
-
if (scope.reconciliationRequired) return "stale";
|
|
1578
|
-
return scope.schemaVersion === CONTENT_SOURCE_SCHEMA_VERSION ? "complete" : "stale";
|
|
1579
|
-
}
|
|
1580
|
-
if (scope.status === "never" || scope.status === "running" || scope.status === "partial" || scope.status === "failed" || scope.status === "stale") return scope.status;
|
|
1581
|
-
return "unknown";
|
|
1582
|
-
}
|
|
1583
|
-
async function loadMediaUsageCoverage(repository) {
|
|
1584
|
-
const { scopes, options } = await repository.findCoverageWithOptions({
|
|
1585
|
-
adapterId: CONTENT_MEDIA_USAGE_ADAPTER_ID,
|
|
1586
|
-
scopeType: CONTENT_MEDIA_USAGE_COLLECTION_SCOPE
|
|
1587
|
-
}, MEDIA_USAGE_SITE_SETTING_OPTIONS);
|
|
1588
|
-
return {
|
|
1589
|
-
coverage: {
|
|
1590
|
-
scope: "all_content_collections",
|
|
1591
|
-
status: aggregateMediaUsageCoverageStatus(scopes)
|
|
1592
|
-
},
|
|
1593
|
-
siteSettings: groupSiteSettingMediaUsage(options)
|
|
1594
|
-
};
|
|
1595
|
-
}
|
|
1596
|
-
function toMediaUsageEntryDetail(group) {
|
|
1597
|
-
const preferred = group.sources.find(({ source }) => source.sourceVariant === "draft_overlay") ?? group.sources.find(({ source }) => source.sourceVariant === "columns");
|
|
1598
|
-
if (!preferred) throw new Error("Media usage entry has no supported source");
|
|
1599
|
-
return {
|
|
1600
|
-
collection: group.collectionSlug,
|
|
1601
|
-
contentId: group.contentId,
|
|
1602
|
-
title: preferred.source.contentTitle,
|
|
1603
|
-
slug: preferred.source.contentSlug,
|
|
1604
|
-
locale: preferred.source.locale,
|
|
1605
|
-
status: preferred.source.contentStatus,
|
|
1606
|
-
scheduledAt: preferred.source.contentScheduledAt,
|
|
1607
|
-
deletedAt: group.contentDeletedAt,
|
|
1608
|
-
sources: group.sources.flatMap(({ source, occurrences }) => {
|
|
1609
|
-
if (source.sourceVariant !== "columns" && source.sourceVariant !== "draft_overlay") return [];
|
|
1610
|
-
return [{
|
|
1611
|
-
variant: source.sourceVariant,
|
|
1612
|
-
occurrences: occurrences.map((occurrence) => ({
|
|
1613
|
-
fieldSlug: occurrence.fieldSlug,
|
|
1614
|
-
fieldPath: occurrence.fieldPath,
|
|
1615
|
-
occurrenceIndex: occurrence.occurrenceIndex,
|
|
1616
|
-
referenceType: normalizeMediaUsageReferenceType(occurrence.referenceType)
|
|
1617
|
-
}))
|
|
1618
|
-
}];
|
|
1619
|
-
})
|
|
1620
|
-
};
|
|
1621
|
-
}
|
|
1622
|
-
function normalizeMediaUsageReferenceType(referenceType) {
|
|
1623
|
-
if (referenceType === "image_field" || referenceType === "file_field" || referenceType === "portable_text_image") return referenceType;
|
|
1624
|
-
return "unknown";
|
|
1625
|
-
}
|
|
1626
|
-
|
|
1627
|
-
//#endregion
|
|
1628
|
-
export { handleMediaUsageSummaries as a, handleMediaUsageRepair as i, handleMediaUsageProgress as n, media_usage_exports as o, handleMediaUsageProgressAdvance as r, processMediaUsageWorkAfterWrite as s, handleMediaUsageDetails as t };
|
|
1629
|
-
//# sourceMappingURL=media-usage-De-zeR9E.mjs.map
|