emdash 0.22.0 → 0.23.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/{adapters-hUy8vOB-.d.mts → adapters-DAAjOID4.d.mts} +1 -1
- package/dist/{adapters-hUy8vOB-.d.mts.map → adapters-DAAjOID4.d.mts.map} +1 -1
- package/dist/{allowed-origins-DjlhyfNN.mjs → allowed-origins-D5FxMUo8.mjs} +2 -2
- package/dist/{allowed-origins-DjlhyfNN.mjs.map → allowed-origins-D5FxMUo8.mjs.map} +1 -1
- package/dist/api/route-utils.d.mts +3 -3
- package/dist/api/route-utils.mjs +11 -11
- package/dist/api/schemas/index.d.mts +1 -1
- package/dist/api/schemas/index.mjs +3 -3
- package/dist/{api-BDuM4bEy.mjs → api-BQ_yKRdG.mjs} +12 -12
- package/dist/{api-BDuM4bEy.mjs.map → api-BQ_yKRdG.mjs.map} +1 -1
- package/dist/{api-tokens-ViYKeIp9.mjs → api-tokens-D6ppjIVi.mjs} +2 -2
- package/dist/{api-tokens-ViYKeIp9.mjs.map → api-tokens-D6ppjIVi.mjs.map} +1 -1
- package/dist/{apply-wDqQoxX4.mjs → apply-CWRyxIoO.mjs} +12 -12
- package/dist/{apply-wDqQoxX4.mjs.map → apply-CWRyxIoO.mjs.map} +1 -1
- package/dist/astro/index.d.mts +11 -11
- package/dist/astro/index.mjs +12 -6
- package/dist/astro/index.mjs.map +1 -1
- package/dist/astro/middleware/auth.d.mts +9 -9
- package/dist/astro/middleware/auth.mjs +6 -6
- package/dist/astro/middleware/redirect.mjs +3 -3
- package/dist/astro/middleware/request-context.d.mts.map +1 -1
- package/dist/astro/middleware/request-context.mjs +5 -3
- package/dist/astro/middleware/request-context.mjs.map +1 -1
- package/dist/astro/middleware/setup.mjs +1 -1
- package/dist/astro/middleware.d.mts +1 -1
- package/dist/astro/middleware.d.mts.map +1 -1
- package/dist/astro/middleware.mjs +349 -128
- package/dist/astro/middleware.mjs.map +1 -1
- package/dist/astro/routes/api/admin/allowed-domains/_domain_.mjs +5 -5
- package/dist/astro/routes/api/admin/allowed-domains/index.mjs +5 -5
- package/dist/astro/routes/api/admin/api-tokens/_id_.mjs +3 -3
- package/dist/astro/routes/api/admin/api-tokens/index.mjs +4 -4
- 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 +12 -11
- package/dist/astro/routes/api/admin/bylines/_id_/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/bylines/_id_/translations.mjs +12 -11
- package/dist/astro/routes/api/admin/bylines/_id_/translations.mjs.map +1 -1
- package/dist/astro/routes/api/admin/bylines/index.mjs +12 -11
- package/dist/astro/routes/api/admin/bylines/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/comments/_id_/status.mjs +9 -9
- package/dist/astro/routes/api/admin/comments/_id_.mjs +3 -3
- package/dist/astro/routes/api/admin/comments/bulk.mjs +7 -7
- package/dist/astro/routes/api/admin/comments/counts.mjs +3 -3
- package/dist/astro/routes/api/admin/comments/index.mjs +7 -7
- package/dist/astro/routes/api/admin/hooks/exclusive/_hookName_.mjs +3 -3
- package/dist/astro/routes/api/admin/hooks/exclusive/index.mjs +2 -2
- 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 +27 -26
- package/dist/astro/routes/api/admin/plugins/_id_/disable.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/_id_/enable.mjs +27 -26
- package/dist/astro/routes/api/admin/plugins/_id_/enable.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/_id_/index.mjs +26 -25
- package/dist/astro/routes/api/admin/plugins/_id_/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/_id_/uninstall.mjs +26 -25
- package/dist/astro/routes/api/admin/plugins/_id_/uninstall.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/_id_/update.mjs +26 -25
- package/dist/astro/routes/api/admin/plugins/_id_/update.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/index.mjs +26 -25
- package/dist/astro/routes/api/admin/plugins/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/marketplace/_id_/icon.mjs +2 -2
- package/dist/astro/routes/api/admin/plugins/marketplace/_id_/index.mjs +26 -25
- package/dist/astro/routes/api/admin/plugins/marketplace/_id_/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/marketplace/_id_/install.mjs +26 -25
- package/dist/astro/routes/api/admin/plugins/marketplace/_id_/install.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/marketplace/index.mjs +26 -25
- package/dist/astro/routes/api/admin/plugins/marketplace/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/registry/_id_/uninstall.mjs +26 -25
- package/dist/astro/routes/api/admin/plugins/registry/_id_/uninstall.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/registry/_id_/update.mjs +27 -26
- package/dist/astro/routes/api/admin/plugins/registry/_id_/update.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/registry/artifact.mjs +26 -25
- package/dist/astro/routes/api/admin/plugins/registry/artifact.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/registry/install.mjs +27 -26
- package/dist/astro/routes/api/admin/plugins/registry/install.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/updates.mjs +26 -25
- package/dist/astro/routes/api/admin/plugins/updates.mjs.map +1 -1
- package/dist/astro/routes/api/admin/themes/marketplace/_id_/index.mjs +26 -25
- package/dist/astro/routes/api/admin/themes/marketplace/_id_/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/themes/marketplace/_id_/thumbnail.mjs +2 -2
- package/dist/astro/routes/api/admin/themes/marketplace/index.mjs +26 -25
- package/dist/astro/routes/api/admin/themes/marketplace/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/users/_id_/disable.mjs +1 -1
- package/dist/astro/routes/api/admin/users/_id_/enable.mjs +1 -1
- package/dist/astro/routes/api/admin/users/_id_/index.mjs +5 -5
- package/dist/astro/routes/api/admin/users/_id_/send-recovery.mjs +2 -2
- package/dist/astro/routes/api/admin/users/index.mjs +5 -5
- package/dist/astro/routes/api/auth/dev-bypass.mjs +3 -3
- package/dist/astro/routes/api/auth/invite/accept.mjs +1 -1
- package/dist/astro/routes/api/auth/invite/complete.mjs +9 -9
- package/dist/astro/routes/api/auth/invite/index.mjs +6 -6
- package/dist/astro/routes/api/auth/invite/register-options.mjs +8 -8
- package/dist/astro/routes/api/auth/logout.mjs +2 -2
- package/dist/astro/routes/api/auth/magic-link/send.mjs +8 -8
- package/dist/astro/routes/api/auth/magic-link/verify.mjs +2 -2
- package/dist/astro/routes/api/auth/me.mjs +5 -5
- package/dist/astro/routes/api/auth/mode.mjs +1 -1
- package/dist/astro/routes/api/auth/oauth/_provider_/callback.mjs +3 -3
- package/dist/astro/routes/api/auth/oauth/_provider_.mjs +2 -2
- package/dist/astro/routes/api/auth/passkey/_id_.mjs +5 -5
- package/dist/astro/routes/api/auth/passkey/index.mjs +1 -1
- package/dist/astro/routes/api/auth/passkey/options.mjs +10 -10
- package/dist/astro/routes/api/auth/passkey/register/options.mjs +8 -8
- package/dist/astro/routes/api/auth/passkey/register/verify.mjs +9 -9
- package/dist/astro/routes/api/auth/passkey/verify.mjs +9 -9
- package/dist/astro/routes/api/auth/signup/complete.mjs +9 -9
- package/dist/astro/routes/api/auth/signup/request.mjs +8 -8
- package/dist/astro/routes/api/auth/signup/verify.mjs +1 -1
- package/dist/astro/routes/api/comments/_collection_/_contentId_/index.mjs +10 -10
- package/dist/astro/routes/api/comments/_collection_/_contentId_/reactions.mjs +9 -9
- package/dist/astro/routes/api/content/_collection_/_id_/compare.mjs +2 -2
- package/dist/astro/routes/api/content/_collection_/_id_/discard-draft.mjs +2 -2
- package/dist/astro/routes/api/content/_collection_/_id_/duplicate.mjs +2 -2
- package/dist/astro/routes/api/content/_collection_/_id_/permanent.mjs +2 -2
- package/dist/astro/routes/api/content/_collection_/_id_/preview-url.mjs +9 -9
- package/dist/astro/routes/api/content/_collection_/_id_/publish.mjs +6 -6
- package/dist/astro/routes/api/content/_collection_/_id_/restore.mjs +2 -2
- package/dist/astro/routes/api/content/_collection_/_id_/revisions.mjs +2 -2
- package/dist/astro/routes/api/content/_collection_/_id_/schedule.mjs +6 -6
- package/dist/astro/routes/api/content/_collection_/_id_/terms/_taxonomy_.mjs +9 -9
- package/dist/astro/routes/api/content/_collection_/_id_/translations.mjs +2 -2
- package/dist/astro/routes/api/content/_collection_/_id_/unpublish.mjs +2 -2
- package/dist/astro/routes/api/content/_collection_/_id_.mjs +6 -6
- package/dist/astro/routes/api/content/_collection_/authors.mjs +2 -2
- package/dist/astro/routes/api/content/_collection_/index.mjs +6 -6
- package/dist/astro/routes/api/content/_collection_/trash.mjs +6 -6
- package/dist/astro/routes/api/dashboard.mjs +3 -3
- package/dist/astro/routes/api/dev/emails.mjs +2 -2
- package/dist/astro/routes/api/import/probe.d.mts +3 -3
- package/dist/astro/routes/api/import/probe.mjs +10 -10
- package/dist/astro/routes/api/import/wordpress/analyze.mjs +2 -2
- package/dist/astro/routes/api/import/wordpress/execute.d.mts +9 -9
- package/dist/astro/routes/api/import/wordpress/execute.mjs +8 -7
- package/dist/astro/routes/api/import/wordpress/execute.mjs.map +1 -1
- package/dist/astro/routes/api/import/wordpress/media.mjs +8 -8
- package/dist/astro/routes/api/import/wordpress/prepare.mjs +8 -8
- package/dist/astro/routes/api/import/wordpress/rewrite-urls.mjs +8 -8
- package/dist/astro/routes/api/import/wordpress-plugin/analyze.d.mts +1 -1
- package/dist/astro/routes/api/import/wordpress-plugin/analyze.mjs +10 -10
- package/dist/astro/routes/api/import/wordpress-plugin/execute.d.mts +1 -1
- package/dist/astro/routes/api/import/wordpress-plugin/execute.mjs +12 -11
- package/dist/astro/routes/api/import/wordpress-plugin/execute.mjs.map +1 -1
- package/dist/astro/routes/api/manifest.mjs +3 -3
- package/dist/astro/routes/api/mcp.mjs +29 -29
- package/dist/astro/routes/api/media/_id_/confirm.mjs +6 -6
- package/dist/astro/routes/api/media/_id_.mjs +6 -6
- package/dist/astro/routes/api/media/file/_...key_.mjs +1 -1
- package/dist/astro/routes/api/media/providers/_providerId_/_itemId_.mjs +2 -2
- package/dist/astro/routes/api/media/providers/_providerId_/index.mjs +2 -2
- package/dist/astro/routes/api/media/providers/index.mjs +2 -2
- package/dist/astro/routes/api/media/upload-url.mjs +8 -8
- package/dist/astro/routes/api/media.mjs +10 -10
- package/dist/astro/routes/api/menus/_name_/items/_id_.mjs +6 -6
- package/dist/astro/routes/api/menus/_name_/items.mjs +6 -6
- package/dist/astro/routes/api/menus/_name_/reorder.mjs +6 -6
- package/dist/astro/routes/api/menus/_name_/translations.mjs +6 -6
- package/dist/astro/routes/api/menus/_name_.mjs +6 -6
- package/dist/astro/routes/api/menus/index.mjs +6 -6
- package/dist/astro/routes/api/oauth/authorize.mjs +6 -6
- package/dist/astro/routes/api/oauth/device/authorize.mjs +5 -5
- package/dist/astro/routes/api/oauth/device/code.mjs +8 -8
- package/dist/astro/routes/api/oauth/device/token.mjs +7 -7
- package/dist/astro/routes/api/oauth/register.mjs +2 -2
- package/dist/astro/routes/api/oauth/token/refresh.mjs +5 -5
- package/dist/astro/routes/api/oauth/token/revoke.mjs +5 -5
- package/dist/astro/routes/api/oauth/token.mjs +5 -5
- package/dist/astro/routes/api/openapi.json.mjs +3 -3
- package/dist/astro/routes/api/plugins/_pluginId_/_...path_.mjs +3 -3
- package/dist/astro/routes/api/redirects/404s/index.mjs +7 -7
- package/dist/astro/routes/api/redirects/404s/summary.mjs +7 -7
- package/dist/astro/routes/api/redirects/_id_.mjs +8 -8
- package/dist/astro/routes/api/redirects/index.mjs +8 -8
- package/dist/astro/routes/api/revisions/_revisionId_/index.mjs +2 -2
- package/dist/astro/routes/api/revisions/_revisionId_/restore.mjs +2 -2
- package/dist/astro/routes/api/schema/collections/_slug_/fields/_fieldSlug_.mjs +26 -25
- package/dist/astro/routes/api/schema/collections/_slug_/fields/_fieldSlug_.mjs.map +1 -1
- package/dist/astro/routes/api/schema/collections/_slug_/fields/index.mjs +26 -25
- package/dist/astro/routes/api/schema/collections/_slug_/fields/index.mjs.map +1 -1
- package/dist/astro/routes/api/schema/collections/_slug_/fields/reorder.mjs +26 -25
- package/dist/astro/routes/api/schema/collections/_slug_/fields/reorder.mjs.map +1 -1
- package/dist/astro/routes/api/schema/collections/_slug_/index.mjs +26 -25
- package/dist/astro/routes/api/schema/collections/_slug_/index.mjs.map +1 -1
- package/dist/astro/routes/api/schema/collections/index.mjs +26 -25
- package/dist/astro/routes/api/schema/collections/index.mjs.map +1 -1
- package/dist/astro/routes/api/schema/index.mjs +7 -6
- package/dist/astro/routes/api/schema/index.mjs.map +1 -1
- package/dist/astro/routes/api/schema/orphans/_slug_.mjs +26 -25
- package/dist/astro/routes/api/schema/orphans/_slug_.mjs.map +1 -1
- package/dist/astro/routes/api/schema/orphans/index.mjs +26 -25
- package/dist/astro/routes/api/schema/orphans/index.mjs.map +1 -1
- package/dist/astro/routes/api/search/enable.mjs +9 -9
- package/dist/astro/routes/api/search/index.mjs +8 -8
- package/dist/astro/routes/api/search/rebuild.mjs +9 -9
- package/dist/astro/routes/api/search/stats.mjs +5 -5
- package/dist/astro/routes/api/search/suggest.mjs +8 -8
- package/dist/astro/routes/api/sections/_slug_.mjs +8 -8
- package/dist/astro/routes/api/sections/index.mjs +8 -8
- package/dist/astro/routes/api/settings/email.mjs +3 -3
- package/dist/astro/routes/api/settings.mjs +9 -9
- package/dist/astro/routes/api/setup/admin-verify.mjs +10 -10
- package/dist/astro/routes/api/setup/admin.mjs +9 -9
- package/dist/astro/routes/api/setup/dev-bypass.mjs +17 -16
- package/dist/astro/routes/api/setup/dev-bypass.mjs.map +1 -1
- package/dist/astro/routes/api/setup/dev-reset.mjs +1 -1
- package/dist/astro/routes/api/setup/index.mjs +18 -17
- package/dist/astro/routes/api/setup/index.mjs.map +1 -1
- package/dist/astro/routes/api/setup/status.mjs +3 -3
- package/dist/astro/routes/api/snapshot.mjs +5 -5
- package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_/translations.mjs +10 -10
- package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_.mjs +10 -10
- package/dist/astro/routes/api/taxonomies/_name_/terms/index.mjs +10 -10
- package/dist/astro/routes/api/taxonomies/index.mjs +10 -10
- package/dist/astro/routes/api/themes/preview.mjs +4 -4
- package/dist/astro/routes/api/typegen.mjs +4 -4
- package/dist/astro/routes/api/well-known/auth.mjs +1 -1
- package/dist/astro/routes/api/well-known/oauth-authorization-server.mjs +2 -2
- package/dist/astro/routes/api/well-known/oauth-protected-resource.mjs +2 -2
- package/dist/astro/routes/api/widget-areas/_name_/reorder.mjs +6 -6
- package/dist/astro/routes/api/widget-areas/_name_/widgets/_id_.mjs +8 -8
- package/dist/astro/routes/api/widget-areas/_name_/widgets.mjs +8 -8
- package/dist/astro/routes/api/widget-areas/_name_.mjs +4 -4
- package/dist/astro/routes/api/widget-areas/index.mjs +8 -8
- package/dist/astro/routes/api/widget-components.mjs +2 -2
- package/dist/astro/routes/robots.txt.mjs +3 -3
- package/dist/astro/routes/sitemap-_collection_.xml.mjs +6 -6
- package/dist/astro/routes/sitemap.xml.mjs +4 -4
- package/dist/astro/types.d.mts +12 -12
- package/dist/auth/providers/github.d.mts +1 -1
- package/dist/auth/providers/google.d.mts +1 -1
- package/dist/{authorize-C0EYoUeV.mjs → authorize-Cse0k7B0.mjs} +2 -2
- package/dist/{authorize-C0EYoUeV.mjs.map → authorize-Cse0k7B0.mjs.map} +1 -1
- package/dist/{byline-CC0WS4Gu.mjs → byline-DVo-liaP.mjs} +15 -73
- package/dist/byline-DVo-liaP.mjs.map +1 -0
- package/dist/{byline-fields-53i9Et0x.mjs → byline-fields-B-KXkg5R.mjs} +2 -2
- package/dist/{byline-fields-53i9Et0x.mjs.map → byline-fields-B-KXkg5R.mjs.map} +1 -1
- package/dist/{byline-fields-DNp0HNKc.mjs → byline-fields-DaMKzkhO.mjs} +1 -1
- package/dist/{byline-fields-DNp0HNKc.mjs.map → byline-fields-DaMKzkhO.mjs.map} +1 -1
- package/dist/{byline-fields-jy07PZJM.d.mts → byline-fields-RFPkDLRw.d.mts} +21 -1
- package/dist/byline-fields-RFPkDLRw.d.mts.map +1 -0
- package/dist/{bylines-CCO1CYnH.mjs → bylines-f5ppBpD5.mjs} +6 -6
- package/dist/{bylines-CCO1CYnH.mjs.map → bylines-f5ppBpD5.mjs.map} +1 -1
- package/dist/{bylines-DGekMGGm.mjs → bylines-pIKgc_TL.mjs} +2 -2
- package/dist/{bylines-DGekMGGm.mjs.map → bylines-pIKgc_TL.mjs.map} +1 -1
- package/dist/{cache-pXTpun6s.mjs → cache-Q6V4U-Xz.mjs} +1 -1
- package/dist/{cache-pXTpun6s.mjs.map → cache-Q6V4U-Xz.mjs.map} +1 -1
- package/dist/{challenge-store-C6E_kWTs.mjs → challenge-store-LhiqMccz.mjs} +1 -1
- package/dist/{challenge-store-C6E_kWTs.mjs.map → challenge-store-LhiqMccz.mjs.map} +1 -1
- package/dist/cli/index.mjs +16 -15
- package/dist/cli/index.mjs.map +1 -1
- package/dist/client/cf-access.d.mts +1 -1
- package/dist/client/index.d.mts +1 -1
- package/dist/client/index.mjs +2 -2
- package/dist/{comment-reaction-B6AdcpXw.mjs → comment-reaction-Dyb-AutY.mjs} +1 -1
- package/dist/{comment-reaction-B6AdcpXw.mjs.map → comment-reaction-Dyb-AutY.mjs.map} +1 -1
- package/dist/{comments-CtPkT2tp.mjs → comments-Cczx7AvD.mjs} +1 -1
- package/dist/{comments-CtPkT2tp.mjs.map → comments-Cczx7AvD.mjs.map} +1 -1
- package/dist/{components-D6ZnrzbB.mjs → components-CYt4uVK9.mjs} +1 -1
- package/dist/{components-D6ZnrzbB.mjs.map → components-CYt4uVK9.mjs.map} +1 -1
- package/dist/{context-f1__jpzF.mjs → context-B1W8soLv.mjs} +58 -20
- package/dist/context-B1W8soLv.mjs.map +1 -0
- package/dist/{cron-CQPxBjYs.mjs → cron-C5LVoNmP.mjs} +14 -2
- package/dist/cron-C5LVoNmP.mjs.map +1 -0
- package/dist/{dashboard-BOESNcwE.mjs → dashboard-CYjpQZ6-.mjs} +1 -1
- package/dist/{dashboard-BOESNcwE.mjs.map → dashboard-CYjpQZ6-.mjs.map} +1 -1
- package/dist/db/index.d.mts +3 -3
- package/dist/db/libsql.d.mts +1 -1
- package/dist/db/postgres.d.mts +1 -1
- package/dist/db/sqlite.d.mts +1 -1
- package/dist/{db-errors-CrC5w3Jz.mjs → db-errors-UXB1CK42.mjs} +1 -1
- package/dist/{db-errors-CrC5w3Jz.mjs.map → db-errors-UXB1CK42.mjs.map} +1 -1
- package/dist/{default-CpBEPn6a.mjs → default-CeRG-Ot4.mjs} +1 -1
- package/dist/{default-CpBEPn6a.mjs.map → default-CeRG-Ot4.mjs.map} +1 -1
- package/dist/{device-flow-Bn-qiDrw.mjs → device-flow-DENDCQ9F.mjs} +4 -4
- package/dist/{device-flow-Bn-qiDrw.mjs.map → device-flow-DENDCQ9F.mjs.map} +1 -1
- package/dist/{email-console-B9VS6eN4.mjs → email-console-DJP32ucW.mjs} +1 -1
- package/dist/{email-console-B9VS6eN4.mjs.map → email-console-DJP32ucW.mjs.map} +1 -1
- package/dist/{error-BQ1pxs0L.mjs → error-Bl6kZgtt.mjs} +1 -1
- package/dist/{error-BQ1pxs0L.mjs.map → error-Bl6kZgtt.mjs.map} +1 -1
- package/dist/{escape-BtbJWyaW.mjs → escape-Bjio4ZsM.mjs} +1 -1
- package/dist/{escape-BtbJWyaW.mjs.map → escape-Bjio4ZsM.mjs.map} +1 -1
- package/dist/field-defs-cache-ztrdzUGb.mjs +77 -0
- package/dist/field-defs-cache-ztrdzUGb.mjs.map +1 -0
- package/dist/{fts-manager-DtiWqwNJ.mjs → fts-manager-CQuHt-vS.mjs} +1 -1
- package/dist/{fts-manager-DtiWqwNJ.mjs.map → fts-manager-CQuHt-vS.mjs.map} +1 -1
- package/dist/{hash-BowcuPwv.mjs → hash-DrvzIXcz.mjs} +1 -1
- package/dist/{hash-BowcuPwv.mjs.map → hash-DrvzIXcz.mjs.map} +1 -1
- package/dist/{import-DqSGOlmR.mjs → import-Bb1T9WJS.mjs} +3 -3
- package/dist/{import-DqSGOlmR.mjs.map → import-Bb1T9WJS.mjs.map} +1 -1
- package/dist/{index-C2dLNT6S.d.mts → index-BaIj5hIq.d.mts} +39 -17
- package/dist/index-BaIj5hIq.d.mts.map +1 -0
- package/dist/{index-ZDEwR7qW.d.mts → index-qbL02uhs.d.mts} +3 -3
- package/dist/{index-ZDEwR7qW.d.mts.map → index-qbL02uhs.d.mts.map} +1 -1
- package/dist/index.d.mts +17 -17
- package/dist/index.mjs +46 -45
- package/dist/{load-Dtoo7KcJ.mjs → load-BNo-ER8C.mjs} +1 -1
- package/dist/{load-Dtoo7KcJ.mjs.map → load-BNo-ER8C.mjs.map} +1 -1
- package/dist/{loader-C8Z48Uof.mjs → loader-Dn74CG1b.mjs} +68 -9
- package/dist/loader-Dn74CG1b.mjs.map +1 -0
- package/dist/{manifest-schema-DDSbwkAL.mjs → manifest-schema-BWKnQYQF.mjs} +1 -1
- package/dist/{manifest-schema-DDSbwkAL.mjs.map → manifest-schema-BWKnQYQF.mjs.map} +1 -1
- package/dist/media/image-endpoint.mjs +1 -1
- package/dist/media/index.d.mts +1 -1
- package/dist/media/index.mjs +2 -2
- package/dist/media/local-runtime.d.mts +19 -11
- package/dist/media/local-runtime.d.mts.map +1 -1
- package/dist/media/local-runtime.mjs +9 -7
- package/dist/media/local-runtime.mjs.map +1 -1
- package/dist/{media-allowlist-DunzrKFM.mjs → media-allowlist-B77I5_bw.mjs} +2 -2
- package/dist/{media-allowlist-DunzrKFM.mjs.map → media-allowlist-B77I5_bw.mjs.map} +1 -1
- package/dist/{media-url-S22B6aPr.mjs → media-url-O4rm9-SQ.mjs} +1 -1
- package/dist/{media-url-S22B6aPr.mjs.map → media-url-O4rm9-SQ.mjs.map} +1 -1
- package/dist/{menus-DOs1MQJg.mjs → menus-DS8VTZgo.mjs} +56 -13
- package/dist/menus-DS8VTZgo.mjs.map +1 -0
- package/dist/{mime-DYpsOAny.mjs → mime-BTzvzJ8M.mjs} +1 -1
- package/dist/{mime-DYpsOAny.mjs.map → mime-BTzvzJ8M.mjs.map} +1 -1
- package/dist/{mode-CFh8Dw8G.mjs → mode-BB0F8xTC.mjs} +1 -1
- package/dist/{mode-CFh8Dw8G.mjs.map → mode-BB0F8xTC.mjs.map} +1 -1
- package/dist/{normalize-Uam4_Vkr.mjs → normalize-ClbNIenm.mjs} +1 -1
- package/dist/{normalize-Uam4_Vkr.mjs.map → normalize-ClbNIenm.mjs.map} +1 -1
- package/dist/{oauth-authorization-BN-t83Uy.mjs → oauth-authorization-CsvzIp_F.mjs} +4 -4
- package/dist/{oauth-authorization-BN-t83Uy.mjs.map → oauth-authorization-CsvzIp_F.mjs.map} +1 -1
- package/dist/{oauth-clients-R6I_V0qz.mjs → oauth-clients-C9SYwEbZ.mjs} +1 -1
- package/dist/{oauth-clients-R6I_V0qz.mjs.map → oauth-clients-C9SYwEbZ.mjs.map} +1 -1
- package/dist/{oauth-state-store-Csoc6kkR.mjs → oauth-state-store---zrApfB.mjs} +1 -1
- package/dist/{oauth-state-store-Csoc6kkR.mjs.map → oauth-state-store---zrApfB.mjs.map} +1 -1
- package/dist/{oauth-user-lookup-d7VYjTpx.mjs → oauth-user-lookup-SHsWRlG9.mjs} +1 -1
- package/dist/{oauth-user-lookup-d7VYjTpx.mjs.map → oauth-user-lookup-SHsWRlG9.mjs.map} +1 -1
- package/dist/object-cache/memory.d.mts +1 -1
- package/dist/{options-DFFpvNJU.d.mts → options-CqECG0gM.d.mts} +3 -3
- package/dist/{options-DFFpvNJU.d.mts.map → options-CqECG0gM.d.mts.map} +1 -1
- package/dist/page/index.d.mts +2 -2
- package/dist/{parse-qrHlnzTy.mjs → parse-C9hpjUyY.mjs} +2 -2
- package/dist/{parse-qrHlnzTy.mjs.map → parse-C9hpjUyY.mjs.map} +1 -1
- package/dist/{passkey-config-BJTbcnI5.mjs → passkey-config-C0YfSBko.mjs} +1 -1
- package/dist/{passkey-config-BJTbcnI5.mjs.map → passkey-config-C0YfSBko.mjs.map} +1 -1
- package/dist/{placeholder-CIDCpyEY.mjs → placeholder-B0s2mWu5.mjs} +1 -1
- package/dist/{placeholder-CIDCpyEY.mjs.map → placeholder-B0s2mWu5.mjs.map} +1 -1
- package/dist/{placeholder-CirPauNG.d.mts → placeholder-QoI4gEzP.d.mts} +1 -1
- package/dist/{placeholder-CirPauNG.d.mts.map → placeholder-QoI4gEzP.d.mts.map} +1 -1
- package/dist/plugin-types.d.mts +1 -1
- package/dist/plugin-utils.d.mts +9 -9
- package/dist/plugins/adapt-sandbox-entry.d.mts +9 -9
- package/dist/plugins/adapt-sandbox-entry.mjs +2 -2
- package/dist/{portable-text-BIFhrU6T.mjs → portable-text-BICg8bTk.mjs} +1 -1
- package/dist/{portable-text-BIFhrU6T.mjs.map → portable-text-BICg8bTk.mjs.map} +1 -1
- package/dist/{preview-IDye9SPQ.mjs → preview-DKGCt2_p.mjs} +2 -2
- package/dist/{preview-IDye9SPQ.mjs.map → preview-DKGCt2_p.mjs.map} +1 -1
- package/dist/{public-url-8lFyQ8ZF.mjs → public-url-CTVqgMmg.mjs} +1 -1
- package/dist/{public-url-8lFyQ8ZF.mjs.map → public-url-CTVqgMmg.mjs.map} +1 -1
- package/dist/{query-B1RVFUNM.mjs → query-DgUHZLWB.mjs} +79 -8
- package/dist/query-DgUHZLWB.mjs.map +1 -0
- package/dist/{rate-limit-DfNAqIWW.mjs → rate-limit-BuQ5d4X_.mjs} +2 -2
- package/dist/{rate-limit-DfNAqIWW.mjs.map → rate-limit-BuQ5d4X_.mjs.map} +1 -1
- package/dist/{redirect-B4wuX2A5.mjs → redirect-CS-PHtNh.mjs} +1 -1
- package/dist/{redirect-B4wuX2A5.mjs.map → redirect-CS-PHtNh.mjs.map} +1 -1
- package/dist/{redirects-CT_vb3NV.mjs → redirects-BZ8Mxn8H.mjs} +2 -2
- package/dist/{redirects-CT_vb3NV.mjs.map → redirects-BZ8Mxn8H.mjs.map} +1 -1
- package/dist/{redirects-DUvXgzCX.mjs → redirects-x9eFPeyi.mjs} +4 -2
- package/dist/redirects-x9eFPeyi.mjs.map +1 -0
- package/dist/{registry-CjK96fHD.mjs → registry-CK1SS6pi.mjs} +2 -2
- package/dist/{registry-CjK96fHD.mjs.map → registry-CK1SS6pi.mjs.map} +1 -1
- package/dist/{request-meta-ei3ATilC.mjs → request-meta-CmS1tDFf.mjs} +2 -2
- package/dist/{request-meta-ei3ATilC.mjs.map → request-meta-CmS1tDFf.mjs.map} +1 -1
- package/dist/{resolve-CpbBglV0.mjs → resolve-C7I0qiR0.mjs} +1 -1
- package/dist/{resolve-CpbBglV0.mjs.map → resolve-C7I0qiR0.mjs.map} +1 -1
- package/dist/{runner-jdXtFEd3.d.mts → runner-CEtq-6Sm.d.mts} +2 -2
- package/dist/{runner-jdXtFEd3.d.mts.map → runner-CEtq-6Sm.d.mts.map} +1 -1
- package/dist/runtime.d.mts +10 -10
- package/dist/runtime.mjs +1 -1
- package/dist/{schema-5z2Jfnbm.mjs → schema-CbFRFoM7.mjs} +3 -3
- package/dist/{schema-5z2Jfnbm.mjs.map → schema-CbFRFoM7.mjs.map} +1 -1
- package/dist/{search-D9FkoM-k.mjs → search-C-waE_YW.mjs} +3 -3
- package/dist/{search-D9FkoM-k.mjs.map → search-C-waE_YW.mjs.map} +1 -1
- package/dist/{secrets-BUE5UQys.mjs → secrets-BSf9pRRY.mjs} +2 -2
- package/dist/{secrets-BUE5UQys.mjs.map → secrets-BSf9pRRY.mjs.map} +1 -1
- package/dist/{sections-DWYZo6HK.mjs → sections-osX9U-YJ.mjs} +2 -2
- package/dist/{sections-DWYZo6HK.mjs.map → sections-osX9U-YJ.mjs.map} +1 -1
- package/dist/seed/index.d.mts +2 -2
- package/dist/seed/index.mjs +12 -11
- package/dist/seo/index.d.mts +1 -1
- package/dist/seo/index.mjs +1 -1
- package/dist/{seo-Cu47j3mJ.mjs → seo-4FovMwNS.mjs} +1 -1
- package/dist/{seo-Cu47j3mJ.mjs.map → seo-4FovMwNS.mjs.map} +1 -1
- package/dist/{seo-DRnqnstF.mjs → seo-DCEF-AVr.mjs} +1 -1
- package/dist/{seo-DRnqnstF.mjs.map → seo-DCEF-AVr.mjs.map} +1 -1
- package/dist/{service-DTmtqCnw.mjs → service-jby1RRmU.mjs} +2 -2
- package/dist/{service-DTmtqCnw.mjs.map → service-jby1RRmU.mjs.map} +1 -1
- package/dist/{session-user-DmtPMNa1.mjs → session-user-B8aLtKAH.mjs} +1 -1
- package/dist/{session-user-DmtPMNa1.mjs.map → session-user-B8aLtKAH.mjs.map} +1 -1
- package/dist/{settings-DUrVDN0c.mjs → settings-4bRT2NIf.mjs} +2 -2
- package/dist/{settings-DUrVDN0c.mjs.map → settings-4bRT2NIf.mjs.map} +1 -1
- package/dist/{settings-yaxu9mU-.mjs → settings-t-H2jPuJ.mjs} +3 -3
- package/dist/{settings-yaxu9mU-.mjs.map → settings-t-H2jPuJ.mjs.map} +1 -1
- package/dist/{setup-complete-BWFHzgvZ.mjs → setup-complete-gEiySUc-.mjs} +1 -1
- package/dist/{setup-complete-BWFHzgvZ.mjs.map → setup-complete-gEiySUc-.mjs.map} +1 -1
- package/dist/{setup-nonce-DFWG-J5c.mjs → setup-nonce-DzS50zme.mjs} +1 -1
- package/dist/{setup-nonce-DFWG-J5c.mjs.map → setup-nonce-DzS50zme.mjs.map} +1 -1
- package/dist/{single-flight-cache-B5p5cNOL.mjs → single-flight-cache-Cdfkic3t.mjs} +1 -1
- package/dist/{single-flight-cache-B5p5cNOL.mjs.map → single-flight-cache-Cdfkic3t.mjs.map} +1 -1
- package/dist/{site-url-BOTPgmeM.mjs → site-url-BLebyON8.mjs} +1 -1
- package/dist/{site-url-BOTPgmeM.mjs.map → site-url-BLebyON8.mjs.map} +1 -1
- package/dist/{ssrf-B0VeRLrp.mjs → ssrf-BRKb343l.mjs} +1 -1
- package/dist/{ssrf-B0VeRLrp.mjs.map → ssrf-BRKb343l.mjs.map} +1 -1
- package/dist/{status-CB2basWJ.mjs → status-vUK0SA17.mjs} +1 -1
- package/dist/{status-CB2basWJ.mjs.map → status-vUK0SA17.mjs.map} +1 -1
- package/dist/storage/local.d.mts +1 -1
- package/dist/storage/local.mjs +1 -1
- package/dist/storage/s3.d.mts +1 -1
- package/dist/storage/s3.mjs +1 -1
- package/dist/{taxonomies-CJmkEpdS.mjs → taxonomies-BBB8O-CU.mjs} +2 -2
- package/dist/{taxonomies-CJmkEpdS.mjs.map → taxonomies-BBB8O-CU.mjs.map} +1 -1
- package/dist/{taxonomies-Be9B1jEj.mjs → taxonomies-Dxrc_szG.mjs} +26 -6
- package/dist/{taxonomies-Be9B1jEj.mjs.map → taxonomies-Dxrc_szG.mjs.map} +1 -1
- package/dist/{tokens-BvrJvIB6.mjs → tokens-LeuXF9gG.mjs} +1 -1
- package/dist/{tokens-BvrJvIB6.mjs.map → tokens-LeuXF9gG.mjs.map} +1 -1
- package/dist/{transport-k7YjfmEn.d.mts → transport-BZ-03aFT.d.mts} +1 -1
- package/dist/{transport-k7YjfmEn.d.mts.map → transport-BZ-03aFT.d.mts.map} +1 -1
- package/dist/{transport-B4rXnSTf.mjs → transport-_2nBz7e9.mjs} +1 -1
- package/dist/{transport-B4rXnSTf.mjs.map → transport-_2nBz7e9.mjs.map} +1 -1
- package/dist/{trusted-proxy-DY1_UqHr.mjs → trusted-proxy-DZY5WCn2.mjs} +1 -1
- package/dist/{trusted-proxy-DY1_UqHr.mjs.map → trusted-proxy-DZY5WCn2.mjs.map} +1 -1
- package/dist/{types-Czg1S3gB.d.mts → types-B-gIxFCE.d.mts} +1 -1
- package/dist/{types-Czg1S3gB.d.mts.map → types-B-gIxFCE.d.mts.map} +1 -1
- package/dist/{types-DXLVzV2w.d.mts → types-BG8_XTLj.d.mts} +1 -1
- package/dist/{types-DXLVzV2w.d.mts.map → types-BG8_XTLj.d.mts.map} +1 -1
- package/dist/{types-CWGYDYqF.d.mts → types-BWh2MjmA.d.mts} +15 -2
- package/dist/types-BWh2MjmA.d.mts.map +1 -0
- package/dist/{types-CgvhU-hF.d.mts → types-BWqGVhFn.d.mts} +1 -1
- package/dist/{types-CgvhU-hF.d.mts.map → types-BWqGVhFn.d.mts.map} +1 -1
- package/dist/{types-DYF2_Vf4.mjs → types-CQAugunJ.mjs} +1 -1
- package/dist/{types-DYF2_Vf4.mjs.map → types-CQAugunJ.mjs.map} +1 -1
- package/dist/{types-DPCpkzvS.d.mts → types-CTLJYMhN.d.mts} +1 -1
- package/dist/{types-DPCpkzvS.d.mts.map → types-CTLJYMhN.d.mts.map} +1 -1
- package/dist/{types-CmivgZbp.d.mts → types-CUsXGRVj.d.mts} +1 -1
- package/dist/{types-CmivgZbp.d.mts.map → types-CUsXGRVj.d.mts.map} +1 -1
- package/dist/types-DXOIbece.mjs.map +1 -1
- package/dist/{types-CKNXt63n.d.mts → types-DrYMm9s5.d.mts} +1 -1
- package/dist/{types-CKNXt63n.d.mts.map → types-DrYMm9s5.d.mts.map} +1 -1
- package/dist/{types-CIKX2HO5.d.mts → types-TTx8uP7V.d.mts} +2 -2
- package/dist/{types-CIKX2HO5.d.mts.map → types-TTx8uP7V.d.mts.map} +1 -1
- package/dist/{types-DCNNfeCv.d.mts → types-fS7-VTdR.d.mts} +1 -1
- package/dist/{types-DCNNfeCv.d.mts.map → types-fS7-VTdR.d.mts.map} +1 -1
- package/dist/{utils-LbHcSRTj.mjs → utils-B7A57fm9.mjs} +1 -1
- package/dist/{utils-LbHcSRTj.mjs.map → utils-B7A57fm9.mjs.map} +1 -1
- package/dist/{validate-Bwl64sxv.mjs → validate-0Utjspbs.mjs} +1 -1
- package/dist/{validate-Bwl64sxv.mjs.map → validate-0Utjspbs.mjs.map} +1 -1
- package/dist/{validate-CE2M0nvx.d.mts → validate-DOFrIb-c.d.mts} +5 -5
- package/dist/{validate-CE2M0nvx.d.mts.map → validate-DOFrIb-c.d.mts.map} +1 -1
- package/dist/{validation-C_yOvFaO.mjs → validation-D9EnzH1T.mjs} +5 -5
- package/dist/{validation-C_yOvFaO.mjs.map → validation-D9EnzH1T.mjs.map} +1 -1
- package/dist/version-BgVM_1MU.mjs +7 -0
- package/dist/{version-RnYXYjzD.mjs.map → version-BgVM_1MU.mjs.map} +1 -1
- package/dist/{widgets-8GONuRHo.mjs → widgets-BSTzPUYa.mjs} +3 -3
- package/dist/{widgets-8GONuRHo.mjs.map → widgets-BSTzPUYa.mjs.map} +1 -1
- package/dist/{zod-generator-D481JjzD.mjs → zod-generator-ElVQOav7.mjs} +50 -14
- package/dist/zod-generator-ElVQOav7.mjs.map +1 -0
- package/package.json +8 -7
- package/src/api/schemas/bylines.ts +8 -0
- package/src/astro/integration/virtual-modules.ts +8 -0
- package/src/astro/integration/vite-config.ts +9 -1
- package/src/astro/middleware/request-context.ts +6 -1
- package/src/astro/middleware/scoped-db.ts +131 -0
- package/src/astro/middleware/stream-end-metrics.ts +4 -8
- package/src/astro/middleware.ts +90 -28
- package/src/astro/routes/admin.astro +5 -1
- package/src/astro/routes/api/schema/index.ts +9 -3
- package/src/cli/commands/export-seed.ts +10 -7
- package/src/components/Block.astro +71 -0
- package/src/components/EmDashMedia.astro +1 -2
- package/src/components/Image.astro +36 -2
- package/src/components/InlinePortableTextEditor.tsx +10 -2
- package/src/components/index.ts +5 -0
- package/src/components/portable-text-text-align.ts +38 -0
- package/src/content/converters/portable-text-to-prosemirror.ts +5 -1
- package/src/content/converters/prosemirror-to-portable-text.ts +8 -0
- package/src/content/converters/types.ts +1 -0
- package/src/database/repositories/byline.ts +14 -0
- package/src/database/repositories/types.ts +13 -0
- package/src/emdash-runtime.ts +226 -71
- package/src/loader.ts +97 -5
- package/src/media/local-runtime.ts +18 -5
- package/src/plugins/context.ts +94 -22
- package/src/plugins/cron.ts +18 -2
- package/src/plugins/routes.ts +40 -1
- package/src/query.ts +108 -1
- package/src/schema/zod-generator.ts +53 -8
- package/src/taxonomies/index.ts +26 -0
- package/src/ui.ts +5 -0
- package/src/virtual-modules.d.ts +13 -0
- package/dist/byline-CC0WS4Gu.mjs.map +0 -1
- package/dist/byline-fields-jy07PZJM.d.mts.map +0 -1
- package/dist/context-f1__jpzF.mjs.map +0 -1
- package/dist/cron-CQPxBjYs.mjs.map +0 -1
- package/dist/index-C2dLNT6S.d.mts.map +0 -1
- package/dist/loader-C8Z48Uof.mjs.map +0 -1
- package/dist/menus-DOs1MQJg.mjs.map +0 -1
- package/dist/query-B1RVFUNM.mjs.map +0 -1
- package/dist/redirects-DUvXgzCX.mjs.map +0 -1
- package/dist/types-CWGYDYqF.d.mts.map +0 -1
- package/dist/version-RnYXYjzD.mjs +0 -7
- package/dist/zod-generator-D481JjzD.mjs.map +0 -1
- /package/dist/{api-tokens-BVH-H8Z9.mjs → api-tokens-B4BQybOp.mjs} +0 -0
- /package/dist/{ssrf-Cz1e2QPn.mjs → ssrf-CcX9zvMK.mjs} +0 -0
- /package/dist/{types-Bfr2Pj6z.mjs → types-BvbeGEtr.mjs} +0 -0
package/src/components/index.ts
CHANGED
|
@@ -36,6 +36,7 @@ export { default as EmDashImage } from "./EmDashImage.astro";
|
|
|
36
36
|
export { default as EmDashMedia } from "./EmDashMedia.astro";
|
|
37
37
|
|
|
38
38
|
// Portable Text block type components
|
|
39
|
+
export { default as Block } from "./Block.astro";
|
|
39
40
|
export { default as Image } from "./Image.astro";
|
|
40
41
|
export { default as Code } from "./Code.astro";
|
|
41
42
|
export { default as Embed } from "./Embed.astro";
|
|
@@ -57,6 +58,7 @@ export { default as Underline } from "./marks/Underline.astro";
|
|
|
57
58
|
export { default as StrikeThrough } from "./marks/StrikeThrough.astro";
|
|
58
59
|
export { default as Link } from "./marks/Link.astro";
|
|
59
60
|
|
|
61
|
+
import BlockComponent from "./Block.astro";
|
|
60
62
|
import BreakComponent from "./Break.astro";
|
|
61
63
|
import ButtonComponent from "./Button.astro";
|
|
62
64
|
import ButtonsComponent from "./Buttons.astro";
|
|
@@ -77,11 +79,14 @@ import TableComponent from "./Table.astro";
|
|
|
77
79
|
* Pre-configured components for EmDash Portable Text content
|
|
78
80
|
*
|
|
79
81
|
* Includes renderers for:
|
|
82
|
+
* - Block styles: paragraph, h1..h6, blockquote — with `textAlign` honoured
|
|
83
|
+
* as a WordPress-style `has-text-align-{value}` class (#1201)
|
|
80
84
|
* - Block types: image, code, embed, gallery, columns, break, htmlBlock, table,
|
|
81
85
|
* button, buttons, cover, file, pullquote
|
|
82
86
|
* - Marks: superscript, subscript, underline, strike-through, link
|
|
83
87
|
*/
|
|
84
88
|
export const emdashComponents = {
|
|
89
|
+
block: BlockComponent,
|
|
85
90
|
type: {
|
|
86
91
|
image: ImageComponent,
|
|
87
92
|
code: CodeComponent,
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Maps a Portable Text block's `textAlign` to a WordPress-style class name
|
|
3
|
+
* (`has-text-align-{value}`) for public rendering. Used by the Portable Text
|
|
4
|
+
* `Block` override in `./Block.astro`.
|
|
5
|
+
*
|
|
6
|
+
* `left` is the document default and intentionally does not produce a class —
|
|
7
|
+
* this matches the converter's omit-on-default rule (see
|
|
8
|
+
* `src/content/converters/prosemirror-to-portable-text.ts`) so untouched
|
|
9
|
+
* content stays bytewise identical and renders without an extra class.
|
|
10
|
+
*
|
|
11
|
+
* Related: https://github.com/emdash-cms/emdash/issues/1201
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
type AlignClassName = "has-text-align-center" | "has-text-align-right" | "has-text-align-justify";
|
|
15
|
+
|
|
16
|
+
const ALIGN_CLASS_MAP: Record<string, AlignClassName> = {
|
|
17
|
+
center: "has-text-align-center",
|
|
18
|
+
right: "has-text-align-right",
|
|
19
|
+
justify: "has-text-align-justify",
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Returns the CSS class for a textAlign value, or `undefined` when no class
|
|
24
|
+
* should be emitted (default left, missing, or unknown values).
|
|
25
|
+
*
|
|
26
|
+
* Allowlist-only by design: arbitrary strings are rejected so a hand-edited
|
|
27
|
+
* or imported Portable Text block cannot inject attacker-controlled class
|
|
28
|
+
* names into the rendered HTML.
|
|
29
|
+
*/
|
|
30
|
+
export function textAlignClassName(value: string | undefined): AlignClassName | undefined {
|
|
31
|
+
if (value === undefined) return undefined;
|
|
32
|
+
// `Object.hasOwn` (not `in`) so prototype keys like "toString" or
|
|
33
|
+
// "constructor" can't slip through as valid alignments.
|
|
34
|
+
if (Object.hasOwn(ALIGN_CLASS_MAP, value)) {
|
|
35
|
+
return ALIGN_CLASS_MAP[value];
|
|
36
|
+
}
|
|
37
|
+
return undefined;
|
|
38
|
+
}
|
|
@@ -164,7 +164,10 @@ function convertTextBlock(block: PortableTextTextBlock): ProseMirrorNode | null
|
|
|
164
164
|
const level = parseInt(style.substring(1), 10);
|
|
165
165
|
return {
|
|
166
166
|
type: "heading",
|
|
167
|
-
attrs: {
|
|
167
|
+
attrs: {
|
|
168
|
+
level,
|
|
169
|
+
...(block.textAlign ? { textAlign: block.textAlign } : {}),
|
|
170
|
+
},
|
|
168
171
|
content: content.length > 0 ? content : undefined,
|
|
169
172
|
};
|
|
170
173
|
}
|
|
@@ -184,6 +187,7 @@ function convertTextBlock(block: PortableTextTextBlock): ProseMirrorNode | null
|
|
|
184
187
|
default:
|
|
185
188
|
return {
|
|
186
189
|
type: "paragraph",
|
|
190
|
+
attrs: block.textAlign ? { textAlign: block.textAlign } : undefined,
|
|
187
191
|
content: content.length > 0 ? content : undefined,
|
|
188
192
|
};
|
|
189
193
|
}
|
|
@@ -106,12 +106,16 @@ function convertParagraph(node: ProseMirrorNode): PortableTextTextBlock | null {
|
|
|
106
106
|
return null;
|
|
107
107
|
}
|
|
108
108
|
|
|
109
|
+
const ta = node.attrs?.textAlign;
|
|
110
|
+
const textAlign = ta === "center" || ta === "right" || ta === "justify" ? ta : undefined;
|
|
111
|
+
|
|
109
112
|
return {
|
|
110
113
|
_type: "block",
|
|
111
114
|
_key: generateKey(),
|
|
112
115
|
style: "normal",
|
|
113
116
|
children,
|
|
114
117
|
markDefs: markDefs.length > 0 ? markDefs : undefined,
|
|
118
|
+
...(textAlign ? { textAlign } : {}),
|
|
115
119
|
};
|
|
116
120
|
}
|
|
117
121
|
|
|
@@ -147,12 +151,16 @@ function convertHeading(node: ProseMirrorNode): PortableTextTextBlock | null {
|
|
|
147
151
|
return null;
|
|
148
152
|
}
|
|
149
153
|
|
|
154
|
+
const ta = node.attrs?.textAlign;
|
|
155
|
+
const textAlign = ta === "center" || ta === "right" || ta === "justify" ? ta : undefined;
|
|
156
|
+
|
|
150
157
|
return {
|
|
151
158
|
_type: "block",
|
|
152
159
|
_key: generateKey(),
|
|
153
160
|
style,
|
|
154
161
|
children,
|
|
155
162
|
markDefs: markDefs.length > 0 ? markDefs : undefined,
|
|
163
|
+
...(textAlign ? { textAlign } : {}),
|
|
156
164
|
};
|
|
157
165
|
}
|
|
158
166
|
|
|
@@ -37,6 +37,8 @@ type BylineRow = Selectable<BylineTable>;
|
|
|
37
37
|
type BylineRowWithAvatar = BylineRow & {
|
|
38
38
|
avatar_storage_key?: string | null;
|
|
39
39
|
avatar_alt?: string | null;
|
|
40
|
+
avatar_blurhash?: string | null;
|
|
41
|
+
avatar_dominant_color?: string | null;
|
|
40
42
|
};
|
|
41
43
|
|
|
42
44
|
export interface CreateBylineInput {
|
|
@@ -113,6 +115,8 @@ function rowToByline(row: BylineRowWithAvatar): BylineSummary {
|
|
|
113
115
|
avatarMediaId: row.avatar_media_id,
|
|
114
116
|
avatarStorageKey: row.avatar_storage_key ?? null,
|
|
115
117
|
avatarAlt: row.avatar_alt ?? null,
|
|
118
|
+
avatarBlurhash: row.avatar_blurhash ?? null,
|
|
119
|
+
avatarDominantColor: row.avatar_dominant_color ?? null,
|
|
116
120
|
websiteUrl: row.website_url,
|
|
117
121
|
userId: row.user_id,
|
|
118
122
|
isGuest: row.is_guest === 1,
|
|
@@ -944,6 +948,8 @@ export class BylineRepository {
|
|
|
944
948
|
"b.avatar_media_id as avatar_media_id",
|
|
945
949
|
"m.storage_key as avatar_storage_key",
|
|
946
950
|
"m.alt as avatar_alt",
|
|
951
|
+
"m.blurhash as avatar_blurhash",
|
|
952
|
+
"m.dominant_color as avatar_dominant_color",
|
|
947
953
|
"b.website_url as website_url",
|
|
948
954
|
"b.user_id as user_id",
|
|
949
955
|
"b.is_guest as is_guest",
|
|
@@ -971,6 +977,8 @@ export class BylineRepository {
|
|
|
971
977
|
avatar_media_id: row.avatar_media_id,
|
|
972
978
|
avatar_storage_key: row.avatar_storage_key,
|
|
973
979
|
avatar_alt: row.avatar_alt,
|
|
980
|
+
avatar_blurhash: row.avatar_blurhash,
|
|
981
|
+
avatar_dominant_color: row.avatar_dominant_color,
|
|
974
982
|
website_url: row.website_url,
|
|
975
983
|
user_id: row.user_id,
|
|
976
984
|
is_guest: row.is_guest,
|
|
@@ -1080,6 +1088,8 @@ export class BylineRepository {
|
|
|
1080
1088
|
"b.avatar_media_id as avatar_media_id",
|
|
1081
1089
|
"m.storage_key as avatar_storage_key",
|
|
1082
1090
|
"m.alt as avatar_alt",
|
|
1091
|
+
"m.blurhash as avatar_blurhash",
|
|
1092
|
+
"m.dominant_color as avatar_dominant_color",
|
|
1083
1093
|
"b.website_url as website_url",
|
|
1084
1094
|
"b.user_id as user_id",
|
|
1085
1095
|
"b.is_guest as is_guest",
|
|
@@ -1104,6 +1114,8 @@ export class BylineRepository {
|
|
|
1104
1114
|
avatar_media_id: row.avatar_media_id,
|
|
1105
1115
|
avatar_storage_key: row.avatar_storage_key,
|
|
1106
1116
|
avatar_alt: row.avatar_alt,
|
|
1117
|
+
avatar_blurhash: row.avatar_blurhash,
|
|
1118
|
+
avatar_dominant_color: row.avatar_dominant_color,
|
|
1107
1119
|
website_url: row.website_url,
|
|
1108
1120
|
user_id: row.user_id,
|
|
1109
1121
|
is_guest: row.is_guest,
|
|
@@ -1182,6 +1194,8 @@ export class BylineRepository {
|
|
|
1182
1194
|
"b.avatar_media_id as avatar_media_id",
|
|
1183
1195
|
"m.storage_key as avatar_storage_key",
|
|
1184
1196
|
"m.alt as avatar_alt",
|
|
1197
|
+
"m.blurhash as avatar_blurhash",
|
|
1198
|
+
"m.dominant_color as avatar_dominant_color",
|
|
1185
1199
|
"b.website_url as website_url",
|
|
1186
1200
|
"b.user_id as user_id",
|
|
1187
1201
|
"b.is_guest as is_guest",
|
|
@@ -78,6 +78,19 @@ export interface BylineSummary {
|
|
|
78
78
|
avatarStorageKey?: string | null;
|
|
79
79
|
/** Avatar media alt text, from the same media join. Null when not joined. */
|
|
80
80
|
avatarAlt?: string | null;
|
|
81
|
+
/**
|
|
82
|
+
* Avatar media blurhash (LQIP placeholder, migration 024), folded in by the
|
|
83
|
+
* same media join as `avatarStorageKey`. Lets a renderer paint a blurred
|
|
84
|
+
* placeholder while the full avatar loads, with no extra media lookup.
|
|
85
|
+
* Null when the byline has no avatar, the media row has no blurhash, or the
|
|
86
|
+
* byline was loaded through a finder that doesn't join media.
|
|
87
|
+
*/
|
|
88
|
+
avatarBlurhash?: string | null;
|
|
89
|
+
/**
|
|
90
|
+
* Avatar media dominant colour (LQIP placeholder, migration 024), from the
|
|
91
|
+
* same media join. Null under the same conditions as `avatarBlurhash`.
|
|
92
|
+
*/
|
|
93
|
+
avatarDominantColor?: string | null;
|
|
81
94
|
websiteUrl: string | null;
|
|
82
95
|
userId: string | null;
|
|
83
96
|
isGuest: boolean;
|
package/src/emdash-runtime.ts
CHANGED
|
@@ -244,6 +244,15 @@ export interface MediaProviderEntry {
|
|
|
244
244
|
*/
|
|
245
245
|
export interface MediaProviderContext {
|
|
246
246
|
db: Kysely<Database>;
|
|
247
|
+
/**
|
|
248
|
+
* Resolver for the live connection, preferred over `db` by providers that
|
|
249
|
+
* query EmDash's database. Resolves the current request/event-scoped
|
|
250
|
+
* connection from ALS so connection-backed adapters (Postgres over
|
|
251
|
+
* Hyperdrive) don't reuse the per-isolate singleton's socket across events.
|
|
252
|
+
* Providers should resolve per operation rather than capturing `db` once.
|
|
253
|
+
* Omitted-safe: falls back to `db` for stateless adapters (D1, Node SQLite).
|
|
254
|
+
*/
|
|
255
|
+
getDb?: () => Kysely<Database>;
|
|
247
256
|
storage: Storage | null;
|
|
248
257
|
}
|
|
249
258
|
|
|
@@ -262,6 +271,16 @@ export interface RuntimeDependencies {
|
|
|
262
271
|
plugins: ResolvedPlugin[];
|
|
263
272
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
264
273
|
createDialect: (config: any) => Dialect;
|
|
274
|
+
/**
|
|
275
|
+
* Factory for a dialect that batches same-turn reads into one round trip
|
|
276
|
+
* ({@link EmDashRuntime.create} uses it for the cold-start read phase).
|
|
277
|
+
* Present only on batching backends (D1, DO); absent backends fall back to
|
|
278
|
+
* the singleton. Returns a fresh connection each call — it must never be the
|
|
279
|
+
* long-lived singleton, whose coalescing buffer would be shared across
|
|
280
|
+
* requests.
|
|
281
|
+
*/
|
|
282
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
283
|
+
createCoalescingDialect?: (config: any) => Dialect | null;
|
|
265
284
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
266
285
|
createStorage: ((config: any) => Storage) | null;
|
|
267
286
|
sandboxEnabled: boolean;
|
|
@@ -323,6 +342,7 @@ export interface EmDashRuntimeParts {
|
|
|
323
342
|
allPipelinePlugins: ResolvedPlugin[];
|
|
324
343
|
pipelineFactoryOptions: {
|
|
325
344
|
db: Kysely<Database>;
|
|
345
|
+
getDb?: () => Kysely<Database>;
|
|
326
346
|
storage?: Storage;
|
|
327
347
|
siteInfo?: { siteName?: string; siteUrl?: string; locale?: string };
|
|
328
348
|
};
|
|
@@ -370,6 +390,28 @@ function getDbHolder(): DbHolder {
|
|
|
370
390
|
}
|
|
371
391
|
return holder;
|
|
372
392
|
}
|
|
393
|
+
|
|
394
|
+
/**
|
|
395
|
+
* Auto-seed runs at most once per isolate per database. Its lock + "done" set
|
|
396
|
+
* live on globalThis (same bundler-duplication reasoning as the db cache) so a
|
|
397
|
+
* reclaimed-and-rerun `create()` can't seed a second time concurrently. The
|
|
398
|
+
* lock polls rather than sharing a promise, so it is safe to await across a
|
|
399
|
+
* cancelled owner in workerd.
|
|
400
|
+
*/
|
|
401
|
+
const SEED_HOLDER_KEY = Symbol.for("emdash:seed-state");
|
|
402
|
+
interface SeedHolder {
|
|
403
|
+
done: Set<string>;
|
|
404
|
+
lock: InitLock;
|
|
405
|
+
}
|
|
406
|
+
function getSeedHolder(): SeedHolder {
|
|
407
|
+
// eslint-disable-next-line typescript/no-unsafe-type-assertion -- globalThis symbol slot, written only below
|
|
408
|
+
let holder = globalSymbolStore[SEED_HOLDER_KEY] as SeedHolder | undefined;
|
|
409
|
+
if (!holder) {
|
|
410
|
+
holder = { done: new Set<string>(), lock: createInitLock() };
|
|
411
|
+
globalSymbolStore[SEED_HOLDER_KEY] = holder;
|
|
412
|
+
}
|
|
413
|
+
return holder;
|
|
414
|
+
}
|
|
373
415
|
const storageCache = new Map<string, Storage>();
|
|
374
416
|
const sandboxedPluginCache = new Map<string, SandboxedPluginInstance>();
|
|
375
417
|
/**
|
|
@@ -414,7 +456,20 @@ export class EmDashRuntime {
|
|
|
414
456
|
readonly configuredPlugins: ResolvedPlugin[];
|
|
415
457
|
readonly sandboxedPlugins: Map<string, SandboxedPluginInstance>;
|
|
416
458
|
readonly sandboxedPluginEntries: SandboxedPluginEntry[];
|
|
417
|
-
|
|
459
|
+
/**
|
|
460
|
+
* Schema registry bound to the current request/event-scoped connection.
|
|
461
|
+
* Built per access (SchemaRegistry just wraps a db) against `this.db`, the
|
|
462
|
+
* ALS-aware getter — never a captured snapshot of the singleton. On a
|
|
463
|
+
* connection-backed adapter (Postgres over Hyperdrive) a captured singleton
|
|
464
|
+
* would query a socket opened by an earlier event and trip workerd's
|
|
465
|
+
* cross-request I/O guard; the catch in handlers like handleContentUpdate
|
|
466
|
+
* would then silently treat a revision-enabled collection as non-revisioned
|
|
467
|
+
* and write draft edits to live columns. Same reasoning as the per-call
|
|
468
|
+
* registry in _buildManifest().
|
|
469
|
+
*/
|
|
470
|
+
get schemaRegistry(): SchemaRegistry {
|
|
471
|
+
return new SchemaRegistry(this.db);
|
|
472
|
+
}
|
|
418
473
|
private _hooks!: HookPipeline;
|
|
419
474
|
readonly config: EmDashConfig;
|
|
420
475
|
readonly mediaProviders: Map<string, MediaProvider>;
|
|
@@ -445,6 +500,7 @@ export class EmDashRuntime {
|
|
|
445
500
|
/** Factory options for the hook pipeline context factory */
|
|
446
501
|
private pipelineFactoryOptions: {
|
|
447
502
|
db: Kysely<Database>;
|
|
503
|
+
getDb?: () => Kysely<Database>;
|
|
448
504
|
storage?: Storage;
|
|
449
505
|
siteInfo?: { siteName?: string; siteUrl?: string; locale?: string };
|
|
450
506
|
};
|
|
@@ -475,7 +531,6 @@ export class EmDashRuntime {
|
|
|
475
531
|
this.configuredPlugins = parts.configuredPlugins;
|
|
476
532
|
this.sandboxedPlugins = parts.sandboxedPlugins;
|
|
477
533
|
this.sandboxedPluginEntries = parts.sandboxedPluginEntries;
|
|
478
|
-
this.schemaRegistry = new SchemaRegistry(parts.db);
|
|
479
534
|
this._hooks = parts.hooks;
|
|
480
535
|
this.enabledPlugins = parts.enabledPlugins;
|
|
481
536
|
this.pluginStates = parts.pluginStates;
|
|
@@ -621,7 +676,9 @@ export class EmDashRuntime {
|
|
|
621
676
|
// The old pipeline's contextFactoryOptions were built up incrementally
|
|
622
677
|
// via setContextFactory calls during create(). We replay them here.
|
|
623
678
|
if (this.email) {
|
|
624
|
-
|
|
679
|
+
// db/getDb are already wired by createHookPipeline above (they live in
|
|
680
|
+
// pipelineFactoryOptions), so the merge only adds emailPipeline.
|
|
681
|
+
newPipeline.setContextFactory({ emailPipeline: this.email });
|
|
625
682
|
}
|
|
626
683
|
if (this.cronScheduler) {
|
|
627
684
|
const scheduler = this.cronScheduler;
|
|
@@ -985,6 +1042,22 @@ export class EmDashRuntime {
|
|
|
985
1042
|
// Initialize database (connects, runs migrations if needed)
|
|
986
1043
|
const db = await phase("rt.db", "DB init + migrations", () => EmDashRuntime.getDatabase(deps));
|
|
987
1044
|
|
|
1045
|
+
// Resolver for the live connection, mirroring the `get db()` getter
|
|
1046
|
+
// below (which can't be used here — the runtime instance doesn't exist
|
|
1047
|
+
// yet). Long-lived subsystems built during create() (cron executor,
|
|
1048
|
+
// plugin context factory, media providers) capture this resolver rather
|
|
1049
|
+
// than the `db` snapshot, so a connection-backed adapter (Postgres over
|
|
1050
|
+
// Hyperdrive) serves their queries from the current request/event-scoped
|
|
1051
|
+
// connection in ALS instead of the per-isolate singleton — whose socket
|
|
1052
|
+
// belongs to an earlier request and would trip workerd's cross-request
|
|
1053
|
+
// I/O guard. Stateless adapters (D1, Node SQLite) set no ALS db on most
|
|
1054
|
+
// paths, so this falls back to the singleton: unchanged behavior.
|
|
1055
|
+
const resolveDb = (): Kysely<Database> => {
|
|
1056
|
+
const ctx = getRequestContext();
|
|
1057
|
+
// eslint-disable-next-line typescript/no-unsafe-type-assertion -- ALS db is typed unknown to avoid a circular import; middleware always sets a Kysely<Database>
|
|
1058
|
+
return (ctx?.db as Kysely<Database> | undefined) ?? db;
|
|
1059
|
+
};
|
|
1060
|
+
|
|
988
1061
|
// Validate EMDASH_ENCRYPTION_KEY once here so a malformed value
|
|
989
1062
|
// surfaces in startup logs instead of as request-time 500s. The key
|
|
990
1063
|
// itself is not yet consumed (a follow-up PR adds plugin-secret
|
|
@@ -998,47 +1071,156 @@ export class EmDashRuntime {
|
|
|
998
1071
|
// Initialize storage (sync)
|
|
999
1072
|
const storage = EmDashRuntime.getStorage(deps);
|
|
1000
1073
|
|
|
1001
|
-
// Fetch plugin states and site info concurrently — independent reads
|
|
1002
|
-
// against different tables (_plugin_state vs options), so they share
|
|
1003
|
-
// one round-trip window instead of paying two sequential ones. Each
|
|
1004
|
-
// phase() wrapper still records that phase's own duration, and each
|
|
1005
|
-
// body keeps its own non-fatal catch.
|
|
1006
1074
|
let pluginStates: Map<string, string> = new Map();
|
|
1007
1075
|
let siteInfo: { siteName?: string; siteUrl?: string; locale?: string } | undefined;
|
|
1008
|
-
|
|
1009
|
-
|
|
1076
|
+
// "Already set up" by default so a read failure (e.g. tables absent on a
|
|
1077
|
+
// pre-migration db) skips seeding rather than seeding a half-built db.
|
|
1078
|
+
let seedGate = { collectionCount: 1, setupDone: true };
|
|
1079
|
+
|
|
1080
|
+
// Seeding must only touch the configured singleton, never a borrowed
|
|
1081
|
+
// per-request db (playground / DO preview) or the loader-fallback db.
|
|
1082
|
+
const reqCtx = getRequestContext();
|
|
1083
|
+
const ownsConfiguredDb = !!deps.config.database && !(reqCtx?.dbIsIsolated && reqCtx.db);
|
|
1084
|
+
|
|
1085
|
+
// Run the init reads on a coalescing connection so the concurrent
|
|
1086
|
+
// same-turn reads flush as one batch() round trip. The singleton can't:
|
|
1087
|
+
// its plain SqliteAdapter reports supportsMultipleConnections=false, so
|
|
1088
|
+
// Kysely's connection mutex serializes concurrent reads into N round
|
|
1089
|
+
// trips. The connection is per-init and discarded — the long-lived
|
|
1090
|
+
// singleton must never coalesce or one request's reads could land in
|
|
1091
|
+
// another's batch. Backends without a coalescing dialect (Node/SQLite)
|
|
1092
|
+
// fall back to the singleton, where serialization costs nothing.
|
|
1093
|
+
let readDb = db;
|
|
1094
|
+
let readDbDisposable: Kysely<Database> | undefined;
|
|
1095
|
+
if (ownsConfiguredDb && deps.createCoalescingDialect && deps.config.database) {
|
|
1096
|
+
try {
|
|
1097
|
+
const dialect = deps.createCoalescingDialect(deps.config.database.config);
|
|
1098
|
+
if (dialect) {
|
|
1099
|
+
readDb = new Kysely<Database>({ dialect, log: kyselyLogOption() });
|
|
1100
|
+
readDbDisposable = readDb;
|
|
1101
|
+
}
|
|
1102
|
+
} catch {
|
|
1103
|
+
readDb = db;
|
|
1104
|
+
}
|
|
1105
|
+
}
|
|
1106
|
+
const optionsRepo = new OptionsRepository(readDb);
|
|
1107
|
+
|
|
1108
|
+
const readSiteInfo = async () => {
|
|
1109
|
+
const siteOpts = await optionsRepo.getMany<string>([
|
|
1110
|
+
"emdash:site_title",
|
|
1111
|
+
"emdash:site_url",
|
|
1112
|
+
"emdash:locale",
|
|
1113
|
+
]);
|
|
1114
|
+
return {
|
|
1115
|
+
siteName: siteOpts.get("emdash:site_title") ?? undefined,
|
|
1116
|
+
siteUrl: siteOpts.get("emdash:site_url") ?? undefined,
|
|
1117
|
+
locale: siteOpts.get("emdash:locale") ?? undefined,
|
|
1118
|
+
};
|
|
1119
|
+
};
|
|
1120
|
+
|
|
1121
|
+
const coldStartReads: Array<Promise<void>> = [
|
|
1010
1122
|
phase("rt.plugins", "Plugin states", async () => {
|
|
1011
1123
|
try {
|
|
1012
|
-
const states = await
|
|
1124
|
+
const states = await readDb
|
|
1013
1125
|
.selectFrom("_plugin_state")
|
|
1014
1126
|
.select(["plugin_id", "status"])
|
|
1015
1127
|
.execute();
|
|
1016
1128
|
pluginStates = new Map(states.map((s) => [s.plugin_id, s.status]));
|
|
1017
1129
|
} catch {
|
|
1018
|
-
//
|
|
1130
|
+
// _plugin_state may not exist yet on a pre-migration db.
|
|
1019
1131
|
}
|
|
1020
1132
|
}),
|
|
1021
|
-
// Load site info for plugin context extensions (1 batch query instead of 3)
|
|
1022
1133
|
phase("rt.site", "Site info options", async () => {
|
|
1023
1134
|
try {
|
|
1024
|
-
|
|
1025
|
-
const siteOpts = await optionsRepo.getMany<string>([
|
|
1026
|
-
"emdash:site_title",
|
|
1027
|
-
"emdash:site_url",
|
|
1028
|
-
"emdash:locale",
|
|
1029
|
-
]);
|
|
1030
|
-
siteInfo = {
|
|
1031
|
-
siteName: siteOpts.get("emdash:site_title") ?? undefined,
|
|
1032
|
-
siteUrl: siteOpts.get("emdash:site_url") ?? undefined,
|
|
1033
|
-
locale: siteOpts.get("emdash:locale") ?? undefined,
|
|
1034
|
-
};
|
|
1135
|
+
siteInfo = await readSiteInfo();
|
|
1035
1136
|
} catch {
|
|
1036
|
-
//
|
|
1137
|
+
// options may not exist yet on a pre-migration db.
|
|
1037
1138
|
}
|
|
1038
1139
|
}),
|
|
1039
|
-
]
|
|
1140
|
+
];
|
|
1141
|
+
|
|
1142
|
+
if (ownsConfiguredDb) {
|
|
1143
|
+
coldStartReads.push(
|
|
1144
|
+
phase("rt.seedcheck", "Auto-seed gate", async () => {
|
|
1145
|
+
try {
|
|
1146
|
+
const [collectionCount, setupOption] = await Promise.all([
|
|
1147
|
+
readDb
|
|
1148
|
+
.selectFrom("_emdash_collections")
|
|
1149
|
+
.select((eb) => eb.fn.countAll<number>().as("count"))
|
|
1150
|
+
.executeTakeFirstOrThrow(),
|
|
1151
|
+
readDb
|
|
1152
|
+
.selectFrom("options")
|
|
1153
|
+
.select("value")
|
|
1154
|
+
.where("name", "=", "emdash:setup_complete")
|
|
1155
|
+
.executeTakeFirst(),
|
|
1156
|
+
]);
|
|
1157
|
+
const setupDone = (() => {
|
|
1158
|
+
try {
|
|
1159
|
+
return !!setupOption && JSON.parse(setupOption.value) === true;
|
|
1160
|
+
} catch {
|
|
1161
|
+
return false;
|
|
1162
|
+
}
|
|
1163
|
+
})();
|
|
1164
|
+
seedGate = { collectionCount: collectionCount.count, setupDone };
|
|
1165
|
+
} catch {
|
|
1166
|
+
// Leave the "already set up" default so a read failure never
|
|
1167
|
+
// triggers a seed onto a half-built db.
|
|
1168
|
+
}
|
|
1169
|
+
}),
|
|
1170
|
+
);
|
|
1171
|
+
}
|
|
1172
|
+
|
|
1173
|
+
await Promise.all(coldStartReads);
|
|
1174
|
+
|
|
1175
|
+
// Auto-seed the default schema for a first load that skipped the setup
|
|
1176
|
+
// wizard (the wizard and dev-bypass apply seeds explicitly). Run under a
|
|
1177
|
+
// per-isolate lock keyed by the configured db so a reclaimed-and-rerun
|
|
1178
|
+
// create() can't apply the seed a second time concurrently.
|
|
1179
|
+
if (seedGate.collectionCount === 0 && !seedGate.setupDone) {
|
|
1180
|
+
const seedKey = deps.config.database?.entrypoint ?? "default";
|
|
1181
|
+
const seedHolder = getSeedHolder();
|
|
1182
|
+
try {
|
|
1183
|
+
await initWithLock(
|
|
1184
|
+
seedHolder.lock,
|
|
1185
|
+
() => (seedHolder.done.has(seedKey) ? true : undefined),
|
|
1186
|
+
async () => {
|
|
1187
|
+
const { applySeed } = await import("./seed/apply.js");
|
|
1188
|
+
const { loadSeed } = await import("./seed/load.js");
|
|
1189
|
+
const { validateSeed } = await import("./seed/validate.js");
|
|
1190
|
+
|
|
1191
|
+
const seed = await loadSeed();
|
|
1192
|
+
const validation = validateSeed(seed);
|
|
1193
|
+
if (validation.valid) {
|
|
1194
|
+
await applySeed(db, seed, { onConflict: "skip" });
|
|
1195
|
+
console.log("Auto-seeded default collections");
|
|
1196
|
+
}
|
|
1197
|
+
seedHolder.done.add(seedKey);
|
|
1198
|
+
return true;
|
|
1199
|
+
},
|
|
1200
|
+
{ deadlineMs: DB_INIT_DEADLINE_MS, anchor: (promise) => after(() => promise) },
|
|
1201
|
+
);
|
|
1202
|
+
// The site-info read ran before the seed wrote its defaults, so
|
|
1203
|
+
// refresh the snapshot the plugin context sees.
|
|
1204
|
+
try {
|
|
1205
|
+
siteInfo = await readSiteInfo();
|
|
1206
|
+
} catch {
|
|
1207
|
+
// Non-fatal — plugin context falls back to undefined fields.
|
|
1208
|
+
}
|
|
1209
|
+
} catch {
|
|
1210
|
+
// Non-fatal — a failed seed (e.g. missing seed module) leaves the
|
|
1211
|
+
// site un-seeded; a later request retries.
|
|
1212
|
+
}
|
|
1213
|
+
}
|
|
1214
|
+
|
|
1215
|
+
// The read connection is single-use; everything below uses the singleton.
|
|
1216
|
+
if (readDbDisposable) {
|
|
1217
|
+
try {
|
|
1218
|
+
await readDbDisposable.destroy();
|
|
1219
|
+
} catch {
|
|
1220
|
+
// Non-fatal — the underlying binding is shared and needs no teardown.
|
|
1221
|
+
}
|
|
1222
|
+
}
|
|
1040
1223
|
|
|
1041
|
-
// Build set of enabled plugins
|
|
1042
1224
|
const enabledPlugins = new Set<string>();
|
|
1043
1225
|
for (const plugin of deps.plugins) {
|
|
1044
1226
|
const status = pluginStates.get(plugin.id);
|
|
@@ -1154,9 +1336,15 @@ export class EmDashRuntime {
|
|
|
1154
1336
|
// Filter to currently enabled plugins for the initial pipeline
|
|
1155
1337
|
const enabledPluginList = allPipelinePlugins.filter((p) => enabledPlugins.has(p.id));
|
|
1156
1338
|
|
|
1157
|
-
// Create hook pipeline
|
|
1339
|
+
// Create hook pipeline. getDb travels here (not just via the email
|
|
1340
|
+
// setContextFactory call below) so it survives rebuildHookPipeline(),
|
|
1341
|
+
// which reconstructs the factory from pipelineFactoryOptions. Without it,
|
|
1342
|
+
// toggling a plugin on an email-less deployment would silently revert
|
|
1343
|
+
// plugin contexts to the singleton db — re-breaking connection-backed
|
|
1344
|
+
// adapters. See #1622.
|
|
1158
1345
|
const pipelineFactoryOptions = {
|
|
1159
1346
|
db,
|
|
1347
|
+
getDb: resolveDb,
|
|
1160
1348
|
storage: storage ?? undefined,
|
|
1161
1349
|
siteInfo,
|
|
1162
1350
|
};
|
|
@@ -1208,7 +1396,7 @@ export class EmDashRuntime {
|
|
|
1208
1396
|
// Initialize media providers
|
|
1209
1397
|
const mediaProviders = new Map<string, MediaProvider>();
|
|
1210
1398
|
const mediaProviderEntries = deps.mediaProviderEntries ?? [];
|
|
1211
|
-
const providerContext: MediaProviderContext = { db, storage };
|
|
1399
|
+
const providerContext: MediaProviderContext = { db, storage, getDb: resolveDb };
|
|
1212
1400
|
|
|
1213
1401
|
for (const entry of mediaProviderEntries) {
|
|
1214
1402
|
try {
|
|
@@ -1249,8 +1437,10 @@ export class EmDashRuntime {
|
|
|
1249
1437
|
};
|
|
1250
1438
|
|
|
1251
1439
|
// Wire email pipeline into context factory (independent of cron —
|
|
1252
|
-
// must not be inside the cron try/catch or ctx.email breaks when cron fails)
|
|
1253
|
-
|
|
1440
|
+
// must not be inside the cron try/catch or ctx.email breaks when cron fails).
|
|
1441
|
+
// db/getDb were already set via pipelineFactoryOptions above; merge only
|
|
1442
|
+
// adds emailPipeline.
|
|
1443
|
+
pipeline.setContextFactory({ emailPipeline });
|
|
1254
1444
|
|
|
1255
1445
|
let cronExecutor: CronExecutor | null = null;
|
|
1256
1446
|
let cronScheduler: CronScheduler | null = null;
|
|
@@ -1262,7 +1452,7 @@ export class EmDashRuntime {
|
|
|
1262
1452
|
|
|
1263
1453
|
await phase("rt.cron", "Cron init (recovery deferred post-response)", async () => {
|
|
1264
1454
|
try {
|
|
1265
|
-
cronExecutor = new CronExecutor(
|
|
1455
|
+
cronExecutor = new CronExecutor(resolveDb, invokeCronHook);
|
|
1266
1456
|
|
|
1267
1457
|
// Recover stale locks from previous crashes. Pure bookkeeping
|
|
1268
1458
|
// against the _emdash_cron_tasks table — no request needs the
|
|
@@ -1444,45 +1634,9 @@ export class EmDashRuntime {
|
|
|
1444
1634
|
// cleanup-flag check costs an extra `options.get()` on every
|
|
1445
1635
|
// isolate cold boot forever. Cheaper to leave it.
|
|
1446
1636
|
|
|
1447
|
-
//
|
|
1448
|
-
//
|
|
1449
|
-
//
|
|
1450
|
-
try {
|
|
1451
|
-
const [collectionCount, setupOption] = await Promise.all([
|
|
1452
|
-
db
|
|
1453
|
-
.selectFrom("_emdash_collections")
|
|
1454
|
-
.select((eb) => eb.fn.countAll<number>().as("count"))
|
|
1455
|
-
.executeTakeFirstOrThrow(),
|
|
1456
|
-
db
|
|
1457
|
-
.selectFrom("options")
|
|
1458
|
-
.select("value")
|
|
1459
|
-
.where("name", "=", "emdash:setup_complete")
|
|
1460
|
-
.executeTakeFirst(),
|
|
1461
|
-
]);
|
|
1462
|
-
|
|
1463
|
-
const setupDone = (() => {
|
|
1464
|
-
try {
|
|
1465
|
-
return setupOption && JSON.parse(setupOption.value) === true;
|
|
1466
|
-
} catch {
|
|
1467
|
-
return false;
|
|
1468
|
-
}
|
|
1469
|
-
})();
|
|
1470
|
-
|
|
1471
|
-
if (collectionCount.count === 0 && !setupDone) {
|
|
1472
|
-
const { applySeed } = await import("./seed/apply.js");
|
|
1473
|
-
const { loadSeed } = await import("./seed/load.js");
|
|
1474
|
-
const { validateSeed } = await import("./seed/validate.js");
|
|
1475
|
-
|
|
1476
|
-
const seed = await loadSeed();
|
|
1477
|
-
const validation = validateSeed(seed);
|
|
1478
|
-
if (validation.valid) {
|
|
1479
|
-
await applySeed(db, seed, { onConflict: "skip" });
|
|
1480
|
-
console.log("Auto-seeded default collections");
|
|
1481
|
-
}
|
|
1482
|
-
}
|
|
1483
|
-
} catch {
|
|
1484
|
-
// Tables may not exist yet. Non-fatal.
|
|
1485
|
-
}
|
|
1637
|
+
// This returns a migrated but possibly unseeded db; create() runs
|
|
1638
|
+
// the seed gate and applies the seed, batched with its other init
|
|
1639
|
+
// reads.
|
|
1486
1640
|
|
|
1487
1641
|
// Publish only while still the current owner: a reclaimed slow
|
|
1488
1642
|
// init must not flip the cached Kysely identity back after the
|
|
@@ -2965,6 +3119,7 @@ export class EmDashRuntime {
|
|
|
2965
3119
|
if (trustedPlugin && this.enabledPlugins.has(trustedPlugin.id)) {
|
|
2966
3120
|
const routeRegistry = new PluginRouteRegistry({
|
|
2967
3121
|
db: this.db,
|
|
3122
|
+
storage: this.storage ?? undefined,
|
|
2968
3123
|
emailPipeline: this.email ?? undefined,
|
|
2969
3124
|
trustedProxyHeaders: getTrustedProxyHeaders(this.config),
|
|
2970
3125
|
});
|