emdash 0.17.0 → 0.17.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api/route-utils.mjs +11 -11
- package/dist/api/schemas/index.d.mts +1 -1
- package/dist/{api-Dmz40c2V.mjs → api-B7GATEYo.mjs} +12 -12
- package/dist/{api-Dmz40c2V.mjs.map → api-B7GATEYo.mjs.map} +1 -1
- package/dist/{apply-CgamLmed.mjs → apply-BrVqULFe.mjs} +16 -16
- package/dist/{apply-CgamLmed.mjs.map → apply-BrVqULFe.mjs.map} +1 -1
- package/dist/astro/index.d.mts +2 -2
- package/dist/astro/index.mjs +10 -1
- package/dist/astro/index.mjs.map +1 -1
- package/dist/astro/middleware/auth.d.mts +2 -2
- package/dist/astro/middleware/auth.mjs +2 -2
- package/dist/astro/middleware/redirect.mjs +5 -5
- package/dist/astro/middleware.d.mts.map +1 -1
- package/dist/astro/middleware.mjs +65 -49
- package/dist/astro/middleware.mjs.map +1 -1
- package/dist/astro/routes/api/admin/allowed-domains/_domain_.mjs +3 -3
- package/dist/astro/routes/api/admin/allowed-domains/index.mjs +3 -3
- package/dist/astro/routes/api/admin/api-tokens/_id_.mjs +2 -2
- package/dist/astro/routes/api/admin/api-tokens/index.mjs +3 -3
- package/dist/astro/routes/api/admin/byline-fields/_slug_/usage.mjs +3 -3
- package/dist/astro/routes/api/admin/byline-fields/_slug_.mjs +4 -4
- package/dist/astro/routes/api/admin/byline-fields/index.mjs +4 -4
- package/dist/astro/routes/api/admin/byline-fields/reorder.mjs +4 -4
- package/dist/astro/routes/api/admin/bylines/_id_/index.mjs +9 -9
- package/dist/astro/routes/api/admin/bylines/_id_/translations.mjs +9 -9
- package/dist/astro/routes/api/admin/bylines/index.mjs +9 -9
- package/dist/astro/routes/api/admin/comments/_id_/status.mjs +7 -7
- package/dist/astro/routes/api/admin/comments/_id_.mjs +5 -5
- package/dist/astro/routes/api/admin/comments/bulk.mjs +6 -6
- package/dist/astro/routes/api/admin/comments/counts.mjs +5 -5
- package/dist/astro/routes/api/admin/comments/index.mjs +6 -6
- 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 +3 -3
- package/dist/astro/routes/api/admin/oauth-clients/index.mjs +3 -3
- package/dist/astro/routes/api/admin/plugins/_id_/disable.mjs +26 -26
- package/dist/astro/routes/api/admin/plugins/_id_/enable.mjs +26 -26
- package/dist/astro/routes/api/admin/plugins/_id_/index.mjs +26 -26
- package/dist/astro/routes/api/admin/plugins/_id_/uninstall.mjs +26 -26
- package/dist/astro/routes/api/admin/plugins/_id_/update.mjs +26 -26
- package/dist/astro/routes/api/admin/plugins/index.mjs +26 -26
- package/dist/astro/routes/api/admin/plugins/marketplace/_id_/icon.mjs +3 -3
- package/dist/astro/routes/api/admin/plugins/marketplace/_id_/index.mjs +26 -26
- package/dist/astro/routes/api/admin/plugins/marketplace/_id_/install.mjs +26 -26
- package/dist/astro/routes/api/admin/plugins/marketplace/index.mjs +26 -26
- package/dist/astro/routes/api/admin/plugins/registry/_id_/uninstall.mjs +26 -26
- package/dist/astro/routes/api/admin/plugins/registry/_id_/update.mjs +27 -27
- package/dist/astro/routes/api/admin/plugins/registry/artifact.mjs +26 -26
- package/dist/astro/routes/api/admin/plugins/registry/install.mjs +27 -27
- package/dist/astro/routes/api/admin/plugins/updates.mjs +26 -26
- package/dist/astro/routes/api/admin/themes/marketplace/_id_/index.mjs +26 -26
- package/dist/astro/routes/api/admin/themes/marketplace/_id_/thumbnail.mjs +3 -3
- package/dist/astro/routes/api/admin/themes/marketplace/index.mjs +26 -26
- 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 +3 -3
- package/dist/astro/routes/api/admin/users/_id_/send-recovery.mjs +2 -2
- package/dist/astro/routes/api/admin/users/index.mjs +3 -3
- package/dist/astro/routes/api/auth/dev-bypass.mjs +4 -4
- package/dist/astro/routes/api/auth/invite/accept.mjs +2 -2
- package/dist/astro/routes/api/auth/invite/complete.mjs +3 -3
- package/dist/astro/routes/api/auth/invite/index.mjs +3 -3
- package/dist/astro/routes/api/auth/invite/register-options.mjs +3 -3
- package/dist/astro/routes/api/auth/logout.mjs +2 -2
- package/dist/astro/routes/api/auth/magic-link/send.mjs +4 -4
- package/dist/astro/routes/api/auth/magic-link/verify.mjs +2 -2
- package/dist/astro/routes/api/auth/me.mjs +4 -4
- package/dist/astro/routes/api/auth/passkey/_id_.mjs +3 -3
- package/dist/astro/routes/api/auth/passkey/index.mjs +2 -2
- package/dist/astro/routes/api/auth/passkey/options.mjs +4 -4
- package/dist/astro/routes/api/auth/passkey/register/options.mjs +3 -3
- package/dist/astro/routes/api/auth/passkey/register/verify.mjs +3 -3
- package/dist/astro/routes/api/auth/passkey/verify.mjs +3 -3
- package/dist/astro/routes/api/auth/signup/complete.mjs +3 -3
- package/dist/astro/routes/api/auth/signup/request.mjs +4 -4
- package/dist/astro/routes/api/auth/signup/verify.mjs +2 -2
- package/dist/astro/routes/api/comments/_collection_/_contentId_/index.mjs +6 -6
- 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 +4 -4
- package/dist/astro/routes/api/content/_collection_/_id_/publish.mjs +4 -4
- 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 +4 -4
- package/dist/astro/routes/api/content/_collection_/_id_/terms/_taxonomy_.mjs +9 -9
- 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 +4 -4
- package/dist/astro/routes/api/content/_collection_/index.mjs +4 -4
- package/dist/astro/routes/api/content/_collection_/trash.mjs +4 -4
- package/dist/astro/routes/api/dashboard.mjs +7 -7
- package/dist/astro/routes/api/dev/emails.mjs +2 -2
- package/dist/astro/routes/api/import/probe.mjs +4 -4
- package/dist/astro/routes/api/import/wordpress/analyze.mjs +3 -3
- package/dist/astro/routes/api/import/wordpress/execute.d.mts +2 -2
- package/dist/astro/routes/api/import/wordpress/execute.mjs +8 -8
- package/dist/astro/routes/api/import/wordpress/media.mjs +4 -4
- package/dist/astro/routes/api/import/wordpress/prepare.mjs +6 -6
- package/dist/astro/routes/api/import/wordpress/rewrite-urls.mjs +5 -5
- package/dist/astro/routes/api/import/wordpress-plugin/analyze.mjs +4 -4
- package/dist/astro/routes/api/import/wordpress-plugin/execute.mjs +6 -6
- package/dist/astro/routes/api/manifest.mjs +3 -3
- package/dist/astro/routes/api/mcp.mjs +26 -26
- package/dist/astro/routes/api/media/_id_/confirm.mjs +4 -4
- package/dist/astro/routes/api/media/_id_.mjs +4 -4
- 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 +4 -4
- package/dist/astro/routes/api/media.mjs +5 -5
- package/dist/astro/routes/api/menus/_name_/items/_id_.mjs +5 -5
- package/dist/astro/routes/api/menus/_name_/items.mjs +5 -5
- package/dist/astro/routes/api/menus/_name_/reorder.mjs +5 -5
- package/dist/astro/routes/api/menus/_name_/translations.mjs +5 -5
- package/dist/astro/routes/api/menus/_name_.mjs +5 -5
- package/dist/astro/routes/api/menus/index.mjs +5 -5
- package/dist/astro/routes/api/oauth/device/authorize.mjs +3 -3
- package/dist/astro/routes/api/oauth/device/code.mjs +4 -4
- package/dist/astro/routes/api/oauth/device/token.mjs +4 -4
- package/dist/astro/routes/api/oauth/register.mjs +2 -2
- package/dist/astro/routes/api/oauth/token/refresh.mjs +3 -3
- package/dist/astro/routes/api/oauth/token/revoke.mjs +3 -3
- package/dist/astro/routes/api/oauth/token.mjs +2 -2
- package/dist/astro/routes/api/openapi.json.mjs +2 -2
- 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 +3 -3
- package/dist/astro/routes/api/revisions/_revisionId_/restore.mjs +3 -3
- package/dist/astro/routes/api/schema/collections/_slug_/fields/_fieldSlug_.mjs +26 -26
- package/dist/astro/routes/api/schema/collections/_slug_/fields/index.mjs +26 -26
- package/dist/astro/routes/api/schema/collections/_slug_/fields/reorder.mjs +26 -26
- package/dist/astro/routes/api/schema/collections/_slug_/index.mjs +26 -26
- package/dist/astro/routes/api/schema/collections/index.mjs +26 -26
- package/dist/astro/routes/api/schema/index.mjs +7 -7
- package/dist/astro/routes/api/schema/orphans/_slug_.mjs +26 -26
- package/dist/astro/routes/api/schema/orphans/index.mjs +26 -26
- package/dist/astro/routes/api/search/enable.mjs +8 -8
- package/dist/astro/routes/api/search/index.mjs +7 -7
- package/dist/astro/routes/api/search/rebuild.mjs +8 -8
- package/dist/astro/routes/api/search/stats.mjs +7 -7
- package/dist/astro/routes/api/search/suggest.mjs +7 -7
- package/dist/astro/routes/api/sections/_slug_.mjs +7 -7
- package/dist/astro/routes/api/sections/index.mjs +7 -7
- package/dist/astro/routes/api/settings/email.mjs +4 -4
- package/dist/astro/routes/api/settings.mjs +9 -9
- package/dist/astro/routes/api/setup/admin-verify.mjs +3 -3
- package/dist/astro/routes/api/setup/admin.mjs +3 -3
- package/dist/astro/routes/api/setup/dev-bypass.mjs +16 -16
- package/dist/astro/routes/api/setup/dev-reset.mjs +2 -2
- package/dist/astro/routes/api/setup/index.mjs +17 -17
- package/dist/astro/routes/api/setup/status.mjs +3 -3
- package/dist/astro/routes/api/snapshot.mjs +3 -3
- package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_/translations.mjs +9 -9
- package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_.mjs +9 -9
- package/dist/astro/routes/api/taxonomies/_name_/terms/index.mjs +9 -9
- package/dist/astro/routes/api/taxonomies/index.mjs +9 -9
- package/dist/astro/routes/api/themes/preview.mjs +3 -3
- package/dist/astro/routes/api/typegen.mjs +5 -5
- package/dist/astro/routes/api/widget-areas/_name_/reorder.mjs +4 -4
- package/dist/astro/routes/api/widget-areas/_name_/widgets/_id_.mjs +7 -7
- package/dist/astro/routes/api/widget-areas/_name_/widgets.mjs +7 -7
- package/dist/astro/routes/api/widget-areas/_name_.mjs +6 -6
- package/dist/astro/routes/api/widget-areas/index.mjs +7 -7
- package/dist/astro/routes/api/widget-components.mjs +2 -2
- package/dist/astro/routes/robots.txt.mjs +5 -5
- package/dist/astro/routes/sitemap-_collection_.xml.mjs +5 -5
- package/dist/astro/routes/sitemap.xml.mjs +5 -5
- package/dist/astro/types.d.mts +2 -2
- package/dist/{authorize-_wWM_44T.mjs → authorize-CLTmOUyx.mjs} +2 -2
- package/dist/{authorize-_wWM_44T.mjs.map → authorize-CLTmOUyx.mjs.map} +1 -1
- package/dist/{byline-BrIVWLm-.mjs → byline-CAhk4FrG.mjs} +4 -4
- package/dist/{byline-BrIVWLm-.mjs.map → byline-CAhk4FrG.mjs.map} +1 -1
- package/dist/{byline-fields-BNy7Ng1U.d.mts → byline-fields-CR5hGLMw.d.mts} +28 -28
- package/dist/{byline-fields-BNy7Ng1U.d.mts.map → byline-fields-CR5hGLMw.d.mts.map} +1 -1
- package/dist/{bylines-sqExMElV.mjs → bylines-CbrD7STW.mjs} +3 -3
- package/dist/{bylines-sqExMElV.mjs.map → bylines-CbrD7STW.mjs.map} +1 -1
- package/dist/{bylines-C_POWmGT.mjs → bylines-DCczH3AV.mjs} +4 -4
- package/dist/{bylines-C_POWmGT.mjs.map → bylines-DCczH3AV.mjs.map} +1 -1
- package/dist/{cache-wsDkA8ru.mjs → cache-DIHHyPkt.mjs} +2 -2
- package/dist/{cache-wsDkA8ru.mjs.map → cache-DIHHyPkt.mjs.map} +1 -1
- package/dist/{chunks-BAYkM-CF.mjs → chunks-DnnHlRG3.mjs} +2 -2
- package/dist/{chunks-BAYkM-CF.mjs.map → chunks-DnnHlRG3.mjs.map} +1 -1
- package/dist/cli/index.mjs +125 -23
- package/dist/cli/index.mjs.map +1 -1
- package/dist/{comment-Cd29aktf.mjs → comment-DkAfGX9E.mjs} +2 -2
- package/dist/{comment-Cd29aktf.mjs.map → comment-DkAfGX9E.mjs.map} +1 -1
- package/dist/{comments-B7ufhkxN.mjs → comments-DLFnXs7J.mjs} +3 -3
- package/dist/{comments-B7ufhkxN.mjs.map → comments-DLFnXs7J.mjs.map} +1 -1
- package/dist/{content-BbqKo3Kc.mjs → content-C7aJ7keg.mjs} +3 -3
- package/dist/{content-BbqKo3Kc.mjs.map → content-C7aJ7keg.mjs.map} +1 -1
- package/dist/{context-BsF1rhoI.mjs → context-Ca0HkaIh.mjs} +8 -8
- package/dist/{context-BsF1rhoI.mjs.map → context-Ca0HkaIh.mjs.map} +1 -1
- package/dist/{dashboard-BwIX9r-X.mjs → dashboard-BrfLIsX1.mjs} +4 -4
- package/dist/{dashboard-BwIX9r-X.mjs.map → dashboard-BrfLIsX1.mjs.map} +1 -1
- package/dist/db/index.mjs +2 -2
- package/dist/{dialect-helpers-BKCvISIQ.mjs → dialect-helpers-DRI5pyY3.mjs} +3 -3
- package/dist/dialect-helpers-DRI5pyY3.mjs.map +1 -0
- package/dist/{error-npZWBSb7.mjs → error-Bk9s3Ism.mjs} +2 -2
- package/dist/{error-npZWBSb7.mjs.map → error-Bk9s3Ism.mjs.map} +1 -1
- package/dist/{fts-manager-DmUAk-kQ.mjs → fts-manager-XpDfbIKo.mjs} +3 -3
- package/dist/{fts-manager-DmUAk-kQ.mjs.map → fts-manager-XpDfbIKo.mjs.map} +1 -1
- package/dist/{index-CjKdMZ3U.d.mts → index-C8ciqSMJ.d.mts} +4 -4
- package/dist/{index-CjKdMZ3U.d.mts.map → index-C8ciqSMJ.d.mts.map} +1 -1
- package/dist/index.d.mts +2 -2
- package/dist/index.mjs +35 -35
- package/dist/{load-DsoLq7ex.mjs → load-CF5oETkh.mjs} +2 -2
- package/dist/{load-DsoLq7ex.mjs.map → load-CF5oETkh.mjs.map} +1 -1
- package/dist/{loader-CJ6lWO0d.mjs → loader-BxyvbrZP.mjs} +4 -4
- package/dist/{loader-CJ6lWO0d.mjs.map → loader-BxyvbrZP.mjs.map} +1 -1
- package/dist/media/local-runtime.d.mts +2 -2
- package/dist/media/local-runtime.mjs +5 -5
- package/dist/{media-jk_HzzOl.mjs → media-Cyz5BhSN.mjs} +2 -2
- package/dist/{media-jk_HzzOl.mjs.map → media-Cyz5BhSN.mjs.map} +1 -1
- package/dist/{menus-CyMO6GBx.mjs → menus-CIdZ_Q6U.mjs} +4 -4
- package/dist/{menus-CyMO6GBx.mjs.map → menus-CIdZ_Q6U.mjs.map} +1 -1
- package/dist/{menus-B-5-3aon.mjs → menus-PFp8FDuO.mjs} +2 -2
- package/dist/{menus-B-5-3aon.mjs.map → menus-PFp8FDuO.mjs.map} +1 -1
- package/dist/{parse-4zO5Y2DL.mjs → parse-B-K21lvm.mjs} +2 -2
- package/dist/{parse-4zO5Y2DL.mjs.map → parse-B-K21lvm.mjs.map} +1 -1
- package/dist/plugin-utils.d.mts +2 -2
- package/dist/plugins/adapt-sandbox-entry.d.mts +2 -2
- package/dist/{query-CuvjwhrE.mjs → query-Cc649nDl.mjs} +17 -16
- package/dist/query-Cc649nDl.mjs.map +1 -0
- package/dist/{rate-limit-D6VQqBk_.mjs → rate-limit-BI1OdpQH.mjs} +2 -2
- package/dist/{rate-limit-D6VQqBk_.mjs.map → rate-limit-BI1OdpQH.mjs.map} +1 -1
- package/dist/{redirect-BZUJltlj.mjs → redirect-C-FeA4j9.mjs} +3 -3
- package/dist/{redirect-BZUJltlj.mjs.map → redirect-C-FeA4j9.mjs.map} +1 -1
- package/dist/{redirects-DnYuqsEf.mjs → redirects-C1UgU9E0.mjs} +3 -3
- package/dist/{redirects-DnYuqsEf.mjs.map → redirects-C1UgU9E0.mjs.map} +1 -1
- package/dist/{registry-Dn6gsx3L.mjs → registry-C-T_PWgp.mjs} +5 -5
- package/dist/{registry-Dn6gsx3L.mjs.map → registry-C-T_PWgp.mjs.map} +1 -1
- package/dist/{runner-eAgyIkeg.mjs → runner-BiuUfx-V.mjs} +4 -4
- package/dist/runner-BiuUfx-V.mjs.map +1 -0
- package/dist/runtime.d.mts +2 -2
- package/dist/runtime.mjs +3 -3
- package/dist/{schema--mYZX4D7.mjs → schema-BpCJh2lU.mjs} +4 -4
- package/dist/{schema--mYZX4D7.mjs.map → schema-BpCJh2lU.mjs.map} +1 -1
- package/dist/{search-C6U_NvZI.mjs → search-BrF7k0Ho.mjs} +4 -4
- package/dist/{search-C6U_NvZI.mjs.map → search-BrF7k0Ho.mjs.map} +1 -1
- package/dist/{sections-Ba-rJLKb.mjs → sections-8DEa-dWt.mjs} +3 -3
- package/dist/{sections-Ba-rJLKb.mjs.map → sections-8DEa-dWt.mjs.map} +1 -1
- package/dist/seed/index.mjs +14 -14
- package/dist/seo/index.mjs +1 -0
- package/dist/seo/index.mjs.map +1 -1
- package/dist/{seo-BTzb5ksq.mjs → seo-CKr7pLfA.mjs} +2 -2
- package/dist/{seo-BTzb5ksq.mjs.map → seo-CKr7pLfA.mjs.map} +1 -1
- package/dist/{service-Cn-kIfZn.mjs → service-9P2cdyR_.mjs} +2 -2
- package/dist/{service-Cn-kIfZn.mjs.map → service-9P2cdyR_.mjs.map} +1 -1
- package/dist/{settings-C65OSm41.mjs → settings-DYVzINdn.mjs} +3 -3
- package/dist/{settings-C65OSm41.mjs.map → settings-DYVzINdn.mjs.map} +1 -1
- package/dist/{settings-ChlQbwU0.mjs → settings-Jro4YcUb.mjs} +3 -3
- package/dist/{settings-ChlQbwU0.mjs.map → settings-Jro4YcUb.mjs.map} +1 -1
- package/dist/{taxonomies-D72gTOg_.mjs → taxonomies-C0bVme_m.mjs} +4 -4
- package/dist/{taxonomies-D72gTOg_.mjs.map → taxonomies-C0bVme_m.mjs.map} +1 -1
- package/dist/{taxonomies-CgpzAU6F.mjs → taxonomies-CGD6y79Q.mjs} +5 -5
- package/dist/{taxonomies-CgpzAU6F.mjs.map → taxonomies-CGD6y79Q.mjs.map} +1 -1
- package/dist/{taxonomy-BBK-UAEo.mjs → taxonomy-Db5xwphL.mjs} +3 -3
- package/dist/{taxonomy-BBK-UAEo.mjs.map → taxonomy-Db5xwphL.mjs.map} +1 -1
- package/dist/{types-SF1DwGf2.mjs → types-CfyYQ7eY.mjs} +2 -2
- package/dist/{types-SF1DwGf2.mjs.map → types-CfyYQ7eY.mjs.map} +1 -1
- package/dist/{user-X4rtyO4Y.mjs → user-tLdHUEXV.mjs} +2 -2
- package/dist/{user-X4rtyO4Y.mjs.map → user-tLdHUEXV.mjs.map} +1 -1
- package/dist/{validate-DactmcJG.mjs → validate-DWmnRg6E.mjs} +2 -2
- package/dist/{validate-DactmcJG.mjs.map → validate-DWmnRg6E.mjs.map} +1 -1
- package/dist/{validation-BYA4i85b.mjs → validation-BQ_TP-On.mjs} +6 -6
- package/dist/{validation-BYA4i85b.mjs.map → validation-BQ_TP-On.mjs.map} +1 -1
- package/dist/version-CgcnMvqS.mjs +7 -0
- package/dist/{version-FGcv0ooe.mjs.map → version-CgcnMvqS.mjs.map} +1 -1
- package/dist/{widgets-DG-1jxnz.mjs → widgets-DzlINGI6.mjs} +2 -2
- package/dist/{widgets-DG-1jxnz.mjs.map → widgets-DzlINGI6.mjs.map} +1 -1
- package/dist/{zod-generator-BNAObjSt.mjs → zod-generator-MMm56Prt.mjs} +2 -2
- package/dist/{zod-generator-BNAObjSt.mjs.map → zod-generator-MMm56Prt.mjs.map} +1 -1
- package/package.json +6 -6
- package/src/astro/integration/vite-config.ts +16 -0
- package/src/astro/middleware.ts +34 -8
- package/src/cli/commands/export-seed.ts +174 -12
- package/src/database/dialect-helpers.ts +8 -2
- package/src/database/migrations/019_i18n.ts +2 -2
- package/src/query.ts +7 -7
- package/src/seo/index.ts +10 -1
- package/dist/dialect-helpers-BKCvISIQ.mjs.map +0 -1
- package/dist/query-CuvjwhrE.mjs.map +0 -1
- package/dist/runner-eAgyIkeg.mjs.map +0 -1
- package/dist/version-FGcv0ooe.mjs +0 -7
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "emdash",
|
|
3
|
-
"version": "0.17.
|
|
3
|
+
"version": "0.17.2",
|
|
4
4
|
"description": "Astro-native CMS with WordPress migration support",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.mjs",
|
|
@@ -218,11 +218,11 @@
|
|
|
218
218
|
"upng-js": "^2.1.0",
|
|
219
219
|
"zod": "^4.4.1",
|
|
220
220
|
"@atcute/client": "^4.2.1",
|
|
221
|
-
"@emdash-cms/admin": "0.17.
|
|
222
|
-
"@emdash-cms/
|
|
221
|
+
"@emdash-cms/admin": "0.17.2",
|
|
222
|
+
"@emdash-cms/auth": "0.17.2",
|
|
223
|
+
"@emdash-cms/gutenberg-to-portable-text": "0.17.2",
|
|
223
224
|
"@emdash-cms/plugin-types": "0.0.1",
|
|
224
|
-
"@emdash-cms/registry-client": "0.3.1"
|
|
225
|
-
"@emdash-cms/auth": "0.17.0"
|
|
225
|
+
"@emdash-cms/registry-client": "0.3.1"
|
|
226
226
|
},
|
|
227
227
|
"optionalDependencies": {
|
|
228
228
|
"@libsql/kysely-libsql": "^0.4.0",
|
|
@@ -255,7 +255,7 @@
|
|
|
255
255
|
"vite": "^6.0.0",
|
|
256
256
|
"vitest": "^4.1.5",
|
|
257
257
|
"zod-openapi": "^5.4.6",
|
|
258
|
-
"@emdash-cms/blocks": "0.17.
|
|
258
|
+
"@emdash-cms/blocks": "0.17.2"
|
|
259
259
|
},
|
|
260
260
|
"repository": {
|
|
261
261
|
"type": "git",
|
|
@@ -395,10 +395,25 @@ export function createViteConfig(
|
|
|
395
395
|
"emdash > @emdash-cms/auth > @oslojs/crypto/ecdsa",
|
|
396
396
|
"emdash > @emdash-cms/auth > @oslojs/crypto/sha2",
|
|
397
397
|
"emdash > @emdash-cms/auth > @oslojs/webauthn",
|
|
398
|
+
// Auth deps imported only on auth/login/callback routes, so
|
|
399
|
+
// the initial page scan misses them. Pre-bundle to avoid a
|
|
400
|
+
// re-optimize + reload cascade on first authenticated request.
|
|
401
|
+
"emdash > @oslojs/crypto/hmac",
|
|
402
|
+
"emdash > @oslojs/crypto/subtle",
|
|
403
|
+
"emdash > @oslojs/crypto/rsa",
|
|
404
|
+
"emdash > arctic",
|
|
398
405
|
// MCP SDK — server/index.js statically imports ajv (CJS-only).
|
|
399
406
|
// Pre-bundling converts CJS to ESM so workerd can load it.
|
|
400
407
|
"emdash > @modelcontextprotocol/sdk > ajv",
|
|
401
408
|
"emdash > @modelcontextprotocol/sdk > ajv-formats",
|
|
409
|
+
// MCP server entrypoints — only imported on the MCP route, so
|
|
410
|
+
// also missed by the initial scan.
|
|
411
|
+
"emdash > @modelcontextprotocol/sdk/server/mcp.js",
|
|
412
|
+
"emdash > @modelcontextprotocol/sdk/server/webStandardStreamableHttp.js",
|
|
413
|
+
// Admin shell SSR deps, reached only when the admin route is
|
|
414
|
+
// first rendered.
|
|
415
|
+
"emdash > @emdash-cms/admin > @lingui/react",
|
|
416
|
+
"emdash > @emdash-cms/admin > @cloudflare/kumo/primitives",
|
|
402
417
|
// React (commonly used, may be hoisted)
|
|
403
418
|
"react",
|
|
404
419
|
"react/jsx-dev-runtime",
|
|
@@ -415,6 +430,7 @@ export function createViteConfig(
|
|
|
415
430
|
"astro/content/runtime",
|
|
416
431
|
"astro/assets/utils/inferRemoteSize.js",
|
|
417
432
|
"astro/assets/fonts/runtime.js",
|
|
433
|
+
"astro/assets/services/noop",
|
|
418
434
|
"@astrojs/cloudflare/image-service",
|
|
419
435
|
],
|
|
420
436
|
},
|
package/src/astro/middleware.ts
CHANGED
|
@@ -50,6 +50,7 @@ import {
|
|
|
50
50
|
type RequestMetrics,
|
|
51
51
|
runWithContext,
|
|
52
52
|
} from "../request-context.js";
|
|
53
|
+
import { isMissingTableError } from "../utils/db-errors.js";
|
|
53
54
|
import type { EmDashConfig } from "./integration/runtime.js";
|
|
54
55
|
import { createPublicPluginApiRouteHandler } from "./public-plugin-api-routes.js";
|
|
55
56
|
import type { EmDashHandlers } from "./types.js";
|
|
@@ -69,8 +70,24 @@ let i18nInitialized = false;
|
|
|
69
70
|
* would query an empty database and crash. Once verified (or once the runtime
|
|
70
71
|
* has initialized via an admin/API request), this stays true for the worker's
|
|
71
72
|
* lifetime.
|
|
73
|
+
*
|
|
74
|
+
* Stored on globalThis behind a Symbol key so the flag is a true singleton
|
|
75
|
+
* even when the bundler duplicates this module across SSR chunks (same
|
|
76
|
+
* pattern as request-cache.ts). A plain module-scoped `let` becomes multiple
|
|
77
|
+
* independent variables, which would make the setup probe re-run far more
|
|
78
|
+
* often than intended — and every re-run is another chance for a transient
|
|
79
|
+
* DB error to be misread as "fresh install" and bounce visitors to setup.
|
|
72
80
|
*/
|
|
73
|
-
|
|
81
|
+
const SETUP_VERIFIED_KEY = Symbol.for("emdash:setup-verified");
|
|
82
|
+
const setupFlagStore = globalThis as Record<symbol, unknown>;
|
|
83
|
+
|
|
84
|
+
function isSetupVerified(): boolean {
|
|
85
|
+
return setupFlagStore[SETUP_VERIFIED_KEY] === true;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function markSetupVerified(): void {
|
|
89
|
+
setupFlagStore[SETUP_VERIFIED_KEY] = true;
|
|
90
|
+
}
|
|
74
91
|
|
|
75
92
|
/**
|
|
76
93
|
* Get EmDash configuration from virtual module
|
|
@@ -338,7 +355,7 @@ export const onRequest = defineMiddleware(async (context, next) => {
|
|
|
338
355
|
// Do a one-time lightweight probe using the same getDb() instance the
|
|
339
356
|
// page will use: if the migrations table doesn't exist, no migrations
|
|
340
357
|
// have ever run -- redirect to the setup wizard.
|
|
341
|
-
if (!
|
|
358
|
+
if (!isSetupVerified()) {
|
|
342
359
|
const t0 = performance.now();
|
|
343
360
|
try {
|
|
344
361
|
const { getDb } = await import("../loader.js");
|
|
@@ -348,10 +365,19 @@ export const onRequest = defineMiddleware(async (context, next) => {
|
|
|
348
365
|
.selectAll()
|
|
349
366
|
.limit(1)
|
|
350
367
|
.execute();
|
|
351
|
-
|
|
352
|
-
} catch {
|
|
353
|
-
//
|
|
354
|
-
|
|
368
|
+
markSetupVerified();
|
|
369
|
+
} catch (error) {
|
|
370
|
+
// Only a genuinely-missing migrations table means a fresh,
|
|
371
|
+
// un-set-up database — redirect to the setup wizard.
|
|
372
|
+
if (isMissingTableError(error)) {
|
|
373
|
+
return context.redirect("/_emdash/admin/setup");
|
|
374
|
+
}
|
|
375
|
+
// Any other failure (transient D1/replica error, timeout, cold-start
|
|
376
|
+
// race, locked SQLite) must NOT be read as "fresh install" — doing so
|
|
377
|
+
// bounces real visitors on a set-up site to /_emdash/admin/setup.
|
|
378
|
+
// Leave the flag unset so a later request can re-verify, and fall
|
|
379
|
+
// through to render the page normally.
|
|
380
|
+
console.error("Setup probe failed (non-fatal):", error);
|
|
355
381
|
}
|
|
356
382
|
timings.push({ name: "setup", dur: performance.now() - t0, desc: "Setup probe" });
|
|
357
383
|
}
|
|
@@ -368,7 +394,7 @@ export const onRequest = defineMiddleware(async (context, next) => {
|
|
|
368
394
|
const t0 = performance.now();
|
|
369
395
|
try {
|
|
370
396
|
const runtime = await getRuntime(config, initSubTimings);
|
|
371
|
-
|
|
397
|
+
markSetupVerified();
|
|
372
398
|
const handlePublicPluginApiRoute = createPublicPluginApiRouteHandler(runtime);
|
|
373
399
|
// eslint-disable-next-line typescript/no-unsafe-type-assertion -- partial object; getPageRuntime() only checks for the page-contribution methods
|
|
374
400
|
locals.emdash = {
|
|
@@ -448,7 +474,7 @@ export const onRequest = defineMiddleware(async (context, next) => {
|
|
|
448
474
|
for (const sub of initSubTimings) timings.push(sub);
|
|
449
475
|
|
|
450
476
|
// Runtime init runs migrations, so the DB is guaranteed set up
|
|
451
|
-
|
|
477
|
+
markSetupVerified();
|
|
452
478
|
|
|
453
479
|
// The manifest is no longer pre-loaded here. It's admin-only
|
|
454
480
|
// content that public/anonymous requests never read, and
|
|
@@ -9,14 +9,17 @@ import { resolve } from "node:path";
|
|
|
9
9
|
import { defineCommand } from "citty";
|
|
10
10
|
import consola from "consola";
|
|
11
11
|
import type { Kysely } from "kysely";
|
|
12
|
+
import { sql } from "kysely";
|
|
12
13
|
|
|
13
14
|
import { createDatabase } from "../../database/connection.js";
|
|
14
15
|
import { runMigrations } from "../../database/migrations/runner.js";
|
|
16
|
+
import { BylineRepository } from "../../database/repositories/byline.js";
|
|
15
17
|
import { ContentRepository } from "../../database/repositories/content.js";
|
|
16
18
|
import { MediaRepository } from "../../database/repositories/media.js";
|
|
17
19
|
import { OptionsRepository } from "../../database/repositories/options.js";
|
|
18
20
|
import { TaxonomyRepository } from "../../database/repositories/taxonomy.js";
|
|
19
21
|
import type { Database } from "../../database/types.js";
|
|
22
|
+
import { validateIdentifier } from "../../database/validate.js";
|
|
20
23
|
import { isI18nEnabled } from "../../i18n/config.js";
|
|
21
24
|
import { SchemaRegistry } from "../../schema/registry.js";
|
|
22
25
|
import type { FieldType } from "../../schema/types.js";
|
|
@@ -31,7 +34,10 @@ import type {
|
|
|
31
34
|
SeedWidgetArea,
|
|
32
35
|
SeedWidget,
|
|
33
36
|
SeedContentEntry,
|
|
37
|
+
SeedByline,
|
|
38
|
+
SeedBylineCredit,
|
|
34
39
|
} from "../../seed/types.js";
|
|
40
|
+
import { isMissingTableError } from "../../utils/db-errors.js";
|
|
35
41
|
import { slugify } from "../../utils/slugify.js";
|
|
36
42
|
|
|
37
43
|
const SETTINGS_PREFIX = "site:";
|
|
@@ -118,16 +124,29 @@ export async function exportSeed(db: Kysely<Database>, withContent?: string): Pr
|
|
|
118
124
|
// 2. Export collections and fields
|
|
119
125
|
seed.collections = await exportCollections(db);
|
|
120
126
|
|
|
127
|
+
// Decide locale-awareness from the data. The runtime sets the i18n config via
|
|
128
|
+
// middleware, but the CLI never does, so `isI18nEnabled()` is always false
|
|
129
|
+
// under `emdash export-seed` (#1330). Detecting multiple locales in the data
|
|
130
|
+
// keeps the export locale-aware without the runtime flag.
|
|
131
|
+
const i18nEnabled = await detectI18nEnabled(db, seed.collections);
|
|
132
|
+
|
|
121
133
|
// 3. Export taxonomy definitions and terms
|
|
122
|
-
seed.taxonomies = await exportTaxonomies(db);
|
|
134
|
+
seed.taxonomies = await exportTaxonomies(db, i18nEnabled);
|
|
123
135
|
|
|
124
136
|
// 4. Export menus
|
|
125
|
-
seed.menus = await exportMenus(db);
|
|
137
|
+
seed.menus = await exportMenus(db, i18nEnabled);
|
|
126
138
|
|
|
127
139
|
// 5. Export widget areas
|
|
128
140
|
seed.widgetAreas = await exportWidgetAreas(db);
|
|
129
141
|
|
|
130
|
-
// 6. Export
|
|
142
|
+
// 6. Export byline profiles. The returned map (translation_group -> seed-local
|
|
143
|
+
// id) lets content credits below reference the same ids the root list emits.
|
|
144
|
+
const { bylines, groupToSeedId } = await exportBylines(db);
|
|
145
|
+
if (bylines.length > 0) {
|
|
146
|
+
seed.bylines = bylines;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// 7. Export content (if requested)
|
|
131
150
|
if (withContent !== undefined) {
|
|
132
151
|
const collections =
|
|
133
152
|
withContent === "" || withContent === "true"
|
|
@@ -137,12 +156,112 @@ export async function exportSeed(db: Kysely<Database>, withContent?: string): Pr
|
|
|
137
156
|
.map((s) => s.trim())
|
|
138
157
|
.filter(Boolean);
|
|
139
158
|
|
|
140
|
-
seed.content = await exportContent(
|
|
159
|
+
seed.content = await exportContent(
|
|
160
|
+
db,
|
|
161
|
+
seed.collections || [],
|
|
162
|
+
collections,
|
|
163
|
+
groupToSeedId,
|
|
164
|
+
i18nEnabled,
|
|
165
|
+
);
|
|
141
166
|
}
|
|
142
167
|
|
|
143
168
|
return seed;
|
|
144
169
|
}
|
|
145
170
|
|
|
171
|
+
/**
|
|
172
|
+
* Export byline profiles as root-level `bylines[]`.
|
|
173
|
+
*
|
|
174
|
+
* `SeedByline` has no locale axis, so locale siblings of the same byline
|
|
175
|
+
* (sharing a `translation_group`) collapse to a single profile. The returned
|
|
176
|
+
* `groupToSeedId` map keys on `translation_group` — the value stored in
|
|
177
|
+
* `_emdash_content_bylines.byline_id` — so content credits can resolve to the
|
|
178
|
+
* emitted seed id.
|
|
179
|
+
*/
|
|
180
|
+
async function exportBylines(
|
|
181
|
+
db: Kysely<Database>,
|
|
182
|
+
): Promise<{ bylines: SeedByline[]; groupToSeedId: Map<string, string> }> {
|
|
183
|
+
const bylineRepo = new BylineRepository(db);
|
|
184
|
+
const bylines: SeedByline[] = [];
|
|
185
|
+
const groupToSeedId = new Map<string, string>();
|
|
186
|
+
const usedSeedIds = new Set<string>();
|
|
187
|
+
|
|
188
|
+
let cursor: string | undefined;
|
|
189
|
+
do {
|
|
190
|
+
const result = await bylineRepo.findMany({ limit: 100, cursor });
|
|
191
|
+
for (const byline of result.items) {
|
|
192
|
+
const group = byline.translationGroup ?? byline.id;
|
|
193
|
+
// One seed entry per translation group; first row seen wins.
|
|
194
|
+
if (groupToSeedId.has(group)) continue;
|
|
195
|
+
|
|
196
|
+
let seedId = `byline:${byline.slug}`;
|
|
197
|
+
// Disambiguate the rare case of two distinct groups sharing a slug
|
|
198
|
+
// (slug is unique per-locale, not globally) so seed ids stay unique.
|
|
199
|
+
if (usedSeedIds.has(seedId)) seedId = `byline:${byline.slug}:${group}`;
|
|
200
|
+
usedSeedIds.add(seedId);
|
|
201
|
+
groupToSeedId.set(group, seedId);
|
|
202
|
+
|
|
203
|
+
bylines.push({
|
|
204
|
+
id: seedId,
|
|
205
|
+
slug: byline.slug,
|
|
206
|
+
displayName: byline.displayName,
|
|
207
|
+
bio: byline.bio || undefined,
|
|
208
|
+
websiteUrl: byline.websiteUrl || undefined,
|
|
209
|
+
isGuest: byline.isGuest || undefined,
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
cursor = result.nextCursor;
|
|
213
|
+
} while (cursor);
|
|
214
|
+
|
|
215
|
+
return { bylines, groupToSeedId };
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* Determine whether the export should emit locale-suffixed seed ids.
|
|
220
|
+
*
|
|
221
|
+
* The runtime initializes the i18n config in middleware, but the CLI never does,
|
|
222
|
+
* so `isI18nEnabled()` is always false under `emdash export-seed` (#1330). When
|
|
223
|
+
* the flag is unset, fall back to the data: a project is multi-locale when its
|
|
224
|
+
* i18n-aware tables hold rows in more than one distinct locale. `locale` is
|
|
225
|
+
* NOT NULL (defaulting to the site's default locale), so a per-row presence
|
|
226
|
+
* check is not enough — only the *count* of distinct locales distinguishes a
|
|
227
|
+
* genuinely single-locale project from a multi-locale one. This keeps
|
|
228
|
+
* single-locale exports on bare ids and gives multi-locale exports the
|
|
229
|
+
* per-locale suffix they need to avoid duplicate seed ids.
|
|
230
|
+
*/
|
|
231
|
+
async function detectI18nEnabled(
|
|
232
|
+
db: Kysely<Database>,
|
|
233
|
+
collections: SeedCollection[],
|
|
234
|
+
): Promise<boolean> {
|
|
235
|
+
if (isI18nEnabled()) return true;
|
|
236
|
+
|
|
237
|
+
const locales = new Set<string>();
|
|
238
|
+
const collectDistinctLocales = async (tableRef: ReturnType<typeof sql.ref>): Promise<boolean> => {
|
|
239
|
+
const result = await sql<{ locale: string | null }>`
|
|
240
|
+
SELECT DISTINCT locale FROM ${tableRef}
|
|
241
|
+
`.execute(db);
|
|
242
|
+
for (const row of result.rows) {
|
|
243
|
+
if (row.locale) locales.add(row.locale);
|
|
244
|
+
}
|
|
245
|
+
return locales.size > 1;
|
|
246
|
+
};
|
|
247
|
+
|
|
248
|
+
if (await collectDistinctLocales(sql.ref("_emdash_taxonomy_defs"))) return true;
|
|
249
|
+
if (await collectDistinctLocales(sql.ref("_emdash_menus"))) return true;
|
|
250
|
+
|
|
251
|
+
for (const collection of collections) {
|
|
252
|
+
validateIdentifier(collection.slug, "collection slug");
|
|
253
|
+
// On D1, deleteCollection is non-atomic, so a collection row can outlive
|
|
254
|
+
// its ec_* table. Skip missing tables rather than crashing the export.
|
|
255
|
+
try {
|
|
256
|
+
if (await collectDistinctLocales(sql.ref(`ec_${collection.slug}`))) return true;
|
|
257
|
+
} catch (error) {
|
|
258
|
+
if (!isMissingTableError(error)) throw error;
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
return false;
|
|
263
|
+
}
|
|
264
|
+
|
|
146
265
|
/**
|
|
147
266
|
* Export site settings
|
|
148
267
|
*/
|
|
@@ -212,9 +331,10 @@ async function exportCollections(db: Kysely<Database>): Promise<SeedCollection[]
|
|
|
212
331
|
/**
|
|
213
332
|
* Export taxonomy definitions and terms
|
|
214
333
|
*/
|
|
215
|
-
async function exportTaxonomies(
|
|
216
|
-
|
|
217
|
-
|
|
334
|
+
async function exportTaxonomies(
|
|
335
|
+
db: Kysely<Database>,
|
|
336
|
+
i18nEnabled: boolean,
|
|
337
|
+
): Promise<SeedTaxonomy[]> {
|
|
218
338
|
// Mirrors the content export pattern: one entry per (name, locale), stable
|
|
219
339
|
// seed-local id, translations linked via `translationOf` to the anchor's id.
|
|
220
340
|
const defs = await db
|
|
@@ -306,9 +426,7 @@ async function exportTaxonomies(db: Kysely<Database>): Promise<SeedTaxonomy[]> {
|
|
|
306
426
|
/**
|
|
307
427
|
* Export menus with their items
|
|
308
428
|
*/
|
|
309
|
-
async function exportMenus(db: Kysely<Database
|
|
310
|
-
const i18nEnabled = isI18nEnabled();
|
|
311
|
-
|
|
429
|
+
async function exportMenus(db: Kysely<Database>, i18nEnabled: boolean): Promise<SeedMenu[]> {
|
|
312
430
|
const menus = await db
|
|
313
431
|
.selectFrom("_emdash_menus")
|
|
314
432
|
.selectAll()
|
|
@@ -546,6 +664,8 @@ async function exportContent(
|
|
|
546
664
|
db: Kysely<Database>,
|
|
547
665
|
collections: SeedCollection[],
|
|
548
666
|
includeCollections: string[] | null,
|
|
667
|
+
bylineGroupToSeedId: Map<string, string>,
|
|
668
|
+
i18nEnabled: boolean,
|
|
549
669
|
): Promise<Record<string, SeedContentEntry[]>> {
|
|
550
670
|
const content: Record<string, SeedContentEntry[]> = {};
|
|
551
671
|
const contentRepo = new ContentRepository(db);
|
|
@@ -579,8 +699,6 @@ async function exportContent(
|
|
|
579
699
|
// Media table might not exist or be empty
|
|
580
700
|
}
|
|
581
701
|
|
|
582
|
-
const i18nEnabled = isI18nEnabled();
|
|
583
|
-
|
|
584
702
|
for (const collection of collections) {
|
|
585
703
|
// Skip if not in include list
|
|
586
704
|
if (includeCollections && !includeCollections.includes(collection.slug)) {
|
|
@@ -642,6 +760,16 @@ async function exportContent(
|
|
|
642
760
|
entry.taxonomies = taxonomies;
|
|
643
761
|
}
|
|
644
762
|
|
|
763
|
+
// Get byline credits. Read the junction directly: its `byline_id`
|
|
764
|
+
// stores the translation_group, which is exactly the key in
|
|
765
|
+
// `bylineGroupToSeedId`. This is locale-agnostic (one row per
|
|
766
|
+
// credit) and avoids the locale-sibling fan-out a hydrated read
|
|
767
|
+
// would produce.
|
|
768
|
+
const bylines = await getBylineCredits(db, collection.slug, item.id, bylineGroupToSeedId);
|
|
769
|
+
if (bylines.length > 0) {
|
|
770
|
+
entry.bylines = bylines;
|
|
771
|
+
}
|
|
772
|
+
|
|
645
773
|
entries.push(entry);
|
|
646
774
|
}
|
|
647
775
|
|
|
@@ -723,6 +851,40 @@ function processDataForExport(
|
|
|
723
851
|
return result;
|
|
724
852
|
}
|
|
725
853
|
|
|
854
|
+
/**
|
|
855
|
+
* Get ordered byline credits for a content entry as `SeedBylineCredit[]`.
|
|
856
|
+
*
|
|
857
|
+
* The `_emdash_content_bylines.byline_id` column stores the credited byline's
|
|
858
|
+
* `translation_group`, so it maps straight through `groupToSeedId`. Credits
|
|
859
|
+
* whose group wasn't emitted in the root `bylines[]` are skipped (defensive;
|
|
860
|
+
* shouldn't happen for a consistent DB).
|
|
861
|
+
*/
|
|
862
|
+
async function getBylineCredits(
|
|
863
|
+
db: Kysely<Database>,
|
|
864
|
+
collection: string,
|
|
865
|
+
entryId: string,
|
|
866
|
+
groupToSeedId: Map<string, string>,
|
|
867
|
+
): Promise<SeedBylineCredit[]> {
|
|
868
|
+
const rows = await db
|
|
869
|
+
.selectFrom("_emdash_content_bylines")
|
|
870
|
+
.select(["byline_id", "role_label"])
|
|
871
|
+
.where("collection_slug", "=", collection)
|
|
872
|
+
.where("content_id", "=", entryId)
|
|
873
|
+
.orderBy("sort_order", "asc")
|
|
874
|
+
.execute();
|
|
875
|
+
|
|
876
|
+
const credits: SeedBylineCredit[] = [];
|
|
877
|
+
for (const row of rows) {
|
|
878
|
+
const seedId = groupToSeedId.get(row.byline_id);
|
|
879
|
+
if (!seedId) continue;
|
|
880
|
+
const credit: SeedBylineCredit = { byline: seedId };
|
|
881
|
+
if (row.role_label) credit.roleLabel = row.role_label;
|
|
882
|
+
credits.push(credit);
|
|
883
|
+
}
|
|
884
|
+
|
|
885
|
+
return credits;
|
|
886
|
+
}
|
|
887
|
+
|
|
726
888
|
/**
|
|
727
889
|
* Get taxonomy term assignments for a content entry
|
|
728
890
|
*/
|
|
@@ -74,10 +74,12 @@ export function currentTimestampValue(db: Kysely<any>): RawBuilder<string> {
|
|
|
74
74
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- accepts any Kysely instance
|
|
75
75
|
export async function tableExists(db: Kysely<any>, tableName: string): Promise<boolean> {
|
|
76
76
|
if (isPostgres(db)) {
|
|
77
|
+
// Scope to the active schema (matches indexExists/columnExists below).
|
|
78
|
+
// Hardcoding 'public' breaks non-public-schema Postgres deployments.
|
|
77
79
|
const result = await sql<{ exists: boolean }>`
|
|
78
80
|
SELECT EXISTS(
|
|
79
81
|
SELECT 1 FROM information_schema.tables
|
|
80
|
-
WHERE table_schema =
|
|
82
|
+
WHERE table_schema = current_schema() AND table_name = ${tableName}
|
|
81
83
|
) as exists
|
|
82
84
|
`.execute(db);
|
|
83
85
|
return result.rows[0]?.exists === true;
|
|
@@ -146,9 +148,13 @@ export async function columnExists(
|
|
|
146
148
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- accepts any Kysely instance
|
|
147
149
|
export async function listTablesLike(db: Kysely<any>, pattern: string): Promise<string[]> {
|
|
148
150
|
if (isPostgres(db)) {
|
|
151
|
+
// Scope to the connection's active schema rather than hardcoding
|
|
152
|
+
// 'public'. A Postgres deployment using a non-public schema (per-tenant
|
|
153
|
+
// or shared-cluster setups), or per-test schemas, otherwise sees tables
|
|
154
|
+
// from the wrong schema — or none at all. Mirrors migration 038.
|
|
149
155
|
const result = await sql<{ table_name: string }>`
|
|
150
156
|
SELECT table_name FROM information_schema.tables
|
|
151
|
-
WHERE table_schema =
|
|
157
|
+
WHERE table_schema = current_schema() AND table_name LIKE ${pattern}
|
|
152
158
|
`.execute(db);
|
|
153
159
|
return result.rows.map((r) => r.table_name);
|
|
154
160
|
}
|
|
@@ -142,7 +142,7 @@ async function upPostgres(db: Kysely<unknown>): Promise<void> {
|
|
|
142
142
|
const hasLocale = await sql<{ exists: boolean }>`
|
|
143
143
|
SELECT EXISTS(
|
|
144
144
|
SELECT 1 FROM information_schema.columns
|
|
145
|
-
WHERE table_schema =
|
|
145
|
+
WHERE table_schema = current_schema() AND table_name = ${t} AND column_name = 'locale'
|
|
146
146
|
) as exists
|
|
147
147
|
`.execute(db);
|
|
148
148
|
if (hasLocale.rows[0]?.exists === true) continue;
|
|
@@ -189,7 +189,7 @@ async function upPostgres(db: Kysely<unknown>): Promise<void> {
|
|
|
189
189
|
const hasTranslatable = await sql<{ exists: boolean }>`
|
|
190
190
|
SELECT EXISTS(
|
|
191
191
|
SELECT 1 FROM information_schema.columns
|
|
192
|
-
WHERE table_schema =
|
|
192
|
+
WHERE table_schema = current_schema() AND table_name = '_emdash_fields' AND column_name = 'translatable'
|
|
193
193
|
) as exists
|
|
194
194
|
`.execute(db);
|
|
195
195
|
if (hasTranslatable.rows[0]?.exists !== true) {
|
package/src/query.ts
CHANGED
|
@@ -495,10 +495,11 @@ async function getEmDashCollectionUncached<T extends string, D = InferCollection
|
|
|
495
495
|
const resolvedLocale =
|
|
496
496
|
filter?.locale ?? ctx?.locale ?? (isI18nEnabled() ? i18nConfig!.defaultLocale : undefined);
|
|
497
497
|
|
|
498
|
+
const requestedLimit = filter?.limit;
|
|
498
499
|
const result = await getLiveCollection(COLLECTION_NAME, {
|
|
499
500
|
type,
|
|
500
501
|
status: filter?.status,
|
|
501
|
-
limit: filter?.limit,
|
|
502
|
+
limit: requestedLimit && requestedLimit > 0 ? requestedLimit + 1 : filter?.limit,
|
|
502
503
|
cursor: filter?.cursor,
|
|
503
504
|
where: filter?.where,
|
|
504
505
|
orderBy: filter?.orderBy,
|
|
@@ -506,18 +507,17 @@ async function getEmDashCollectionUncached<T extends string, D = InferCollection
|
|
|
506
507
|
});
|
|
507
508
|
|
|
508
509
|
const { entries, error, cacheHint } = result;
|
|
509
|
-
// nextCursor is returned by the emdash loader but not part of Astro's base
|
|
510
|
-
// LiveLoader return type. Extract it safely via property descriptor to avoid
|
|
511
|
-
// an unsafe type assertion on the `any`-typed result object.
|
|
512
|
-
const rawCursor = Object.getOwnPropertyDescriptor(result, "nextCursor")?.value;
|
|
513
|
-
const nextCursor: string | undefined = typeof rawCursor === "string" ? rawCursor : undefined;
|
|
514
510
|
|
|
515
511
|
if (error) {
|
|
516
512
|
return { entries: [], error, cacheHint: {} };
|
|
517
513
|
}
|
|
518
514
|
|
|
515
|
+
const hasMore = requestedLimit != null && requestedLimit > 0 && entries.length > requestedLimit;
|
|
516
|
+
const pageEntries = hasMore ? entries.slice(0, requestedLimit) : entries;
|
|
517
|
+
const nextCursor = hasMore ? encodeEntryCursor(pageEntries.at(-1), filter?.orderBy) : undefined;
|
|
518
|
+
|
|
519
519
|
const isEditMode = ctx?.editMode ?? false;
|
|
520
|
-
const entriesWithEdit =
|
|
520
|
+
const entriesWithEdit = pageEntries.map((entry: ContentEntry<D>) => {
|
|
521
521
|
const dbId = entryDatabaseId(entry);
|
|
522
522
|
if (isEditMode) {
|
|
523
523
|
tagEditableFields(entryData(entry), type, dbId);
|
package/src/seo/index.ts
CHANGED
|
@@ -170,7 +170,16 @@ function buildMediaUrl(imageRef: string, siteUrl?: string): string {
|
|
|
170
170
|
return imageRef;
|
|
171
171
|
}
|
|
172
172
|
|
|
173
|
-
//
|
|
173
|
+
// Root-relative path — the CMS SEO panel stores seo_image as
|
|
174
|
+
// "/_emdash/api/media/file/01KS....svg" (already includes the API
|
|
175
|
+
// prefix). Without this branch we'd re-prefix and produce
|
|
176
|
+
// "${siteUrl}/_emdash/api/media/file//_emdash/api/media/file/<id>"
|
|
177
|
+
// which 404s and breaks <meta property="og:image">.
|
|
178
|
+
if (imageRef.startsWith("/")) {
|
|
179
|
+
return siteUrl ? `${siteUrl.replace(TRAILING_SLASH_RE, "")}${imageRef}` : imageRef;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// Bare media_id — build the full media API path
|
|
174
183
|
const mediaPath = `/_emdash/api/media/file/${imageRef}`;
|
|
175
184
|
if (siteUrl) {
|
|
176
185
|
return `${siteUrl.replace(TRAILING_SLASH_RE, "")}${mediaPath}`;
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"dialect-helpers-BKCvISIQ.mjs","names":[],"sources":["../src/database/dialect-helpers.ts"],"sourcesContent":["/**\n * Dialect-specific SQL helpers\n *\n * Every function takes a Kysely `db` instance and detects the dialect from\n * the adapter class. No module-level state, no globals, no heuristics —\n * the adapter is the source of truth.\n *\n * This is NOT an ORM abstraction — just targeted helpers for the ~15 places\n * that use raw dialect-specific SQL. Most Kysely schema builder code already\n * works cross-dialect.\n */\n\nimport type { ColumnDataType, Kysely, RawBuilder } from \"kysely\";\nimport { sql } from \"kysely\";\n\nimport type { DatabaseDialectType } from \"../db/adapters.js\";\nimport { validateIdentifier, validateJsonFieldName } from \"./validate.js\";\n\nexport type { DatabaseDialectType };\n\n/**\n * Detect dialect type from a Kysely instance via the adapter class name.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any -- accepts any Kysely instance\nexport function detectDialect(db: Kysely<any>): DatabaseDialectType {\n\tconst name = db.getExecutor().adapter.constructor.name;\n\tif (name === \"PostgresAdapter\") return \"postgres\";\n\treturn \"sqlite\";\n}\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any -- accepts any Kysely instance\nexport function isSqlite(db: Kysely<any>): boolean {\n\treturn detectDialect(db) === \"sqlite\";\n}\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any -- accepts any Kysely instance\nexport function isPostgres(db: Kysely<any>): boolean {\n\treturn detectDialect(db) === \"postgres\";\n}\n\n/**\n * Default timestamp expression for column defaults.\n * Wrapped in parens for use in CREATE TABLE ... DEFAULT (...).\n *\n * sqlite: (datetime('now'))\n * postgres: CURRENT_TIMESTAMP\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any -- accepts any Kysely instance\nexport function currentTimestamp(db: Kysely<any>): RawBuilder<string> {\n\tif (isPostgres(db)) {\n\t\treturn sql`CURRENT_TIMESTAMP`;\n\t}\n\treturn sql`(datetime('now'))`;\n}\n\n/**\n * Timestamp expression for use in WHERE clauses and SET expressions.\n * No wrapping parens.\n *\n * sqlite: datetime('now')\n * postgres: CURRENT_TIMESTAMP\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any -- accepts any Kysely instance\nexport function currentTimestampValue(db: Kysely<any>): RawBuilder<string> {\n\tif (isPostgres(db)) {\n\t\treturn sql`CURRENT_TIMESTAMP`;\n\t}\n\treturn sql`datetime('now')`;\n}\n\n/**\n * Check if a table exists in the database.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any -- accepts any Kysely instance\nexport async function tableExists(db: Kysely<any>, tableName: string): Promise<boolean> {\n\tif (isPostgres(db)) {\n\t\tconst result = await sql<{ exists: boolean }>`\n\t\t\tSELECT EXISTS(\n\t\t\t\tSELECT 1 FROM information_schema.tables\n\t\t\t\tWHERE table_schema = 'public' AND table_name = ${tableName}\n\t\t\t) as exists\n\t\t`.execute(db);\n\t\treturn result.rows[0]?.exists === true;\n\t}\n\n\tconst result = await sql<{ name: string }>`\n\t\tSELECT name FROM sqlite_master\n\t\tWHERE type = 'table' AND name = ${tableName}\n\t`.execute(db);\n\treturn result.rows.length > 0;\n}\n\n/**\n * Check if an index exists in the database.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any -- accepts any Kysely instance\nexport async function indexExists(db: Kysely<any>, indexName: string): Promise<boolean> {\n\tif (isPostgres(db)) {\n\t\tconst result = await sql<{ exists: boolean }>`\n\t\t\tSELECT EXISTS(\n\t\t\t\tSELECT 1 FROM pg_indexes\n\t\t\t\tWHERE schemaname = current_schema() AND indexname = ${indexName}\n\t\t\t) as exists\n\t\t`.execute(db);\n\t\treturn result.rows[0]?.exists === true;\n\t}\n\n\tconst result = await sql<{ name: string }>`\n\t\tSELECT name FROM sqlite_master\n\t\tWHERE type = 'index' AND name = ${indexName}\n\t`.execute(db);\n\treturn result.rows.length > 0;\n}\n\n/**\n * Check if a column exists in the database.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any -- accepts any Kysely instance\nexport async function columnExists(\n\tdb: Kysely<any>,\n\ttableName: string,\n\tcolumnName: string,\n): Promise<boolean> {\n\tif (isPostgres(db)) {\n\t\tconst result = await sql<{ exists: boolean }>`\n\t\t\tSELECT EXISTS(\n\t\t\t\tSELECT 1 FROM information_schema.columns\n\t\t\t\tWHERE table_schema = current_schema()\n\t\t\t\t\tAND table_name = ${tableName}\n\t\t\t\t\tAND column_name = ${columnName}\n\t\t\t) as exists\n\t\t`.execute(db);\n\t\treturn result.rows[0]?.exists === true;\n\t}\n\n\tconst result = await sql<{ name: string }>`\n\t\tSELECT name FROM pragma_table_info(${tableName})\n\t\tWHERE name = ${columnName}\n\t`.execute(db);\n\treturn result.rows.length > 0;\n}\n\n/**\n * List tables matching a LIKE pattern.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any -- accepts any Kysely instance\nexport async function listTablesLike(db: Kysely<any>, pattern: string): Promise<string[]> {\n\tif (isPostgres(db)) {\n\t\tconst result = await sql<{ table_name: string }>`\n\t\t\tSELECT table_name FROM information_schema.tables\n\t\t\tWHERE table_schema = 'public' AND table_name LIKE ${pattern}\n\t\t`.execute(db);\n\t\treturn result.rows.map((r) => r.table_name);\n\t}\n\n\tconst result = await sql<{ name: string }>`\n\t\tSELECT name FROM sqlite_master\n\t\tWHERE type = 'table' AND name LIKE ${pattern}\n\t`.execute(db);\n\treturn result.rows.map((r) => r.name);\n}\n\n/**\n * Column type for binary data.\n *\n * sqlite: blob\n * postgres: bytea\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any -- accepts any Kysely instance\nexport function binaryType(db: Kysely<any>): ColumnDataType {\n\tif (isPostgres(db)) {\n\t\treturn \"bytea\";\n\t}\n\treturn \"blob\";\n}\n\n/**\n * SQL expression for extracting a field from a JSON/JSONB column.\n *\n * sqlite: json_extract(column, '$.path')\n * postgres: column->>'path'\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any -- accepts any Kysely instance\nexport function jsonExtractExpr(db: Kysely<any>, column: string, path: string): string {\n\tvalidateIdentifier(column, \"JSON column name\");\n\tvalidateJsonFieldName(path, \"JSON path\");\n\tif (isPostgres(db)) {\n\t\treturn `${column}->>'${path}'`;\n\t}\n\treturn `json_extract(${column}, '$.${path}')`;\n}\n"],"mappings":";;;;;;;AAwBA,SAAgB,cAAc,IAAsC;AAEnE,KADa,GAAG,aAAa,CAAC,QAAQ,YAAY,SACrC,kBAAmB,QAAO;AACvC,QAAO;;AAIR,SAAgB,SAAS,IAA0B;AAClD,QAAO,cAAc,GAAG,KAAK;;AAI9B,SAAgB,WAAW,IAA0B;AACpD,QAAO,cAAc,GAAG,KAAK;;;;;;;;;AAW9B,SAAgB,iBAAiB,IAAqC;AACrE,KAAI,WAAW,GAAG,CACjB,QAAO,GAAG;AAEX,QAAO,GAAG;;;;;;;;;AAWX,SAAgB,sBAAsB,IAAqC;AAC1E,KAAI,WAAW,GAAG,CACjB,QAAO,GAAG;AAEX,QAAO,GAAG;;;;;AAOX,eAAsB,YAAY,IAAiB,WAAqC;AACvF,KAAI,WAAW,GAAG,CAOjB,SANe,MAAM,GAAwB;;;qDAGM,UAAU;;IAE3D,QAAQ,GAAG,EACC,KAAK,IAAI,WAAW;AAOnC,SAJe,MAAM,GAAqB;;oCAEP,UAAU;GAC3C,QAAQ,GAAG,EACC,KAAK,SAAS;;;;;AA6B7B,eAAsB,aACrB,IACA,WACA,YACmB;AACnB,KAAI,WAAW,GAAG,CASjB,SARe,MAAM,GAAwB;;;;wBAIvB,UAAU;yBACT,WAAW;;IAEhC,QAAQ,GAAG,EACC,KAAK,IAAI,WAAW;AAOnC,SAJe,MAAM,GAAqB;uCACJ,UAAU;iBAChC,WAAW;GACzB,QAAQ,GAAG,EACC,KAAK,SAAS;;;;;AAO7B,eAAsB,eAAe,IAAiB,SAAoC;AACzF,KAAI,WAAW,GAAG,CAKjB,SAJe,MAAM,GAA2B;;uDAEK,QAAQ;IAC3D,QAAQ,GAAG,EACC,KAAK,KAAK,MAAM,EAAE,WAAW;AAO5C,SAJe,MAAM,GAAqB;;uCAEJ,QAAQ;GAC5C,QAAQ,GAAG,EACC,KAAK,KAAK,MAAM,EAAE,KAAK;;;;;;;;AAUtC,SAAgB,WAAW,IAAiC;AAC3D,KAAI,WAAW,GAAG,CACjB,QAAO;AAER,QAAO;;;;;;;;AAUR,SAAgB,gBAAgB,IAAiB,QAAgB,MAAsB;AACtF,oBAAmB,QAAQ,mBAAmB;AAC9C,uBAAsB,MAAM,YAAY;AACxC,KAAI,WAAW,GAAG,CACjB,QAAO,GAAG,OAAO,MAAM,KAAK;AAE7B,QAAO,gBAAgB,OAAO,OAAO,KAAK"}
|