emdash 0.30.0 → 0.31.1
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-BkqFzIu4.mjs} +23 -23
- package/dist/api-BkqFzIu4.mjs.map +1 -0
- package/dist/{apply-CmIJK9j8.mjs → apply-DuXsqll7.mjs} +26 -25
- package/dist/apply-DuXsqll7.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 +146 -70
- 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-DoW-H0r4.mjs} +2 -2
- package/dist/{backup-S8kFWtwD.mjs.map → backup-DoW-H0r4.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-Bc-3xtpz.mjs} +6 -6
- package/dist/{bylines-czseViYo.mjs.map → bylines-Bc-3xtpz.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-BZJ_5FOX.d.mts} +50 -4
- package/dist/index-BZJ_5FOX.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-Bz9bWZfm.mjs} +14 -14
- package/dist/{query-DR73ZNfm.mjs.map → query-Bz9bWZfm.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-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/{relations-Bh8jlFsU.d.mts → relations-qKmSj9KM.d.mts} +27 -23
- package/dist/relations-qKmSj9KM.d.mts.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-Ce49uIzY.mjs → taxonomies-BN6M9Nrv.mjs} +26 -17
- package/dist/taxonomies-BN6M9Nrv.mjs.map +1 -0
- package/dist/{taxonomies-DjSKBZpq.mjs → taxonomies-r7pqLBCn.mjs} +53 -24
- package/dist/taxonomies-r7pqLBCn.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-BRMngh9I.mjs +7 -0
- package/dist/{version-907opKac.mjs.map → version-BRMngh9I.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-DrihupaC.mjs} +4 -4
- package/dist/{wxr-taxonomies-Cs1N6O8z.mjs.map → wxr-taxonomies-DrihupaC.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 +7 -7
- 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/prefetch.ts +7 -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/components/widgets/Categories.astro +1 -1
- package/src/components/widgets/Tags.astro +1 -1
- 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/src/taxonomies/index.ts +64 -23
- 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/taxonomies-DjSKBZpq.mjs.map +0 -1
- package/dist/validate-V9nCwq_-.mjs.map +0 -1
- package/dist/version-907opKac.mjs +0 -7
|
@@ -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
|
|
|
@@ -12,7 +12,7 @@ interface Props {
|
|
|
12
12
|
|
|
13
13
|
const { showCount = true, hierarchical = true } = Astro.props;
|
|
14
14
|
|
|
15
|
-
const categories = await getTaxonomyTerms("category");
|
|
15
|
+
const categories = await getTaxonomyTerms("category", { includeCounts: showCount });
|
|
16
16
|
---
|
|
17
17
|
|
|
18
18
|
<ul class="widget-categories">
|
|
@@ -12,7 +12,7 @@ interface Props {
|
|
|
12
12
|
|
|
13
13
|
const { showCount = false, limit = 20 } = Astro.props;
|
|
14
14
|
|
|
15
|
-
const allTags = await getTaxonomyTerms("tag");
|
|
15
|
+
const allTags = await getTaxonomyTerms("tag", { includeCounts: showCount });
|
|
16
16
|
const tags = allTags.slice(0, limit);
|
|
17
17
|
---
|
|
18
18
|
|
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
|
package/src/emdash-runtime.ts
CHANGED
|
@@ -36,6 +36,8 @@ import type {
|
|
|
36
36
|
ContentDateField,
|
|
37
37
|
} from "./database/repositories/types.js";
|
|
38
38
|
import { validateIdentifier } from "./database/validate.js";
|
|
39
|
+
import { getI18nConfig } from "./i18n/config.js";
|
|
40
|
+
import { repairLocaleCasing } from "./i18n/repair-locale-casing.js";
|
|
39
41
|
import { normalizeMediaValue } from "./media/normalize.js";
|
|
40
42
|
import type { MediaProvider, MediaProviderCapabilities } from "./media/types.js";
|
|
41
43
|
import {
|
|
@@ -71,6 +73,12 @@ import { createSingleFlightCache, singleFlightCached } from "./utils/single-flig
|
|
|
71
73
|
import { COMMIT, VERSION } from "./version.js";
|
|
72
74
|
|
|
73
75
|
const LEADING_SLASH_PATTERN = /^\//;
|
|
76
|
+
const LOCALE_CASING_REPAIR_OPTION = "emdash:repair_locale_casing";
|
|
77
|
+
|
|
78
|
+
function getLocaleCasingRepairVersion(locales: readonly string[]): string | null {
|
|
79
|
+
if (locales.length === 0) return null;
|
|
80
|
+
return `1:${locales.toSorted().join(",")}`;
|
|
81
|
+
}
|
|
74
82
|
|
|
75
83
|
/**
|
|
76
84
|
* Parse a JSON column expected to contain an array of strings.
|
|
@@ -1130,6 +1138,10 @@ export class EmDashRuntime {
|
|
|
1130
1138
|
const storage = EmDashRuntime.getStorage(deps);
|
|
1131
1139
|
|
|
1132
1140
|
let pluginStates: Map<string, string> = new Map();
|
|
1141
|
+
const configuredLocales: string[] =
|
|
1142
|
+
virtualConfig?.i18n?.locales ?? getI18nConfig()?.locales ?? [];
|
|
1143
|
+
const localeCasingRepairVersion = getLocaleCasingRepairVersion(configuredLocales);
|
|
1144
|
+
let storedLocaleCasingRepairVersion: string | undefined;
|
|
1133
1145
|
let siteInfo:
|
|
1134
1146
|
| {
|
|
1135
1147
|
siteName?: string;
|
|
@@ -1175,7 +1187,9 @@ export class EmDashRuntime {
|
|
|
1175
1187
|
"emdash:site_title",
|
|
1176
1188
|
"emdash:site_url",
|
|
1177
1189
|
"emdash:locale",
|
|
1190
|
+
LOCALE_CASING_REPAIR_OPTION,
|
|
1178
1191
|
]);
|
|
1192
|
+
storedLocaleCasingRepairVersion = siteOpts.get(LOCALE_CASING_REPAIR_OPTION);
|
|
1179
1193
|
return {
|
|
1180
1194
|
siteName: siteOpts.get("emdash:site_title") ?? undefined,
|
|
1181
1195
|
siteUrl: siteOpts.get("emdash:site_url") ?? undefined,
|
|
@@ -1241,6 +1255,20 @@ export class EmDashRuntime {
|
|
|
1241
1255
|
|
|
1242
1256
|
await Promise.all(coldStartReads);
|
|
1243
1257
|
|
|
1258
|
+
if (
|
|
1259
|
+
localeCasingRepairVersion &&
|
|
1260
|
+
(configuredLocales.some(
|
|
1261
|
+
(locale) => locale.includes("-") || locale !== locale.toLowerCase(),
|
|
1262
|
+
) ||
|
|
1263
|
+
storedLocaleCasingRepairVersion !== undefined) &&
|
|
1264
|
+
storedLocaleCasingRepairVersion !== localeCasingRepairVersion
|
|
1265
|
+
) {
|
|
1266
|
+
await phase("rt.locale", "Repair locale casing", async () => {
|
|
1267
|
+
await repairLocaleCasing(db, configuredLocales);
|
|
1268
|
+
await new OptionsRepository(db).set(LOCALE_CASING_REPAIR_OPTION, localeCasingRepairVersion);
|
|
1269
|
+
});
|
|
1270
|
+
}
|
|
1271
|
+
|
|
1244
1272
|
// Auto-seed the default schema for a first load that skipped the setup
|
|
1245
1273
|
// wizard (the wizard and dev-bypass apply seeds explicitly). Run under a
|
|
1246
1274
|
// per-isolate lock keyed by the configured db so a reclaimed-and-rerun
|
|
@@ -2965,7 +2993,7 @@ export class EmDashRuntime {
|
|
|
2965
2993
|
await this.refreshContentUsageAfterSuccessfulWrite(collection, [result.data.id]);
|
|
2966
2994
|
}
|
|
2967
2995
|
|
|
2968
|
-
// Run afterDelete hooks (
|
|
2996
|
+
// Run afterDelete hooks (deferred past the response via after())
|
|
2969
2997
|
if (result.success) {
|
|
2970
2998
|
this.runAfterDeleteHooks(id, collection, false);
|
|
2971
2999
|
}
|
|
@@ -3052,7 +3080,7 @@ export class EmDashRuntime {
|
|
|
3052
3080
|
await this.refreshContentUsageAfterSuccessfulWrite(collection, [result.data.item.id]);
|
|
3053
3081
|
}
|
|
3054
3082
|
|
|
3055
|
-
// Run afterUnpublish hooks (
|
|
3083
|
+
// Run afterUnpublish hooks (deferred past the response via after())
|
|
3056
3084
|
if (result.success && result.data) {
|
|
3057
3085
|
this.runAfterUnpublishHooks(contentItemToRecord(result.data.item), collection);
|
|
3058
3086
|
}
|
|
@@ -3746,24 +3774,34 @@ export class EmDashRuntime {
|
|
|
3746
3774
|
}
|
|
3747
3775
|
|
|
3748
3776
|
private runAfterDeleteHooks(id: string, collection: string, permanent: boolean): void {
|
|
3749
|
-
|
|
3750
|
-
|
|
3751
|
-
this.hooks
|
|
3752
|
-
|
|
3753
|
-
|
|
3754
|
-
|
|
3777
|
+
after(async () => {
|
|
3778
|
+
// Trusted plugins
|
|
3779
|
+
if (this.hooks.hasHooks("content:afterDelete")) {
|
|
3780
|
+
try {
|
|
3781
|
+
await this.hooks.runContentAfterDelete(id, collection, permanent);
|
|
3782
|
+
} catch (err) {
|
|
3783
|
+
console.error("EmDash afterDelete hook error:", err);
|
|
3784
|
+
}
|
|
3785
|
+
}
|
|
3755
3786
|
|
|
3756
|
-
|
|
3757
|
-
|
|
3758
|
-
const [
|
|
3759
|
-
|
|
3787
|
+
// Sandboxed plugins
|
|
3788
|
+
const tasks: Promise<void>[] = [];
|
|
3789
|
+
for (const [pluginKey, plugin] of this.sandboxedPlugins) {
|
|
3790
|
+
const [pluginId] = pluginKey.split(":");
|
|
3791
|
+
if (!pluginId || !this.isPluginEnabled(pluginId)) continue;
|
|
3760
3792
|
|
|
3761
|
-
|
|
3762
|
-
|
|
3763
|
-
|
|
3764
|
-
|
|
3793
|
+
tasks.push(
|
|
3794
|
+
(async () => {
|
|
3795
|
+
try {
|
|
3796
|
+
await plugin.invokeHook("content:afterDelete", { id, collection, permanent });
|
|
3797
|
+
} catch (err) {
|
|
3798
|
+
console.error(`EmDash: Sandboxed plugin ${pluginId} afterDelete error:`, err);
|
|
3799
|
+
}
|
|
3800
|
+
})(),
|
|
3765
3801
|
);
|
|
3766
|
-
|
|
3802
|
+
}
|
|
3803
|
+
await Promise.allSettled(tasks);
|
|
3804
|
+
});
|
|
3767
3805
|
}
|
|
3768
3806
|
|
|
3769
3807
|
private runDeferredContentHook(
|
package/src/i18n/config.ts
CHANGED
|
@@ -30,6 +30,14 @@ export function getI18nConfig(): I18nConfig | null {
|
|
|
30
30
|
return _config ?? null;
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
+
/** Match a locale to the exact casing used by the site configuration. */
|
|
34
|
+
export function resolveConfiguredLocale(locale: string): string {
|
|
35
|
+
return (
|
|
36
|
+
_config?.locales.find((configured) => configured.toLowerCase() === locale.toLowerCase()) ??
|
|
37
|
+
locale
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
|
|
33
41
|
/**
|
|
34
42
|
* Check if i18n is enabled.
|
|
35
43
|
* Returns true when multiple locales are configured.
|