emdash 0.22.0 → 0.24.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 +15 -15
- package/dist/api/schemas/index.d.mts +1 -1
- package/dist/api/schemas/index.mjs +3 -3
- package/dist/{api-BDuM4bEy.mjs → api-d_0wi9fW.mjs} +20 -20
- package/dist/{api-BDuM4bEy.mjs.map → api-d_0wi9fW.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-BE9UaWX0.mjs} +17 -17
- package/dist/{apply-wDqQoxX4.mjs.map → apply-BE9UaWX0.mjs.map} +1 -1
- package/dist/astro/index.d.mts +11 -11
- package/dist/astro/index.mjs +36 -11
- package/dist/astro/index.mjs.map +1 -1
- package/dist/astro/middleware/auth.d.mts +9 -9
- package/dist/astro/middleware/auth.mjs +7 -7
- package/dist/astro/middleware/redirect.mjs +5 -5
- 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 +362 -141
- 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 +4 -4
- package/dist/astro/routes/api/admin/api-tokens/index.mjs +5 -5
- package/dist/astro/routes/api/admin/byline-fields/_slug_/usage.mjs +4 -4
- package/dist/astro/routes/api/admin/byline-fields/_slug_.mjs +8 -8
- package/dist/astro/routes/api/admin/byline-fields/index.mjs +8 -8
- package/dist/astro/routes/api/admin/byline-fields/reorder.mjs +8 -8
- package/dist/astro/routes/api/admin/bylines/_id_/index.mjs +13 -12
- package/dist/astro/routes/api/admin/bylines/_id_/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/bylines/_id_/translations.mjs +13 -12
- package/dist/astro/routes/api/admin/bylines/_id_/translations.mjs.map +1 -1
- package/dist/astro/routes/api/admin/bylines/index.mjs +13 -12
- package/dist/astro/routes/api/admin/bylines/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/comments/_id_/status.mjs +11 -11
- 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/oauth-clients/_id_.mjs +4 -4
- package/dist/astro/routes/api/admin/oauth-clients/index.mjs +4 -4
- package/dist/astro/routes/api/admin/plugins/_id_/disable.mjs +35 -34
- package/dist/astro/routes/api/admin/plugins/_id_/disable.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/_id_/enable.mjs +35 -34
- package/dist/astro/routes/api/admin/plugins/_id_/enable.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/_id_/index.mjs +34 -33
- package/dist/astro/routes/api/admin/plugins/_id_/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/_id_/uninstall.mjs +34 -33
- package/dist/astro/routes/api/admin/plugins/_id_/uninstall.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/_id_/update.mjs +34 -33
- package/dist/astro/routes/api/admin/plugins/_id_/update.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/index.mjs +34 -33
- package/dist/astro/routes/api/admin/plugins/index.mjs.map +1 -1
- 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 -33
- 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 +34 -33
- package/dist/astro/routes/api/admin/plugins/marketplace/_id_/install.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/marketplace/index.mjs +34 -33
- package/dist/astro/routes/api/admin/plugins/marketplace/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/registry/_id_/uninstall.mjs +34 -33
- 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 +35 -34
- package/dist/astro/routes/api/admin/plugins/registry/_id_/update.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/registry/artifact.mjs +34 -33
- package/dist/astro/routes/api/admin/plugins/registry/artifact.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/registry/install.mjs +35 -34
- package/dist/astro/routes/api/admin/plugins/registry/install.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/updates.mjs +34 -33
- package/dist/astro/routes/api/admin/plugins/updates.mjs.map +1 -1
- package/dist/astro/routes/api/admin/themes/marketplace/_id_/index.mjs +34 -33
- 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 +3 -3
- package/dist/astro/routes/api/admin/themes/marketplace/index.mjs +34 -33
- package/dist/astro/routes/api/admin/themes/marketplace/index.mjs.map +1 -1
- 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 +3 -3
- package/dist/astro/routes/api/admin/users/index.mjs +6 -6
- package/dist/astro/routes/api/auth/dev-bypass.mjs +5 -5
- package/dist/astro/routes/api/auth/invite/accept.mjs +2 -2
- package/dist/astro/routes/api/auth/invite/complete.mjs +10 -10
- package/dist/astro/routes/api/auth/invite/index.mjs +7 -7
- package/dist/astro/routes/api/auth/invite/register-options.mjs +9 -9
- package/dist/astro/routes/api/auth/logout.mjs +3 -3
- package/dist/astro/routes/api/auth/magic-link/send.mjs +9 -9
- package/dist/astro/routes/api/auth/magic-link/verify.mjs +3 -3
- package/dist/astro/routes/api/auth/me.mjs +7 -7
- 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 +6 -6
- package/dist/astro/routes/api/auth/passkey/index.mjs +2 -2
- package/dist/astro/routes/api/auth/passkey/options.mjs +11 -11
- package/dist/astro/routes/api/auth/passkey/register/options.mjs +9 -9
- package/dist/astro/routes/api/auth/passkey/register/verify.mjs +10 -10
- package/dist/astro/routes/api/auth/passkey/verify.mjs +10 -10
- package/dist/astro/routes/api/auth/signup/complete.mjs +10 -10
- package/dist/astro/routes/api/auth/signup/request.mjs +9 -9
- package/dist/astro/routes/api/auth/signup/verify.mjs +2 -2
- package/dist/astro/routes/api/comments/_collection_/_contentId_/index.mjs +12 -12
- package/dist/astro/routes/api/comments/_collection_/_contentId_/reactions.mjs +11 -11
- 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 +10 -10
- package/dist/astro/routes/api/content/_collection_/_id_/publish.mjs +7 -7
- 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 +12 -12
- 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 +3 -3
- package/dist/astro/routes/api/import/probe.d.mts +3 -3
- package/dist/astro/routes/api/import/probe.mjs +11 -11
- package/dist/astro/routes/api/import/wordpress/analyze.mjs +3 -3
- package/dist/astro/routes/api/import/wordpress/execute.d.mts +9 -9
- package/dist/astro/routes/api/import/wordpress/execute.mjs +10 -9
- package/dist/astro/routes/api/import/wordpress/execute.mjs.map +1 -1
- package/dist/astro/routes/api/import/wordpress/media.mjs +9 -9
- package/dist/astro/routes/api/import/wordpress/prepare.mjs +9 -9
- package/dist/astro/routes/api/import/wordpress/rewrite-urls.mjs +9 -9
- package/dist/astro/routes/api/import/wordpress-plugin/analyze.d.mts +1 -1
- package/dist/astro/routes/api/import/wordpress-plugin/analyze.mjs +11 -11
- package/dist/astro/routes/api/import/wordpress-plugin/execute.d.mts +1 -1
- package/dist/astro/routes/api/import/wordpress-plugin/execute.mjs +13 -12
- package/dist/astro/routes/api/import/wordpress-plugin/execute.mjs.map +1 -1
- package/dist/astro/routes/api/manifest.mjs +4 -4
- 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_.mjs +7 -7
- 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 +9 -9
- package/dist/astro/routes/api/media.mjs +12 -12
- 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.mjs +6 -6
- package/dist/astro/routes/api/oauth/device/authorize.mjs +6 -6
- package/dist/astro/routes/api/oauth/device/code.mjs +9 -9
- package/dist/astro/routes/api/oauth/device/token.mjs +8 -8
- package/dist/astro/routes/api/oauth/register.mjs +3 -3
- package/dist/astro/routes/api/oauth/token/refresh.mjs +6 -6
- package/dist/astro/routes/api/oauth/token/revoke.mjs +6 -6
- package/dist/astro/routes/api/oauth/token.mjs +6 -6
- 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 +9 -9
- package/dist/astro/routes/api/redirects/404s/summary.mjs +9 -9
- package/dist/astro/routes/api/redirects/_id_.mjs +10 -10
- package/dist/astro/routes/api/redirects/index.mjs +10 -10
- 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 -33
- 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 +34 -33
- 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 +34 -33
- package/dist/astro/routes/api/schema/collections/_slug_/fields/reorder.mjs.map +1 -1
- package/dist/astro/routes/api/schema/collections/_slug_/index.mjs +34 -33
- package/dist/astro/routes/api/schema/collections/_slug_/index.mjs.map +1 -1
- package/dist/astro/routes/api/schema/collections/index.mjs +34 -33
- package/dist/astro/routes/api/schema/collections/index.mjs.map +1 -1
- package/dist/astro/routes/api/schema/index.mjs +8 -7
- package/dist/astro/routes/api/schema/index.mjs.map +1 -1
- package/dist/astro/routes/api/schema/orphans/_slug_.mjs +34 -33
- package/dist/astro/routes/api/schema/orphans/_slug_.mjs.map +1 -1
- package/dist/astro/routes/api/schema/orphans/index.mjs +34 -33
- package/dist/astro/routes/api/schema/orphans/index.mjs.map +1 -1
- package/dist/astro/routes/api/search/enable.mjs +10 -10
- package/dist/astro/routes/api/search/index.mjs +9 -9
- package/dist/astro/routes/api/search/rebuild.mjs +10 -10
- package/dist/astro/routes/api/search/stats.mjs +6 -6
- package/dist/astro/routes/api/search/suggest.mjs +9 -9
- package/dist/astro/routes/api/sections/_slug_.mjs +9 -9
- package/dist/astro/routes/api/sections/index.mjs +9 -9
- package/dist/astro/routes/api/settings/email.mjs +4 -4
- package/dist/astro/routes/api/settings.mjs +11 -11
- package/dist/astro/routes/api/setup/admin-verify.mjs +11 -11
- package/dist/astro/routes/api/setup/admin.mjs +10 -10
- package/dist/astro/routes/api/setup/dev-bypass.mjs +23 -22
- package/dist/astro/routes/api/setup/dev-bypass.mjs.map +1 -1
- package/dist/astro/routes/api/setup/dev-reset.mjs +2 -2
- package/dist/astro/routes/api/setup/index.mjs +24 -23
- package/dist/astro/routes/api/setup/index.mjs.map +1 -1
- package/dist/astro/routes/api/setup/status.mjs +4 -4
- package/dist/astro/routes/api/snapshot.mjs +6 -6
- package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_/translations.mjs +12 -12
- package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_.mjs +12 -12
- package/dist/astro/routes/api/taxonomies/_name_/terms/index.mjs +12 -12
- package/dist/astro/routes/api/taxonomies/index.mjs +12 -12
- package/dist/astro/routes/api/themes/preview.mjs +5 -5
- package/dist/astro/routes/api/typegen.mjs +5 -5
- 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 +7 -7
- package/dist/astro/routes/api/widget-areas/_name_/widgets/_id_.mjs +9 -9
- package/dist/astro/routes/api/widget-areas/_name_/widgets.mjs +9 -9
- package/dist/astro/routes/api/widget-areas/_name_.mjs +5 -5
- package/dist/astro/routes/api/widget-areas/index.mjs +9 -9
- package/dist/astro/routes/api/widget-components.mjs +3 -3
- package/dist/astro/routes/robots.txt.mjs +5 -5
- package/dist/astro/routes/sitemap-_collection_.xml.mjs +8 -8
- package/dist/astro/routes/sitemap.xml.mjs +6 -6
- 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-B__u-iZJ.mjs} +2 -2
- package/dist/{authorize-C0EYoUeV.mjs.map → authorize-B__u-iZJ.mjs.map} +1 -1
- package/dist/{byline-CC0WS4Gu.mjs → byline-C-YajfV7.mjs} +18 -76
- package/dist/byline-C-YajfV7.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-BMtJnPnG.mjs} +7 -7
- package/dist/{bylines-CCO1CYnH.mjs.map → bylines-BMtJnPnG.mjs.map} +1 -1
- package/dist/{bylines-DGekMGGm.mjs → bylines-D4KADDAi.mjs} +4 -4
- package/dist/{bylines-DGekMGGm.mjs.map → bylines-D4KADDAi.mjs.map} +1 -1
- package/dist/{cache-pXTpun6s.mjs → cache-BUJe2w6Z.mjs} +2 -2
- package/dist/{cache-pXTpun6s.mjs.map → cache-BUJe2w6Z.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/{chunks-SyjZaYwV.mjs → chunks-BHgcHh2C.mjs} +2 -2
- package/dist/{chunks-SyjZaYwV.mjs.map → chunks-BHgcHh2C.mjs.map} +1 -1
- package/dist/cli/index.mjs +25 -24
- 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-80UyJJUR.mjs → comment-BDx50EX5.mjs} +2 -2
- package/dist/{comment-80UyJJUR.mjs.map → comment-BDx50EX5.mjs.map} +1 -1
- package/dist/{comment-reaction-B6AdcpXw.mjs → comment-reaction-Gv_pgfI3.mjs} +2 -2
- package/dist/{comment-reaction-B6AdcpXw.mjs.map → comment-reaction-Gv_pgfI3.mjs.map} +1 -1
- package/dist/{comments-CtPkT2tp.mjs → comments-CXHuQ6jI.mjs} +3 -3
- package/dist/{comments-CtPkT2tp.mjs.map → comments-CXHuQ6jI.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/{content-2PTDNnoh.mjs → content-PoVGKjp0.mjs} +3 -3
- package/dist/{content-2PTDNnoh.mjs.map → content-PoVGKjp0.mjs.map} +1 -1
- package/dist/{context-f1__jpzF.mjs → context-Dvws41_A.mjs} +62 -24
- package/dist/context-Dvws41_A.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-DsYU8JKS.mjs} +4 -4
- package/dist/{dashboard-BOESNcwE.mjs.map → dashboard-DsYU8JKS.mjs.map} +1 -1
- package/dist/db/index.d.mts +3 -3
- package/dist/db/index.mjs +1 -1
- 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-lq_fL-RS.mjs} +2 -2
- package/dist/{error-BQ1pxs0L.mjs.map → error-lq_fL-RS.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-CYYx8xlG.mjs +77 -0
- package/dist/field-defs-cache-CYYx8xlG.mjs.map +1 -0
- package/dist/{fts-manager-DtiWqwNJ.mjs → fts-manager-DW_NR-Fs.mjs} +2 -2
- package/dist/{fts-manager-DtiWqwNJ.mjs.map → fts-manager-DW_NR-Fs.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-BroXT-vD.d.mts} +136 -38
- package/dist/index-BroXT-vD.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 +55 -54
- package/dist/{load-Dtoo7KcJ.mjs → load-DMFi4n1p.mjs} +2 -2
- package/dist/{load-Dtoo7KcJ.mjs.map → load-DMFi4n1p.mjs.map} +1 -1
- package/dist/{loader-C8Z48Uof.mjs → loader-BR2SgfEc.mjs} +77 -12
- package/dist/loader-BR2SgfEc.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 +11 -9
- package/dist/media/local-runtime.mjs.map +1 -1
- package/dist/{media-Bw0sA6rb.mjs → media-CTjJoJTh.mjs} +2 -2
- package/dist/{media-Bw0sA6rb.mjs.map → media-CTjJoJTh.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-CYs0WZoL.mjs → menus-8O6xNcYW.mjs} +2 -2
- package/dist/{menus-CYs0WZoL.mjs.map → menus-8O6xNcYW.mjs.map} +1 -1
- package/dist/{menus-DOs1MQJg.mjs → menus-GvRSpgIA.mjs} +57 -14
- package/dist/menus-GvRSpgIA.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-DHI873qU.mjs} +2 -2
- package/dist/{parse-qrHlnzTy.mjs.map → parse-DHI873qU.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-DZdlS6Cu.mjs} +92 -14
- package/dist/query-DZdlS6Cu.mjs.map +1 -0
- package/dist/{rate-limit-DfNAqIWW.mjs → rate-limit-D1Y6VFVP.mjs} +2 -2
- package/dist/{rate-limit-DfNAqIWW.mjs.map → rate-limit-D1Y6VFVP.mjs.map} +1 -1
- package/dist/{redirect-Bifv_yHv.mjs → redirect-C1KVGYWe.mjs} +2 -2
- package/dist/{redirect-Bifv_yHv.mjs.map → redirect-C1KVGYWe.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-DgnypVir.mjs} +4 -4
- package/dist/{redirects-CT_vb3NV.mjs.map → redirects-DgnypVir.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-CJkCubOJ.mjs} +4 -4
- package/dist/{registry-CjK96fHD.mjs.map → registry-CJkCubOJ.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-DYYnW530.mjs → runner-BsquExlK.mjs} +246 -174
- package/dist/runner-BsquExlK.mjs.map +1 -0
- 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 +2 -2
- package/dist/{schema-5z2Jfnbm.mjs → schema-DMjXuvNU.mjs} +4 -4
- package/dist/{schema-5z2Jfnbm.mjs.map → schema-DMjXuvNU.mjs.map} +1 -1
- package/dist/{search-D9FkoM-k.mjs → search-D1wKk3lc.mjs} +4 -4
- package/dist/{search-D9FkoM-k.mjs.map → search-D1wKk3lc.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-CCMic8dB.mjs} +3 -3
- package/dist/{sections-DWYZo6HK.mjs.map → sections-CCMic8dB.mjs.map} +1 -1
- package/dist/seed/index.d.mts +2 -2
- package/dist/seed/index.mjs +17 -16
- package/dist/seo/index.d.mts +1 -1
- package/dist/seo/index.mjs +1 -1
- package/dist/{seo-Cu47j3mJ.mjs → seo-3QrZ1EPT.mjs} +2 -2
- package/dist/{seo-Cu47j3mJ.mjs.map → seo-3QrZ1EPT.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-CQHK_10l.mjs} +3 -3
- package/dist/{service-DTmtqCnw.mjs.map → service-CQHK_10l.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-C3Yi5Co3.mjs} +3 -3
- package/dist/{settings-DUrVDN0c.mjs.map → settings-C3Yi5Co3.mjs.map} +1 -1
- package/dist/{settings-yaxu9mU-.mjs → settings-D9rvaLuY.mjs} +4 -4
- package/dist/{settings-yaxu9mU-.mjs.map → settings-D9rvaLuY.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-Be9B1jEj.mjs → taxonomies-CurpLtNC.mjs} +52 -24
- package/dist/taxonomies-CurpLtNC.mjs.map +1 -0
- package/dist/{taxonomies-CJmkEpdS.mjs → taxonomies-DhLaNJji.mjs} +34 -27
- package/dist/taxonomies-DhLaNJji.mjs.map +1 -0
- package/dist/{taxonomy-B2HQuVf5.mjs → taxonomy-BBUlGug5.mjs} +33 -7
- package/dist/taxonomy-BBUlGug5.mjs.map +1 -0
- 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 → types-CmI1OyQg.mjs} +2 -2
- package/dist/types-CmI1OyQg.mjs.map +1 -0
- 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/{user-Db-Rti_z.mjs → user-JAuc8VUf.mjs} +3 -3
- package/dist/{user-Db-Rti_z.mjs.map → user-JAuc8VUf.mjs.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-BzXHWnkV.mjs} +2 -2
- package/dist/{validate-Bwl64sxv.mjs.map → validate-BzXHWnkV.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-CY1gk4Ar.mjs} +6 -6
- package/dist/{validation-C_yOvFaO.mjs.map → validation-CY1gk4Ar.mjs.map} +1 -1
- package/dist/version-B5nHxI5Y.mjs +7 -0
- package/dist/{version-RnYXYjzD.mjs.map → version-B5nHxI5Y.mjs.map} +1 -1
- package/dist/{widgets-8GONuRHo.mjs → widgets-Dri0spI4.mjs} +3 -3
- package/dist/{widgets-8GONuRHo.mjs.map → widgets-Dri0spI4.mjs.map} +1 -1
- package/dist/{zod-generator-D481JjzD.mjs → zod-generator-xEHODMJf.mjs} +51 -15
- package/dist/zod-generator-xEHODMJf.mjs.map +1 -0
- package/package.json +8 -7
- package/src/api/handlers/taxonomies.ts +62 -32
- package/src/api/schemas/bylines.ts +8 -0
- package/src/astro/integration/shims/use-sync-external-store-with-selector.js +71 -0
- package/src/astro/integration/shims/use-sync-external-store.js +1 -0
- package/src/astro/integration/virtual-modules.ts +8 -0
- package/src/astro/integration/vite-config.ts +56 -9
- 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 +103 -31
- 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 +15 -11
- 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/migrations/045_taxonomy_parent_group.ts +68 -0
- package/src/database/migrations/runner.ts +2 -0
- package/src/database/repositories/byline.ts +14 -0
- package/src/database/repositories/taxonomy.ts +50 -7
- package/src/database/repositories/types.ts +13 -0
- package/src/emdash-runtime.ts +226 -71
- package/src/loader.ts +161 -13
- 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 +201 -19
- package/src/schema/zod-generator.ts +53 -8
- package/src/taxonomies/index.ts +46 -8
- 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/runner-DYYnW530.mjs.map +0 -1
- package/dist/taxonomies-Be9B1jEj.mjs.map +0 -1
- package/dist/taxonomies-CJmkEpdS.mjs.map +0 -1
- package/dist/taxonomy-B2HQuVf5.mjs.map +0 -1
- package/dist/types-CWGYDYqF.d.mts.map +0 -1
- package/dist/types-DXOIbece.mjs.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
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { a as __exportAll } from "./runner-
|
|
2
|
-
import { n as hashString } from "./hash-
|
|
1
|
+
import { a as __exportAll } from "./runner-BsquExlK.mjs";
|
|
2
|
+
import { n as hashString } from "./hash-DrvzIXcz.mjs";
|
|
3
3
|
import { z } from "zod";
|
|
4
4
|
|
|
5
5
|
//#region src/schema/zod-generator.ts
|
|
@@ -8,7 +8,8 @@ var zod_generator_exports = /* @__PURE__ */ __exportAll({
|
|
|
8
8
|
generateSchemaHash: () => generateSchemaHash,
|
|
9
9
|
generateTypeScript: () => generateTypeScript,
|
|
10
10
|
generateTypesFile: () => generateTypesFile,
|
|
11
|
-
generateZodSchema: () => generateZodSchema
|
|
11
|
+
generateZodSchema: () => generateZodSchema,
|
|
12
|
+
uniqueInterfaceNames: () => uniqueInterfaceNames
|
|
12
13
|
});
|
|
13
14
|
/** Pattern to split on underscores, hyphens, and spaces for PascalCase conversion */
|
|
14
15
|
const PASCAL_CASE_SPLIT_PATTERN = /[_\-\s]+/;
|
|
@@ -115,8 +116,7 @@ function applyValidation(schema, field) {
|
|
|
115
116
|
* Generate TypeScript interface from field definitions
|
|
116
117
|
* Used by CLI `emdash types` to generate types
|
|
117
118
|
*/
|
|
118
|
-
function generateTypeScript(collection) {
|
|
119
|
-
const interfaceName = getInterfaceName(collection);
|
|
119
|
+
function generateTypeScript(collection, interfaceName = getInterfaceName(collection)) {
|
|
120
120
|
const lines = [];
|
|
121
121
|
lines.push(`export interface ${interfaceName} {`);
|
|
122
122
|
lines.push(` id: string;`);
|
|
@@ -151,16 +151,14 @@ function generateTypesFile(collections) {
|
|
|
151
151
|
if (needsPortableText) imports.push("PortableTextBlock");
|
|
152
152
|
lines.push(`import type { ${imports.join(", ")} } from "emdash";`);
|
|
153
153
|
lines.push(``);
|
|
154
|
+
const interfaceNames = uniqueInterfaceNames(collections);
|
|
154
155
|
for (const collection of collections) {
|
|
155
|
-
lines.push(generateTypeScript(collection));
|
|
156
|
+
lines.push(generateTypeScript(collection, interfaceNames.get(collection.slug)));
|
|
156
157
|
lines.push(``);
|
|
157
158
|
}
|
|
158
159
|
lines.push(`declare module "emdash" {`);
|
|
159
160
|
lines.push(` interface EmDashCollections {`);
|
|
160
|
-
for (const collection of collections) {
|
|
161
|
-
const interfaceName = getInterfaceName(collection);
|
|
162
|
-
lines.push(` ${collection.slug}: ${interfaceName};`);
|
|
163
|
-
}
|
|
161
|
+
for (const collection of collections) lines.push(` ${collection.slug}: ${interfaceNames.get(collection.slug)};`);
|
|
164
162
|
lines.push(` }`);
|
|
165
163
|
lines.push(`}`);
|
|
166
164
|
return lines.join("\n");
|
|
@@ -215,7 +213,8 @@ function pascalCase(str) {
|
|
|
215
213
|
return str.split(PASCAL_CASE_SPLIT_PATTERN).filter(Boolean).map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()).join("");
|
|
216
214
|
}
|
|
217
215
|
/**
|
|
218
|
-
*
|
|
216
|
+
* Naive singularization for slug-derived interface names. Handles the common
|
|
217
|
+
* English plural endings; intentionally simple, not a full inflector.
|
|
219
218
|
*/
|
|
220
219
|
function singularize(str) {
|
|
221
220
|
if (str.endsWith("ies")) return str.slice(0, -3) + "y";
|
|
@@ -224,12 +223,49 @@ function singularize(str) {
|
|
|
224
223
|
return str;
|
|
225
224
|
}
|
|
226
225
|
/**
|
|
227
|
-
* Get the interface name for a collection
|
|
226
|
+
* Get the interface name for a collection.
|
|
227
|
+
*
|
|
228
|
+
* Derived from the slug, not the human label. Slugs are constrained to
|
|
229
|
+
* `/^[a-z][a-z0-9_]*$/`, so PascalCasing one always yields a valid TS
|
|
230
|
+
* identifier; labels are arbitrary and user-controlled (punctuation, spaces,
|
|
231
|
+
* duplicates across collections), which produced syntactically invalid or
|
|
232
|
+
* duplicate interface names. The slug is singularized first because the
|
|
233
|
+
* interface describes a single entry, not the collection (`posts` -> `Post`).
|
|
234
|
+
*
|
|
235
|
+
* Singularization can map two distinct slugs onto the same name, so callers
|
|
236
|
+
* generating more than one interface must dedupe -- see `uniqueInterfaceNames`.
|
|
228
237
|
*/
|
|
229
238
|
function getInterfaceName(collection) {
|
|
230
|
-
return pascalCase(
|
|
239
|
+
return pascalCase(singularize(collection.slug));
|
|
240
|
+
}
|
|
241
|
+
/**
|
|
242
|
+
* Resolve interface names for a set of collections, guaranteeing each is
|
|
243
|
+
* unique within the file. Collisions (from singularization or PascalCasing
|
|
244
|
+
* collapsing distinct slugs) get a numeric suffix in collection order, so the
|
|
245
|
+
* generated `.d.ts` never declares two interfaces with the same identifier.
|
|
246
|
+
*
|
|
247
|
+
* The suffix is chosen against the set of names already emitted, not a
|
|
248
|
+
* per-base counter, so a generated name can't collide with another slug's
|
|
249
|
+
* base name (e.g. slugs `book`, `books`, `book2`: `books` -> `Book2` would
|
|
250
|
+
* clash with `book2`, so it advances to `Book3`).
|
|
251
|
+
*/
|
|
252
|
+
function uniqueInterfaceNames(collections) {
|
|
253
|
+
const used = /* @__PURE__ */ new Set();
|
|
254
|
+
const names = /* @__PURE__ */ new Map();
|
|
255
|
+
for (const collection of collections) {
|
|
256
|
+
const base = getInterfaceName(collection);
|
|
257
|
+
let name = base;
|
|
258
|
+
let suffix = 2;
|
|
259
|
+
while (used.has(name)) {
|
|
260
|
+
name = `${base}${suffix}`;
|
|
261
|
+
suffix++;
|
|
262
|
+
}
|
|
263
|
+
used.add(name);
|
|
264
|
+
names.set(collection.slug, name);
|
|
265
|
+
}
|
|
266
|
+
return names;
|
|
231
267
|
}
|
|
232
268
|
|
|
233
269
|
//#endregion
|
|
234
|
-
export { generateZodSchema as n,
|
|
235
|
-
//# sourceMappingURL=zod-generator-
|
|
270
|
+
export { zod_generator_exports as i, generateZodSchema as n, uniqueInterfaceNames as r, generateTypeScript as t };
|
|
271
|
+
//# sourceMappingURL=zod-generator-xEHODMJf.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"zod-generator-xEHODMJf.mjs","names":[],"sources":["../src/schema/zod-generator.ts"],"sourcesContent":["import { z, type ZodTypeAny } from \"zod\";\n\nimport { hashString } from \"../utils/hash.js\";\nimport type { Field, FieldType, CollectionWithFields } from \"./types.js\";\n\n/** Pattern to split on underscores, hyphens, and spaces for PascalCase conversion */\nconst PASCAL_CASE_SPLIT_PATTERN = /[_\\-\\s]+/;\n\n/**\n * Generate a Zod schema from a collection's field definitions\n *\n * This allows runtime validation of content based on dynamically\n * defined schemas stored in D1.\n */\nexport function generateZodSchema(\n\tcollection: CollectionWithFields,\n): z.ZodObject<Record<string, ZodTypeAny>> {\n\tconst shape: Record<string, ZodTypeAny> = {};\n\n\tfor (const field of collection.fields) {\n\t\tshape[field.slug] = generateFieldSchema(field);\n\t}\n\n\treturn z.object(shape);\n}\n\n/**\n * Generate Zod schema for a single field\n */\nexport function generateFieldSchema(field: Field): ZodTypeAny {\n\tlet schema = getBaseSchema(field.type, field);\n\n\t// Apply validation rules\n\tif (field.validation) {\n\t\tschema = applyValidation(schema, field);\n\t}\n\n\t// Apply required/optional. Non-required fields use `.nullish()` rather\n\t// than `.optional()` because the underlying SQLite columns are nullable\n\t// (see `SchemaRegistry.addFieldColumn` -- non-required fields are added\n\t// without `NOT NULL`). The admin re-sends what it loaded from the\n\t// server on autosave, so any field that's actually `null` in the DB\n\t// must round-trip cleanly through the validator. `.optional()` only\n\t// accepts `undefined`; `.nullish()` accepts both `undefined` and\n\t// `null`. (#867 — autosave failures on seeded entries.)\n\tif (!field.required) {\n\t\tschema = schema.nullish();\n\t}\n\n\t// Apply default value\n\tif (field.defaultValue !== undefined) {\n\t\tschema = schema.default(field.defaultValue);\n\t}\n\n\treturn schema;\n}\n\n/**\n * Get base Zod schema for a field type\n */\nfunction getBaseSchema(type: FieldType, field: Field): ZodTypeAny {\n\tswitch (type) {\n\t\tcase \"url\":\n\t\t\treturn z.string().url();\n\n\t\tcase \"string\":\n\t\tcase \"text\":\n\t\tcase \"slug\":\n\t\t\treturn z.string();\n\n\t\tcase \"number\":\n\t\t\treturn z.number();\n\n\t\tcase \"integer\":\n\t\t\treturn z.number().int();\n\n\t\tcase \"boolean\":\n\t\t\t// Boolean fields map to `INTEGER` columns (`FIELD_TYPE_TO_COLUMN`\n\t\t\t// in `schema/types.ts`) and `serializeValue` in\n\t\t\t// `database/repositories/content.ts` writes booleans as 0/1.\n\t\t\t// `deserializeValue` never converts them back, so reads return\n\t\t\t// numbers. Coerce the stored 0/1 shape here so a GET → POST\n\t\t\t// round-trip on a boolean field passes validation. Other inputs\n\t\t\t// (strings, other numbers) fall through to `z.boolean()` and\n\t\t\t// produce its standard rejection.\n\t\t\treturn z.preprocess((v) => (v === 0 || v === 1 ? Boolean(v) : v), z.boolean());\n\n\t\tcase \"datetime\":\n\t\t\treturn z.string().datetime().or(z.string().date());\n\n\t\tcase \"select\": {\n\t\t\tconst options = field.validation?.options;\n\t\t\tif (options && options.length > 0) {\n\t\t\t\tconst [first, ...rest] = options;\n\t\t\t\treturn z.enum([first, ...rest]);\n\t\t\t}\n\t\t\treturn z.string();\n\t\t}\n\n\t\tcase \"multiSelect\": {\n\t\t\tconst multiOptions = field.validation?.options;\n\t\t\tif (multiOptions && multiOptions.length > 0) {\n\t\t\t\tconst [first, ...rest] = multiOptions;\n\t\t\t\treturn z.array(z.enum([first, ...rest]));\n\t\t\t}\n\t\t\treturn z.array(z.string());\n\t\t}\n\n\t\tcase \"portableText\":\n\t\t\t// Portable Text is an array of blocks. We require `_type` because\n\t\t\t// renderers dispatch on it, but `_key` is intentionally optional:\n\t\t\t// it's a UI-layer concern that the editor regenerates on every\n\t\t\t// change (see `PortableTextEditor`), and the rest of this schema\n\t\t\t// uses `.passthrough()` for everything below the top level. Making\n\t\t\t// `_key` strictly required here was an accidentally tight invariant\n\t\t\t// that rejected any seed/import data not authored against the\n\t\t\t// editor (#867 — autosave failures on seeded template content).\n\t\t\treturn z.array(\n\t\t\t\tz\n\t\t\t\t\t.object({\n\t\t\t\t\t\t_type: z.string(),\n\t\t\t\t\t\t_key: z.string().optional(),\n\t\t\t\t\t})\n\t\t\t\t\t.passthrough(),\n\t\t\t);\n\n\t\tcase \"image\":\n\t\t\treturn z.object({\n\t\t\t\tid: z.string(),\n\t\t\t\tsrc: z.string().optional(),\n\t\t\t\talt: z.string().optional(),\n\t\t\t\twidth: z.number().optional(),\n\t\t\t\theight: z.number().optional(),\n\t\t\t\t/** Provider ID (e.g. \"local\", \"cloudflare-images\") */\n\t\t\t\tprovider: z.string().optional(),\n\t\t\t\t/** Admin-side preview URL for external providers (not persisted by plugins) */\n\t\t\t\tpreviewUrl: z.string().optional(),\n\t\t\t\t/** Provider-specific metadata; for local media this carries storageKey */\n\t\t\t\tmeta: z.record(z.string(), z.unknown()).optional(),\n\t\t\t});\n\n\t\tcase \"file\":\n\t\t\treturn z.object({\n\t\t\t\tid: z.string(),\n\t\t\t\tsrc: z.string().optional(),\n\t\t\t\tfilename: z.string().optional(),\n\t\t\t\tmimeType: z.string().optional(),\n\t\t\t\tsize: z.number().optional(),\n\t\t\t\t/** Provider ID (e.g. \"local\", \"s3\") */\n\t\t\t\tprovider: z.string().optional(),\n\t\t\t\t/** Provider-specific metadata; for local media this carries storageKey */\n\t\t\t\tmeta: z.record(z.string(), z.unknown()).optional(),\n\t\t\t});\n\n\t\tcase \"reference\":\n\t\t\treturn z.string(); // Reference ID\n\n\t\tcase \"json\":\n\t\t\treturn z.unknown();\n\n\t\tdefault:\n\t\t\treturn z.unknown();\n\t}\n}\n\n/**\n * Apply validation rules to a schema\n */\nfunction applyValidation(schema: ZodTypeAny, field: Field): ZodTypeAny {\n\tconst validation = field.validation;\n\tif (!validation) return schema;\n\n\t// String validations\n\tif (schema instanceof z.ZodString) {\n\t\tlet strSchema = schema;\n\t\tif (validation.minLength !== undefined) {\n\t\t\tstrSchema = strSchema.min(validation.minLength);\n\t\t}\n\t\tif (validation.maxLength !== undefined) {\n\t\t\tstrSchema = strSchema.max(validation.maxLength);\n\t\t}\n\t\tif (validation.pattern) {\n\t\t\tstrSchema = strSchema.regex(new RegExp(validation.pattern));\n\t\t}\n\t\treturn strSchema;\n\t}\n\n\t// Number validations\n\tif (schema instanceof z.ZodNumber) {\n\t\tlet numSchema = schema;\n\t\tif (validation.min !== undefined) {\n\t\t\tnumSchema = numSchema.min(validation.min);\n\t\t}\n\t\tif (validation.max !== undefined) {\n\t\t\tnumSchema = numSchema.max(validation.max);\n\t\t}\n\t\treturn numSchema;\n\t}\n\n\treturn schema;\n}\n\n/**\n * Schema cache to avoid regenerating schemas on every request\n */\nconst schemaCache = new Map<string, { schema: z.ZodObject<any>; version: string }>();\n\n/**\n * Get or generate a cached schema for a collection\n */\nexport function getCachedSchema(\n\tcollection: CollectionWithFields,\n\tversion?: string,\n): z.ZodObject<any> {\n\tconst cacheKey = collection.slug;\n\tconst cached = schemaCache.get(cacheKey);\n\n\t// If version matches, return cached schema\n\tif (cached && (!version || cached.version === version)) {\n\t\treturn cached.schema;\n\t}\n\n\t// Generate new schema\n\tconst schema = generateZodSchema(collection);\n\n\t// Cache it\n\tschemaCache.set(cacheKey, {\n\t\tschema,\n\t\tversion: version || collection.updatedAt,\n\t});\n\n\treturn schema;\n}\n\n/**\n * Invalidate cached schema for a collection\n */\nexport function invalidateSchemaCache(slug: string): void {\n\tschemaCache.delete(slug);\n}\n\n/**\n * Clear all cached schemas\n */\nexport function clearSchemaCache(): void {\n\tschemaCache.clear();\n}\n\n/**\n * Validate data against a collection's schema\n */\nexport function validateContent(\n\tcollection: CollectionWithFields,\n\tdata: unknown,\n): { success: true; data: unknown } | { success: false; errors: z.ZodError } {\n\tconst schema = getCachedSchema(collection);\n\n\tconst result = schema.safeParse(data);\n\n\tif (result.success) {\n\t\treturn { success: true, data: result.data };\n\t}\n\n\treturn { success: false, errors: result.error };\n}\n\n/**\n * Generate TypeScript interface from field definitions\n * Used by CLI `emdash types` to generate types\n */\nexport function generateTypeScript(\n\tcollection: CollectionWithFields,\n\tinterfaceName: string = getInterfaceName(collection),\n): string {\n\tconst lines: string[] = [];\n\n\tlines.push(`export interface ${interfaceName} {`);\n\tlines.push(` id: string;`);\n\tlines.push(` slug: string | null;`);\n\tlines.push(` status: string;`);\n\n\tfor (const field of collection.fields) {\n\t\tconst tsType = fieldTypeToTypeScript(field);\n\t\tconst optional = field.required ? \"\" : \"?\";\n\t\tlines.push(` ${field.slug}${optional}: ${tsType};`);\n\t}\n\n\tlines.push(` createdAt: Date;`);\n\tlines.push(` updatedAt: Date;`);\n\tlines.push(` publishedAt: Date | null;`);\n\t// Bylines are eagerly loaded by getEmDashCollection/getEmDashEntry\n\tlines.push(` bylines?: ContentBylineCredit[];`);\n\t// Taxonomy terms are eagerly loaded by getEmDashCollection/getEmDashEntry,\n\t// keyed by taxonomy name (e.g. data.terms?.tag)\n\tlines.push(` terms?: Record<string, TaxonomyTerm[]>;`);\n\tlines.push(`}`);\n\n\treturn lines.join(\"\\n\");\n}\n\n/**\n * Generate a complete types file with module augmentation\n * This produces emdash-env.d.ts content that provides typed query functions\n */\nexport function generateTypesFile(collections: CollectionWithFields[]): string {\n\tconst lines: string[] = [];\n\n\t// Header\n\tlines.push(`// Generated by EmDash on dev server start`);\n\tlines.push(`// Do not edit manually`);\n\tlines.push(``);\n\tlines.push(`/// <reference types=\"emdash/locals\" />`);\n\tlines.push(``);\n\n\t// Check if we need PortableTextBlock import\n\tconst needsPortableText = collections.some((c) =>\n\t\tc.fields.some((f) => f.type === \"portableText\"),\n\t);\n\n\t// Build imports - ContentBylineCredit and TaxonomyTerm are always needed\n\t// for the hydrated bylines/terms fields\n\tconst imports = [\"ContentBylineCredit\", \"TaxonomyTerm\"];\n\tif (needsPortableText) {\n\t\timports.push(\"PortableTextBlock\");\n\t}\n\tlines.push(`import type { ${imports.join(\", \")} } from \"emdash\";`);\n\tlines.push(``);\n\n\t// Singularizing the slug can map two distinct slugs to the same name\n\t// (e.g. `book` and `books` both -> `Book`), so resolve collisions up front\n\t// to keep every interface identifier unique within the file.\n\tconst interfaceNames = uniqueInterfaceNames(collections);\n\n\t// Generate individual interfaces\n\tfor (const collection of collections) {\n\t\tlines.push(generateTypeScript(collection, interfaceNames.get(collection.slug)));\n\t\tlines.push(``);\n\t}\n\n\t// Generate the Collections interface for module augmentation\n\tlines.push(`declare module \"emdash\" {`);\n\tlines.push(` interface EmDashCollections {`);\n\tfor (const collection of collections) {\n\t\tlines.push(` ${collection.slug}: ${interfaceNames.get(collection.slug)};`);\n\t}\n\tlines.push(` }`);\n\tlines.push(`}`);\n\n\treturn lines.join(\"\\n\");\n}\n\n/**\n * Generate schema hash for cache invalidation\n */\nexport async function generateSchemaHash(collections: CollectionWithFields[]): Promise<string> {\n\tconst str = JSON.stringify(\n\t\tcollections.map((c) => ({\n\t\t\tslug: c.slug,\n\t\t\tfields: c.fields.map((f) => ({\n\t\t\t\tslug: f.slug,\n\t\t\t\ttype: f.type,\n\t\t\t\trequired: f.required,\n\t\t\t\tvalidation: f.validation,\n\t\t\t})),\n\t\t})),\n\t);\n\treturn hashString(str);\n}\n\n/**\n * Map field type to TypeScript type\n */\nfunction fieldTypeToTypeScript(field: Field): string {\n\tswitch (field.type) {\n\t\tcase \"string\":\n\t\tcase \"text\":\n\t\tcase \"slug\":\n\t\tcase \"url\":\n\t\tcase \"datetime\":\n\t\t\treturn \"string\";\n\n\t\tcase \"number\":\n\t\tcase \"integer\":\n\t\t\treturn \"number\";\n\n\t\tcase \"boolean\":\n\t\t\treturn \"boolean\";\n\n\t\tcase \"select\":\n\t\t\tconst options = field.validation?.options;\n\t\t\tif (options && options.length > 0) {\n\t\t\t\treturn options.map((o) => `\"${o}\"`).join(\" | \");\n\t\t\t}\n\t\t\treturn \"string\";\n\n\t\tcase \"multiSelect\":\n\t\t\tconst multiOptions = field.validation?.options;\n\t\t\tif (multiOptions && multiOptions.length > 0) {\n\t\t\t\treturn `(${multiOptions.map((o) => `\"${o}\"`).join(\" | \")})[]`;\n\t\t\t}\n\t\t\treturn \"string[]\";\n\n\t\tcase \"portableText\":\n\t\t\treturn \"PortableTextBlock[]\";\n\n\t\tcase \"image\":\n\t\t\treturn \"{ id: string; src?: string; alt?: string; width?: number; height?: number; provider?: string; previewUrl?: string; meta?: Record<string, unknown> }\";\n\n\t\tcase \"file\":\n\t\t\treturn \"{ id: string; src?: string; filename?: string; mimeType?: string; size?: number; provider?: string; meta?: Record<string, unknown> }\";\n\n\t\tcase \"reference\":\n\t\t\t// Could be enhanced to include the referenced collection type\n\t\t\treturn \"string\";\n\n\t\tcase \"json\":\n\t\t\treturn \"unknown\";\n\n\t\tdefault:\n\t\t\treturn \"unknown\";\n\t}\n}\n\n/**\n * Convert string to PascalCase (handles slugs, spaces, etc.)\n */\nfunction pascalCase(str: string): string {\n\treturn str\n\t\t.split(PASCAL_CASE_SPLIT_PATTERN)\n\t\t.filter(Boolean)\n\t\t.map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())\n\t\t.join(\"\");\n}\n\n/**\n * Naive singularization for slug-derived interface names. Handles the common\n * English plural endings; intentionally simple, not a full inflector.\n */\nfunction singularize(str: string): string {\n\tif (str.endsWith(\"ies\")) {\n\t\treturn str.slice(0, -3) + \"y\";\n\t}\n\tif (\n\t\tstr.endsWith(\"es\") &&\n\t\t(str.endsWith(\"sses\") || str.endsWith(\"xes\") || str.endsWith(\"ches\") || str.endsWith(\"shes\"))\n\t) {\n\t\treturn str.slice(0, -2);\n\t}\n\tif (str.endsWith(\"s\") && !str.endsWith(\"ss\")) {\n\t\treturn str.slice(0, -1);\n\t}\n\treturn str;\n}\n\n/**\n * Get the interface name for a collection.\n *\n * Derived from the slug, not the human label. Slugs are constrained to\n * `/^[a-z][a-z0-9_]*$/`, so PascalCasing one always yields a valid TS\n * identifier; labels are arbitrary and user-controlled (punctuation, spaces,\n * duplicates across collections), which produced syntactically invalid or\n * duplicate interface names. The slug is singularized first because the\n * interface describes a single entry, not the collection (`posts` -> `Post`).\n *\n * Singularization can map two distinct slugs onto the same name, so callers\n * generating more than one interface must dedupe -- see `uniqueInterfaceNames`.\n */\nfunction getInterfaceName(collection: CollectionWithFields): string {\n\treturn pascalCase(singularize(collection.slug));\n}\n\n/**\n * Resolve interface names for a set of collections, guaranteeing each is\n * unique within the file. Collisions (from singularization or PascalCasing\n * collapsing distinct slugs) get a numeric suffix in collection order, so the\n * generated `.d.ts` never declares two interfaces with the same identifier.\n *\n * The suffix is chosen against the set of names already emitted, not a\n * per-base counter, so a generated name can't collide with another slug's\n * base name (e.g. slugs `book`, `books`, `book2`: `books` -> `Book2` would\n * clash with `book2`, so it advances to `Book3`).\n */\nexport function uniqueInterfaceNames(collections: CollectionWithFields[]): Map<string, string> {\n\tconst used = new Set<string>();\n\tconst names = new Map<string, string>();\n\tfor (const collection of collections) {\n\t\tconst base = getInterfaceName(collection);\n\t\tlet name = base;\n\t\tlet suffix = 2;\n\t\twhile (used.has(name)) {\n\t\t\tname = `${base}${suffix}`;\n\t\t\tsuffix++;\n\t\t}\n\t\tused.add(name);\n\t\tnames.set(collection.slug, name);\n\t}\n\treturn names;\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "emdash",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.24.0",
|
|
4
4
|
"description": "Astro-native CMS with WordPress migration support",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.mjs",
|
|
@@ -230,11 +230,11 @@
|
|
|
230
230
|
"upng-js": "^2.1.0",
|
|
231
231
|
"zod": "^4.4.1",
|
|
232
232
|
"@atcute/client": "^5.0.0",
|
|
233
|
-
"@emdash-cms/
|
|
234
|
-
"@emdash-cms/gutenberg-to-portable-text": "0.
|
|
233
|
+
"@emdash-cms/admin": "0.24.0",
|
|
234
|
+
"@emdash-cms/gutenberg-to-portable-text": "0.24.0",
|
|
235
|
+
"@emdash-cms/auth": "0.24.0",
|
|
235
236
|
"@emdash-cms/plugin-types": "0.1.0",
|
|
236
|
-
"@emdash-cms/registry-client": "0.3.2"
|
|
237
|
-
"@emdash-cms/admin": "0.22.0"
|
|
237
|
+
"@emdash-cms/registry-client": "0.3.2"
|
|
238
238
|
},
|
|
239
239
|
"optionalDependencies": {
|
|
240
240
|
"@libsql/kysely-libsql": "^0.4.0",
|
|
@@ -267,7 +267,7 @@
|
|
|
267
267
|
"vite": "^6.0.0",
|
|
268
268
|
"vitest": "^4.1.5",
|
|
269
269
|
"zod-openapi": "^5.4.6",
|
|
270
|
-
"@emdash-cms/blocks": "0.
|
|
270
|
+
"@emdash-cms/blocks": "0.24.0"
|
|
271
271
|
},
|
|
272
272
|
"repository": {
|
|
273
273
|
"type": "git",
|
|
@@ -290,6 +290,7 @@
|
|
|
290
290
|
"check": "publint && attw --pack --ignore-rules=cjs-resolves-to-esm --ignore-rules=no-resolution --ignore-rules=internal-resolution-error",
|
|
291
291
|
"test": "vitest",
|
|
292
292
|
"test:smoke": "vitest run --config vitest.smoke.config.ts",
|
|
293
|
-
"test:integration": "vitest run --config vitest.integration.config.ts"
|
|
293
|
+
"test:integration": "vitest run --config vitest.integration.config.ts",
|
|
294
|
+
"test:repro": "vitest run --config vitest.repro.config.ts"
|
|
294
295
|
}
|
|
295
296
|
}
|
|
@@ -95,12 +95,21 @@ export interface TaxonomyDefTranslationsResponse {
|
|
|
95
95
|
* Build tree structure from flat terms
|
|
96
96
|
*/
|
|
97
97
|
function buildTree(flatTerms: TermWithCount[]): TermWithCount[] {
|
|
98
|
-
|
|
98
|
+
// `parentId` holds the parent's translation_group, so resolve links by group.
|
|
99
|
+
// Key by (locale, group): a child's parent lives in the same locale, and an
|
|
100
|
+
// unfiltered list mixes locales whose translated siblings share a group —
|
|
101
|
+
// keying by group alone would collide and misattach children across locales.
|
|
102
|
+
const byLocaleGroup = new Map<string, TermWithCount>();
|
|
99
103
|
const roots: TermWithCount[] = [];
|
|
100
|
-
for (const term of flatTerms) map.set(term.id, term);
|
|
101
104
|
for (const term of flatTerms) {
|
|
102
|
-
|
|
103
|
-
|
|
105
|
+
byLocaleGroup.set(`${term.locale}::${term.translationGroup ?? term.id}`, term);
|
|
106
|
+
}
|
|
107
|
+
for (const term of flatTerms) {
|
|
108
|
+
const parent = term.parentId
|
|
109
|
+
? byLocaleGroup.get(`${term.locale}::${term.parentId}`)
|
|
110
|
+
: undefined;
|
|
111
|
+
if (parent) {
|
|
112
|
+
parent.children.push(term);
|
|
104
113
|
} else {
|
|
105
114
|
roots.push(term);
|
|
106
115
|
}
|
|
@@ -411,24 +420,20 @@ export async function handleTermList(
|
|
|
411
420
|
* - `parentId === null` -> caller intends to detach; no-op here.
|
|
412
421
|
* - parent must exist (FK exists -> term row not soft-deleted).
|
|
413
422
|
* - parent must live in the same taxonomy.
|
|
414
|
-
* -
|
|
415
|
-
*
|
|
423
|
+
* - reject a parent in the term's own translation_group (self-parent),
|
|
424
|
+
* including the create path: a translation inherits its source's group, so
|
|
425
|
+
* `selfGroup` carries that prospective group when `termId` is absent.
|
|
426
|
+
* - on update, walk up the parent chain to detect cycles.
|
|
416
427
|
*/
|
|
417
428
|
async function validateParentTerm(
|
|
418
429
|
repo: TaxonomyRepository,
|
|
419
430
|
taxonomyName: string,
|
|
420
431
|
termId: string | undefined,
|
|
421
432
|
parentId: string | null | undefined,
|
|
433
|
+
selfGroup?: string | null,
|
|
422
434
|
): Promise<{ code: "VALIDATION_ERROR"; message: string } | null> {
|
|
423
435
|
if (parentId === undefined || parentId === null) return null;
|
|
424
436
|
|
|
425
|
-
if (termId !== undefined && parentId === termId) {
|
|
426
|
-
return {
|
|
427
|
-
code: "VALIDATION_ERROR",
|
|
428
|
-
message: "A term cannot be its own parent",
|
|
429
|
-
};
|
|
430
|
-
}
|
|
431
|
-
|
|
432
437
|
const parent = await repo.findById(parentId);
|
|
433
438
|
if (!parent) {
|
|
434
439
|
return {
|
|
@@ -443,6 +448,22 @@ async function validateParentTerm(
|
|
|
443
448
|
};
|
|
444
449
|
}
|
|
445
450
|
|
|
451
|
+
// Parentage keys off translation_group (what `parent_id` persists), so the
|
|
452
|
+
// self-parent and cycle checks compare groups, not row ids — picking a
|
|
453
|
+
// sibling translation of the term as its parent is still self-parenting.
|
|
454
|
+
const parentGroup = parent.translationGroup ?? parent.id;
|
|
455
|
+
let termGroup: string | null = selfGroup ?? null;
|
|
456
|
+
if (termId !== undefined) {
|
|
457
|
+
const term = await repo.findById(termId);
|
|
458
|
+
termGroup = term ? (term.translationGroup ?? term.id) : termId;
|
|
459
|
+
}
|
|
460
|
+
if (termGroup !== null && parentGroup === termGroup) {
|
|
461
|
+
return {
|
|
462
|
+
code: "VALIDATION_ERROR",
|
|
463
|
+
message: "A term cannot be its own parent",
|
|
464
|
+
};
|
|
465
|
+
}
|
|
466
|
+
|
|
446
467
|
// Walk up the parent chain. Two checks fold into one walk:
|
|
447
468
|
// - Cycle detection (only on update — a non-existent term-being-
|
|
448
469
|
// created can't be its own ancestor): if the walk revisits termId
|
|
@@ -454,11 +475,13 @@ async function validateParentTerm(
|
|
|
454
475
|
// The depth-exceeded error fires only when we hit the limit AND there
|
|
455
476
|
// was still chain to walk — a legitimate chain of exactly MAX_DEPTH
|
|
456
477
|
// ancestors exits with `cursor === null` and is accepted.
|
|
478
|
+
// `parent_id` stores a translation_group, which always equals the anchor
|
|
479
|
+
// row's id, so findById(cursor) still resolves each ancestor.
|
|
457
480
|
const MAX_DEPTH = 100;
|
|
458
481
|
let cursor: string | null = parent.parentId;
|
|
459
482
|
let steps = 0;
|
|
460
483
|
while (cursor !== null && steps < MAX_DEPTH) {
|
|
461
|
-
if (
|
|
484
|
+
if (termGroup !== null && cursor === termGroup) {
|
|
462
485
|
return {
|
|
463
486
|
code: "VALIDATION_ERROR",
|
|
464
487
|
message: "Cycle detected: cannot make a descendant the parent",
|
|
@@ -504,7 +527,7 @@ export async function handleTermCreate(
|
|
|
504
527
|
const repo = new TaxonomyRepository(db);
|
|
505
528
|
|
|
506
529
|
// Coerce empty-string parentId to undefined (treat as "no parent").
|
|
507
|
-
|
|
530
|
+
const parentId =
|
|
508
531
|
input.parentId === "" || input.parentId === undefined ? undefined : input.parentId;
|
|
509
532
|
|
|
510
533
|
// Conflict check is scoped to locale (per-locale slugs are unique).
|
|
@@ -521,27 +544,29 @@ export async function handleTermCreate(
|
|
|
521
544
|
};
|
|
522
545
|
}
|
|
523
546
|
|
|
524
|
-
//
|
|
525
|
-
//
|
|
526
|
-
|
|
547
|
+
// No locale re-pointing needed: `repo.create` persists the parent's
|
|
548
|
+
// translation_group in `parent_id`, so a child stays nested under the
|
|
549
|
+
// parent in every locale automatically — including parents translated
|
|
550
|
+
// after the child was created.
|
|
551
|
+
|
|
552
|
+
// A translation inherits its source's translation_group; pass that
|
|
553
|
+
// prospective group so validateParentTerm can reject a parent in the same
|
|
554
|
+
// group (cross-locale self-parent) even though the term doesn't exist yet.
|
|
555
|
+
let selfGroup: string | null = null;
|
|
556
|
+
if (input.translationOf) {
|
|
527
557
|
const source = await repo.findById(input.translationOf);
|
|
528
|
-
|
|
529
|
-
const sourceParent = await repo.findById(parentId);
|
|
530
|
-
if (sourceParent?.translationGroup) {
|
|
531
|
-
const translatedParent = await db
|
|
532
|
-
.selectFrom("taxonomies")
|
|
533
|
-
.select("id")
|
|
534
|
-
.where("translation_group", "=", sourceParent.translationGroup)
|
|
535
|
-
.where("locale", "=", input.locale)
|
|
536
|
-
.executeTakeFirst();
|
|
537
|
-
if (translatedParent) parentId = translatedParent.id;
|
|
538
|
-
}
|
|
539
|
-
}
|
|
558
|
+
selfGroup = source ? (source.translationGroup ?? source.id) : null;
|
|
540
559
|
}
|
|
541
560
|
|
|
542
561
|
// Validate parentId: must exist AND belong to the same taxonomy.
|
|
543
562
|
// (Cycle check is N/A on create — the term doesn't exist yet.)
|
|
544
|
-
const parentError = await validateParentTerm(
|
|
563
|
+
const parentError = await validateParentTerm(
|
|
564
|
+
repo,
|
|
565
|
+
taxonomyName,
|
|
566
|
+
undefined,
|
|
567
|
+
parentId,
|
|
568
|
+
selfGroup,
|
|
569
|
+
);
|
|
545
570
|
if (parentError) {
|
|
546
571
|
return { success: false, error: parentError };
|
|
547
572
|
}
|
|
@@ -606,7 +631,9 @@ export async function handleTermGet(
|
|
|
606
631
|
}
|
|
607
632
|
|
|
608
633
|
const count = await repo.countEntriesWithTerm(term.id);
|
|
609
|
-
|
|
634
|
+
// Children share this term's translation_group as their parent_id; scope
|
|
635
|
+
// to the term's own locale so the response stays within one locale's tree.
|
|
636
|
+
const children = await repo.findChildren(term.id, term.locale);
|
|
610
637
|
|
|
611
638
|
return {
|
|
612
639
|
success: true,
|
|
@@ -791,6 +818,9 @@ export async function handleTermDelete(
|
|
|
791
818
|
};
|
|
792
819
|
}
|
|
793
820
|
|
|
821
|
+
// Block deletion if the term's group still parents any child in any
|
|
822
|
+
// locale — children store this group in parent_id, so removing the term
|
|
823
|
+
// would orphan them (or null their parent_id via the self-FK).
|
|
794
824
|
const children = await repo.findChildren(term.id);
|
|
795
825
|
if (children.length > 0) {
|
|
796
826
|
return {
|
|
@@ -19,6 +19,14 @@ export const bylineSummarySchema = z
|
|
|
19
19
|
*/
|
|
20
20
|
avatarStorageKey: z.string().nullish(),
|
|
21
21
|
avatarAlt: z.string().nullish(),
|
|
22
|
+
/**
|
|
23
|
+
* Avatar media LQIP placeholder (blurhash + dominant colour, migration
|
|
24
|
+
* 024), from the same media join. Lets clients render a placeholder
|
|
25
|
+
* while the avatar loads. Null under the same conditions as
|
|
26
|
+
* `avatarStorageKey`.
|
|
27
|
+
*/
|
|
28
|
+
avatarBlurhash: z.string().nullish(),
|
|
29
|
+
avatarDominantColor: z.string().nullish(),
|
|
22
30
|
websiteUrl: z.string().nullable(),
|
|
23
31
|
userId: z.string().nullable(),
|
|
24
32
|
isGuest: z.boolean(),
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
|
|
3
|
+
const objectIs =
|
|
4
|
+
typeof Object.is === "function"
|
|
5
|
+
? Object.is
|
|
6
|
+
: (x, y) => (x === y && (x !== 0 || 1 / x === 1 / y)) || (x !== x && y !== y);
|
|
7
|
+
|
|
8
|
+
export function useSyncExternalStoreWithSelector(
|
|
9
|
+
subscribe,
|
|
10
|
+
getSnapshot,
|
|
11
|
+
getServerSnapshot,
|
|
12
|
+
selector,
|
|
13
|
+
isEqual,
|
|
14
|
+
) {
|
|
15
|
+
const instRef = React.useRef(null);
|
|
16
|
+
if (instRef.current === null) {
|
|
17
|
+
instRef.current = { hasValue: false, value: null };
|
|
18
|
+
}
|
|
19
|
+
const inst = instRef.current;
|
|
20
|
+
|
|
21
|
+
const [getSelection, getServerSelection] = React.useMemo(() => {
|
|
22
|
+
let hasMemo = false;
|
|
23
|
+
let memoizedSnapshot;
|
|
24
|
+
let memoizedSelection;
|
|
25
|
+
|
|
26
|
+
const memoizedSelector = (nextSnapshot) => {
|
|
27
|
+
if (!hasMemo) {
|
|
28
|
+
hasMemo = true;
|
|
29
|
+
memoizedSnapshot = nextSnapshot;
|
|
30
|
+
const nextSelection = selector(nextSnapshot);
|
|
31
|
+
if (isEqual !== undefined && inst.hasValue) {
|
|
32
|
+
const currentSelection = inst.value;
|
|
33
|
+
if (isEqual(currentSelection, nextSelection)) {
|
|
34
|
+
memoizedSelection = currentSelection;
|
|
35
|
+
return currentSelection;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
memoizedSelection = nextSelection;
|
|
39
|
+
return nextSelection;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const previousSelection = memoizedSelection;
|
|
43
|
+
if (objectIs(memoizedSnapshot, nextSnapshot)) {
|
|
44
|
+
return previousSelection;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const nextSelection = selector(nextSnapshot);
|
|
48
|
+
if (isEqual !== undefined && isEqual(previousSelection, nextSelection)) {
|
|
49
|
+
memoizedSnapshot = nextSnapshot;
|
|
50
|
+
return previousSelection;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
memoizedSnapshot = nextSnapshot;
|
|
54
|
+
memoizedSelection = nextSelection;
|
|
55
|
+
return nextSelection;
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
return [
|
|
59
|
+
() => memoizedSelector(getSnapshot()),
|
|
60
|
+
getServerSnapshot === undefined ? undefined : () => memoizedSelector(getServerSnapshot()),
|
|
61
|
+
];
|
|
62
|
+
}, [getSnapshot, getServerSnapshot, selector, isEqual]);
|
|
63
|
+
|
|
64
|
+
const value = React.useSyncExternalStore(subscribe, getSelection, getServerSelection);
|
|
65
|
+
React.useEffect(() => {
|
|
66
|
+
inst.hasValue = true;
|
|
67
|
+
inst.value = value;
|
|
68
|
+
}, [inst, value]);
|
|
69
|
+
React.useDebugValue(value);
|
|
70
|
+
return value;
|
|
71
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { useSyncExternalStore } from "react";
|
|
@@ -96,14 +96,21 @@ export function generateDialectModule(opts: {
|
|
|
96
96
|
`export const createDialect = undefined;`,
|
|
97
97
|
`export const dialectType = "sqlite";`,
|
|
98
98
|
`export const createRequestScopedDb = (_opts) => null;`,
|
|
99
|
+
`export const createCoalescingDialect = undefined;`,
|
|
99
100
|
].join("\n");
|
|
100
101
|
}
|
|
101
102
|
const type = opts.type ?? "sqlite";
|
|
102
103
|
|
|
104
|
+
// Namespace access (not a named re-export) so backends that don't export
|
|
105
|
+
// createCoalescingDialect yield `undefined` rather than a build error.
|
|
106
|
+
const coalescingReExport = `import * as _dialectModule from "${entrypoint}";
|
|
107
|
+
export const createCoalescingDialect = _dialectModule.createCoalescingDialect;`;
|
|
108
|
+
|
|
103
109
|
if (supportsRequestScope) {
|
|
104
110
|
return `
|
|
105
111
|
import { createDialect as _createDialect } from "${entrypoint}";
|
|
106
112
|
export { createRequestScopedDb } from "${entrypoint}";
|
|
113
|
+
${coalescingReExport}
|
|
107
114
|
export const createDialect = _createDialect;
|
|
108
115
|
export const dialectType = ${JSON.stringify(type)};
|
|
109
116
|
`;
|
|
@@ -111,6 +118,7 @@ export const dialectType = ${JSON.stringify(type)};
|
|
|
111
118
|
|
|
112
119
|
return `
|
|
113
120
|
import { createDialect as _createDialect } from "${entrypoint}";
|
|
121
|
+
${coalescingReExport}
|
|
114
122
|
export const createDialect = _createDialect;
|
|
115
123
|
export const dialectType = ${JSON.stringify(type)};
|
|
116
124
|
export const createRequestScopedDb = (_opts) => null;
|
|
@@ -145,6 +145,15 @@ function resolveAdminSource(projectRoot: string): string | undefined {
|
|
|
145
145
|
return undefined;
|
|
146
146
|
}
|
|
147
147
|
|
|
148
|
+
function resolveIntegrationShim(fileName: string): string {
|
|
149
|
+
const currentDir = dirname(fileURLToPath(import.meta.url));
|
|
150
|
+
const sourceShimPath = resolve(currentDir, "shims", fileName);
|
|
151
|
+
if (existsSync(sourceShimPath)) {
|
|
152
|
+
return sourceShimPath;
|
|
153
|
+
}
|
|
154
|
+
return resolve(currentDir, "..", "..", "src", "astro", "integration", "shims", fileName);
|
|
155
|
+
}
|
|
156
|
+
|
|
148
157
|
export interface VitePluginOptions {
|
|
149
158
|
/** Serializable config (database, storage, auth descriptors) */
|
|
150
159
|
serializableConfig: Record<string, unknown>;
|
|
@@ -159,7 +168,10 @@ export interface VitePluginOptions {
|
|
|
159
168
|
/**
|
|
160
169
|
* Creates the EmDash virtual modules Vite plugin.
|
|
161
170
|
*/
|
|
162
|
-
export function createVirtualModulesPlugin(
|
|
171
|
+
export function createVirtualModulesPlugin(
|
|
172
|
+
options: VitePluginOptions,
|
|
173
|
+
astroCommand: "dev" | "build" | "preview" | "sync",
|
|
174
|
+
): Plugin {
|
|
163
175
|
const { serializableConfig, resolvedConfig, pluginDescriptors, astroConfig } = options;
|
|
164
176
|
|
|
165
177
|
let viteCommand: "build" | "serve" | undefined;
|
|
@@ -294,8 +306,16 @@ export function createVirtualModulesPlugin(options: VitePluginOptions): Plugin {
|
|
|
294
306
|
// Generate scheduler module — a NodeCronScheduler factory on
|
|
295
307
|
// long-lived runtimes, or null under the Cloudflare adapter where
|
|
296
308
|
// a Cron Trigger drives scheduled work instead.
|
|
309
|
+
//
|
|
310
|
+
// Decide from Astro's command, not Vite's config.command: the
|
|
311
|
+
// Cloudflare adapter builds the worker bundle via a nested Vite
|
|
312
|
+
// *build* pass even during `astro dev`, so viteCommand reports
|
|
313
|
+
// "build" and would wrongly suppress the in-process timer (#1635).
|
|
314
|
+
// Astro's command stays "dev", which is the only case that should
|
|
315
|
+
// fall through to a NodeCronScheduler.
|
|
297
316
|
if (id === RESOLVED_VIRTUAL_SCHEDULER_ID) {
|
|
298
|
-
|
|
317
|
+
const schedulerCommand = astroCommand === "dev" ? "serve" : "build";
|
|
318
|
+
return generateSchedulerModule(astroConfig.adapter?.name, schedulerCommand);
|
|
299
319
|
}
|
|
300
320
|
},
|
|
301
321
|
};
|
|
@@ -307,6 +327,10 @@ export function createVirtualModulesPlugin(options: VitePluginOptions): Plugin {
|
|
|
307
327
|
* On Cloudflare, the adapter handles its own externalization — setting
|
|
308
328
|
* ssr.external there conflicts with @cloudflare/vite-plugin's validation.
|
|
309
329
|
*/
|
|
330
|
+
// Matches the admin stylesheet import with or without a trailing query (e.g.
|
|
331
|
+
// `?url`), so both forms resolve to dist rather than the source alias.
|
|
332
|
+
const ADMIN_STYLES_ALIAS = /^@emdash-cms\/admin\/styles\.css/;
|
|
333
|
+
|
|
310
334
|
const NODE_NATIVE_EXTERNALS = [
|
|
311
335
|
"better-sqlite3",
|
|
312
336
|
"bindings",
|
|
@@ -336,6 +360,10 @@ export function createViteConfig(
|
|
|
336
360
|
|
|
337
361
|
const adminSourcePath = isDev ? resolveAdminSource(projectRoot) : undefined;
|
|
338
362
|
const useSource = adminSourcePath !== undefined;
|
|
363
|
+
const useSyncExternalStoreShimPath = resolveIntegrationShim("use-sync-external-store.js");
|
|
364
|
+
const useSyncExternalStoreWithSelectorShimPath = resolveIntegrationShim(
|
|
365
|
+
"use-sync-external-store-with-selector.js",
|
|
366
|
+
);
|
|
339
367
|
|
|
340
368
|
return {
|
|
341
369
|
// Astro SSR routes resolve version.ts from source (not tsdown dist),
|
|
@@ -353,8 +381,12 @@ export function createViteConfig(
|
|
|
353
381
|
// The styles.css alias must come before the package alias, otherwise
|
|
354
382
|
// Vite's prefix matching on "@emdash-cms/admin" would resolve
|
|
355
383
|
// "@emdash-cms/admin/styles.css" through the source directory.
|
|
384
|
+
// Regex (not string) so the `?url` variant — admin.astro imports the
|
|
385
|
+
// stylesheet as `?url` to keep it out of the page CSS graph — also
|
|
386
|
+
// resolves to dist; a string `find` only matches on a `/` or end
|
|
387
|
+
// boundary, so `styles.css?url` would slip through to the source alias.
|
|
356
388
|
alias: [
|
|
357
|
-
{ find:
|
|
389
|
+
{ find: ADMIN_STYLES_ALIAS, replacement: resolve(adminDistPath, "styles.css") },
|
|
358
390
|
{ find: "@emdash-cms/admin", replacement: useSource ? adminSourcePath : adminDistPath },
|
|
359
391
|
// `use-sync-external-store/shim` is a React <18 polyfill that ships
|
|
360
392
|
// only as CJS. It's pulled in transitively by `@tiptap/react`. With
|
|
@@ -362,19 +394,34 @@ export function createViteConfig(
|
|
|
362
394
|
// dep scanner can't reach it for pre-bundling — so the browser is
|
|
363
395
|
// served raw `module.exports` and hydration fails with
|
|
364
396
|
// `SyntaxError: ... does not provide an export named
|
|
365
|
-
// 'useSyncExternalStore'`. Redirect both shim entry points to
|
|
366
|
-
//
|
|
367
|
-
//
|
|
397
|
+
// 'useSyncExternalStore'`. Redirect both shim entry points to a
|
|
398
|
+
// tiny ESM shim file that re-exports React's built-in hook, and
|
|
399
|
+
// redirect the selector entry points to an ESM wrapper around that
|
|
400
|
+
// hook. The absolute file paths are required because Vite/Rolldown
|
|
401
|
+
// dependency optimization applies aliases without EmDash's virtual
|
|
402
|
+
// module plugin. This also avoids the package main entry's React
|
|
403
|
+
// 18+ dev warning.
|
|
404
|
+
{
|
|
405
|
+
find: "use-sync-external-store/shim/with-selector.js",
|
|
406
|
+
replacement: useSyncExternalStoreWithSelectorShimPath,
|
|
407
|
+
},
|
|
408
|
+
{
|
|
409
|
+
find: "use-sync-external-store/shim/with-selector",
|
|
410
|
+
replacement: useSyncExternalStoreWithSelectorShimPath,
|
|
411
|
+
},
|
|
368
412
|
{
|
|
369
413
|
find: "use-sync-external-store/shim/index.js",
|
|
370
|
-
replacement:
|
|
414
|
+
replacement: useSyncExternalStoreShimPath,
|
|
415
|
+
},
|
|
416
|
+
{
|
|
417
|
+
find: "use-sync-external-store/shim",
|
|
418
|
+
replacement: useSyncExternalStoreShimPath,
|
|
371
419
|
},
|
|
372
|
-
{ find: "use-sync-external-store/shim", replacement: "use-sync-external-store" },
|
|
373
420
|
],
|
|
374
421
|
},
|
|
375
422
|
// eslint-disable-next-line typescript/no-unsafe-type-assertion -- Monorepo has both vite 6 (docs) and vite 7 (core). tsgo resolves correctly.
|
|
376
423
|
plugins: [
|
|
377
|
-
createVirtualModulesPlugin(options),
|
|
424
|
+
createVirtualModulesPlugin(options, command),
|
|
378
425
|
// In dev mode with source alias, compile Lingui macros on the fly
|
|
379
426
|
// and redirect locale .mjs imports to dist/.
|
|
380
427
|
// In production, macros are pre-compiled by tsdown in the admin package.
|
|
@@ -30,10 +30,15 @@ async function injectToolbar(response: Response, toolbarHtml: string): Promise<R
|
|
|
30
30
|
if (!html.includes("</body>")) return new Response(html, response);
|
|
31
31
|
|
|
32
32
|
const injected = html.replace("</body>", `${toolbarHtml}</body>`);
|
|
33
|
-
|
|
33
|
+
const result = new Response(injected, {
|
|
34
34
|
status: response.status,
|
|
35
35
|
headers: response.headers,
|
|
36
36
|
});
|
|
37
|
+
// Toolbar-injected HTML is session-specific (its presence reveals an active
|
|
38
|
+
// editor session); it must never be stored in a shared CDN cache and served
|
|
39
|
+
// to anonymous visitors. Mirrors the preview branch's guard (#1398).
|
|
40
|
+
result.headers.set("Cache-Control", "private, no-store");
|
|
41
|
+
return result;
|
|
37
42
|
}
|
|
38
43
|
|
|
39
44
|
export const onRequest = defineMiddleware(async (context, next) => {
|