emdash 0.40.0 → 0.41.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/action-token-CbKDcPJi.mjs +26 -0
- package/dist/action-token-CbKDcPJi.mjs.map +1 -0
- package/dist/activation-PtniBLt9.mjs +382 -0
- package/dist/activation-PtniBLt9.mjs.map +1 -0
- package/dist/adapters-C_Tf5x90.d.mts +171 -0
- package/dist/adapters-C_Tf5x90.d.mts.map +1 -0
- package/dist/allowed-origins-U1z4TdEZ.mjs +116 -0
- package/dist/allowed-origins-U1z4TdEZ.mjs.map +1 -0
- package/dist/api/route-utils.d.mts +4 -4
- package/dist/api/route-utils.mjs +46 -45
- package/dist/api/route-utils.mjs.map +1 -1
- package/dist/api/schemas/index.d.mts +2 -2
- package/dist/api/schemas/index.mjs +10 -10
- package/dist/api-CXwQkV_m.mjs +5122 -0
- package/dist/api-CXwQkV_m.mjs.map +1 -0
- package/dist/api-tokens-89WlohEN.mjs +166 -0
- package/dist/api-tokens-89WlohEN.mjs.map +1 -0
- package/dist/apply-Do3KNnUk.mjs +1659 -0
- package/dist/apply-Do3KNnUk.mjs.map +1 -0
- package/dist/approvals-CAX9Yw33.mjs +460 -0
- package/dist/approvals-CAX9Yw33.mjs.map +1 -0
- package/dist/artifact-fetch-B9W4CEST.mjs +659 -0
- package/dist/artifact-fetch-B9W4CEST.mjs.map +1 -0
- package/dist/astro/index.d.mts +14 -14
- package/dist/astro/index.mjs +26 -30
- package/dist/astro/index.mjs.map +1 -1
- package/dist/astro/middleware/auth.d.mts +12 -12
- package/dist/astro/middleware/auth.mjs +10 -10
- package/dist/astro/middleware/media-usage-write-fence.mjs +5 -5
- package/dist/astro/middleware/redirect.mjs +7 -7
- package/dist/astro/middleware/request-context.mjs +3 -3
- package/dist/astro/middleware/setup.mjs +1 -1
- package/dist/astro/middleware.d.mts +12 -12
- package/dist/astro/middleware.d.mts.map +1 -1
- package/dist/astro/middleware.mjs +110 -106
- package/dist/astro/middleware.mjs.map +1 -1
- package/dist/astro/routes/api/admin/allowed-domains/_domain_.mjs +14 -14
- package/dist/astro/routes/api/admin/allowed-domains/index.mjs +14 -14
- package/dist/astro/routes/api/admin/api-tokens/_id_.mjs +6 -6
- package/dist/astro/routes/api/admin/api-tokens/index.mjs +7 -7
- package/dist/astro/routes/api/admin/byline-fields/_slug_/usage.mjs +7 -7
- package/dist/astro/routes/api/admin/byline-fields/_slug_.mjs +17 -17
- package/dist/astro/routes/api/admin/byline-fields/index.mjs +17 -17
- package/dist/astro/routes/api/admin/byline-fields/reorder.mjs +17 -17
- package/dist/astro/routes/api/admin/bylines/_id_/index.mjs +23 -23
- package/dist/astro/routes/api/admin/bylines/_id_/translations.mjs +23 -23
- package/dist/astro/routes/api/admin/bylines/index.mjs +23 -23
- package/dist/astro/routes/api/admin/comments/_id_/status.mjs +18 -18
- package/dist/astro/routes/api/admin/comments/_id_.mjs +7 -7
- package/dist/astro/routes/api/admin/comments/bulk.mjs +17 -17
- package/dist/astro/routes/api/admin/comments/counts.mjs +7 -7
- package/dist/astro/routes/api/admin/comments/index.mjs +17 -17
- package/dist/astro/routes/api/admin/hooks/exclusive/_hookName_.mjs +6 -6
- package/dist/astro/routes/api/admin/hooks/exclusive/index.mjs +5 -5
- package/dist/astro/routes/api/admin/media-usage/activation.mjs +20 -20
- package/dist/astro/routes/api/admin/media-usage/collection-deletions/index.mjs +22 -22
- package/dist/astro/routes/api/admin/media-usage/collection-deletions/retry.mjs +22 -22
- package/dist/astro/routes/api/admin/media-usage/progress.mjs +25 -25
- package/dist/astro/routes/api/admin/media-usage/repair.mjs +31 -31
- package/dist/astro/routes/api/admin/media-usage/work/index.mjs +22 -22
- package/dist/astro/routes/api/admin/media-usage/work/retry.mjs +22 -22
- package/dist/astro/routes/api/admin/oauth-clients/_id_.mjs +6 -6
- package/dist/astro/routes/api/admin/oauth-clients/index.mjs +6 -6
- package/dist/astro/routes/api/admin/plugins/_id_/disable.mjs +8 -8
- package/dist/astro/routes/api/admin/plugins/_id_/enable.mjs +8 -8
- package/dist/astro/routes/api/admin/plugins/_id_/index.mjs +72 -68
- package/dist/astro/routes/api/admin/plugins/_id_/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/_id_/mcp.mjs +7 -7
- package/dist/astro/routes/api/admin/plugins/_id_/settings.mjs +71 -67
- package/dist/astro/routes/api/admin/plugins/_id_/settings.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/_id_/uninstall.mjs +72 -68
- package/dist/astro/routes/api/admin/plugins/_id_/uninstall.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/_id_/update.mjs +82 -78
- package/dist/astro/routes/api/admin/plugins/_id_/update.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/index.mjs +72 -68
- package/dist/astro/routes/api/admin/plugins/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/marketplace/_id_/icon.mjs +5 -5
- package/dist/astro/routes/api/admin/plugins/marketplace/_id_/index.mjs +71 -67
- package/dist/astro/routes/api/admin/plugins/marketplace/_id_/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/marketplace/_id_/install.mjs +81 -77
- package/dist/astro/routes/api/admin/plugins/marketplace/_id_/install.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/marketplace/index.mjs +71 -67
- package/dist/astro/routes/api/admin/plugins/marketplace/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/registry/_id_/uninstall.mjs +72 -68
- package/dist/astro/routes/api/admin/plugins/registry/_id_/uninstall.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/registry/_id_/update.mjs +83 -79
- package/dist/astro/routes/api/admin/plugins/registry/_id_/update.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/registry/artifact.mjs +9 -9
- package/dist/astro/routes/api/admin/plugins/registry/install.mjs +74 -70
- package/dist/astro/routes/api/admin/plugins/registry/install.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/registry/publisher-handle.mjs +7 -7
- package/dist/astro/routes/api/admin/plugins/registry/verify.mjs +72 -68
- package/dist/astro/routes/api/admin/plugins/registry/verify.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/updates.mjs +71 -67
- package/dist/astro/routes/api/admin/plugins/updates.mjs.map +1 -1
- package/dist/astro/routes/api/admin/scheduled-policy-rejections/_collection_/_id_.mjs +6 -6
- package/dist/astro/routes/api/admin/themes/marketplace/_id_/index.mjs +71 -67
- package/dist/astro/routes/api/admin/themes/marketplace/_id_/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/themes/marketplace/_id_/thumbnail.mjs +5 -5
- package/dist/astro/routes/api/admin/themes/marketplace/index.mjs +71 -67
- package/dist/astro/routes/api/admin/themes/marketplace/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/transfer/_...path_.mjs +4 -4
- package/dist/astro/routes/api/admin/transfer/approvals/_id_/approve.mjs +40 -40
- package/dist/astro/routes/api/admin/transfer/approvals/_id_/deny.mjs +40 -40
- package/dist/astro/routes/api/admin/transfer/approvals/index.mjs +42 -42
- package/dist/astro/routes/api/admin/transfer/capabilities.mjs +42 -42
- package/dist/astro/routes/api/admin/transfer/exports/_id_/advance.mjs +42 -42
- package/dist/astro/routes/api/admin/transfer/exports/_id_/archive.mjs +43 -43
- package/dist/astro/routes/api/admin/transfer/exports/_id_/files/_...path_.mjs +43 -43
- package/dist/astro/routes/api/admin/transfer/exports/_id_/index.mjs +42 -42
- package/dist/astro/routes/api/admin/transfer/exports/_id_/manifest.mjs +43 -43
- package/dist/astro/routes/api/admin/transfer/exports/index.mjs +44 -44
- package/dist/astro/routes/api/admin/transfer/imports/_id_/abandon.mjs +42 -42
- package/dist/astro/routes/api/admin/transfer/imports/_id_/advance.mjs +42 -42
- package/dist/astro/routes/api/admin/transfer/imports/_id_/analyze.mjs +44 -44
- package/dist/astro/routes/api/admin/transfer/imports/_id_/cancel.mjs +42 -42
- package/dist/astro/routes/api/admin/transfer/imports/_id_/execute.mjs +44 -44
- package/dist/astro/routes/api/admin/transfer/imports/_id_/files/_...path_.mjs +42 -42
- package/dist/astro/routes/api/admin/transfer/imports/_id_/index.mjs +42 -42
- package/dist/astro/routes/api/admin/transfer/imports/_id_/missing.mjs +44 -44
- package/dist/astro/routes/api/admin/transfer/imports/_id_/plan.mjs +42 -42
- package/dist/astro/routes/api/admin/transfer/imports/_id_/receipt.mjs +42 -42
- package/dist/astro/routes/api/admin/transfer/imports/index.mjs +44 -44
- package/dist/astro/routes/api/admin/users/_id_/disable.mjs +5 -5
- package/dist/astro/routes/api/admin/users/_id_/enable.mjs +4 -4
- package/dist/astro/routes/api/admin/users/_id_/index.mjs +15 -15
- package/dist/astro/routes/api/admin/users/_id_/send-recovery.mjs +6 -6
- package/dist/astro/routes/api/admin/users/index.mjs +14 -14
- package/dist/astro/routes/api/auth/dev-bypass.mjs +6 -6
- package/dist/astro/routes/api/auth/invite/accept.mjs +4 -4
- package/dist/astro/routes/api/auth/invite/complete.mjs +18 -18
- package/dist/astro/routes/api/auth/invite/index.mjs +16 -16
- package/dist/astro/routes/api/auth/invite/register-options.mjs +17 -17
- package/dist/astro/routes/api/auth/logout.mjs +5 -5
- package/dist/astro/routes/api/auth/magic-link/send.mjs +18 -18
- package/dist/astro/routes/api/auth/magic-link/verify.mjs +14 -14
- package/dist/astro/routes/api/auth/me.mjs +15 -15
- package/dist/astro/routes/api/auth/mode.mjs +5 -5
- package/dist/astro/routes/api/auth/oauth/_provider_/callback.mjs +3 -3
- package/dist/astro/routes/api/auth/oauth/_provider_.mjs +2 -2
- package/dist/astro/routes/api/auth/passkey/_id_.mjs +14 -14
- package/dist/astro/routes/api/auth/passkey/index.mjs +4 -4
- package/dist/astro/routes/api/auth/passkey/options.mjs +19 -19
- package/dist/astro/routes/api/auth/passkey/register/options.mjs +17 -17
- package/dist/astro/routes/api/auth/passkey/register/verify.mjs +18 -18
- package/dist/astro/routes/api/auth/passkey/verify.mjs +18 -18
- package/dist/astro/routes/api/auth/signup/complete.mjs +18 -18
- package/dist/astro/routes/api/auth/signup/request.mjs +17 -17
- package/dist/astro/routes/api/auth/signup/verify.mjs +4 -4
- package/dist/astro/routes/api/comments/_collection_/_contentId_/index.mjs +12 -12
- package/dist/astro/routes/api/comments/_collection_/_contentId_/reactions.mjs +18 -18
- package/dist/astro/routes/api/content/_collection_/_id_/compare.mjs +5 -5
- package/dist/astro/routes/api/content/_collection_/_id_/discard-draft.mjs +17 -17
- package/dist/astro/routes/api/content/_collection_/_id_/duplicate.mjs +5 -5
- package/dist/astro/routes/api/content/_collection_/_id_/lock.mjs +17 -17
- package/dist/astro/routes/api/content/_collection_/_id_/permanent.mjs +5 -5
- package/dist/astro/routes/api/content/_collection_/_id_/plugin-extensions/_pluginId_/_kind_/_extensionId_.mjs +11 -11
- package/dist/astro/routes/api/content/_collection_/_id_/preview-url.mjs +31 -31
- package/dist/astro/routes/api/content/_collection_/_id_/publish.mjs +17 -17
- package/dist/astro/routes/api/content/_collection_/_id_/references/_relation_/children.d.mts +1 -2
- package/dist/astro/routes/api/content/_collection_/_id_/references/_relation_/children.d.mts.map +1 -1
- package/dist/astro/routes/api/content/_collection_/_id_/references/_relation_/children.mjs +42 -53
- package/dist/astro/routes/api/content/_collection_/_id_/references/_relation_/children.mjs.map +1 -1
- package/dist/astro/routes/api/content/_collection_/_id_/references/_relation_/parents.mjs +34 -29
- package/dist/astro/routes/api/content/_collection_/_id_/references/_relation_/parents.mjs.map +1 -1
- package/dist/astro/routes/api/content/_collection_/_id_/restore.mjs +5 -5
- package/dist/astro/routes/api/content/_collection_/_id_/revisions.mjs +5 -5
- package/dist/astro/routes/api/content/_collection_/_id_/schedule.mjs +17 -17
- package/dist/astro/routes/api/content/_collection_/_id_/terms/_taxonomy_.mjs +25 -24
- package/dist/astro/routes/api/content/_collection_/_id_/terms/_taxonomy_.mjs.map +1 -1
- package/dist/astro/routes/api/content/_collection_/_id_/translations.mjs +5 -5
- package/dist/astro/routes/api/content/_collection_/_id_/unpublish.mjs +17 -17
- package/dist/astro/routes/api/content/_collection_/_id_.d.mts.map +1 -1
- package/dist/astro/routes/api/content/_collection_/_id_.mjs +18 -18
- package/dist/astro/routes/api/content/_collection_/_id_.mjs.map +1 -1
- package/dist/astro/routes/api/content/_collection_/authors.mjs +5 -5
- package/dist/astro/routes/api/content/_collection_/index.mjs +15 -15
- package/dist/astro/routes/api/content/_collection_/trash.mjs +15 -15
- package/dist/astro/routes/api/dashboard.mjs +10 -9
- package/dist/astro/routes/api/dashboard.mjs.map +1 -1
- package/dist/astro/routes/api/dev/emails.mjs +5 -5
- package/dist/astro/routes/api/health.mjs +6 -6
- package/dist/astro/routes/api/import/probe.d.mts +3 -3
- package/dist/astro/routes/api/import/probe.mjs +23 -23
- package/dist/astro/routes/api/import/wordpress/analyze.mjs +6 -6
- package/dist/astro/routes/api/import/wordpress/execute.d.mts +13 -13
- package/dist/astro/routes/api/import/wordpress/execute.mjs +16 -16
- package/dist/astro/routes/api/import/wordpress/media.d.mts +12 -12
- package/dist/astro/routes/api/import/wordpress/media.mjs +19 -19
- package/dist/astro/routes/api/import/wordpress/prepare.mjs +18 -18
- package/dist/astro/routes/api/import/wordpress/rewrite-urls.d.mts +13 -13
- package/dist/astro/routes/api/import/wordpress/rewrite-urls.mjs +28 -28
- package/dist/astro/routes/api/import/wordpress-plugin/analyze.d.mts +1 -1
- package/dist/astro/routes/api/import/wordpress-plugin/analyze.mjs +23 -23
- package/dist/astro/routes/api/import/wordpress-plugin/execute.d.mts +13 -13
- package/dist/astro/routes/api/import/wordpress-plugin/execute.mjs +34 -34
- package/dist/astro/routes/api/manifest.mjs +6 -6
- package/dist/astro/routes/api/mcp.mjs +98 -118
- package/dist/astro/routes/api/mcp.mjs.map +1 -1
- package/dist/astro/routes/api/media/_id_/confirm.mjs +19 -19
- package/dist/astro/routes/api/media/_id_/replace.mjs +16 -16
- package/dist/astro/routes/api/media/_id_/upload.mjs +9 -9
- package/dist/astro/routes/api/media/_id_/usage.mjs +33 -33
- package/dist/astro/routes/api/media/_id_.mjs +31 -31
- package/dist/astro/routes/api/media/asset/_id_/_filename_.mjs +6 -6
- package/dist/astro/routes/api/media/file/_...key_.mjs +9 -9
- package/dist/astro/routes/api/media/folders/_id_.mjs +16 -16
- package/dist/astro/routes/api/media/folders/index.mjs +16 -16
- package/dist/astro/routes/api/media/providers/_providerId_/_itemId_.mjs +5 -5
- package/dist/astro/routes/api/media/providers/_providerId_/index.mjs +5 -5
- package/dist/astro/routes/api/media/providers/index.mjs +5 -5
- package/dist/astro/routes/api/media/upload-url.mjs +18 -18
- package/dist/astro/routes/api/media.mjs +35 -35
- package/dist/astro/routes/api/menus/_name_/items/_id_.mjs +17 -17
- package/dist/astro/routes/api/menus/_name_/items.mjs +17 -17
- package/dist/astro/routes/api/menus/_name_/reorder.mjs +17 -17
- package/dist/astro/routes/api/menus/_name_/translations.mjs +17 -17
- package/dist/astro/routes/api/menus/_name_.mjs +17 -17
- package/dist/astro/routes/api/menus/index.mjs +17 -17
- package/dist/astro/routes/api/oauth/authorize.mjs +6 -6
- package/dist/astro/routes/api/oauth/device/authorize.d.mts +2 -1
- package/dist/astro/routes/api/oauth/device/authorize.d.mts.map +1 -1
- package/dist/astro/routes/api/oauth/device/authorize.mjs +23 -9
- package/dist/astro/routes/api/oauth/device/authorize.mjs.map +1 -1
- package/dist/astro/routes/api/oauth/device/code.mjs +11 -11
- package/dist/astro/routes/api/oauth/device/token.mjs +10 -10
- package/dist/astro/routes/api/oauth/register.mjs +5 -5
- package/dist/astro/routes/api/oauth/token/refresh.mjs +8 -8
- package/dist/astro/routes/api/oauth/token/revoke.mjs +8 -8
- package/dist/astro/routes/api/oauth/token.mjs +8 -8
- package/dist/astro/routes/api/openapi.json.mjs +20 -20
- package/dist/astro/routes/api/plugins/_pluginId_/_...path_.mjs +11 -11
- package/dist/astro/routes/api/redirects/404s/index.mjs +19 -19
- package/dist/astro/routes/api/redirects/404s/summary.mjs +19 -19
- package/dist/astro/routes/api/redirects/_id_.mjs +19 -19
- package/dist/astro/routes/api/redirects/index.mjs +19 -19
- package/dist/astro/routes/api/relations/_id_/index.mjs +34 -29
- package/dist/astro/routes/api/relations/_id_/index.mjs.map +1 -1
- package/dist/astro/routes/api/relations/index.mjs +36 -31
- package/dist/astro/routes/api/relations/index.mjs.map +1 -1
- package/dist/astro/routes/api/revisions/_revisionId_/index.mjs +5 -5
- package/dist/astro/routes/api/revisions/_revisionId_/restore.mjs +5 -5
- package/dist/astro/routes/api/schema/block-types/_slug_/index.mjs +71 -67
- package/dist/astro/routes/api/schema/block-types/_slug_/index.mjs.map +1 -1
- package/dist/astro/routes/api/schema/block-types/_slug_/versions/_version_/activate.mjs +71 -67
- package/dist/astro/routes/api/schema/block-types/_slug_/versions/_version_/activate.mjs.map +1 -1
- package/dist/astro/routes/api/schema/block-types/index.mjs +71 -67
- package/dist/astro/routes/api/schema/block-types/index.mjs.map +1 -1
- package/dist/astro/routes/api/schema/collections/_slug_/fields/_fieldSlug_.mjs +73 -69
- package/dist/astro/routes/api/schema/collections/_slug_/fields/_fieldSlug_.mjs.map +1 -1
- package/dist/astro/routes/api/schema/collections/_slug_/fields/index.mjs +71 -67
- package/dist/astro/routes/api/schema/collections/_slug_/fields/index.mjs.map +1 -1
- package/dist/astro/routes/api/schema/collections/_slug_/fields/reorder.mjs +71 -67
- package/dist/astro/routes/api/schema/collections/_slug_/fields/reorder.mjs.map +1 -1
- package/dist/astro/routes/api/schema/collections/_slug_/index.mjs +71 -67
- package/dist/astro/routes/api/schema/collections/_slug_/index.mjs.map +1 -1
- package/dist/astro/routes/api/schema/collections/index.mjs +71 -67
- package/dist/astro/routes/api/schema/collections/index.mjs.map +1 -1
- package/dist/astro/routes/api/schema/collections/reorder.mjs +71 -67
- package/dist/astro/routes/api/schema/collections/reorder.mjs.map +1 -1
- package/dist/astro/routes/api/schema/index.mjs +16 -16
- package/dist/astro/routes/api/schema/orphans/_slug_.mjs +71 -67
- package/dist/astro/routes/api/schema/orphans/_slug_.mjs.map +1 -1
- package/dist/astro/routes/api/schema/orphans/index.mjs +71 -67
- package/dist/astro/routes/api/schema/orphans/index.mjs.map +1 -1
- package/dist/astro/routes/api/search/enable.mjs +19 -19
- package/dist/astro/routes/api/search/index.mjs +18 -18
- package/dist/astro/routes/api/search/rebuild.mjs +19 -19
- package/dist/astro/routes/api/search/stats.mjs +9 -9
- package/dist/astro/routes/api/search/suggest.mjs +18 -18
- package/dist/astro/routes/api/sections/_slug_.mjs +18 -18
- package/dist/astro/routes/api/sections/index.mjs +18 -18
- package/dist/astro/routes/api/settings/backups/archives/_name_.mjs +7 -7
- package/dist/astro/routes/api/settings/backups/archives/index.mjs +7 -7
- package/dist/astro/routes/api/settings/backups/export.mjs +7 -7
- package/dist/astro/routes/api/settings/backups/index.mjs +8 -8
- package/dist/astro/routes/api/settings/email.mjs +6 -6
- package/dist/astro/routes/api/settings.mjs +21 -21
- package/dist/astro/routes/api/setup/admin-verify.mjs +19 -19
- package/dist/astro/routes/api/setup/admin.mjs +18 -18
- package/dist/astro/routes/api/setup/dev-bypass.mjs +45 -39
- package/dist/astro/routes/api/setup/dev-bypass.mjs.map +1 -1
- package/dist/astro/routes/api/setup/dev-reset.mjs +4 -4
- package/dist/astro/routes/api/setup/index.d.mts.map +1 -1
- package/dist/astro/routes/api/setup/index.mjs +80 -49
- package/dist/astro/routes/api/setup/index.mjs.map +1 -1
- package/dist/astro/routes/api/setup/status.mjs +6 -6
- package/dist/astro/routes/api/snapshot.mjs +9 -9
- package/dist/astro/routes/api/snapshot.mjs.map +1 -1
- package/dist/astro/routes/api/taxonomies/_name_/reorder.mjs +23 -23
- package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_/translations.mjs +23 -23
- package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_.mjs +23 -23
- package/dist/astro/routes/api/taxonomies/_name_/terms/index.mjs +23 -23
- package/dist/astro/routes/api/taxonomies/_name_/translations.mjs +22 -22
- package/dist/astro/routes/api/taxonomies/_name_.mjs +23 -23
- package/dist/astro/routes/api/taxonomies/bulk-tag.mjs +36 -35
- package/dist/astro/routes/api/taxonomies/bulk-tag.mjs.map +1 -1
- package/dist/astro/routes/api/taxonomies/index.mjs +23 -23
- package/dist/astro/routes/api/themes/preview.mjs +6 -6
- package/dist/astro/routes/api/typegen.mjs +8 -8
- package/dist/astro/routes/api/visual-editing/action-token.mjs +6 -6
- package/dist/astro/routes/api/visual-editing/content/_collection_/_id_/publish.mjs +19 -19
- package/dist/astro/routes/api/visual-editing/toolbar-labels.mjs +4 -4
- package/dist/astro/routes/api/well-known/auth.mjs +1 -1
- package/dist/astro/routes/api/well-known/oauth-authorization-server.mjs +2 -2
- package/dist/astro/routes/api/well-known/oauth-protected-resource.mjs +2 -2
- package/dist/astro/routes/api/widget-areas/_name_/reorder.mjs +16 -16
- package/dist/astro/routes/api/widget-areas/_name_/widgets/_id_.mjs +19 -19
- package/dist/astro/routes/api/widget-areas/_name_/widgets.mjs +19 -19
- package/dist/astro/routes/api/widget-areas/_name_.mjs +9 -9
- package/dist/astro/routes/api/widget-areas/index.mjs +19 -19
- package/dist/astro/routes/api/widget-components.mjs +5 -5
- package/dist/astro/routes/robots.txt.mjs +6 -6
- package/dist/astro/routes/sitemap-_collection_.xml.mjs +9 -9
- package/dist/astro/routes/sitemap.xml.mjs +7 -7
- package/dist/astro/types.d.mts +28 -18
- package/dist/astro/types.d.mts.map +1 -1
- package/dist/audit-CrgmE9LE.mjs +127 -0
- package/dist/audit-CrgmE9LE.mjs.map +1 -0
- package/dist/auth/providers/github.d.mts +1 -1
- package/dist/auth/providers/google.d.mts +1 -1
- package/dist/authoritative-records-C2YzIdbu.mjs +5172 -0
- package/dist/authoritative-records-C2YzIdbu.mjs.map +1 -0
- package/dist/authorize-WgdKF8QY.mjs +49 -0
- package/dist/authorize-WgdKF8QY.mjs.map +1 -0
- package/dist/backup-Ck8_lMO3.mjs +246 -0
- package/dist/backup-Ck8_lMO3.mjs.map +1 -0
- package/dist/block-types-BQ90asVI.mjs +132 -0
- package/dist/block-types-BQ90asVI.mjs.map +1 -0
- package/dist/block-values-ACFqgB1D.mjs +175 -0
- package/dist/block-values-ACFqgB1D.mjs.map +1 -0
- package/dist/bundle-Db1iNMv_.mjs +667 -0
- package/dist/bundle-Db1iNMv_.mjs.map +1 -0
- package/dist/byline-BayaYGoj.mjs +909 -0
- package/dist/byline-BayaYGoj.mjs.map +1 -0
- package/dist/byline-fields-B8HH-35f.mjs +254 -0
- package/dist/byline-fields-B8HH-35f.mjs.map +1 -0
- package/dist/byline-fields-hMPjf6Eu.mjs +123 -0
- package/dist/byline-fields-hMPjf6Eu.mjs.map +1 -0
- package/dist/byline-registry-B_EK_TQf.mjs +406 -0
- package/dist/byline-registry-B_EK_TQf.mjs.map +1 -0
- package/dist/bylines-DFAaFXWi.mjs +214 -0
- package/dist/bylines-DFAaFXWi.mjs.map +1 -0
- package/dist/bylines-DkIxUxmr.mjs +232 -0
- package/dist/bylines-DkIxUxmr.mjs.map +1 -0
- package/dist/cache-DkvhQ8XE.mjs +108 -0
- package/dist/cache-DkvhQ8XE.mjs.map +1 -0
- package/dist/canonical-CcSuuTlH.mjs +174 -0
- package/dist/canonical-CcSuuTlH.mjs.map +1 -0
- package/dist/capture-triggers-DJEoOTOq.mjs +362 -0
- package/dist/capture-triggers-DJEoOTOq.mjs.map +1 -0
- package/dist/challenge-store-CvBl81AQ.mjs +51 -0
- package/dist/challenge-store-CvBl81AQ.mjs.map +1 -0
- package/dist/checksum-CClweQzI.mjs +162 -0
- package/dist/checksum-CClweQzI.mjs.map +1 -0
- package/dist/chrome-tags-D5caJwwp.mjs +24 -0
- package/dist/chrome-tags-D5caJwwp.mjs.map +1 -0
- package/dist/chunks-DwBaj8aT.mjs +25 -0
- package/dist/chunks-DwBaj8aT.mjs.map +1 -0
- package/dist/cli/index.mjs +374 -761
- package/dist/cli/index.mjs.map +1 -1
- package/dist/client/cf-access.d.mts +1 -1
- package/dist/client/index.d.mts +18 -18
- package/dist/client/index.mjs +2 -2
- package/dist/collection-deletion-CLCdXsnV.mjs +436 -0
- package/dist/collection-deletion-CLCdXsnV.mjs.map +1 -0
- package/dist/collection-deletion-processor-hNw8x01F.mjs +217 -0
- package/dist/collection-deletion-processor-hNw8x01F.mjs.map +1 -0
- package/dist/collection-slugs-cache-CUuiduLq.mjs +85 -0
- package/dist/collection-slugs-cache-CUuiduLq.mjs.map +1 -0
- package/dist/comment-D2uvL63j.mjs +313 -0
- package/dist/comment-D2uvL63j.mjs.map +1 -0
- package/dist/comment-reaction-DevUuzg4.mjs +85 -0
- package/dist/comment-reaction-DevUuzg4.mjs.map +1 -0
- package/dist/comments-Cq0s7_hO.mjs +195 -0
- package/dist/comments-Cq0s7_hO.mjs.map +1 -0
- package/dist/comments-M4EDYAHw.mjs +99 -0
- package/dist/comments-M4EDYAHw.mjs.map +1 -0
- package/dist/components-CuIGwXMs.mjs +108 -0
- package/dist/components-CuIGwXMs.mjs.map +1 -0
- package/dist/config-52Ea5IWt.d.mts +39 -0
- package/dist/config-52Ea5IWt.d.mts.map +1 -0
- package/dist/config-CCz3xOLc.mjs +242 -0
- package/dist/config-CCz3xOLc.mjs.map +1 -0
- package/dist/config-D3d5Qudq.d.mts +6669 -0
- package/dist/config-D3d5Qudq.d.mts.map +1 -0
- package/dist/content-CbnufDsM.mjs +2018 -0
- package/dist/content-CbnufDsM.mjs.map +1 -0
- package/dist/content-list-query-D_7B1FE5.d.mts +26 -0
- package/dist/content-list-query-D_7B1FE5.d.mts.map +1 -0
- package/dist/content-policy-CYu6K1KB.mjs +46 -0
- package/dist/content-policy-CYu6K1KB.mjs.map +1 -0
- package/dist/content-repair-DlDUgFGp.mjs +442 -0
- package/dist/content-repair-DlDUgFGp.mjs.map +1 -0
- package/dist/context-CGQLA1-a.mjs +1922 -0
- package/dist/context-CGQLA1-a.mjs.map +1 -0
- package/dist/cron-c4D5C5Fx.mjs +284 -0
- package/dist/cron-c4D5C5Fx.mjs.map +1 -0
- package/dist/dashboard-CBq9kmOn.mjs +151 -0
- package/dist/dashboard-CBq9kmOn.mjs.map +1 -0
- package/dist/db/index.d.mts +3 -3
- package/dist/db/index.mjs +1 -1
- package/dist/db/libsql-migrations.d.mts +1 -1
- package/dist/db/libsql-migrations.mjs +4 -4
- package/dist/db/libsql.d.mts +1 -1
- package/dist/db/postgres-migrations.d.mts +1 -1
- package/dist/db/postgres-migrations.mjs +4 -4
- package/dist/db/postgres.d.mts +1 -1
- package/dist/db/sqlite-migrations.d.mts +1 -1
- package/dist/db/sqlite-migrations.mjs +4 -4
- package/dist/db/sqlite.d.mts +1 -1
- package/dist/db/sqlite.mjs +1 -1
- package/dist/default-DPsys51U.mjs +81 -0
- package/dist/default-DPsys51U.mjs.map +1 -0
- package/dist/deferred-tasks-CZ7rzBdo.d.mts +9 -0
- package/dist/deferred-tasks-CZ7rzBdo.d.mts.map +1 -0
- package/dist/dev-typegen-HRxwLRcT.mjs +29 -0
- package/dist/dev-typegen-HRxwLRcT.mjs.map +1 -0
- package/dist/device-flow-OcSqE9uY.mjs +521 -0
- package/dist/device-flow-OcSqE9uY.mjs.map +1 -0
- package/dist/digest-DVZ--cE9.mjs +194 -0
- package/dist/digest-DVZ--cE9.mjs.map +1 -0
- package/dist/direct-executor-DyjAqkpT.mjs +104 -0
- package/dist/direct-executor-DyjAqkpT.mjs.map +1 -0
- package/dist/dist-FPR93_xf.mjs +810 -0
- package/dist/dist-FPR93_xf.mjs.map +1 -0
- package/dist/email-console-DyQIgEnz.mjs +50 -0
- package/dist/email-console-DyQIgEnz.mjs.map +1 -0
- package/dist/email-locale-BYb16rVd.mjs +25 -0
- package/dist/email-locale-BYb16rVd.mjs.map +1 -0
- package/dist/emdash-runtime-CrzxJFmF.mjs +4214 -0
- package/dist/emdash-runtime-CrzxJFmF.mjs.map +1 -0
- package/dist/enrich-DBtCncE2.mjs +194 -0
- package/dist/enrich-DBtCncE2.mjs.map +1 -0
- package/dist/entry-lock-BN5y4YbO.d.mts +4481 -0
- package/dist/entry-lock-BN5y4YbO.d.mts.map +1 -0
- package/dist/entry-lock-BaRBHCsH.mjs +1173 -0
- package/dist/entry-lock-BaRBHCsH.mjs.map +1 -0
- package/dist/entry-lock-C6NcnZPV.mjs +163 -0
- package/dist/entry-lock-C6NcnZPV.mjs.map +1 -0
- package/dist/entry-locks-BTyQLdbC.mjs +167 -0
- package/dist/entry-locks-BTyQLdbC.mjs.map +1 -0
- package/dist/error-BfsNNrIE.mjs +90 -0
- package/dist/error-BfsNNrIE.mjs.map +1 -0
- package/dist/errors-BN1QAnEY.mjs +460 -0
- package/dist/errors-BN1QAnEY.mjs.map +1 -0
- package/dist/errors-Bt3goF8I.mjs +120 -0
- package/dist/errors-Bt3goF8I.mjs.map +1 -0
- package/dist/escape-BveidMa2.mjs +9 -0
- package/dist/escape-BveidMa2.mjs.map +1 -0
- package/dist/fence-Bb_IbCxI.mjs +162 -0
- package/dist/fence-Bb_IbCxI.mjs.map +1 -0
- package/dist/field-defs-cache-CsZctvbu.mjs +77 -0
- package/dist/field-defs-cache-CsZctvbu.mjs.map +1 -0
- package/dist/field-map-6m9rF49t.mjs +83 -0
- package/dist/field-map-6m9rF49t.mjs.map +1 -0
- package/dist/focal-point-CZ3d1wK5.mjs +23 -0
- package/dist/focal-point-CZ3d1wK5.mjs.map +1 -0
- package/dist/fts-manager-CCaZTp8y.mjs +443 -0
- package/dist/fts-manager-CCaZTp8y.mjs.map +1 -0
- package/dist/gc-xowRjczI.mjs +75 -0
- package/dist/gc-xowRjczI.mjs.map +1 -0
- package/dist/hash-COVK27Pc.mjs +37 -0
- package/dist/hash-COVK27Pc.mjs.map +1 -0
- package/dist/hook-result-CYSk0XFe.d.mts +31 -0
- package/dist/hook-result-CYSk0XFe.d.mts.map +1 -0
- package/dist/hreflang-CChPV7jx.mjs +105 -0
- package/dist/hreflang-CChPV7jx.mjs.map +1 -0
- package/dist/hreflang-DRslq3QI.d.mts +50 -0
- package/dist/hreflang-DRslq3QI.d.mts.map +1 -0
- package/dist/http-route-dispatch-CAdp2onn.mjs +339 -0
- package/dist/http-route-dispatch-CAdp2onn.mjs.map +1 -0
- package/dist/identity-NVTOOQyq.mjs +35 -0
- package/dist/identity-NVTOOQyq.mjs.map +1 -0
- package/dist/import-wpSO2N0x.mjs +2020 -0
- package/dist/import-wpSO2N0x.mjs.map +1 -0
- package/dist/index-CDs2wq4X.d.mts +623 -0
- package/dist/index-CDs2wq4X.d.mts.map +1 -0
- package/dist/index.d.mts +24 -24
- package/dist/index.mjs +103 -101
- package/dist/install-finalization-D9R9R-W8.mjs +58 -0
- package/dist/install-finalization-D9R9R-W8.mjs.map +1 -0
- package/dist/keys-Bck6LBfF.mjs +61 -0
- package/dist/keys-Bck6LBfF.mjs.map +1 -0
- package/dist/kinds-CYmRESWj.mjs +974 -0
- package/dist/kinds-CYmRESWj.mjs.map +1 -0
- package/dist/lifecycle-C815ZQfV.mjs +25 -0
- package/dist/lifecycle-C815ZQfV.mjs.map +1 -0
- package/dist/load-D99axixL.mjs +28 -0
- package/dist/load-D99axixL.mjs.map +1 -0
- package/dist/loader-CrRPfkHS.mjs +1197 -0
- package/dist/loader-CrRPfkHS.mjs.map +1 -0
- package/dist/loops-DMKlygqX.mjs +203 -0
- package/dist/loops-DMKlygqX.mjs.map +1 -0
- package/dist/manifest-builder-BQzCHNgB.mjs +189 -0
- package/dist/manifest-builder-BQzCHNgB.mjs.map +1 -0
- package/dist/manifest-schema-Ci2gmd0u.mjs +492 -0
- package/dist/manifest-schema-Ci2gmd0u.mjs.map +1 -0
- package/dist/media/image-endpoint.mjs +1 -1
- package/dist/media/index.d.mts +1 -1
- package/dist/media/index.mjs +4 -4
- package/dist/media/local-runtime.d.mts +14 -14
- package/dist/media/local-runtime.mjs +6 -6
- package/dist/media-BUQePMxP.mjs +373 -0
- package/dist/media-BUQePMxP.mjs.map +1 -0
- package/dist/media-DH8ibNlY.mjs +294 -0
- package/dist/media-DH8ibNlY.mjs.map +1 -0
- package/dist/media-OEIQ3bVc.mjs +408 -0
- package/dist/media-OEIQ3bVc.mjs.map +1 -0
- package/dist/media-allowlist-pYtaBA95.mjs +44 -0
- package/dist/media-allowlist-pYtaBA95.mjs.map +1 -0
- package/dist/media-folders-Bf8_s4de.mjs +210 -0
- package/dist/media-folders-Bf8_s4de.mjs.map +1 -0
- package/dist/media-url-C6klEuNd.mjs +43 -0
- package/dist/media-url-C6klEuNd.mjs.map +1 -0
- package/dist/media-usage-D7Y64m6v.mjs +1629 -0
- package/dist/media-usage-D7Y64m6v.mjs.map +1 -0
- package/dist/media-usage-activation-DrqbmgLA.mjs +78 -0
- package/dist/media-usage-activation-DrqbmgLA.mjs.map +1 -0
- package/dist/media-usage-work-DommYhYA.mjs +152 -0
- package/dist/media-usage-work-DommYhYA.mjs.map +1 -0
- package/dist/media-usage-work-HU63hNDu.mjs +586 -0
- package/dist/media-usage-work-HU63hNDu.mjs.map +1 -0
- package/dist/menus-BQfusWEC.mjs +3608 -0
- package/dist/menus-BQfusWEC.mjs.map +1 -0
- package/dist/menus-BtwjQt5s.mjs +753 -0
- package/dist/menus-BtwjQt5s.mjs.map +1 -0
- package/dist/menus-p_M1V7J_.mjs +139 -0
- package/dist/menus-p_M1V7J_.mjs.map +1 -0
- package/dist/migrations/index.d.mts +1 -1
- package/dist/migrations/index.mjs +3 -3
- package/dist/mime-C94qBG-P.mjs +36 -0
- package/dist/mime-C94qBG-P.mjs.map +1 -0
- package/dist/mode-DpYW3w6U.mjs +23 -0
- package/dist/mode-DpYW3w6U.mjs.map +1 -0
- package/dist/node-sqlite-compat-pWFw0lcc.mjs +46 -0
- package/dist/node-sqlite-compat-pWFw0lcc.mjs.map +1 -0
- package/dist/normalize-DduyxBjf.mjs +191 -0
- package/dist/normalize-DduyxBjf.mjs.map +1 -0
- package/dist/oauth-authorization-DAXsH1H9.mjs +274 -0
- package/dist/oauth-authorization-DAXsH1H9.mjs.map +1 -0
- package/dist/oauth-clients-DENiDQri.mjs +266 -0
- package/dist/oauth-clients-DENiDQri.mjs.map +1 -0
- package/dist/oauth-state-store-y8mEYVq9.mjs +50 -0
- package/dist/oauth-state-store-y8mEYVq9.mjs.map +1 -0
- package/dist/oauth-user-lookup-CtTYAy-O.mjs +26 -0
- package/dist/oauth-user-lookup-CtTYAy-O.mjs.map +1 -0
- package/dist/object-cache/memory.d.mts +1 -1
- package/dist/options-BYa1FgIM.d.mts +81 -0
- package/dist/options-BYa1FgIM.d.mts.map +1 -0
- package/dist/page/index.d.mts +2 -2
- package/dist/page/index.mjs +5 -5
- package/dist/parse-CORGGhHf.mjs +81 -0
- package/dist/parse-CORGGhHf.mjs.map +1 -0
- package/dist/parse-avNM1xWV.d.mts +168 -0
- package/dist/parse-avNM1xWV.d.mts.map +1 -0
- package/dist/passkey-config-Dih5YeIS.mjs +46 -0
- package/dist/passkey-config-Dih5YeIS.mjs.map +1 -0
- package/dist/paths-d51RFm8M.mjs +77 -0
- package/dist/paths-d51RFm8M.mjs.map +1 -0
- package/dist/patterns-CoqlXUvk.mjs +145 -0
- package/dist/patterns-CoqlXUvk.mjs.map +1 -0
- package/dist/placeholder-D2aksPMF.d.mts +306 -0
- package/dist/placeholder-D2aksPMF.d.mts.map +1 -0
- package/dist/plan-DqeZKuaR.mjs +135 -0
- package/dist/plan-DqeZKuaR.mjs.map +1 -0
- package/dist/plugin-test-runtime.d.mts +14 -14
- package/dist/plugin-test-runtime.mjs +110 -107
- package/dist/plugin-types.d.mts +2 -2
- package/dist/plugin-utils.d.mts +12 -12
- package/dist/plugins/adapt-sandbox-entry.d.mts +12 -12
- package/dist/plugins/adapt-sandbox-entry.mjs +3 -3
- package/dist/plugins/host.d.mts +5 -5
- package/dist/plugins/host.mjs +42 -41
- package/dist/plugins-Bb7oqjQA.mjs +277 -0
- package/dist/plugins-Bb7oqjQA.mjs.map +1 -0
- package/dist/policy-BcEqut3n.mjs +45 -0
- package/dist/policy-BcEqut3n.mjs.map +1 -0
- package/dist/portable-text-DXE8ymtD.mjs +307 -0
- package/dist/portable-text-DXE8ymtD.mjs.map +1 -0
- package/dist/preview-DEDWbwA_.mjs +107 -0
- package/dist/preview-DEDWbwA_.mjs.map +1 -0
- package/dist/protocol-BJbTzvwl.d.mts +61 -0
- package/dist/protocol-BJbTzvwl.d.mts.map +1 -0
- package/dist/public-submission-D9c9S14m.mjs +250 -0
- package/dist/public-submission-D9c9S14m.mjs.map +1 -0
- package/dist/public-url-CIRe-2T6.mjs +101 -0
- package/dist/public-url-CIRe-2T6.mjs.map +1 -0
- package/dist/query-BzifXlPS.mjs +1156 -0
- package/dist/query-BzifXlPS.mjs.map +1 -0
- package/dist/query-OzMJ6vJP.mjs +41 -0
- package/dist/query-OzMJ6vJP.mjs.map +1 -0
- package/dist/rate-limit-Csp60Vik.mjs +120 -0
- package/dist/rate-limit-Csp60Vik.mjs.map +1 -0
- package/dist/receipt-B-aU4hpJ.mjs +43 -0
- package/dist/receipt-B-aU4hpJ.mjs.map +1 -0
- package/dist/redirect-CDSw1sU3.mjs +17 -0
- package/dist/redirect-CDSw1sU3.mjs.map +1 -0
- package/dist/redirect-D1ArbO85.mjs +411 -0
- package/dist/redirect-D1ArbO85.mjs.map +1 -0
- package/dist/redirects-BjTwDTsV.mjs +148 -0
- package/dist/redirects-BjTwDTsV.mjs.map +1 -0
- package/dist/redirects-Ck50kH3n.mjs +446 -0
- package/dist/redirects-Ck50kH3n.mjs.map +1 -0
- package/dist/registry/testing.mjs +3 -3
- package/dist/registry-CFcNCayZ.mjs +6754 -0
- package/dist/registry-CFcNCayZ.mjs.map +1 -0
- package/dist/relations-Cfaa1fDl.mjs +776 -0
- package/dist/relations-Cfaa1fDl.mjs.map +1 -0
- package/dist/request-cache-iHRlHx1d.mjs +104 -0
- package/dist/request-cache-iHRlHx1d.mjs.map +1 -0
- package/dist/request-context.d.mts +1 -1
- package/dist/request-meta-D47mqyev.mjs +141 -0
- package/dist/request-meta-D47mqyev.mjs.map +1 -0
- package/dist/resolve-BPE8sMvx.mjs +99 -0
- package/dist/resolve-BPE8sMvx.mjs.map +1 -0
- package/dist/resolve-C0s1E_fH.mjs +199 -0
- package/dist/resolve-C0s1E_fH.mjs.map +1 -0
- package/dist/revision-j1p4-bOj.mjs +302 -0
- package/dist/revision-j1p4-bOj.mjs.map +1 -0
- package/dist/route-wire-C9PJV9aL.mjs +197 -0
- package/dist/route-wire-C9PJV9aL.mjs.map +1 -0
- package/dist/routes-lyYw0mMf.mjs +272 -0
- package/dist/routes-lyYw0mMf.mjs.map +1 -0
- package/dist/runner-B3eyB9Gb.mjs +6121 -0
- package/dist/runner-B3eyB9Gb.mjs.map +1 -0
- package/dist/runner-DoYH2Jcu.d.mts +68 -0
- package/dist/runner-DoYH2Jcu.d.mts.map +1 -0
- package/dist/runtime.d.mts +13 -13
- package/dist/runtime.mjs +3 -3
- package/dist/schema-BAayK46S.mjs +13 -0
- package/dist/schema-BAayK46S.mjs.map +1 -0
- package/dist/schema-Gqcl-8G4.mjs +815 -0
- package/dist/schema-Gqcl-8G4.mjs.map +1 -0
- package/dist/scopes-BqPOKoKf.mjs +34 -0
- package/dist/scopes-BqPOKoKf.mjs.map +1 -0
- package/dist/search-YJKPIEV6.mjs +448 -0
- package/dist/search-YJKPIEV6.mjs.map +1 -0
- package/dist/sections-BR_e-wK5.mjs +346 -0
- package/dist/sections-BR_e-wK5.mjs.map +1 -0
- package/dist/seed/index.d.mts +2 -2
- package/dist/seed/index.mjs +37 -31
- package/dist/seo/index.d.mts +3 -3
- package/dist/seo/index.mjs +22 -21
- package/dist/seo/index.mjs.map +1 -1
- package/dist/seo-Dsj8hy3j.mjs +114 -0
- package/dist/seo-Dsj8hy3j.mjs.map +1 -0
- package/dist/seo-XvH4LNNp.mjs +133 -0
- package/dist/seo-XvH4LNNp.mjs.map +1 -0
- package/dist/service-BsVG05gS.mjs +150 -0
- package/dist/service-BsVG05gS.mjs.map +1 -0
- package/dist/session-user-DgKbYrlj.mjs +51 -0
- package/dist/session-user-DgKbYrlj.mjs.map +1 -0
- package/dist/settings-CNPUntkh.mjs +51 -0
- package/dist/settings-CNPUntkh.mjs.map +1 -0
- package/dist/settings-D5EHi0Tk.mjs +439 -0
- package/dist/settings-D5EHi0Tk.mjs.map +1 -0
- package/dist/settings-DSfE7wOa.mjs +61 -0
- package/dist/settings-DSfE7wOa.mjs.map +1 -0
- package/dist/setup-complete-B8W8sJ9v.mjs +26 -0
- package/dist/setup-complete-B8W8sJ9v.mjs.map +1 -0
- package/dist/setup-nonce-DnSBP260.mjs +25 -0
- package/dist/setup-nonce-DnSBP260.mjs.map +1 -0
- package/dist/site-settings-NGzdrt7O.mjs +50 -0
- package/dist/site-settings-NGzdrt7O.mjs.map +1 -0
- package/dist/site-url-D6JB7tLW.mjs +16 -0
- package/dist/site-url-D6JB7tLW.mjs.map +1 -0
- package/dist/snapshot-CdcwwWAf.mjs +414 -0
- package/dist/snapshot-CdcwwWAf.mjs.map +1 -0
- package/dist/ssrf-Dv0_tRpo.mjs +406 -0
- package/dist/ssrf-Dv0_tRpo.mjs.map +1 -0
- package/dist/stage-CUjhED3P.mjs +662 -0
- package/dist/stage-CUjhED3P.mjs.map +1 -0
- package/dist/staged-C36IWXff.mjs +659 -0
- package/dist/staged-C36IWXff.mjs.map +1 -0
- package/dist/state-CKouMCSY.mjs +153 -0
- package/dist/state-CKouMCSY.mjs.map +1 -0
- package/dist/status-lzyj4Uu7.mjs +30 -0
- package/dist/status-lzyj4Uu7.mjs.map +1 -0
- package/dist/storage/local.d.mts +1 -1
- package/dist/storage/local.mjs +1 -1
- package/dist/storage/s3.d.mts +1 -1
- package/dist/storage/s3.mjs +1 -1
- package/dist/storage-query-B-cWcTjJ.d.mts +1594 -0
- package/dist/storage-query-B-cWcTjJ.d.mts.map +1 -0
- package/dist/tar-DsTXX6ch.mjs +449 -0
- package/dist/tar-DsTXX6ch.mjs.map +1 -0
- package/dist/target-DLQCwp_Z.mjs +27 -0
- package/dist/target-DLQCwp_Z.mjs.map +1 -0
- package/dist/taxonomies-BlAjr4BL.mjs +697 -0
- package/dist/taxonomies-BlAjr4BL.mjs.map +1 -0
- package/dist/taxonomies-Byyo7LOZ.mjs +939 -0
- package/dist/taxonomies-Byyo7LOZ.mjs.map +1 -0
- package/dist/taxonomy-CKDwM61Y.mjs +525 -0
- package/dist/taxonomy-CKDwM61Y.mjs.map +1 -0
- package/dist/tokens-BojXlk49.mjs +171 -0
- package/dist/tokens-BojXlk49.mjs.map +1 -0
- package/dist/transaction-DLPQWik1.mjs +29 -0
- package/dist/transaction-DLPQWik1.mjs.map +1 -0
- package/dist/transfer-XSTh2BCr.mjs +8706 -0
- package/dist/transfer-XSTh2BCr.mjs.map +1 -0
- package/dist/transfer-download-DkoCDA9d.mjs +33 -0
- package/dist/transfer-download-DkoCDA9d.mjs.map +1 -0
- package/dist/transfer-iQ26J-RT.mjs +166 -0
- package/dist/transfer-iQ26J-RT.mjs.map +1 -0
- package/dist/transformations-C7RQabKQ.mjs +196 -0
- package/dist/transformations-C7RQabKQ.mjs.map +1 -0
- package/dist/transport-D3RulfD6.mjs +136 -0
- package/dist/transport-D3RulfD6.mjs.map +1 -0
- package/dist/transport-DhlZlf4D.d.mts +42 -0
- package/dist/transport-DhlZlf4D.d.mts.map +1 -0
- package/dist/trusted-proxy-B6ECOZJc.mjs +51 -0
- package/dist/trusted-proxy-B6ECOZJc.mjs.map +1 -0
- package/dist/turnstile-lqUiY7lP.mjs +53 -0
- package/dist/turnstile-lqUiY7lP.mjs.map +1 -0
- package/dist/types-4Dn9bZhu.mjs +77 -0
- package/dist/types-4Dn9bZhu.mjs.map +1 -0
- package/dist/types-5LSo7PPx.d.mts +85 -0
- package/dist/types-5LSo7PPx.d.mts.map +1 -0
- package/dist/types-BQ3hwYJT.d.mts +896 -0
- package/dist/types-BQ3hwYJT.d.mts.map +1 -0
- package/dist/types-BYEk7qo3.d.mts +198 -0
- package/dist/types-BYEk7qo3.d.mts.map +1 -0
- package/dist/types-CJKsWVFR.mjs +199 -0
- package/dist/types-CJKsWVFR.mjs.map +1 -0
- package/dist/types-Ca_w8mmY.d.mts +363 -0
- package/dist/types-Ca_w8mmY.d.mts.map +1 -0
- package/dist/types-CkE41ZAG.mjs +18 -0
- package/dist/types-CkE41ZAG.mjs.map +1 -0
- package/dist/types-D0aJW2uR.d.mts +1641 -0
- package/dist/types-D0aJW2uR.d.mts.map +1 -0
- package/dist/types-DbpN4Qto.d.mts +372 -0
- package/dist/types-DbpN4Qto.d.mts.map +1 -0
- package/dist/types-ILDI1sdY.mjs +16 -0
- package/dist/types-ILDI1sdY.mjs.map +1 -0
- package/dist/types-OC5c-edM.mjs +22 -0
- package/dist/types-OC5c-edM.mjs.map +1 -0
- package/dist/types-aOOxRSx6.mjs +103 -0
- package/dist/types-aOOxRSx6.mjs.map +1 -0
- package/dist/types-m1WbUffD.d.mts +198 -0
- package/dist/types-m1WbUffD.d.mts.map +1 -0
- package/dist/types-uxLoPBio.d.mts +124 -0
- package/dist/types-uxLoPBio.d.mts.map +1 -0
- package/dist/types-we5uR-tV.d.mts +287 -0
- package/dist/types-we5uR-tV.d.mts.map +1 -0
- package/dist/upload-attempts-DduMy6B0.mjs +32 -0
- package/dist/upload-attempts-DduMy6B0.mjs.map +1 -0
- package/dist/url-pattern-B3EwxAAk.mjs +33 -0
- package/dist/url-pattern-B3EwxAAk.mjs.map +1 -0
- package/dist/user-ElwQjTQT.mjs +171 -0
- package/dist/user-ElwQjTQT.mjs.map +1 -0
- package/dist/utils-BlAXmfOG.mjs +439 -0
- package/dist/utils-BlAXmfOG.mjs.map +1 -0
- package/dist/validate-CH0X5b2c.d.mts +468 -0
- package/dist/validate-CH0X5b2c.d.mts.map +1 -0
- package/dist/validate-CfgRpcjA.mjs +492 -0
- package/dist/validate-CfgRpcjA.mjs.map +1 -0
- package/dist/validation-DvYJtv4k.mjs +218 -0
- package/dist/validation-DvYJtv4k.mjs.map +1 -0
- package/dist/version-DgYjhTud.mjs +9 -0
- package/dist/version-DgYjhTud.mjs.map +1 -0
- package/dist/version-Dq71scUb.mjs +7 -0
- package/dist/version-Dq71scUb.mjs.map +1 -0
- package/dist/widgets-ChFIj0be.mjs +126 -0
- package/dist/widgets-ChFIj0be.mjs.map +1 -0
- package/dist/wxr-taxonomies-CBZMp2YX.mjs +372 -0
- package/dist/wxr-taxonomies-CBZMp2YX.mjs.map +1 -0
- package/dist/wxr-taxonomies-DlKDpWN1.d.mts +34 -0
- package/dist/wxr-taxonomies-DlKDpWN1.d.mts.map +1 -0
- package/dist/zod-generator-DmTKI-Ig.mjs +426 -0
- package/dist/zod-generator-DmTKI-Ig.mjs.map +1 -0
- package/package.json +7 -6
- package/src/api/handlers/content.ts +593 -16
- package/src/api/handlers/device-flow.ts +74 -21
- package/src/api/handlers/index.ts +1 -0
- package/src/api/handlers/manifest.ts +79 -5
- package/src/api/handlers/media-upload.ts +17 -71
- package/src/api/handlers/media.ts +97 -3
- package/src/api/handlers/relations.ts +638 -157
- package/src/api/handlers/revision.ts +30 -0
- package/src/api/handlers/schema.ts +403 -1
- package/src/api/handlers/snapshot.ts +257 -3
- package/src/api/handlers/staged-references.ts +142 -0
- package/src/api/handlers/validate-references.ts +146 -0
- package/src/api/schemas/content.ts +13 -0
- package/src/api/schemas/relations.ts +54 -44
- package/src/api/schemas/schema.ts +14 -0
- package/src/astro/integration/routes.ts +15 -19
- package/src/astro/integration/vite-config.ts +10 -4
- package/src/astro/middleware.ts +1 -0
- package/src/astro/routes/api/content/[collection]/[id]/references/[relation]/children.ts +11 -54
- package/src/astro/routes/api/content/[collection]/[id].ts +3 -1
- package/src/astro/routes/api/oauth/device/authorize.ts +33 -4
- package/src/astro/routes/api/relations/index.ts +4 -4
- package/src/astro/routes/api/schema/collections/[slug]/fields/[fieldSlug].ts +6 -2
- package/src/astro/routes/api/setup/index.ts +66 -23
- package/src/astro/routes/api/snapshot.ts +2 -1
- package/src/astro/types.ts +10 -0
- package/src/cleanup.ts +10 -0
- package/src/cli/commands/export-seed.ts +510 -89
- package/src/components/Columns.astro +3 -1
- package/src/components/Cover.astro +3 -1
- package/src/components/WidgetArea.astro +3 -2
- package/src/database/migrations/086_relations_structural.ts +197 -0
- package/src/database/migrations/087_reference_field_relations.ts +407 -0
- package/src/database/migrations/runner.ts +4 -0
- package/src/database/reference-backfill.ts +141 -0
- package/src/database/repositories/content.ts +43 -8
- package/src/database/repositories/media.ts +40 -1
- package/src/database/repositories/redirect.ts +17 -34
- package/src/database/repositories/relation.ts +620 -208
- package/src/database/repositories/revision.ts +16 -0
- package/src/database/repositories/types.ts +38 -0
- package/src/database/transaction.ts +12 -1
- package/src/database/types.ts +14 -5
- package/src/emdash-runtime.ts +114 -11
- package/src/index.ts +11 -0
- package/src/loader.ts +169 -22
- package/src/mcp/server.ts +13 -48
- package/src/query.ts +455 -25
- package/src/references/field-map.ts +115 -0
- package/src/references/resolve.ts +160 -0
- package/src/references/staged.ts +117 -0
- package/src/references/types.ts +16 -0
- package/src/registry/artifact-fetch.ts +45 -271
- package/src/schema/registry.ts +99 -24
- package/src/schema/types.ts +58 -0
- package/src/schema/zod-generator.ts +67 -1
- package/src/seed/apply.ts +841 -103
- package/src/seed/types.ts +36 -2
- package/src/seed/validate.ts +78 -2
- package/src/transfer/analyze/unique-keys.ts +3 -12
- package/src/transfer/analyze/validate.ts +65 -39
- package/src/transfer/analyze/values.ts +12 -1
- package/src/transfer/export/readers.ts +12 -8
- package/src/transfer/format/columns.ts +26 -6
- package/src/transfer/format/kinds.ts +21 -5
- package/src/transfer/import/context.ts +8 -1
- package/src/transfer/ops/package-index.ts +1 -1
- package/dist/action-token-DYwe4Pk0.mjs +0 -26
- package/dist/action-token-DYwe4Pk0.mjs.map +0 -1
- package/dist/activation-LOkDM5WT.mjs +0 -382
- package/dist/activation-LOkDM5WT.mjs.map +0 -1
- package/dist/adapters-B64LbYcB.d.mts +0 -171
- package/dist/adapters-B64LbYcB.d.mts.map +0 -1
- package/dist/allowed-origins-CHB8oZNM.mjs +0 -116
- package/dist/allowed-origins-CHB8oZNM.mjs.map +0 -1
- package/dist/api-cFFZpyS0.mjs +0 -4718
- package/dist/api-cFFZpyS0.mjs.map +0 -1
- package/dist/api-tokens-s4i4aUp_.mjs +0 -166
- package/dist/api-tokens-s4i4aUp_.mjs.map +0 -1
- package/dist/apply-CoT603H3.mjs +0 -1163
- package/dist/apply-CoT603H3.mjs.map +0 -1
- package/dist/approvals-CqMfNxak.mjs +0 -460
- package/dist/approvals-CqMfNxak.mjs.map +0 -1
- package/dist/artifact-fetch-DZMOGZ3-.mjs +0 -818
- package/dist/artifact-fetch-DZMOGZ3-.mjs.map +0 -1
- package/dist/astro/routes/api/relations/_id_/translations.d.mts +0 -8
- package/dist/astro/routes/api/relations/_id_/translations.d.mts.map +0 -1
- package/dist/astro/routes/api/relations/_id_/translations.mjs +0 -47
- package/dist/astro/routes/api/relations/_id_/translations.mjs.map +0 -1
- package/dist/audit-RfCugiSB.mjs +0 -127
- package/dist/audit-RfCugiSB.mjs.map +0 -1
- package/dist/authoritative-records-CoJvBXAD.mjs +0 -5172
- package/dist/authoritative-records-CoJvBXAD.mjs.map +0 -1
- package/dist/authorize-seCifOMJ.mjs +0 -49
- package/dist/authorize-seCifOMJ.mjs.map +0 -1
- package/dist/backup-CBu0LrXf.mjs +0 -246
- package/dist/backup-CBu0LrXf.mjs.map +0 -1
- package/dist/block-type-registry-DUI_3KxT.mjs +0 -6709
- package/dist/block-type-registry-DUI_3KxT.mjs.map +0 -1
- package/dist/block-types-BmZmLmAD.mjs +0 -132
- package/dist/block-types-BmZmLmAD.mjs.map +0 -1
- package/dist/block-values-C_VIPr5t.mjs +0 -175
- package/dist/block-values-C_VIPr5t.mjs.map +0 -1
- package/dist/byline-DYmkXqvo.mjs +0 -909
- package/dist/byline-DYmkXqvo.mjs.map +0 -1
- package/dist/byline-fields-D28AT-Fh.mjs +0 -123
- package/dist/byline-fields-D28AT-Fh.mjs.map +0 -1
- package/dist/byline-registry-gnKscbQX.mjs +0 -406
- package/dist/byline-registry-gnKscbQX.mjs.map +0 -1
- package/dist/bylines-BPwJqoYH.mjs +0 -232
- package/dist/bylines-BPwJqoYH.mjs.map +0 -1
- package/dist/bylines-ukLaYpVZ.mjs +0 -214
- package/dist/bylines-ukLaYpVZ.mjs.map +0 -1
- package/dist/cache-m7UEkRFV.mjs +0 -108
- package/dist/cache-m7UEkRFV.mjs.map +0 -1
- package/dist/canonical-YhEQezjg.mjs +0 -174
- package/dist/canonical-YhEQezjg.mjs.map +0 -1
- package/dist/capture-triggers-kJyl_yyM.mjs +0 -362
- package/dist/capture-triggers-kJyl_yyM.mjs.map +0 -1
- package/dist/challenge-store-ppU6Uv13.mjs +0 -51
- package/dist/challenge-store-ppU6Uv13.mjs.map +0 -1
- package/dist/checksum-B2IINIlN.mjs +0 -162
- package/dist/checksum-B2IINIlN.mjs.map +0 -1
- package/dist/chrome-tags-DApCQSIk.mjs +0 -24
- package/dist/chrome-tags-DApCQSIk.mjs.map +0 -1
- package/dist/chunks-Dms7Uxbt.mjs +0 -25
- package/dist/chunks-Dms7Uxbt.mjs.map +0 -1
- package/dist/collection-deletion-BIm28mo3.mjs +0 -436
- package/dist/collection-deletion-BIm28mo3.mjs.map +0 -1
- package/dist/collection-deletion-processor-Br6rxs3u.mjs +0 -217
- package/dist/collection-deletion-processor-Br6rxs3u.mjs.map +0 -1
- package/dist/collection-slugs-cache-CjGk__zp.mjs +0 -85
- package/dist/collection-slugs-cache-CjGk__zp.mjs.map +0 -1
- package/dist/comment-CrBl22OF.mjs +0 -313
- package/dist/comment-CrBl22OF.mjs.map +0 -1
- package/dist/comment-reaction-JEQ2Fpd8.mjs +0 -85
- package/dist/comment-reaction-JEQ2Fpd8.mjs.map +0 -1
- package/dist/comments-2ah9du9y.mjs +0 -195
- package/dist/comments-2ah9du9y.mjs.map +0 -1
- package/dist/comments-fHZ8ON9O.mjs +0 -99
- package/dist/comments-fHZ8ON9O.mjs.map +0 -1
- package/dist/components-CXbq7CSM.mjs +0 -108
- package/dist/components-CXbq7CSM.mjs.map +0 -1
- package/dist/config-5ii2haYu.d.mts +0 -6528
- package/dist/config-5ii2haYu.d.mts.map +0 -1
- package/dist/config-IhybvkIQ.mjs +0 -242
- package/dist/config-IhybvkIQ.mjs.map +0 -1
- package/dist/config-Py43JK9r.d.mts +0 -39
- package/dist/config-Py43JK9r.d.mts.map +0 -1
- package/dist/content-DFaIEDj9.mjs +0 -2281
- package/dist/content-DFaIEDj9.mjs.map +0 -1
- package/dist/content-list-query-Dra4Dalc.d.mts +0 -26
- package/dist/content-list-query-Dra4Dalc.d.mts.map +0 -1
- package/dist/content-policy-DFNw91-d.mjs +0 -46
- package/dist/content-policy-DFNw91-d.mjs.map +0 -1
- package/dist/content-repair-Q8IUrpLL.mjs +0 -442
- package/dist/content-repair-Q8IUrpLL.mjs.map +0 -1
- package/dist/context-BeGccdUX.mjs +0 -1921
- package/dist/context-BeGccdUX.mjs.map +0 -1
- package/dist/cron-7DCJwPXq.mjs +0 -284
- package/dist/cron-7DCJwPXq.mjs.map +0 -1
- package/dist/dashboard-DjrB-xxZ.mjs +0 -151
- package/dist/dashboard-DjrB-xxZ.mjs.map +0 -1
- package/dist/default-DQ6vsviu.mjs +0 -81
- package/dist/default-DQ6vsviu.mjs.map +0 -1
- package/dist/deferred-tasks-BPxXUB4x.d.mts +0 -9
- package/dist/deferred-tasks-BPxXUB4x.d.mts.map +0 -1
- package/dist/dev-typegen-CZaPLl3V.mjs +0 -29
- package/dist/dev-typegen-CZaPLl3V.mjs.map +0 -1
- package/dist/device-flow-CRd6DXmW.mjs +0 -466
- package/dist/device-flow-CRd6DXmW.mjs.map +0 -1
- package/dist/digest-BarSh-pN.mjs +0 -194
- package/dist/digest-BarSh-pN.mjs.map +0 -1
- package/dist/direct-executor-BmuFJJZV.mjs +0 -104
- package/dist/direct-executor-BmuFJJZV.mjs.map +0 -1
- package/dist/dist-BNwANFJR.mjs +0 -810
- package/dist/dist-BNwANFJR.mjs.map +0 -1
- package/dist/email-console-bJn3ctqA.mjs +0 -50
- package/dist/email-console-bJn3ctqA.mjs.map +0 -1
- package/dist/email-locale-CN6WAMx0.mjs +0 -25
- package/dist/email-locale-CN6WAMx0.mjs.map +0 -1
- package/dist/emdash-runtime-DAjghyEG.mjs +0 -4186
- package/dist/emdash-runtime-DAjghyEG.mjs.map +0 -1
- package/dist/enrich-Dl3kZ-lP.mjs +0 -194
- package/dist/enrich-Dl3kZ-lP.mjs.map +0 -1
- package/dist/entry-lock-BJYdBfXb.mjs +0 -1097
- package/dist/entry-lock-BJYdBfXb.mjs.map +0 -1
- package/dist/entry-lock-DHQOxN7R.mjs +0 -163
- package/dist/entry-lock-DHQOxN7R.mjs.map +0 -1
- package/dist/entry-lock-DVhCt49A.d.mts +0 -4368
- package/dist/entry-lock-DVhCt49A.d.mts.map +0 -1
- package/dist/entry-locks-D0foLdjQ.mjs +0 -167
- package/dist/entry-locks-D0foLdjQ.mjs.map +0 -1
- package/dist/error-CfvOHP0M.mjs +0 -90
- package/dist/error-CfvOHP0M.mjs.map +0 -1
- package/dist/errors-BF0_LFhW.mjs +0 -460
- package/dist/errors-BF0_LFhW.mjs.map +0 -1
- package/dist/errors-DgE1zJGG.mjs +0 -120
- package/dist/errors-DgE1zJGG.mjs.map +0 -1
- package/dist/escape-CuaZhZvL.mjs +0 -9
- package/dist/escape-CuaZhZvL.mjs.map +0 -1
- package/dist/fence-CMDXJYc_.mjs +0 -162
- package/dist/fence-CMDXJYc_.mjs.map +0 -1
- package/dist/field-defs-cache-HIgBbqZZ.mjs +0 -77
- package/dist/field-defs-cache-HIgBbqZZ.mjs.map +0 -1
- package/dist/focal-point-Gr34o-4o.mjs +0 -23
- package/dist/focal-point-Gr34o-4o.mjs.map +0 -1
- package/dist/fts-manager-S-K0laoS.mjs +0 -443
- package/dist/fts-manager-S-K0laoS.mjs.map +0 -1
- package/dist/gc-DjKY0Ay1.mjs +0 -75
- package/dist/gc-DjKY0Ay1.mjs.map +0 -1
- package/dist/hash-SDAW6zC-.mjs +0 -37
- package/dist/hash-SDAW6zC-.mjs.map +0 -1
- package/dist/hook-result-B5bXDgS2.d.mts +0 -31
- package/dist/hook-result-B5bXDgS2.d.mts.map +0 -1
- package/dist/hreflang-D5uNnsGJ.d.mts +0 -50
- package/dist/hreflang-D5uNnsGJ.d.mts.map +0 -1
- package/dist/hreflang-DMFBL2eb.mjs +0 -105
- package/dist/hreflang-DMFBL2eb.mjs.map +0 -1
- package/dist/http-route-dispatch-BitqzwMy.mjs +0 -339
- package/dist/http-route-dispatch-BitqzwMy.mjs.map +0 -1
- package/dist/identity-IyNWwXr6.mjs +0 -35
- package/dist/identity-IyNWwXr6.mjs.map +0 -1
- package/dist/import-C3JZplWq.mjs +0 -2020
- package/dist/import-C3JZplWq.mjs.map +0 -1
- package/dist/index-D-hdtLe8.d.mts +0 -623
- package/dist/index-D-hdtLe8.d.mts.map +0 -1
- package/dist/install-finalization-DfM1fj5x.mjs +0 -58
- package/dist/install-finalization-DfM1fj5x.mjs.map +0 -1
- package/dist/keys-yxLm5l35.mjs +0 -61
- package/dist/keys-yxLm5l35.mjs.map +0 -1
- package/dist/kinds-CRu_T5T5.mjs +0 -961
- package/dist/kinds-CRu_T5T5.mjs.map +0 -1
- package/dist/lifecycle-BzeGPeQ-.mjs +0 -25
- package/dist/lifecycle-BzeGPeQ-.mjs.map +0 -1
- package/dist/load-XgJiE6_3.mjs +0 -28
- package/dist/load-XgJiE6_3.mjs.map +0 -1
- package/dist/loader-BzqeR1ZN.mjs +0 -1086
- package/dist/loader-BzqeR1ZN.mjs.map +0 -1
- package/dist/loops-BQSzv5Zn.mjs +0 -203
- package/dist/loops-BQSzv5Zn.mjs.map +0 -1
- package/dist/manifest-builder-B8zR-73J.mjs +0 -189
- package/dist/manifest-builder-B8zR-73J.mjs.map +0 -1
- package/dist/manifest-schema-CY3zng_M.mjs +0 -492
- package/dist/manifest-schema-CY3zng_M.mjs.map +0 -1
- package/dist/media-Pu1L6xir.mjs +0 -408
- package/dist/media-Pu1L6xir.mjs.map +0 -1
- package/dist/media-Qp5S3eH3.mjs +0 -355
- package/dist/media-Qp5S3eH3.mjs.map +0 -1
- package/dist/media-allowlist-BSoa9Vvm.mjs +0 -44
- package/dist/media-allowlist-BSoa9Vvm.mjs.map +0 -1
- package/dist/media-folders-BE0oo2eX.mjs +0 -210
- package/dist/media-folders-BE0oo2eX.mjs.map +0 -1
- package/dist/media-h7tOiDLj.mjs +0 -221
- package/dist/media-h7tOiDLj.mjs.map +0 -1
- package/dist/media-url-jArBpzIG.mjs +0 -43
- package/dist/media-url-jArBpzIG.mjs.map +0 -1
- package/dist/media-usage-My-Vi-ex.mjs +0 -1629
- package/dist/media-usage-My-Vi-ex.mjs.map +0 -1
- package/dist/media-usage-activation-HKp7zk7W.mjs +0 -78
- package/dist/media-usage-activation-HKp7zk7W.mjs.map +0 -1
- package/dist/media-usage-work-C2OZLCAd.mjs +0 -586
- package/dist/media-usage-work-C2OZLCAd.mjs.map +0 -1
- package/dist/media-usage-work-DwUNbgvS.mjs +0 -152
- package/dist/media-usage-work-DwUNbgvS.mjs.map +0 -1
- package/dist/menus-BM7BPLOb.mjs +0 -139
- package/dist/menus-BM7BPLOb.mjs.map +0 -1
- package/dist/menus-ITeAbcIF.mjs +0 -753
- package/dist/menus-ITeAbcIF.mjs.map +0 -1
- package/dist/menus-TsSGmSR4.mjs +0 -3608
- package/dist/menus-TsSGmSR4.mjs.map +0 -1
- package/dist/mime-ChLqYwDk.mjs +0 -36
- package/dist/mime-ChLqYwDk.mjs.map +0 -1
- package/dist/mode-CCuKXUci.mjs +0 -23
- package/dist/mode-CCuKXUci.mjs.map +0 -1
- package/dist/node-sqlite-compat-CONMsl-x.mjs +0 -46
- package/dist/node-sqlite-compat-CONMsl-x.mjs.map +0 -1
- package/dist/normalize-CO2P8-iE.mjs +0 -191
- package/dist/normalize-CO2P8-iE.mjs.map +0 -1
- package/dist/oauth-authorization-DlMIL5_h.mjs +0 -274
- package/dist/oauth-authorization-DlMIL5_h.mjs.map +0 -1
- package/dist/oauth-clients-Djq9r_KP.mjs +0 -266
- package/dist/oauth-clients-Djq9r_KP.mjs.map +0 -1
- package/dist/oauth-state-store-BbjnZXNC.mjs +0 -50
- package/dist/oauth-state-store-BbjnZXNC.mjs.map +0 -1
- package/dist/oauth-user-lookup-vue9a64A.mjs +0 -26
- package/dist/oauth-user-lookup-vue9a64A.mjs.map +0 -1
- package/dist/options-SQCHQCPH.d.mts +0 -81
- package/dist/options-SQCHQCPH.d.mts.map +0 -1
- package/dist/parse-CVgO-Qai.d.mts +0 -168
- package/dist/parse-CVgO-Qai.d.mts.map +0 -1
- package/dist/parse-DY6OD1j_.mjs +0 -81
- package/dist/parse-DY6OD1j_.mjs.map +0 -1
- package/dist/passkey-config-X_H8128a.mjs +0 -46
- package/dist/passkey-config-X_H8128a.mjs.map +0 -1
- package/dist/paths-JxokKIbr.mjs +0 -77
- package/dist/paths-JxokKIbr.mjs.map +0 -1
- package/dist/patterns-BhAvqO0S.mjs +0 -145
- package/dist/patterns-BhAvqO0S.mjs.map +0 -1
- package/dist/placeholder-MSEd8gty.d.mts +0 -306
- package/dist/placeholder-MSEd8gty.d.mts.map +0 -1
- package/dist/plan-xjcWrAah.mjs +0 -135
- package/dist/plan-xjcWrAah.mjs.map +0 -1
- package/dist/plugins-DUXUt8B9.mjs +0 -277
- package/dist/plugins-DUXUt8B9.mjs.map +0 -1
- package/dist/policy-CUvwAARc.mjs +0 -45
- package/dist/policy-CUvwAARc.mjs.map +0 -1
- package/dist/portable-text-5O_ZGUjB.mjs +0 -307
- package/dist/portable-text-5O_ZGUjB.mjs.map +0 -1
- package/dist/preview-CIUcPYr6.mjs +0 -107
- package/dist/preview-CIUcPYr6.mjs.map +0 -1
- package/dist/protocol-B97DZaFr.d.mts +0 -61
- package/dist/protocol-B97DZaFr.d.mts.map +0 -1
- package/dist/public-submission-BFBUrqst.mjs +0 -250
- package/dist/public-submission-BFBUrqst.mjs.map +0 -1
- package/dist/public-url-Bn7U0D7-.mjs +0 -101
- package/dist/public-url-Bn7U0D7-.mjs.map +0 -1
- package/dist/query-B48peoRT.mjs +0 -890
- package/dist/query-B48peoRT.mjs.map +0 -1
- package/dist/query-C4IH0uhR.mjs +0 -41
- package/dist/query-C4IH0uhR.mjs.map +0 -1
- package/dist/rate-limit-BZ6nybgc.mjs +0 -120
- package/dist/rate-limit-BZ6nybgc.mjs.map +0 -1
- package/dist/receipt-B4wJj5Jq.mjs +0 -43
- package/dist/receipt-B4wJj5Jq.mjs.map +0 -1
- package/dist/redirect-Cd1E7VUt.mjs +0 -17
- package/dist/redirect-Cd1E7VUt.mjs.map +0 -1
- package/dist/redirect-iJf5fltD.mjs +0 -415
- package/dist/redirect-iJf5fltD.mjs.map +0 -1
- package/dist/redirects-CYu1u1aK.mjs +0 -446
- package/dist/redirects-CYu1u1aK.mjs.map +0 -1
- package/dist/redirects-Cv9apQKj.mjs +0 -148
- package/dist/redirects-Cv9apQKj.mjs.map +0 -1
- package/dist/relation-M4NUCb0b.mjs +0 -334
- package/dist/relation-M4NUCb0b.mjs.map +0 -1
- package/dist/relations-CCif47Oq.mjs +0 -403
- package/dist/relations-CCif47Oq.mjs.map +0 -1
- package/dist/relations-CK9CYUyr.mjs +0 -310
- package/dist/relations-CK9CYUyr.mjs.map +0 -1
- package/dist/request-cache-DzLYKm_x.mjs +0 -104
- package/dist/request-cache-DzLYKm_x.mjs.map +0 -1
- package/dist/request-meta-sZXt3sRo.mjs +0 -141
- package/dist/request-meta-sZXt3sRo.mjs.map +0 -1
- package/dist/resolve-2WbQsCvT.mjs +0 -199
- package/dist/resolve-2WbQsCvT.mjs.map +0 -1
- package/dist/route-wire--1hLuACz.mjs +0 -197
- package/dist/route-wire--1hLuACz.mjs.map +0 -1
- package/dist/routes-CUsM40Cc.mjs +0 -272
- package/dist/routes-CUsM40Cc.mjs.map +0 -1
- package/dist/runner-1y4J9fJB.mjs +0 -5742
- package/dist/runner-1y4J9fJB.mjs.map +0 -1
- package/dist/runner-D5_LzKXI.d.mts +0 -68
- package/dist/runner-D5_LzKXI.d.mts.map +0 -1
- package/dist/schema-BABiRdsH.mjs +0 -13
- package/dist/schema-BABiRdsH.mjs.map +0 -1
- package/dist/schema-Du3MzCG0.mjs +0 -446
- package/dist/schema-Du3MzCG0.mjs.map +0 -1
- package/dist/scopes-Dbk-ElhT.mjs +0 -34
- package/dist/scopes-Dbk-ElhT.mjs.map +0 -1
- package/dist/search-Bt1PL1jf.mjs +0 -448
- package/dist/search-Bt1PL1jf.mjs.map +0 -1
- package/dist/sections-Ddptx_o9.mjs +0 -346
- package/dist/sections-Ddptx_o9.mjs.map +0 -1
- package/dist/seo-CZT2oLtT.mjs +0 -114
- package/dist/seo-CZT2oLtT.mjs.map +0 -1
- package/dist/seo-D5w3-Azy.mjs +0 -133
- package/dist/seo-D5w3-Azy.mjs.map +0 -1
- package/dist/service-DuykXPyW.mjs +0 -150
- package/dist/service-DuykXPyW.mjs.map +0 -1
- package/dist/session-user-BhaVp8w0.mjs +0 -51
- package/dist/session-user-BhaVp8w0.mjs.map +0 -1
- package/dist/settings-2xNYr90o.mjs +0 -51
- package/dist/settings-2xNYr90o.mjs.map +0 -1
- package/dist/settings-CgjRWGW9.mjs +0 -439
- package/dist/settings-CgjRWGW9.mjs.map +0 -1
- package/dist/settings-DYidIB26.mjs +0 -61
- package/dist/settings-DYidIB26.mjs.map +0 -1
- package/dist/setup-complete-bOogcHWG.mjs +0 -26
- package/dist/setup-complete-bOogcHWG.mjs.map +0 -1
- package/dist/setup-nonce-0EGuKM4s.mjs +0 -25
- package/dist/setup-nonce-0EGuKM4s.mjs.map +0 -1
- package/dist/site-settings-DOgRUoFX.mjs +0 -50
- package/dist/site-settings-DOgRUoFX.mjs.map +0 -1
- package/dist/site-url-BU_bbxwj.mjs +0 -16
- package/dist/site-url-BU_bbxwj.mjs.map +0 -1
- package/dist/snapshot-CugwUqKQ.mjs +0 -237
- package/dist/snapshot-CugwUqKQ.mjs.map +0 -1
- package/dist/ssrf-CJUnJymJ.mjs +0 -406
- package/dist/ssrf-CJUnJymJ.mjs.map +0 -1
- package/dist/stage-DgrBz_du.mjs +0 -662
- package/dist/stage-DgrBz_du.mjs.map +0 -1
- package/dist/state-DDiPySSG.mjs +0 -153
- package/dist/state-DDiPySSG.mjs.map +0 -1
- package/dist/status-DZKIG4a9.mjs +0 -30
- package/dist/status-DZKIG4a9.mjs.map +0 -1
- package/dist/storage-query-Bdv7A62k.d.mts +0 -1576
- package/dist/storage-query-Bdv7A62k.d.mts.map +0 -1
- package/dist/tar-_1AgTYFu.mjs +0 -449
- package/dist/tar-_1AgTYFu.mjs.map +0 -1
- package/dist/target-_7pn2Gbg.mjs +0 -27
- package/dist/target-_7pn2Gbg.mjs.map +0 -1
- package/dist/taxonomies-C1IwNe8Q.mjs +0 -697
- package/dist/taxonomies-C1IwNe8Q.mjs.map +0 -1
- package/dist/taxonomies-C_XMoRcX.mjs +0 -939
- package/dist/taxonomies-C_XMoRcX.mjs.map +0 -1
- package/dist/taxonomy-C3Fu1YeH.mjs +0 -525
- package/dist/taxonomy-C3Fu1YeH.mjs.map +0 -1
- package/dist/tokens-u78jETkX.mjs +0 -171
- package/dist/tokens-u78jETkX.mjs.map +0 -1
- package/dist/transaction-BcJO4Tmc.mjs +0 -29
- package/dist/transaction-BcJO4Tmc.mjs.map +0 -1
- package/dist/transfer-BhUCrgDc.mjs +0 -8675
- package/dist/transfer-BhUCrgDc.mjs.map +0 -1
- package/dist/transfer-DIGvR9Af.mjs +0 -166
- package/dist/transfer-DIGvR9Af.mjs.map +0 -1
- package/dist/transfer-download-Pml7RMio.mjs +0 -33
- package/dist/transfer-download-Pml7RMio.mjs.map +0 -1
- package/dist/transformations-9gfpwY65.mjs +0 -196
- package/dist/transformations-9gfpwY65.mjs.map +0 -1
- package/dist/transport-BIfH7_hx.d.mts +0 -42
- package/dist/transport-BIfH7_hx.d.mts.map +0 -1
- package/dist/transport-DKWIq53q.mjs +0 -136
- package/dist/transport-DKWIq53q.mjs.map +0 -1
- package/dist/trusted-proxy-tKiVtyTD.mjs +0 -51
- package/dist/trusted-proxy-tKiVtyTD.mjs.map +0 -1
- package/dist/turnstile-DpsoyOfg.mjs +0 -53
- package/dist/turnstile-DpsoyOfg.mjs.map +0 -1
- package/dist/types-B4sUC2p1.d.mts +0 -198
- package/dist/types-B4sUC2p1.d.mts.map +0 -1
- package/dist/types-B7Lmsh1E.d.mts +0 -887
- package/dist/types-B7Lmsh1E.d.mts.map +0 -1
- package/dist/types-BZakh7Ym.mjs +0 -22
- package/dist/types-BZakh7Ym.mjs.map +0 -1
- package/dist/types-B_CppEmv.d.mts +0 -264
- package/dist/types-B_CppEmv.d.mts.map +0 -1
- package/dist/types-BcrBrE6-.mjs +0 -159
- package/dist/types-BcrBrE6-.mjs.map +0 -1
- package/dist/types-BkUg2yHx.mjs +0 -92
- package/dist/types-BkUg2yHx.mjs.map +0 -1
- package/dist/types-CAZgq9fO.d.mts +0 -124
- package/dist/types-CAZgq9fO.d.mts.map +0 -1
- package/dist/types-Cd-O03VG.d.mts +0 -363
- package/dist/types-Cd-O03VG.d.mts.map +0 -1
- package/dist/types-Cr-Kg-3D.d.mts +0 -1641
- package/dist/types-Cr-Kg-3D.d.mts.map +0 -1
- package/dist/types-D2fvWd1i.d.mts +0 -359
- package/dist/types-D2fvWd1i.d.mts.map +0 -1
- package/dist/types-D7HUsguf.mjs +0 -77
- package/dist/types-D7HUsguf.mjs.map +0 -1
- package/dist/types-DA1Te3Oy.d.mts +0 -198
- package/dist/types-DA1Te3Oy.d.mts.map +0 -1
- package/dist/types-DhV6Q5bP.mjs +0 -18
- package/dist/types-DhV6Q5bP.mjs.map +0 -1
- package/dist/types-DnnVSl6Y.d.mts +0 -85
- package/dist/types-DnnVSl6Y.d.mts.map +0 -1
- package/dist/types-VT4-BugW.mjs +0 -16
- package/dist/types-VT4-BugW.mjs.map +0 -1
- package/dist/upload-attempts-B68ZGNu9.mjs +0 -32
- package/dist/upload-attempts-B68ZGNu9.mjs.map +0 -1
- package/dist/url-pattern-CCeZMGOh.mjs +0 -33
- package/dist/url-pattern-CCeZMGOh.mjs.map +0 -1
- package/dist/user-DDSL-sGw.mjs +0 -171
- package/dist/user-DDSL-sGw.mjs.map +0 -1
- package/dist/utils-DdhmO9w9.mjs +0 -439
- package/dist/utils-DdhmO9w9.mjs.map +0 -1
- package/dist/validate-CHosPEhs.mjs +0 -453
- package/dist/validate-CHosPEhs.mjs.map +0 -1
- package/dist/validate-CM79QXYE.d.mts +0 -432
- package/dist/validate-CM79QXYE.d.mts.map +0 -1
- package/dist/validation-BFecQczG.mjs +0 -218
- package/dist/validation-BFecQczG.mjs.map +0 -1
- package/dist/version-BRZXVifl.mjs +0 -9
- package/dist/version-BRZXVifl.mjs.map +0 -1
- package/dist/version-DUQDHgrf.mjs +0 -7
- package/dist/version-DUQDHgrf.mjs.map +0 -1
- package/dist/widgets-WdV72brA.mjs +0 -126
- package/dist/widgets-WdV72brA.mjs.map +0 -1
- package/dist/wxr-taxonomies-BHTdqkmZ.d.mts +0 -34
- package/dist/wxr-taxonomies-BHTdqkmZ.d.mts.map +0 -1
- package/dist/wxr-taxonomies-DP6ESgMN.mjs +0 -372
- package/dist/wxr-taxonomies-DP6ESgMN.mjs.map +0 -1
- package/dist/zod-generator-D6uE4WiS.mjs +0 -389
- package/dist/zod-generator-D6uE4WiS.mjs.map +0 -1
- package/src/astro/routes/api/relations/[id]/translations.ts +0 -33
- /package/dist/{api-tokens-CE1ECIg0.mjs → api-tokens-FaG1zPsj.mjs} +0 -0
- /package/dist/{ssrf-DpBH7aOt.mjs → ssrf-DZOt8Qof.mjs} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"normalize-DduyxBjf.mjs","names":[],"sources":["../src/media/normalize.ts"],"sourcesContent":["/**\n * Media Value Normalization\n *\n * Normalizes media field values into a consistent shape regardless of\n * creation path (seed scripts, media picker, WP import, URL input).\n *\n * Called at content create/update time when a media provider is available,\n * filling in missing dimensions, storageKey, mimeType, and filename from\n * the provider's `get()` method.\n */\n\nimport { normalizeFocalPoint } from \"./focal-point.js\";\nimport type { MediaProvider, MediaProviderItem, MediaValue } from \"./types.js\";\n\nexport const INTERNAL_MEDIA_PREFIX = \"/_emdash/api/media/file/\";\nconst URL_PATTERN = /^https?:\\/\\//;\n\nexport function normalizeLegacyExternalMediaValue(value: MediaValue): MediaValue {\n\tif (value.provider !== \"external-url\") return value;\n\tconst src = value.src ?? value.previewUrl;\n\treturn {\n\t\t...value,\n\t\tprovider: \"external\",\n\t\t...(src === undefined ? {} : { src }),\n\t};\n}\n\n/**\n * Normalize a media field value into a consistent MediaValue shape.\n *\n * - `null`/`undefined` → `null`\n * - Bare URL string → `{ provider: \"external\", id: \"\", src: url }`\n * - Bare internal media URL → resolved via local provider's `get()`\n * - Bare local media ID → resolved via local provider's `get()`\n * - Object with `provider` + `id` → enriched with missing fields from provider\n */\nexport async function normalizeMediaValue(\n\tvalue: unknown,\n\tgetProvider: (id: string) => MediaProvider | undefined,\n): Promise<MediaValue | null> {\n\tif (value == null) return null;\n\n\t// Bare string URL\n\tif (typeof value === \"string\") {\n\t\treturn normalizeStringUrl(value, getProvider);\n\t}\n\n\t// Not an object — can't normalize\n\tif (!isRecord(value)) return null;\n\n\t// Must have at least an id to be a valid media value\n\tif (!(\"id\" in value) && !(\"src\" in value)) return null;\n\n\tconst parsed = normalizeLegacyExternalMediaValue(recordToMediaValue(value));\n\tconst provider = parsed.provider || \"local\";\n\tconst id = parsed.id;\n\n\t// External URLs — return as-is, no server-side dimension detection\n\tif (provider === \"external\") {\n\t\treturn parsed;\n\t}\n\n\t// Build the base value from the input\n\tconst result: MediaValue = { ...parsed, provider };\n\n\t// For local media, strip `src` — it's derived at display time from storageKey\n\tif (provider === \"local\") {\n\t\tdelete result.src;\n\t}\n\n\t// Determine if we need to call the provider\n\tconst needsDimensions = result.width == null || result.height == null;\n\tconst needsStorageKey = provider === \"local\" && !result.meta?.storageKey;\n\tconst needsFileInfo = !result.mimeType || !result.filename;\n\t// LQIP placeholders are immutable facts of the bytes: if an image record is\n\t// missing them, the provider may have gained them since (e.g. content saved\n\t// before LQIP backfill ran, or the row's blurhash was populated later). Pull\n\t// them on every image lookup so the LQIP backfill in mergeProviderData runs.\n\tconst needsLqip =\n\t\t(result.mimeType ?? \"\").startsWith(\"image/\") &&\n\t\t(result.blurhash == null || result.dominantColor == null);\n\tconst needsLookup = needsDimensions || needsStorageKey || needsFileInfo || needsLqip;\n\n\tif (!needsLookup || !id) return result;\n\n\t// Try to enrich from provider\n\tconst mediaProvider = getProvider(provider);\n\tif (!mediaProvider?.get) return result;\n\n\tlet providerItem: MediaProviderItem | null;\n\ttry {\n\t\tproviderItem = await mediaProvider.get(id);\n\t} catch {\n\t\treturn result;\n\t}\n\n\tif (!providerItem) return result;\n\n\treturn mergeProviderData(result, providerItem);\n}\n\nasync function normalizeStringUrl(\n\turl: string,\n\tgetProvider: (id: string) => MediaProvider | undefined,\n): Promise<MediaValue | null> {\n\t// Internal media URL — try to resolve via local provider\n\tif (url.startsWith(INTERNAL_MEDIA_PREFIX)) {\n\t\treturn resolveInternalUrl(url, getProvider);\n\t}\n\n\t// External HTTP(S) URL\n\tif (URL_PATTERN.test(url)) {\n\t\treturn Promise.resolve({\n\t\t\tprovider: \"external\",\n\t\t\tid: \"\",\n\t\t\tsrc: url,\n\t\t});\n\t}\n\n\tconst localMedia = await resolveLocalId(url, getProvider);\n\tif (localMedia) return localMedia;\n\n\t// Unrecognized string — preserve legacy behavior and treat as external\n\treturn {\n\t\tprovider: \"external\",\n\t\tid: \"\",\n\t\tsrc: url,\n\t};\n}\n\nasync function resolveInternalUrl(\n\turl: string,\n\tgetProvider: (id: string) => MediaProvider | undefined,\n): Promise<MediaValue> {\n\tconst storageKey = url.slice(INTERNAL_MEDIA_PREFIX.length);\n\tconst localProvider = getProvider(\"local\");\n\n\tif (!localProvider?.get) {\n\t\treturn { provider: \"external\", id: \"\", src: url };\n\t}\n\n\tlet item: MediaProviderItem | null;\n\ttry {\n\t\titem = await localProvider.get(storageKey);\n\t} catch {\n\t\treturn { provider: \"external\", id: \"\", src: url };\n\t}\n\n\tif (!item) {\n\t\treturn { provider: \"external\", id: \"\", src: url };\n\t}\n\n\tconst focalPoint = normalizeFocalPoint(item.focalX, item.focalY);\n\treturn {\n\t\tprovider: \"local\",\n\t\tid: item.id,\n\t\tfilename: item.filename,\n\t\tmimeType: item.mimeType,\n\t\twidth: item.width,\n\t\theight: item.height,\n\t\t...focalPoint,\n\t\tblurhash: item.blurhash,\n\t\tdominantColor: item.dominantColor,\n\t\talt: item.alt,\n\t\tmeta: item.meta,\n\t};\n}\n\nasync function resolveLocalId(\n\tid: string,\n\tgetProvider: (id: string) => MediaProvider | undefined,\n): Promise<MediaValue | null> {\n\tconst localProvider = getProvider(\"local\");\n\n\tif (!localProvider?.get) return null;\n\n\tlet item: MediaProviderItem | null;\n\ttry {\n\t\titem = await localProvider.get(id);\n\t} catch {\n\t\treturn null;\n\t}\n\n\tif (!item) return null;\n\n\tconst focalPoint = normalizeFocalPoint(item.focalX, item.focalY);\n\treturn {\n\t\tprovider: \"local\",\n\t\tid: item.id,\n\t\tfilename: item.filename,\n\t\tmimeType: item.mimeType,\n\t\twidth: item.width,\n\t\theight: item.height,\n\t\t...focalPoint,\n\t\tblurhash: item.blurhash,\n\t\tdominantColor: item.dominantColor,\n\t\talt: item.alt,\n\t\tmeta: item.meta,\n\t};\n}\n\n/**\n * Merge provider data into an existing MediaValue, preserving caller-supplied fields.\n * Caller `alt` takes priority over provider `alt` (per-usage, not per-image).\n */\nfunction mergeProviderData(existing: MediaValue, item: MediaProviderItem): MediaValue {\n\tconst result = { ...existing };\n\n\t// Fill missing dimensions\n\tif (result.width == null && item.width != null) result.width = item.width;\n\tif (result.height == null && item.height != null) result.height = item.height;\n\n\t// Fill missing LQIP placeholders (immutable facts of the bytes; caller wins)\n\tif (result.blurhash == null && item.blurhash != null) result.blurhash = item.blurhash;\n\tif (result.dominantColor == null && item.dominantColor != null) {\n\t\tresult.dominantColor = item.dominantColor;\n\t}\n\n\t// Fill missing file info\n\tif (!result.filename && item.filename) result.filename = item.filename;\n\tif (!result.mimeType && item.mimeType) result.mimeType = item.mimeType;\n\n\t// Fill missing alt (provider alt is fallback, not override)\n\tif (!result.alt && item.alt) result.alt = item.alt;\n\n\t// Fill missing meta (merge, don't replace)\n\tif (item.meta) {\n\t\tresult.meta = { ...item.meta, ...result.meta };\n\t}\n\n\treturn result;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\n/**\n * Extract known MediaValue fields from a runtime-checked record.\n * Avoids unsafe `as MediaValue` cast by reading each property explicitly.\n */\nfunction recordToMediaValue(obj: Record<string, unknown>): MediaValue {\n\tconst result: MediaValue = {\n\t\tid: typeof obj.id === \"string\" ? obj.id : \"\",\n\t};\n\tif (typeof obj.provider === \"string\") result.provider = obj.provider;\n\tif (typeof obj.src === \"string\") result.src = obj.src;\n\tif (typeof obj.previewUrl === \"string\") result.previewUrl = obj.previewUrl;\n\tif (typeof obj.filename === \"string\") result.filename = obj.filename;\n\tif (typeof obj.mimeType === \"string\") result.mimeType = obj.mimeType;\n\tif (typeof obj.width === \"number\") result.width = obj.width;\n\tif (typeof obj.height === \"number\") result.height = obj.height;\n\tconst focalPoint = normalizeFocalPoint(obj.focalX, obj.focalY);\n\tif (focalPoint) {\n\t\tresult.focalX = focalPoint.focalX;\n\t\tresult.focalY = focalPoint.focalY;\n\t}\n\tif (typeof obj.blurhash === \"string\") result.blurhash = obj.blurhash;\n\tif (typeof obj.dominantColor === \"string\") result.dominantColor = obj.dominantColor;\n\tif (typeof obj.alt === \"string\") result.alt = obj.alt;\n\tif (isRecord(obj.meta)) result.meta = obj.meta;\n\treturn result;\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
import { t as withTransaction } from "./transaction-DLPQWik1.mjs";
|
|
2
|
+
import { i as generatePrefixedToken, o as hashApiToken, s as isValidScope, t as TOKEN_PREFIXES } from "./api-tokens-FaG1zPsj.mjs";
|
|
3
|
+
import { c as validateRedirectUri, o as lookupOAuthClient, s as validateClientRedirectUri } from "./oauth-clients-DENiDQri.mjs";
|
|
4
|
+
import { t as lookupUserRoleAndStatus } from "./oauth-user-lookup-CtTYAy-O.mjs";
|
|
5
|
+
import { clampScopes, computeS256Challenge, secureCompare } from "@emdash-cms/auth";
|
|
6
|
+
import { generateCodeVerifier } from "arctic";
|
|
7
|
+
|
|
8
|
+
//#region src/api/handlers/oauth-authorization.ts
|
|
9
|
+
/**
|
|
10
|
+
* OAuth 2.1 Authorization Code + PKCE handlers.
|
|
11
|
+
*
|
|
12
|
+
* Implements the server side of the authorization code grant for MCP clients
|
|
13
|
+
* (Claude Desktop, VS Code, etc.) per the MCP authorization spec (draft).
|
|
14
|
+
*
|
|
15
|
+
* Uses arctic for PKCE challenge generation and @emdash-cms/auth for token
|
|
16
|
+
* utilities. Token infrastructure is shared with the device flow.
|
|
17
|
+
*/
|
|
18
|
+
/** Authorization codes expire after 10 minutes (RFC 6749 §4.1.2 recommends short-lived) */
|
|
19
|
+
const AUTH_CODE_TTL_SECONDS = 600;
|
|
20
|
+
/** Access token TTL: 1 hour */
|
|
21
|
+
const ACCESS_TOKEN_TTL_SECONDS = 3600;
|
|
22
|
+
/** Refresh token TTL: 90 days */
|
|
23
|
+
const REFRESH_TOKEN_TTL_SECONDS = 2160 * 60 * 60;
|
|
24
|
+
function expiresAt(seconds) {
|
|
25
|
+
return new Date(Date.now() + seconds * 1e3).toISOString();
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Validate and normalize scopes. Returns validated scope list.
|
|
29
|
+
*/
|
|
30
|
+
function normalizeScopes(requested) {
|
|
31
|
+
if (!requested) return [];
|
|
32
|
+
return requested.split(" ").filter(Boolean).filter(isValidScope);
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Process an authorization request after the user approves consent.
|
|
36
|
+
*
|
|
37
|
+
* Generates an authorization code, stores it with the PKCE challenge,
|
|
38
|
+
* and returns the redirect URL with the code appended.
|
|
39
|
+
*
|
|
40
|
+
* Scopes are clamped to the user's role to prevent scope escalation.
|
|
41
|
+
*/
|
|
42
|
+
async function handleAuthorizationApproval(db, userId, userRole, params) {
|
|
43
|
+
try {
|
|
44
|
+
if (params.response_type !== "code") return {
|
|
45
|
+
success: false,
|
|
46
|
+
error: {
|
|
47
|
+
code: "UNSUPPORTED_RESPONSE_TYPE",
|
|
48
|
+
message: "Only response_type=code is supported"
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
const uriError = validateRedirectUri(params.redirect_uri);
|
|
52
|
+
if (uriError) return {
|
|
53
|
+
success: false,
|
|
54
|
+
error: {
|
|
55
|
+
code: "INVALID_REDIRECT_URI",
|
|
56
|
+
message: uriError
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
const client = await lookupOAuthClient(db, params.client_id);
|
|
60
|
+
if (!client) return {
|
|
61
|
+
success: false,
|
|
62
|
+
error: {
|
|
63
|
+
code: "INVALID_CLIENT",
|
|
64
|
+
message: "Unknown client_id"
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
const clientUriError = validateClientRedirectUri(params.redirect_uri, client.redirectUris);
|
|
68
|
+
if (clientUriError) return {
|
|
69
|
+
success: false,
|
|
70
|
+
error: {
|
|
71
|
+
code: "INVALID_REDIRECT_URI",
|
|
72
|
+
message: clientUriError
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
if (params.code_challenge_method !== "S256") return {
|
|
76
|
+
success: false,
|
|
77
|
+
error: {
|
|
78
|
+
code: "INVALID_REQUEST",
|
|
79
|
+
message: "Only S256 code_challenge_method is supported"
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
if (!params.code_challenge) return {
|
|
83
|
+
success: false,
|
|
84
|
+
error: {
|
|
85
|
+
code: "INVALID_REQUEST",
|
|
86
|
+
message: "code_challenge is required"
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
const userScopes = clampScopes(normalizeScopes(params.scope), userRole);
|
|
90
|
+
const clientScopes = client.scopes;
|
|
91
|
+
const scopes = clientScopes?.length ? userScopes.filter((s) => clientScopes.includes(s)) : userScopes;
|
|
92
|
+
if (scopes.length === 0) return {
|
|
93
|
+
success: false,
|
|
94
|
+
error: {
|
|
95
|
+
code: "INVALID_SCOPE",
|
|
96
|
+
message: "No valid scopes requested"
|
|
97
|
+
}
|
|
98
|
+
};
|
|
99
|
+
const code = generateCodeVerifier();
|
|
100
|
+
const codeHash = hashApiToken(code);
|
|
101
|
+
await db.insertInto("_emdash_authorization_codes").values({
|
|
102
|
+
code_hash: codeHash,
|
|
103
|
+
client_id: params.client_id,
|
|
104
|
+
redirect_uri: params.redirect_uri,
|
|
105
|
+
user_id: userId,
|
|
106
|
+
scopes: JSON.stringify(scopes),
|
|
107
|
+
code_challenge: params.code_challenge,
|
|
108
|
+
code_challenge_method: params.code_challenge_method,
|
|
109
|
+
resource: params.resource ?? null,
|
|
110
|
+
expires_at: expiresAt(AUTH_CODE_TTL_SECONDS)
|
|
111
|
+
}).execute();
|
|
112
|
+
const redirectUrl = new URL(params.redirect_uri);
|
|
113
|
+
redirectUrl.searchParams.set("code", code);
|
|
114
|
+
if (params.state) redirectUrl.searchParams.set("state", params.state);
|
|
115
|
+
return {
|
|
116
|
+
success: true,
|
|
117
|
+
data: { redirect_url: redirectUrl.toString() }
|
|
118
|
+
};
|
|
119
|
+
} catch (error) {
|
|
120
|
+
console.error("Authorization error:", error);
|
|
121
|
+
return {
|
|
122
|
+
success: false,
|
|
123
|
+
error: {
|
|
124
|
+
code: "AUTHORIZATION_ERROR",
|
|
125
|
+
message: "Failed to process authorization"
|
|
126
|
+
}
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Exchange an authorization code for access + refresh tokens.
|
|
132
|
+
*
|
|
133
|
+
* Validates the code, verifies PKCE, and issues tokens using the same
|
|
134
|
+
* infrastructure as the device flow (ec_oat_*, ec_ort_*).
|
|
135
|
+
*/
|
|
136
|
+
async function handleAuthorizationCodeExchange(db, params) {
|
|
137
|
+
try {
|
|
138
|
+
if (params.grant_type !== "authorization_code") return {
|
|
139
|
+
success: false,
|
|
140
|
+
error: {
|
|
141
|
+
code: "unsupported_grant_type",
|
|
142
|
+
message: "Invalid grant_type"
|
|
143
|
+
}
|
|
144
|
+
};
|
|
145
|
+
const codeHash = hashApiToken(params.code);
|
|
146
|
+
const row = await db.deleteFrom("_emdash_authorization_codes").where("code_hash", "=", codeHash).returningAll().executeTakeFirst();
|
|
147
|
+
if (!row) return {
|
|
148
|
+
success: false,
|
|
149
|
+
error: {
|
|
150
|
+
code: "invalid_grant",
|
|
151
|
+
message: "Invalid authorization code"
|
|
152
|
+
}
|
|
153
|
+
};
|
|
154
|
+
if (new Date(row.expires_at) < /* @__PURE__ */ new Date()) return {
|
|
155
|
+
success: false,
|
|
156
|
+
error: {
|
|
157
|
+
code: "invalid_grant",
|
|
158
|
+
message: "Authorization code expired"
|
|
159
|
+
}
|
|
160
|
+
};
|
|
161
|
+
if (row.redirect_uri !== params.redirect_uri) return {
|
|
162
|
+
success: false,
|
|
163
|
+
error: {
|
|
164
|
+
code: "invalid_grant",
|
|
165
|
+
message: "redirect_uri mismatch"
|
|
166
|
+
}
|
|
167
|
+
};
|
|
168
|
+
if (row.client_id !== params.client_id) return {
|
|
169
|
+
success: false,
|
|
170
|
+
error: {
|
|
171
|
+
code: "invalid_grant",
|
|
172
|
+
message: "client_id mismatch"
|
|
173
|
+
}
|
|
174
|
+
};
|
|
175
|
+
if (!secureCompare(computeS256Challenge(params.code_verifier), row.code_challenge)) return {
|
|
176
|
+
success: false,
|
|
177
|
+
error: {
|
|
178
|
+
code: "invalid_grant",
|
|
179
|
+
message: "PKCE verification failed"
|
|
180
|
+
}
|
|
181
|
+
};
|
|
182
|
+
if (row.resource && params.resource && row.resource !== params.resource) return {
|
|
183
|
+
success: false,
|
|
184
|
+
error: {
|
|
185
|
+
code: "invalid_grant",
|
|
186
|
+
message: "resource mismatch"
|
|
187
|
+
}
|
|
188
|
+
};
|
|
189
|
+
const userInfo = await lookupUserRoleAndStatus(db, row.user_id);
|
|
190
|
+
if (!userInfo) return {
|
|
191
|
+
success: false,
|
|
192
|
+
error: {
|
|
193
|
+
code: "invalid_grant",
|
|
194
|
+
message: "User not found"
|
|
195
|
+
}
|
|
196
|
+
};
|
|
197
|
+
if (userInfo.disabled) return {
|
|
198
|
+
success: false,
|
|
199
|
+
error: {
|
|
200
|
+
code: "invalid_grant",
|
|
201
|
+
message: "User account is disabled"
|
|
202
|
+
}
|
|
203
|
+
};
|
|
204
|
+
let scopes = clampScopes(JSON.parse(row.scopes), userInfo.role);
|
|
205
|
+
const client = await lookupOAuthClient(db, row.client_id);
|
|
206
|
+
if (client?.scopes?.length) scopes = scopes.filter((s) => client.scopes.includes(s));
|
|
207
|
+
if (scopes.length === 0) return {
|
|
208
|
+
success: false,
|
|
209
|
+
error: {
|
|
210
|
+
code: "invalid_grant",
|
|
211
|
+
message: "User role no longer supports any of the requested scopes"
|
|
212
|
+
}
|
|
213
|
+
};
|
|
214
|
+
const accessToken = generatePrefixedToken(TOKEN_PREFIXES.OAUTH_ACCESS);
|
|
215
|
+
const accessExpires = expiresAt(ACCESS_TOKEN_TTL_SECONDS);
|
|
216
|
+
const refreshToken = generatePrefixedToken(TOKEN_PREFIXES.OAUTH_REFRESH);
|
|
217
|
+
const refreshExpires = expiresAt(REFRESH_TOKEN_TTL_SECONDS);
|
|
218
|
+
await withTransaction(db, async (trx) => {
|
|
219
|
+
await trx.insertInto("_emdash_oauth_tokens").values({
|
|
220
|
+
token_hash: accessToken.hash,
|
|
221
|
+
token_type: "access",
|
|
222
|
+
user_id: row.user_id,
|
|
223
|
+
scopes: JSON.stringify(scopes),
|
|
224
|
+
client_type: "mcp",
|
|
225
|
+
expires_at: accessExpires,
|
|
226
|
+
refresh_token_hash: refreshToken.hash,
|
|
227
|
+
client_id: row.client_id
|
|
228
|
+
}).execute();
|
|
229
|
+
await trx.insertInto("_emdash_oauth_tokens").values({
|
|
230
|
+
token_hash: refreshToken.hash,
|
|
231
|
+
token_type: "refresh",
|
|
232
|
+
user_id: row.user_id,
|
|
233
|
+
scopes: JSON.stringify(scopes),
|
|
234
|
+
client_type: "mcp",
|
|
235
|
+
expires_at: refreshExpires,
|
|
236
|
+
refresh_token_hash: null,
|
|
237
|
+
client_id: row.client_id
|
|
238
|
+
}).execute();
|
|
239
|
+
});
|
|
240
|
+
return {
|
|
241
|
+
success: true,
|
|
242
|
+
data: {
|
|
243
|
+
access_token: accessToken.raw,
|
|
244
|
+
refresh_token: refreshToken.raw,
|
|
245
|
+
token_type: "Bearer",
|
|
246
|
+
expires_in: ACCESS_TOKEN_TTL_SECONDS,
|
|
247
|
+
scope: scopes.join(" ")
|
|
248
|
+
}
|
|
249
|
+
};
|
|
250
|
+
} catch (error) {
|
|
251
|
+
console.error("Token exchange error:", error);
|
|
252
|
+
return {
|
|
253
|
+
success: false,
|
|
254
|
+
error: {
|
|
255
|
+
code: "TOKEN_EXCHANGE_ERROR",
|
|
256
|
+
message: "Failed to exchange authorization code"
|
|
257
|
+
}
|
|
258
|
+
};
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
/**
|
|
262
|
+
* Build the authorization denied redirect URL.
|
|
263
|
+
*/
|
|
264
|
+
function buildDeniedRedirect(redirectUri, state) {
|
|
265
|
+
const url = new URL(redirectUri);
|
|
266
|
+
url.searchParams.set("error", "access_denied");
|
|
267
|
+
url.searchParams.set("error_description", "The user denied the authorization request");
|
|
268
|
+
if (state) url.searchParams.set("state", state);
|
|
269
|
+
return url.toString();
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
//#endregion
|
|
273
|
+
export { handleAuthorizationApproval as n, handleAuthorizationCodeExchange as r, buildDeniedRedirect as t };
|
|
274
|
+
//# sourceMappingURL=oauth-authorization-DAXsH1H9.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"oauth-authorization-DAXsH1H9.mjs","names":[],"sources":["../src/api/handlers/oauth-authorization.ts"],"sourcesContent":["/**\n * OAuth 2.1 Authorization Code + PKCE handlers.\n *\n * Implements the server side of the authorization code grant for MCP clients\n * (Claude Desktop, VS Code, etc.) per the MCP authorization spec (draft).\n *\n * Uses arctic for PKCE challenge generation and @emdash-cms/auth for token\n * utilities. Token infrastructure is shared with the device flow.\n */\n\nimport { clampScopes, computeS256Challenge, secureCompare } from \"@emdash-cms/auth\";\nimport type { RoleLevel } from \"@emdash-cms/auth\";\nimport { generateCodeVerifier } from \"arctic\";\nimport type { Kysely } from \"kysely\";\n\nimport {\n\tgeneratePrefixedToken,\n\thashApiToken,\n\tisValidScope,\n\tTOKEN_PREFIXES,\n} from \"../../auth/api-tokens.js\";\nimport { withTransaction } from \"../../database/transaction.js\";\nimport type { Database } from \"../../database/types.js\";\nimport { validateRedirectUri } from \"../oauth/redirect-uri.js\";\nimport type { ApiResult } from \"../types.js\";\nimport { lookupOAuthClient, validateClientRedirectUri } from \"./oauth-clients.js\";\nimport { lookupUserRoleAndStatus } from \"./oauth-user-lookup.js\";\n\n// ---------------------------------------------------------------------------\n// Constants\n// ---------------------------------------------------------------------------\n\n/** Authorization codes expire after 10 minutes (RFC 6749 §4.1.2 recommends short-lived) */\nconst AUTH_CODE_TTL_SECONDS = 10 * 60;\n\n/** Access token TTL: 1 hour */\nconst ACCESS_TOKEN_TTL_SECONDS = 60 * 60;\n\n/** Refresh token TTL: 90 days */\nconst REFRESH_TOKEN_TTL_SECONDS = 90 * 24 * 60 * 60;\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport interface AuthorizationParams {\n\tresponse_type: string;\n\tclient_id: string;\n\tredirect_uri: string;\n\tscope?: string;\n\tstate?: string;\n\tcode_challenge: string;\n\tcode_challenge_method: string;\n\tresource?: string;\n}\n\nexport interface TokenExchangeParams {\n\tgrant_type: string;\n\tcode: string;\n\tredirect_uri: string;\n\tclient_id: string;\n\tcode_verifier: string;\n\tresource?: string;\n}\n\nexport interface TokenResponse {\n\taccess_token: string;\n\trefresh_token: string;\n\ttoken_type: \"Bearer\";\n\texpires_in: number;\n\tscope: string;\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nfunction expiresAt(seconds: number): string {\n\treturn new Date(Date.now() + seconds * 1000).toISOString();\n}\n\nexport { validateRedirectUri };\n\n/**\n * Validate and normalize scopes. Returns validated scope list.\n */\nfunction normalizeScopes(requested?: string): string[] {\n\tif (!requested) return [];\n\n\tconst scopes = requested.split(\" \").filter(Boolean).filter(isValidScope);\n\n\treturn scopes;\n}\n\n// ---------------------------------------------------------------------------\n// Handlers\n// ---------------------------------------------------------------------------\n\n/**\n * Process an authorization request after the user approves consent.\n *\n * Generates an authorization code, stores it with the PKCE challenge,\n * and returns the redirect URL with the code appended.\n *\n * Scopes are clamped to the user's role to prevent scope escalation.\n */\nexport async function handleAuthorizationApproval(\n\tdb: Kysely<Database>,\n\tuserId: string,\n\tuserRole: RoleLevel,\n\tparams: AuthorizationParams,\n): Promise<ApiResult<{ redirect_url: string }>> {\n\ttry {\n\t\t// Validate response_type\n\t\tif (params.response_type !== \"code\") {\n\t\t\treturn {\n\t\t\t\tsuccess: false,\n\t\t\t\terror: {\n\t\t\t\t\tcode: \"UNSUPPORTED_RESPONSE_TYPE\",\n\t\t\t\t\tmessage: \"Only response_type=code is supported\",\n\t\t\t\t},\n\t\t\t};\n\t\t}\n\n\t\t// Validate redirect_uri scheme/host (basic security check)\n\t\tconst uriError = validateRedirectUri(params.redirect_uri);\n\t\tif (uriError) {\n\t\t\treturn {\n\t\t\t\tsuccess: false,\n\t\t\t\terror: { code: \"INVALID_REDIRECT_URI\", message: uriError },\n\t\t\t};\n\t\t}\n\n\t\t// Look up the registered OAuth client\n\t\tconst client = await lookupOAuthClient(db, params.client_id);\n\t\tif (!client) {\n\t\t\treturn {\n\t\t\t\tsuccess: false,\n\t\t\t\terror: {\n\t\t\t\t\tcode: \"INVALID_CLIENT\",\n\t\t\t\t\tmessage: \"Unknown client_id\",\n\t\t\t\t},\n\t\t\t};\n\t\t}\n\n\t\t// Validate redirect_uri against client's registered URIs\n\t\tconst clientUriError = validateClientRedirectUri(params.redirect_uri, client.redirectUris);\n\t\tif (clientUriError) {\n\t\t\treturn {\n\t\t\t\tsuccess: false,\n\t\t\t\terror: { code: \"INVALID_REDIRECT_URI\", message: clientUriError },\n\t\t\t};\n\t\t}\n\n\t\t// Validate code_challenge_method\n\t\tif (params.code_challenge_method !== \"S256\") {\n\t\t\treturn {\n\t\t\t\tsuccess: false,\n\t\t\t\terror: {\n\t\t\t\t\tcode: \"INVALID_REQUEST\",\n\t\t\t\t\tmessage: \"Only S256 code_challenge_method is supported\",\n\t\t\t\t},\n\t\t\t};\n\t\t}\n\n\t\t// Validate code_challenge is present\n\t\tif (!params.code_challenge) {\n\t\t\treturn {\n\t\t\t\tsuccess: false,\n\t\t\t\terror: { code: \"INVALID_REQUEST\", message: \"code_challenge is required\" },\n\t\t\t};\n\t\t}\n\n\t\t// Validate scopes, then clamp to user's role\n\t\tconst userScopes = clampScopes(normalizeScopes(params.scope), userRole);\n\n\t\t// SEC-41: Intersect with client's registered scopes (if restricted).\n\t\t// A client registered with scopes: [\"content:read\"] should never receive\n\t\t// admin or schema:write, regardless of the approving user's role.\n\t\tconst clientScopes = client.scopes;\n\t\tconst scopes = clientScopes?.length\n\t\t\t? userScopes.filter((s: string) => clientScopes.includes(s))\n\t\t\t: userScopes;\n\n\t\tif (scopes.length === 0) {\n\t\t\treturn {\n\t\t\t\tsuccess: false,\n\t\t\t\terror: { code: \"INVALID_SCOPE\", message: \"No valid scopes requested\" },\n\t\t\t};\n\t\t}\n\n\t\t// Generate authorization code (high entropy, base64url)\n\t\tconst code = generateCodeVerifier(); // 32 bytes random, base64url\n\t\tconst codeHash = hashApiToken(code);\n\n\t\t// Store the authorization code\n\t\tawait db\n\t\t\t.insertInto(\"_emdash_authorization_codes\")\n\t\t\t.values({\n\t\t\t\tcode_hash: codeHash,\n\t\t\t\tclient_id: params.client_id,\n\t\t\t\tredirect_uri: params.redirect_uri,\n\t\t\t\tuser_id: userId,\n\t\t\t\tscopes: JSON.stringify(scopes),\n\t\t\t\tcode_challenge: params.code_challenge,\n\t\t\t\tcode_challenge_method: params.code_challenge_method,\n\t\t\t\tresource: params.resource ?? null,\n\t\t\t\texpires_at: expiresAt(AUTH_CODE_TTL_SECONDS),\n\t\t\t})\n\t\t\t.execute();\n\n\t\t// Build the redirect URL\n\t\tconst redirectUrl = new URL(params.redirect_uri);\n\t\tredirectUrl.searchParams.set(\"code\", code);\n\t\tif (params.state) {\n\t\t\tredirectUrl.searchParams.set(\"state\", params.state);\n\t\t}\n\n\t\treturn {\n\t\t\tsuccess: true,\n\t\t\tdata: { redirect_url: redirectUrl.toString() },\n\t\t};\n\t} catch (error) {\n\t\tconsole.error(\"Authorization error:\", error);\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\terror: {\n\t\t\t\tcode: \"AUTHORIZATION_ERROR\",\n\t\t\t\tmessage: \"Failed to process authorization\",\n\t\t\t},\n\t\t};\n\t}\n}\n\n/**\n * Exchange an authorization code for access + refresh tokens.\n *\n * Validates the code, verifies PKCE, and issues tokens using the same\n * infrastructure as the device flow (ec_oat_*, ec_ort_*).\n */\nexport async function handleAuthorizationCodeExchange(\n\tdb: Kysely<Database>,\n\tparams: TokenExchangeParams,\n): Promise<ApiResult<TokenResponse>> {\n\ttry {\n\t\t// Validate grant_type\n\t\tif (params.grant_type !== \"authorization_code\") {\n\t\t\treturn {\n\t\t\t\tsuccess: false,\n\t\t\t\terror: { code: \"unsupported_grant_type\", message: \"Invalid grant_type\" },\n\t\t\t};\n\t\t}\n\n\t\t// SEC-39: Atomically consume the authorization code using DELETE...RETURNING.\n\t\t// This prevents TOCTOU double-exchange: two concurrent requests with the\n\t\t// same code will race on the DELETE, and only one will get a row back.\n\t\tconst codeHash = hashApiToken(params.code);\n\n\t\tconst row = await db\n\t\t\t.deleteFrom(\"_emdash_authorization_codes\")\n\t\t\t.where(\"code_hash\", \"=\", codeHash)\n\t\t\t.returningAll()\n\t\t\t.executeTakeFirst();\n\n\t\tif (!row) {\n\t\t\treturn {\n\t\t\t\tsuccess: false,\n\t\t\t\terror: { code: \"invalid_grant\", message: \"Invalid authorization code\" },\n\t\t\t};\n\t\t}\n\n\t\t// Check expiry\n\t\tif (new Date(row.expires_at) < new Date()) {\n\t\t\treturn {\n\t\t\t\tsuccess: false,\n\t\t\t\terror: { code: \"invalid_grant\", message: \"Authorization code expired\" },\n\t\t\t};\n\t\t}\n\n\t\t// Verify redirect_uri matches exactly\n\t\tif (row.redirect_uri !== params.redirect_uri) {\n\t\t\treturn {\n\t\t\t\tsuccess: false,\n\t\t\t\terror: { code: \"invalid_grant\", message: \"redirect_uri mismatch\" },\n\t\t\t};\n\t\t}\n\n\t\t// Verify client_id matches\n\t\tif (row.client_id !== params.client_id) {\n\t\t\treturn {\n\t\t\t\tsuccess: false,\n\t\t\t\terror: { code: \"invalid_grant\", message: \"client_id mismatch\" },\n\t\t\t};\n\t\t}\n\n\t\t// PKCE verification: SHA256(code_verifier) must match stored code_challenge\n\t\t// Use constant-time comparison to prevent timing side-channels\n\t\tconst derivedChallenge = computeS256Challenge(params.code_verifier);\n\t\tif (!secureCompare(derivedChallenge, row.code_challenge)) {\n\t\t\treturn {\n\t\t\t\tsuccess: false,\n\t\t\t\terror: { code: \"invalid_grant\", message: \"PKCE verification failed\" },\n\t\t\t};\n\t\t}\n\n\t\t// Verify resource matches (if stored)\n\t\tif (row.resource && params.resource && row.resource !== params.resource) {\n\t\t\treturn {\n\t\t\t\tsuccess: false,\n\t\t\t\terror: { code: \"invalid_grant\", message: \"resource mismatch\" },\n\t\t\t};\n\t\t}\n\n\t\t// Revalidate user role before issuing tokens (same pattern as handleTokenRefresh).\n\t\t// The user's role may have changed since the authorization code was issued.\n\t\tconst userInfo = await lookupUserRoleAndStatus(db, row.user_id);\n\t\tif (!userInfo) {\n\t\t\treturn {\n\t\t\t\tsuccess: false,\n\t\t\t\terror: { code: \"invalid_grant\", message: \"User not found\" },\n\t\t\t};\n\t\t}\n\n\t\tif (userInfo.disabled) {\n\t\t\treturn {\n\t\t\t\tsuccess: false,\n\t\t\t\terror: { code: \"invalid_grant\", message: \"User account is disabled\" },\n\t\t\t};\n\t\t}\n\n\t\t// Re-clamp scopes against the user's current role\n\t\tconst storedScopes = JSON.parse(row.scopes) as string[];\n\t\tlet scopes = clampScopes(storedScopes, userInfo.role);\n\n\t\t// Intersect with client's registered scopes (if restricted)\n\t\tconst client = await lookupOAuthClient(db, row.client_id);\n\t\tif (client?.scopes?.length) {\n\t\t\tscopes = scopes.filter((s: string) => client.scopes!.includes(s));\n\t\t}\n\n\t\tif (scopes.length === 0) {\n\t\t\treturn {\n\t\t\t\tsuccess: false,\n\t\t\t\terror: {\n\t\t\t\t\tcode: \"invalid_grant\",\n\t\t\t\t\tmessage: \"User role no longer supports any of the requested scopes\",\n\t\t\t\t},\n\t\t\t};\n\t\t}\n\n\t\t// Issue tokens (same as device flow)\n\t\tconst accessToken = generatePrefixedToken(TOKEN_PREFIXES.OAUTH_ACCESS);\n\t\tconst accessExpires = expiresAt(ACCESS_TOKEN_TTL_SECONDS);\n\n\t\tconst refreshToken = generatePrefixedToken(TOKEN_PREFIXES.OAUTH_REFRESH);\n\t\tconst refreshExpires = expiresAt(REFRESH_TOKEN_TTL_SECONDS);\n\n\t\t// Atomically store both tokens in a transaction\n\t\tawait withTransaction(db, async (trx) => {\n\t\t\tawait trx\n\t\t\t\t.insertInto(\"_emdash_oauth_tokens\")\n\t\t\t\t.values({\n\t\t\t\t\ttoken_hash: accessToken.hash,\n\t\t\t\t\ttoken_type: \"access\",\n\t\t\t\t\tuser_id: row.user_id,\n\t\t\t\t\tscopes: JSON.stringify(scopes),\n\t\t\t\t\tclient_type: \"mcp\",\n\t\t\t\t\texpires_at: accessExpires,\n\t\t\t\t\trefresh_token_hash: refreshToken.hash,\n\t\t\t\t\tclient_id: row.client_id,\n\t\t\t\t})\n\t\t\t\t.execute();\n\n\t\t\tawait trx\n\t\t\t\t.insertInto(\"_emdash_oauth_tokens\")\n\t\t\t\t.values({\n\t\t\t\t\ttoken_hash: refreshToken.hash,\n\t\t\t\t\ttoken_type: \"refresh\",\n\t\t\t\t\tuser_id: row.user_id,\n\t\t\t\t\tscopes: JSON.stringify(scopes),\n\t\t\t\t\tclient_type: \"mcp\",\n\t\t\t\t\texpires_at: refreshExpires,\n\t\t\t\t\trefresh_token_hash: null,\n\t\t\t\t\tclient_id: row.client_id,\n\t\t\t\t})\n\t\t\t\t.execute();\n\t\t});\n\n\t\treturn {\n\t\t\tsuccess: true,\n\t\t\tdata: {\n\t\t\t\taccess_token: accessToken.raw,\n\t\t\t\trefresh_token: refreshToken.raw,\n\t\t\t\ttoken_type: \"Bearer\",\n\t\t\t\texpires_in: ACCESS_TOKEN_TTL_SECONDS,\n\t\t\t\tscope: scopes.join(\" \"),\n\t\t\t},\n\t\t};\n\t} catch (error) {\n\t\tconsole.error(\"Token exchange error:\", error);\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\terror: {\n\t\t\t\tcode: \"TOKEN_EXCHANGE_ERROR\",\n\t\t\t\tmessage: \"Failed to exchange authorization code\",\n\t\t\t},\n\t\t};\n\t}\n}\n\n/**\n * Build the authorization denied redirect URL.\n */\nexport function buildDeniedRedirect(redirectUri: string, state?: string): string {\n\tconst url = new URL(redirectUri);\n\turl.searchParams.set(\"error\", \"access_denied\");\n\turl.searchParams.set(\"error_description\", \"The user denied the authorization request\");\n\tif (state) {\n\t\turl.searchParams.set(\"state\", state);\n\t}\n\treturn url.toString();\n}\n\n/**\n * Clean up expired authorization codes.\n */\nexport async function cleanupExpiredAuthorizationCodes(db: Kysely<Database>): Promise<number> {\n\tconst result = await db\n\t\t.deleteFrom(\"_emdash_authorization_codes\")\n\t\t.where(\"expires_at\", \"<\", new Date().toISOString())\n\t\t.executeTakeFirst();\n\n\treturn Number(result.numDeletedRows);\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAiCA,MAAM,wBAAwB;;AAG9B,MAAM,2BAA2B;;AAGjC,MAAM,4BAA4B,OAAU,KAAK;AAsCjD,SAAS,UAAU,SAAyB;AAC3C,QAAO,IAAI,KAAK,KAAK,KAAK,GAAG,UAAU,IAAK,CAAC,aAAa;;;;;AAQ3D,SAAS,gBAAgB,WAA8B;AACtD,KAAI,CAAC,UAAW,QAAO,EAAE;AAIzB,QAFe,UAAU,MAAM,IAAI,CAAC,OAAO,QAAQ,CAAC,OAAO,aAAa;;;;;;;;;;AAiBzE,eAAsB,4BACrB,IACA,QACA,UACA,QAC+C;AAC/C,KAAI;AAEH,MAAI,OAAO,kBAAkB,OAC5B,QAAO;GACN,SAAS;GACT,OAAO;IACN,MAAM;IACN,SAAS;IACT;GACD;EAIF,MAAM,WAAW,oBAAoB,OAAO,aAAa;AACzD,MAAI,SACH,QAAO;GACN,SAAS;GACT,OAAO;IAAE,MAAM;IAAwB,SAAS;IAAU;GAC1D;EAIF,MAAM,SAAS,MAAM,kBAAkB,IAAI,OAAO,UAAU;AAC5D,MAAI,CAAC,OACJ,QAAO;GACN,SAAS;GACT,OAAO;IACN,MAAM;IACN,SAAS;IACT;GACD;EAIF,MAAM,iBAAiB,0BAA0B,OAAO,cAAc,OAAO,aAAa;AAC1F,MAAI,eACH,QAAO;GACN,SAAS;GACT,OAAO;IAAE,MAAM;IAAwB,SAAS;IAAgB;GAChE;AAIF,MAAI,OAAO,0BAA0B,OACpC,QAAO;GACN,SAAS;GACT,OAAO;IACN,MAAM;IACN,SAAS;IACT;GACD;AAIF,MAAI,CAAC,OAAO,eACX,QAAO;GACN,SAAS;GACT,OAAO;IAAE,MAAM;IAAmB,SAAS;IAA8B;GACzE;EAIF,MAAM,aAAa,YAAY,gBAAgB,OAAO,MAAM,EAAE,SAAS;EAKvE,MAAM,eAAe,OAAO;EAC5B,MAAM,SAAS,cAAc,SAC1B,WAAW,QAAQ,MAAc,aAAa,SAAS,EAAE,CAAC,GAC1D;AAEH,MAAI,OAAO,WAAW,EACrB,QAAO;GACN,SAAS;GACT,OAAO;IAAE,MAAM;IAAiB,SAAS;IAA6B;GACtE;EAIF,MAAM,OAAO,sBAAsB;EACnC,MAAM,WAAW,aAAa,KAAK;AAGnC,QAAM,GACJ,WAAW,8BAA8B,CACzC,OAAO;GACP,WAAW;GACX,WAAW,OAAO;GAClB,cAAc,OAAO;GACrB,SAAS;GACT,QAAQ,KAAK,UAAU,OAAO;GAC9B,gBAAgB,OAAO;GACvB,uBAAuB,OAAO;GAC9B,UAAU,OAAO,YAAY;GAC7B,YAAY,UAAU,sBAAsB;GAC5C,CAAC,CACD,SAAS;EAGX,MAAM,cAAc,IAAI,IAAI,OAAO,aAAa;AAChD,cAAY,aAAa,IAAI,QAAQ,KAAK;AAC1C,MAAI,OAAO,MACV,aAAY,aAAa,IAAI,SAAS,OAAO,MAAM;AAGpD,SAAO;GACN,SAAS;GACT,MAAM,EAAE,cAAc,YAAY,UAAU,EAAE;GAC9C;UACO,OAAO;AACf,UAAQ,MAAM,wBAAwB,MAAM;AAC5C,SAAO;GACN,SAAS;GACT,OAAO;IACN,MAAM;IACN,SAAS;IACT;GACD;;;;;;;;;AAUH,eAAsB,gCACrB,IACA,QACoC;AACpC,KAAI;AAEH,MAAI,OAAO,eAAe,qBACzB,QAAO;GACN,SAAS;GACT,OAAO;IAAE,MAAM;IAA0B,SAAS;IAAsB;GACxE;EAMF,MAAM,WAAW,aAAa,OAAO,KAAK;EAE1C,MAAM,MAAM,MAAM,GAChB,WAAW,8BAA8B,CACzC,MAAM,aAAa,KAAK,SAAS,CACjC,cAAc,CACd,kBAAkB;AAEpB,MAAI,CAAC,IACJ,QAAO;GACN,SAAS;GACT,OAAO;IAAE,MAAM;IAAiB,SAAS;IAA8B;GACvE;AAIF,MAAI,IAAI,KAAK,IAAI,WAAW,mBAAG,IAAI,MAAM,CACxC,QAAO;GACN,SAAS;GACT,OAAO;IAAE,MAAM;IAAiB,SAAS;IAA8B;GACvE;AAIF,MAAI,IAAI,iBAAiB,OAAO,aAC/B,QAAO;GACN,SAAS;GACT,OAAO;IAAE,MAAM;IAAiB,SAAS;IAAyB;GAClE;AAIF,MAAI,IAAI,cAAc,OAAO,UAC5B,QAAO;GACN,SAAS;GACT,OAAO;IAAE,MAAM;IAAiB,SAAS;IAAsB;GAC/D;AAMF,MAAI,CAAC,cADoB,qBAAqB,OAAO,cAAc,EAC9B,IAAI,eAAe,CACvD,QAAO;GACN,SAAS;GACT,OAAO;IAAE,MAAM;IAAiB,SAAS;IAA4B;GACrE;AAIF,MAAI,IAAI,YAAY,OAAO,YAAY,IAAI,aAAa,OAAO,SAC9D,QAAO;GACN,SAAS;GACT,OAAO;IAAE,MAAM;IAAiB,SAAS;IAAqB;GAC9D;EAKF,MAAM,WAAW,MAAM,wBAAwB,IAAI,IAAI,QAAQ;AAC/D,MAAI,CAAC,SACJ,QAAO;GACN,SAAS;GACT,OAAO;IAAE,MAAM;IAAiB,SAAS;IAAkB;GAC3D;AAGF,MAAI,SAAS,SACZ,QAAO;GACN,SAAS;GACT,OAAO;IAAE,MAAM;IAAiB,SAAS;IAA4B;GACrE;EAKF,IAAI,SAAS,YADQ,KAAK,MAAM,IAAI,OAAO,EACJ,SAAS,KAAK;EAGrD,MAAM,SAAS,MAAM,kBAAkB,IAAI,IAAI,UAAU;AACzD,MAAI,QAAQ,QAAQ,OACnB,UAAS,OAAO,QAAQ,MAAc,OAAO,OAAQ,SAAS,EAAE,CAAC;AAGlE,MAAI,OAAO,WAAW,EACrB,QAAO;GACN,SAAS;GACT,OAAO;IACN,MAAM;IACN,SAAS;IACT;GACD;EAIF,MAAM,cAAc,sBAAsB,eAAe,aAAa;EACtE,MAAM,gBAAgB,UAAU,yBAAyB;EAEzD,MAAM,eAAe,sBAAsB,eAAe,cAAc;EACxE,MAAM,iBAAiB,UAAU,0BAA0B;AAG3D,QAAM,gBAAgB,IAAI,OAAO,QAAQ;AACxC,SAAM,IACJ,WAAW,uBAAuB,CAClC,OAAO;IACP,YAAY,YAAY;IACxB,YAAY;IACZ,SAAS,IAAI;IACb,QAAQ,KAAK,UAAU,OAAO;IAC9B,aAAa;IACb,YAAY;IACZ,oBAAoB,aAAa;IACjC,WAAW,IAAI;IACf,CAAC,CACD,SAAS;AAEX,SAAM,IACJ,WAAW,uBAAuB,CAClC,OAAO;IACP,YAAY,aAAa;IACzB,YAAY;IACZ,SAAS,IAAI;IACb,QAAQ,KAAK,UAAU,OAAO;IAC9B,aAAa;IACb,YAAY;IACZ,oBAAoB;IACpB,WAAW,IAAI;IACf,CAAC,CACD,SAAS;IACV;AAEF,SAAO;GACN,SAAS;GACT,MAAM;IACL,cAAc,YAAY;IAC1B,eAAe,aAAa;IAC5B,YAAY;IACZ,YAAY;IACZ,OAAO,OAAO,KAAK,IAAI;IACvB;GACD;UACO,OAAO;AACf,UAAQ,MAAM,yBAAyB,MAAM;AAC7C,SAAO;GACN,SAAS;GACT,OAAO;IACN,MAAM;IACN,SAAS;IACT;GACD;;;;;;AAOH,SAAgB,oBAAoB,aAAqB,OAAwB;CAChF,MAAM,MAAM,IAAI,IAAI,YAAY;AAChC,KAAI,aAAa,IAAI,SAAS,gBAAgB;AAC9C,KAAI,aAAa,IAAI,qBAAqB,4CAA4C;AACtF,KAAI,MACH,KAAI,aAAa,IAAI,SAAS,MAAM;AAErC,QAAO,IAAI,UAAU"}
|
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
//#region src/api/oauth/redirect-uri.ts
|
|
2
|
+
/**
|
|
3
|
+
* Validate a redirect URI per OAuth 2.1 security requirements.
|
|
4
|
+
*
|
|
5
|
+
* Allows localhost / loopback redirect URIs over HTTP for native clients,
|
|
6
|
+
* and any HTTPS URL for web-based flows.
|
|
7
|
+
*/
|
|
8
|
+
function validateRedirectUri(uri) {
|
|
9
|
+
try {
|
|
10
|
+
const url = new URL(uri);
|
|
11
|
+
if (uri.startsWith("//")) return "Protocol-relative redirect URIs are not allowed";
|
|
12
|
+
if (url.protocol === "http:") {
|
|
13
|
+
const host = url.hostname;
|
|
14
|
+
if (host === "127.0.0.1" || host === "localhost" || host === "[::1]") return null;
|
|
15
|
+
return "HTTP redirect URIs are only allowed for localhost";
|
|
16
|
+
}
|
|
17
|
+
if (url.protocol === "https:") return null;
|
|
18
|
+
return `Unsupported redirect URI scheme: ${url.protocol}`;
|
|
19
|
+
} catch {
|
|
20
|
+
return "Invalid redirect URI";
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
//#endregion
|
|
25
|
+
//#region src/api/handlers/oauth-clients.ts
|
|
26
|
+
/** Parse a JSON string column into a typed value. */
|
|
27
|
+
function parseJsonColumn(value) {
|
|
28
|
+
return JSON.parse(value);
|
|
29
|
+
}
|
|
30
|
+
function validateRegisteredRedirectUris(redirectUris) {
|
|
31
|
+
for (const redirectUri of redirectUris) {
|
|
32
|
+
const error = validateRedirectUri(redirectUri);
|
|
33
|
+
if (error) return `Invalid redirect URI: ${error}`;
|
|
34
|
+
}
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Create a new OAuth client.
|
|
39
|
+
*/
|
|
40
|
+
async function handleOAuthClientCreate(db, input) {
|
|
41
|
+
try {
|
|
42
|
+
if (input.redirectUris.length === 0) return {
|
|
43
|
+
success: false,
|
|
44
|
+
error: {
|
|
45
|
+
code: "VALIDATION_ERROR",
|
|
46
|
+
message: "At least one redirect URI is required"
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
const redirectUriError = validateRegisteredRedirectUris(input.redirectUris);
|
|
50
|
+
if (redirectUriError) return {
|
|
51
|
+
success: false,
|
|
52
|
+
error: {
|
|
53
|
+
code: "VALIDATION_ERROR",
|
|
54
|
+
message: redirectUriError
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
if (await db.selectFrom("_emdash_oauth_clients").select("id").where("id", "=", input.id).executeTakeFirst()) return {
|
|
58
|
+
success: false,
|
|
59
|
+
error: {
|
|
60
|
+
code: "CONFLICT",
|
|
61
|
+
message: "OAuth client with this ID already exists"
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
65
|
+
await db.insertInto("_emdash_oauth_clients").values({
|
|
66
|
+
id: input.id,
|
|
67
|
+
name: input.name,
|
|
68
|
+
redirect_uris: JSON.stringify(input.redirectUris),
|
|
69
|
+
scopes: input.scopes && input.scopes.length > 0 ? JSON.stringify(input.scopes) : null
|
|
70
|
+
}).execute();
|
|
71
|
+
return {
|
|
72
|
+
success: true,
|
|
73
|
+
data: {
|
|
74
|
+
id: input.id,
|
|
75
|
+
name: input.name,
|
|
76
|
+
redirectUris: input.redirectUris,
|
|
77
|
+
scopes: input.scopes && input.scopes.length > 0 ? input.scopes : null,
|
|
78
|
+
createdAt: now,
|
|
79
|
+
updatedAt: now
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
} catch {
|
|
83
|
+
return {
|
|
84
|
+
success: false,
|
|
85
|
+
error: {
|
|
86
|
+
code: "CLIENT_CREATE_ERROR",
|
|
87
|
+
message: "Failed to create OAuth client"
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* List all registered OAuth clients.
|
|
94
|
+
*/
|
|
95
|
+
async function handleOAuthClientList(db) {
|
|
96
|
+
try {
|
|
97
|
+
return {
|
|
98
|
+
success: true,
|
|
99
|
+
data: { items: (await db.selectFrom("_emdash_oauth_clients").selectAll().orderBy("created_at", "desc").execute()).map((row) => ({
|
|
100
|
+
id: row.id,
|
|
101
|
+
name: row.name,
|
|
102
|
+
redirectUris: parseJsonColumn(row.redirect_uris),
|
|
103
|
+
scopes: row.scopes ? parseJsonColumn(row.scopes) : null,
|
|
104
|
+
createdAt: row.created_at,
|
|
105
|
+
updatedAt: row.updated_at
|
|
106
|
+
})) }
|
|
107
|
+
};
|
|
108
|
+
} catch {
|
|
109
|
+
return {
|
|
110
|
+
success: false,
|
|
111
|
+
error: {
|
|
112
|
+
code: "CLIENT_LIST_ERROR",
|
|
113
|
+
message: "Failed to list OAuth clients"
|
|
114
|
+
}
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Get a single OAuth client by ID.
|
|
120
|
+
*/
|
|
121
|
+
async function handleOAuthClientGet(db, clientId) {
|
|
122
|
+
try {
|
|
123
|
+
const row = await db.selectFrom("_emdash_oauth_clients").selectAll().where("id", "=", clientId).executeTakeFirst();
|
|
124
|
+
if (!row) return {
|
|
125
|
+
success: false,
|
|
126
|
+
error: {
|
|
127
|
+
code: "NOT_FOUND",
|
|
128
|
+
message: "OAuth client not found"
|
|
129
|
+
}
|
|
130
|
+
};
|
|
131
|
+
return {
|
|
132
|
+
success: true,
|
|
133
|
+
data: {
|
|
134
|
+
id: row.id,
|
|
135
|
+
name: row.name,
|
|
136
|
+
redirectUris: parseJsonColumn(row.redirect_uris),
|
|
137
|
+
scopes: row.scopes ? parseJsonColumn(row.scopes) : null,
|
|
138
|
+
createdAt: row.created_at,
|
|
139
|
+
updatedAt: row.updated_at
|
|
140
|
+
}
|
|
141
|
+
};
|
|
142
|
+
} catch {
|
|
143
|
+
return {
|
|
144
|
+
success: false,
|
|
145
|
+
error: {
|
|
146
|
+
code: "CLIENT_GET_ERROR",
|
|
147
|
+
message: "Failed to get OAuth client"
|
|
148
|
+
}
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Update an OAuth client.
|
|
154
|
+
*/
|
|
155
|
+
async function handleOAuthClientUpdate(db, clientId, input) {
|
|
156
|
+
try {
|
|
157
|
+
if (!await db.selectFrom("_emdash_oauth_clients").selectAll().where("id", "=", clientId).executeTakeFirst()) return {
|
|
158
|
+
success: false,
|
|
159
|
+
error: {
|
|
160
|
+
code: "NOT_FOUND",
|
|
161
|
+
message: "OAuth client not found"
|
|
162
|
+
}
|
|
163
|
+
};
|
|
164
|
+
if (input.redirectUris !== void 0 && input.redirectUris.length === 0) return {
|
|
165
|
+
success: false,
|
|
166
|
+
error: {
|
|
167
|
+
code: "VALIDATION_ERROR",
|
|
168
|
+
message: "At least one redirect URI is required"
|
|
169
|
+
}
|
|
170
|
+
};
|
|
171
|
+
if (input.redirectUris !== void 0) {
|
|
172
|
+
const redirectUriError = validateRegisteredRedirectUris(input.redirectUris);
|
|
173
|
+
if (redirectUriError) return {
|
|
174
|
+
success: false,
|
|
175
|
+
error: {
|
|
176
|
+
code: "VALIDATION_ERROR",
|
|
177
|
+
message: redirectUriError
|
|
178
|
+
}
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
const updates = { updated_at: (/* @__PURE__ */ new Date()).toISOString() };
|
|
182
|
+
if (input.name !== void 0) updates.name = input.name;
|
|
183
|
+
if (input.redirectUris !== void 0) updates.redirect_uris = JSON.stringify(input.redirectUris);
|
|
184
|
+
if (input.scopes !== void 0) updates.scopes = input.scopes && input.scopes.length > 0 ? JSON.stringify(input.scopes) : null;
|
|
185
|
+
await db.updateTable("_emdash_oauth_clients").set(updates).where("id", "=", clientId).execute();
|
|
186
|
+
const updated = await db.selectFrom("_emdash_oauth_clients").selectAll().where("id", "=", clientId).executeTakeFirst();
|
|
187
|
+
if (!updated) return {
|
|
188
|
+
success: false,
|
|
189
|
+
error: {
|
|
190
|
+
code: "NOT_FOUND",
|
|
191
|
+
message: "OAuth client not found after update"
|
|
192
|
+
}
|
|
193
|
+
};
|
|
194
|
+
return {
|
|
195
|
+
success: true,
|
|
196
|
+
data: {
|
|
197
|
+
id: updated.id,
|
|
198
|
+
name: updated.name,
|
|
199
|
+
redirectUris: parseJsonColumn(updated.redirect_uris),
|
|
200
|
+
scopes: updated.scopes ? parseJsonColumn(updated.scopes) : null,
|
|
201
|
+
createdAt: updated.created_at,
|
|
202
|
+
updatedAt: updated.updated_at
|
|
203
|
+
}
|
|
204
|
+
};
|
|
205
|
+
} catch {
|
|
206
|
+
return {
|
|
207
|
+
success: false,
|
|
208
|
+
error: {
|
|
209
|
+
code: "CLIENT_UPDATE_ERROR",
|
|
210
|
+
message: "Failed to update OAuth client"
|
|
211
|
+
}
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* Delete an OAuth client.
|
|
217
|
+
*/
|
|
218
|
+
async function handleOAuthClientDelete(db, clientId) {
|
|
219
|
+
try {
|
|
220
|
+
if ((await db.deleteFrom("_emdash_oauth_clients").where("id", "=", clientId).executeTakeFirst()).numDeletedRows === 0n) return {
|
|
221
|
+
success: false,
|
|
222
|
+
error: {
|
|
223
|
+
code: "NOT_FOUND",
|
|
224
|
+
message: "OAuth client not found"
|
|
225
|
+
}
|
|
226
|
+
};
|
|
227
|
+
return {
|
|
228
|
+
success: true,
|
|
229
|
+
data: { deleted: true }
|
|
230
|
+
};
|
|
231
|
+
} catch {
|
|
232
|
+
return {
|
|
233
|
+
success: false,
|
|
234
|
+
error: {
|
|
235
|
+
code: "CLIENT_DELETE_ERROR",
|
|
236
|
+
message: "Failed to delete OAuth client"
|
|
237
|
+
}
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
/**
|
|
242
|
+
* Look up a registered OAuth client by ID.
|
|
243
|
+
* Returns the client's redirect URIs or null if the client is not registered.
|
|
244
|
+
*/
|
|
245
|
+
async function lookupOAuthClient(db, clientId) {
|
|
246
|
+
const row = await db.selectFrom("_emdash_oauth_clients").select(["redirect_uris", "scopes"]).where("id", "=", clientId).executeTakeFirst();
|
|
247
|
+
if (!row) return null;
|
|
248
|
+
return {
|
|
249
|
+
redirectUris: parseJsonColumn(row.redirect_uris),
|
|
250
|
+
scopes: row.scopes ? parseJsonColumn(row.scopes) : null
|
|
251
|
+
};
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
* Validate that a redirect URI is in the client's registered set.
|
|
255
|
+
*
|
|
256
|
+
* Comparison is exact string match (per RFC 6749 §3.1.2.3).
|
|
257
|
+
* Returns null if valid, or an error message if not.
|
|
258
|
+
*/
|
|
259
|
+
function validateClientRedirectUri(redirectUri, allowedUris) {
|
|
260
|
+
if (allowedUris.includes(redirectUri)) return null;
|
|
261
|
+
return "redirect_uri is not registered for this client";
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
//#endregion
|
|
265
|
+
export { handleOAuthClientUpdate as a, validateRedirectUri as c, handleOAuthClientList as i, handleOAuthClientDelete as n, lookupOAuthClient as o, handleOAuthClientGet as r, validateClientRedirectUri as s, handleOAuthClientCreate as t };
|
|
266
|
+
//# sourceMappingURL=oauth-clients-DENiDQri.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"oauth-clients-DENiDQri.mjs","names":[],"sources":["../src/api/oauth/redirect-uri.ts","../src/api/handlers/oauth-clients.ts"],"sourcesContent":["/**\n * Validate a redirect URI per OAuth 2.1 security requirements.\n *\n * Allows localhost / loopback redirect URIs over HTTP for native clients,\n * and any HTTPS URL for web-based flows.\n */\nexport function validateRedirectUri(uri: string): string | null {\n\ttry {\n\t\tconst url = new URL(uri);\n\n\t\t// Reject protocol-relative URLs\n\t\tif (uri.startsWith(\"//\")) {\n\t\t\treturn \"Protocol-relative redirect URIs are not allowed\";\n\t\t}\n\n\t\t// Allow localhost/loopback over HTTP (for desktop MCP clients)\n\t\tif (url.protocol === \"http:\") {\n\t\t\tconst host = url.hostname;\n\t\t\tif (host === \"127.0.0.1\" || host === \"localhost\" || host === \"[::1]\") {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\treturn \"HTTP redirect URIs are only allowed for localhost\";\n\t\t}\n\n\t\t// Allow HTTPS\n\t\tif (url.protocol === \"https:\") {\n\t\t\treturn null;\n\t\t}\n\n\t\treturn `Unsupported redirect URI scheme: ${url.protocol}`;\n\t} catch {\n\t\treturn \"Invalid redirect URI\";\n\t}\n}\n","/**\n * OAuth client management handlers.\n *\n * CRUD operations for registered OAuth clients. Each client has a set\n * of pre-registered redirect URIs. The authorization endpoint rejects\n * any redirect_uri not in the client's registered set.\n */\n\nimport type { Kysely } from \"kysely\";\n\nimport type { Database } from \"../../database/types.js\";\nimport { validateRedirectUri } from \"../oauth/redirect-uri.js\";\nimport type { ApiResult } from \"../types.js\";\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\n/** Parse a JSON string column into a typed value. */\nfunction parseJsonColumn<T>(value: string): T {\n\t// eslint-disable-next-line typescript/no-unsafe-type-assertion -- JSON.parse returns unknown, callers provide the expected shape\n\treturn JSON.parse(value) as T;\n}\n\nfunction validateRegisteredRedirectUris(redirectUris: string[]): string | null {\n\tfor (const redirectUri of redirectUris) {\n\t\tconst error = validateRedirectUri(redirectUri);\n\t\tif (error) {\n\t\t\treturn `Invalid redirect URI: ${error}`;\n\t\t}\n\t}\n\treturn null;\n}\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport interface OAuthClientInfo {\n\tid: string;\n\tname: string;\n\tredirectUris: string[];\n\tscopes: string[] | null;\n\tcreatedAt: string;\n\tupdatedAt: string;\n}\n\n// ---------------------------------------------------------------------------\n// Handlers\n// ---------------------------------------------------------------------------\n\n/**\n * Create a new OAuth client.\n */\nexport async function handleOAuthClientCreate(\n\tdb: Kysely<Database>,\n\tinput: {\n\t\tid: string;\n\t\tname: string;\n\t\tredirectUris: string[];\n\t\tscopes?: string[] | null;\n\t},\n): Promise<ApiResult<OAuthClientInfo>> {\n\ttry {\n\t\tif (input.redirectUris.length === 0) {\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: \"At least one redirect URI is required\",\n\t\t\t\t},\n\t\t\t};\n\t\t}\n\n\t\tconst redirectUriError = validateRegisteredRedirectUris(input.redirectUris);\n\t\tif (redirectUriError) {\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: redirectUriError,\n\t\t\t\t},\n\t\t\t};\n\t\t}\n\n\t\t// Check for duplicate client ID\n\t\tconst existing = await db\n\t\t\t.selectFrom(\"_emdash_oauth_clients\")\n\t\t\t.select(\"id\")\n\t\t\t.where(\"id\", \"=\", input.id)\n\t\t\t.executeTakeFirst();\n\n\t\tif (existing) {\n\t\t\treturn {\n\t\t\t\tsuccess: false,\n\t\t\t\terror: { code: \"CONFLICT\", message: \"OAuth client with this ID already exists\" },\n\t\t\t};\n\t\t}\n\n\t\tconst now = new Date().toISOString();\n\n\t\tawait db\n\t\t\t.insertInto(\"_emdash_oauth_clients\")\n\t\t\t.values({\n\t\t\t\tid: input.id,\n\t\t\t\tname: input.name,\n\t\t\t\tredirect_uris: JSON.stringify(input.redirectUris),\n\t\t\t\tscopes: input.scopes && input.scopes.length > 0 ? JSON.stringify(input.scopes) : null,\n\t\t\t})\n\t\t\t.execute();\n\n\t\treturn {\n\t\t\tsuccess: true,\n\t\t\tdata: {\n\t\t\t\tid: input.id,\n\t\t\t\tname: input.name,\n\t\t\t\tredirectUris: input.redirectUris,\n\t\t\t\tscopes: input.scopes && input.scopes.length > 0 ? input.scopes : null,\n\t\t\t\tcreatedAt: now,\n\t\t\t\tupdatedAt: now,\n\t\t\t},\n\t\t};\n\t} catch {\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\terror: {\n\t\t\t\tcode: \"CLIENT_CREATE_ERROR\",\n\t\t\t\tmessage: \"Failed to create OAuth client\",\n\t\t\t},\n\t\t};\n\t}\n}\n\n/**\n * List all registered OAuth clients.\n */\nexport async function handleOAuthClientList(\n\tdb: Kysely<Database>,\n): Promise<ApiResult<{ items: OAuthClientInfo[] }>> {\n\ttry {\n\t\tconst rows = await db\n\t\t\t.selectFrom(\"_emdash_oauth_clients\")\n\t\t\t.selectAll()\n\t\t\t.orderBy(\"created_at\", \"desc\")\n\t\t\t.execute();\n\n\t\tconst items: OAuthClientInfo[] = rows.map((row) => ({\n\t\t\tid: row.id,\n\t\t\tname: row.name,\n\t\t\tredirectUris: parseJsonColumn<string[]>(row.redirect_uris),\n\t\t\tscopes: row.scopes ? parseJsonColumn<string[]>(row.scopes) : null,\n\t\t\tcreatedAt: row.created_at,\n\t\t\tupdatedAt: row.updated_at,\n\t\t}));\n\n\t\treturn { success: true, data: { items } };\n\t} catch {\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\terror: {\n\t\t\t\tcode: \"CLIENT_LIST_ERROR\",\n\t\t\t\tmessage: \"Failed to list OAuth clients\",\n\t\t\t},\n\t\t};\n\t}\n}\n\n/**\n * Get a single OAuth client by ID.\n */\nexport async function handleOAuthClientGet(\n\tdb: Kysely<Database>,\n\tclientId: string,\n): Promise<ApiResult<OAuthClientInfo>> {\n\ttry {\n\t\tconst row = await db\n\t\t\t.selectFrom(\"_emdash_oauth_clients\")\n\t\t\t.selectAll()\n\t\t\t.where(\"id\", \"=\", clientId)\n\t\t\t.executeTakeFirst();\n\n\t\tif (!row) {\n\t\t\treturn {\n\t\t\t\tsuccess: false,\n\t\t\t\terror: { code: \"NOT_FOUND\", message: \"OAuth client not found\" },\n\t\t\t};\n\t\t}\n\n\t\treturn {\n\t\t\tsuccess: true,\n\t\t\tdata: {\n\t\t\t\tid: row.id,\n\t\t\t\tname: row.name,\n\t\t\t\tredirectUris: parseJsonColumn<string[]>(row.redirect_uris),\n\t\t\t\tscopes: row.scopes ? parseJsonColumn<string[]>(row.scopes) : null,\n\t\t\t\tcreatedAt: row.created_at,\n\t\t\t\tupdatedAt: row.updated_at,\n\t\t\t},\n\t\t};\n\t} catch {\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\terror: {\n\t\t\t\tcode: \"CLIENT_GET_ERROR\",\n\t\t\t\tmessage: \"Failed to get OAuth client\",\n\t\t\t},\n\t\t};\n\t}\n}\n\n/**\n * Update an OAuth client.\n */\nexport async function handleOAuthClientUpdate(\n\tdb: Kysely<Database>,\n\tclientId: string,\n\tinput: {\n\t\tname?: string;\n\t\tredirectUris?: string[];\n\t\tscopes?: string[] | null;\n\t},\n): Promise<ApiResult<OAuthClientInfo>> {\n\ttry {\n\t\tconst existing = await db\n\t\t\t.selectFrom(\"_emdash_oauth_clients\")\n\t\t\t.selectAll()\n\t\t\t.where(\"id\", \"=\", clientId)\n\t\t\t.executeTakeFirst();\n\n\t\tif (!existing) {\n\t\t\treturn {\n\t\t\t\tsuccess: false,\n\t\t\t\terror: { code: \"NOT_FOUND\", message: \"OAuth client not found\" },\n\t\t\t};\n\t\t}\n\n\t\tif (input.redirectUris !== undefined && input.redirectUris.length === 0) {\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: \"At least one redirect URI is required\",\n\t\t\t\t},\n\t\t\t};\n\t\t}\n\n\t\tif (input.redirectUris !== undefined) {\n\t\t\tconst redirectUriError = validateRegisteredRedirectUris(input.redirectUris);\n\t\t\tif (redirectUriError) {\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: \"VALIDATION_ERROR\",\n\t\t\t\t\t\tmessage: redirectUriError,\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\n\t\tconst updates: Record<string, string | null> = {\n\t\t\tupdated_at: new Date().toISOString(),\n\t\t};\n\n\t\tif (input.name !== undefined) {\n\t\t\tupdates.name = input.name;\n\t\t}\n\t\tif (input.redirectUris !== undefined) {\n\t\t\tupdates.redirect_uris = JSON.stringify(input.redirectUris);\n\t\t}\n\t\tif (input.scopes !== undefined) {\n\t\t\tupdates.scopes =\n\t\t\t\tinput.scopes && input.scopes.length > 0 ? JSON.stringify(input.scopes) : null;\n\t\t}\n\n\t\tawait db.updateTable(\"_emdash_oauth_clients\").set(updates).where(\"id\", \"=\", clientId).execute();\n\n\t\t// Fetch the updated row\n\t\tconst updated = await db\n\t\t\t.selectFrom(\"_emdash_oauth_clients\")\n\t\t\t.selectAll()\n\t\t\t.where(\"id\", \"=\", clientId)\n\t\t\t.executeTakeFirst();\n\n\t\tif (!updated) {\n\t\t\treturn {\n\t\t\t\tsuccess: false,\n\t\t\t\terror: { code: \"NOT_FOUND\", message: \"OAuth client not found after update\" },\n\t\t\t};\n\t\t}\n\n\t\treturn {\n\t\t\tsuccess: true,\n\t\t\tdata: {\n\t\t\t\tid: updated.id,\n\t\t\t\tname: updated.name,\n\t\t\t\tredirectUris: parseJsonColumn<string[]>(updated.redirect_uris),\n\t\t\t\tscopes: updated.scopes ? parseJsonColumn<string[]>(updated.scopes) : null,\n\t\t\t\tcreatedAt: updated.created_at,\n\t\t\t\tupdatedAt: updated.updated_at,\n\t\t\t},\n\t\t};\n\t} catch {\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\terror: {\n\t\t\t\tcode: \"CLIENT_UPDATE_ERROR\",\n\t\t\t\tmessage: \"Failed to update OAuth client\",\n\t\t\t},\n\t\t};\n\t}\n}\n\n/**\n * Delete an OAuth client.\n */\nexport async function handleOAuthClientDelete(\n\tdb: Kysely<Database>,\n\tclientId: string,\n): Promise<ApiResult<{ deleted: true }>> {\n\ttry {\n\t\tconst result = await db\n\t\t\t.deleteFrom(\"_emdash_oauth_clients\")\n\t\t\t.where(\"id\", \"=\", clientId)\n\t\t\t.executeTakeFirst();\n\n\t\tif (result.numDeletedRows === 0n) {\n\t\t\treturn {\n\t\t\t\tsuccess: false,\n\t\t\t\terror: { code: \"NOT_FOUND\", message: \"OAuth client not found\" },\n\t\t\t};\n\t\t}\n\n\t\treturn { success: true, data: { deleted: true } };\n\t} catch {\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\terror: {\n\t\t\t\tcode: \"CLIENT_DELETE_ERROR\",\n\t\t\t\tmessage: \"Failed to delete OAuth client\",\n\t\t\t},\n\t\t};\n\t}\n}\n\n// ---------------------------------------------------------------------------\n// Lookup helpers (used by authorization handler)\n// ---------------------------------------------------------------------------\n\n/**\n * Look up a registered OAuth client by ID.\n * Returns the client's redirect URIs or null if the client is not registered.\n */\nexport async function lookupOAuthClient(\n\tdb: Kysely<Database>,\n\tclientId: string,\n): Promise<{ redirectUris: string[]; scopes: string[] | null } | null> {\n\tconst row = await db\n\t\t.selectFrom(\"_emdash_oauth_clients\")\n\t\t.select([\"redirect_uris\", \"scopes\"])\n\t\t.where(\"id\", \"=\", clientId)\n\t\t.executeTakeFirst();\n\n\tif (!row) return null;\n\n\treturn {\n\t\tredirectUris: parseJsonColumn<string[]>(row.redirect_uris),\n\t\tscopes: row.scopes ? parseJsonColumn<string[]>(row.scopes) : null,\n\t};\n}\n\n/**\n * Validate that a redirect URI is in the client's registered set.\n *\n * Comparison is exact string match (per RFC 6749 §3.1.2.3).\n * Returns null if valid, or an error message if not.\n */\nexport function validateClientRedirectUri(\n\tredirectUri: string,\n\tallowedUris: string[],\n): string | null {\n\tif (allowedUris.includes(redirectUri)) {\n\t\treturn null; // OK\n\t}\n\treturn \"redirect_uri is not registered for this client\";\n}\n"],"mappings":"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"}
|