emdash 0.35.0 → 0.37.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/activation-K0kGBWuJ.mjs +382 -0
- package/dist/activation-K0kGBWuJ.mjs.map +1 -0
- package/dist/{adapters-Bb1vG41D.d.mts → adapters-BDQwg236.d.mts} +6 -4
- package/dist/{adapters-Bb1vG41D.d.mts.map → adapters-BDQwg236.d.mts.map} +1 -1
- package/dist/{allowed-origins-DW7sYyqg.mjs → allowed-origins-BGglilcs.mjs} +2 -2
- package/dist/{allowed-origins-DW7sYyqg.mjs.map → allowed-origins-BGglilcs.mjs.map} +1 -1
- package/dist/api/route-utils.d.mts +3 -3
- package/dist/api/route-utils.mjs +23 -21
- package/dist/api/route-utils.mjs.map +1 -1
- package/dist/api/schemas/index.d.mts +2 -2
- package/dist/api/schemas/index.mjs +5 -5
- package/dist/api-Dz6rgoa3.mjs +10040 -0
- package/dist/api-Dz6rgoa3.mjs.map +1 -0
- package/dist/{api-tokens-KO24G1Fd.mjs → api-tokens-BSsQACNe.mjs} +2 -2
- package/dist/{api-tokens-KO24G1Fd.mjs.map → api-tokens-BSsQACNe.mjs.map} +1 -1
- package/dist/{apply-kUDt80-G.mjs → apply-B4SIOxR1.mjs} +34 -35
- package/dist/{apply-kUDt80-G.mjs.map → apply-B4SIOxR1.mjs.map} +1 -1
- package/dist/astro/image-endpoint.mjs +2 -2
- package/dist/astro/image-endpoint.mjs.map +1 -1
- package/dist/astro/index.d.mts +12 -12
- package/dist/astro/index.d.mts.map +1 -1
- package/dist/astro/index.mjs +128 -44
- package/dist/astro/index.mjs.map +1 -1
- package/dist/astro/middleware/auth.d.mts +10 -10
- package/dist/astro/middleware/auth.d.mts.map +1 -1
- package/dist/astro/middleware/auth.mjs +10 -7
- package/dist/astro/middleware/auth.mjs.map +1 -1
- package/dist/astro/middleware/media-usage-write-fence.mjs +2 -2
- package/dist/astro/middleware/redirect.mjs +4 -4
- package/dist/astro/middleware/request-context.mjs +3 -3
- package/dist/astro/middleware/setup.mjs +1 -1
- package/dist/astro/middleware.d.mts +11 -12
- package/dist/astro/middleware.d.mts.map +1 -1
- package/dist/astro/middleware.mjs +237 -1412
- package/dist/astro/middleware.mjs.map +1 -1
- package/dist/astro/routes/api/admin/allowed-domains/_domain_.mjs +6 -6
- package/dist/astro/routes/api/admin/allowed-domains/index.mjs +6 -6
- package/dist/astro/routes/api/admin/api-tokens/_id_.mjs +3 -3
- package/dist/astro/routes/api/admin/api-tokens/index.d.mts.map +1 -1
- package/dist/astro/routes/api/admin/api-tokens/index.mjs +5 -5
- package/dist/astro/routes/api/admin/api-tokens/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/byline-fields/_slug_/usage.mjs +4 -4
- package/dist/astro/routes/api/admin/byline-fields/_slug_.mjs +9 -9
- package/dist/astro/routes/api/admin/byline-fields/index.mjs +9 -9
- package/dist/astro/routes/api/admin/byline-fields/reorder.mjs +9 -9
- package/dist/astro/routes/api/admin/bylines/_id_/index.mjs +16 -16
- package/dist/astro/routes/api/admin/bylines/_id_/translations.mjs +16 -16
- package/dist/astro/routes/api/admin/bylines/index.mjs +16 -16
- package/dist/astro/routes/api/admin/comments/_id_/status.mjs +13 -13
- package/dist/astro/routes/api/admin/comments/_id_.mjs +5 -5
- package/dist/astro/routes/api/admin/comments/bulk.mjs +10 -10
- package/dist/astro/routes/api/admin/comments/counts.mjs +5 -5
- package/dist/astro/routes/api/admin/comments/index.mjs +10 -10
- package/dist/astro/routes/api/admin/hooks/exclusive/_hookName_.mjs +4 -4
- package/dist/astro/routes/api/admin/hooks/exclusive/index.mjs +3 -3
- package/dist/astro/routes/api/admin/media-usage/activation.d.mts +9 -0
- package/dist/astro/routes/api/admin/media-usage/activation.d.mts.map +1 -0
- package/dist/astro/routes/api/admin/media-usage/activation.mjs +46 -0
- package/dist/astro/routes/api/admin/media-usage/activation.mjs.map +1 -0
- package/dist/astro/routes/api/admin/media-usage/collection-deletions/index.mjs +14 -13
- package/dist/astro/routes/api/admin/media-usage/collection-deletions/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/media-usage/collection-deletions/retry.mjs +14 -13
- package/dist/astro/routes/api/admin/media-usage/collection-deletions/retry.mjs.map +1 -1
- package/dist/astro/routes/api/admin/media-usage/progress.d.mts +9 -0
- package/dist/astro/routes/api/admin/media-usage/progress.d.mts.map +1 -0
- package/dist/astro/routes/api/admin/media-usage/progress.mjs +44 -0
- package/dist/astro/routes/api/admin/media-usage/progress.mjs.map +1 -0
- package/dist/astro/routes/api/admin/media-usage/repair.mjs +16 -11
- package/dist/astro/routes/api/admin/media-usage/repair.mjs.map +1 -1
- package/dist/astro/routes/api/admin/media-usage/work/index.mjs +14 -13
- package/dist/astro/routes/api/admin/media-usage/work/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/media-usage/work/retry.mjs +14 -13
- package/dist/astro/routes/api/admin/media-usage/work/retry.mjs.map +1 -1
- package/dist/astro/routes/api/admin/oauth-clients/_id_.mjs +4 -4
- package/dist/astro/routes/api/admin/oauth-clients/_id_.mjs.map +1 -1
- package/dist/astro/routes/api/admin/oauth-clients/index.mjs +4 -4
- package/dist/astro/routes/api/admin/oauth-clients/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/_id_/disable.mjs +55 -49
- package/dist/astro/routes/api/admin/plugins/_id_/disable.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/_id_/enable.mjs +55 -49
- package/dist/astro/routes/api/admin/plugins/_id_/enable.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/_id_/index.mjs +53 -47
- package/dist/astro/routes/api/admin/plugins/_id_/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/_id_/mcp.mjs +4 -4
- package/dist/astro/routes/api/admin/plugins/_id_/settings.mjs +53 -47
- package/dist/astro/routes/api/admin/plugins/_id_/settings.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/_id_/uninstall.mjs +54 -48
- package/dist/astro/routes/api/admin/plugins/_id_/uninstall.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/_id_/update.mjs +54 -48
- package/dist/astro/routes/api/admin/plugins/_id_/update.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/index.mjs +53 -47
- package/dist/astro/routes/api/admin/plugins/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/marketplace/_id_/icon.mjs +2 -2
- package/dist/astro/routes/api/admin/plugins/marketplace/_id_/index.mjs +53 -47
- package/dist/astro/routes/api/admin/plugins/marketplace/_id_/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/marketplace/_id_/install.mjs +54 -48
- package/dist/astro/routes/api/admin/plugins/marketplace/_id_/install.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/marketplace/index.mjs +53 -47
- package/dist/astro/routes/api/admin/plugins/marketplace/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/registry/_id_/uninstall.mjs +54 -48
- package/dist/astro/routes/api/admin/plugins/registry/_id_/uninstall.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/registry/_id_/update.d.mts.map +1 -1
- package/dist/astro/routes/api/admin/plugins/registry/_id_/update.mjs +60 -50
- package/dist/astro/routes/api/admin/plugins/registry/_id_/update.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/registry/artifact.d.mts.map +1 -1
- package/dist/astro/routes/api/admin/plugins/registry/artifact.mjs +179 -139
- package/dist/astro/routes/api/admin/plugins/registry/artifact.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/registry/install.d.mts.map +1 -1
- package/dist/astro/routes/api/admin/plugins/registry/install.mjs +61 -51
- package/dist/astro/routes/api/admin/plugins/registry/install.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/registry/verify.d.mts +8 -0
- package/dist/astro/routes/api/admin/plugins/registry/verify.d.mts.map +1 -0
- package/dist/astro/routes/api/admin/plugins/registry/verify.mjs +93 -0
- package/dist/astro/routes/api/admin/plugins/registry/verify.mjs.map +1 -0
- package/dist/astro/routes/api/admin/plugins/updates.mjs +53 -47
- package/dist/astro/routes/api/admin/plugins/updates.mjs.map +1 -1
- package/dist/astro/routes/api/admin/themes/marketplace/_id_/index.mjs +53 -47
- package/dist/astro/routes/api/admin/themes/marketplace/_id_/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/themes/marketplace/_id_/thumbnail.mjs +2 -2
- package/dist/astro/routes/api/admin/themes/marketplace/index.mjs +53 -47
- package/dist/astro/routes/api/admin/themes/marketplace/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/users/_id_/disable.mjs +2 -2
- package/dist/astro/routes/api/admin/users/_id_/enable.mjs +1 -1
- package/dist/astro/routes/api/admin/users/_id_/index.mjs +7 -7
- package/dist/astro/routes/api/admin/users/_id_/send-recovery.mjs +3 -3
- package/dist/astro/routes/api/admin/users/index.mjs +6 -6
- package/dist/astro/routes/api/auth/dev-bypass.mjs +3 -3
- package/dist/astro/routes/api/auth/invite/accept.mjs +1 -1
- package/dist/astro/routes/api/auth/invite/complete.mjs +11 -11
- package/dist/astro/routes/api/auth/invite/index.mjs +8 -8
- package/dist/astro/routes/api/auth/invite/register-options.mjs +10 -10
- package/dist/astro/routes/api/auth/logout.mjs +2 -2
- package/dist/astro/routes/api/auth/magic-link/send.mjs +10 -10
- package/dist/astro/routes/api/auth/magic-link/verify.mjs +2 -2
- package/dist/astro/routes/api/auth/me.d.mts.map +1 -1
- package/dist/astro/routes/api/auth/me.mjs +19 -9
- package/dist/astro/routes/api/auth/me.mjs.map +1 -1
- package/dist/astro/routes/api/auth/mode.mjs +2 -2
- package/dist/astro/routes/api/auth/oauth/_provider_/callback.mjs +4 -4
- package/dist/astro/routes/api/auth/oauth/_provider_.mjs +2 -2
- package/dist/astro/routes/api/auth/passkey/_id_.mjs +6 -6
- package/dist/astro/routes/api/auth/passkey/index.mjs +1 -1
- package/dist/astro/routes/api/auth/passkey/options.mjs +12 -12
- package/dist/astro/routes/api/auth/passkey/register/options.mjs +10 -10
- package/dist/astro/routes/api/auth/passkey/register/verify.mjs +11 -11
- package/dist/astro/routes/api/auth/passkey/verify.mjs +11 -11
- package/dist/astro/routes/api/auth/signup/complete.mjs +11 -11
- package/dist/astro/routes/api/auth/signup/request.mjs +10 -10
- package/dist/astro/routes/api/auth/signup/verify.mjs +1 -1
- package/dist/astro/routes/api/comments/_collection_/_contentId_/index.mjs +14 -14
- package/dist/astro/routes/api/comments/_collection_/_contentId_/reactions.mjs +13 -13
- package/dist/astro/routes/api/content/_collection_/_id_/compare.mjs +2 -2
- package/dist/astro/routes/api/content/_collection_/_id_/discard-draft.d.mts.map +1 -1
- package/dist/astro/routes/api/content/_collection_/_id_/discard-draft.mjs +14 -5
- package/dist/astro/routes/api/content/_collection_/_id_/discard-draft.mjs.map +1 -1
- package/dist/astro/routes/api/content/_collection_/_id_/duplicate.mjs +3 -3
- package/dist/astro/routes/api/content/_collection_/_id_/permanent.mjs +2 -2
- package/dist/astro/routes/api/content/_collection_/_id_/preview-url.mjs +11 -11
- package/dist/astro/routes/api/content/_collection_/_id_/publish.mjs +13 -10
- package/dist/astro/routes/api/content/_collection_/_id_/publish.mjs.map +1 -1
- package/dist/astro/routes/api/content/_collection_/_id_/references/_relation_/children.mjs +17 -15
- package/dist/astro/routes/api/content/_collection_/_id_/references/_relation_/children.mjs.map +1 -1
- package/dist/astro/routes/api/content/_collection_/_id_/references/_relation_/parents.mjs +17 -15
- package/dist/astro/routes/api/content/_collection_/_id_/references/_relation_/parents.mjs.map +1 -1
- package/dist/astro/routes/api/content/_collection_/_id_/restore.mjs +3 -3
- package/dist/astro/routes/api/content/_collection_/_id_/revisions.mjs +2 -2
- package/dist/astro/routes/api/content/_collection_/_id_/schedule.mjs +8 -8
- package/dist/astro/routes/api/content/_collection_/_id_/terms/_taxonomy_.mjs +14 -14
- package/dist/astro/routes/api/content/_collection_/_id_/translations.mjs +2 -2
- package/dist/astro/routes/api/content/_collection_/_id_/unpublish.d.mts.map +1 -1
- package/dist/astro/routes/api/content/_collection_/_id_/unpublish.mjs +14 -5
- package/dist/astro/routes/api/content/_collection_/_id_/unpublish.mjs.map +1 -1
- package/dist/astro/routes/api/content/_collection_/_id_.mjs +8 -8
- package/dist/astro/routes/api/content/_collection_/authors.mjs +2 -2
- package/dist/astro/routes/api/content/_collection_/index.mjs +8 -8
- package/dist/astro/routes/api/content/_collection_/trash.mjs +7 -7
- package/dist/astro/routes/api/dashboard.mjs +8 -8
- package/dist/astro/routes/api/dev/emails.mjs +2 -2
- package/dist/astro/routes/api/import/probe.d.mts +3 -3
- package/dist/astro/routes/api/import/probe.mjs +17 -17
- package/dist/astro/routes/api/import/wordpress/analyze.mjs +2 -2
- package/dist/astro/routes/api/import/wordpress/execute.d.mts +11 -11
- package/dist/astro/routes/api/import/wordpress/execute.mjs +13 -13
- package/dist/astro/routes/api/import/wordpress/media.d.mts +10 -10
- package/dist/astro/routes/api/import/wordpress/media.mjs +11 -11
- package/dist/astro/routes/api/import/wordpress/prepare.mjs +9 -9
- package/dist/astro/routes/api/import/wordpress/rewrite-urls.d.mts +11 -11
- package/dist/astro/routes/api/import/wordpress/rewrite-urls.mjs +12 -10
- package/dist/astro/routes/api/import/wordpress/rewrite-urls.mjs.map +1 -1
- package/dist/astro/routes/api/import/wordpress-plugin/analyze.d.mts +1 -1
- package/dist/astro/routes/api/import/wordpress-plugin/analyze.mjs +17 -17
- package/dist/astro/routes/api/import/wordpress-plugin/execute.d.mts +11 -11
- package/dist/astro/routes/api/import/wordpress-plugin/execute.mjs +27 -27
- package/dist/astro/routes/api/manifest.mjs +4 -4
- package/dist/astro/routes/api/manifest.mjs.map +1 -1
- package/dist/astro/routes/api/mcp.mjs +188 -65
- package/dist/astro/routes/api/mcp.mjs.map +1 -1
- package/dist/astro/routes/api/media/_id_/confirm.mjs +11 -11
- package/dist/astro/routes/api/media/_id_/replace.d.mts +8 -0
- package/dist/astro/routes/api/media/_id_/replace.d.mts.map +1 -0
- package/dist/astro/routes/api/media/_id_/replace.mjs +91 -0
- package/dist/astro/routes/api/media/_id_/replace.mjs.map +1 -0
- package/dist/astro/routes/api/media/_id_/upload.mjs +6 -6
- package/dist/astro/routes/api/media/_id_/usage.mjs +18 -13
- package/dist/astro/routes/api/media/_id_/usage.mjs.map +1 -1
- package/dist/astro/routes/api/media/_id_.d.mts.map +1 -1
- package/dist/astro/routes/api/media/_id_.mjs +21 -13
- package/dist/astro/routes/api/media/_id_.mjs.map +1 -1
- package/dist/astro/routes/api/media/file/_...key_.d.mts.map +1 -1
- package/dist/astro/routes/api/media/file/_...key_.mjs +3 -2
- package/dist/astro/routes/api/media/file/_...key_.mjs.map +1 -1
- package/dist/astro/routes/api/media/folders/_id_.d.mts +10 -0
- package/dist/astro/routes/api/media/folders/_id_.d.mts.map +1 -0
- package/dist/astro/routes/api/media/folders/_id_.mjs +52 -0
- package/dist/astro/routes/api/media/folders/_id_.mjs.map +1 -0
- package/dist/astro/routes/api/media/folders/index.d.mts +9 -0
- package/dist/astro/routes/api/media/folders/index.d.mts.map +1 -0
- package/dist/astro/routes/api/media/folders/index.mjs +41 -0
- package/dist/astro/routes/api/media/folders/index.mjs.map +1 -0
- package/dist/astro/routes/api/media/providers/_providerId_/_itemId_.mjs +2 -2
- package/dist/astro/routes/api/media/providers/_providerId_/index.mjs +2 -2
- package/dist/astro/routes/api/media/providers/index.mjs +2 -2
- package/dist/astro/routes/api/media/upload-url.mjs +16 -14
- package/dist/astro/routes/api/media/upload-url.mjs.map +1 -1
- package/dist/astro/routes/api/media.d.mts.map +1 -1
- package/dist/astro/routes/api/media.mjs +59 -27
- package/dist/astro/routes/api/media.mjs.map +1 -1
- package/dist/astro/routes/api/menus/_name_/items/_id_.d.mts.map +1 -1
- package/dist/astro/routes/api/menus/_name_/items/_id_.mjs +20 -13
- package/dist/astro/routes/api/menus/_name_/items/_id_.mjs.map +1 -1
- package/dist/astro/routes/api/menus/_name_/items.d.mts.map +1 -1
- package/dist/astro/routes/api/menus/_name_/items.mjs +15 -11
- package/dist/astro/routes/api/menus/_name_/items.mjs.map +1 -1
- package/dist/astro/routes/api/menus/_name_/reorder.d.mts.map +1 -1
- package/dist/astro/routes/api/menus/_name_/reorder.mjs +15 -11
- package/dist/astro/routes/api/menus/_name_/reorder.mjs.map +1 -1
- package/dist/astro/routes/api/menus/_name_/translations.d.mts.map +1 -1
- package/dist/astro/routes/api/menus/_name_/translations.mjs +16 -12
- package/dist/astro/routes/api/menus/_name_/translations.mjs.map +1 -1
- package/dist/astro/routes/api/menus/_name_.d.mts.map +1 -1
- package/dist/astro/routes/api/menus/_name_.mjs +21 -14
- package/dist/astro/routes/api/menus/_name_.mjs.map +1 -1
- package/dist/astro/routes/api/menus/index.d.mts.map +1 -1
- package/dist/astro/routes/api/menus/index.mjs +15 -11
- package/dist/astro/routes/api/menus/index.mjs.map +1 -1
- package/dist/astro/routes/api/oauth/authorize.mjs +6 -6
- package/dist/astro/routes/api/oauth/device/authorize.mjs +5 -5
- package/dist/astro/routes/api/oauth/device/code.mjs +8 -8
- package/dist/astro/routes/api/oauth/device/token.mjs +7 -7
- package/dist/astro/routes/api/oauth/register.mjs +2 -2
- package/dist/astro/routes/api/oauth/token/refresh.mjs +5 -5
- package/dist/astro/routes/api/oauth/token/revoke.mjs +5 -5
- package/dist/astro/routes/api/oauth/token.mjs +5 -5
- package/dist/astro/routes/api/openapi.json.mjs +253 -40
- package/dist/astro/routes/api/openapi.json.mjs.map +1 -1
- package/dist/astro/routes/api/plugins/_pluginId_/_...path_.mjs +4 -4
- package/dist/astro/routes/api/redirects/404s/index.mjs +10 -10
- package/dist/astro/routes/api/redirects/404s/summary.mjs +10 -10
- package/dist/astro/routes/api/redirects/_id_.mjs +11 -11
- package/dist/astro/routes/api/redirects/index.mjs +11 -11
- package/dist/astro/routes/api/relations/_id_/index.mjs +17 -15
- package/dist/astro/routes/api/relations/_id_/index.mjs.map +1 -1
- package/dist/astro/routes/api/relations/_id_/translations.mjs +12 -10
- package/dist/astro/routes/api/relations/_id_/translations.mjs.map +1 -1
- package/dist/astro/routes/api/relations/index.mjs +17 -15
- package/dist/astro/routes/api/relations/index.mjs.map +1 -1
- package/dist/astro/routes/api/revisions/_revisionId_/index.mjs +2 -2
- package/dist/astro/routes/api/revisions/_revisionId_/restore.mjs +3 -3
- package/dist/astro/routes/api/schema/collections/_slug_/fields/_fieldSlug_.mjs +53 -47
- package/dist/astro/routes/api/schema/collections/_slug_/fields/_fieldSlug_.mjs.map +1 -1
- package/dist/astro/routes/api/schema/collections/_slug_/fields/index.mjs +53 -47
- package/dist/astro/routes/api/schema/collections/_slug_/fields/index.mjs.map +1 -1
- package/dist/astro/routes/api/schema/collections/_slug_/fields/reorder.mjs +53 -47
- package/dist/astro/routes/api/schema/collections/_slug_/fields/reorder.mjs.map +1 -1
- package/dist/astro/routes/api/schema/collections/_slug_/index.mjs +53 -47
- package/dist/astro/routes/api/schema/collections/_slug_/index.mjs.map +1 -1
- package/dist/astro/routes/api/schema/collections/index.mjs +53 -47
- package/dist/astro/routes/api/schema/collections/index.mjs.map +1 -1
- package/dist/astro/routes/api/schema/collections/reorder.mjs +53 -47
- package/dist/astro/routes/api/schema/collections/reorder.mjs.map +1 -1
- package/dist/astro/routes/api/schema/index.mjs +10 -8
- package/dist/astro/routes/api/schema/index.mjs.map +1 -1
- package/dist/astro/routes/api/schema/orphans/_slug_.mjs +53 -47
- package/dist/astro/routes/api/schema/orphans/_slug_.mjs.map +1 -1
- package/dist/astro/routes/api/schema/orphans/index.mjs +53 -47
- package/dist/astro/routes/api/schema/orphans/index.mjs.map +1 -1
- package/dist/astro/routes/api/search/enable.mjs +10 -10
- package/dist/astro/routes/api/search/index.mjs +9 -9
- package/dist/astro/routes/api/search/rebuild.mjs +10 -10
- package/dist/astro/routes/api/search/stats.mjs +5 -5
- package/dist/astro/routes/api/search/suggest.mjs +9 -9
- package/dist/astro/routes/api/sections/_slug_.mjs +9 -9
- package/dist/astro/routes/api/sections/index.mjs +9 -9
- package/dist/astro/routes/api/settings/backups/archives/_name_.mjs +6 -6
- package/dist/astro/routes/api/settings/backups/archives/index.mjs +5 -5
- package/dist/astro/routes/api/settings/backups/export.mjs +6 -6
- package/dist/astro/routes/api/settings/backups/index.mjs +7 -7
- package/dist/astro/routes/api/settings/email.mjs +5 -5
- package/dist/astro/routes/api/settings/email.mjs.map +1 -1
- package/dist/astro/routes/api/settings.d.mts.map +1 -1
- package/dist/astro/routes/api/settings.mjs +20 -16
- package/dist/astro/routes/api/settings.mjs.map +1 -1
- package/dist/astro/routes/api/setup/admin-verify.mjs +12 -12
- package/dist/astro/routes/api/setup/admin.mjs +11 -11
- package/dist/astro/routes/api/setup/dev-bypass.d.mts.map +1 -1
- package/dist/astro/routes/api/setup/dev-bypass.mjs +35 -28
- package/dist/astro/routes/api/setup/dev-bypass.mjs.map +1 -1
- package/dist/astro/routes/api/setup/dev-reset.mjs +2 -2
- package/dist/astro/routes/api/setup/index.mjs +32 -30
- package/dist/astro/routes/api/setup/index.mjs.map +1 -1
- package/dist/astro/routes/api/setup/status.mjs +3 -3
- package/dist/astro/routes/api/snapshot.mjs +7 -7
- package/dist/astro/routes/api/taxonomies/_name_/reorder.d.mts.map +1 -1
- package/dist/astro/routes/api/taxonomies/_name_/reorder.mjs +20 -16
- package/dist/astro/routes/api/taxonomies/_name_/reorder.mjs.map +1 -1
- package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_/translations.d.mts.map +1 -1
- package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_/translations.mjs +21 -17
- package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_/translations.mjs.map +1 -1
- package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_.d.mts.map +1 -1
- package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_.mjs +25 -18
- package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_.mjs.map +1 -1
- package/dist/astro/routes/api/taxonomies/_name_/terms/index.d.mts.map +1 -1
- package/dist/astro/routes/api/taxonomies/_name_/terms/index.mjs +20 -16
- package/dist/astro/routes/api/taxonomies/_name_/terms/index.mjs.map +1 -1
- package/dist/astro/routes/api/taxonomies/_name_/translations.mjs +14 -14
- package/dist/astro/routes/api/taxonomies/_name_.d.mts.map +1 -1
- package/dist/astro/routes/api/taxonomies/_name_.mjs +26 -19
- package/dist/astro/routes/api/taxonomies/_name_.mjs.map +1 -1
- package/dist/astro/routes/api/taxonomies/index.d.mts.map +1 -1
- package/dist/astro/routes/api/taxonomies/index.mjs +20 -16
- package/dist/astro/routes/api/taxonomies/index.mjs.map +1 -1
- package/dist/astro/routes/api/themes/preview.mjs +5 -5
- package/dist/astro/routes/api/typegen.mjs +4 -4
- package/dist/astro/routes/api/well-known/auth.mjs +2 -2
- package/dist/astro/routes/api/well-known/oauth-authorization-server.mjs +2 -2
- package/dist/astro/routes/api/well-known/oauth-protected-resource.mjs +2 -2
- package/dist/astro/routes/api/widget-areas/_name_/reorder.d.mts.map +1 -1
- package/dist/astro/routes/api/widget-areas/_name_/reorder.mjs +10 -8
- package/dist/astro/routes/api/widget-areas/_name_/reorder.mjs.map +1 -1
- package/dist/astro/routes/api/widget-areas/_name_/widgets/_id_.d.mts.map +1 -1
- package/dist/astro/routes/api/widget-areas/_name_/widgets/_id_.mjs +17 -13
- package/dist/astro/routes/api/widget-areas/_name_/widgets/_id_.mjs.map +1 -1
- package/dist/astro/routes/api/widget-areas/_name_/widgets.d.mts.map +1 -1
- package/dist/astro/routes/api/widget-areas/_name_/widgets.mjs +15 -12
- package/dist/astro/routes/api/widget-areas/_name_/widgets.mjs.map +1 -1
- package/dist/astro/routes/api/widget-areas/_name_.d.mts.map +1 -1
- package/dist/astro/routes/api/widget-areas/_name_.mjs +8 -6
- package/dist/astro/routes/api/widget-areas/_name_.mjs.map +1 -1
- package/dist/astro/routes/api/widget-areas/index.d.mts.map +1 -1
- package/dist/astro/routes/api/widget-areas/index.mjs +15 -12
- package/dist/astro/routes/api/widget-areas/index.mjs.map +1 -1
- package/dist/astro/routes/api/widget-components.mjs +2 -2
- package/dist/astro/routes/robots.txt.mjs +7 -7
- package/dist/astro/routes/sitemap-_collection_.xml.mjs +10 -10
- package/dist/astro/routes/sitemap.xml.mjs +8 -8
- package/dist/astro/types.d.mts +37 -17
- package/dist/astro/types.d.mts.map +1 -1
- package/dist/auth/providers/github.d.mts +1 -1
- package/dist/auth/providers/google.d.mts +1 -1
- package/dist/{authorize-DUElxgOQ.mjs → authorize-Bkf_UHhD.mjs} +2 -2
- package/dist/{authorize-DUElxgOQ.mjs.map → authorize-Bkf_UHhD.mjs.map} +1 -1
- package/dist/{backup-DWYpJlLj.mjs → backup-rwVAl9NI.mjs} +5 -5
- package/dist/{backup-DWYpJlLj.mjs.map → backup-rwVAl9NI.mjs.map} +1 -1
- package/dist/{bundle-vn56sLos.mjs → bundle-C8S2Zl6U.mjs} +4 -4
- package/dist/{bundle-vn56sLos.mjs.map → bundle-C8S2Zl6U.mjs.map} +1 -1
- package/dist/{byline-yjvWq4ip.mjs → byline-DuhF7NWl.mjs} +27 -14
- package/dist/byline-DuhF7NWl.mjs.map +1 -0
- package/dist/{byline-fields-txaLGoME.mjs → byline-fields-BovY4KYM.mjs} +2 -2
- package/dist/{byline-fields-txaLGoME.mjs.map → byline-fields-BovY4KYM.mjs.map} +1 -1
- package/dist/{byline-registry-DDun8sxh.mjs → byline-registry-Bpu9-MVs.mjs} +2 -2
- package/dist/{byline-registry-DDun8sxh.mjs.map → byline-registry-Bpu9-MVs.mjs.map} +1 -1
- package/dist/{bylines-DjXS5p0P.mjs → bylines-CJ5nd6Lw.mjs} +7 -7
- package/dist/{bylines-DjXS5p0P.mjs.map → bylines-CJ5nd6Lw.mjs.map} +1 -1
- package/dist/{bylines-Bu7pchQ4.mjs → bylines-RwBAeOF1.mjs} +3 -3
- package/dist/{bylines-Bu7pchQ4.mjs.map → bylines-RwBAeOF1.mjs.map} +1 -1
- package/dist/{cache-C46-3Irl.mjs → cache-BF5Kvn59.mjs} +4 -4
- package/dist/{cache-C46-3Irl.mjs.map → cache-BF5Kvn59.mjs.map} +1 -1
- package/dist/capture-triggers-CNW1q3HK.mjs +362 -0
- package/dist/capture-triggers-CNW1q3HK.mjs.map +1 -0
- package/dist/{challenge-store-SIL5DsF2.mjs → challenge-store-DQN_Yrck.mjs} +5 -3
- package/dist/challenge-store-DQN_Yrck.mjs.map +1 -0
- package/dist/chrome-tags-D8fiZG94.mjs +24 -0
- package/dist/chrome-tags-D8fiZG94.mjs.map +1 -0
- package/dist/{chunks-fiZ8G9RJ.mjs → chunks-C4szrD8o.mjs} +2 -2
- package/dist/{chunks-fiZ8G9RJ.mjs.map → chunks-C4szrD8o.mjs.map} +1 -1
- package/dist/cli/index.mjs +37 -53
- package/dist/cli/index.mjs.map +1 -1
- package/dist/client/cf-access.d.mts +1 -1
- package/dist/client/index.d.mts +74 -4
- package/dist/client/index.d.mts.map +1 -1
- package/dist/client/index.mjs +54 -2
- package/dist/client/index.mjs.map +1 -1
- package/dist/{collection-deletion-DQPvMD8R.mjs → collection-deletion-Bj07NHbj.mjs} +13 -356
- package/dist/collection-deletion-Bj07NHbj.mjs.map +1 -0
- package/dist/{comment-reaction-D-2J84UE.mjs → comment-reaction-BhrvSHml.mjs} +2 -2
- package/dist/{comment-reaction-D-2J84UE.mjs.map → comment-reaction-BhrvSHml.mjs.map} +1 -1
- package/dist/{comment-Dxlep6cE.mjs → comment-vxOzWbZN.mjs} +2 -2
- package/dist/{comment-Dxlep6cE.mjs.map → comment-vxOzWbZN.mjs.map} +1 -1
- package/dist/{comments-CTfZtLmM.mjs → comments-Ct4ensnf.mjs} +2 -2
- package/dist/{comments-CTfZtLmM.mjs.map → comments-Ct4ensnf.mjs.map} +1 -1
- package/dist/{components-CQy3lh9x.mjs → components-DJbo1z0S.mjs} +1 -1
- package/dist/{components-CQy3lh9x.mjs.map → components-DJbo1z0S.mjs.map} +1 -1
- package/dist/{config-COQzTe5Q.d.mts → config-B9eZ340f.d.mts} +1 -1
- package/dist/{config-COQzTe5Q.d.mts.map → config-B9eZ340f.d.mts.map} +1 -1
- package/dist/config-it29yDLA.mjs +1163 -0
- package/dist/config-it29yDLA.mjs.map +1 -0
- package/dist/{content-ZHCc1ngN.mjs → content-DjvM0T92.mjs} +86 -45
- package/dist/content-DjvM0T92.mjs.map +1 -0
- package/dist/{content-list-query-wJ2WN8Vp.d.mts → content-list-query-Btqd4uV2.d.mts} +1 -1
- package/dist/{content-list-query-wJ2WN8Vp.d.mts.map → content-list-query-Btqd4uV2.d.mts.map} +1 -1
- package/dist/{content-refresh-B_8SJzuU.mjs → content-refresh-Bwp-8yGy.mjs} +1139 -111
- package/dist/content-refresh-Bwp-8yGy.mjs.map +1 -0
- package/dist/{media-usage-BZCydfvu.mjs → content-repair-Czdp7jz5.mjs} +5 -196
- package/dist/content-repair-Czdp7jz5.mjs.map +1 -0
- package/dist/{context-ZldbZcle.mjs → context-CX6gxOLW.mjs} +55 -20
- package/dist/context-CX6gxOLW.mjs.map +1 -0
- package/dist/{cron-Y9aLtgrA.mjs → cron-C6o7VppJ.mjs} +1 -1
- package/dist/{cron-Y9aLtgrA.mjs.map → cron-C6o7VppJ.mjs.map} +1 -1
- package/dist/{dashboard-DvHbk_cv.mjs → dashboard-C2kTeeRI.mjs} +5 -5
- package/dist/{dashboard-DvHbk_cv.mjs.map → dashboard-C2kTeeRI.mjs.map} +1 -1
- package/dist/db/index.d.mts +3 -3
- package/dist/db/index.mjs +3 -3
- package/dist/db/index.mjs.map +1 -1
- package/dist/db/libsql-migrations.d.mts +1 -1
- package/dist/db/libsql-migrations.mjs +4 -4
- package/dist/db/libsql.d.mts +1 -1
- package/dist/db/postgres-migrations.d.mts +1 -1
- package/dist/db/postgres-migrations.mjs +4 -4
- package/dist/db/postgres.d.mts +1 -1
- package/dist/db/postgres.d.mts.map +1 -1
- package/dist/db/postgres.mjs +19 -3
- package/dist/db/postgres.mjs.map +1 -1
- package/dist/db/sqlite-migrations.d.mts +1 -1
- package/dist/db/sqlite-migrations.mjs +4 -4
- package/dist/db/sqlite.d.mts +1 -1
- package/dist/db/sqlite.mjs +3 -3
- package/dist/db/sqlite.mjs.map +1 -1
- package/dist/{default-DdDl3fxv.mjs → default-Clra32mw.mjs} +1 -1
- package/dist/{default-DdDl3fxv.mjs.map → default-Clra32mw.mjs.map} +1 -1
- package/dist/{deferred-tasks-SDWxrgzJ.d.mts → deferred-tasks-CvDETTJO.d.mts} +1 -1
- package/dist/{deferred-tasks-SDWxrgzJ.d.mts.map → deferred-tasks-CvDETTJO.d.mts.map} +1 -1
- package/dist/dev-typegen-DzOPfsNj.mjs +29 -0
- package/dist/dev-typegen-DzOPfsNj.mjs.map +1 -0
- package/dist/{device-flow-C0GdD_z8.mjs → device-flow-D2oCWvLJ.mjs} +5 -5
- package/dist/{device-flow-C0GdD_z8.mjs.map → device-flow-D2oCWvLJ.mjs.map} +1 -1
- package/dist/{direct-executor-CDXeJCSs.mjs → direct-executor-Bfa5_ToE.mjs} +3 -3
- package/dist/{direct-executor-CDXeJCSs.mjs.map → direct-executor-Bfa5_ToE.mjs.map} +1 -1
- package/dist/{dist-D_6CKR8z.mjs → dist-89xCrGqi.mjs} +1 -1
- package/dist/{dist-D_6CKR8z.mjs.map → dist-89xCrGqi.mjs.map} +1 -1
- package/dist/{email-console-BHNjIwiB.mjs → email-console-Dzb6uGYa.mjs} +1 -1
- package/dist/{email-console-BHNjIwiB.mjs.map → email-console-Dzb6uGYa.mjs.map} +1 -1
- package/dist/{enrich-_ySMEvEE.mjs → enrich-BX0IDp4z.mjs} +3 -3
- package/dist/{enrich-_ySMEvEE.mjs.map → enrich-BX0IDp4z.mjs.map} +1 -1
- package/dist/{error-DupyJZE2.mjs → error-DFrQjppn.mjs} +2 -2
- package/dist/{error-DupyJZE2.mjs.map → error-DFrQjppn.mjs.map} +1 -1
- package/dist/{errors-CLUPm7aD.mjs → errors-DsVoDUjJ.mjs} +24 -2
- package/dist/errors-DsVoDUjJ.mjs.map +1 -0
- package/dist/{escape-DUY2r2Zs.mjs → escape-HmHTC1Is.mjs} +1 -1
- package/dist/{escape-DUY2r2Zs.mjs.map → escape-HmHTC1Is.mjs.map} +1 -1
- package/dist/{field-defs-cache-BzwBlJrR.mjs → field-defs-cache-BM4SIRqH.mjs} +5 -5
- package/dist/{field-defs-cache-BzwBlJrR.mjs.map → field-defs-cache-BM4SIRqH.mjs.map} +1 -1
- package/dist/focal-point-BeWFo6Xx.mjs +23 -0
- package/dist/focal-point-BeWFo6Xx.mjs.map +1 -0
- package/dist/{fts-manager-DyZEohZC.mjs → fts-manager-Do1BlW2r.mjs} +3 -3
- package/dist/{fts-manager-DyZEohZC.mjs.map → fts-manager-Do1BlW2r.mjs.map} +1 -1
- package/dist/{hash-Cg0TXJPV.mjs → hash-3JJPlHF2.mjs} +1 -1
- package/dist/{hash-Cg0TXJPV.mjs.map → hash-3JJPlHF2.mjs.map} +1 -1
- package/dist/hook-result-DCh2WUpe.d.mts +31 -0
- package/dist/hook-result-DCh2WUpe.d.mts.map +1 -0
- package/dist/{hreflang-DwT2E0Sa.d.mts → hreflang-B6hbAuuO.d.mts} +2 -2
- package/dist/{hreflang-DwT2E0Sa.d.mts.map → hreflang-B6hbAuuO.d.mts.map} +1 -1
- package/dist/{hreflang-BBe83kKa.mjs → hreflang-DQbPZliA.mjs} +7 -7
- package/dist/{hreflang-BBe83kKa.mjs.map → hreflang-DQbPZliA.mjs.map} +1 -1
- package/dist/{identity-Ys6Dlc9C.mjs → identity-DksvEazf.mjs} +3 -3
- package/dist/{identity-Ys6Dlc9C.mjs.map → identity-DksvEazf.mjs.map} +1 -1
- package/dist/{import-DPkLmeXO.mjs → import-CJpaBBBT.mjs} +6 -6
- package/dist/{import-DPkLmeXO.mjs.map → import-CJpaBBBT.mjs.map} +1 -1
- package/dist/{index-BVBZj4-7.d.mts → index-BJNMCWmu.d.mts} +267 -82
- package/dist/index-BJNMCWmu.d.mts.map +1 -0
- package/dist/{index-C9KuQyO-.d.mts → index-Du8K7bWa.d.mts} +3 -3
- package/dist/{index-C9KuQyO-.d.mts.map → index-Du8K7bWa.d.mts.map} +1 -1
- package/dist/index.d.mts +22 -21
- package/dist/index.mjs +79 -73
- package/dist/{init-lock-6b309ZrF.mjs → init-lock-DJkX6Hto.mjs} +1 -1
- package/dist/{init-lock-6b309ZrF.mjs.map → init-lock-DJkX6Hto.mjs.map} +1 -1
- package/dist/{load-YJ2xl3ra.mjs → load-CawHjTOH.mjs} +2 -2
- package/dist/{load-YJ2xl3ra.mjs.map → load-CawHjTOH.mjs.map} +1 -1
- package/dist/{loader-CdG_Ci3H.mjs → loader-Z8vl7zTq.mjs} +48 -13
- package/dist/loader-Z8vl7zTq.mjs.map +1 -0
- package/dist/{manifest-builder-B252yQUf.mjs → manifest-builder-COtzuca2.mjs} +2 -2
- package/dist/{manifest-builder-B252yQUf.mjs.map → manifest-builder-COtzuca2.mjs.map} +1 -1
- package/dist/{manifest-schema-BXbUAHod.mjs → manifest-schema-BNWwR8Vd.mjs} +5 -5
- package/dist/manifest-schema-BNWwR8Vd.mjs.map +1 -0
- package/dist/media/image-endpoint.d.mts +4 -2
- package/dist/media/image-endpoint.d.mts.map +1 -1
- package/dist/media/image-endpoint.mjs +6 -4
- package/dist/media/image-endpoint.mjs.map +1 -1
- package/dist/media/index.d.mts +1 -1
- package/dist/media/index.mjs +13 -3
- package/dist/media/index.mjs.map +1 -1
- package/dist/media/local-runtime.d.mts +14 -12
- package/dist/media/local-runtime.d.mts.map +1 -1
- package/dist/media/local-runtime.mjs +12 -6
- package/dist/media/local-runtime.mjs.map +1 -1
- package/dist/{media-CzhAn2--.mjs → media-BBm8Wg3f.mjs} +69 -12
- package/dist/media-BBm8Wg3f.mjs.map +1 -0
- package/dist/{media-BWWWb8kg.mjs → media-BHjus86Y.mjs} +133 -9
- package/dist/media-BHjus86Y.mjs.map +1 -0
- package/dist/{media-allowlist-D6x-Us02.mjs → media-allowlist-CoTBWoDp.mjs} +3 -2
- package/dist/media-allowlist-CoTBWoDp.mjs.map +1 -0
- package/dist/media-folders-BGkATs8n.mjs +210 -0
- package/dist/media-folders-BGkATs8n.mjs.map +1 -0
- package/dist/{media-upload-CHBVn6m-.mjs → media-upload-BCidR-EY.mjs} +9 -9
- package/dist/{media-upload-CHBVn6m-.mjs.map → media-upload-BCidR-EY.mjs.map} +1 -1
- package/dist/{media-url-BvoX88FA.mjs → media-url-DHoPr0hq.mjs} +1 -1
- package/dist/{media-url-BvoX88FA.mjs.map → media-url-DHoPr0hq.mjs.map} +1 -1
- package/dist/media-usage-CdY5jhSR.mjs +1833 -0
- package/dist/media-usage-CdY5jhSR.mjs.map +1 -0
- package/dist/media-usage-activation-BgeMtK5C.mjs +78 -0
- package/dist/media-usage-activation-BgeMtK5C.mjs.map +1 -0
- package/dist/{media-usage-work-CLo_6tct.mjs → media-usage-work-CnGCdHxx.mjs} +4 -4
- package/dist/{media-usage-work-CLo_6tct.mjs.map → media-usage-work-CnGCdHxx.mjs.map} +1 -1
- package/dist/{media-usage-work-DrCbqBcl.mjs → media-usage-work-D6D9sMCA.mjs} +221 -59
- package/dist/media-usage-work-D6D9sMCA.mjs.map +1 -0
- package/dist/{media-usage-write-fence-aHEgN1zB.mjs → media-usage-write-fence-hjeD4u7s.mjs} +2 -2
- package/dist/{media-usage-write-fence-aHEgN1zB.mjs.map → media-usage-write-fence-hjeD4u7s.mjs.map} +1 -1
- package/dist/{menus-DSo5QeW0.mjs → menus-6qSwTNxG.mjs} +375 -107
- package/dist/menus-6qSwTNxG.mjs.map +1 -0
- package/dist/{menus-TCNSd2vp.mjs → menus-uvPLXMZf.mjs} +4 -4
- package/dist/{menus-TCNSd2vp.mjs.map → menus-uvPLXMZf.mjs.map} +1 -1
- package/dist/migrations/index.d.mts +1 -1
- package/dist/migrations/index.mjs +3 -3
- package/dist/{mime-DfIVjNkr.mjs → mime-CUIG6x84.mjs} +1 -1
- package/dist/mime-CUIG6x84.mjs.map +1 -0
- package/dist/{mode-BDoH_WcF.mjs → mode-DN_WneRx.mjs} +1 -1
- package/dist/{mode-BDoH_WcF.mjs.map → mode-DN_WneRx.mjs.map} +1 -1
- package/dist/node-sqlite-compat-BuJXIeMz.mjs +46 -0
- package/dist/node-sqlite-compat-BuJXIeMz.mjs.map +1 -0
- package/dist/{normalize-Bc-s_r-a.mjs → normalize-C2xNjTSG.mjs} +36 -5
- package/dist/normalize-C2xNjTSG.mjs.map +1 -0
- package/dist/{oauth-authorization-iOikmrJd.mjs → oauth-authorization-Dj6Kwc21.mjs} +5 -5
- package/dist/{oauth-authorization-iOikmrJd.mjs.map → oauth-authorization-Dj6Kwc21.mjs.map} +1 -1
- package/dist/{oauth-clients-CvI0nHMJ.mjs → oauth-clients-FD7I0J8m.mjs} +1 -1
- package/dist/{oauth-clients-CvI0nHMJ.mjs.map → oauth-clients-FD7I0J8m.mjs.map} +1 -1
- package/dist/{oauth-state-store-Ba8KZlwW.mjs → oauth-state-store-DkmDOmHs.mjs} +1 -1
- package/dist/{oauth-state-store-Ba8KZlwW.mjs.map → oauth-state-store-DkmDOmHs.mjs.map} +1 -1
- package/dist/{oauth-user-lookup-C5SQwGYC.mjs → oauth-user-lookup-CvIwGpYd.mjs} +1 -1
- package/dist/{oauth-user-lookup-C5SQwGYC.mjs.map → oauth-user-lookup-CvIwGpYd.mjs.map} +1 -1
- package/dist/object-cache/memory.d.mts +1 -1
- package/dist/{object-cache-71tPfV4A.mjs → object-cache-DVKnyOfy.mjs} +19 -3
- package/dist/object-cache-DVKnyOfy.mjs.map +1 -0
- package/dist/{options-CBXIHUoT.mjs → options-BHPeIbBd.mjs} +1 -1
- package/dist/{options-CBXIHUoT.mjs.map → options-BHPeIbBd.mjs.map} +1 -1
- package/dist/{options--hhz-jZ1.d.mts → options-CYb4y7hM.d.mts} +24 -11
- package/dist/options-CYb4y7hM.d.mts.map +1 -0
- package/dist/page/index.d.mts +2 -2
- package/dist/{parse-DFbuc-Fh.mjs → parse-Ckpg-Qfp.mjs} +2 -2
- package/dist/{parse-DFbuc-Fh.mjs.map → parse-Ckpg-Qfp.mjs.map} +1 -1
- package/dist/{passkey-config-DFAmUyuE.mjs → passkey-config-O_lj3y0k.mjs} +1 -1
- package/dist/{passkey-config-DFAmUyuE.mjs.map → passkey-config-O_lj3y0k.mjs.map} +1 -1
- package/dist/{patterns-CiyXeDgr.mjs → patterns-D9iDO3j8.mjs} +1 -1
- package/dist/{patterns-CiyXeDgr.mjs.map → patterns-D9iDO3j8.mjs.map} +1 -1
- package/dist/{placeholder-Dp0K3RkD.d.mts → placeholder-4X9BrRrp.d.mts} +7 -1
- package/dist/placeholder-4X9BrRrp.d.mts.map +1 -0
- package/dist/plugin-types.d.mts +8 -3
- package/dist/plugin-types.d.mts.map +1 -1
- package/dist/plugin-utils.d.mts +10 -10
- package/dist/plugins/adapt-sandbox-entry.d.mts +10 -10
- package/dist/plugins/adapt-sandbox-entry.mjs +2 -2
- package/dist/{policy-TluUIxuu.mjs → policy-Dhtwntrt.mjs} +2 -2
- package/dist/{policy-TluUIxuu.mjs.map → policy-Dhtwntrt.mjs.map} +1 -1
- package/dist/{portable-text-imBW5cHK.mjs → portable-text-U85hOafW.mjs} +1 -1
- package/dist/{portable-text-imBW5cHK.mjs.map → portable-text-U85hOafW.mjs.map} +1 -1
- package/dist/{preview-PW-nOnq4.mjs → preview-B_vJLvf8.mjs} +2 -2
- package/dist/{preview-PW-nOnq4.mjs.map → preview-B_vJLvf8.mjs.map} +1 -1
- package/dist/{protocol-DjsJHTlK.d.mts → protocol-JdD2YhY9.d.mts} +2 -2
- package/dist/{protocol-DjsJHTlK.d.mts.map → protocol-JdD2YhY9.d.mts.map} +1 -1
- package/dist/{public-url-CWoFhQT8.mjs → public-url-CarhZJgf.mjs} +1 -1
- package/dist/{public-url-CWoFhQT8.mjs.map → public-url-CarhZJgf.mjs.map} +1 -1
- package/dist/{query-zTVAR1Sl.mjs → query-BZKZcG5b.mjs} +15 -15
- package/dist/{query-zTVAR1Sl.mjs.map → query-BZKZcG5b.mjs.map} +1 -1
- package/dist/{query-BWs7O5Il.mjs → query-BndaFxxp.mjs} +5 -5
- package/dist/{query-BWs7O5Il.mjs.map → query-BndaFxxp.mjs.map} +1 -1
- package/dist/{rate-limit-Bx4g9m3p.mjs → rate-limit-BZmATC6W.mjs} +2 -2
- package/dist/{rate-limit-Bx4g9m3p.mjs.map → rate-limit-BZmATC6W.mjs.map} +1 -1
- package/dist/{redirect-COsS6SWJ.mjs → redirect-CZkbozu9.mjs} +2 -2
- package/dist/{redirect-COsS6SWJ.mjs.map → redirect-CZkbozu9.mjs.map} +1 -1
- package/dist/{redirect-BgAOGHDq.mjs → redirect-CzqnLxK-.mjs} +1 -1
- package/dist/{redirect-BgAOGHDq.mjs.map → redirect-CzqnLxK-.mjs.map} +1 -1
- package/dist/{redirects-DTDHWH31.mjs → redirects-BLNOWQTn.mjs} +64 -29
- package/dist/redirects-BLNOWQTn.mjs.map +1 -0
- package/dist/{redirects-DyChwDkG.mjs → redirects-CqzNM0KM.mjs} +5 -5
- package/dist/{redirects-DyChwDkG.mjs.map → redirects-CqzNM0KM.mjs.map} +1 -1
- package/dist/{registry-Cqa2I749.mjs → registry-AZAsRsor.mjs} +30 -126
- package/dist/registry-AZAsRsor.mjs.map +1 -0
- package/dist/{relation-BnHB0T4J.mjs → relation-04DfKRTO.mjs} +2 -2
- package/dist/{relation-BnHB0T4J.mjs.map → relation-04DfKRTO.mjs.map} +1 -1
- package/dist/{relations-BBApI4e2.mjs → relations-C4htk5sb.mjs} +7 -7
- package/dist/relations-C4htk5sb.mjs.map +1 -0
- package/dist/{relations-D5sM5fW0.mjs → relations-CcFwDJdJ.mjs} +4 -4
- package/dist/{relations-D5sM5fW0.mjs.map → relations-CcFwDJdJ.mjs.map} +1 -1
- package/dist/{relations-BHo5A8Zf.d.mts → relations-DnRK4YIT.d.mts} +347 -54
- package/dist/relations-DnRK4YIT.d.mts.map +1 -0
- package/dist/{request-cache-BSUptuJR.mjs → request-cache-DH9zdCOD.mjs} +1 -1
- package/dist/{request-cache-BSUptuJR.mjs.map → request-cache-DH9zdCOD.mjs.map} +1 -1
- package/dist/request-context.d.mts +1 -1
- package/dist/{request-meta-DgZJh3zG.mjs → request-meta-DYxLlnmz.mjs} +2 -2
- package/dist/{request-meta-DgZJh3zG.mjs.map → request-meta-DYxLlnmz.mjs.map} +1 -1
- package/dist/{resolve-DOhVEvty.mjs → resolve-prZ3mP7l.mjs} +1 -1
- package/dist/{resolve-DOhVEvty.mjs.map → resolve-prZ3mP7l.mjs.map} +1 -1
- package/dist/{runner-C1T11CfC.mjs → runner-BLIDKpmA.mjs} +471 -290
- package/dist/runner-BLIDKpmA.mjs.map +1 -0
- package/dist/{runner-BYHZn3Jy.d.mts → runner-YKfIMnaF.d.mts} +3 -2
- package/dist/runner-YKfIMnaF.d.mts.map +1 -0
- package/dist/runtime.d.mts +11 -11
- package/dist/runtime.mjs +1 -1
- package/dist/{schema-DZ5YVVZj.mjs → schema-CGnBeLiW.mjs} +3 -3
- package/dist/{schema-DZ5YVVZj.mjs.map → schema-CGnBeLiW.mjs.map} +1 -1
- package/dist/{schema-2AOsSn2v.mjs → schema-DYr-Vd-L.mjs} +36 -6
- package/dist/{schema-2AOsSn2v.mjs.map → schema-DYr-Vd-L.mjs.map} +1 -1
- package/dist/{scopes-8ClPF2bC.mjs → scopes-BhWvBavj.mjs} +3 -3
- package/dist/{scopes-8ClPF2bC.mjs.map → scopes-BhWvBavj.mjs.map} +1 -1
- package/dist/{search-u1QYdOCG.mjs → search-C-qDk4kx.mjs} +4 -4
- package/dist/{search-u1QYdOCG.mjs.map → search-C-qDk4kx.mjs.map} +1 -1
- package/dist/{secrets-BEgsAQEU.mjs → secrets-rEtHt-6z.mjs} +3 -3
- package/dist/{secrets-BEgsAQEU.mjs.map → secrets-rEtHt-6z.mjs.map} +1 -1
- package/dist/{sections-DmHviGyM.mjs → sections-B_nYvlwn.mjs} +2 -2
- package/dist/{sections-DmHviGyM.mjs.map → sections-B_nYvlwn.mjs.map} +1 -1
- package/dist/seed/index.d.mts +2 -2
- package/dist/seed/index.mjs +25 -23
- package/dist/seo/index.d.mts +3 -3
- package/dist/seo/index.mjs +17 -15
- package/dist/seo/index.mjs.map +1 -1
- package/dist/{seo-Dq4G-RrO.mjs → seo-926NRIgt.mjs} +3 -3
- package/dist/{seo-Dq4G-RrO.mjs.map → seo-926NRIgt.mjs.map} +1 -1
- package/dist/{seo-AFpVvTqr.mjs → seo-CVWkdv6x.mjs} +1 -1
- package/dist/{seo-AFpVvTqr.mjs.map → seo-CVWkdv6x.mjs.map} +1 -1
- package/dist/{service-BpArayPr.mjs → service-CJl3ZAYs.mjs} +3 -3
- package/dist/{service-BpArayPr.mjs.map → service-CJl3ZAYs.mjs.map} +1 -1
- package/dist/{session-user-BEorKVT-.mjs → session-user-BlMgqCHS.mjs} +1 -1
- package/dist/{session-user-BEorKVT-.mjs.map → session-user-BlMgqCHS.mjs.map} +1 -1
- package/dist/{settings-xRdoUZr0.mjs → settings--wobrkkC.mjs} +21 -8
- package/dist/settings--wobrkkC.mjs.map +1 -0
- package/dist/{settings-DE9xtzqd.mjs → settings-Cwm6o2jY.mjs} +3 -3
- package/dist/{settings-DE9xtzqd.mjs.map → settings-Cwm6o2jY.mjs.map} +1 -1
- package/dist/{setup-complete-BnT8pq_C.mjs → setup-complete-DQbClIN2.mjs} +2 -2
- package/dist/{setup-complete-BnT8pq_C.mjs.map → setup-complete-DQbClIN2.mjs.map} +1 -1
- package/dist/{setup-nonce-CBitf_oQ.mjs → setup-nonce-DZCFS2sn.mjs} +1 -1
- package/dist/{setup-nonce-CBitf_oQ.mjs.map → setup-nonce-DZCFS2sn.mjs.map} +1 -1
- package/dist/{single-flight-cache-B0eLKS6K.mjs → single-flight-cache-BPuGPdcN.mjs} +2 -2
- package/dist/{single-flight-cache-B0eLKS6K.mjs.map → single-flight-cache-BPuGPdcN.mjs.map} +1 -1
- package/dist/{site-url-DjpIXMXJ.mjs → site-url-BrxA_E9H.mjs} +3 -3
- package/dist/{site-url-DjpIXMXJ.mjs.map → site-url-BrxA_E9H.mjs.map} +1 -1
- package/dist/{snapshot-BBlGkb2q.mjs → snapshot--OCDTqdb.mjs} +1 -1
- package/dist/{snapshot-BBlGkb2q.mjs.map → snapshot--OCDTqdb.mjs.map} +1 -1
- package/dist/{ssrf-Cpvg_n3A.mjs → ssrf-5sIM5jzl.mjs} +23 -6
- package/dist/{ssrf-Cpvg_n3A.mjs.map → ssrf-5sIM5jzl.mjs.map} +1 -1
- package/dist/{state-DYwPue40.mjs → state-BpFVsJZB.mjs} +12 -4
- package/dist/state-BpFVsJZB.mjs.map +1 -0
- package/dist/{status-CWVYpbD8.mjs → status-B777-dXz.mjs} +1 -1
- package/dist/{status-CWVYpbD8.mjs.map → status-B777-dXz.mjs.map} +1 -1
- package/dist/storage/local.d.mts +2 -1
- package/dist/storage/local.d.mts.map +1 -1
- package/dist/storage/local.mjs +1 -1
- package/dist/storage/local.mjs.map +1 -1
- package/dist/storage/s3.d.mts +2 -1
- package/dist/storage/s3.d.mts.map +1 -1
- package/dist/storage/s3.mjs +3 -2
- package/dist/storage/s3.mjs.map +1 -1
- package/dist/{target-DixqqV5i.mjs → target-BmR0iTwz.mjs} +1 -1
- package/dist/{target-DixqqV5i.mjs.map → target-BmR0iTwz.mjs.map} +1 -1
- package/dist/{taxonomies-OHUIiIpI.mjs → taxonomies-DkAkMupr.mjs} +17 -14
- package/dist/taxonomies-DkAkMupr.mjs.map +1 -0
- package/dist/{taxonomies-BlrncHi9.mjs → taxonomies-Wfy_Lg12.mjs} +43 -17
- package/dist/taxonomies-Wfy_Lg12.mjs.map +1 -0
- package/dist/{taxonomy-BqCZ1TdU.mjs → taxonomy-tJepplLL.mjs} +5 -5
- package/dist/{taxonomy-BqCZ1TdU.mjs.map → taxonomy-tJepplLL.mjs.map} +1 -1
- package/dist/{tokens-C39klX8R.mjs → tokens-BCO1oruF.mjs} +1 -1
- package/dist/{tokens-C39klX8R.mjs.map → tokens-BCO1oruF.mjs.map} +1 -1
- package/dist/{transaction-NQj4VJ7Z.mjs → transaction-0KOpOyMu.mjs} +2 -1
- package/dist/{transaction-NQj4VJ7Z.mjs.map → transaction-0KOpOyMu.mjs.map} +1 -1
- package/dist/{transport-DBJwa-Si.mjs → transport-Dr3qtwXC.mjs} +4 -3
- package/dist/{transport-DBJwa-Si.mjs.map → transport-Dr3qtwXC.mjs.map} +1 -1
- package/dist/{transport-RQE36APG.d.mts → transport-xh6YKW2G.d.mts} +1 -1
- package/dist/{transport-RQE36APG.d.mts.map → transport-xh6YKW2G.d.mts.map} +1 -1
- package/dist/{trusted-proxy-CEVekpby.mjs → trusted-proxy-BR5F1Otp.mjs} +1 -1
- package/dist/{trusted-proxy-CEVekpby.mjs.map → trusted-proxy-BR5F1Otp.mjs.map} +1 -1
- package/dist/{types-BW1syrlw.mjs → types-3qNFPlci.mjs} +1 -1
- package/dist/{types-BW1syrlw.mjs.map → types-3qNFPlci.mjs.map} +1 -1
- package/dist/types-75KIqzL9.mjs.map +1 -1
- package/dist/{types-DrJrVCT1.d.mts → types-B6GrPic4.d.mts} +9 -3
- package/dist/{types-DrJrVCT1.d.mts.map → types-B6GrPic4.d.mts.map} +1 -1
- package/dist/{types-DN64_zzZ.d.mts → types-BuHW4xDE.d.mts} +11 -10
- package/dist/types-BuHW4xDE.d.mts.map +1 -0
- package/dist/{types-DWRhk9xZ.d.mts → types-C00oyCZp.d.mts} +1 -1
- package/dist/{types-DWRhk9xZ.d.mts.map → types-C00oyCZp.d.mts.map} +1 -1
- package/dist/{types-BntycPTF.d.mts → types-CDtkNSFQ.d.mts} +1 -1
- package/dist/{types-BntycPTF.d.mts.map → types-CDtkNSFQ.d.mts.map} +1 -1
- package/dist/{types-Dfk8KI5R.d.mts → types-CPeXo1wF.d.mts} +1 -1
- package/dist/{types-Dfk8KI5R.d.mts.map → types-CPeXo1wF.d.mts.map} +1 -1
- package/dist/types-CQPWhPxE.mjs.map +1 -1
- package/dist/{types-BcqdcT-r.d.mts → types-CXFkwEGC.d.mts} +3 -2
- package/dist/types-CXFkwEGC.d.mts.map +1 -0
- package/dist/{types-CtzytVXn.mjs → types-DM3vioBY.mjs} +1 -1
- package/dist/{types-CtzytVXn.mjs.map → types-DM3vioBY.mjs.map} +1 -1
- package/dist/{types-CXnOzDe1.d.mts → types-DczELMop.d.mts} +1 -1
- package/dist/{types-CXnOzDe1.d.mts.map → types-DczELMop.d.mts.map} +1 -1
- package/dist/types-DfuTR6dL.mjs +3 -0
- package/dist/{types-DQIDRKF2.d.mts → types-FV23hEoW.d.mts} +10 -1
- package/dist/types-FV23hEoW.d.mts.map +1 -0
- package/dist/{types-C2pMvO62.d.mts → types-xDMtUFnO.d.mts} +2 -1
- package/dist/types-xDMtUFnO.d.mts.map +1 -0
- package/dist/{upload-attempts-D4FS8LT6.mjs → upload-attempts-BsqoQ1fn.mjs} +1 -1
- package/dist/{upload-attempts-D4FS8LT6.mjs.map → upload-attempts-BsqoQ1fn.mjs.map} +1 -1
- package/dist/{url-pattern-BHS0V5Ng.mjs → url-pattern-D4c2czpJ.mjs} +1 -1
- package/dist/{url-pattern-BHS0V5Ng.mjs.map → url-pattern-D4c2czpJ.mjs.map} +1 -1
- package/dist/{user-DJZfUJVE.mjs → user-BTZ40aq6.mjs} +2 -2
- package/dist/{user-DJZfUJVE.mjs.map → user-BTZ40aq6.mjs.map} +1 -1
- package/dist/{utils-D4vD_Y98.mjs → utils-BKvNjjhY.mjs} +1 -1
- package/dist/{utils-D4vD_Y98.mjs.map → utils-BKvNjjhY.mjs.map} +1 -1
- package/dist/{validate-BMLBvxOC.mjs → validate-DE_LRwo9.mjs} +2 -2
- package/dist/{validate-BMLBvxOC.mjs.map → validate-DE_LRwo9.mjs.map} +1 -1
- package/dist/{validate-CTqt5nuE.d.mts → validate-DUP27OYD.d.mts} +5 -5
- package/dist/{validate-CTqt5nuE.d.mts.map → validate-DUP27OYD.d.mts.map} +1 -1
- package/dist/{validation-npvENUCB.mjs → validation-BMImFJ11.mjs} +10 -8
- package/dist/{validation-npvENUCB.mjs.map → validation-BMImFJ11.mjs.map} +1 -1
- package/dist/version-Bii3suaO.mjs +7 -0
- package/dist/{version-DB_fqCSI.mjs.map → version-Bii3suaO.mjs.map} +1 -1
- package/dist/{widgets-BD3ho7Rq.mjs → widgets-D3gJ10xU.mjs} +18 -5
- package/dist/widgets-D3gJ10xU.mjs.map +1 -0
- package/dist/{wxr-taxonomies-Ca68766D.d.mts → wxr-taxonomies-B2Og_6rU.d.mts} +1 -1
- package/dist/{wxr-taxonomies-Ca68766D.d.mts.map → wxr-taxonomies-B2Og_6rU.d.mts.map} +1 -1
- package/dist/{wxr-taxonomies-B1R3vBoD.mjs → wxr-taxonomies-Cxngsjwo.mjs} +4 -4
- package/dist/{wxr-taxonomies-B1R3vBoD.mjs.map → wxr-taxonomies-Cxngsjwo.mjs.map} +1 -1
- package/dist/{zod-generator-LC-on_Vb.mjs → zod-generator-BuYSQJB7.mjs} +32 -22
- package/dist/zod-generator-BuYSQJB7.mjs.map +1 -0
- package/package.json +20 -9
- package/src/api/errors.ts +22 -0
- package/src/api/handlers/content.ts +49 -11
- package/src/api/handlers/index.ts +18 -0
- package/src/api/handlers/manifest.ts +161 -12
- package/src/api/handlers/media-allowlist.ts +1 -0
- package/src/api/handlers/media-folders.ts +130 -0
- package/src/api/handlers/media-usage-activation.ts +102 -0
- package/src/api/handlers/media-usage.ts +108 -0
- package/src/api/handlers/media.ts +92 -2
- package/src/api/handlers/registry.ts +483 -561
- package/src/api/handlers/taxonomies.ts +16 -9
- package/src/api/openapi/document.ts +277 -7
- package/src/api/parse.ts +1 -1
- package/src/api/schemas/auth.ts +4 -4
- package/src/api/schemas/bylines.ts +3 -3
- package/src/api/schemas/comments.ts +1 -1
- package/src/api/schemas/common.ts +3 -2
- package/src/api/schemas/content.ts +78 -22
- package/src/api/schemas/media-usage.ts +77 -0
- package/src/api/schemas/media.ts +121 -0
- package/src/api/schemas/redirects.ts +6 -1
- package/src/api/schemas/schema.ts +4 -0
- package/src/api/schemas/setup.ts +1 -1
- package/src/api/schemas/taxonomies.ts +2 -2
- package/src/api/schemas/users.ts +1 -1
- package/src/api/types.ts +23 -10
- package/src/astro/dev-typegen.ts +35 -0
- package/src/astro/image-endpoint.ts +2 -2
- package/src/astro/integration/dev-typegen.ts +91 -0
- package/src/astro/integration/index.ts +9 -44
- package/src/astro/integration/routes.ts +23 -0
- package/src/astro/integration/vite-config.ts +23 -9
- package/src/astro/middleware/auth.ts +4 -0
- package/src/astro/middleware.ts +5 -7
- package/src/astro/routes/api/admin/api-tokens/index.ts +4 -1
- package/src/astro/routes/api/admin/media-usage/activation.ts +42 -0
- package/src/astro/routes/api/admin/media-usage/progress.ts +37 -0
- package/src/astro/routes/api/admin/oauth-clients/[id].ts +1 -1
- package/src/astro/routes/api/admin/oauth-clients/index.ts +1 -1
- package/src/astro/routes/api/admin/plugins/registry/[id]/update.ts +4 -0
- package/src/astro/routes/api/admin/plugins/registry/artifact.ts +247 -101
- package/src/astro/routes/api/admin/plugins/registry/install.ts +4 -0
- package/src/astro/routes/api/admin/plugins/registry/verify.ts +60 -0
- package/src/astro/routes/api/auth/me.ts +14 -2
- package/src/astro/routes/api/content/[collection]/[id]/discard-draft.ts +8 -2
- package/src/astro/routes/api/content/[collection]/[id]/publish.ts +2 -1
- package/src/astro/routes/api/content/[collection]/[id]/unpublish.ts +6 -2
- package/src/astro/routes/api/manifest.ts +1 -1
- package/src/astro/routes/api/media/[id]/replace.ts +114 -0
- package/src/astro/routes/api/media/[id].ts +3 -0
- package/src/astro/routes/api/media/file/[...key].ts +4 -1
- package/src/astro/routes/api/media/folders/[id].ts +55 -0
- package/src/astro/routes/api/media/folders/index.ts +37 -0
- package/src/astro/routes/api/media/upload-url.ts +8 -4
- package/src/astro/routes/api/media.ts +66 -10
- package/src/astro/routes/api/menus/[name]/items/[id].ts +7 -2
- package/src/astro/routes/api/menus/[name]/items.ts +4 -1
- package/src/astro/routes/api/menus/[name]/reorder.ts +4 -1
- package/src/astro/routes/api/menus/[name]/translations.ts +4 -1
- package/src/astro/routes/api/menus/[name].ts +7 -2
- package/src/astro/routes/api/menus/index.ts +4 -1
- package/src/astro/routes/api/settings/email.ts +1 -1
- package/src/astro/routes/api/settings.ts +4 -1
- package/src/astro/routes/api/setup/dev-bypass.ts +12 -0
- package/src/astro/routes/api/taxonomies/[name]/reorder.ts +4 -1
- package/src/astro/routes/api/taxonomies/[name]/terms/[slug]/translations.ts +4 -1
- package/src/astro/routes/api/taxonomies/[name]/terms/[slug].ts +7 -2
- package/src/astro/routes/api/taxonomies/[name]/terms/index.ts +4 -1
- package/src/astro/routes/api/taxonomies/[name].ts +7 -2
- package/src/astro/routes/api/taxonomies/index.ts +4 -1
- package/src/astro/routes/api/widget-areas/[name]/reorder.ts +3 -1
- package/src/astro/routes/api/widget-areas/[name]/widgets/[id].ts +5 -2
- package/src/astro/routes/api/widget-areas/[name]/widgets.ts +3 -1
- package/src/astro/routes/api/widget-areas/[name].ts +3 -1
- package/src/astro/routes/api/widget-areas/index.ts +3 -1
- package/src/astro/types.ts +34 -6
- package/src/auth/challenge-store.ts +3 -1
- package/src/aws-sdk.d.ts +1 -0
- package/src/cache/chrome-tags.ts +24 -0
- package/src/client/index.ts +140 -2
- package/src/client/transport.ts +6 -2
- package/src/components/EmDashImage.astro +156 -51
- package/src/components/EmDashMedia.astro +2 -1
- package/src/components/Gallery.astro +7 -0
- package/src/components/InlinePortableTextEditor.tsx +136 -2
- package/src/components/LiveSearch.astro +23 -0
- package/src/components/inline-code-block.tsx +180 -49
- package/src/components/widgets/Archives.astro +2 -37
- package/src/content/converters/gallery.ts +2 -0
- package/src/content/converters/index.ts +2 -0
- package/src/content/converters/mark-safety.ts +1 -0
- package/src/content/converters/portable-text-identity.ts +139 -0
- package/src/content/converters/portable-text-to-prosemirror.ts +202 -69
- package/src/content/converters/prosemirror-to-portable-text.ts +96 -25
- package/src/content/converters/types.ts +3 -0
- package/src/database/connection.ts +2 -31
- package/src/database/index.ts +1 -1
- package/src/database/json-recordset.ts +16 -0
- package/src/database/migrations/017_authorization_codes.ts +14 -4
- package/src/database/migrations/019_i18n.ts +1 -1
- package/src/database/migrations/071_restore_content_bylines_table.ts +43 -0
- package/src/database/migrations/072_media_folders.ts +72 -0
- package/src/database/migrations/073_media_focal_point.ts +57 -0
- package/src/database/migrations/074_content_deleted_scheduled_index.ts +55 -0
- package/src/database/migrations/runner.ts +11 -3
- package/src/database/repositories/byline.ts +32 -16
- package/src/database/repositories/content.ts +119 -51
- package/src/database/repositories/media-folders.ts +115 -0
- package/src/database/repositories/media-usage-work.ts +395 -111
- package/src/database/repositories/media-usage.ts +1104 -47
- package/src/database/repositories/media.ts +156 -29
- package/src/database/repositories/plugin-storage.ts +74 -9
- package/src/database/repositories/types.ts +8 -7
- package/src/database/transaction.ts +1 -0
- package/src/database/types.ts +13 -0
- package/src/db/adapters.ts +10 -3
- package/src/db/node-sqlite-compat.ts +78 -0
- package/src/db/postgres.ts +23 -0
- package/src/db/sqlite.ts +3 -3
- package/src/emdash-runtime.ts +186 -251
- package/src/fields/boolean.ts +1 -1
- package/src/fields/datetime.ts +1 -1
- package/src/fields/file.ts +1 -1
- package/src/fields/image.ts +7 -1
- package/src/fields/integer.ts +1 -1
- package/src/fields/json.ts +1 -1
- package/src/fields/multiselect.ts +1 -1
- package/src/fields/number.ts +1 -1
- package/src/fields/portable-text.ts +1 -1
- package/src/fields/richtext.ts +1 -1
- package/src/fields/select.ts +1 -1
- package/src/fields/slug.ts +1 -1
- package/src/fields/text.ts +1 -1
- package/src/fields/textarea.ts +1 -1
- package/src/fields/types.ts +8 -4
- package/src/index.ts +30 -3
- package/src/loader.ts +63 -10
- package/src/mcp/server.ts +228 -24
- package/src/media/focal-point.ts +37 -0
- package/src/media/image-endpoint.ts +5 -2
- package/src/media/local-runtime.ts +8 -0
- package/src/media/mime.ts +1 -0
- package/src/media/normalize.ts +25 -4
- package/src/media/types.ts +10 -0
- package/src/media/usage/activation.ts +162 -35
- package/src/media/usage/capture-triggers.ts +19 -3
- package/src/media/usage/cleanup.ts +9 -8
- package/src/media/usage/collection-deletion-processor.ts +7 -3
- package/src/media/usage/collection-deletion.ts +10 -0
- package/src/media/usage/content-refresh.ts +258 -39
- package/src/media/usage/content-snapshots.ts +128 -31
- package/src/media/usage/extractor.ts +32 -13
- package/src/media/usage/maintenance-engine.ts +166 -0
- package/src/media/usage/reconciliation-processor.ts +106 -29
- package/src/media/usage/reconciliation.ts +90 -7
- package/src/media/usage/work-processor.ts +342 -101
- package/src/menus/index.ts +16 -0
- package/src/object-cache/index.ts +44 -2
- package/src/plugin-types.ts +18 -1
- package/src/plugins/hooks.ts +4 -1
- package/src/plugins/index.ts +7 -0
- package/src/plugins/manager.ts +2 -1
- package/src/plugins/manifest-schema.ts +1 -1
- package/src/plugins/routes.ts +3 -1
- package/src/plugins/sandbox/hook-result.ts +52 -0
- package/src/plugins/sandbox/index.ts +10 -0
- package/src/plugins/save-rejection.ts +20 -0
- package/src/plugins/scheduler/node.ts +1 -13
- package/src/plugins/scheduler/types.ts +0 -2
- package/src/plugins/state.ts +13 -3
- package/src/plugins/types.ts +6 -0
- package/src/registry/artifact-checksum.ts +15 -0
- package/src/registry/artifact-fetch.ts +530 -0
- package/src/registry/artifact-verification.ts +85 -0
- package/src/registry/authoritative-records.ts +180 -0
- package/src/registry/config.ts +24 -6
- package/src/registry/record-labels.ts +28 -0
- package/src/registry/types.ts +12 -15
- package/src/schema/registry.ts +26 -3
- package/src/schema/types.ts +1 -0
- package/src/schema/zod-generator.ts +28 -17
- package/src/security/ssrf.ts +26 -4
- package/src/seed/apply.ts +4 -4
- package/src/settings/index.ts +16 -0
- package/src/storage/local.ts +1 -0
- package/src/storage/s3.ts +2 -0
- package/src/storage/types.ts +2 -0
- package/src/taxonomies/index.ts +40 -20
- package/src/ui.ts +2 -0
- package/src/widgets/archives.ts +67 -0
- package/src/widgets/index.ts +16 -0
- package/dist/api-BeBglVxU.mjs +0 -4695
- package/dist/api-BeBglVxU.mjs.map +0 -1
- package/dist/byline-yjvWq4ip.mjs.map +0 -1
- package/dist/challenge-store-SIL5DsF2.mjs.map +0 -1
- package/dist/collection-deletion-DQPvMD8R.mjs.map +0 -1
- package/dist/content-ZHCc1ngN.mjs.map +0 -1
- package/dist/content-refresh-B_8SJzuU.mjs.map +0 -1
- package/dist/context-ZldbZcle.mjs.map +0 -1
- package/dist/errors-CLUPm7aD.mjs.map +0 -1
- package/dist/index-BVBZj4-7.d.mts.map +0 -1
- package/dist/loader-CdG_Ci3H.mjs.map +0 -1
- package/dist/manifest-schema-BXbUAHod.mjs.map +0 -1
- package/dist/media-BWWWb8kg.mjs.map +0 -1
- package/dist/media-CzhAn2--.mjs.map +0 -1
- package/dist/media-allowlist-D6x-Us02.mjs.map +0 -1
- package/dist/media-usage-BZCydfvu.mjs.map +0 -1
- package/dist/media-usage-work-DrCbqBcl.mjs.map +0 -1
- package/dist/menus-DSo5QeW0.mjs.map +0 -1
- package/dist/mime-DfIVjNkr.mjs.map +0 -1
- package/dist/normalize-Bc-s_r-a.mjs.map +0 -1
- package/dist/object-cache-71tPfV4A.mjs.map +0 -1
- package/dist/options--hhz-jZ1.d.mts.map +0 -1
- package/dist/placeholder-Dp0K3RkD.d.mts.map +0 -1
- package/dist/redirects-DTDHWH31.mjs.map +0 -1
- package/dist/registry-Cqa2I749.mjs.map +0 -1
- package/dist/relations-BBApI4e2.mjs.map +0 -1
- package/dist/relations-BHo5A8Zf.d.mts.map +0 -1
- package/dist/runner-BYHZn3Jy.d.mts.map +0 -1
- package/dist/runner-C1T11CfC.mjs.map +0 -1
- package/dist/settings-xRdoUZr0.mjs.map +0 -1
- package/dist/state-DYwPue40.mjs.map +0 -1
- package/dist/taxonomies-BlrncHi9.mjs.map +0 -1
- package/dist/taxonomies-OHUIiIpI.mjs.map +0 -1
- package/dist/types-BcqdcT-r.d.mts.map +0 -1
- package/dist/types-C2pMvO62.d.mts.map +0 -1
- package/dist/types-CP1CflWf.mjs +0 -3
- package/dist/types-DN64_zzZ.d.mts.map +0 -1
- package/dist/types-DQIDRKF2.d.mts.map +0 -1
- package/dist/version-DB_fqCSI.mjs +0 -7
- package/dist/widgets-BD3ho7Rq.mjs.map +0 -1
- package/dist/zod-generator-LC-on_Vb.mjs.map +0 -1
- /package/dist/{api-tokens-rIXC6LdE.mjs → api-tokens-BfYts-sq.mjs} +0 -0
- /package/dist/{ssrf-DpXgKsna.mjs → ssrf-Dg3cIT-b.mjs} +0 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"redirects-DyChwDkG.mjs","names":[],"sources":["../src/redirects/loops.ts","../src/api/handlers/redirects.ts"],"sourcesContent":["/**\n * Redirect loop and chain detection utilities.\n *\n * Builds a directed graph from redirect rules and detects:\n * - Cycles (loops): /a → /b → /c → /a\n * - Long chains: /a → /b → /c → /d → /e (exceeding a warning threshold)\n *\n * Handles both exact and pattern redirects. When the walker encounters\n * a path with no exact source match, it tests against compiled pattern\n * sources and resolves the destination using captured parameters.\n */\n\nimport {\n\tcompilePattern,\n\tmatchPattern,\n\tinterpolateDestination,\n\ttype CompiledPattern,\n} from \"./patterns.js\";\n\nexport interface RedirectEdge {\n\tid: string;\n\tsource: string;\n\tdestination: string;\n\tenabled: boolean;\n\tisPattern: boolean;\n}\n\ninterface CompiledPatternRedirect {\n\tid: string;\n\tcompiled: CompiledPattern;\n\tdestination: string;\n}\n\n/**\n * Compile all enabled pattern redirects for matching during graph walks.\n */\nfunction compilePatterns(edges: RedirectEdge[]): CompiledPatternRedirect[] {\n\tconst result: CompiledPatternRedirect[] = [];\n\tfor (const edge of edges) {\n\t\tif (edge.enabled && edge.isPattern) {\n\t\t\tresult.push({\n\t\t\t\tid: edge.id,\n\t\t\t\tcompiled: compilePattern(edge.source),\n\t\t\t\tdestination: edge.destination,\n\t\t\t});\n\t\t}\n\t}\n\treturn result;\n}\n\n/** Single-segment dummy value for representative path generation */\nconst DUMMY_SEGMENT = \"__p__\";\n\n/** Splat pattern: [...paramName] */\nconst SPLAT_RE = /\\[\\.\\.\\.(\\w+)\\]/g;\n\n/** Param pattern: [paramName] */\nconst PARAM_RE = /\\[(\\w+)\\]/g;\n\n/**\n * Extract the literal prefix from a pattern source (everything before the\n * first placeholder), stripped of leading segments shared with a base path.\n * e.g., \"/new/docs/[slug]\" → \"docs/__p__\" (the part after \"/new/\")\n */\nfunction extractPatternSuffix(patternSource: string): string {\n\t// Replace placeholders with dummy values\n\tlet result = patternSource.replace(SPLAT_RE, DUMMY_SEGMENT);\n\tSPLAT_RE.lastIndex = 0;\n\tresult = result.replace(PARAM_RE, DUMMY_SEGMENT);\n\t// Strip leading slash and first segment (e.g., \"/new/docs/__p__\" → \"docs/__p__\")\n\tconst parts = result.split(\"/\").filter(Boolean);\n\treturn parts.slice(1).join(\"/\");\n}\n\n/**\n * Generate representative concrete paths from a template string.\n * Replaces [param] with a dummy segment and [...rest] with multiple\n * depth variants. For catch-alls, also generates representatives using\n * literal prefixes from existing pattern sources to catch cross-pattern loops.\n */\nfunction generateRepresentatives(template: string, existingEdges?: RedirectEdge[]): string[] {\n\tconst hasSplat = SPLAT_RE.test(template);\n\tSPLAT_RE.lastIndex = 0;\n\n\tif (hasSplat) {\n\t\t// Extract the static prefix before the catch-all (e.g., \"/old/\" from \"/old/[...path]\")\n\t\tconst splatIndex = template.indexOf(\"[...\");\n\t\tconst prefix = template.slice(0, splatIndex);\n\n\t\tconst reps = [\n\t\t\ttemplate.replace(SPLAT_RE, DUMMY_SEGMENT).replace(PARAM_RE, DUMMY_SEGMENT),\n\t\t\ttemplate\n\t\t\t\t.replace(SPLAT_RE, `${DUMMY_SEGMENT}/${DUMMY_SEGMENT}`)\n\t\t\t\t.replace(PARAM_RE, DUMMY_SEGMENT),\n\t\t\ttemplate\n\t\t\t\t.replace(SPLAT_RE, `${DUMMY_SEGMENT}/${DUMMY_SEGMENT}/${DUMMY_SEGMENT}`)\n\t\t\t\t.replace(PARAM_RE, DUMMY_SEGMENT),\n\t\t];\n\n\t\t// Add representatives derived from existing pattern sources' literal prefixes\n\t\tif (existingEdges) {\n\t\t\tfor (const edge of existingEdges) {\n\t\t\t\tif (edge.enabled && edge.isPattern && edge.source !== template) {\n\t\t\t\t\tconst suffix = extractPatternSuffix(edge.source);\n\t\t\t\t\tif (suffix) {\n\t\t\t\t\t\treps.push(`${prefix}${suffix}`);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn reps;\n\t}\n\n\treturn [template.replace(PARAM_RE, DUMMY_SEGMENT)];\n}\n\n/**\n * Resolve the next hop for a given path. Tries exact match first,\n * then pattern matching with parameter interpolation for concrete paths,\n * then representative-based matching for template strings.\n */\nfunction resolveNext(\n\tpath: string,\n\tgraph: Map<string, { destination: string; id: string }>,\n\tpatterns: CompiledPatternRedirect[],\n\tedges?: RedirectEdge[],\n): { destination: string; id: string } | null {\n\t// Exact match (fast) — works for both real paths and template strings\n\tconst exact = graph.get(path);\n\tif (exact) return exact;\n\n\tif (!path.includes(\"[\")) {\n\t\t// Concrete path — try pattern matching directly\n\t\tfor (const pr of patterns) {\n\t\t\tconst params = matchPattern(pr.compiled, path);\n\t\t\tif (params) {\n\t\t\t\tconst resolved = interpolateDestination(pr.destination, params);\n\t\t\t\treturn { destination: resolved, id: pr.id };\n\t\t\t}\n\t\t}\n\t} else {\n\t\t// Template string — generate representative paths and test against patterns\n\t\tconst representatives = generateRepresentatives(path, edges);\n\t\tfor (const pr of patterns) {\n\t\t\tfor (const rep of representatives) {\n\t\t\t\tconst params = matchPattern(pr.compiled, rep);\n\t\t\t\tif (params) {\n\t\t\t\t\tconst resolved = interpolateDestination(pr.destination, params);\n\t\t\t\t\treturn { destination: resolved, id: pr.id };\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn null;\n}\n\n/**\n * Build an adjacency map from redirect edges.\n * Includes both exact and pattern redirects — pattern redirects use their\n * template strings as literal graph edges, which works because EmDash\n * patterns pass parameters through without transformation.\n */\nfunction buildGraph(edges: RedirectEdge[]): Map<string, { destination: string; id: string }> {\n\tconst graph = new Map<string, { destination: string; id: string }>();\n\tfor (const edge of edges) {\n\t\tif (edge.enabled) {\n\t\t\tgraph.set(edge.source, { destination: edge.destination, id: edge.id });\n\t\t}\n\t}\n\treturn graph;\n}\n\n/**\n * Detect all redirect IDs that participate in cycles.\n * Walks every node in the graph once, collecting IDs from any cycles found.\n *\n * @returns Array of redirect IDs that are part of a loop\n */\nexport function detectLoops(edges: RedirectEdge[]): string[] {\n\tconst graph = buildGraph(edges);\n\tconst patterns = compilePatterns(edges);\n\tconst visited = new Set<string>();\n\tconst loopRedirectIds = new Set<string>();\n\n\tfor (const [startSource] of graph) {\n\t\tif (visited.has(startSource)) continue;\n\n\t\tconst path: string[] = [];\n\t\tconst pathSet = new Set<string>();\n\t\tconst pathIds: string[] = [];\n\t\tlet current: string | undefined = startSource;\n\n\t\twhile (current) {\n\t\t\tif (pathSet.has(current)) {\n\t\t\t\t// Found a cycle — collect IDs of redirects in the loop\n\t\t\t\tconst loopStart = path.indexOf(current);\n\t\t\t\tfor (const id of pathIds.slice(loopStart)) loopRedirectIds.add(id);\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tif (visited.has(current)) {\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tconst next = resolveNext(current, graph, patterns, edges);\n\t\t\tif (!next) break;\n\n\t\t\tpath.push(current);\n\t\t\tpathSet.add(current);\n\t\t\tpathIds.push(next.id);\n\t\t\tcurrent = next.destination;\n\t\t}\n\n\t\tfor (const node of path) visited.add(node);\n\t}\n\n\treturn [...loopRedirectIds];\n}\n\n/**\n * Find a compiled pattern redirect whose source matches the given resolved path,\n * returning the source template string for display purposes.\n */\nfunction findMatchingTemplate(\n\tresolvedPath: string,\n\tpatterns: CompiledPatternRedirect[],\n): string | null {\n\tfor (const pr of patterns) {\n\t\tif (matchPattern(pr.compiled, resolvedPath) !== null) {\n\t\t\treturn pr.compiled.source;\n\t\t}\n\t}\n\treturn null;\n}\n\n/**\n * Check if adding or updating a redirect would create a loop.\n *\n * Walks the chain from `destination` through existing redirects.\n * If it reaches `source`, a cycle would form.\n *\n * @returns The loop path if a cycle would be created, or null if safe\n */\nexport function wouldCreateLoop(\n\tsource: string,\n\tdestination: string,\n\texistingEdges: RedirectEdge[],\n\texcludeId?: string,\n): string[] | null {\n\tconst filtered = excludeId ? existingEdges.filter((e) => e.id !== excludeId) : existingEdges;\n\tconst graph = buildGraph(filtered);\n\tconst patterns = compilePatterns(filtered);\n\n\t// If the proposed source is a pattern, compile it so we can check\n\t// whether resolved paths would match it (not just string equality)\n\tconst sourceIsPattern = source.includes(\"[\");\n\tconst compiledSource = sourceIsPattern ? compilePattern(source) : null;\n\n\t// Determine starting points for the walk. If the destination is a\n\t// template, generate representative concrete paths AND find existing\n\t// exact sources in the graph that match the template.\n\tlet startingPoints: string[];\n\tif (destination.includes(\"[\")) {\n\t\tconst reps = generateRepresentatives(destination, filtered);\n\t\t// Also find existing exact graph keys that match this template\n\t\tconst compiled = compilePattern(destination);\n\t\tfor (const [key] of graph) {\n\t\t\tif (!key.includes(\"[\") && matchPattern(compiled, key) !== null) {\n\t\t\t\treps.push(key);\n\t\t\t}\n\t\t}\n\t\t// Always include the destination itself — it may be an exact graph key\n\t\t// (e.g., /a/sub/[...path] exists as a literal source in the graph)\n\t\treps.push(destination);\n\t\tstartingPoints = reps;\n\t} else {\n\t\tstartingPoints = [destination];\n\t}\n\n\tfor (const start of startingPoints) {\n\t\tconst path = [source, destination];\n\t\tlet current = start;\n\t\tconst seen = new Set<string>([source, destination, start]);\n\n\t\t// Walk the chain until it ends or we revisit a node\n\t\t// eslint-disable-next-line no-constant-condition -- terminates via return/break when chain ends or cycle found\n\t\twhile (true) {\n\t\t\tconst next = resolveNext(current, graph, patterns, filtered);\n\t\t\tif (!next) break; // chain ends, try next starting point\n\n\t\t\t// Check if we've looped back — either exact match or pattern match\n\t\t\tconst loopsBack =\n\t\t\t\tseen.has(next.destination) ||\n\t\t\t\t(compiledSource !== null && matchPattern(compiledSource, next.destination) !== null);\n\n\t\t\tif (loopsBack) {\n\t\t\t\t// Show the source template instead of dummy resolved path\n\t\t\t\tconst displayPath =\n\t\t\t\t\t!seen.has(next.destination) && compiledSource !== null ? source : next.destination;\n\t\t\t\tpath.push(displayPath);\n\t\t\t\treturn path; // cycle found\n\t\t\t}\n\n\t\t\t// If the resolved path contains dummy segments, try to find the\n\t\t\t// original pattern template that produced it for cleaner display\n\t\t\tconst cleanDest = next.destination.includes(DUMMY_SEGMENT)\n\t\t\t\t? (findMatchingTemplate(next.destination, patterns) ?? next.destination)\n\t\t\t\t: next.destination;\n\t\t\tpath.push(cleanDest);\n\t\t\tseen.add(next.destination);\n\t\t\tcurrent = next.destination;\n\t\t}\n\t}\n\n\treturn null;\n}\n","/**\n * Redirect CRUD and 404 log handlers\n */\n\nimport type { Kysely } from \"kysely\";\n\nimport { OptionsRepository } from \"../../database/repositories/options.js\";\nimport {\n\tRedirectRepository,\n\ttype Redirect,\n\ttype NotFoundEntry,\n\ttype NotFoundSummary,\n} from \"../../database/repositories/redirect.js\";\nimport { InvalidCursorError } from \"../../database/repositories/types.js\";\nimport type { FindManyResult } from \"../../database/repositories/types.js\";\nimport type { Database } from \"../../database/types.js\";\nimport { wouldCreateLoop, detectLoops, type RedirectEdge } from \"../../redirects/loops.js\";\nimport { validatePattern, validateDestinationParams, isPattern } from \"../../redirects/patterns.js\";\nimport { isTerminalStatus } from \"../../redirects/status.js\";\nimport type { ApiResult } from \"../types.js\";\n\n// ---------------------------------------------------------------------------\n// Redirects\n// ---------------------------------------------------------------------------\n\n/**\n * List redirects with cursor pagination and optional filters\n */\nexport async function handleRedirectList(\n\tdb: Kysely<Database>,\n\tparams: {\n\t\tcursor?: string;\n\t\tlimit?: number;\n\t\tsearch?: string;\n\t\tgroup?: string;\n\t\tenabled?: boolean;\n\t\tauto?: boolean;\n\t},\n): Promise<ApiResult<FindManyResult<Redirect> & { loopRedirectIds?: string[] }>> {\n\ttry {\n\t\tconst repo = new RedirectRepository(db);\n\t\tconst result = await repo.findMany(params);\n\n\t\tconst loopRedirectIds = await getLoopRedirectIds(db);\n\n\t\treturn {\n\t\t\tsuccess: true,\n\t\t\tdata: {\n\t\t\t\t...result,\n\t\t\t\t...(loopRedirectIds.length > 0 ? { loopRedirectIds } : {}),\n\t\t\t},\n\t\t};\n\t} catch (error) {\n\t\tif (error instanceof InvalidCursorError) {\n\t\t\treturn {\n\t\t\t\tsuccess: false,\n\t\t\t\terror: { code: \"INVALID_CURSOR\", message: error.message },\n\t\t\t};\n\t\t}\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\terror: { code: \"REDIRECT_LIST_ERROR\", message: \"Failed to fetch redirects\" },\n\t\t};\n\t}\n}\n\n/**\n * Create a redirect rule\n */\nexport async function handleRedirectCreate(\n\tdb: Kysely<Database>,\n\tinput: {\n\t\tsource: string;\n\t\tdestination?: string;\n\t\ttype?: number;\n\t\tenabled?: boolean;\n\t\tgroupName?: string | null;\n\t},\n): Promise<ApiResult<Redirect>> {\n\ttry {\n\t\tconst repo = new RedirectRepository(db);\n\n\t\tconst type = input.type ?? 301;\n\t\t// Terminal statuses (410 Gone / 451) are served directly and have no\n\t\t// destination — skip the destination/loop checks for them.\n\t\tconst terminal = isTerminalStatus(type);\n\t\tconst destination = terminal ? \"\" : (input.destination ?? \"\");\n\n\t\t// Source and destination must differ\n\t\tif (!terminal && input.source === destination) {\n\t\t\treturn {\n\t\t\t\tsuccess: false,\n\t\t\t\terror: {\n\t\t\t\t\tcode: \"VALIDATION_ERROR\",\n\t\t\t\t\tmessage: \"Source and destination must be different\",\n\t\t\t\t},\n\t\t\t};\n\t\t}\n\n\t\t// If source looks like a pattern, validate it\n\t\tconst sourceIsPattern = isPattern(input.source);\n\t\tif (sourceIsPattern) {\n\t\t\tconst patternError = validatePattern(input.source);\n\t\t\tif (patternError) {\n\t\t\t\treturn {\n\t\t\t\t\tsuccess: false,\n\t\t\t\t\terror: { code: \"VALIDATION_ERROR\", message: `Invalid source pattern: ${patternError}` },\n\t\t\t\t};\n\t\t\t}\n\n\t\t\t// Validate destination params reference valid source params\n\t\t\t// (terminal rules have no destination to interpolate)\n\t\t\tif (!terminal) {\n\t\t\t\tconst destError = validateDestinationParams(input.source, destination);\n\t\t\t\tif (destError) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tsuccess: false,\n\t\t\t\t\t\terror: { code: \"VALIDATION_ERROR\", message: destError },\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Check for duplicate source (exact match only for non-patterns)\n\t\tconst existing = await repo.findBySource(input.source);\n\t\tif (existing) {\n\t\t\treturn {\n\t\t\t\tsuccess: false,\n\t\t\t\terror: {\n\t\t\t\t\tcode: \"CONFLICT\",\n\t\t\t\t\tmessage: `A redirect from \"${input.source}\" already exists`,\n\t\t\t\t},\n\t\t\t};\n\t\t}\n\n\t\t// Check for redirect loops (skip if creating as disabled, or terminal —\n\t\t// a Gone rule has no destination, so it can't form a loop)\n\t\tif (!terminal && input.enabled !== false) {\n\t\t\tconst edges = toEdges(await repo.findAllEnabled());\n\t\t\tconst loopPath = wouldCreateLoop(input.source, destination, edges);\n\t\t\tif (loopPath) return loopError(loopPath);\n\t\t}\n\n\t\tconst redirect = await repo.create({\n\t\t\tsource: input.source,\n\t\t\tdestination,\n\t\t\ttype,\n\t\t\tisPattern: sourceIsPattern,\n\t\t\tenabled: input.enabled ?? true,\n\t\t\tgroupName: input.groupName ?? null,\n\t\t});\n\n\t\treturn { success: true, data: redirect };\n\t} catch {\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\terror: { code: \"REDIRECT_CREATE_ERROR\", message: \"Failed to create redirect\" },\n\t\t};\n\t}\n}\n\n/**\n * Get a redirect by ID\n */\nexport async function handleRedirectGet(\n\tdb: Kysely<Database>,\n\tid: string,\n): Promise<ApiResult<Redirect>> {\n\ttry {\n\t\tconst repo = new RedirectRepository(db);\n\t\tconst redirect = await repo.findById(id);\n\n\t\tif (!redirect) {\n\t\t\treturn {\n\t\t\t\tsuccess: false,\n\t\t\t\terror: { code: \"NOT_FOUND\", message: `Redirect \"${id}\" not found` },\n\t\t\t};\n\t\t}\n\n\t\treturn { success: true, data: redirect };\n\t} catch {\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\terror: { code: \"REDIRECT_GET_ERROR\", message: \"Failed to fetch redirect\" },\n\t\t};\n\t}\n}\n\n/**\n * Update a redirect by ID\n */\nexport async function handleRedirectUpdate(\n\tdb: Kysely<Database>,\n\tid: string,\n\tinput: {\n\t\tsource?: string;\n\t\tdestination?: string;\n\t\ttype?: number;\n\t\tenabled?: boolean;\n\t\tgroupName?: string | null;\n\t},\n): Promise<ApiResult<Redirect>> {\n\ttry {\n\t\tconst repo = new RedirectRepository(db);\n\n\t\tconst existing = await repo.findById(id);\n\t\tif (!existing) {\n\t\t\treturn {\n\t\t\t\tsuccess: false,\n\t\t\t\terror: { code: \"NOT_FOUND\", message: `Redirect \"${id}\" not found` },\n\t\t\t};\n\t\t}\n\n\t\tconst newSource = input.source ?? existing.source;\n\t\tconst newDest = input.destination ?? existing.destination;\n\n\t\t// Source and destination must differ\n\t\tif (newSource === newDest) {\n\t\t\treturn {\n\t\t\t\tsuccess: false,\n\t\t\t\terror: {\n\t\t\t\t\tcode: \"VALIDATION_ERROR\",\n\t\t\t\t\tmessage: \"Source and destination must be different\",\n\t\t\t\t},\n\t\t\t};\n\t\t}\n\n\t\t// If source is changing, validate patterns\n\t\tif (input.source !== undefined) {\n\t\t\tconst sourceIsPattern = isPattern(input.source);\n\t\t\tif (sourceIsPattern) {\n\t\t\t\tconst patternError = validatePattern(input.source);\n\t\t\t\tif (patternError) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tsuccess: false,\n\t\t\t\t\t\terror: {\n\t\t\t\t\t\t\tcode: \"VALIDATION_ERROR\",\n\t\t\t\t\t\t\tmessage: `Invalid source pattern: ${patternError}`,\n\t\t\t\t\t\t},\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Check for duplicate source (exclude self)\n\t\t\tconst dup = await repo.findBySource(input.source);\n\t\t\tif (dup && dup.id !== id) {\n\t\t\t\treturn {\n\t\t\t\t\tsuccess: false,\n\t\t\t\t\terror: {\n\t\t\t\t\t\tcode: \"CONFLICT\",\n\t\t\t\t\t\tmessage: `A redirect from \"${input.source}\" already exists`,\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\n\t\t// Validate destination params against the (possibly updated) source\n\t\tconst newSourceIsPattern = isPattern(newSource);\n\t\tif (newSourceIsPattern) {\n\t\t\tconst destError = validateDestinationParams(newSource, newDest);\n\t\t\tif (destError) {\n\t\t\t\treturn {\n\t\t\t\t\tsuccess: false,\n\t\t\t\t\terror: { code: \"VALIDATION_ERROR\", message: destError },\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\n\t\t// Check for redirect loops if source or destination changed\n\t\tif (input.source !== undefined || input.destination !== undefined) {\n\t\t\tconst edges = toEdges(await repo.findAllEnabled());\n\t\t\tconst loopPath = wouldCreateLoop(newSource, newDest, edges, id);\n\t\t\tif (loopPath) return loopError(loopPath);\n\t\t}\n\n\t\tconst updated = await repo.update(id, {\n\t\t\tsource: input.source,\n\t\t\tdestination: input.destination,\n\t\t\ttype: input.type,\n\t\t\tenabled: input.enabled,\n\t\t\tgroupName: input.groupName,\n\t\t});\n\n\t\tif (!updated) {\n\t\t\treturn {\n\t\t\t\tsuccess: false,\n\t\t\t\terror: { code: \"REDIRECT_UPDATE_ERROR\", message: \"Failed to update redirect\" },\n\t\t\t};\n\t\t}\n\n\t\t// Recompute cache — redirect was modified, so re-fetch\n\t\tawait updateLoopCache(db);\n\n\t\treturn { success: true, data: updated };\n\t} catch {\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\terror: { code: \"REDIRECT_UPDATE_ERROR\", message: \"Failed to update redirect\" },\n\t\t};\n\t}\n}\n\n/**\n * Delete a redirect by ID\n */\nexport async function handleRedirectDelete(\n\tdb: Kysely<Database>,\n\tid: string,\n): Promise<ApiResult<{ deleted: true }>> {\n\ttry {\n\t\tconst repo = new RedirectRepository(db);\n\t\tconst deleted = await repo.delete(id);\n\n\t\tif (!deleted) {\n\t\t\treturn {\n\t\t\t\tsuccess: false,\n\t\t\t\terror: { code: \"NOT_FOUND\", message: `Redirect \"${id}\" not found` },\n\t\t\t};\n\t\t}\n\n\t\tawait updateLoopCache(db);\n\n\t\treturn { success: true, data: { deleted: true } };\n\t} catch {\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\terror: { code: \"REDIRECT_DELETE_ERROR\", message: \"Failed to delete redirect\" },\n\t\t};\n\t}\n}\n\n// ---------------------------------------------------------------------------\n// Loop analysis cache\n// ---------------------------------------------------------------------------\n\nfunction loopError(loopPath: string[]): ApiResult<never> {\n\tconst hops = loopPath\n\t\t.slice(0, -1)\n\t\t.map((p, i) => `${p} \\u2192 ${loopPath[i + 1]}`)\n\t\t.join(\"\\n\");\n\treturn {\n\t\tsuccess: false,\n\t\terror: {\n\t\t\tcode: \"VALIDATION_ERROR\",\n\t\t\tmessage: `This redirect would create a loop:\\n${hops}`,\n\t\t},\n\t};\n}\n\nfunction toEdges(redirects: Redirect[]): RedirectEdge[] {\n\treturn redirects.map((r) => ({\n\t\tid: r.id,\n\t\tsource: r.source,\n\t\tdestination: r.destination,\n\t\tenabled: r.enabled,\n\t\tisPattern: r.isPattern,\n\t}));\n}\n\nconst LOOP_CACHE_KEY = \"_redirect_loop_ids\";\n\n/**\n * Recompute loop redirect IDs and store in the options table.\n */\nasync function updateLoopCache(db: Kysely<Database>): Promise<void> {\n\ttry {\n\t\tconst options = new OptionsRepository(db);\n\t\tconst edges = toEdges(await new RedirectRepository(db).findAllEnabled());\n\t\tconst loopRedirectIds = detectLoops(edges);\n\t\tawait options.set(LOOP_CACHE_KEY, loopRedirectIds);\n\t} catch (error) {\n\t\tconsole.error(\"Failed to update redirect loop cache:\", error);\n\t}\n}\n\n/**\n * Get loop redirect IDs from cache, computing lazily on first access.\n */\nasync function getLoopRedirectIds(db: Kysely<Database>): Promise<string[]> {\n\ttry {\n\t\tconst options = new OptionsRepository(db);\n\t\tconst cached = await options.get<string[]>(LOOP_CACHE_KEY);\n\t\tif (cached !== null) return cached;\n\n\t\t// First access after upgrade — compute and cache\n\t\tawait updateLoopCache(db);\n\t\treturn (await options.get<string[]>(LOOP_CACHE_KEY)) ?? [];\n\t} catch {\n\t\treturn [];\n\t}\n}\n\n// ---------------------------------------------------------------------------\n// 404 Log\n// ---------------------------------------------------------------------------\n\n/**\n * List 404 log entries with cursor pagination\n */\nexport async function handleNotFoundList(\n\tdb: Kysely<Database>,\n\tparams: { cursor?: string; limit?: number; search?: string },\n): Promise<ApiResult<FindManyResult<NotFoundEntry>>> {\n\ttry {\n\t\tconst repo = new RedirectRepository(db);\n\t\tconst result = await repo.find404s(params);\n\t\treturn { success: true, data: result };\n\t} catch (error) {\n\t\tif (error instanceof InvalidCursorError) {\n\t\t\treturn {\n\t\t\t\tsuccess: false,\n\t\t\t\terror: { code: \"INVALID_CURSOR\", message: error.message },\n\t\t\t};\n\t\t}\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\terror: { code: \"NOT_FOUND_LIST_ERROR\", message: \"Failed to fetch 404 log\" },\n\t\t};\n\t}\n}\n\n/**\n * Get 404 summary (grouped by path, sorted by count)\n */\nexport async function handleNotFoundSummary(\n\tdb: Kysely<Database>,\n\tlimit?: number,\n): Promise<ApiResult<{ items: NotFoundSummary[] }>> {\n\ttry {\n\t\tconst repo = new RedirectRepository(db);\n\t\tconst items = await repo.get404Summary(limit);\n\t\treturn { success: true, data: { items } };\n\t} catch {\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\terror: { code: \"NOT_FOUND_SUMMARY_ERROR\", message: \"Failed to fetch 404 summary\" },\n\t\t};\n\t}\n}\n\n/**\n * Clear all 404 log entries\n */\nexport async function handleNotFoundClear(\n\tdb: Kysely<Database>,\n): Promise<ApiResult<{ deleted: number }>> {\n\ttry {\n\t\tconst repo = new RedirectRepository(db);\n\t\tconst deleted = await repo.clear404s();\n\t\treturn { success: true, data: { deleted } };\n\t} catch {\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\terror: { code: \"NOT_FOUND_CLEAR_ERROR\", message: \"Failed to clear 404 log\" },\n\t\t};\n\t}\n}\n\n/**\n * Prune 404 log entries older than a given date\n */\nexport async function handleNotFoundPrune(\n\tdb: Kysely<Database>,\n\tolderThan: string,\n): Promise<ApiResult<{ deleted: number }>> {\n\ttry {\n\t\tconst repo = new RedirectRepository(db);\n\t\tconst deleted = await repo.prune404s(olderThan);\n\t\treturn { success: true, data: { deleted } };\n\t} catch {\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\terror: { code: \"NOT_FOUND_PRUNE_ERROR\", message: \"Failed to prune 404 log\" },\n\t\t};\n\t}\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"redirects-CqzNM0KM.mjs","names":[],"sources":["../src/redirects/loops.ts","../src/api/handlers/redirects.ts"],"sourcesContent":["/**\n * Redirect loop and chain detection utilities.\n *\n * Builds a directed graph from redirect rules and detects:\n * - Cycles (loops): /a → /b → /c → /a\n * - Long chains: /a → /b → /c → /d → /e (exceeding a warning threshold)\n *\n * Handles both exact and pattern redirects. When the walker encounters\n * a path with no exact source match, it tests against compiled pattern\n * sources and resolves the destination using captured parameters.\n */\n\nimport {\n\tcompilePattern,\n\tmatchPattern,\n\tinterpolateDestination,\n\ttype CompiledPattern,\n} from \"./patterns.js\";\n\nexport interface RedirectEdge {\n\tid: string;\n\tsource: string;\n\tdestination: string;\n\tenabled: boolean;\n\tisPattern: boolean;\n}\n\ninterface CompiledPatternRedirect {\n\tid: string;\n\tcompiled: CompiledPattern;\n\tdestination: string;\n}\n\n/**\n * Compile all enabled pattern redirects for matching during graph walks.\n */\nfunction compilePatterns(edges: RedirectEdge[]): CompiledPatternRedirect[] {\n\tconst result: CompiledPatternRedirect[] = [];\n\tfor (const edge of edges) {\n\t\tif (edge.enabled && edge.isPattern) {\n\t\t\tresult.push({\n\t\t\t\tid: edge.id,\n\t\t\t\tcompiled: compilePattern(edge.source),\n\t\t\t\tdestination: edge.destination,\n\t\t\t});\n\t\t}\n\t}\n\treturn result;\n}\n\n/** Single-segment dummy value for representative path generation */\nconst DUMMY_SEGMENT = \"__p__\";\n\n/** Splat pattern: [...paramName] */\nconst SPLAT_RE = /\\[\\.\\.\\.(\\w+)\\]/g;\n\n/** Param pattern: [paramName] */\nconst PARAM_RE = /\\[(\\w+)\\]/g;\n\n/**\n * Extract the literal prefix from a pattern source (everything before the\n * first placeholder), stripped of leading segments shared with a base path.\n * e.g., \"/new/docs/[slug]\" → \"docs/__p__\" (the part after \"/new/\")\n */\nfunction extractPatternSuffix(patternSource: string): string {\n\t// Replace placeholders with dummy values\n\tlet result = patternSource.replace(SPLAT_RE, DUMMY_SEGMENT);\n\tSPLAT_RE.lastIndex = 0;\n\tresult = result.replace(PARAM_RE, DUMMY_SEGMENT);\n\t// Strip leading slash and first segment (e.g., \"/new/docs/__p__\" → \"docs/__p__\")\n\tconst parts = result.split(\"/\").filter(Boolean);\n\treturn parts.slice(1).join(\"/\");\n}\n\n/**\n * Generate representative concrete paths from a template string.\n * Replaces [param] with a dummy segment and [...rest] with multiple\n * depth variants. For catch-alls, also generates representatives using\n * literal prefixes from existing pattern sources to catch cross-pattern loops.\n */\nfunction generateRepresentatives(template: string, existingEdges?: RedirectEdge[]): string[] {\n\tconst hasSplat = SPLAT_RE.test(template);\n\tSPLAT_RE.lastIndex = 0;\n\n\tif (hasSplat) {\n\t\t// Extract the static prefix before the catch-all (e.g., \"/old/\" from \"/old/[...path]\")\n\t\tconst splatIndex = template.indexOf(\"[...\");\n\t\tconst prefix = template.slice(0, splatIndex);\n\n\t\tconst reps = [\n\t\t\ttemplate.replace(SPLAT_RE, DUMMY_SEGMENT).replace(PARAM_RE, DUMMY_SEGMENT),\n\t\t\ttemplate\n\t\t\t\t.replace(SPLAT_RE, `${DUMMY_SEGMENT}/${DUMMY_SEGMENT}`)\n\t\t\t\t.replace(PARAM_RE, DUMMY_SEGMENT),\n\t\t\ttemplate\n\t\t\t\t.replace(SPLAT_RE, `${DUMMY_SEGMENT}/${DUMMY_SEGMENT}/${DUMMY_SEGMENT}`)\n\t\t\t\t.replace(PARAM_RE, DUMMY_SEGMENT),\n\t\t];\n\n\t\t// Add representatives derived from existing pattern sources' literal prefixes\n\t\tif (existingEdges) {\n\t\t\tfor (const edge of existingEdges) {\n\t\t\t\tif (edge.enabled && edge.isPattern && edge.source !== template) {\n\t\t\t\t\tconst suffix = extractPatternSuffix(edge.source);\n\t\t\t\t\tif (suffix) {\n\t\t\t\t\t\treps.push(`${prefix}${suffix}`);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn reps;\n\t}\n\n\treturn [template.replace(PARAM_RE, DUMMY_SEGMENT)];\n}\n\n/**\n * Resolve the next hop for a given path. Tries exact match first,\n * then pattern matching with parameter interpolation for concrete paths,\n * then representative-based matching for template strings.\n */\nfunction resolveNext(\n\tpath: string,\n\tgraph: Map<string, { destination: string; id: string }>,\n\tpatterns: CompiledPatternRedirect[],\n\tedges?: RedirectEdge[],\n): { destination: string; id: string } | null {\n\t// Exact match (fast) — works for both real paths and template strings\n\tconst exact = graph.get(path);\n\tif (exact) return exact;\n\n\tif (!path.includes(\"[\")) {\n\t\t// Concrete path — try pattern matching directly\n\t\tfor (const pr of patterns) {\n\t\t\tconst params = matchPattern(pr.compiled, path);\n\t\t\tif (params) {\n\t\t\t\tconst resolved = interpolateDestination(pr.destination, params);\n\t\t\t\treturn { destination: resolved, id: pr.id };\n\t\t\t}\n\t\t}\n\t} else {\n\t\t// Template string — generate representative paths and test against patterns\n\t\tconst representatives = generateRepresentatives(path, edges);\n\t\tfor (const pr of patterns) {\n\t\t\tfor (const rep of representatives) {\n\t\t\t\tconst params = matchPattern(pr.compiled, rep);\n\t\t\t\tif (params) {\n\t\t\t\t\tconst resolved = interpolateDestination(pr.destination, params);\n\t\t\t\t\treturn { destination: resolved, id: pr.id };\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn null;\n}\n\n/**\n * Build an adjacency map from redirect edges.\n * Includes both exact and pattern redirects — pattern redirects use their\n * template strings as literal graph edges, which works because EmDash\n * patterns pass parameters through without transformation.\n */\nfunction buildGraph(edges: RedirectEdge[]): Map<string, { destination: string; id: string }> {\n\tconst graph = new Map<string, { destination: string; id: string }>();\n\tfor (const edge of edges) {\n\t\tif (edge.enabled) {\n\t\t\tgraph.set(edge.source, { destination: edge.destination, id: edge.id });\n\t\t}\n\t}\n\treturn graph;\n}\n\n/**\n * Detect all redirect IDs that participate in cycles.\n * Walks every node in the graph once, collecting IDs from any cycles found.\n *\n * @returns Array of redirect IDs that are part of a loop\n */\nexport function detectLoops(edges: RedirectEdge[]): string[] {\n\tconst graph = buildGraph(edges);\n\tconst patterns = compilePatterns(edges);\n\tconst visited = new Set<string>();\n\tconst loopRedirectIds = new Set<string>();\n\n\tfor (const [startSource] of graph) {\n\t\tif (visited.has(startSource)) continue;\n\n\t\tconst path: string[] = [];\n\t\tconst pathSet = new Set<string>();\n\t\tconst pathIds: string[] = [];\n\t\tlet current: string | undefined = startSource;\n\n\t\twhile (current) {\n\t\t\tif (pathSet.has(current)) {\n\t\t\t\t// Found a cycle — collect IDs of redirects in the loop\n\t\t\t\tconst loopStart = path.indexOf(current);\n\t\t\t\tfor (const id of pathIds.slice(loopStart)) loopRedirectIds.add(id);\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tif (visited.has(current)) {\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tconst next = resolveNext(current, graph, patterns, edges);\n\t\t\tif (!next) break;\n\n\t\t\tpath.push(current);\n\t\t\tpathSet.add(current);\n\t\t\tpathIds.push(next.id);\n\t\t\tcurrent = next.destination;\n\t\t}\n\n\t\tfor (const node of path) visited.add(node);\n\t}\n\n\treturn [...loopRedirectIds];\n}\n\n/**\n * Find a compiled pattern redirect whose source matches the given resolved path,\n * returning the source template string for display purposes.\n */\nfunction findMatchingTemplate(\n\tresolvedPath: string,\n\tpatterns: CompiledPatternRedirect[],\n): string | null {\n\tfor (const pr of patterns) {\n\t\tif (matchPattern(pr.compiled, resolvedPath) !== null) {\n\t\t\treturn pr.compiled.source;\n\t\t}\n\t}\n\treturn null;\n}\n\n/**\n * Check if adding or updating a redirect would create a loop.\n *\n * Walks the chain from `destination` through existing redirects.\n * If it reaches `source`, a cycle would form.\n *\n * @returns The loop path if a cycle would be created, or null if safe\n */\nexport function wouldCreateLoop(\n\tsource: string,\n\tdestination: string,\n\texistingEdges: RedirectEdge[],\n\texcludeId?: string,\n): string[] | null {\n\tconst filtered = excludeId ? existingEdges.filter((e) => e.id !== excludeId) : existingEdges;\n\tconst graph = buildGraph(filtered);\n\tconst patterns = compilePatterns(filtered);\n\n\t// If the proposed source is a pattern, compile it so we can check\n\t// whether resolved paths would match it (not just string equality)\n\tconst sourceIsPattern = source.includes(\"[\");\n\tconst compiledSource = sourceIsPattern ? compilePattern(source) : null;\n\n\t// Determine starting points for the walk. If the destination is a\n\t// template, generate representative concrete paths AND find existing\n\t// exact sources in the graph that match the template.\n\tlet startingPoints: string[];\n\tif (destination.includes(\"[\")) {\n\t\tconst reps = generateRepresentatives(destination, filtered);\n\t\t// Also find existing exact graph keys that match this template\n\t\tconst compiled = compilePattern(destination);\n\t\tfor (const [key] of graph) {\n\t\t\tif (!key.includes(\"[\") && matchPattern(compiled, key) !== null) {\n\t\t\t\treps.push(key);\n\t\t\t}\n\t\t}\n\t\t// Always include the destination itself — it may be an exact graph key\n\t\t// (e.g., /a/sub/[...path] exists as a literal source in the graph)\n\t\treps.push(destination);\n\t\tstartingPoints = reps;\n\t} else {\n\t\tstartingPoints = [destination];\n\t}\n\n\tfor (const start of startingPoints) {\n\t\tconst path = [source, destination];\n\t\tlet current = start;\n\t\tconst seen = new Set<string>([source, destination, start]);\n\n\t\t// Walk the chain until it ends or we revisit a node\n\t\t// eslint-disable-next-line no-constant-condition -- terminates via return/break when chain ends or cycle found\n\t\twhile (true) {\n\t\t\tconst next = resolveNext(current, graph, patterns, filtered);\n\t\t\tif (!next) break; // chain ends, try next starting point\n\n\t\t\t// Check if we've looped back — either exact match or pattern match\n\t\t\tconst loopsBack =\n\t\t\t\tseen.has(next.destination) ||\n\t\t\t\t(compiledSource !== null && matchPattern(compiledSource, next.destination) !== null);\n\n\t\t\tif (loopsBack) {\n\t\t\t\t// Show the source template instead of dummy resolved path\n\t\t\t\tconst displayPath =\n\t\t\t\t\t!seen.has(next.destination) && compiledSource !== null ? source : next.destination;\n\t\t\t\tpath.push(displayPath);\n\t\t\t\treturn path; // cycle found\n\t\t\t}\n\n\t\t\t// If the resolved path contains dummy segments, try to find the\n\t\t\t// original pattern template that produced it for cleaner display\n\t\t\tconst cleanDest = next.destination.includes(DUMMY_SEGMENT)\n\t\t\t\t? (findMatchingTemplate(next.destination, patterns) ?? next.destination)\n\t\t\t\t: next.destination;\n\t\t\tpath.push(cleanDest);\n\t\t\tseen.add(next.destination);\n\t\t\tcurrent = next.destination;\n\t\t}\n\t}\n\n\treturn null;\n}\n","/**\n * Redirect CRUD and 404 log handlers\n */\n\nimport type { Kysely } from \"kysely\";\n\nimport { OptionsRepository } from \"../../database/repositories/options.js\";\nimport {\n\tRedirectRepository,\n\ttype Redirect,\n\ttype NotFoundEntry,\n\ttype NotFoundSummary,\n} from \"../../database/repositories/redirect.js\";\nimport { InvalidCursorError } from \"../../database/repositories/types.js\";\nimport type { FindManyResult } from \"../../database/repositories/types.js\";\nimport type { Database } from \"../../database/types.js\";\nimport { wouldCreateLoop, detectLoops, type RedirectEdge } from \"../../redirects/loops.js\";\nimport { validatePattern, validateDestinationParams, isPattern } from \"../../redirects/patterns.js\";\nimport { isTerminalStatus } from \"../../redirects/status.js\";\nimport type { ApiResult } from \"../types.js\";\n\n// ---------------------------------------------------------------------------\n// Redirects\n// ---------------------------------------------------------------------------\n\n/**\n * List redirects with cursor pagination and optional filters\n */\nexport async function handleRedirectList(\n\tdb: Kysely<Database>,\n\tparams: {\n\t\tcursor?: string;\n\t\tlimit?: number;\n\t\tsearch?: string;\n\t\tgroup?: string;\n\t\tenabled?: boolean;\n\t\tauto?: boolean;\n\t},\n): Promise<ApiResult<FindManyResult<Redirect> & { loopRedirectIds?: string[] }>> {\n\ttry {\n\t\tconst repo = new RedirectRepository(db);\n\t\tconst result = await repo.findMany(params);\n\n\t\tconst loopRedirectIds = await getLoopRedirectIds(db);\n\n\t\treturn {\n\t\t\tsuccess: true,\n\t\t\tdata: {\n\t\t\t\t...result,\n\t\t\t\t...(loopRedirectIds.length > 0 ? { loopRedirectIds } : {}),\n\t\t\t},\n\t\t};\n\t} catch (error) {\n\t\tif (error instanceof InvalidCursorError) {\n\t\t\treturn {\n\t\t\t\tsuccess: false,\n\t\t\t\terror: { code: \"INVALID_CURSOR\", message: error.message },\n\t\t\t};\n\t\t}\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\terror: { code: \"REDIRECT_LIST_ERROR\", message: \"Failed to fetch redirects\" },\n\t\t};\n\t}\n}\n\n/**\n * Create a redirect rule\n */\nexport async function handleRedirectCreate(\n\tdb: Kysely<Database>,\n\tinput: {\n\t\tsource: string;\n\t\tdestination?: string;\n\t\ttype?: number;\n\t\tenabled?: boolean;\n\t\tgroupName?: string | null;\n\t},\n): Promise<ApiResult<Redirect>> {\n\ttry {\n\t\tconst repo = new RedirectRepository(db);\n\n\t\tconst type = input.type ?? 301;\n\t\t// Terminal statuses (410 Gone / 451) are served directly and have no\n\t\t// destination — skip the destination/loop checks for them.\n\t\tconst terminal = isTerminalStatus(type);\n\t\tconst destination = terminal ? \"\" : (input.destination ?? \"\");\n\n\t\t// Source and destination must differ\n\t\tif (!terminal && input.source === destination) {\n\t\t\treturn {\n\t\t\t\tsuccess: false,\n\t\t\t\terror: {\n\t\t\t\t\tcode: \"VALIDATION_ERROR\",\n\t\t\t\t\tmessage: \"Source and destination must be different\",\n\t\t\t\t},\n\t\t\t};\n\t\t}\n\n\t\t// If source looks like a pattern, validate it\n\t\tconst sourceIsPattern = isPattern(input.source);\n\t\tif (sourceIsPattern) {\n\t\t\tconst patternError = validatePattern(input.source);\n\t\t\tif (patternError) {\n\t\t\t\treturn {\n\t\t\t\t\tsuccess: false,\n\t\t\t\t\terror: { code: \"VALIDATION_ERROR\", message: `Invalid source pattern: ${patternError}` },\n\t\t\t\t};\n\t\t\t}\n\n\t\t\t// Validate destination params reference valid source params\n\t\t\t// (terminal rules have no destination to interpolate)\n\t\t\tif (!terminal) {\n\t\t\t\tconst destError = validateDestinationParams(input.source, destination);\n\t\t\t\tif (destError) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tsuccess: false,\n\t\t\t\t\t\terror: { code: \"VALIDATION_ERROR\", message: destError },\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Check for duplicate source (exact match only for non-patterns)\n\t\tconst existing = await repo.findBySource(input.source);\n\t\tif (existing) {\n\t\t\treturn {\n\t\t\t\tsuccess: false,\n\t\t\t\terror: {\n\t\t\t\t\tcode: \"CONFLICT\",\n\t\t\t\t\tmessage: `A redirect from \"${input.source}\" already exists`,\n\t\t\t\t},\n\t\t\t};\n\t\t}\n\n\t\t// Check for redirect loops (skip if creating as disabled, or terminal —\n\t\t// a Gone rule has no destination, so it can't form a loop)\n\t\tif (!terminal && input.enabled !== false) {\n\t\t\tconst edges = toEdges(await repo.findAllEnabled());\n\t\t\tconst loopPath = wouldCreateLoop(input.source, destination, edges);\n\t\t\tif (loopPath) return loopError(loopPath);\n\t\t}\n\n\t\tconst redirect = await repo.create({\n\t\t\tsource: input.source,\n\t\t\tdestination,\n\t\t\ttype,\n\t\t\tisPattern: sourceIsPattern,\n\t\t\tenabled: input.enabled ?? true,\n\t\t\tgroupName: input.groupName ?? null,\n\t\t});\n\n\t\treturn { success: true, data: redirect };\n\t} catch {\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\terror: { code: \"REDIRECT_CREATE_ERROR\", message: \"Failed to create redirect\" },\n\t\t};\n\t}\n}\n\n/**\n * Get a redirect by ID\n */\nexport async function handleRedirectGet(\n\tdb: Kysely<Database>,\n\tid: string,\n): Promise<ApiResult<Redirect>> {\n\ttry {\n\t\tconst repo = new RedirectRepository(db);\n\t\tconst redirect = await repo.findById(id);\n\n\t\tif (!redirect) {\n\t\t\treturn {\n\t\t\t\tsuccess: false,\n\t\t\t\terror: { code: \"NOT_FOUND\", message: `Redirect \"${id}\" not found` },\n\t\t\t};\n\t\t}\n\n\t\treturn { success: true, data: redirect };\n\t} catch {\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\terror: { code: \"REDIRECT_GET_ERROR\", message: \"Failed to fetch redirect\" },\n\t\t};\n\t}\n}\n\n/**\n * Update a redirect by ID\n */\nexport async function handleRedirectUpdate(\n\tdb: Kysely<Database>,\n\tid: string,\n\tinput: {\n\t\tsource?: string;\n\t\tdestination?: string;\n\t\ttype?: number;\n\t\tenabled?: boolean;\n\t\tgroupName?: string | null;\n\t},\n): Promise<ApiResult<Redirect>> {\n\ttry {\n\t\tconst repo = new RedirectRepository(db);\n\n\t\tconst existing = await repo.findById(id);\n\t\tif (!existing) {\n\t\t\treturn {\n\t\t\t\tsuccess: false,\n\t\t\t\terror: { code: \"NOT_FOUND\", message: `Redirect \"${id}\" not found` },\n\t\t\t};\n\t\t}\n\n\t\tconst newSource = input.source ?? existing.source;\n\t\tconst newDest = input.destination ?? existing.destination;\n\n\t\t// Source and destination must differ\n\t\tif (newSource === newDest) {\n\t\t\treturn {\n\t\t\t\tsuccess: false,\n\t\t\t\terror: {\n\t\t\t\t\tcode: \"VALIDATION_ERROR\",\n\t\t\t\t\tmessage: \"Source and destination must be different\",\n\t\t\t\t},\n\t\t\t};\n\t\t}\n\n\t\t// If source is changing, validate patterns\n\t\tif (input.source !== undefined) {\n\t\t\tconst sourceIsPattern = isPattern(input.source);\n\t\t\tif (sourceIsPattern) {\n\t\t\t\tconst patternError = validatePattern(input.source);\n\t\t\t\tif (patternError) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tsuccess: false,\n\t\t\t\t\t\terror: {\n\t\t\t\t\t\t\tcode: \"VALIDATION_ERROR\",\n\t\t\t\t\t\t\tmessage: `Invalid source pattern: ${patternError}`,\n\t\t\t\t\t\t},\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Check for duplicate source (exclude self)\n\t\t\tconst dup = await repo.findBySource(input.source);\n\t\t\tif (dup && dup.id !== id) {\n\t\t\t\treturn {\n\t\t\t\t\tsuccess: false,\n\t\t\t\t\terror: {\n\t\t\t\t\t\tcode: \"CONFLICT\",\n\t\t\t\t\t\tmessage: `A redirect from \"${input.source}\" already exists`,\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\n\t\t// Validate destination params against the (possibly updated) source\n\t\tconst newSourceIsPattern = isPattern(newSource);\n\t\tif (newSourceIsPattern) {\n\t\t\tconst destError = validateDestinationParams(newSource, newDest);\n\t\t\tif (destError) {\n\t\t\t\treturn {\n\t\t\t\t\tsuccess: false,\n\t\t\t\t\terror: { code: \"VALIDATION_ERROR\", message: destError },\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\n\t\t// Check for redirect loops if source or destination changed\n\t\tif (input.source !== undefined || input.destination !== undefined) {\n\t\t\tconst edges = toEdges(await repo.findAllEnabled());\n\t\t\tconst loopPath = wouldCreateLoop(newSource, newDest, edges, id);\n\t\t\tif (loopPath) return loopError(loopPath);\n\t\t}\n\n\t\tconst updated = await repo.update(id, {\n\t\t\tsource: input.source,\n\t\t\tdestination: input.destination,\n\t\t\ttype: input.type,\n\t\t\tenabled: input.enabled,\n\t\t\tgroupName: input.groupName,\n\t\t});\n\n\t\tif (!updated) {\n\t\t\treturn {\n\t\t\t\tsuccess: false,\n\t\t\t\terror: { code: \"REDIRECT_UPDATE_ERROR\", message: \"Failed to update redirect\" },\n\t\t\t};\n\t\t}\n\n\t\t// Recompute cache — redirect was modified, so re-fetch\n\t\tawait updateLoopCache(db);\n\n\t\treturn { success: true, data: updated };\n\t} catch {\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\terror: { code: \"REDIRECT_UPDATE_ERROR\", message: \"Failed to update redirect\" },\n\t\t};\n\t}\n}\n\n/**\n * Delete a redirect by ID\n */\nexport async function handleRedirectDelete(\n\tdb: Kysely<Database>,\n\tid: string,\n): Promise<ApiResult<{ deleted: true }>> {\n\ttry {\n\t\tconst repo = new RedirectRepository(db);\n\t\tconst deleted = await repo.delete(id);\n\n\t\tif (!deleted) {\n\t\t\treturn {\n\t\t\t\tsuccess: false,\n\t\t\t\terror: { code: \"NOT_FOUND\", message: `Redirect \"${id}\" not found` },\n\t\t\t};\n\t\t}\n\n\t\tawait updateLoopCache(db);\n\n\t\treturn { success: true, data: { deleted: true } };\n\t} catch {\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\terror: { code: \"REDIRECT_DELETE_ERROR\", message: \"Failed to delete redirect\" },\n\t\t};\n\t}\n}\n\n// ---------------------------------------------------------------------------\n// Loop analysis cache\n// ---------------------------------------------------------------------------\n\nfunction loopError(loopPath: string[]): ApiResult<never> {\n\tconst hops = loopPath\n\t\t.slice(0, -1)\n\t\t.map((p, i) => `${p} \\u2192 ${loopPath[i + 1]}`)\n\t\t.join(\"\\n\");\n\treturn {\n\t\tsuccess: false,\n\t\terror: {\n\t\t\tcode: \"VALIDATION_ERROR\",\n\t\t\tmessage: `This redirect would create a loop:\\n${hops}`,\n\t\t},\n\t};\n}\n\nfunction toEdges(redirects: Redirect[]): RedirectEdge[] {\n\treturn redirects.map((r) => ({\n\t\tid: r.id,\n\t\tsource: r.source,\n\t\tdestination: r.destination,\n\t\tenabled: r.enabled,\n\t\tisPattern: r.isPattern,\n\t}));\n}\n\nconst LOOP_CACHE_KEY = \"_redirect_loop_ids\";\n\n/**\n * Recompute loop redirect IDs and store in the options table.\n */\nasync function updateLoopCache(db: Kysely<Database>): Promise<void> {\n\ttry {\n\t\tconst options = new OptionsRepository(db);\n\t\tconst edges = toEdges(await new RedirectRepository(db).findAllEnabled());\n\t\tconst loopRedirectIds = detectLoops(edges);\n\t\tawait options.set(LOOP_CACHE_KEY, loopRedirectIds);\n\t} catch (error) {\n\t\tconsole.error(\"Failed to update redirect loop cache:\", error);\n\t}\n}\n\n/**\n * Get loop redirect IDs from cache, computing lazily on first access.\n */\nasync function getLoopRedirectIds(db: Kysely<Database>): Promise<string[]> {\n\ttry {\n\t\tconst options = new OptionsRepository(db);\n\t\tconst cached = await options.get<string[]>(LOOP_CACHE_KEY);\n\t\tif (cached !== null) return cached;\n\n\t\t// First access after upgrade — compute and cache\n\t\tawait updateLoopCache(db);\n\t\treturn (await options.get<string[]>(LOOP_CACHE_KEY)) ?? [];\n\t} catch {\n\t\treturn [];\n\t}\n}\n\n// ---------------------------------------------------------------------------\n// 404 Log\n// ---------------------------------------------------------------------------\n\n/**\n * List 404 log entries with cursor pagination\n */\nexport async function handleNotFoundList(\n\tdb: Kysely<Database>,\n\tparams: { cursor?: string; limit?: number; search?: string },\n): Promise<ApiResult<FindManyResult<NotFoundEntry>>> {\n\ttry {\n\t\tconst repo = new RedirectRepository(db);\n\t\tconst result = await repo.find404s(params);\n\t\treturn { success: true, data: result };\n\t} catch (error) {\n\t\tif (error instanceof InvalidCursorError) {\n\t\t\treturn {\n\t\t\t\tsuccess: false,\n\t\t\t\terror: { code: \"INVALID_CURSOR\", message: error.message },\n\t\t\t};\n\t\t}\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\terror: { code: \"NOT_FOUND_LIST_ERROR\", message: \"Failed to fetch 404 log\" },\n\t\t};\n\t}\n}\n\n/**\n * Get 404 summary (grouped by path, sorted by count)\n */\nexport async function handleNotFoundSummary(\n\tdb: Kysely<Database>,\n\tlimit?: number,\n): Promise<ApiResult<{ items: NotFoundSummary[] }>> {\n\ttry {\n\t\tconst repo = new RedirectRepository(db);\n\t\tconst items = await repo.get404Summary(limit);\n\t\treturn { success: true, data: { items } };\n\t} catch {\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\terror: { code: \"NOT_FOUND_SUMMARY_ERROR\", message: \"Failed to fetch 404 summary\" },\n\t\t};\n\t}\n}\n\n/**\n * Clear all 404 log entries\n */\nexport async function handleNotFoundClear(\n\tdb: Kysely<Database>,\n): Promise<ApiResult<{ deleted: number }>> {\n\ttry {\n\t\tconst repo = new RedirectRepository(db);\n\t\tconst deleted = await repo.clear404s();\n\t\treturn { success: true, data: { deleted } };\n\t} catch {\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\terror: { code: \"NOT_FOUND_CLEAR_ERROR\", message: \"Failed to clear 404 log\" },\n\t\t};\n\t}\n}\n\n/**\n * Prune 404 log entries older than a given date\n */\nexport async function handleNotFoundPrune(\n\tdb: Kysely<Database>,\n\tolderThan: string,\n): Promise<ApiResult<{ deleted: number }>> {\n\ttry {\n\t\tconst repo = new RedirectRepository(db);\n\t\tconst deleted = await repo.prune404s(olderThan);\n\t\treturn { success: true, data: { deleted } };\n\t} catch {\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\terror: { code: \"NOT_FOUND_PRUNE_ERROR\", message: \"Failed to prune 404 log\" },\n\t\t};\n\t}\n}\n"],"mappings":"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"}
|
|
@@ -1,130 +1,17 @@
|
|
|
1
|
-
import { c as __exportAll } from "./runner-
|
|
1
|
+
import { c as __exportAll } from "./runner-BLIDKpmA.mjs";
|
|
2
2
|
import { t as validateIdentifier } from "./validate-BpwoDOgt.mjs";
|
|
3
|
-
import { a as currentTimestamp, p as tableExists,
|
|
3
|
+
import { a as currentTimestamp, p as tableExists, u as listTablesLike } from "./dialect-helpers-BSbfaO3F.mjs";
|
|
4
4
|
import { c as isIndexableFieldType, o as RESERVED_COLLECTION_SLUGS, r as FIELD_TYPE_TO_COLUMN, s as RESERVED_FIELD_SLUGS } from "./types-75KIqzL9.mjs";
|
|
5
|
-
import { n as chunks, t as SQL_BATCH_SIZE } from "./chunks-
|
|
6
|
-
import { t as withTransaction } from "./transaction-
|
|
7
|
-
import { t as FTSManager } from "./fts-manager-
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
5
|
+
import { n as chunks, t as SQL_BATCH_SIZE } from "./chunks-C4szrD8o.mjs";
|
|
6
|
+
import { t as withTransaction } from "./transaction-0KOpOyMu.mjs";
|
|
7
|
+
import { t as FTSManager } from "./fts-manager-Do1BlW2r.mjs";
|
|
8
|
+
import { t as refreshDevTypes } from "./dev-typegen-DzOPfsNj.mjs";
|
|
9
|
+
import { c as installPreparedMediaUsageCollectionCapture, i as canResumeMediaUsageCollectionCapture, l as markMediaUsageCollectionCaptureReady, o as finalizeMediaUsageCollectionCapture, u as prepareMediaUsageCollectionCapture } from "./activation-K0kGBWuJ.mjs";
|
|
10
|
+
import { i as isMediaUsageCollectionSlugDeleting, r as deleteActivatedMediaUsageCollection } from "./collection-deletion-Bj07NHbj.mjs";
|
|
11
|
+
import { a as deleteContentMediaUsageCollection, l as markContentMediaUsageCollectionStaleSafely, s as invalidateContentMediaUsageSchemaChange } from "./content-refresh-Bwp-8yGy.mjs";
|
|
10
12
|
import { sql } from "kysely";
|
|
11
13
|
import { ulid } from "ulidx";
|
|
12
14
|
|
|
13
|
-
//#region src/media/usage/activation.ts
|
|
14
|
-
const ACTIVATION_KEY = "incremental_capture";
|
|
15
|
-
const MEDIA_USAGE_ACTIVATION_RUNTIME_GENERATION = 1;
|
|
16
|
-
const MEDIA_USAGE_ACTIVATION_LIMITS = Object.freeze({
|
|
17
|
-
collectionsPerCall: 1,
|
|
18
|
-
leaseDurationSeconds: 300
|
|
19
|
-
});
|
|
20
|
-
async function canResumeMediaUsageCollectionCapture(db, identity) {
|
|
21
|
-
const activation = await findActivationIfAvailable(db);
|
|
22
|
-
if (!activation) return false;
|
|
23
|
-
assertRuntimeGeneration(activation);
|
|
24
|
-
if (activation.state !== "active") return false;
|
|
25
|
-
const lifecycle = await db.selectFrom("_emdash_media_usage_index_status").select(["collection_id", "cursor"]).where("adapter_id", "=", "content-media").where("scope_type", "=", "collection").where("scope_key", "=", identity.collectionSlug).where("collection_id", "=", identity.collectionId).where("capture_state", "in", ["installing", "ready"]).executeTakeFirst();
|
|
26
|
-
return lifecycle?.collection_id === identity.collectionId && (identity.creationFingerprint ? lifecycle.cursor === identity.creationFingerprint : lifecycle.cursor === null);
|
|
27
|
-
}
|
|
28
|
-
async function prepareMediaUsageCollectionCapture(db, input) {
|
|
29
|
-
const activation = await findActivationIfAvailable(db);
|
|
30
|
-
if (!activation) return {
|
|
31
|
-
captureRequired: false,
|
|
32
|
-
collectionId: input.collectionId,
|
|
33
|
-
registrationExists: input.registeredCollectionId !== void 0,
|
|
34
|
-
resuming: false
|
|
35
|
-
};
|
|
36
|
-
assertRuntimeGeneration(activation);
|
|
37
|
-
if (activation.state !== "active") return {
|
|
38
|
-
captureRequired: false,
|
|
39
|
-
collectionId: input.collectionId,
|
|
40
|
-
registrationExists: input.registeredCollectionId !== void 0,
|
|
41
|
-
resuming: false
|
|
42
|
-
};
|
|
43
|
-
const existing = await db.selectFrom("_emdash_media_usage_index_status").select([
|
|
44
|
-
"collection_id",
|
|
45
|
-
"capture_state",
|
|
46
|
-
"cursor"
|
|
47
|
-
]).where("adapter_id", "=", "content-media").where("scope_type", "=", "collection").where("scope_key", "=", input.collectionSlug).executeTakeFirst();
|
|
48
|
-
if (existing) {
|
|
49
|
-
if (existing.collection_id && (existing.capture_state === "installing" || existing.capture_state === "ready") && (input.creationFingerprint ? existing.cursor === input.creationFingerprint : existing.cursor === null) && (input.registeredCollectionId === void 0 || input.registeredCollectionId === existing.collection_id)) return {
|
|
50
|
-
captureRequired: true,
|
|
51
|
-
collectionId: existing.collection_id,
|
|
52
|
-
registrationExists: input.registeredCollectionId !== void 0,
|
|
53
|
-
resuming: true
|
|
54
|
-
};
|
|
55
|
-
throw new Error("Media usage collection lifecycle identity conflict");
|
|
56
|
-
}
|
|
57
|
-
if (input.registeredCollectionId !== void 0) throw new Error("Media usage collection lifecycle is missing");
|
|
58
|
-
await db.insertInto("_emdash_media_usage_index_status").values({
|
|
59
|
-
adapter_id: "content-media",
|
|
60
|
-
scope_type: "collection",
|
|
61
|
-
scope_key: input.collectionSlug,
|
|
62
|
-
status: "never",
|
|
63
|
-
collection_id: input.collectionId,
|
|
64
|
-
reconciliation_required: 1,
|
|
65
|
-
capture_state: "installing",
|
|
66
|
-
cursor: input.creationFingerprint ?? null,
|
|
67
|
-
updated_at: timestampOffset(db, 0)
|
|
68
|
-
}).execute();
|
|
69
|
-
return {
|
|
70
|
-
captureRequired: true,
|
|
71
|
-
collectionId: input.collectionId,
|
|
72
|
-
registrationExists: false,
|
|
73
|
-
resuming: false
|
|
74
|
-
};
|
|
75
|
-
}
|
|
76
|
-
async function installPreparedMediaUsageCollectionCapture(db, identity) {
|
|
77
|
-
await installMediaUsageCaptureTriggers(db, identity, { replaceExisting: false });
|
|
78
|
-
if (!await verifyMediaUsageCaptureTriggers(db, identity)) throw new Error("Media usage capture trigger verification failed");
|
|
79
|
-
}
|
|
80
|
-
async function markMediaUsageCollectionCaptureReady(db, identity) {
|
|
81
|
-
const result = await db.updateTable("_emdash_media_usage_index_status").set({
|
|
82
|
-
capture_state: "ready",
|
|
83
|
-
updated_at: timestampOffset(db, 0)
|
|
84
|
-
}).where("adapter_id", "=", "content-media").where("scope_type", "=", "collection").where("scope_key", "=", identity.collectionSlug).where("collection_id", "=", identity.collectionId).where("capture_state", "in", ["installing", "ready"]).where(sql`EXISTS (
|
|
85
|
-
SELECT 1 FROM _emdash_media_usage_activation AS activation
|
|
86
|
-
WHERE activation.task_key = ${ACTIVATION_KEY}
|
|
87
|
-
AND activation.state = 'active'
|
|
88
|
-
AND activation.runtime_generation = ${MEDIA_USAGE_ACTIVATION_RUNTIME_GENERATION}
|
|
89
|
-
)`).executeTakeFirst();
|
|
90
|
-
if (Number(result.numUpdatedRows ?? 0) === 0) throw new Error("Media usage collection readiness lost its fence");
|
|
91
|
-
}
|
|
92
|
-
async function finalizeMediaUsageCollectionCapture(db, identity) {
|
|
93
|
-
const result = await db.updateTable("_emdash_media_usage_index_status").set({
|
|
94
|
-
capture_state: "active",
|
|
95
|
-
cursor: null,
|
|
96
|
-
updated_at: timestampOffset(db, 0)
|
|
97
|
-
}).where("adapter_id", "=", "content-media").where("scope_type", "=", "collection").where("scope_key", "=", identity.collectionSlug).where("collection_id", "=", identity.collectionId).where("capture_state", "=", "ready").where(sql`EXISTS (
|
|
98
|
-
SELECT 1 FROM _emdash_collections AS collection
|
|
99
|
-
WHERE collection.id = ${identity.collectionId}
|
|
100
|
-
AND collection.slug = ${identity.collectionSlug}
|
|
101
|
-
)`).where(sql`EXISTS (
|
|
102
|
-
SELECT 1 FROM _emdash_media_usage_activation AS activation
|
|
103
|
-
WHERE activation.task_key = ${ACTIVATION_KEY}
|
|
104
|
-
AND activation.state = 'active'
|
|
105
|
-
AND activation.runtime_generation = ${MEDIA_USAGE_ACTIVATION_RUNTIME_GENERATION}
|
|
106
|
-
)`).executeTakeFirst();
|
|
107
|
-
if (Number(result.numUpdatedRows ?? 0) === 0) throw new Error("Media usage collection activation lost its fence");
|
|
108
|
-
}
|
|
109
|
-
async function findActivation(db) {
|
|
110
|
-
return db.selectFrom("_emdash_media_usage_activation").selectAll().where("task_key", "=", ACTIVATION_KEY).executeTakeFirstOrThrow();
|
|
111
|
-
}
|
|
112
|
-
async function findActivationIfAvailable(db) {
|
|
113
|
-
if (!await tableExists(db, "_emdash_media_usage_activation")) return null;
|
|
114
|
-
return findActivation(db);
|
|
115
|
-
}
|
|
116
|
-
function assertRuntimeGeneration(activation) {
|
|
117
|
-
if (activation.runtime_generation !== MEDIA_USAGE_ACTIVATION_RUNTIME_GENERATION) throw new Error("Media usage activation runtime generation mismatch");
|
|
118
|
-
}
|
|
119
|
-
function timestampOffset(db, seconds) {
|
|
120
|
-
if (isPostgres(db)) return sql`to_char(
|
|
121
|
-
clock_timestamp() AT TIME ZONE 'UTC' + (${seconds} * interval '1 second'),
|
|
122
|
-
'YYYY-MM-DD"T"HH24:MI:SS.MS"Z"'
|
|
123
|
-
)`;
|
|
124
|
-
return sql`strftime('%Y-%m-%dT%H:%M:%fZ', 'now', ${`+${seconds} seconds`})`;
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
//#endregion
|
|
128
15
|
//#region src/schema/registry.ts
|
|
129
16
|
var registry_exports = /* @__PURE__ */ __exportAll({
|
|
130
17
|
SchemaError: () => SchemaError,
|
|
@@ -294,6 +181,12 @@ var SchemaRegistry = class {
|
|
|
294
181
|
this.db = db;
|
|
295
182
|
}
|
|
296
183
|
/**
|
|
184
|
+
* Notify the dev typegen hook that the schema has changed.
|
|
185
|
+
*/
|
|
186
|
+
notifyTypegen() {
|
|
187
|
+
refreshDevTypes(this.db);
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
297
190
|
* List all collections
|
|
298
191
|
*/
|
|
299
192
|
async listCollections() {
|
|
@@ -433,6 +326,7 @@ var SchemaRegistry = class {
|
|
|
433
326
|
});
|
|
434
327
|
const collection = await this.getCollection(input.slug);
|
|
435
328
|
if (!collection) throw new SchemaError("Failed to create collection", "CREATE_FAILED");
|
|
329
|
+
this.notifyTypegen();
|
|
436
330
|
return collection;
|
|
437
331
|
}
|
|
438
332
|
/**
|
|
@@ -558,6 +452,7 @@ var SchemaRegistry = class {
|
|
|
558
452
|
if (schemaMutated) await markContentMediaUsageCollectionStaleSafely(this.db, input.slug, "CONTENT_USAGE_STALE");
|
|
559
453
|
throw error;
|
|
560
454
|
}
|
|
455
|
+
this.notifyTypegen();
|
|
561
456
|
}
|
|
562
457
|
async assertSeedFieldDefinitions(collectionId, fields, db) {
|
|
563
458
|
const stored = await db.selectFrom("_emdash_fields").selectAll().where("collection_id", "=", collectionId).execute();
|
|
@@ -575,7 +470,7 @@ var SchemaRegistry = class {
|
|
|
575
470
|
* Update a collection
|
|
576
471
|
*/
|
|
577
472
|
async updateCollection(slug, input) {
|
|
578
|
-
|
|
473
|
+
const updated = await withTransaction(this.db, async (trx) => {
|
|
579
474
|
const existingRow = await trx.selectFrom("_emdash_collections").where("slug", "=", slug).selectAll().executeTakeFirst();
|
|
580
475
|
if (!existingRow) throw new SchemaError(`Collection "${slug}" not found`, "COLLECTION_NOT_FOUND");
|
|
581
476
|
const existing = this.mapCollectionRow(existingRow);
|
|
@@ -611,6 +506,8 @@ var SchemaRegistry = class {
|
|
|
611
506
|
}
|
|
612
507
|
return this.mapCollectionRow(row);
|
|
613
508
|
});
|
|
509
|
+
this.notifyTypegen();
|
|
510
|
+
return updated;
|
|
614
511
|
}
|
|
615
512
|
/**
|
|
616
513
|
* Delete a collection
|
|
@@ -641,6 +538,7 @@ var SchemaRegistry = class {
|
|
|
641
538
|
if (contentTableDropped && !await tableExists(this.db, this.getTableName(slug))) await deleteContentMediaUsageCollection(this.db, slug);
|
|
642
539
|
throw error;
|
|
643
540
|
}
|
|
541
|
+
this.notifyTypegen();
|
|
644
542
|
}
|
|
645
543
|
/**
|
|
646
544
|
* List fields for a collection
|
|
@@ -707,6 +605,7 @@ var SchemaRegistry = class {
|
|
|
707
605
|
});
|
|
708
606
|
if (activeCoverageInvalidated) await invalidateContentMediaUsageSchemaChange(this.db, collectionSlug);
|
|
709
607
|
else await markContentMediaUsageCollectionStaleSafely(this.db, collectionSlug, "CONTENT_USAGE_STALE");
|
|
608
|
+
this.notifyTypegen();
|
|
710
609
|
return created;
|
|
711
610
|
} catch (error) {
|
|
712
611
|
if (schemaMutated) if (activeCoverageInvalidated) await invalidateContentMediaUsageSchemaChange(this.db, collectionSlug);
|
|
@@ -777,6 +676,7 @@ var SchemaRegistry = class {
|
|
|
777
676
|
});
|
|
778
677
|
if (schemaMutated) if (activeCoverageInvalidated) await invalidateContentMediaUsageSchemaChange(this.db, collectionSlug);
|
|
779
678
|
else await markContentMediaUsageCollectionStaleSafely(this.db, collectionSlug, "CONTENT_USAGE_STALE");
|
|
679
|
+
this.notifyTypegen();
|
|
780
680
|
return updatedField;
|
|
781
681
|
} catch (error) {
|
|
782
682
|
if (schemaMutated) if (activeCoverageInvalidated) await invalidateContentMediaUsageSchemaChange(this.db, collectionSlug);
|
|
@@ -841,6 +741,7 @@ var SchemaRegistry = class {
|
|
|
841
741
|
else await markContentMediaUsageCollectionStaleSafely(this.db, collectionSlug, "CONTENT_USAGE_STALE");
|
|
842
742
|
throw error;
|
|
843
743
|
}
|
|
744
|
+
this.notifyTypegen();
|
|
844
745
|
}
|
|
845
746
|
/**
|
|
846
747
|
* Reorder collections in the admin sidebar.
|
|
@@ -869,6 +770,7 @@ var SchemaRegistry = class {
|
|
|
869
770
|
updated_at: now
|
|
870
771
|
}).where("slug", "in", slugChunk).execute();
|
|
871
772
|
});
|
|
773
|
+
this.notifyTypegen();
|
|
872
774
|
}
|
|
873
775
|
/**
|
|
874
776
|
* Reorder fields
|
|
@@ -877,6 +779,7 @@ var SchemaRegistry = class {
|
|
|
877
779
|
const collection = await this.getCollection(collectionSlug);
|
|
878
780
|
if (!collection) throw new SchemaError(`Collection "${collectionSlug}" not found`, "COLLECTION_NOT_FOUND");
|
|
879
781
|
for (let i = 0; i < fieldSlugs.length; i++) await this.db.updateTable("_emdash_fields").set({ sort_order: i }).where("collection_id", "=", collection.id).where("slug", "=", fieldSlugs[i]).execute();
|
|
782
|
+
this.notifyTypegen();
|
|
880
783
|
}
|
|
881
784
|
/**
|
|
882
785
|
* Create a content table for a collection
|
|
@@ -902,8 +805,8 @@ var SchemaRegistry = class {
|
|
|
902
805
|
ON ${sql.ref(tableName)} (slug)
|
|
903
806
|
`.execute(conn);
|
|
904
807
|
await sql`
|
|
905
|
-
${createIndex} ${sql.ref(`idx_${tableName}
|
|
906
|
-
ON ${sql.ref(tableName)} (scheduled_at)
|
|
808
|
+
${createIndex} ${sql.ref(`idx_${tableName}_del_sched`)}
|
|
809
|
+
ON ${sql.ref(tableName)} (deleted_at, scheduled_at)
|
|
907
810
|
WHERE scheduled_at IS NOT NULL
|
|
908
811
|
`.execute(conn);
|
|
909
812
|
await sql`
|
|
@@ -1256,6 +1159,7 @@ var SchemaRegistry = class {
|
|
|
1256
1159
|
const collection = await this.getCollection(slug);
|
|
1257
1160
|
if (!collection) throw new SchemaError("Failed to register orphaned table", "REGISTER_FAILED");
|
|
1258
1161
|
await markContentMediaUsageCollectionStaleSafely(this.db, slug, "CONTENT_USAGE_STALE");
|
|
1162
|
+
this.notifyTypegen();
|
|
1259
1163
|
return collection;
|
|
1260
1164
|
} catch (error) {
|
|
1261
1165
|
if (collectionRegistered) await markContentMediaUsageCollectionStaleSafely(this.db, slug, "CONTENT_USAGE_STALE");
|
|
@@ -1272,4 +1176,4 @@ var SchemaRegistry = class {
|
|
|
1272
1176
|
|
|
1273
1177
|
//#endregion
|
|
1274
1178
|
export { SchemaRegistry as n, registry_exports as r, SchemaError as t };
|
|
1275
|
-
//# sourceMappingURL=registry-
|
|
1179
|
+
//# sourceMappingURL=registry-AZAsRsor.mjs.map
|