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
|
@@ -69,11 +69,16 @@ function getCsrfCookie(request: Request): string | null {
|
|
|
69
69
|
|
|
70
70
|
const SCOPE_LABELS: Record<string, string> = {
|
|
71
71
|
"content:read": "Read content (posts, pages, etc.)",
|
|
72
|
-
"content:write": "Create, edit, and delete content",
|
|
72
|
+
"content:write": "Create, edit, and delete content; manage menus and taxonomies",
|
|
73
73
|
"media:read": "View media files",
|
|
74
74
|
"media:write": "Upload and manage media files",
|
|
75
75
|
"schema:read": "View collection schemas",
|
|
76
76
|
"schema:write": "Create and modify collection schemas",
|
|
77
|
+
"taxonomies:manage": "Manage taxonomies",
|
|
78
|
+
"menus:manage": "Manage navigation menus",
|
|
79
|
+
"settings:read": "View site settings",
|
|
80
|
+
"settings:manage": "Modify site settings",
|
|
81
|
+
"mcp:tools": "Use MCP tools from all enabled plugins",
|
|
77
82
|
admin: "Full administrative access",
|
|
78
83
|
};
|
|
79
84
|
|
|
@@ -141,7 +146,9 @@ export const GET: APIRoute = async ({ url, request, locals }) => {
|
|
|
141
146
|
}
|
|
142
147
|
|
|
143
148
|
// Parse and validate scopes
|
|
144
|
-
const requestedScopes =
|
|
149
|
+
const requestedScopes = [
|
|
150
|
+
...new Set((scope ?? "").split(" ").filter(Boolean).filter(isValidScope)),
|
|
151
|
+
];
|
|
145
152
|
|
|
146
153
|
if (requestedScopes.length === 0) {
|
|
147
154
|
return new Response(renderErrorPage("No valid scopes requested."), {
|
|
@@ -201,6 +208,21 @@ export const POST: APIRoute = async ({ request, locals }) => {
|
|
|
201
208
|
const v = formData.get(name);
|
|
202
209
|
return typeof v === "string" ? v : fallback;
|
|
203
210
|
};
|
|
211
|
+
const requestedScopes = new Set(
|
|
212
|
+
(new URL(request.url).searchParams.get("scope") ?? "")
|
|
213
|
+
.split(" ")
|
|
214
|
+
.filter(Boolean)
|
|
215
|
+
.filter(isValidScope),
|
|
216
|
+
);
|
|
217
|
+
const selectedScopes = [
|
|
218
|
+
...new Set(
|
|
219
|
+
formData
|
|
220
|
+
.getAll("scope")
|
|
221
|
+
.filter((value): value is string => typeof value === "string")
|
|
222
|
+
.filter(isValidScope)
|
|
223
|
+
.filter((scope) => requestedScopes.has(scope)),
|
|
224
|
+
),
|
|
225
|
+
];
|
|
204
226
|
|
|
205
227
|
// SEC-18: Validate CSRF token (double-submit cookie pattern).
|
|
206
228
|
// The form includes a hidden csrf_token field; the cookie has the same value.
|
|
@@ -285,7 +307,7 @@ export const POST: APIRoute = async ({ request, locals }) => {
|
|
|
285
307
|
response_type: field("response_type", "code"),
|
|
286
308
|
client_id: field("client_id"),
|
|
287
309
|
redirect_uri: redirectUri,
|
|
288
|
-
scope:
|
|
310
|
+
scope: selectedScopes.join(" "),
|
|
289
311
|
state,
|
|
290
312
|
code_challenge: field("code_challenge"),
|
|
291
313
|
code_challenge_method: field("code_challenge_method", "S256"),
|
|
@@ -294,12 +316,16 @@ export const POST: APIRoute = async ({ request, locals }) => {
|
|
|
294
316
|
|
|
295
317
|
if (!result.success) {
|
|
296
318
|
const errMsg = result.error?.message ?? "Authorization failed";
|
|
319
|
+
const invalidScope = result.error?.code === "INVALID_SCOPE";
|
|
297
320
|
// On error, redirect back with error params — use generic description to avoid
|
|
298
321
|
// leaking internal error details to the (already-validated) redirect target
|
|
299
322
|
try {
|
|
300
323
|
const errorUrl = new URL(redirectUri);
|
|
301
|
-
errorUrl.searchParams.set("error", "server_error");
|
|
302
|
-
errorUrl.searchParams.set(
|
|
324
|
+
errorUrl.searchParams.set("error", invalidScope ? "invalid_scope" : "server_error");
|
|
325
|
+
errorUrl.searchParams.set(
|
|
326
|
+
"error_description",
|
|
327
|
+
invalidScope ? "No selected permission can be granted" : "Authorization failed",
|
|
328
|
+
);
|
|
303
329
|
if (state) errorUrl.searchParams.set("state", state);
|
|
304
330
|
return Response.redirect(errorUrl.toString(), 302);
|
|
305
331
|
} catch {
|
|
@@ -331,8 +357,8 @@ function renderConsentPage(params: {
|
|
|
331
357
|
}): string {
|
|
332
358
|
const scopeList = params.scopes
|
|
333
359
|
.map((s) => {
|
|
334
|
-
const label = SCOPE_LABELS[s] ?? s;
|
|
335
|
-
return `<li>${escapeHtml(label)}</li>`;
|
|
360
|
+
const label = SCOPE_LABELS[s] ?? getPluginScopeLabel(s) ?? s;
|
|
361
|
+
return `<li><label><input type="checkbox" name="scope" value="${escapeHtml(s)}" checked><span>${escapeHtml(label)}</span></label></li>`;
|
|
336
362
|
})
|
|
337
363
|
.join("\n");
|
|
338
364
|
|
|
@@ -353,6 +379,8 @@ function renderConsentPage(params: {
|
|
|
353
379
|
ul { list-style: none; margin-bottom: 1.5rem; }
|
|
354
380
|
li { padding: 0.5rem 0; border-bottom: 1px solid #262626; font-size: 0.875rem; }
|
|
355
381
|
li:last-child { border-bottom: none; }
|
|
382
|
+
label { display: flex; align-items: flex-start; gap: 0.625rem; cursor: pointer; }
|
|
383
|
+
input[type="checkbox"] { margin-top: 0.125rem; accent-color: #2563eb; }
|
|
356
384
|
.actions { display: flex; gap: 0.75rem; }
|
|
357
385
|
button { flex: 1; padding: 0.625rem 1rem; border-radius: 8px; border: none; font-size: 0.875rem; font-weight: 500; cursor: pointer; }
|
|
358
386
|
.approve { background: #2563eb; color: white; }
|
|
@@ -366,14 +394,13 @@ function renderConsentPage(params: {
|
|
|
366
394
|
<h1>Authorize Application</h1>
|
|
367
395
|
<p class="client-id">${escapeHtml(params.clientId)}</p>
|
|
368
396
|
<p class="user">Signed in as <strong>${escapeHtml(params.userName)}</strong></p>
|
|
369
|
-
<h2>Permissions requested</h2>
|
|
370
|
-
<ul>${scopeList}</ul>
|
|
371
397
|
<form method="POST">
|
|
398
|
+
<h2>Permissions requested</h2>
|
|
399
|
+
<ul>${scopeList}</ul>
|
|
372
400
|
<input type="hidden" name="csrf_token" value="${escapeHtml(params.csrfToken)}">
|
|
373
401
|
<input type="hidden" name="response_type" value="${escapeHtml(params.responseType)}">
|
|
374
402
|
<input type="hidden" name="client_id" value="${escapeHtml(params.clientId)}">
|
|
375
403
|
<input type="hidden" name="redirect_uri" value="${escapeHtml(params.redirectUri)}">
|
|
376
|
-
<input type="hidden" name="scope" value="${escapeHtml(params.scopes.join(" "))}">
|
|
377
404
|
<input type="hidden" name="state" value="${escapeHtml(params.state)}">
|
|
378
405
|
<input type="hidden" name="code_challenge" value="${escapeHtml(params.codeChallenge)}">
|
|
379
406
|
<input type="hidden" name="code_challenge_method" value="${escapeHtml(params.codeChallengeMethod)}">
|
|
@@ -388,6 +415,11 @@ function renderConsentPage(params: {
|
|
|
388
415
|
</html>`;
|
|
389
416
|
}
|
|
390
417
|
|
|
418
|
+
function getPluginScopeLabel(scope: string): string | null {
|
|
419
|
+
const pluginId = scope.startsWith("mcp:tools:") ? scope.slice("mcp:tools:".length) : "";
|
|
420
|
+
return pluginId ? `Use MCP tools from ${pluginId}` : null;
|
|
421
|
+
}
|
|
422
|
+
|
|
391
423
|
function renderErrorPage(message: string): string {
|
|
392
424
|
return `<!DOCTYPE html>
|
|
393
425
|
<html lang="en">
|
|
@@ -2,11 +2,17 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* Portable Text Gallery block component
|
|
4
4
|
*
|
|
5
|
-
* Renders image galleries from WordPress imports.
|
|
6
|
-
* Uses
|
|
5
|
+
* Renders image galleries from WordPress imports and EmDash media.
|
|
6
|
+
* Uses the provider's getEmbed/getSrc functions for external media (mirrors
|
|
7
|
+
* Image.astro), falling back to Astro's Image component when dimensions are
|
|
8
|
+
* available for locally-stored media.
|
|
7
9
|
*/
|
|
8
10
|
import { Image as AstroImage } from "astro:assets";
|
|
11
|
+
import type { ImageEmbed } from "../media/types.js";
|
|
12
|
+
import { getMediaProvider } from "../media/provider-loader.js";
|
|
9
13
|
import { buildRenderMediaUrl } from "../media/url.js";
|
|
14
|
+
import { toAbsoluteMediaUrl, RESPONSIVE_BREAKPOINTS } from "../media/responsive.js";
|
|
15
|
+
import { getPublicOrigin } from "../api/public-url.js";
|
|
10
16
|
|
|
11
17
|
export interface Props {
|
|
12
18
|
node: {
|
|
@@ -18,50 +24,159 @@ export interface Props {
|
|
|
18
24
|
asset: {
|
|
19
25
|
_ref: string;
|
|
20
26
|
url?: string;
|
|
27
|
+
/** Provider ID for external media (e.g., "cloudflare-images") */
|
|
28
|
+
provider?: string;
|
|
21
29
|
};
|
|
22
30
|
alt?: string;
|
|
23
31
|
caption?: string;
|
|
24
32
|
width?: number;
|
|
25
33
|
height?: number;
|
|
34
|
+
/** LQIP blurhash placeholder (images only) */
|
|
35
|
+
blurhash?: string;
|
|
36
|
+
/** LQIP dominant-color placeholder, as a CSS color (images only) */
|
|
37
|
+
dominantColor?: string;
|
|
26
38
|
}>;
|
|
27
39
|
columns?: number;
|
|
28
40
|
};
|
|
41
|
+
/** Render the LQIP placeholder as an inline background. Disable for strict CSP. */
|
|
42
|
+
placeholder?: boolean;
|
|
29
43
|
}
|
|
30
44
|
|
|
31
|
-
|
|
45
|
+
/**
|
|
46
|
+
* Generate srcset using provider's getSrc function
|
|
47
|
+
*/
|
|
48
|
+
function generateSrcset(
|
|
49
|
+
getSrc: NonNullable<ImageEmbed["getSrc"]>,
|
|
50
|
+
maxWidth: number,
|
|
51
|
+
aspectRatio?: number,
|
|
52
|
+
): string {
|
|
53
|
+
return RESPONSIVE_BREAKPOINTS.filter((w) => w <= maxWidth * 2)
|
|
54
|
+
.map((w) => {
|
|
55
|
+
const h = aspectRatio ? Math.round(w / aspectRatio) : undefined;
|
|
56
|
+
return `${getSrc({ width: w, height: h })} ${w}w`;
|
|
57
|
+
})
|
|
58
|
+
.join(", ");
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const { node, placeholder = true } = Astro.props;
|
|
32
62
|
const images = node?.images ?? [];
|
|
33
63
|
const columns = node?.columns ?? 3;
|
|
34
64
|
|
|
35
65
|
if (!images.length) {
|
|
36
66
|
return null;
|
|
37
67
|
}
|
|
68
|
+
|
|
69
|
+
// Resolve provider embeds up front (async), keeping the template's `.map()`
|
|
70
|
+
// synchronous over the resolved data — mirrors Image.astro's per-image logic.
|
|
71
|
+
const resolvedImages = await Promise.all(
|
|
72
|
+
images.map(async (image) => {
|
|
73
|
+
const { asset, alt = "", width, height } = image;
|
|
74
|
+
const aspectRatio = width && height ? width / height : undefined;
|
|
75
|
+
|
|
76
|
+
let src = "";
|
|
77
|
+
let srcset: string | undefined;
|
|
78
|
+
let sizes: string | undefined;
|
|
79
|
+
let astroImageSrc = "";
|
|
80
|
+
const providerId = asset.provider;
|
|
81
|
+
|
|
82
|
+
if (providerId && providerId !== "local") {
|
|
83
|
+
const provider = await getMediaProvider(providerId);
|
|
84
|
+
if (provider) {
|
|
85
|
+
try {
|
|
86
|
+
const mediaValue = {
|
|
87
|
+
provider: providerId,
|
|
88
|
+
id: asset._ref,
|
|
89
|
+
width,
|
|
90
|
+
height,
|
|
91
|
+
alt,
|
|
92
|
+
};
|
|
93
|
+
const result = provider.getEmbed(mediaValue, { width, height });
|
|
94
|
+
const embed = result instanceof Promise ? await result : result;
|
|
95
|
+
if (embed.type === "image") {
|
|
96
|
+
src = embed.src;
|
|
97
|
+
|
|
98
|
+
if (embed.getSrc) {
|
|
99
|
+
const maxWidth = width || 1200;
|
|
100
|
+
srcset = generateSrcset(embed.getSrc, maxWidth, aspectRatio);
|
|
101
|
+
sizes = width ? `(min-width: ${width}px) ${width}px, 100vw` : "100vw";
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
} catch (error) {
|
|
105
|
+
console.warn(`Failed to get embed for image ${asset._ref}:`, error);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Fallback for local provider. `asset.url` carries the storage key with
|
|
111
|
+
// extension when present; `asset._ref` is a bare ULID that only the
|
|
112
|
+
// internal `/file/{id}` route can resolve. `buildRenderMediaUrl` picks
|
|
113
|
+
// the right shape.
|
|
114
|
+
if (!src) {
|
|
115
|
+
src = buildRenderMediaUrl(Astro.locals.emdash?.getPublicMediaUrl, {
|
|
116
|
+
url: asset.url,
|
|
117
|
+
id: asset._ref,
|
|
118
|
+
});
|
|
119
|
+
if (width && height) {
|
|
120
|
+
astroImageSrc = toAbsoluteMediaUrl(
|
|
121
|
+
src,
|
|
122
|
+
getPublicOrigin(Astro.url, Astro.locals.emdash?.config),
|
|
123
|
+
);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// Prefer blurhash over dominant color for the LQIP placeholder, like
|
|
128
|
+
// Image.astro.
|
|
129
|
+
let placeholderStyle = "";
|
|
130
|
+
if (placeholder && image.blurhash) {
|
|
131
|
+
const { blurhashToImageCssString } = await import("@unpic/placeholder");
|
|
132
|
+
placeholderStyle = blurhashToImageCssString(image.blurhash);
|
|
133
|
+
} else if (placeholder && image.dominantColor) {
|
|
134
|
+
placeholderStyle = `background-color: ${image.dominantColor};`;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
return {
|
|
138
|
+
key: image._key,
|
|
139
|
+
alt,
|
|
140
|
+
caption: image.caption,
|
|
141
|
+
width,
|
|
142
|
+
height,
|
|
143
|
+
src,
|
|
144
|
+
srcset,
|
|
145
|
+
sizes,
|
|
146
|
+
astroImageSrc,
|
|
147
|
+
placeholderStyle,
|
|
148
|
+
};
|
|
149
|
+
}),
|
|
150
|
+
);
|
|
38
151
|
---
|
|
39
152
|
|
|
40
153
|
<div class="emdash-gallery" style={`--columns: ${columns}`}>
|
|
41
154
|
{
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
155
|
+
resolvedImages.map((image) => (
|
|
156
|
+
<figure class="emdash-gallery-item" style={image.placeholderStyle || undefined}>
|
|
157
|
+
{image.astroImageSrc ? (
|
|
158
|
+
<AstroImage
|
|
159
|
+
src={image.astroImageSrc}
|
|
160
|
+
alt={image.alt}
|
|
161
|
+
width={image.width!}
|
|
162
|
+
height={image.height!}
|
|
163
|
+
layout="constrained"
|
|
164
|
+
/>
|
|
165
|
+
) : (
|
|
166
|
+
<img
|
|
167
|
+
src={image.src}
|
|
168
|
+
srcset={image.srcset}
|
|
169
|
+
sizes={image.sizes}
|
|
170
|
+
alt={image.alt}
|
|
171
|
+
width={image.width}
|
|
172
|
+
height={image.height}
|
|
173
|
+
loading="lazy"
|
|
174
|
+
decoding="async"
|
|
175
|
+
/>
|
|
176
|
+
)}
|
|
177
|
+
{image.caption && <figcaption>{image.caption}</figcaption>}
|
|
178
|
+
</figure>
|
|
179
|
+
))
|
|
65
180
|
}
|
|
66
181
|
</div>
|
|
67
182
|
|
package/src/config/secrets.ts
CHANGED
|
@@ -108,8 +108,9 @@ export interface ResolveSecretsOptions {
|
|
|
108
108
|
db: Kysely<Database>;
|
|
109
109
|
/**
|
|
110
110
|
* Optional explicit env override map. When omitted, falls back to
|
|
111
|
-
* `
|
|
112
|
-
* explicit map to avoid
|
|
111
|
+
* `process.env` via `readDefaultEnv` below (never `import.meta.env` —
|
|
112
|
+
* see that function's docstring). Tests pass an explicit map to avoid
|
|
113
|
+
* leaking process state.
|
|
113
114
|
*/
|
|
114
115
|
env?: SecretsEnv;
|
|
115
116
|
/**
|
|
@@ -514,29 +515,34 @@ function decodeBase64urlStrict(input: string): Uint8Array | null {
|
|
|
514
515
|
/**
|
|
515
516
|
* Default env reader.
|
|
516
517
|
*
|
|
517
|
-
*
|
|
518
|
-
* `import.meta.env
|
|
519
|
-
*
|
|
520
|
-
*
|
|
521
|
-
* `
|
|
522
|
-
*
|
|
523
|
-
*
|
|
518
|
+
* Reads **only** `process.env`. This module must never reference
|
|
519
|
+
* `import.meta.env`: in an Astro/Vite production build the bare
|
|
520
|
+
* `import.meta.env` expression is statically replaced with an object
|
|
521
|
+
* literal built from the env loaded at build time, which (a) embeds any
|
|
522
|
+
* secret present in `.env` on the build machine into the shipped server
|
|
523
|
+
* bundle, and (b) makes that stale build-time value silently shadow the
|
|
524
|
+
* real runtime secret configured on the deployment platform (e.g. via
|
|
525
|
+
* `wrangler secret put`). See #2139.
|
|
526
|
+
*
|
|
527
|
+
* `process.env` is the runtime source on Node/container deployments and
|
|
528
|
+
* on Cloudflare Workers with Node compatibility (the same source
|
|
529
|
+
* `resolveS3Config` in `../storage/s3.ts` uses). The CLI surface
|
|
530
|
+
* (`cli/commands/secrets.ts`) runs outside the bundle where
|
|
531
|
+
* `process.env` is native.
|
|
524
532
|
*
|
|
525
533
|
* The convention documented in AGENTS.md ("import.meta.env.EMDASH_X ||
|
|
526
|
-
* import.meta.env.X") is
|
|
527
|
-
*
|
|
534
|
+
* import.meta.env.X") is for public, build-time config in route
|
|
535
|
+
* handlers; secrets are deliberately excluded from it.
|
|
528
536
|
*/
|
|
529
537
|
function readDefaultEnv(): SecretsEnv {
|
|
530
|
-
// eslint-disable-next-line typescript/no-unsafe-type-assertion -- import.meta.env is loose by design
|
|
531
|
-
const meta = (import.meta.env ?? {}) as Record<string, string | undefined>;
|
|
532
538
|
const proc = typeof process !== "undefined" && process.env ? process.env : {};
|
|
533
539
|
|
|
534
540
|
return {
|
|
535
|
-
EMDASH_ENCRYPTION_KEY:
|
|
536
|
-
EMDASH_PREVIEW_SECRET:
|
|
537
|
-
PREVIEW_SECRET:
|
|
538
|
-
EMDASH_IP_SALT:
|
|
539
|
-
EMDASH_AUTH_SECRET:
|
|
540
|
-
AUTH_SECRET:
|
|
541
|
+
EMDASH_ENCRYPTION_KEY: proc.EMDASH_ENCRYPTION_KEY,
|
|
542
|
+
EMDASH_PREVIEW_SECRET: proc.EMDASH_PREVIEW_SECRET,
|
|
543
|
+
PREVIEW_SECRET: proc.PREVIEW_SECRET,
|
|
544
|
+
EMDASH_IP_SALT: proc.EMDASH_IP_SALT,
|
|
545
|
+
EMDASH_AUTH_SECRET: proc.EMDASH_AUTH_SECRET,
|
|
546
|
+
AUTH_SECRET: proc.AUTH_SECRET,
|
|
541
547
|
};
|
|
542
548
|
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared sanitization for gallery block images, used by both converters so
|
|
3
|
+
* the editor round-trip and the stored shape stay in lockstep.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { PortableTextGalleryImage } from "./types.js";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Normalize an untrusted `images` value into well-formed gallery images.
|
|
10
|
+
* Non-object entries and entries without an asset object are dropped.
|
|
11
|
+
* Missing `_key`s are filled via `generateKey` when provided (PM → PT);
|
|
12
|
+
* left empty otherwise (PT → PM keeps whatever the block carried).
|
|
13
|
+
*/
|
|
14
|
+
export function sanitizeGalleryImages(
|
|
15
|
+
value: unknown,
|
|
16
|
+
generateKey?: () => string,
|
|
17
|
+
): PortableTextGalleryImage[] {
|
|
18
|
+
if (!Array.isArray(value)) return [];
|
|
19
|
+
|
|
20
|
+
const images: PortableTextGalleryImage[] = [];
|
|
21
|
+
for (const entry of value as unknown[]) {
|
|
22
|
+
if (!isRecord(entry)) continue;
|
|
23
|
+
const record = entry;
|
|
24
|
+
const asset = record.asset;
|
|
25
|
+
if (!isRecord(asset)) continue;
|
|
26
|
+
const assetRecord = asset;
|
|
27
|
+
|
|
28
|
+
const image: PortableTextGalleryImage = {
|
|
29
|
+
_type: "image",
|
|
30
|
+
_key:
|
|
31
|
+
typeof record._key === "string" && record._key
|
|
32
|
+
? record._key
|
|
33
|
+
: generateKey
|
|
34
|
+
? generateKey()
|
|
35
|
+
: "",
|
|
36
|
+
asset: {
|
|
37
|
+
_type: "reference",
|
|
38
|
+
_ref: typeof assetRecord._ref === "string" ? assetRecord._ref : "",
|
|
39
|
+
...(typeof assetRecord.url === "string" && assetRecord.url ? { url: assetRecord.url } : {}),
|
|
40
|
+
...(typeof assetRecord.provider === "string" && assetRecord.provider
|
|
41
|
+
? { provider: assetRecord.provider }
|
|
42
|
+
: {}),
|
|
43
|
+
},
|
|
44
|
+
};
|
|
45
|
+
if (typeof record.alt === "string" && record.alt) image.alt = record.alt;
|
|
46
|
+
if (typeof record.caption === "string" && record.caption) image.caption = record.caption;
|
|
47
|
+
if (typeof record.width === "number") image.width = record.width;
|
|
48
|
+
if (typeof record.height === "number") image.height = record.height;
|
|
49
|
+
if (typeof record.blurhash === "string" && record.blurhash) image.blurhash = record.blurhash;
|
|
50
|
+
if (typeof record.dominantColor === "string" && record.dominantColor)
|
|
51
|
+
image.dominantColor = record.dominantColor;
|
|
52
|
+
|
|
53
|
+
images.push(image);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return images;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
60
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
61
|
+
}
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* Converts Portable Text to TipTap's ProseMirror JSON format for editing.
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
+
import { sanitizeGalleryImages } from "./gallery.js";
|
|
7
8
|
import type {
|
|
8
9
|
ProseMirrorDocument,
|
|
9
10
|
ProseMirrorNode,
|
|
@@ -13,6 +14,7 @@ import type {
|
|
|
13
14
|
PortableTextSpan,
|
|
14
15
|
PortableTextMarkDef,
|
|
15
16
|
PortableTextImageBlock,
|
|
17
|
+
PortableTextGalleryBlock,
|
|
16
18
|
PortableTextCodeBlock,
|
|
17
19
|
} from "./types.js";
|
|
18
20
|
|
|
@@ -128,6 +130,14 @@ function isImageBlock(block: PortableTextBlock): block is PortableTextImageBlock
|
|
|
128
130
|
);
|
|
129
131
|
}
|
|
130
132
|
|
|
133
|
+
/**
|
|
134
|
+
* Type guard for gallery blocks. Requires an `images` array — a gallery
|
|
135
|
+
* without one is malformed and falls through to the unknown-block path.
|
|
136
|
+
*/
|
|
137
|
+
function isGalleryBlock(block: PortableTextBlock): block is PortableTextGalleryBlock {
|
|
138
|
+
return block._type === "gallery" && "images" in block && Array.isArray(block.images);
|
|
139
|
+
}
|
|
140
|
+
|
|
131
141
|
/**
|
|
132
142
|
* Type guard for code blocks
|
|
133
143
|
*/
|
|
@@ -149,6 +159,15 @@ function convertBlock(block: PortableTextBlock): ProseMirrorNode | null {
|
|
|
149
159
|
// Malformed image block (no asset wrapper) — extract url from top level
|
|
150
160
|
return convertMalformedImage(block);
|
|
151
161
|
}
|
|
162
|
+
if (isGalleryBlock(block)) {
|
|
163
|
+
return {
|
|
164
|
+
type: "gallery",
|
|
165
|
+
attrs: {
|
|
166
|
+
images: sanitizeGalleryImages(block.images),
|
|
167
|
+
columns: typeof block.columns === "number" ? block.columns : undefined,
|
|
168
|
+
},
|
|
169
|
+
};
|
|
170
|
+
}
|
|
152
171
|
if (isCodeBlock(block)) {
|
|
153
172
|
return convertCodeBlock(block);
|
|
154
173
|
}
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* Converts TipTap's ProseMirror JSON format to Portable Text for storage.
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
+
import { sanitizeGalleryImages } from "./gallery.js";
|
|
7
8
|
import type {
|
|
8
9
|
ProseMirrorDocument,
|
|
9
10
|
ProseMirrorNode,
|
|
@@ -13,6 +14,7 @@ import type {
|
|
|
13
14
|
PortableTextSpan,
|
|
14
15
|
PortableTextMarkDef,
|
|
15
16
|
PortableTextImageBlock,
|
|
17
|
+
PortableTextGalleryBlock,
|
|
16
18
|
PortableTextCodeBlock,
|
|
17
19
|
PortableTextHtmlBlock,
|
|
18
20
|
} from "./types.js";
|
|
@@ -77,6 +79,9 @@ function convertNode(node: ProseMirrorNode): PortableTextBlock | PortableTextBlo
|
|
|
77
79
|
case "image":
|
|
78
80
|
return convertImage(node);
|
|
79
81
|
|
|
82
|
+
case "gallery":
|
|
83
|
+
return convertGallery(node);
|
|
84
|
+
|
|
80
85
|
case "horizontalRule":
|
|
81
86
|
return {
|
|
82
87
|
_type: "break",
|
|
@@ -327,6 +332,19 @@ function convertImage(node: ProseMirrorNode): PortableTextImageBlock {
|
|
|
327
332
|
};
|
|
328
333
|
}
|
|
329
334
|
|
|
335
|
+
/**
|
|
336
|
+
* Convert gallery node to Portable Text
|
|
337
|
+
*/
|
|
338
|
+
function convertGallery(node: ProseMirrorNode): PortableTextGalleryBlock {
|
|
339
|
+
const columns = node.attrs?.columns;
|
|
340
|
+
return {
|
|
341
|
+
_type: "gallery",
|
|
342
|
+
_key: generateKey(),
|
|
343
|
+
images: sanitizeGalleryImages(node.attrs?.images, generateKey),
|
|
344
|
+
...(typeof columns === "number" ? { columns } : {}),
|
|
345
|
+
};
|
|
346
|
+
}
|
|
347
|
+
|
|
330
348
|
/**
|
|
331
349
|
* Convert inline content (text nodes with marks) to Portable Text spans
|
|
332
350
|
*/
|
|
@@ -70,6 +70,41 @@ export interface PortableTextImageBlock {
|
|
|
70
70
|
displayHeight?: number;
|
|
71
71
|
}
|
|
72
72
|
|
|
73
|
+
/**
|
|
74
|
+
* A single image inside a gallery block. Mirrors the shape produced by
|
|
75
|
+
* gutenberg-to-portable-text and consumed by Gallery.astro.
|
|
76
|
+
*/
|
|
77
|
+
export interface PortableTextGalleryImage {
|
|
78
|
+
_type: "image";
|
|
79
|
+
_key: string;
|
|
80
|
+
asset: {
|
|
81
|
+
/** Present on WordPress-imported galleries; always emitted on round-trip */
|
|
82
|
+
_type?: "reference";
|
|
83
|
+
_ref: string;
|
|
84
|
+
url?: string;
|
|
85
|
+
/** Provider ID for external media (e.g., "cloudflare-images") */
|
|
86
|
+
provider?: string;
|
|
87
|
+
};
|
|
88
|
+
alt?: string;
|
|
89
|
+
caption?: string;
|
|
90
|
+
width?: number;
|
|
91
|
+
height?: number;
|
|
92
|
+
/** LQIP blurhash placeholder (images only) */
|
|
93
|
+
blurhash?: string;
|
|
94
|
+
/** LQIP dominant-color placeholder, as a CSS color (images only) */
|
|
95
|
+
dominantColor?: string;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Gallery block (grid of images with optional per-image captions)
|
|
100
|
+
*/
|
|
101
|
+
export interface PortableTextGalleryBlock {
|
|
102
|
+
_type: "gallery";
|
|
103
|
+
_key: string;
|
|
104
|
+
images: PortableTextGalleryImage[];
|
|
105
|
+
columns?: number;
|
|
106
|
+
}
|
|
107
|
+
|
|
73
108
|
/**
|
|
74
109
|
* Code block
|
|
75
110
|
*/
|
|
@@ -105,6 +140,7 @@ export interface PortableTextUnknownBlock {
|
|
|
105
140
|
export type PortableTextBlock =
|
|
106
141
|
| PortableTextTextBlock
|
|
107
142
|
| PortableTextImageBlock
|
|
143
|
+
| PortableTextGalleryBlock
|
|
108
144
|
| PortableTextCodeBlock
|
|
109
145
|
| PortableTextHtmlBlock
|
|
110
146
|
| PortableTextUnknownBlock;
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
13
|
import type { ColumnDataType, Kysely, RawBuilder } from "kysely";
|
|
14
|
-
import { sql } from "kysely";
|
|
14
|
+
import { PostgresAdapter, sql } from "kysely";
|
|
15
15
|
|
|
16
16
|
import type { DatabaseDialectType } from "../db/adapters.js";
|
|
17
17
|
import { validateIdentifier, validateJsonFieldName } from "./validate.js";
|
|
@@ -19,12 +19,11 @@ import { validateIdentifier, validateJsonFieldName } from "./validate.js";
|
|
|
19
19
|
export type { DatabaseDialectType };
|
|
20
20
|
|
|
21
21
|
/**
|
|
22
|
-
* Detect dialect type from a Kysely instance via the adapter class
|
|
22
|
+
* Detect dialect type from a Kysely instance via the adapter class.
|
|
23
23
|
*/
|
|
24
24
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- accepts any Kysely instance
|
|
25
25
|
export function detectDialect(db: Kysely<any>): DatabaseDialectType {
|
|
26
|
-
|
|
27
|
-
if (name === "PostgresAdapter") return "postgres";
|
|
26
|
+
if (db.getExecutor().adapter instanceof PostgresAdapter) return "postgres";
|
|
28
27
|
return "sqlite";
|
|
29
28
|
}
|
|
30
29
|
|
|
@@ -38,10 +38,7 @@ const KYSELY_PG_MIGRATION_LOCK_ID = BigInt("3853314791062309107");
|
|
|
38
38
|
|
|
39
39
|
/**
|
|
40
40
|
* Extends the stock adapter so every capability flag and `instanceof` check
|
|
41
|
-
* is inherited
|
|
42
|
-
* `detectDialect()` (dialect-helpers.ts) identifies the dialect via
|
|
43
|
-
* `adapter.constructor.name` — a differently-named adapter would make every
|
|
44
|
-
* dialect helper fall back to SQLite SQL against a Postgres database.
|
|
41
|
+
* is inherited.
|
|
45
42
|
*/
|
|
46
43
|
class PostgresAdapter extends KyselyPostgresAdapter {
|
|
47
44
|
// eslint-disable-next-line typescript/no-explicit-any -- matches the DialectAdapter signature
|