emdash 0.30.0 → 0.31.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/api/route-utils.mjs +13 -13
- package/dist/api/schemas/index.d.mts +1 -1
- package/dist/api/schemas/index.mjs +3 -3
- package/dist/{api-b8WIiGU4.mjs → api-EibxGP-V.mjs} +23 -23
- package/dist/api-EibxGP-V.mjs.map +1 -0
- package/dist/{apply-CmIJK9j8.mjs → apply-fGHCAwWN.mjs} +26 -25
- package/dist/apply-fGHCAwWN.mjs.map +1 -0
- package/dist/astro/index.d.mts +2 -2
- package/dist/astro/index.mjs +1 -1
- package/dist/astro/middleware/auth.d.mts +2 -2
- package/dist/astro/middleware/auth.mjs +2 -2
- package/dist/astro/middleware/redirect.mjs +5 -5
- package/dist/astro/middleware/request-context.mjs +1 -1
- package/dist/astro/middleware.d.mts +2 -2
- package/dist/astro/middleware.mjs +139 -68
- package/dist/astro/middleware.mjs.map +1 -1
- package/dist/astro/routes/api/admin/allowed-domains/_domain_.mjs +6 -6
- package/dist/astro/routes/api/admin/allowed-domains/index.mjs +6 -6
- package/dist/astro/routes/api/admin/api-tokens/_id_.mjs +2 -2
- package/dist/astro/routes/api/admin/api-tokens/index.mjs +3 -3
- package/dist/astro/routes/api/admin/byline-fields/_slug_/usage.mjs +3 -3
- package/dist/astro/routes/api/admin/byline-fields/_slug_.mjs +7 -7
- package/dist/astro/routes/api/admin/byline-fields/index.mjs +7 -7
- package/dist/astro/routes/api/admin/byline-fields/reorder.mjs +7 -7
- package/dist/astro/routes/api/admin/bylines/_id_/index.mjs +14 -14
- package/dist/astro/routes/api/admin/bylines/_id_/translations.mjs +14 -14
- package/dist/astro/routes/api/admin/bylines/index.d.mts.map +1 -1
- package/dist/astro/routes/api/admin/bylines/index.mjs +18 -17
- package/dist/astro/routes/api/admin/bylines/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/comments/_id_/status.mjs +10 -10
- package/dist/astro/routes/api/admin/comments/_id_.mjs +5 -5
- package/dist/astro/routes/api/admin/comments/bulk.mjs +9 -9
- package/dist/astro/routes/api/admin/comments/counts.mjs +5 -5
- package/dist/astro/routes/api/admin/comments/index.mjs +9 -9
- package/dist/astro/routes/api/admin/hooks/exclusive/_hookName_.mjs +4 -4
- package/dist/astro/routes/api/admin/hooks/exclusive/index.mjs +3 -3
- package/dist/astro/routes/api/admin/media-usage/repair.mjs +10 -10
- package/dist/astro/routes/api/admin/oauth-clients/_id_.mjs +3 -3
- package/dist/astro/routes/api/admin/oauth-clients/index.mjs +3 -3
- package/dist/astro/routes/api/admin/plugins/_id_/disable.mjs +34 -34
- package/dist/astro/routes/api/admin/plugins/_id_/enable.mjs +34 -34
- package/dist/astro/routes/api/admin/plugins/_id_/index.mjs +34 -34
- package/dist/astro/routes/api/admin/plugins/_id_/mcp.mjs +4 -4
- package/dist/astro/routes/api/admin/plugins/_id_/settings.mjs +34 -34
- package/dist/astro/routes/api/admin/plugins/_id_/uninstall.mjs +34 -34
- package/dist/astro/routes/api/admin/plugins/_id_/update.mjs +34 -34
- package/dist/astro/routes/api/admin/plugins/index.mjs +34 -34
- package/dist/astro/routes/api/admin/plugins/marketplace/_id_/icon.mjs +3 -3
- package/dist/astro/routes/api/admin/plugins/marketplace/_id_/index.mjs +34 -34
- package/dist/astro/routes/api/admin/plugins/marketplace/_id_/install.mjs +34 -34
- package/dist/astro/routes/api/admin/plugins/marketplace/index.mjs +34 -34
- package/dist/astro/routes/api/admin/plugins/registry/_id_/uninstall.mjs +34 -34
- package/dist/astro/routes/api/admin/plugins/registry/_id_/update.mjs +35 -35
- package/dist/astro/routes/api/admin/plugins/registry/artifact.mjs +34 -34
- package/dist/astro/routes/api/admin/plugins/registry/install.mjs +35 -35
- package/dist/astro/routes/api/admin/plugins/updates.mjs +34 -34
- package/dist/astro/routes/api/admin/themes/marketplace/_id_/index.mjs +34 -34
- package/dist/astro/routes/api/admin/themes/marketplace/_id_/thumbnail.mjs +3 -3
- package/dist/astro/routes/api/admin/themes/marketplace/index.mjs +34 -34
- package/dist/astro/routes/api/admin/users/_id_/disable.mjs +2 -2
- package/dist/astro/routes/api/admin/users/_id_/enable.mjs +2 -2
- package/dist/astro/routes/api/admin/users/_id_/index.mjs +6 -6
- package/dist/astro/routes/api/admin/users/_id_/send-recovery.mjs +2 -2
- package/dist/astro/routes/api/admin/users/index.mjs +6 -6
- package/dist/astro/routes/api/auth/dev-bypass.mjs +4 -4
- package/dist/astro/routes/api/auth/invite/accept.mjs +2 -2
- package/dist/astro/routes/api/auth/invite/complete.mjs +6 -6
- package/dist/astro/routes/api/auth/invite/index.mjs +6 -6
- package/dist/astro/routes/api/auth/invite/register-options.mjs +6 -6
- package/dist/astro/routes/api/auth/logout.mjs +2 -2
- package/dist/astro/routes/api/auth/magic-link/send.mjs +7 -7
- package/dist/astro/routes/api/auth/magic-link/verify.mjs +2 -2
- package/dist/astro/routes/api/auth/me.mjs +7 -7
- package/dist/astro/routes/api/auth/mode.mjs +2 -2
- package/dist/astro/routes/api/auth/passkey/_id_.mjs +6 -6
- package/dist/astro/routes/api/auth/passkey/index.mjs +2 -2
- package/dist/astro/routes/api/auth/passkey/options.mjs +7 -7
- package/dist/astro/routes/api/auth/passkey/register/options.mjs +6 -6
- package/dist/astro/routes/api/auth/passkey/register/verify.mjs +6 -6
- package/dist/astro/routes/api/auth/passkey/verify.mjs +6 -6
- package/dist/astro/routes/api/auth/signup/complete.mjs +6 -6
- package/dist/astro/routes/api/auth/signup/request.mjs +7 -7
- package/dist/astro/routes/api/auth/signup/verify.mjs +2 -2
- package/dist/astro/routes/api/comments/_collection_/_contentId_/index.mjs +10 -10
- package/dist/astro/routes/api/comments/_collection_/_contentId_/reactions.mjs +10 -10
- package/dist/astro/routes/api/content/_collection_/_id_/compare.mjs +3 -3
- package/dist/astro/routes/api/content/_collection_/_id_/discard-draft.mjs +3 -3
- package/dist/astro/routes/api/content/_collection_/_id_/duplicate.mjs +3 -3
- package/dist/astro/routes/api/content/_collection_/_id_/permanent.mjs +3 -3
- package/dist/astro/routes/api/content/_collection_/_id_/preview-url.mjs +9 -9
- package/dist/astro/routes/api/content/_collection_/_id_/publish.mjs +7 -7
- package/dist/astro/routes/api/content/_collection_/_id_/references/_relation_/children.mjs +14 -14
- package/dist/astro/routes/api/content/_collection_/_id_/references/_relation_/parents.mjs +14 -14
- package/dist/astro/routes/api/content/_collection_/_id_/restore.mjs +3 -3
- package/dist/astro/routes/api/content/_collection_/_id_/revisions.mjs +3 -3
- package/dist/astro/routes/api/content/_collection_/_id_/schedule.mjs +7 -7
- package/dist/astro/routes/api/content/_collection_/_id_/terms/_taxonomy_.mjs +13 -13
- package/dist/astro/routes/api/content/_collection_/_id_/translations.mjs +3 -3
- package/dist/astro/routes/api/content/_collection_/_id_/unpublish.mjs +3 -3
- package/dist/astro/routes/api/content/_collection_/_id_.mjs +7 -7
- package/dist/astro/routes/api/content/_collection_/authors.mjs +3 -3
- package/dist/astro/routes/api/content/_collection_/index.mjs +7 -7
- package/dist/astro/routes/api/content/_collection_/trash.mjs +7 -7
- package/dist/astro/routes/api/dashboard.mjs +7 -7
- package/dist/astro/routes/api/dev/emails.mjs +2 -2
- package/dist/astro/routes/api/import/probe.mjs +12 -12
- package/dist/astro/routes/api/import/wordpress/analyze.mjs +3 -3
- package/dist/astro/routes/api/import/wordpress/execute.d.mts +2 -2
- package/dist/astro/routes/api/import/wordpress/execute.mjs +11 -11
- package/dist/astro/routes/api/import/wordpress/media.d.mts +2 -2
- package/dist/astro/routes/api/import/wordpress/media.mjs +7 -7
- package/dist/astro/routes/api/import/wordpress/prepare.mjs +9 -9
- package/dist/astro/routes/api/import/wordpress/rewrite-urls.d.mts +2 -2
- package/dist/astro/routes/api/import/wordpress/rewrite-urls.mjs +9 -9
- package/dist/astro/routes/api/import/wordpress-plugin/analyze.mjs +12 -12
- package/dist/astro/routes/api/import/wordpress-plugin/execute.d.mts +2 -2
- package/dist/astro/routes/api/import/wordpress-plugin/execute.mjs +19 -19
- package/dist/astro/routes/api/manifest.mjs +3 -3
- package/dist/astro/routes/api/mcp.mjs +39 -39
- package/dist/astro/routes/api/media/_id_/confirm.mjs +7 -7
- package/dist/astro/routes/api/media/_id_/usage.mjs +11 -11
- package/dist/astro/routes/api/media/_id_.mjs +10 -10
- package/dist/astro/routes/api/media/file/_...key_.mjs +2 -2
- package/dist/astro/routes/api/media/providers/_providerId_/_itemId_.mjs +3 -3
- package/dist/astro/routes/api/media/providers/_providerId_/index.mjs +3 -3
- package/dist/astro/routes/api/media/providers/index.mjs +3 -3
- package/dist/astro/routes/api/media/upload-url.mjs +7 -7
- package/dist/astro/routes/api/media.mjs +10 -10
- package/dist/astro/routes/api/menus/_name_/items/_id_.mjs +8 -8
- package/dist/astro/routes/api/menus/_name_/items.mjs +8 -8
- package/dist/astro/routes/api/menus/_name_/reorder.mjs +8 -8
- package/dist/astro/routes/api/menus/_name_/translations.mjs +8 -8
- package/dist/astro/routes/api/menus/_name_.mjs +8 -8
- package/dist/astro/routes/api/menus/index.mjs +8 -8
- package/dist/astro/routes/api/oauth/authorize.d.mts.map +1 -1
- package/dist/astro/routes/api/oauth/authorize.mjs +23 -9
- package/dist/astro/routes/api/oauth/authorize.mjs.map +1 -1
- package/dist/astro/routes/api/oauth/device/authorize.mjs +3 -3
- package/dist/astro/routes/api/oauth/device/code.mjs +4 -4
- package/dist/astro/routes/api/oauth/device/token.mjs +4 -4
- package/dist/astro/routes/api/oauth/register.mjs +2 -2
- package/dist/astro/routes/api/oauth/token/refresh.mjs +3 -3
- package/dist/astro/routes/api/oauth/token/revoke.mjs +3 -3
- package/dist/astro/routes/api/oauth/token.mjs +2 -2
- package/dist/astro/routes/api/openapi.json.mjs +4 -4
- package/dist/astro/routes/api/plugins/_pluginId_/_...path_.mjs +4 -4
- package/dist/astro/routes/api/redirects/404s/index.mjs +10 -10
- package/dist/astro/routes/api/redirects/404s/summary.mjs +10 -10
- package/dist/astro/routes/api/redirects/_id_.mjs +11 -11
- package/dist/astro/routes/api/redirects/index.mjs +11 -11
- package/dist/astro/routes/api/relations/_id_/index.mjs +14 -14
- package/dist/astro/routes/api/relations/_id_/translations.mjs +10 -10
- package/dist/astro/routes/api/relations/index.mjs +14 -14
- package/dist/astro/routes/api/revisions/_revisionId_/index.mjs +3 -3
- package/dist/astro/routes/api/revisions/_revisionId_/restore.mjs +3 -3
- package/dist/astro/routes/api/schema/collections/_slug_/fields/_fieldSlug_.mjs +34 -34
- package/dist/astro/routes/api/schema/collections/_slug_/fields/index.mjs +34 -34
- package/dist/astro/routes/api/schema/collections/_slug_/fields/reorder.mjs +34 -34
- package/dist/astro/routes/api/schema/collections/_slug_/index.mjs +34 -34
- package/dist/astro/routes/api/schema/collections/index.mjs +34 -34
- package/dist/astro/routes/api/schema/index.mjs +8 -8
- package/dist/astro/routes/api/schema/orphans/_slug_.mjs +34 -34
- package/dist/astro/routes/api/schema/orphans/index.mjs +34 -34
- package/dist/astro/routes/api/search/enable.mjs +11 -11
- package/dist/astro/routes/api/search/index.mjs +10 -10
- package/dist/astro/routes/api/search/rebuild.mjs +11 -11
- package/dist/astro/routes/api/search/stats.mjs +7 -7
- package/dist/astro/routes/api/search/suggest.mjs +10 -10
- package/dist/astro/routes/api/sections/_slug_.mjs +10 -10
- package/dist/astro/routes/api/sections/index.mjs +10 -10
- package/dist/astro/routes/api/settings/backups/archives/_name_.mjs +4 -4
- package/dist/astro/routes/api/settings/backups/archives/index.mjs +4 -4
- package/dist/astro/routes/api/settings/backups/export.mjs +4 -4
- package/dist/astro/routes/api/settings/backups/index.mjs +5 -5
- package/dist/astro/routes/api/settings/email.mjs +4 -4
- package/dist/astro/routes/api/settings.mjs +12 -12
- package/dist/astro/routes/api/setup/admin-verify.mjs +6 -6
- package/dist/astro/routes/api/setup/admin.mjs +6 -6
- package/dist/astro/routes/api/setup/dev-bypass.mjs +18 -18
- package/dist/astro/routes/api/setup/dev-reset.mjs +2 -2
- package/dist/astro/routes/api/setup/index.mjs +22 -22
- package/dist/astro/routes/api/setup/status.mjs +3 -3
- package/dist/astro/routes/api/snapshot.mjs +4 -4
- package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_/translations.mjs +13 -13
- package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_.mjs +13 -13
- package/dist/astro/routes/api/taxonomies/_name_/terms/index.mjs +13 -13
- package/dist/astro/routes/api/taxonomies/index.mjs +13 -13
- package/dist/astro/routes/api/themes/preview.mjs +4 -4
- package/dist/astro/routes/api/typegen.mjs +5 -5
- package/dist/astro/routes/api/widget-areas/_name_/reorder.mjs +7 -7
- package/dist/astro/routes/api/widget-areas/_name_/widgets/_id_.mjs +10 -10
- package/dist/astro/routes/api/widget-areas/_name_/widgets.mjs +10 -10
- package/dist/astro/routes/api/widget-areas/_name_.mjs +6 -6
- package/dist/astro/routes/api/widget-areas/index.mjs +10 -10
- package/dist/astro/routes/api/widget-components.mjs +2 -2
- package/dist/astro/routes/robots.txt.mjs +5 -5
- package/dist/astro/routes/sitemap-_collection_.xml.mjs +7 -7
- package/dist/astro/routes/sitemap.xml.mjs +5 -5
- package/dist/astro/types.d.mts +2 -2
- package/dist/{authorize-WxsiePzy.mjs → authorize-6WPZa1xZ.mjs} +2 -2
- package/dist/{authorize-WxsiePzy.mjs.map → authorize-6WPZa1xZ.mjs.map} +1 -1
- package/dist/{backup-S8kFWtwD.mjs → backup-Qr9PaGUo.mjs} +2 -2
- package/dist/{backup-S8kFWtwD.mjs.map → backup-Qr9PaGUo.mjs.map} +1 -1
- package/dist/{byline-XEjchwzZ.mjs → byline-BTOxUlFF.mjs} +6 -6
- package/dist/{byline-XEjchwzZ.mjs.map → byline-BTOxUlFF.mjs.map} +1 -1
- package/dist/{bylines-czseViYo.mjs → bylines-FyZu6TbJ.mjs} +6 -6
- package/dist/{bylines-czseViYo.mjs.map → bylines-FyZu6TbJ.mjs.map} +1 -1
- package/dist/{bylines-BJbT4gKS.mjs → bylines-oVN0iPwX.mjs} +12 -8
- package/dist/bylines-oVN0iPwX.mjs.map +1 -0
- package/dist/{cache-CGCd6AVM.mjs → cache-DDwy3JDW.mjs} +2 -2
- package/dist/{cache-CGCd6AVM.mjs.map → cache-DDwy3JDW.mjs.map} +1 -1
- package/dist/{chunks-BxXyunY-.mjs → chunks-Bq-5DPrD.mjs} +2 -2
- package/dist/{chunks-BxXyunY-.mjs.map → chunks-Bq-5DPrD.mjs.map} +1 -1
- package/dist/cli/index.mjs +18 -18
- package/dist/{comment-DPT0WKyd.mjs → comment-B9cUud8H.mjs} +2 -2
- package/dist/{comment-DPT0WKyd.mjs.map → comment-B9cUud8H.mjs.map} +1 -1
- package/dist/{comment-reaction-C65MldIB.mjs → comment-reaction-VUXO981F.mjs} +2 -2
- package/dist/{comment-reaction-C65MldIB.mjs.map → comment-reaction-VUXO981F.mjs.map} +1 -1
- package/dist/{comments-Bz6sCbgD.mjs → comments-PXj1E9Si.mjs} +3 -3
- package/dist/{comments-Bz6sCbgD.mjs.map → comments-PXj1E9Si.mjs.map} +1 -1
- package/dist/{config-CVssduLe.mjs → config-B6b_BobR.mjs} +6 -2
- package/dist/config-B6b_BobR.mjs.map +1 -0
- package/dist/{content-Ci04z2z-.mjs → content-BC43pICM.mjs} +4 -4
- package/dist/{content-Ci04z2z-.mjs.map → content-BC43pICM.mjs.map} +1 -1
- package/dist/{content-refresh-D4khvC0R.mjs → content-refresh-CPMSauD3.mjs} +4 -4
- package/dist/{content-refresh-D4khvC0R.mjs.map → content-refresh-CPMSauD3.mjs.map} +1 -1
- package/dist/{context-B6hc7zJL.mjs → context-DOurRIrb.mjs} +10 -10
- package/dist/{context-B6hc7zJL.mjs.map → context-DOurRIrb.mjs.map} +1 -1
- package/dist/{dashboard-C5NkXFbi.mjs → dashboard-CBm4zhc3.mjs} +4 -4
- package/dist/{dashboard-C5NkXFbi.mjs.map → dashboard-CBm4zhc3.mjs.map} +1 -1
- package/dist/database/pg-migration-lock.d.mts.map +1 -1
- package/dist/database/pg-migration-lock.mjs +1 -4
- package/dist/database/pg-migration-lock.mjs.map +1 -1
- package/dist/db/index.mjs +2 -2
- package/dist/{dialect-helpers-HxEQGl_1.mjs → dialect-helpers-BtOwo2us.mjs} +4 -4
- package/dist/dialect-helpers-BtOwo2us.mjs.map +1 -0
- package/dist/{error-CEGF6UZb.mjs → error-DJ98TRbQ.mjs} +2 -2
- package/dist/{error-CEGF6UZb.mjs.map → error-DJ98TRbQ.mjs.map} +1 -1
- package/dist/{field-defs-cache-DvmlgP-D.mjs → field-defs-cache-KfNJ_qLQ.mjs} +2 -2
- package/dist/{field-defs-cache-DvmlgP-D.mjs.map → field-defs-cache-KfNJ_qLQ.mjs.map} +1 -1
- package/dist/{fts-manager-DzqIBrrW.mjs → fts-manager-hyCU9OOp.mjs} +3 -3
- package/dist/{fts-manager-DzqIBrrW.mjs.map → fts-manager-hyCU9OOp.mjs.map} +1 -1
- package/dist/{hreflang-db2Tpb2o.mjs → hreflang-CbYeCzl9.mjs} +7 -7
- package/dist/{hreflang-db2Tpb2o.mjs.map → hreflang-CbYeCzl9.mjs.map} +1 -1
- package/dist/{import-Dmkm8S1W.mjs → import-oDYCgNYQ.mjs} +2 -2
- package/dist/{import-Dmkm8S1W.mjs.map → import-oDYCgNYQ.mjs.map} +1 -1
- package/dist/{index-wYnC6u4o.d.mts → index-BcEH_FfS.d.mts} +33 -2
- package/dist/index-BcEH_FfS.d.mts.map +1 -0
- package/dist/index.d.mts +2 -2
- package/dist/index.mjs +48 -48
- package/dist/{load-Cx27ki1l.mjs → load-Dg5gtWma.mjs} +2 -2
- package/dist/{load-Cx27ki1l.mjs.map → load-Dg5gtWma.mjs.map} +1 -1
- package/dist/{loader-Be3ouI5L.mjs → loader-D4rigvjR.mjs} +4 -4
- package/dist/{loader-Be3ouI5L.mjs.map → loader-D4rigvjR.mjs.map} +1 -1
- package/dist/media/local-runtime.d.mts +2 -2
- package/dist/media/local-runtime.mjs +5 -5
- package/dist/{media-kIV1IxFf.mjs → media-BJ6SRY3g.mjs} +8 -4
- package/dist/media-BJ6SRY3g.mjs.map +1 -0
- package/dist/{media-BjhhENaJ.mjs → media-its1WLYv.mjs} +2 -2
- package/dist/{media-BjhhENaJ.mjs.map → media-its1WLYv.mjs.map} +1 -1
- package/dist/{media-upload-D2wk3EIt.mjs → media-upload-DNu3QySc.mjs} +4 -4
- package/dist/{media-upload-D2wk3EIt.mjs.map → media-upload-DNu3QySc.mjs.map} +1 -1
- package/dist/{media-usage-CljdO1mc.mjs → media-usage-DPQ3K4xB.mjs} +6 -6
- package/dist/{media-usage-CljdO1mc.mjs.map → media-usage-DPQ3K4xB.mjs.map} +1 -1
- package/dist/{menus-CZyG6rvx.mjs → menus-BMGzWyWH.mjs} +15 -8
- package/dist/menus-BMGzWyWH.mjs.map +1 -0
- package/dist/{menus-BcyElFtI.mjs → menus-CPf_SW7u.mjs} +86 -8
- package/dist/menus-CPf_SW7u.mjs.map +1 -0
- package/dist/{parse-C_-6klII.mjs → parse-53zyxlpv.mjs} +2 -2
- package/dist/{parse-C_-6klII.mjs.map → parse-53zyxlpv.mjs.map} +1 -1
- package/dist/plugin-utils.d.mts +2 -2
- package/dist/plugins/adapt-sandbox-entry.d.mts +2 -2
- package/dist/{query-DR73ZNfm.mjs → query-BbJQ-dGg.mjs} +14 -14
- package/dist/{query-DR73ZNfm.mjs.map → query-BbJQ-dGg.mjs.map} +1 -1
- package/dist/{query-Di7DOmPV.mjs → query-DdFGHzQF.mjs} +3 -3
- package/dist/{query-Di7DOmPV.mjs.map → query-DdFGHzQF.mjs.map} +1 -1
- package/dist/{rate-limit-CMj83JNW.mjs → rate-limit-D3IEiUi2.mjs} +2 -2
- package/dist/{rate-limit-CMj83JNW.mjs.map → rate-limit-D3IEiUi2.mjs.map} +1 -1
- package/dist/{redirect-CgLPYflR.mjs → redirect-BoUac4NT.mjs} +3 -3
- package/dist/{redirect-CgLPYflR.mjs.map → redirect-BoUac4NT.mjs.map} +1 -1
- package/dist/{redirects-B7t9bKsL.mjs → redirects-ChbpqKiS.mjs} +3 -3
- package/dist/{redirects-B7t9bKsL.mjs.map → redirects-ChbpqKiS.mjs.map} +1 -1
- package/dist/{redirects-BBq3n2Rj.mjs → redirects-D457qwt0.mjs} +8 -8
- package/dist/redirects-D457qwt0.mjs.map +1 -0
- package/dist/{registry-FV15nLge.mjs → registry-y21kjhfG.mjs} +6 -6
- package/dist/{registry-FV15nLge.mjs.map → registry-y21kjhfG.mjs.map} +1 -1
- package/dist/{relation-9M9j_UWo.mjs → relation-Du0r04E0.mjs} +3 -3
- package/dist/{relation-9M9j_UWo.mjs.map → relation-Du0r04E0.mjs.map} +1 -1
- package/dist/{relations-Bh8jlFsU.d.mts → relations-BKybBoOX.d.mts} +12 -8
- package/dist/relations-BKybBoOX.d.mts.map +1 -0
- package/dist/{relations-5_avdrN_.mjs → relations-CZMpBqEd.mjs} +3 -3
- package/dist/{relations-5_avdrN_.mjs.map → relations-CZMpBqEd.mjs.map} +1 -1
- package/dist/{relations-BKvO39-9.mjs → relations-DtX1UMBH.mjs} +13 -7
- package/dist/relations-DtX1UMBH.mjs.map +1 -0
- package/dist/{resolve-Cd9dzclN.mjs → resolve-DFr4kq72.mjs} +2 -2
- package/dist/{resolve-Cd9dzclN.mjs.map → resolve-DFr4kq72.mjs.map} +1 -1
- package/dist/{runner-DfnZ5eUr.mjs → runner-BdeLEgad.mjs} +3 -3
- package/dist/{runner-DfnZ5eUr.mjs.map → runner-BdeLEgad.mjs.map} +1 -1
- package/dist/runtime.d.mts +2 -2
- package/dist/runtime.mjs +3 -3
- package/dist/{schema-BXxlHeAf.mjs → schema-BH8P8vaC.mjs} +3 -3
- package/dist/{schema-BXxlHeAf.mjs.map → schema-BH8P8vaC.mjs.map} +1 -1
- package/dist/{scopes-Bl4IwHA-.mjs → scopes-DTIkIaGA.mjs} +2 -2
- package/dist/{scopes-Bl4IwHA-.mjs.map → scopes-DTIkIaGA.mjs.map} +1 -1
- package/dist/{search-Bff-7jFt.mjs → search-D-Yhpmvs.mjs} +8 -7
- package/dist/search-D-Yhpmvs.mjs.map +1 -0
- package/dist/{secrets-CSwQIl4q.mjs → secrets-CQ-69kF9.mjs} +23 -17
- package/dist/secrets-CQ-69kF9.mjs.map +1 -0
- package/dist/{sections-CwW4s1al.mjs → sections-CzVBAKjw.mjs} +3 -3
- package/dist/{sections-CwW4s1al.mjs.map → sections-CzVBAKjw.mjs.map} +1 -1
- package/dist/seed/index.mjs +16 -16
- package/dist/seo/index.mjs +12 -12
- package/dist/{seo-2cmFHZns.mjs → seo-kJzVAmmu.mjs} +2 -2
- package/dist/{seo-2cmFHZns.mjs.map → seo-kJzVAmmu.mjs.map} +1 -1
- package/dist/{service-DkGTWGIi.mjs → service-CQnc276a.mjs} +2 -2
- package/dist/{service-DkGTWGIi.mjs.map → service-CQnc276a.mjs.map} +1 -1
- package/dist/{settings-CpA4lQFt.mjs → settings-C2PaBS49.mjs} +3 -3
- package/dist/{settings-CpA4lQFt.mjs.map → settings-C2PaBS49.mjs.map} +1 -1
- package/dist/{settings-C4s8hFQm.mjs → settings-Dtc0DU31.mjs} +3 -3
- package/dist/{settings-C4s8hFQm.mjs.map → settings-Dtc0DU31.mjs.map} +1 -1
- package/dist/{taxonomies-DjSKBZpq.mjs → taxonomies-HI9fnTdp.mjs} +7 -7
- package/dist/{taxonomies-DjSKBZpq.mjs.map → taxonomies-HI9fnTdp.mjs.map} +1 -1
- package/dist/{taxonomies-Ce49uIzY.mjs → taxonomies-rMeBzOjX.mjs} +26 -17
- package/dist/taxonomies-rMeBzOjX.mjs.map +1 -0
- package/dist/{taxonomy-DfVooU4W.mjs → taxonomy-0mCI25HN.mjs} +3 -3
- package/dist/{taxonomy-DfVooU4W.mjs.map → taxonomy-0mCI25HN.mjs.map} +1 -1
- package/dist/{types-D1iJ3DpO.mjs → types-CrRUFdej.mjs} +2 -2
- package/dist/{types-D1iJ3DpO.mjs.map → types-CrRUFdej.mjs.map} +1 -1
- package/dist/{user-Bh-L1qo6.mjs → user-aTXqmXBz.mjs} +3 -3
- package/dist/{user-Bh-L1qo6.mjs.map → user-aTXqmXBz.mjs.map} +1 -1
- package/dist/{validate-V9nCwq_-.mjs → validate-CDT1jl6_.mjs} +11 -6
- package/dist/validate-CDT1jl6_.mjs.map +1 -0
- package/dist/validate-DULfgpJP.d.mts.map +1 -1
- package/dist/{validation-BsVUJfsP.mjs → validation-DlD0E35W.mjs} +8 -8
- package/dist/{validation-BsVUJfsP.mjs.map → validation-DlD0E35W.mjs.map} +1 -1
- package/dist/version-Ci6bw6YK.mjs +7 -0
- package/dist/{version-907opKac.mjs.map → version-Ci6bw6YK.mjs.map} +1 -1
- package/dist/{widgets-DGv1Z04V.mjs → widgets-5fipNkMT.mjs} +2 -2
- package/dist/{widgets-DGv1Z04V.mjs.map → widgets-5fipNkMT.mjs.map} +1 -1
- package/dist/{wxr-taxonomies-Cs1N6O8z.mjs → wxr-taxonomies-BmUnBNgz.mjs} +4 -4
- package/dist/{wxr-taxonomies-Cs1N6O8z.mjs.map → wxr-taxonomies-BmUnBNgz.mjs.map} +1 -1
- package/dist/{zod-generator-B5prQ5M4.mjs → zod-generator-CwkHWz4f.mjs} +2 -2
- package/dist/{zod-generator-B5prQ5M4.mjs.map → zod-generator-CwkHWz4f.mjs.map} +1 -1
- package/package.json +5 -5
- package/src/api/handlers/bylines.ts +5 -4
- package/src/api/handlers/content.ts +25 -7
- package/src/api/handlers/menus.ts +11 -6
- package/src/api/handlers/relations.ts +7 -2
- package/src/api/handlers/taxonomies.ts +22 -14
- package/src/api/schemas/bylines.ts +4 -4
- package/src/api/schemas/common.ts +7 -6
- package/src/api/schemas/menus.ts +2 -1
- package/src/api/schemas/relations.ts +3 -1
- package/src/api/schemas/taxonomies.ts +4 -2
- package/src/astro/routes/api/admin/bylines/index.ts +5 -8
- package/src/astro/routes/api/oauth/authorize.ts +42 -10
- package/src/components/Gallery.astro +141 -26
- package/src/config/secrets.ts +25 -19
- package/src/content/converters/gallery.ts +61 -0
- package/src/content/converters/portable-text-to-prosemirror.ts +19 -0
- package/src/content/converters/prosemirror-to-portable-text.ts +18 -0
- package/src/content/converters/types.ts +36 -0
- package/src/database/dialect-helpers.ts +3 -4
- package/src/database/pg-migration-lock.ts +1 -4
- package/src/emdash-runtime.ts +55 -17
- package/src/i18n/config.ts +8 -0
- package/src/i18n/repair-locale-casing.ts +51 -0
- package/src/search/query.ts +3 -2
- package/src/seed/apply.ts +9 -7
- package/src/seed/validate.ts +15 -4
- package/dist/api-b8WIiGU4.mjs.map +0 -1
- package/dist/apply-CmIJK9j8.mjs.map +0 -1
- package/dist/bylines-BJbT4gKS.mjs.map +0 -1
- package/dist/config-CVssduLe.mjs.map +0 -1
- package/dist/dialect-helpers-HxEQGl_1.mjs.map +0 -1
- package/dist/index-wYnC6u4o.d.mts.map +0 -1
- package/dist/media-kIV1IxFf.mjs.map +0 -1
- package/dist/menus-BcyElFtI.mjs.map +0 -1
- package/dist/menus-CZyG6rvx.mjs.map +0 -1
- package/dist/redirects-BBq3n2Rj.mjs.map +0 -1
- package/dist/relations-BKvO39-9.mjs.map +0 -1
- package/dist/relations-Bh8jlFsU.d.mts.map +0 -1
- package/dist/search-Bff-7jFt.mjs.map +0 -1
- package/dist/secrets-CSwQIl4q.mjs.map +0 -1
- package/dist/taxonomies-Ce49uIzY.mjs.map +0 -1
- package/dist/validate-V9nCwq_-.mjs.map +0 -1
- package/dist/version-907opKac.mjs +0 -7
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
import "../../../../after-B1IIdH3Y.mjs";
|
|
2
2
|
import "../../../../object-cache-Bok5j2ae.mjs";
|
|
3
3
|
import "../../../../base64-B-PsqheR.mjs";
|
|
4
|
-
import "../../../../types-
|
|
5
|
-
import { n as handleMenuDelete, r as handleMenuGet, u as handleMenuUpdate } from "../../../../menus-
|
|
6
|
-
import { a as unwrapResult, r as handleError } from "../../../../error-
|
|
7
|
-
import { i as parseQuery, n as parseBody, t as isParseError } from "../../../../parse-
|
|
8
|
-
import { z as localeFilterQuery } from "../../../../media-
|
|
9
|
-
import { ct as updateMenuBody } from "../../../../redirects-
|
|
10
|
-
import "../../../../relations-
|
|
4
|
+
import "../../../../types-CrRUFdej.mjs";
|
|
5
|
+
import { n as handleMenuDelete, r as handleMenuGet, u as handleMenuUpdate } from "../../../../menus-BMGzWyWH.mjs";
|
|
6
|
+
import { a as unwrapResult, r as handleError } from "../../../../error-DJ98TRbQ.mjs";
|
|
7
|
+
import { i as parseQuery, n as parseBody, t as isParseError } from "../../../../parse-53zyxlpv.mjs";
|
|
8
|
+
import { z as localeFilterQuery } from "../../../../media-BJ6SRY3g.mjs";
|
|
9
|
+
import { ct as updateMenuBody } from "../../../../redirects-D457qwt0.mjs";
|
|
10
|
+
import "../../../../relations-CZMpBqEd.mjs";
|
|
11
11
|
import "../../../../status-COfycGIU.mjs";
|
|
12
12
|
import "../../../../api/schemas/index.mjs";
|
|
13
|
-
import { r as requirePerm } from "../../../../authorize-
|
|
13
|
+
import { r as requirePerm } from "../../../../authorize-6WPZa1xZ.mjs";
|
|
14
14
|
|
|
15
15
|
//#region src/astro/routes/api/menus/[name].ts
|
|
16
16
|
const prerender = false;
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
import "../../../../after-B1IIdH3Y.mjs";
|
|
2
2
|
import "../../../../object-cache-Bok5j2ae.mjs";
|
|
3
3
|
import "../../../../base64-B-PsqheR.mjs";
|
|
4
|
-
import "../../../../types-
|
|
5
|
-
import { c as handleMenuList, t as handleMenuCreate } from "../../../../menus-
|
|
6
|
-
import { a as unwrapResult, r as handleError } from "../../../../error-
|
|
7
|
-
import { i as parseQuery, n as parseBody, t as isParseError } from "../../../../parse-
|
|
8
|
-
import { z as localeFilterQuery } from "../../../../media-
|
|
9
|
-
import { $ as createMenuBody } from "../../../../redirects-
|
|
10
|
-
import "../../../../relations-
|
|
4
|
+
import "../../../../types-CrRUFdej.mjs";
|
|
5
|
+
import { c as handleMenuList, t as handleMenuCreate } from "../../../../menus-BMGzWyWH.mjs";
|
|
6
|
+
import { a as unwrapResult, r as handleError } from "../../../../error-DJ98TRbQ.mjs";
|
|
7
|
+
import { i as parseQuery, n as parseBody, t as isParseError } from "../../../../parse-53zyxlpv.mjs";
|
|
8
|
+
import { z as localeFilterQuery } from "../../../../media-BJ6SRY3g.mjs";
|
|
9
|
+
import { $ as createMenuBody } from "../../../../redirects-D457qwt0.mjs";
|
|
10
|
+
import "../../../../relations-CZMpBqEd.mjs";
|
|
11
11
|
import "../../../../status-COfycGIU.mjs";
|
|
12
12
|
import "../../../../api/schemas/index.mjs";
|
|
13
|
-
import { r as requirePerm } from "../../../../authorize-
|
|
13
|
+
import { r as requirePerm } from "../../../../authorize-6WPZa1xZ.mjs";
|
|
14
14
|
|
|
15
15
|
//#region src/astro/routes/api/menus/index.ts
|
|
16
16
|
const prerender = false;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"authorize.d.mts","names":[],"sources":["../../../../../src/astro/routes/api/oauth/authorize.ts"],"mappings":";;;cA2Ba,SAAA;AAAA,
|
|
1
|
+
{"version":3,"file":"authorize.d.mts","names":[],"sources":["../../../../../src/astro/routes/api/oauth/authorize.ts"],"mappings":";;;cA2Ba,SAAA;AAAA,cA6DA,GAAA,EAAK,QAAA;AAAA,cAoGL,IAAA,EAAM,QAAA"}
|
|
@@ -26,11 +26,16 @@ function getCsrfCookie(request) {
|
|
|
26
26
|
}
|
|
27
27
|
const SCOPE_LABELS = {
|
|
28
28
|
"content:read": "Read content (posts, pages, etc.)",
|
|
29
|
-
"content:write": "Create, edit, and delete content",
|
|
29
|
+
"content:write": "Create, edit, and delete content; manage menus and taxonomies",
|
|
30
30
|
"media:read": "View media files",
|
|
31
31
|
"media:write": "Upload and manage media files",
|
|
32
32
|
"schema:read": "View collection schemas",
|
|
33
33
|
"schema:write": "Create and modify collection schemas",
|
|
34
|
+
"taxonomies:manage": "Manage taxonomies",
|
|
35
|
+
"menus:manage": "Manage navigation menus",
|
|
36
|
+
"settings:read": "View site settings",
|
|
37
|
+
"settings:manage": "Modify site settings",
|
|
38
|
+
"mcp:tools": "Use MCP tools from all enabled plugins",
|
|
34
39
|
admin: "Full administrative access"
|
|
35
40
|
};
|
|
36
41
|
const GET = async ({ url, request, locals }) => {
|
|
@@ -66,7 +71,7 @@ const GET = async ({ url, request, locals }) => {
|
|
|
66
71
|
loginUrl.searchParams.set("redirect", url.pathname + url.search);
|
|
67
72
|
return Response.redirect(loginUrl.toString(), 302);
|
|
68
73
|
}
|
|
69
|
-
const requestedScopes = (scope ?? "").split(" ").filter(Boolean).filter(isValidScope);
|
|
74
|
+
const requestedScopes = [...new Set((scope ?? "").split(" ").filter(Boolean).filter(isValidScope))];
|
|
70
75
|
if (requestedScopes.length === 0) return new Response(renderErrorPage("No valid scopes requested."), {
|
|
71
76
|
status: 400,
|
|
72
77
|
headers: { "Content-Type": "text/html; charset=utf-8" }
|
|
@@ -104,6 +109,8 @@ const POST = async ({ request, locals }) => {
|
|
|
104
109
|
const v = formData.get(name);
|
|
105
110
|
return typeof v === "string" ? v : fallback;
|
|
106
111
|
};
|
|
112
|
+
const requestedScopes = new Set((new URL(request.url).searchParams.get("scope") ?? "").split(" ").filter(Boolean).filter(isValidScope));
|
|
113
|
+
const selectedScopes = [...new Set(formData.getAll("scope").filter((value) => typeof value === "string").filter(isValidScope).filter((scope) => requestedScopes.has(scope)))];
|
|
107
114
|
const formCsrf = field("csrf_token");
|
|
108
115
|
const cookieCsrf = getCsrfCookie(request);
|
|
109
116
|
const csrfError = new Response(renderErrorPage("Invalid or missing CSRF token. Please try again."), {
|
|
@@ -152,7 +159,7 @@ const POST = async ({ request, locals }) => {
|
|
|
152
159
|
response_type: field("response_type", "code"),
|
|
153
160
|
client_id: field("client_id"),
|
|
154
161
|
redirect_uri: redirectUri,
|
|
155
|
-
scope:
|
|
162
|
+
scope: selectedScopes.join(" "),
|
|
156
163
|
state,
|
|
157
164
|
code_challenge: field("code_challenge"),
|
|
158
165
|
code_challenge_method: field("code_challenge_method", "S256"),
|
|
@@ -160,10 +167,11 @@ const POST = async ({ request, locals }) => {
|
|
|
160
167
|
});
|
|
161
168
|
if (!result.success) {
|
|
162
169
|
const errMsg = result.error?.message ?? "Authorization failed";
|
|
170
|
+
const invalidScope = result.error?.code === "INVALID_SCOPE";
|
|
163
171
|
try {
|
|
164
172
|
const errorUrl = new URL(redirectUri);
|
|
165
|
-
errorUrl.searchParams.set("error", "server_error");
|
|
166
|
-
errorUrl.searchParams.set("error_description", "Authorization failed");
|
|
173
|
+
errorUrl.searchParams.set("error", invalidScope ? "invalid_scope" : "server_error");
|
|
174
|
+
errorUrl.searchParams.set("error_description", invalidScope ? "No selected permission can be granted" : "Authorization failed");
|
|
167
175
|
if (state) errorUrl.searchParams.set("state", state);
|
|
168
176
|
return Response.redirect(errorUrl.toString(), 302);
|
|
169
177
|
} catch {
|
|
@@ -177,7 +185,8 @@ const POST = async ({ request, locals }) => {
|
|
|
177
185
|
};
|
|
178
186
|
function renderConsentPage(params) {
|
|
179
187
|
const scopeList = params.scopes.map((s) => {
|
|
180
|
-
|
|
188
|
+
const label = SCOPE_LABELS[s] ?? getPluginScopeLabel(s) ?? s;
|
|
189
|
+
return `<li><label><input type="checkbox" name="scope" value="${escapeHtml(s)}" checked><span>${escapeHtml(label)}</span></label></li>`;
|
|
181
190
|
}).join("\n");
|
|
182
191
|
return `<!DOCTYPE html>
|
|
183
192
|
<html lang="en">
|
|
@@ -196,6 +205,8 @@ function renderConsentPage(params) {
|
|
|
196
205
|
ul { list-style: none; margin-bottom: 1.5rem; }
|
|
197
206
|
li { padding: 0.5rem 0; border-bottom: 1px solid #262626; font-size: 0.875rem; }
|
|
198
207
|
li:last-child { border-bottom: none; }
|
|
208
|
+
label { display: flex; align-items: flex-start; gap: 0.625rem; cursor: pointer; }
|
|
209
|
+
input[type="checkbox"] { margin-top: 0.125rem; accent-color: #2563eb; }
|
|
199
210
|
.actions { display: flex; gap: 0.75rem; }
|
|
200
211
|
button { flex: 1; padding: 0.625rem 1rem; border-radius: 8px; border: none; font-size: 0.875rem; font-weight: 500; cursor: pointer; }
|
|
201
212
|
.approve { background: #2563eb; color: white; }
|
|
@@ -209,14 +220,13 @@ function renderConsentPage(params) {
|
|
|
209
220
|
<h1>Authorize Application</h1>
|
|
210
221
|
<p class="client-id">${escapeHtml(params.clientId)}</p>
|
|
211
222
|
<p class="user">Signed in as <strong>${escapeHtml(params.userName)}</strong></p>
|
|
212
|
-
<h2>Permissions requested</h2>
|
|
213
|
-
<ul>${scopeList}</ul>
|
|
214
223
|
<form method="POST">
|
|
224
|
+
<h2>Permissions requested</h2>
|
|
225
|
+
<ul>${scopeList}</ul>
|
|
215
226
|
<input type="hidden" name="csrf_token" value="${escapeHtml(params.csrfToken)}">
|
|
216
227
|
<input type="hidden" name="response_type" value="${escapeHtml(params.responseType)}">
|
|
217
228
|
<input type="hidden" name="client_id" value="${escapeHtml(params.clientId)}">
|
|
218
229
|
<input type="hidden" name="redirect_uri" value="${escapeHtml(params.redirectUri)}">
|
|
219
|
-
<input type="hidden" name="scope" value="${escapeHtml(params.scopes.join(" "))}">
|
|
220
230
|
<input type="hidden" name="state" value="${escapeHtml(params.state)}">
|
|
221
231
|
<input type="hidden" name="code_challenge" value="${escapeHtml(params.codeChallenge)}">
|
|
222
232
|
<input type="hidden" name="code_challenge_method" value="${escapeHtml(params.codeChallengeMethod)}">
|
|
@@ -230,6 +240,10 @@ function renderConsentPage(params) {
|
|
|
230
240
|
</body>
|
|
231
241
|
</html>`;
|
|
232
242
|
}
|
|
243
|
+
function getPluginScopeLabel(scope) {
|
|
244
|
+
const pluginId = scope.startsWith("mcp:tools:") ? scope.slice(10) : "";
|
|
245
|
+
return pluginId ? `Use MCP tools from ${pluginId}` : null;
|
|
246
|
+
}
|
|
233
247
|
function renderErrorPage(message) {
|
|
234
248
|
return `<!DOCTYPE html>
|
|
235
249
|
<html lang="en">
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"authorize.mjs","names":[],"sources":["../../../../../src/astro/routes/api/oauth/authorize.ts"],"sourcesContent":["/**\n * GET/POST /_emdash/oauth/authorize\n *\n * OAuth 2.1 Authorization Endpoint. Handles both the consent page (GET)\n * and consent submission (POST).\n *\n * GET: Renders an HTML consent page showing which client is requesting\n * access and which scopes are being requested.\n * POST: Processes the user's decision (approve/deny) and redirects\n * to the client's redirect_uri with an authorization code or error.\n *\n * Requires an authenticated session (not token auth). If unauthenticated,\n * redirects to login with a return URL.\n */\n\nimport type { APIRoute } from \"astro\";\n\nimport { escapeHtml } from \"#api/escape.js\";\nimport {\n\tbuildDeniedRedirect,\n\thandleAuthorizationApproval,\n\tvalidateRedirectUri,\n} from \"#api/handlers/oauth-authorization.js\";\nimport { lookupOAuthClient, validateClientRedirectUri } from \"#api/handlers/oauth-clients.js\";\nimport { getPublicOrigin } from \"#api/public-url.js\";\nimport { isValidScope } from \"#auth/api-tokens.js\";\n\nexport const prerender = false;\n\n// ---------------------------------------------------------------------------\n// CSRF (SEC-18): Double-submit cookie pattern\n// ---------------------------------------------------------------------------\n\nconst CSRF_COOKIE_NAME = \"emdash_oauth_csrf\";\n\n/** Generate a 32-byte random token as hex. */\nfunction generateCsrfToken(): string {\n\tconst bytes = new Uint8Array(32);\n\tcrypto.getRandomValues(bytes);\n\treturn Array.from(bytes, (b) => b.toString(16).padStart(2, \"0\")).join(\"\");\n}\n\n/** Build the Set-Cookie header value for the CSRF token. */\nfunction csrfCookieHeader(token: string, request: Request, siteUrl?: string): string {\n\t// SameSite=Strict prevents cross-site form submission.\n\t// HttpOnly: the token value is embedded in the form hidden field server-side,\n\t// so JS never needs to read the cookie. HttpOnly adds defense-in-depth.\n\t// Secure is set when:\n\t// - siteUrl is configured and uses https (proxy case — request may be http internally), OR\n\t// - the actual request is over https (non-proxy case, preserve existing behaviour)\n\tconst isSecure = siteUrl\n\t\t? siteUrl.startsWith(\"https:\")\n\t\t: new URL(request.url).protocol === \"https:\";\n\tconst secure = isSecure ? \"; Secure\" : \"\";\n\treturn `${CSRF_COOKIE_NAME}=${token}; Path=/_emdash/oauth/authorize; HttpOnly; SameSite=Strict${secure}`;\n}\n\n/** Extract the CSRF token from the request's cookies. */\nfunction getCsrfCookie(request: Request): string | null {\n\tconst cookieHeader = request.headers.get(\"Cookie\");\n\tif (!cookieHeader) return null;\n\tconst match = cookieHeader.match(new RegExp(`(?:^|;\\\\s*)${CSRF_COOKIE_NAME}=([^;]+)`));\n\treturn match?.[1] ?? null;\n}\n\n// ---------------------------------------------------------------------------\n// Human-readable scope labels\n// ---------------------------------------------------------------------------\n\nconst SCOPE_LABELS: Record<string, string> = {\n\t\"content:read\": \"Read content (posts, pages, etc.)\",\n\t\"content:write\": \"Create, edit, and delete content\",\n\t\"media:read\": \"View media files\",\n\t\"media:write\": \"Upload and manage media files\",\n\t\"schema:read\": \"View collection schemas\",\n\t\"schema:write\": \"Create and modify collection schemas\",\n\tadmin: \"Full administrative access\",\n};\n\n// ---------------------------------------------------------------------------\n// GET: Render consent page\n// ---------------------------------------------------------------------------\n\nexport const GET: APIRoute = async ({ url, request, locals }) => {\n\tconst { emdash, user } = locals;\n\n\t// Validate required OAuth params before rendering\n\tconst clientId = url.searchParams.get(\"client_id\");\n\tconst redirectUri = url.searchParams.get(\"redirect_uri\");\n\tconst responseType = url.searchParams.get(\"response_type\");\n\tconst codeChallenge = url.searchParams.get(\"code_challenge\");\n\tconst codeChallengeMethod = url.searchParams.get(\"code_challenge_method\");\n\tconst scope = url.searchParams.get(\"scope\");\n\tconst state = url.searchParams.get(\"state\");\n\n\t// Basic validation — detailed validation happens on POST\n\tif (!clientId || !redirectUri || responseType !== \"code\" || !codeChallenge) {\n\t\treturn new Response(\n\t\t\trenderErrorPage(\"Invalid authorization request. Missing required parameters.\"),\n\t\t\t{\n\t\t\t\tstatus: 400,\n\t\t\t\theaders: { \"Content-Type\": \"text/html; charset=utf-8\" },\n\t\t\t},\n\t\t);\n\t}\n\n\tif (codeChallengeMethod && codeChallengeMethod !== \"S256\") {\n\t\treturn new Response(renderErrorPage(\"Only S256 code challenge method is supported.\"), {\n\t\t\tstatus: 400,\n\t\t\theaders: { \"Content-Type\": \"text/html; charset=utf-8\" },\n\t\t});\n\t}\n\n\t// Validate client_id is registered and redirect_uri is in the allowlist.\n\t// This check happens BEFORE authentication so we never redirect to an\n\t// unregistered URI (even for the login redirect, we only redirect to our\n\t// own login page, not to the client's redirect_uri).\n\tif (emdash?.db) {\n\t\tconst client = await lookupOAuthClient(emdash.db, clientId);\n\t\tif (!client) {\n\t\t\treturn new Response(renderErrorPage(\"Unknown client application.\"), {\n\t\t\t\tstatus: 400,\n\t\t\t\theaders: { \"Content-Type\": \"text/html; charset=utf-8\" },\n\t\t\t});\n\t\t}\n\n\t\tconst clientUriError = validateClientRedirectUri(redirectUri, client.redirectUris);\n\t\tif (clientUriError) {\n\t\t\treturn new Response(renderErrorPage(\"The redirect URI is not registered for this client.\"), {\n\t\t\t\tstatus: 400,\n\t\t\t\theaders: { \"Content-Type\": \"text/html; charset=utf-8\" },\n\t\t\t});\n\t\t}\n\t}\n\n\t// If not authenticated, redirect to login with return URL\n\tif (!user) {\n\t\tconst loginUrl = new URL(\"/_emdash/admin/login\", getPublicOrigin(url, emdash?.config));\n\t\tloginUrl.searchParams.set(\"redirect\", url.pathname + url.search);\n\t\treturn Response.redirect(loginUrl.toString(), 302);\n\t}\n\n\t// Parse and validate scopes\n\tconst requestedScopes = (scope ?? \"\").split(\" \").filter(Boolean).filter(isValidScope);\n\n\tif (requestedScopes.length === 0) {\n\t\treturn new Response(renderErrorPage(\"No valid scopes requested.\"), {\n\t\t\tstatus: 400,\n\t\t\theaders: { \"Content-Type\": \"text/html; charset=utf-8\" },\n\t\t});\n\t}\n\n\t// SEC-18: Generate CSRF token for the consent form (double-submit cookie pattern)\n\tconst csrfToken = generateCsrfToken();\n\n\t// Render the consent page\n\tconst html = renderConsentPage({\n\t\tclientId,\n\t\tscopes: requestedScopes,\n\t\tredirectUri,\n\t\tresponseType,\n\t\tcodeChallenge,\n\t\tcodeChallengeMethod: codeChallengeMethod ?? \"S256\",\n\t\tstate: state ?? \"\",\n\t\tresource: url.searchParams.get(\"resource\") ?? \"\",\n\t\tuserName: user.name ?? user.email,\n\t\tcsrfToken,\n\t});\n\n\treturn new Response(html, {\n\t\theaders: {\n\t\t\t\"Content-Type\": \"text/html; charset=utf-8\",\n\t\t\t\"Set-Cookie\": csrfCookieHeader(csrfToken, request, getPublicOrigin(url, emdash?.config)),\n\t\t},\n\t});\n};\n\n// ---------------------------------------------------------------------------\n// POST: Process consent\n// ---------------------------------------------------------------------------\n\nexport const POST: APIRoute = async ({ request, locals }) => {\n\tconst { emdash, user } = locals;\n\n\tif (!emdash?.db) {\n\t\treturn new Response(renderErrorPage(\"EmDash is not initialized.\"), {\n\t\t\tstatus: 500,\n\t\t\theaders: { \"Content-Type\": \"text/html; charset=utf-8\" },\n\t\t});\n\t}\n\n\tif (!user) {\n\t\treturn new Response(renderErrorPage(\"Authentication required.\"), {\n\t\t\tstatus: 401,\n\t\t\theaders: { \"Content-Type\": \"text/html; charset=utf-8\" },\n\t\t});\n\t}\n\n\tconst formData = await request.formData();\n\tconst field = (name: string, fallback = \"\"): string => {\n\t\tconst v = formData.get(name);\n\t\treturn typeof v === \"string\" ? v : fallback;\n\t};\n\n\t// SEC-18: Validate CSRF token (double-submit cookie pattern).\n\t// The form includes a hidden csrf_token field; the cookie has the same value.\n\t// An attacker cannot read the cookie to forge the form field (HttpOnly + SameSite=Strict).\n\tconst formCsrf = field(\"csrf_token\");\n\tconst cookieCsrf = getCsrfCookie(request);\n\tconst csrfError = new Response(\n\t\trenderErrorPage(\"Invalid or missing CSRF token. Please try again.\"),\n\t\t{ status: 403, headers: { \"Content-Type\": \"text/html; charset=utf-8\" } },\n\t);\n\tif (!formCsrf || !cookieCsrf) return csrfError;\n\n\t// Constant-time comparison: hash both values to fixed-length 32-byte digests,\n\t// then XOR every byte pair. This avoids crypto.subtle.timingSafeEqual which is\n\t// a Cloudflare Workers extension and doesn't exist in Node.js.\n\t// The SHA-256 pre-hash ensures fixed length, eliminating length-leaking.\n\tconst csrfEncoder = new TextEncoder();\n\tconst [csrfHashA, csrfHashB] = await Promise.all([\n\t\tcrypto.subtle.digest(\"SHA-256\", csrfEncoder.encode(formCsrf)),\n\t\tcrypto.subtle.digest(\"SHA-256\", csrfEncoder.encode(cookieCsrf)),\n\t]);\n\tconst a = new Uint8Array(csrfHashA);\n\tconst b = new Uint8Array(csrfHashB);\n\tlet diff = 0;\n\t// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion -- tsgo needs these\n\tfor (let i = 0; i < a.length; i++) diff |= a[i]! ^ b[i]!;\n\tif (diff !== 0) return csrfError;\n\n\tconst action = field(\"action\");\n\tconst redirectUri = field(\"redirect_uri\");\n\tconst state = field(\"state\") || undefined;\n\n\tif (!redirectUri) {\n\t\treturn new Response(renderErrorPage(\"Missing redirect_uri.\"), {\n\t\t\tstatus: 400,\n\t\t\theaders: { \"Content-Type\": \"text/html; charset=utf-8\" },\n\t\t});\n\t}\n\n\t// Validate redirect_uri scheme/host before using it for any redirect\n\tconst uriError = validateRedirectUri(redirectUri);\n\tif (uriError) {\n\t\treturn new Response(renderErrorPage(escapeHtml(uriError)), {\n\t\t\tstatus: 400,\n\t\t\theaders: { \"Content-Type\": \"text/html; charset=utf-8\" },\n\t\t});\n\t}\n\n\t// User denied — SEC-44: validate redirect_uri against client's registered URIs\n\t// before redirecting, to prevent open redirect on the deny path.\n\tif (action === \"deny\") {\n\t\tconst clientId = field(\"client_id\");\n\t\tif (!clientId) {\n\t\t\treturn new Response(renderErrorPage(\"Missing client_id.\"), {\n\t\t\t\tstatus: 400,\n\t\t\t\theaders: { \"Content-Type\": \"text/html; charset=utf-8\" },\n\t\t\t});\n\t\t}\n\n\t\tconst client = await lookupOAuthClient(emdash.db, clientId);\n\t\tif (!client) {\n\t\t\treturn new Response(renderErrorPage(\"Unknown client application.\"), {\n\t\t\t\tstatus: 400,\n\t\t\t\theaders: { \"Content-Type\": \"text/html; charset=utf-8\" },\n\t\t\t});\n\t\t}\n\n\t\tconst clientUriError = validateClientRedirectUri(redirectUri, client.redirectUris);\n\t\tif (clientUriError) {\n\t\t\treturn new Response(renderErrorPage(\"The redirect URI is not registered for this client.\"), {\n\t\t\t\tstatus: 400,\n\t\t\t\theaders: { \"Content-Type\": \"text/html; charset=utf-8\" },\n\t\t\t});\n\t\t}\n\n\t\tconst denyUrl = buildDeniedRedirect(redirectUri, state);\n\t\treturn Response.redirect(denyUrl, 302);\n\t}\n\n\t// User approved — process the authorization\n\tconst result = await handleAuthorizationApproval(emdash.db, user.id, user.role, {\n\t\tresponse_type: field(\"response_type\", \"code\"),\n\t\tclient_id: field(\"client_id\"),\n\t\tredirect_uri: redirectUri,\n\t\tscope: field(\"scope\"),\n\t\tstate,\n\t\tcode_challenge: field(\"code_challenge\"),\n\t\tcode_challenge_method: field(\"code_challenge_method\", \"S256\"),\n\t\tresource: field(\"resource\") || undefined,\n\t});\n\n\tif (!result.success) {\n\t\tconst errMsg = result.error?.message ?? \"Authorization failed\";\n\t\t// On error, redirect back with error params — use generic description to avoid\n\t\t// leaking internal error details to the (already-validated) redirect target\n\t\ttry {\n\t\t\tconst errorUrl = new URL(redirectUri);\n\t\t\terrorUrl.searchParams.set(\"error\", \"server_error\");\n\t\t\terrorUrl.searchParams.set(\"error_description\", \"Authorization failed\");\n\t\t\tif (state) errorUrl.searchParams.set(\"state\", state);\n\t\t\treturn Response.redirect(errorUrl.toString(), 302);\n\t\t} catch {\n\t\t\treturn new Response(renderErrorPage(escapeHtml(errMsg)), {\n\t\t\t\tstatus: 400,\n\t\t\t\theaders: { \"Content-Type\": \"text/html; charset=utf-8\" },\n\t\t\t});\n\t\t}\n\t}\n\n\treturn Response.redirect(result.data.redirect_url, 302);\n};\n\n// ---------------------------------------------------------------------------\n// HTML rendering\n// ---------------------------------------------------------------------------\n\nfunction renderConsentPage(params: {\n\tclientId: string;\n\tscopes: string[];\n\tredirectUri: string;\n\tresponseType: string;\n\tcodeChallenge: string;\n\tcodeChallengeMethod: string;\n\tstate: string;\n\tresource: string;\n\tuserName: string;\n\tcsrfToken: string;\n}): string {\n\tconst scopeList = params.scopes\n\t\t.map((s) => {\n\t\t\tconst label = SCOPE_LABELS[s] ?? s;\n\t\t\treturn `<li>${escapeHtml(label)}</li>`;\n\t\t})\n\t\t.join(\"\\n\");\n\n\treturn `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n<meta charset=\"utf-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n<title>Authorize Application — EmDash</title>\n<style>\n * { margin: 0; padding: 0; box-sizing: border-box; }\n body { font-family: system-ui, -apple-system, sans-serif; background: #0a0a0a; color: #e5e5e5; display: flex; justify-content: center; align-items: center; min-height: 100vh; padding: 1rem; }\n .card { background: #171717; border: 1px solid #262626; border-radius: 12px; max-width: 420px; width: 100%; padding: 2rem; }\n h1 { font-size: 1.25rem; font-weight: 600; margin-bottom: 0.5rem; }\n .client-id { color: #a3a3a3; font-size: 0.875rem; word-break: break-all; margin-bottom: 1.5rem; }\n .user { color: #a3a3a3; font-size: 0.875rem; margin-bottom: 1rem; }\n h2 { font-size: 0.875rem; font-weight: 500; color: #a3a3a3; text-transform: uppercase; letter-spacing: 0.05em; margin-bottom: 0.75rem; }\n ul { list-style: none; margin-bottom: 1.5rem; }\n li { padding: 0.5rem 0; border-bottom: 1px solid #262626; font-size: 0.875rem; }\n li:last-child { border-bottom: none; }\n .actions { display: flex; gap: 0.75rem; }\n button { flex: 1; padding: 0.625rem 1rem; border-radius: 8px; border: none; font-size: 0.875rem; font-weight: 500; cursor: pointer; }\n .approve { background: #2563eb; color: white; }\n .approve:hover { background: #1d4ed8; }\n .deny { background: #262626; color: #e5e5e5; }\n .deny:hover { background: #333; }\n</style>\n</head>\n<body>\n<div class=\"card\">\n <h1>Authorize Application</h1>\n <p class=\"client-id\">${escapeHtml(params.clientId)}</p>\n <p class=\"user\">Signed in as <strong>${escapeHtml(params.userName)}</strong></p>\n <h2>Permissions requested</h2>\n <ul>${scopeList}</ul>\n <form method=\"POST\">\n <input type=\"hidden\" name=\"csrf_token\" value=\"${escapeHtml(params.csrfToken)}\">\n <input type=\"hidden\" name=\"response_type\" value=\"${escapeHtml(params.responseType)}\">\n <input type=\"hidden\" name=\"client_id\" value=\"${escapeHtml(params.clientId)}\">\n <input type=\"hidden\" name=\"redirect_uri\" value=\"${escapeHtml(params.redirectUri)}\">\n <input type=\"hidden\" name=\"scope\" value=\"${escapeHtml(params.scopes.join(\" \"))}\">\n <input type=\"hidden\" name=\"state\" value=\"${escapeHtml(params.state)}\">\n <input type=\"hidden\" name=\"code_challenge\" value=\"${escapeHtml(params.codeChallenge)}\">\n <input type=\"hidden\" name=\"code_challenge_method\" value=\"${escapeHtml(params.codeChallengeMethod)}\">\n <input type=\"hidden\" name=\"resource\" value=\"${escapeHtml(params.resource)}\">\n <div class=\"actions\">\n <button type=\"submit\" name=\"action\" value=\"deny\" class=\"deny\">Deny</button>\n <button type=\"submit\" name=\"action\" value=\"approve\" class=\"approve\">Approve</button>\n </div>\n </form>\n</div>\n</body>\n</html>`;\n}\n\nfunction renderErrorPage(message: string): string {\n\treturn `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n<meta charset=\"utf-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n<title>Authorization Error — EmDash</title>\n<style>\n * { margin: 0; padding: 0; box-sizing: border-box; }\n body { font-family: system-ui, -apple-system, sans-serif; background: #0a0a0a; color: #e5e5e5; display: flex; justify-content: center; align-items: center; min-height: 100vh; padding: 1rem; }\n .card { background: #171717; border: 1px solid #262626; border-radius: 12px; max-width: 420px; width: 100%; padding: 2rem; }\n h1 { font-size: 1.25rem; font-weight: 600; margin-bottom: 1rem; color: #ef4444; }\n p { font-size: 0.875rem; color: #a3a3a3; }\n</style>\n</head>\n<body>\n<div class=\"card\">\n <h1>Authorization Error</h1>\n <p>${escapeHtml(message)}</p>\n</div>\n</body>\n</html>`;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"authorize.mjs","names":[],"sources":["../../../../../src/astro/routes/api/oauth/authorize.ts"],"sourcesContent":["/**\n * GET/POST /_emdash/oauth/authorize\n *\n * OAuth 2.1 Authorization Endpoint. Handles both the consent page (GET)\n * and consent submission (POST).\n *\n * GET: Renders an HTML consent page showing which client is requesting\n * access and which scopes are being requested.\n * POST: Processes the user's decision (approve/deny) and redirects\n * to the client's redirect_uri with an authorization code or error.\n *\n * Requires an authenticated session (not token auth). If unauthenticated,\n * redirects to login with a return URL.\n */\n\nimport type { APIRoute } from \"astro\";\n\nimport { escapeHtml } from \"#api/escape.js\";\nimport {\n\tbuildDeniedRedirect,\n\thandleAuthorizationApproval,\n\tvalidateRedirectUri,\n} from \"#api/handlers/oauth-authorization.js\";\nimport { lookupOAuthClient, validateClientRedirectUri } from \"#api/handlers/oauth-clients.js\";\nimport { getPublicOrigin } from \"#api/public-url.js\";\nimport { isValidScope } from \"#auth/api-tokens.js\";\n\nexport const prerender = false;\n\n// ---------------------------------------------------------------------------\n// CSRF (SEC-18): Double-submit cookie pattern\n// ---------------------------------------------------------------------------\n\nconst CSRF_COOKIE_NAME = \"emdash_oauth_csrf\";\n\n/** Generate a 32-byte random token as hex. */\nfunction generateCsrfToken(): string {\n\tconst bytes = new Uint8Array(32);\n\tcrypto.getRandomValues(bytes);\n\treturn Array.from(bytes, (b) => b.toString(16).padStart(2, \"0\")).join(\"\");\n}\n\n/** Build the Set-Cookie header value for the CSRF token. */\nfunction csrfCookieHeader(token: string, request: Request, siteUrl?: string): string {\n\t// SameSite=Strict prevents cross-site form submission.\n\t// HttpOnly: the token value is embedded in the form hidden field server-side,\n\t// so JS never needs to read the cookie. HttpOnly adds defense-in-depth.\n\t// Secure is set when:\n\t// - siteUrl is configured and uses https (proxy case — request may be http internally), OR\n\t// - the actual request is over https (non-proxy case, preserve existing behaviour)\n\tconst isSecure = siteUrl\n\t\t? siteUrl.startsWith(\"https:\")\n\t\t: new URL(request.url).protocol === \"https:\";\n\tconst secure = isSecure ? \"; Secure\" : \"\";\n\treturn `${CSRF_COOKIE_NAME}=${token}; Path=/_emdash/oauth/authorize; HttpOnly; SameSite=Strict${secure}`;\n}\n\n/** Extract the CSRF token from the request's cookies. */\nfunction getCsrfCookie(request: Request): string | null {\n\tconst cookieHeader = request.headers.get(\"Cookie\");\n\tif (!cookieHeader) return null;\n\tconst match = cookieHeader.match(new RegExp(`(?:^|;\\\\s*)${CSRF_COOKIE_NAME}=([^;]+)`));\n\treturn match?.[1] ?? null;\n}\n\n// ---------------------------------------------------------------------------\n// Human-readable scope labels\n// ---------------------------------------------------------------------------\n\nconst SCOPE_LABELS: Record<string, string> = {\n\t\"content:read\": \"Read content (posts, pages, etc.)\",\n\t\"content:write\": \"Create, edit, and delete content; manage menus and taxonomies\",\n\t\"media:read\": \"View media files\",\n\t\"media:write\": \"Upload and manage media files\",\n\t\"schema:read\": \"View collection schemas\",\n\t\"schema:write\": \"Create and modify collection schemas\",\n\t\"taxonomies:manage\": \"Manage taxonomies\",\n\t\"menus:manage\": \"Manage navigation menus\",\n\t\"settings:read\": \"View site settings\",\n\t\"settings:manage\": \"Modify site settings\",\n\t\"mcp:tools\": \"Use MCP tools from all enabled plugins\",\n\tadmin: \"Full administrative access\",\n};\n\n// ---------------------------------------------------------------------------\n// GET: Render consent page\n// ---------------------------------------------------------------------------\n\nexport const GET: APIRoute = async ({ url, request, locals }) => {\n\tconst { emdash, user } = locals;\n\n\t// Validate required OAuth params before rendering\n\tconst clientId = url.searchParams.get(\"client_id\");\n\tconst redirectUri = url.searchParams.get(\"redirect_uri\");\n\tconst responseType = url.searchParams.get(\"response_type\");\n\tconst codeChallenge = url.searchParams.get(\"code_challenge\");\n\tconst codeChallengeMethod = url.searchParams.get(\"code_challenge_method\");\n\tconst scope = url.searchParams.get(\"scope\");\n\tconst state = url.searchParams.get(\"state\");\n\n\t// Basic validation — detailed validation happens on POST\n\tif (!clientId || !redirectUri || responseType !== \"code\" || !codeChallenge) {\n\t\treturn new Response(\n\t\t\trenderErrorPage(\"Invalid authorization request. Missing required parameters.\"),\n\t\t\t{\n\t\t\t\tstatus: 400,\n\t\t\t\theaders: { \"Content-Type\": \"text/html; charset=utf-8\" },\n\t\t\t},\n\t\t);\n\t}\n\n\tif (codeChallengeMethod && codeChallengeMethod !== \"S256\") {\n\t\treturn new Response(renderErrorPage(\"Only S256 code challenge method is supported.\"), {\n\t\t\tstatus: 400,\n\t\t\theaders: { \"Content-Type\": \"text/html; charset=utf-8\" },\n\t\t});\n\t}\n\n\t// Validate client_id is registered and redirect_uri is in the allowlist.\n\t// This check happens BEFORE authentication so we never redirect to an\n\t// unregistered URI (even for the login redirect, we only redirect to our\n\t// own login page, not to the client's redirect_uri).\n\tif (emdash?.db) {\n\t\tconst client = await lookupOAuthClient(emdash.db, clientId);\n\t\tif (!client) {\n\t\t\treturn new Response(renderErrorPage(\"Unknown client application.\"), {\n\t\t\t\tstatus: 400,\n\t\t\t\theaders: { \"Content-Type\": \"text/html; charset=utf-8\" },\n\t\t\t});\n\t\t}\n\n\t\tconst clientUriError = validateClientRedirectUri(redirectUri, client.redirectUris);\n\t\tif (clientUriError) {\n\t\t\treturn new Response(renderErrorPage(\"The redirect URI is not registered for this client.\"), {\n\t\t\t\tstatus: 400,\n\t\t\t\theaders: { \"Content-Type\": \"text/html; charset=utf-8\" },\n\t\t\t});\n\t\t}\n\t}\n\n\t// If not authenticated, redirect to login with return URL\n\tif (!user) {\n\t\tconst loginUrl = new URL(\"/_emdash/admin/login\", getPublicOrigin(url, emdash?.config));\n\t\tloginUrl.searchParams.set(\"redirect\", url.pathname + url.search);\n\t\treturn Response.redirect(loginUrl.toString(), 302);\n\t}\n\n\t// Parse and validate scopes\n\tconst requestedScopes = [\n\t\t...new Set((scope ?? \"\").split(\" \").filter(Boolean).filter(isValidScope)),\n\t];\n\n\tif (requestedScopes.length === 0) {\n\t\treturn new Response(renderErrorPage(\"No valid scopes requested.\"), {\n\t\t\tstatus: 400,\n\t\t\theaders: { \"Content-Type\": \"text/html; charset=utf-8\" },\n\t\t});\n\t}\n\n\t// SEC-18: Generate CSRF token for the consent form (double-submit cookie pattern)\n\tconst csrfToken = generateCsrfToken();\n\n\t// Render the consent page\n\tconst html = renderConsentPage({\n\t\tclientId,\n\t\tscopes: requestedScopes,\n\t\tredirectUri,\n\t\tresponseType,\n\t\tcodeChallenge,\n\t\tcodeChallengeMethod: codeChallengeMethod ?? \"S256\",\n\t\tstate: state ?? \"\",\n\t\tresource: url.searchParams.get(\"resource\") ?? \"\",\n\t\tuserName: user.name ?? user.email,\n\t\tcsrfToken,\n\t});\n\n\treturn new Response(html, {\n\t\theaders: {\n\t\t\t\"Content-Type\": \"text/html; charset=utf-8\",\n\t\t\t\"Set-Cookie\": csrfCookieHeader(csrfToken, request, getPublicOrigin(url, emdash?.config)),\n\t\t},\n\t});\n};\n\n// ---------------------------------------------------------------------------\n// POST: Process consent\n// ---------------------------------------------------------------------------\n\nexport const POST: APIRoute = async ({ request, locals }) => {\n\tconst { emdash, user } = locals;\n\n\tif (!emdash?.db) {\n\t\treturn new Response(renderErrorPage(\"EmDash is not initialized.\"), {\n\t\t\tstatus: 500,\n\t\t\theaders: { \"Content-Type\": \"text/html; charset=utf-8\" },\n\t\t});\n\t}\n\n\tif (!user) {\n\t\treturn new Response(renderErrorPage(\"Authentication required.\"), {\n\t\t\tstatus: 401,\n\t\t\theaders: { \"Content-Type\": \"text/html; charset=utf-8\" },\n\t\t});\n\t}\n\n\tconst formData = await request.formData();\n\tconst field = (name: string, fallback = \"\"): string => {\n\t\tconst v = formData.get(name);\n\t\treturn typeof v === \"string\" ? v : fallback;\n\t};\n\tconst requestedScopes = new Set(\n\t\t(new URL(request.url).searchParams.get(\"scope\") ?? \"\")\n\t\t\t.split(\" \")\n\t\t\t.filter(Boolean)\n\t\t\t.filter(isValidScope),\n\t);\n\tconst selectedScopes = [\n\t\t...new Set(\n\t\t\tformData\n\t\t\t\t.getAll(\"scope\")\n\t\t\t\t.filter((value): value is string => typeof value === \"string\")\n\t\t\t\t.filter(isValidScope)\n\t\t\t\t.filter((scope) => requestedScopes.has(scope)),\n\t\t),\n\t];\n\n\t// SEC-18: Validate CSRF token (double-submit cookie pattern).\n\t// The form includes a hidden csrf_token field; the cookie has the same value.\n\t// An attacker cannot read the cookie to forge the form field (HttpOnly + SameSite=Strict).\n\tconst formCsrf = field(\"csrf_token\");\n\tconst cookieCsrf = getCsrfCookie(request);\n\tconst csrfError = new Response(\n\t\trenderErrorPage(\"Invalid or missing CSRF token. Please try again.\"),\n\t\t{ status: 403, headers: { \"Content-Type\": \"text/html; charset=utf-8\" } },\n\t);\n\tif (!formCsrf || !cookieCsrf) return csrfError;\n\n\t// Constant-time comparison: hash both values to fixed-length 32-byte digests,\n\t// then XOR every byte pair. This avoids crypto.subtle.timingSafeEqual which is\n\t// a Cloudflare Workers extension and doesn't exist in Node.js.\n\t// The SHA-256 pre-hash ensures fixed length, eliminating length-leaking.\n\tconst csrfEncoder = new TextEncoder();\n\tconst [csrfHashA, csrfHashB] = await Promise.all([\n\t\tcrypto.subtle.digest(\"SHA-256\", csrfEncoder.encode(formCsrf)),\n\t\tcrypto.subtle.digest(\"SHA-256\", csrfEncoder.encode(cookieCsrf)),\n\t]);\n\tconst a = new Uint8Array(csrfHashA);\n\tconst b = new Uint8Array(csrfHashB);\n\tlet diff = 0;\n\t// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion -- tsgo needs these\n\tfor (let i = 0; i < a.length; i++) diff |= a[i]! ^ b[i]!;\n\tif (diff !== 0) return csrfError;\n\n\tconst action = field(\"action\");\n\tconst redirectUri = field(\"redirect_uri\");\n\tconst state = field(\"state\") || undefined;\n\n\tif (!redirectUri) {\n\t\treturn new Response(renderErrorPage(\"Missing redirect_uri.\"), {\n\t\t\tstatus: 400,\n\t\t\theaders: { \"Content-Type\": \"text/html; charset=utf-8\" },\n\t\t});\n\t}\n\n\t// Validate redirect_uri scheme/host before using it for any redirect\n\tconst uriError = validateRedirectUri(redirectUri);\n\tif (uriError) {\n\t\treturn new Response(renderErrorPage(escapeHtml(uriError)), {\n\t\t\tstatus: 400,\n\t\t\theaders: { \"Content-Type\": \"text/html; charset=utf-8\" },\n\t\t});\n\t}\n\n\t// User denied — SEC-44: validate redirect_uri against client's registered URIs\n\t// before redirecting, to prevent open redirect on the deny path.\n\tif (action === \"deny\") {\n\t\tconst clientId = field(\"client_id\");\n\t\tif (!clientId) {\n\t\t\treturn new Response(renderErrorPage(\"Missing client_id.\"), {\n\t\t\t\tstatus: 400,\n\t\t\t\theaders: { \"Content-Type\": \"text/html; charset=utf-8\" },\n\t\t\t});\n\t\t}\n\n\t\tconst client = await lookupOAuthClient(emdash.db, clientId);\n\t\tif (!client) {\n\t\t\treturn new Response(renderErrorPage(\"Unknown client application.\"), {\n\t\t\t\tstatus: 400,\n\t\t\t\theaders: { \"Content-Type\": \"text/html; charset=utf-8\" },\n\t\t\t});\n\t\t}\n\n\t\tconst clientUriError = validateClientRedirectUri(redirectUri, client.redirectUris);\n\t\tif (clientUriError) {\n\t\t\treturn new Response(renderErrorPage(\"The redirect URI is not registered for this client.\"), {\n\t\t\t\tstatus: 400,\n\t\t\t\theaders: { \"Content-Type\": \"text/html; charset=utf-8\" },\n\t\t\t});\n\t\t}\n\n\t\tconst denyUrl = buildDeniedRedirect(redirectUri, state);\n\t\treturn Response.redirect(denyUrl, 302);\n\t}\n\n\t// User approved — process the authorization\n\tconst result = await handleAuthorizationApproval(emdash.db, user.id, user.role, {\n\t\tresponse_type: field(\"response_type\", \"code\"),\n\t\tclient_id: field(\"client_id\"),\n\t\tredirect_uri: redirectUri,\n\t\tscope: selectedScopes.join(\" \"),\n\t\tstate,\n\t\tcode_challenge: field(\"code_challenge\"),\n\t\tcode_challenge_method: field(\"code_challenge_method\", \"S256\"),\n\t\tresource: field(\"resource\") || undefined,\n\t});\n\n\tif (!result.success) {\n\t\tconst errMsg = result.error?.message ?? \"Authorization failed\";\n\t\tconst invalidScope = result.error?.code === \"INVALID_SCOPE\";\n\t\t// On error, redirect back with error params — use generic description to avoid\n\t\t// leaking internal error details to the (already-validated) redirect target\n\t\ttry {\n\t\t\tconst errorUrl = new URL(redirectUri);\n\t\t\terrorUrl.searchParams.set(\"error\", invalidScope ? \"invalid_scope\" : \"server_error\");\n\t\t\terrorUrl.searchParams.set(\n\t\t\t\t\"error_description\",\n\t\t\t\tinvalidScope ? \"No selected permission can be granted\" : \"Authorization failed\",\n\t\t\t);\n\t\t\tif (state) errorUrl.searchParams.set(\"state\", state);\n\t\t\treturn Response.redirect(errorUrl.toString(), 302);\n\t\t} catch {\n\t\t\treturn new Response(renderErrorPage(escapeHtml(errMsg)), {\n\t\t\t\tstatus: 400,\n\t\t\t\theaders: { \"Content-Type\": \"text/html; charset=utf-8\" },\n\t\t\t});\n\t\t}\n\t}\n\n\treturn Response.redirect(result.data.redirect_url, 302);\n};\n\n// ---------------------------------------------------------------------------\n// HTML rendering\n// ---------------------------------------------------------------------------\n\nfunction renderConsentPage(params: {\n\tclientId: string;\n\tscopes: string[];\n\tredirectUri: string;\n\tresponseType: string;\n\tcodeChallenge: string;\n\tcodeChallengeMethod: string;\n\tstate: string;\n\tresource: string;\n\tuserName: string;\n\tcsrfToken: string;\n}): string {\n\tconst scopeList = params.scopes\n\t\t.map((s) => {\n\t\t\tconst label = SCOPE_LABELS[s] ?? getPluginScopeLabel(s) ?? s;\n\t\t\treturn `<li><label><input type=\"checkbox\" name=\"scope\" value=\"${escapeHtml(s)}\" checked><span>${escapeHtml(label)}</span></label></li>`;\n\t\t})\n\t\t.join(\"\\n\");\n\n\treturn `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n<meta charset=\"utf-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n<title>Authorize Application — EmDash</title>\n<style>\n * { margin: 0; padding: 0; box-sizing: border-box; }\n body { font-family: system-ui, -apple-system, sans-serif; background: #0a0a0a; color: #e5e5e5; display: flex; justify-content: center; align-items: center; min-height: 100vh; padding: 1rem; }\n .card { background: #171717; border: 1px solid #262626; border-radius: 12px; max-width: 420px; width: 100%; padding: 2rem; }\n h1 { font-size: 1.25rem; font-weight: 600; margin-bottom: 0.5rem; }\n .client-id { color: #a3a3a3; font-size: 0.875rem; word-break: break-all; margin-bottom: 1.5rem; }\n .user { color: #a3a3a3; font-size: 0.875rem; margin-bottom: 1rem; }\n h2 { font-size: 0.875rem; font-weight: 500; color: #a3a3a3; text-transform: uppercase; letter-spacing: 0.05em; margin-bottom: 0.75rem; }\n ul { list-style: none; margin-bottom: 1.5rem; }\n li { padding: 0.5rem 0; border-bottom: 1px solid #262626; font-size: 0.875rem; }\n li:last-child { border-bottom: none; }\n label { display: flex; align-items: flex-start; gap: 0.625rem; cursor: pointer; }\n input[type=\"checkbox\"] { margin-top: 0.125rem; accent-color: #2563eb; }\n .actions { display: flex; gap: 0.75rem; }\n button { flex: 1; padding: 0.625rem 1rem; border-radius: 8px; border: none; font-size: 0.875rem; font-weight: 500; cursor: pointer; }\n .approve { background: #2563eb; color: white; }\n .approve:hover { background: #1d4ed8; }\n .deny { background: #262626; color: #e5e5e5; }\n .deny:hover { background: #333; }\n</style>\n</head>\n<body>\n<div class=\"card\">\n <h1>Authorize Application</h1>\n <p class=\"client-id\">${escapeHtml(params.clientId)}</p>\n <p class=\"user\">Signed in as <strong>${escapeHtml(params.userName)}</strong></p>\n <form method=\"POST\">\n <h2>Permissions requested</h2>\n <ul>${scopeList}</ul>\n <input type=\"hidden\" name=\"csrf_token\" value=\"${escapeHtml(params.csrfToken)}\">\n <input type=\"hidden\" name=\"response_type\" value=\"${escapeHtml(params.responseType)}\">\n <input type=\"hidden\" name=\"client_id\" value=\"${escapeHtml(params.clientId)}\">\n <input type=\"hidden\" name=\"redirect_uri\" value=\"${escapeHtml(params.redirectUri)}\">\n <input type=\"hidden\" name=\"state\" value=\"${escapeHtml(params.state)}\">\n <input type=\"hidden\" name=\"code_challenge\" value=\"${escapeHtml(params.codeChallenge)}\">\n <input type=\"hidden\" name=\"code_challenge_method\" value=\"${escapeHtml(params.codeChallengeMethod)}\">\n <input type=\"hidden\" name=\"resource\" value=\"${escapeHtml(params.resource)}\">\n <div class=\"actions\">\n <button type=\"submit\" name=\"action\" value=\"deny\" class=\"deny\">Deny</button>\n <button type=\"submit\" name=\"action\" value=\"approve\" class=\"approve\">Approve</button>\n </div>\n </form>\n</div>\n</body>\n</html>`;\n}\n\nfunction getPluginScopeLabel(scope: string): string | null {\n\tconst pluginId = scope.startsWith(\"mcp:tools:\") ? scope.slice(\"mcp:tools:\".length) : \"\";\n\treturn pluginId ? `Use MCP tools from ${pluginId}` : null;\n}\n\nfunction renderErrorPage(message: string): string {\n\treturn `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n<meta charset=\"utf-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n<title>Authorization Error — EmDash</title>\n<style>\n * { margin: 0; padding: 0; box-sizing: border-box; }\n body { font-family: system-ui, -apple-system, sans-serif; background: #0a0a0a; color: #e5e5e5; display: flex; justify-content: center; align-items: center; min-height: 100vh; padding: 1rem; }\n .card { background: #171717; border: 1px solid #262626; border-radius: 12px; max-width: 420px; width: 100%; padding: 2rem; }\n h1 { font-size: 1.25rem; font-weight: 600; margin-bottom: 1rem; color: #ef4444; }\n p { font-size: 0.875rem; color: #a3a3a3; }\n</style>\n</head>\n<body>\n<div class=\"card\">\n <h1>Authorization Error</h1>\n <p>${escapeHtml(message)}</p>\n</div>\n</body>\n</html>`;\n}\n"],"mappings":"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"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import "../../../../../base64-B-PsqheR.mjs";
|
|
2
|
-
import "../../../../../types-
|
|
3
|
-
import { a as unwrapResult, r as handleError, t as apiError } from "../../../../../error-
|
|
4
|
-
import { n as parseBody, t as isParseError } from "../../../../../parse-
|
|
2
|
+
import "../../../../../types-CrRUFdej.mjs";
|
|
3
|
+
import { a as unwrapResult, r as handleError, t as apiError } from "../../../../../error-DJ98TRbQ.mjs";
|
|
4
|
+
import { n as parseBody, t as isParseError } from "../../../../../parse-53zyxlpv.mjs";
|
|
5
5
|
import "../../../../../api-tokens-Cvmixds7.mjs";
|
|
6
6
|
import "../../../../../oauth-user-lookup-oUllxvAv.mjs";
|
|
7
7
|
import { t as handleDeviceAuthorize } from "../../../../../device-flow-BeA6lUS1.mjs";
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import "../../../../../base64-B-PsqheR.mjs";
|
|
2
|
-
import "../../../../../types-
|
|
3
|
-
import { a as unwrapResult, r as handleError, t as apiError } from "../../../../../error-
|
|
4
|
-
import { n as parseBody, t as isParseError } from "../../../../../parse-
|
|
2
|
+
import "../../../../../types-CrRUFdej.mjs";
|
|
3
|
+
import { a as unwrapResult, r as handleError, t as apiError } from "../../../../../error-DJ98TRbQ.mjs";
|
|
4
|
+
import { n as parseBody, t as isParseError } from "../../../../../parse-53zyxlpv.mjs";
|
|
5
5
|
import { t as getTrustedProxyHeaders } from "../../../../../trusted-proxy-CwjQj0YG.mjs";
|
|
6
6
|
import { n as getPublicOrigin } from "../../../../../public-url-DSGTnJFw.mjs";
|
|
7
7
|
import "../../../../../api-tokens-Cvmixds7.mjs";
|
|
8
8
|
import "../../../../../oauth-user-lookup-oUllxvAv.mjs";
|
|
9
9
|
import { n as handleDeviceCodeRequest } from "../../../../../device-flow-BeA6lUS1.mjs";
|
|
10
|
-
import { n as getClientIp, r as rateLimitResponse, t as checkRateLimit } from "../../../../../rate-limit-
|
|
10
|
+
import { n as getClientIp, r as rateLimitResponse, t as checkRateLimit } from "../../../../../rate-limit-D3IEiUi2.mjs";
|
|
11
11
|
import { z } from "zod";
|
|
12
12
|
|
|
13
13
|
//#region src/astro/routes/api/oauth/device/code.ts
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import "../../../../../base64-B-PsqheR.mjs";
|
|
2
|
-
import "../../../../../types-
|
|
3
|
-
import { a as unwrapResult, r as handleError, t as apiError } from "../../../../../error-
|
|
4
|
-
import { n as parseBody, t as isParseError } from "../../../../../parse-
|
|
2
|
+
import "../../../../../types-CrRUFdej.mjs";
|
|
3
|
+
import { a as unwrapResult, r as handleError, t as apiError } from "../../../../../error-DJ98TRbQ.mjs";
|
|
4
|
+
import { n as parseBody, t as isParseError } from "../../../../../parse-53zyxlpv.mjs";
|
|
5
5
|
import { t as getTrustedProxyHeaders } from "../../../../../trusted-proxy-CwjQj0YG.mjs";
|
|
6
6
|
import "../../../../../api-tokens-Cvmixds7.mjs";
|
|
7
7
|
import "../../../../../oauth-user-lookup-oUllxvAv.mjs";
|
|
8
8
|
import { r as handleDeviceTokenExchange } from "../../../../../device-flow-BeA6lUS1.mjs";
|
|
9
|
-
import { n as getClientIp, r as rateLimitResponse, t as checkRateLimit } from "../../../../../rate-limit-
|
|
9
|
+
import { n as getClientIp, r as rateLimitResponse, t as checkRateLimit } from "../../../../../rate-limit-D3IEiUi2.mjs";
|
|
10
10
|
import { z } from "zod";
|
|
11
11
|
|
|
12
12
|
//#region src/astro/routes/api/oauth/device/token.ts
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import "../../../../base64-B-PsqheR.mjs";
|
|
2
|
-
import "../../../../types-
|
|
3
|
-
import { r as handleError, t as apiError } from "../../../../error-
|
|
2
|
+
import "../../../../types-CrRUFdej.mjs";
|
|
3
|
+
import { r as handleError, t as apiError } from "../../../../error-DJ98TRbQ.mjs";
|
|
4
4
|
import { t as handleOAuthClientCreate } from "../../../../oauth-clients-BlrUHAsf.mjs";
|
|
5
5
|
|
|
6
6
|
//#region src/astro/routes/api/oauth/register.ts
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import "../../../../../base64-B-PsqheR.mjs";
|
|
2
|
-
import "../../../../../types-
|
|
3
|
-
import { a as unwrapResult, r as handleError, t as apiError } from "../../../../../error-
|
|
4
|
-
import { n as parseBody, t as isParseError } from "../../../../../parse-
|
|
2
|
+
import "../../../../../types-CrRUFdej.mjs";
|
|
3
|
+
import { a as unwrapResult, r as handleError, t as apiError } from "../../../../../error-DJ98TRbQ.mjs";
|
|
4
|
+
import { n as parseBody, t as isParseError } from "../../../../../parse-53zyxlpv.mjs";
|
|
5
5
|
import "../../../../../api-tokens-Cvmixds7.mjs";
|
|
6
6
|
import "../../../../../oauth-user-lookup-oUllxvAv.mjs";
|
|
7
7
|
import { i as handleTokenRefresh } from "../../../../../device-flow-BeA6lUS1.mjs";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import "../../../../../base64-B-PsqheR.mjs";
|
|
2
|
-
import "../../../../../types-
|
|
3
|
-
import { a as unwrapResult, r as handleError, t as apiError } from "../../../../../error-
|
|
4
|
-
import { n as parseBody, t as isParseError } from "../../../../../parse-
|
|
2
|
+
import "../../../../../types-CrRUFdej.mjs";
|
|
3
|
+
import { a as unwrapResult, r as handleError, t as apiError } from "../../../../../error-DJ98TRbQ.mjs";
|
|
4
|
+
import { n as parseBody, t as isParseError } from "../../../../../parse-53zyxlpv.mjs";
|
|
5
5
|
import "../../../../../api-tokens-Cvmixds7.mjs";
|
|
6
6
|
import "../../../../../oauth-user-lookup-oUllxvAv.mjs";
|
|
7
7
|
import { a as handleTokenRevoke } from "../../../../../device-flow-BeA6lUS1.mjs";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import "../../../../base64-B-PsqheR.mjs";
|
|
2
|
-
import "../../../../types-
|
|
3
|
-
import { r as handleError, t as apiError } from "../../../../error-
|
|
2
|
+
import "../../../../types-CrRUFdej.mjs";
|
|
3
|
+
import { r as handleError, t as apiError } from "../../../../error-DJ98TRbQ.mjs";
|
|
4
4
|
import "../../../../api-tokens-Cvmixds7.mjs";
|
|
5
5
|
import "../../../../oauth-user-lookup-oUllxvAv.mjs";
|
|
6
6
|
import { r as handleAuthorizationCodeExchange } from "../../../../oauth-authorization-oqfbBuMH.mjs";
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import "../../../base64-B-PsqheR.mjs";
|
|
2
|
-
import "../../../types-
|
|
3
|
-
import { r as handleError } from "../../../error-
|
|
4
|
-
import { C as mediaUsageDetailsResponseSchema, E as mediaUsageRepairBody, I as deleteResponseSchema, N as apiErrorSchema, O as mediaUsageRepairResponseSchema, S as mediaUsageDetailsQuery, U as successEnvelope, _ as mediaUpdateBody, a as mediaConfirmResponseSchema, d as mediaListReadResponseSchema, f as mediaListResponseSchema, g as mediaResponseSchema, h as mediaReadResponseSchema, i as mediaConfirmBody, l as mediaListQuery, n as DEFAULT_MAX_UPLOAD_SIZE, o as mediaExistingResponseSchema, s as mediaGetQuery, v as mediaUploadUrlBody, y as mediaUploadUrlResponseSchema } from "../../../media-
|
|
5
|
-
import { $ as createMenuBody, $t as contentTermsBody, A as searchRebuildBody, At as fieldListResponseSchema, B as updateSectionBody, C as userDetailSchema, Ct as collectionGetQuery, D as usersListQuery, Dt as collectionWithFieldsResponseSchema, E as userUpdateBody, F as siteSettingsSchema, Ft as orphanedTableListResponseSchema, G as taxonomyListResponseSchema, Gt as contentListQuery, H as createTermBody, Ht as contentCompareResponseSchema, I as createSectionBody, J as termResponseSchema, K as termGetResponseSchema, Kt as contentListResponseSchema, L as sectionListResponseSchema, Mt as fieldResponseSchema, N as searchSuggestQuery, O as searchEnableBody, Ot as createCollectionBody, P as settingsUpdateBody, Pt as orphanRegisterBody, Q as updateTermBody, R as sectionSchema, Rt as updateCollectionBody, S as allowedDomainUpdateBody, T as userSchema, Tt as collectionResponseSchema, Ut as contentCreateBody, Vt as contentAuthorsResponseSchema, Wt as contentItemSchema, Xt as contentScheduleBody, Yt as contentResponseSchema, _ as widgetAreaSchema, _t as commentSchema, a as notFoundPruneBody, an as trashedContentListResponseSchema, b as widgetSchema, ct as updateMenuBody, d as redirectsListQuery, et as createMenuItemBody, f as updateRedirectBody, ft as adminCommentListResponseSchema, g as updateWidgetBody, gt as commentListQuery, h as reorderWidgetsBody, ht as commentCountsResponseSchema, i as notFoundListResponseSchema, j as searchResponseSchema, jt as fieldReorderBody, k as searchQuery, kt as createFieldBody, l as redirectListResponseSchema, lt as updateMenuItemBody, m as createWidgetBody, mt as commentBulkResponseSchema, nn as contentTrashQuery, ot as menuWithItemsSchema, p as createWidgetAreaBody, pt as commentBulkBody, q as termListResponseSchema, r as notFoundListQuery, rn as contentUpdateBody, rt as menuListItemSchema, s as notFoundSummaryResponseSchema, st as reorderMenuItemsBody, t as createRedirectBody, tn as contentTranslationsResponseSchema, tt as menuItemSchema, u as redirectSchema, v as widgetAreaWithWidgetsAndCountSchema, vt as commentStatusBody, w as userListResponseSchema, wt as collectionListResponseSchema, x as allowedDomainCreateBody, xt as publicCommentListResponseSchema, y as widgetAreaWithWidgetsSchema, yt as createCommentBody, z as sectionsListQuery, zt as updateFieldBody } from "../../../redirects-
|
|
2
|
+
import "../../../types-CrRUFdej.mjs";
|
|
3
|
+
import { r as handleError } from "../../../error-DJ98TRbQ.mjs";
|
|
4
|
+
import { C as mediaUsageDetailsResponseSchema, E as mediaUsageRepairBody, I as deleteResponseSchema, N as apiErrorSchema, O as mediaUsageRepairResponseSchema, S as mediaUsageDetailsQuery, U as successEnvelope, _ as mediaUpdateBody, a as mediaConfirmResponseSchema, d as mediaListReadResponseSchema, f as mediaListResponseSchema, g as mediaResponseSchema, h as mediaReadResponseSchema, i as mediaConfirmBody, l as mediaListQuery, n as DEFAULT_MAX_UPLOAD_SIZE, o as mediaExistingResponseSchema, s as mediaGetQuery, v as mediaUploadUrlBody, y as mediaUploadUrlResponseSchema } from "../../../media-BJ6SRY3g.mjs";
|
|
5
|
+
import { $ as createMenuBody, $t as contentTermsBody, A as searchRebuildBody, At as fieldListResponseSchema, B as updateSectionBody, C as userDetailSchema, Ct as collectionGetQuery, D as usersListQuery, Dt as collectionWithFieldsResponseSchema, E as userUpdateBody, F as siteSettingsSchema, Ft as orphanedTableListResponseSchema, G as taxonomyListResponseSchema, Gt as contentListQuery, H as createTermBody, Ht as contentCompareResponseSchema, I as createSectionBody, J as termResponseSchema, K as termGetResponseSchema, Kt as contentListResponseSchema, L as sectionListResponseSchema, Mt as fieldResponseSchema, N as searchSuggestQuery, O as searchEnableBody, Ot as createCollectionBody, P as settingsUpdateBody, Pt as orphanRegisterBody, Q as updateTermBody, R as sectionSchema, Rt as updateCollectionBody, S as allowedDomainUpdateBody, T as userSchema, Tt as collectionResponseSchema, Ut as contentCreateBody, Vt as contentAuthorsResponseSchema, Wt as contentItemSchema, Xt as contentScheduleBody, Yt as contentResponseSchema, _ as widgetAreaSchema, _t as commentSchema, a as notFoundPruneBody, an as trashedContentListResponseSchema, b as widgetSchema, ct as updateMenuBody, d as redirectsListQuery, et as createMenuItemBody, f as updateRedirectBody, ft as adminCommentListResponseSchema, g as updateWidgetBody, gt as commentListQuery, h as reorderWidgetsBody, ht as commentCountsResponseSchema, i as notFoundListResponseSchema, j as searchResponseSchema, jt as fieldReorderBody, k as searchQuery, kt as createFieldBody, l as redirectListResponseSchema, lt as updateMenuItemBody, m as createWidgetBody, mt as commentBulkResponseSchema, nn as contentTrashQuery, ot as menuWithItemsSchema, p as createWidgetAreaBody, pt as commentBulkBody, q as termListResponseSchema, r as notFoundListQuery, rn as contentUpdateBody, rt as menuListItemSchema, s as notFoundSummaryResponseSchema, st as reorderMenuItemsBody, t as createRedirectBody, tn as contentTranslationsResponseSchema, tt as menuItemSchema, u as redirectSchema, v as widgetAreaWithWidgetsAndCountSchema, vt as commentStatusBody, w as userListResponseSchema, wt as collectionListResponseSchema, x as allowedDomainCreateBody, xt as publicCommentListResponseSchema, y as widgetAreaWithWidgetsSchema, yt as createCommentBody, z as sectionsListQuery, zt as updateFieldBody } from "../../../redirects-D457qwt0.mjs";
|
|
6
6
|
import "../../../status-COfycGIU.mjs";
|
|
7
7
|
import { z } from "zod";
|
|
8
8
|
import { globalRegistry } from "zod/v4/core";
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import "../../../../../base64-B-PsqheR.mjs";
|
|
2
|
-
import "../../../../../types-
|
|
3
|
-
import { n as apiSuccess, t as apiError } from "../../../../../error-
|
|
2
|
+
import "../../../../../types-CrRUFdej.mjs";
|
|
3
|
+
import { n as apiSuccess, t as apiError } from "../../../../../error-DJ98TRbQ.mjs";
|
|
4
4
|
import "../../../../../api-tokens-Cvmixds7.mjs";
|
|
5
|
-
import { r as requirePerm } from "../../../../../authorize-
|
|
6
|
-
import { t as requireScope } from "../../../../../scopes-
|
|
5
|
+
import { r as requirePerm } from "../../../../../authorize-6WPZa1xZ.mjs";
|
|
6
|
+
import { t as requireScope } from "../../../../../scopes-DTIkIaGA.mjs";
|
|
7
7
|
import { Permissions } from "@emdash-cms/auth";
|
|
8
8
|
|
|
9
9
|
//#region src/astro/routes/api/plugins/[pluginId]/[...path].ts
|
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
import "../../../../../dialect-helpers-
|
|
1
|
+
import "../../../../../dialect-helpers-BtOwo2us.mjs";
|
|
2
2
|
import "../../../../../base64-B-PsqheR.mjs";
|
|
3
|
-
import "../../../../../types-
|
|
3
|
+
import "../../../../../types-CrRUFdej.mjs";
|
|
4
4
|
import "../../../../../options-BlmBHTvX.mjs";
|
|
5
|
-
import "../../../../../redirect-
|
|
6
|
-
import { a as unwrapResult, i as requireDb, r as handleError } from "../../../../../error-
|
|
7
|
-
import { i as parseQuery, n as parseBody, t as isParseError } from "../../../../../parse-
|
|
8
|
-
import "../../../../../media-
|
|
9
|
-
import { a as notFoundPruneBody, r as notFoundListQuery } from "../../../../../redirects-
|
|
10
|
-
import "../../../../../relations-
|
|
5
|
+
import "../../../../../redirect-BoUac4NT.mjs";
|
|
6
|
+
import { a as unwrapResult, i as requireDb, r as handleError } from "../../../../../error-DJ98TRbQ.mjs";
|
|
7
|
+
import { i as parseQuery, n as parseBody, t as isParseError } from "../../../../../parse-53zyxlpv.mjs";
|
|
8
|
+
import "../../../../../media-BJ6SRY3g.mjs";
|
|
9
|
+
import { a as notFoundPruneBody, r as notFoundListQuery } from "../../../../../redirects-D457qwt0.mjs";
|
|
10
|
+
import "../../../../../relations-CZMpBqEd.mjs";
|
|
11
11
|
import "../../../../../status-COfycGIU.mjs";
|
|
12
12
|
import "../../../../../api/schemas/index.mjs";
|
|
13
|
-
import { r as requirePerm } from "../../../../../authorize-
|
|
14
|
-
import { n as handleNotFoundList, r as handleNotFoundPrune, t as handleNotFoundClear } from "../../../../../redirects-
|
|
13
|
+
import { r as requirePerm } from "../../../../../authorize-6WPZa1xZ.mjs";
|
|
14
|
+
import { n as handleNotFoundList, r as handleNotFoundPrune, t as handleNotFoundClear } from "../../../../../redirects-ChbpqKiS.mjs";
|
|
15
15
|
|
|
16
16
|
//#region src/astro/routes/api/redirects/404s/index.ts
|
|
17
17
|
const prerender = false;
|
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
import "../../../../../dialect-helpers-
|
|
1
|
+
import "../../../../../dialect-helpers-BtOwo2us.mjs";
|
|
2
2
|
import "../../../../../base64-B-PsqheR.mjs";
|
|
3
|
-
import "../../../../../types-
|
|
3
|
+
import "../../../../../types-CrRUFdej.mjs";
|
|
4
4
|
import "../../../../../options-BlmBHTvX.mjs";
|
|
5
|
-
import "../../../../../redirect-
|
|
6
|
-
import { a as unwrapResult, i as requireDb, r as handleError } from "../../../../../error-
|
|
7
|
-
import { i as parseQuery, t as isParseError } from "../../../../../parse-
|
|
8
|
-
import "../../../../../media-
|
|
9
|
-
import { o as notFoundSummaryQuery } from "../../../../../redirects-
|
|
10
|
-
import "../../../../../relations-
|
|
5
|
+
import "../../../../../redirect-BoUac4NT.mjs";
|
|
6
|
+
import { a as unwrapResult, i as requireDb, r as handleError } from "../../../../../error-DJ98TRbQ.mjs";
|
|
7
|
+
import { i as parseQuery, t as isParseError } from "../../../../../parse-53zyxlpv.mjs";
|
|
8
|
+
import "../../../../../media-BJ6SRY3g.mjs";
|
|
9
|
+
import { o as notFoundSummaryQuery } from "../../../../../redirects-D457qwt0.mjs";
|
|
10
|
+
import "../../../../../relations-CZMpBqEd.mjs";
|
|
11
11
|
import "../../../../../status-COfycGIU.mjs";
|
|
12
12
|
import "../../../../../api/schemas/index.mjs";
|
|
13
|
-
import { r as requirePerm } from "../../../../../authorize-
|
|
14
|
-
import { i as handleNotFoundSummary } from "../../../../../redirects-
|
|
13
|
+
import { r as requirePerm } from "../../../../../authorize-6WPZa1xZ.mjs";
|
|
14
|
+
import { i as handleNotFoundSummary } from "../../../../../redirects-ChbpqKiS.mjs";
|
|
15
15
|
|
|
16
16
|
//#region src/astro/routes/api/redirects/404s/summary.ts
|
|
17
17
|
const prerender = false;
|
|
@@ -1,18 +1,18 @@
|
|
|
1
|
-
import "../../../../dialect-helpers-
|
|
1
|
+
import "../../../../dialect-helpers-BtOwo2us.mjs";
|
|
2
2
|
import "../../../../base64-B-PsqheR.mjs";
|
|
3
|
-
import "../../../../types-
|
|
3
|
+
import "../../../../types-CrRUFdej.mjs";
|
|
4
4
|
import "../../../../options-BlmBHTvX.mjs";
|
|
5
|
-
import "../../../../redirect-
|
|
6
|
-
import { r as invalidateRedirectCache } from "../../../../cache-
|
|
7
|
-
import { a as unwrapResult, i as requireDb, r as handleError, t as apiError } from "../../../../error-
|
|
8
|
-
import { n as parseBody, t as isParseError } from "../../../../parse-
|
|
9
|
-
import "../../../../media-
|
|
10
|
-
import { f as updateRedirectBody } from "../../../../redirects-
|
|
11
|
-
import "../../../../relations-
|
|
5
|
+
import "../../../../redirect-BoUac4NT.mjs";
|
|
6
|
+
import { r as invalidateRedirectCache } from "../../../../cache-DDwy3JDW.mjs";
|
|
7
|
+
import { a as unwrapResult, i as requireDb, r as handleError, t as apiError } from "../../../../error-DJ98TRbQ.mjs";
|
|
8
|
+
import { n as parseBody, t as isParseError } from "../../../../parse-53zyxlpv.mjs";
|
|
9
|
+
import "../../../../media-BJ6SRY3g.mjs";
|
|
10
|
+
import { f as updateRedirectBody } from "../../../../redirects-D457qwt0.mjs";
|
|
11
|
+
import "../../../../relations-CZMpBqEd.mjs";
|
|
12
12
|
import "../../../../status-COfycGIU.mjs";
|
|
13
13
|
import "../../../../api/schemas/index.mjs";
|
|
14
|
-
import { r as requirePerm } from "../../../../authorize-
|
|
15
|
-
import { l as handleRedirectUpdate, o as handleRedirectDelete, s as handleRedirectGet } from "../../../../redirects-
|
|
14
|
+
import { r as requirePerm } from "../../../../authorize-6WPZa1xZ.mjs";
|
|
15
|
+
import { l as handleRedirectUpdate, o as handleRedirectDelete, s as handleRedirectGet } from "../../../../redirects-ChbpqKiS.mjs";
|
|
16
16
|
|
|
17
17
|
//#region src/astro/routes/api/redirects/[id].ts
|
|
18
18
|
const prerender = false;
|
|
@@ -1,18 +1,18 @@
|
|
|
1
|
-
import "../../../../dialect-helpers-
|
|
1
|
+
import "../../../../dialect-helpers-BtOwo2us.mjs";
|
|
2
2
|
import "../../../../base64-B-PsqheR.mjs";
|
|
3
|
-
import "../../../../types-
|
|
3
|
+
import "../../../../types-CrRUFdej.mjs";
|
|
4
4
|
import "../../../../options-BlmBHTvX.mjs";
|
|
5
|
-
import "../../../../redirect-
|
|
6
|
-
import { r as invalidateRedirectCache } from "../../../../cache-
|
|
7
|
-
import { a as unwrapResult, i as requireDb, r as handleError } from "../../../../error-
|
|
8
|
-
import { i as parseQuery, n as parseBody, t as isParseError } from "../../../../parse-
|
|
9
|
-
import "../../../../media-
|
|
10
|
-
import { d as redirectsListQuery, t as createRedirectBody } from "../../../../redirects-
|
|
11
|
-
import "../../../../relations-
|
|
5
|
+
import "../../../../redirect-BoUac4NT.mjs";
|
|
6
|
+
import { r as invalidateRedirectCache } from "../../../../cache-DDwy3JDW.mjs";
|
|
7
|
+
import { a as unwrapResult, i as requireDb, r as handleError } from "../../../../error-DJ98TRbQ.mjs";
|
|
8
|
+
import { i as parseQuery, n as parseBody, t as isParseError } from "../../../../parse-53zyxlpv.mjs";
|
|
9
|
+
import "../../../../media-BJ6SRY3g.mjs";
|
|
10
|
+
import { d as redirectsListQuery, t as createRedirectBody } from "../../../../redirects-D457qwt0.mjs";
|
|
11
|
+
import "../../../../relations-CZMpBqEd.mjs";
|
|
12
12
|
import "../../../../status-COfycGIU.mjs";
|
|
13
13
|
import "../../../../api/schemas/index.mjs";
|
|
14
|
-
import { r as requirePerm } from "../../../../authorize-
|
|
15
|
-
import { a as handleRedirectCreate, c as handleRedirectList } from "../../../../redirects-
|
|
14
|
+
import { r as requirePerm } from "../../../../authorize-6WPZa1xZ.mjs";
|
|
15
|
+
import { a as handleRedirectCreate, c as handleRedirectList } from "../../../../redirects-ChbpqKiS.mjs";
|
|
16
16
|
|
|
17
17
|
//#region src/astro/routes/api/redirects/index.ts
|
|
18
18
|
const prerender = false;
|
|
@@ -1,22 +1,22 @@
|
|
|
1
|
-
import "../../../../../dialect-helpers-
|
|
1
|
+
import "../../../../../dialect-helpers-BtOwo2us.mjs";
|
|
2
2
|
import "../../../../../after-B1IIdH3Y.mjs";
|
|
3
3
|
import "../../../../../object-cache-Bok5j2ae.mjs";
|
|
4
|
-
import "../../../../../content-
|
|
4
|
+
import "../../../../../content-BC43pICM.mjs";
|
|
5
5
|
import "../../../../../base64-B-PsqheR.mjs";
|
|
6
|
-
import "../../../../../types-
|
|
7
|
-
import "../../../../../relation-
|
|
8
|
-
import "../../../../../fts-manager-
|
|
9
|
-
import "../../../../../content-refresh-
|
|
10
|
-
import "../../../../../registry-
|
|
11
|
-
import { a as unwrapResult, i as requireDb, r as handleError, t as apiError } from "../../../../../error-
|
|
12
|
-
import { n as parseBody, t as isParseError } from "../../../../../parse-
|
|
13
|
-
import "../../../../../media-
|
|
14
|
-
import "../../../../../redirects-
|
|
15
|
-
import { u as updateRelationBody } from "../../../../../relations-
|
|
6
|
+
import "../../../../../types-CrRUFdej.mjs";
|
|
7
|
+
import "../../../../../relation-Du0r04E0.mjs";
|
|
8
|
+
import "../../../../../fts-manager-hyCU9OOp.mjs";
|
|
9
|
+
import "../../../../../content-refresh-CPMSauD3.mjs";
|
|
10
|
+
import "../../../../../registry-y21kjhfG.mjs";
|
|
11
|
+
import { a as unwrapResult, i as requireDb, r as handleError, t as apiError } from "../../../../../error-DJ98TRbQ.mjs";
|
|
12
|
+
import { n as parseBody, t as isParseError } from "../../../../../parse-53zyxlpv.mjs";
|
|
13
|
+
import "../../../../../media-BJ6SRY3g.mjs";
|
|
14
|
+
import "../../../../../redirects-D457qwt0.mjs";
|
|
15
|
+
import { u as updateRelationBody } from "../../../../../relations-CZMpBqEd.mjs";
|
|
16
16
|
import "../../../../../status-COfycGIU.mjs";
|
|
17
17
|
import "../../../../../api/schemas/index.mjs";
|
|
18
|
-
import { r as requirePerm } from "../../../../../authorize-
|
|
19
|
-
import { a as handleRelationDelete, l as handleRelationUpdate, o as handleRelationGet } from "../../../../../relations-
|
|
18
|
+
import { r as requirePerm } from "../../../../../authorize-6WPZa1xZ.mjs";
|
|
19
|
+
import { a as handleRelationDelete, l as handleRelationUpdate, o as handleRelationGet } from "../../../../../relations-DtX1UMBH.mjs";
|
|
20
20
|
|
|
21
21
|
//#region src/astro/routes/api/relations/[id]/index.ts
|
|
22
22
|
const prerender = false;
|