emdash 0.17.1 → 0.18.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api/route-utils.mjs +11 -11
- package/dist/{api-Dmz40c2V.mjs → api-Cs7DAACP.mjs} +12 -12
- package/dist/{api-Dmz40c2V.mjs.map → api-Cs7DAACP.mjs.map} +1 -1
- package/dist/{apply-CuuZG6op.mjs → apply-BWMV4Zmw.mjs} +16 -16
- package/dist/{apply-CuuZG6op.mjs.map → apply-BWMV4Zmw.mjs.map} +1 -1
- package/dist/astro/index.mjs +1 -1
- 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 +274 -91
- 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.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/{authorize-_wWM_44T.mjs → authorize-CotM4Yiu.mjs} +2 -2
- package/dist/{authorize-_wWM_44T.mjs.map → authorize-CotM4Yiu.mjs.map} +1 -1
- package/dist/{byline-BrIVWLm-.mjs → byline-CWQ9aSoz.mjs} +4 -4
- package/dist/{byline-BrIVWLm-.mjs.map → byline-CWQ9aSoz.mjs.map} +1 -1
- package/dist/{bylines-C_POWmGT.mjs → bylines-BJSva1Un.mjs} +4 -4
- package/dist/{bylines-C_POWmGT.mjs.map → bylines-BJSva1Un.mjs.map} +1 -1
- package/dist/{bylines-sqExMElV.mjs → bylines-LJMgENMI.mjs} +3 -3
- package/dist/{bylines-sqExMElV.mjs.map → bylines-LJMgENMI.mjs.map} +1 -1
- package/dist/{cache-wsDkA8ru.mjs → cache-lZL7SgVb.mjs} +2 -2
- package/dist/{cache-wsDkA8ru.mjs.map → cache-lZL7SgVb.mjs.map} +1 -1
- package/dist/{chunks-BAYkM-CF.mjs → chunks-BU-vP9Dh.mjs} +2 -2
- package/dist/{chunks-BAYkM-CF.mjs.map → chunks-BU-vP9Dh.mjs.map} +1 -1
- package/dist/cli/index.mjs +14 -14
- package/dist/{comment-Cd29aktf.mjs → comment-C4jVbCM8.mjs} +2 -2
- package/dist/{comment-Cd29aktf.mjs.map → comment-C4jVbCM8.mjs.map} +1 -1
- package/dist/{comments-B7ufhkxN.mjs → comments-BTAbC0Ek.mjs} +3 -3
- package/dist/{comments-B7ufhkxN.mjs.map → comments-BTAbC0Ek.mjs.map} +1 -1
- package/dist/{content-BbqKo3Kc.mjs → content-CyqOmOzm.mjs} +3 -3
- package/dist/{content-BbqKo3Kc.mjs.map → content-CyqOmOzm.mjs.map} +1 -1
- package/dist/{context-BsF1rhoI.mjs → context-DZ7bEh5-.mjs} +8 -8
- package/dist/{context-BsF1rhoI.mjs.map → context-DZ7bEh5-.mjs.map} +1 -1
- package/dist/{dashboard-BwIX9r-X.mjs → dashboard-B5WQpNTP.mjs} +4 -4
- package/dist/{dashboard-BwIX9r-X.mjs.map → dashboard-B5WQpNTP.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-DJOsMVSt.mjs} +2 -2
- package/dist/{error-npZWBSb7.mjs.map → error-DJOsMVSt.mjs.map} +1 -1
- package/dist/{fts-manager-DmUAk-kQ.mjs → fts-manager-DR1ERA0c.mjs} +3 -3
- package/dist/{fts-manager-DmUAk-kQ.mjs.map → fts-manager-DR1ERA0c.mjs.map} +1 -1
- package/dist/index-CjKdMZ3U.d.mts.map +1 -1
- package/dist/index.mjs +35 -35
- package/dist/{load-DsoLq7ex.mjs → load-6ZrRhepW.mjs} +2 -2
- package/dist/{load-DsoLq7ex.mjs.map → load-6ZrRhepW.mjs.map} +1 -1
- package/dist/{loader-CJ6lWO0d.mjs → loader-Dyx8dhFV.mjs} +4 -4
- package/dist/{loader-CJ6lWO0d.mjs.map → loader-Dyx8dhFV.mjs.map} +1 -1
- package/dist/media/local-runtime.mjs +5 -5
- package/dist/{media-jk_HzzOl.mjs → media-C-oovGCG.mjs} +2 -2
- package/dist/{media-jk_HzzOl.mjs.map → media-C-oovGCG.mjs.map} +1 -1
- package/dist/{menus-CyMO6GBx.mjs → menus-BKkxXCmd.mjs} +30 -11
- package/dist/menus-BKkxXCmd.mjs.map +1 -0
- package/dist/{menus-B-5-3aon.mjs → menus-DugoYwTX.mjs} +2 -2
- package/dist/{menus-B-5-3aon.mjs.map → menus-DugoYwTX.mjs.map} +1 -1
- package/dist/{parse-4zO5Y2DL.mjs → parse-BBkFmLVr.mjs} +2 -2
- package/dist/{parse-4zO5Y2DL.mjs.map → parse-BBkFmLVr.mjs.map} +1 -1
- package/dist/{query-Bt52mHXp.mjs → query-Ctlq1aOk.mjs} +10 -10
- package/dist/{query-Bt52mHXp.mjs.map → query-Ctlq1aOk.mjs.map} +1 -1
- package/dist/{rate-limit-D6VQqBk_.mjs → rate-limit-CH6W6ikK.mjs} +2 -2
- package/dist/{rate-limit-D6VQqBk_.mjs.map → rate-limit-CH6W6ikK.mjs.map} +1 -1
- package/dist/{redirect-BZUJltlj.mjs → redirect-C6tJA7tk.mjs} +3 -3
- package/dist/{redirect-BZUJltlj.mjs.map → redirect-C6tJA7tk.mjs.map} +1 -1
- package/dist/{redirects-DnYuqsEf.mjs → redirects-CacE9eQa.mjs} +3 -3
- package/dist/{redirects-DnYuqsEf.mjs.map → redirects-CacE9eQa.mjs.map} +1 -1
- package/dist/{registry-Dn6gsx3L.mjs → registry-CIDxZbhh.mjs} +5 -5
- package/dist/{registry-Dn6gsx3L.mjs.map → registry-CIDxZbhh.mjs.map} +1 -1
- package/dist/runner-DM1yR5qd.d.mts.map +1 -1
- package/dist/{runner-eAgyIkeg.mjs → runner-pt6Wl-l-.mjs} +11 -6
- package/dist/runner-pt6Wl-l-.mjs.map +1 -0
- package/dist/runtime.mjs +3 -3
- package/dist/{schema--mYZX4D7.mjs → schema-B4tk0HAG.mjs} +4 -4
- package/dist/{schema--mYZX4D7.mjs.map → schema-B4tk0HAG.mjs.map} +1 -1
- package/dist/{search-C6U_NvZI.mjs → search-f-fNfwab.mjs} +4 -4
- package/dist/{search-C6U_NvZI.mjs.map → search-f-fNfwab.mjs.map} +1 -1
- package/dist/{sections-Ba-rJLKb.mjs → sections-biElLfT9.mjs} +3 -3
- package/dist/{sections-Ba-rJLKb.mjs.map → sections-biElLfT9.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-BR39kvTF.mjs} +2 -2
- package/dist/{seo-BTzb5ksq.mjs.map → seo-BR39kvTF.mjs.map} +1 -1
- package/dist/{service-Cn-kIfZn.mjs → service-BhR2acnc.mjs} +2 -2
- package/dist/{service-Cn-kIfZn.mjs.map → service-BhR2acnc.mjs.map} +1 -1
- package/dist/{settings-C65OSm41.mjs → settings-D_NJvjgN.mjs} +3 -3
- package/dist/{settings-C65OSm41.mjs.map → settings-D_NJvjgN.mjs.map} +1 -1
- package/dist/{settings-ChlQbwU0.mjs → settings-b5zW1R1T.mjs} +3 -3
- package/dist/{settings-ChlQbwU0.mjs.map → settings-b5zW1R1T.mjs.map} +1 -1
- package/dist/{taxonomies-ByLlXrv5.mjs → taxonomies-Crtzy4MT.mjs} +8 -7
- package/dist/taxonomies-Crtzy4MT.mjs.map +1 -0
- package/dist/{taxonomies-CbO6v7EE.mjs → taxonomies-Mhn9rjTQ.mjs} +4 -4
- package/dist/{taxonomies-CbO6v7EE.mjs.map → taxonomies-Mhn9rjTQ.mjs.map} +1 -1
- package/dist/{taxonomy-BBK-UAEo.mjs → taxonomy-DTZrIQpi.mjs} +3 -3
- package/dist/{taxonomy-BBK-UAEo.mjs.map → taxonomy-DTZrIQpi.mjs.map} +1 -1
- package/dist/{types-SF1DwGf2.mjs → types-K3MDsxpy.mjs} +2 -2
- package/dist/{types-SF1DwGf2.mjs.map → types-K3MDsxpy.mjs.map} +1 -1
- package/dist/{user-X4rtyO4Y.mjs → user-DzEUl5zA.mjs} +2 -2
- package/dist/{user-X4rtyO4Y.mjs.map → user-DzEUl5zA.mjs.map} +1 -1
- package/dist/{validate-DactmcJG.mjs → validate-JCXcsqiY.mjs} +2 -2
- package/dist/{validate-DactmcJG.mjs.map → validate-JCXcsqiY.mjs.map} +1 -1
- package/dist/{validation-BYA4i85b.mjs → validation-Bq-VyKJg.mjs} +6 -6
- package/dist/{validation-BYA4i85b.mjs.map → validation-Bq-VyKJg.mjs.map} +1 -1
- package/dist/version-CnS-Cr8A.mjs +7 -0
- package/dist/{version-CWbvq9LG.mjs.map → version-CnS-Cr8A.mjs.map} +1 -1
- package/dist/{widgets-DG-1jxnz.mjs → widgets-Bap1eS1X.mjs} +2 -2
- package/dist/{widgets-DG-1jxnz.mjs.map → widgets-Bap1eS1X.mjs.map} +1 -1
- package/dist/{zod-generator-BNAObjSt.mjs → zod-generator-BSDpkqSH.mjs} +4 -3
- package/dist/zod-generator-BSDpkqSH.mjs.map +1 -0
- package/package.json +7 -7
- package/src/astro/middleware/stream-end-metrics.ts +96 -0
- package/src/astro/middleware.ts +114 -40
- package/src/components/EmDashImage.astro +1 -0
- package/src/database/dialect-helpers.ts +8 -2
- package/src/database/migrations/019_i18n.ts +2 -2
- package/src/database/migrations/runner.ts +7 -2
- package/src/emdash-runtime.ts +177 -126
- package/src/menus/index.ts +27 -9
- package/src/plugins/hooks.ts +35 -6
- package/src/plugins/manager.ts +1 -0
- package/src/schema/zod-generator.ts +6 -2
- package/src/seo/index.ts +10 -1
- package/src/taxonomies/index.ts +12 -8
- package/src/utils/init-lock.ts +143 -0
- package/dist/dialect-helpers-BKCvISIQ.mjs.map +0 -1
- package/dist/menus-CyMO6GBx.mjs.map +0 -1
- package/dist/runner-eAgyIkeg.mjs.map +0 -1
- package/dist/taxonomies-ByLlXrv5.mjs.map +0 -1
- package/dist/version-CWbvq9LG.mjs +0 -7
- package/dist/zod-generator-BNAObjSt.mjs.map +0 -1
package/src/astro/middleware.ts
CHANGED
|
@@ -27,12 +27,14 @@ import { sandboxedPlugins as virtualSandboxedPlugins } from "virtual:emdash/sand
|
|
|
27
27
|
// @ts-ignore - virtual module
|
|
28
28
|
import { createStorage as virtualCreateStorage } from "virtual:emdash/storage";
|
|
29
29
|
|
|
30
|
+
import { after } from "../after.js";
|
|
30
31
|
import {
|
|
31
32
|
createRecorder,
|
|
32
33
|
flushRecorder,
|
|
33
34
|
isInstrumentationEnabled,
|
|
34
35
|
} from "../database/instrumentation.js";
|
|
35
36
|
import {
|
|
37
|
+
DB_INIT_DEADLINE_MS,
|
|
36
38
|
EmDashRuntime,
|
|
37
39
|
type RuntimeDependencies,
|
|
38
40
|
type SandboxedPluginEntry,
|
|
@@ -50,17 +52,21 @@ import {
|
|
|
50
52
|
type RequestMetrics,
|
|
51
53
|
runWithContext,
|
|
52
54
|
} from "../request-context.js";
|
|
55
|
+
import { isMissingTableError } from "../utils/db-errors.js";
|
|
56
|
+
import { createInitLock, type InitLock, initWithLock } from "../utils/init-lock.js";
|
|
53
57
|
import type { EmDashConfig } from "./integration/runtime.js";
|
|
58
|
+
import { wrapBodyForStreamMetrics } from "./middleware/stream-end-metrics.js";
|
|
54
59
|
import { createPublicPluginApiRouteHandler } from "./public-plugin-api-routes.js";
|
|
55
60
|
import type { EmDashHandlers } from "./types.js";
|
|
56
61
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
let
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
62
|
+
/**
|
|
63
|
+
* Runtime init lock reclaim deadline. Must be strictly larger than the db
|
|
64
|
+
* init deadline: this lock wraps EmDashRuntime.create() → getDatabase() →
|
|
65
|
+
* the db init lock, and equal deadlines would let this outer lock reclaim
|
|
66
|
+
* (spawning a second cron scheduler and sandbox runner) while the inner db
|
|
67
|
+
* init is legitimately still working through a contended migration.
|
|
68
|
+
*/
|
|
69
|
+
const RUNTIME_INIT_DEADLINE_MS = DB_INIT_DEADLINE_MS + 15_000;
|
|
64
70
|
|
|
65
71
|
/**
|
|
66
72
|
* Whether we've verified the database has been set up.
|
|
@@ -69,8 +75,50 @@ let i18nInitialized = false;
|
|
|
69
75
|
* would query an empty database and crash. Once verified (or once the runtime
|
|
70
76
|
* has initialized via an admin/API request), this stays true for the worker's
|
|
71
77
|
* lifetime.
|
|
78
|
+
*
|
|
79
|
+
* Stored on globalThis behind a Symbol key so the flag is a true singleton
|
|
80
|
+
* even when the bundler duplicates this module across SSR chunks (same
|
|
81
|
+
* pattern as request-cache.ts). A plain module-scoped `let` becomes multiple
|
|
82
|
+
* independent variables, which would make the setup probe re-run far more
|
|
83
|
+
* often than intended — and every re-run is another chance for a transient
|
|
84
|
+
* DB error to be misread as "fresh install" and bounce visitors to setup.
|
|
72
85
|
*/
|
|
73
|
-
|
|
86
|
+
const SETUP_VERIFIED_KEY = Symbol.for("emdash:setup-verified");
|
|
87
|
+
const setupFlagStore = globalThis as Record<symbol, unknown>;
|
|
88
|
+
|
|
89
|
+
function isSetupVerified(): boolean {
|
|
90
|
+
return setupFlagStore[SETUP_VERIFIED_KEY] === true;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function markSetupVerified(): void {
|
|
94
|
+
setupFlagStore[SETUP_VERIFIED_KEY] = true;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* The runtime singleton and its init lock live on globalThis behind a
|
|
99
|
+
* Symbol — same reasoning as SETUP_VERIFIED_KEY above: the bundler can
|
|
100
|
+
* duplicate this module across SSR chunks, and a duplicated instance/lock
|
|
101
|
+
* would mean multiple runtimes (each with its own cron scheduler) per
|
|
102
|
+
* isolate, initializing and reclaiming independently.
|
|
103
|
+
*/
|
|
104
|
+
const RUNTIME_HOLDER_KEY = Symbol.for("emdash:runtime-holder");
|
|
105
|
+
interface RuntimeHolder {
|
|
106
|
+
instance: EmDashRuntime | null;
|
|
107
|
+
lock: InitLock;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function getRuntimeHolder(): RuntimeHolder {
|
|
111
|
+
// eslint-disable-next-line typescript/no-unsafe-type-assertion -- globalThis symbol slot, written only below
|
|
112
|
+
let holder = setupFlagStore[RUNTIME_HOLDER_KEY] as RuntimeHolder | undefined;
|
|
113
|
+
if (!holder) {
|
|
114
|
+
holder = { instance: null, lock: createInitLock() };
|
|
115
|
+
setupFlagStore[RUNTIME_HOLDER_KEY] = holder;
|
|
116
|
+
}
|
|
117
|
+
return holder;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/** Whether i18n config has been initialized from the virtual module */
|
|
121
|
+
let i18nInitialized = false;
|
|
74
122
|
|
|
75
123
|
/**
|
|
76
124
|
* Get EmDash configuration from virtual module
|
|
@@ -159,29 +207,40 @@ async function getRuntime(
|
|
|
159
207
|
config: EmDashConfig,
|
|
160
208
|
initTimings?: Array<{ name: string; dur: number; desc?: string }>,
|
|
161
209
|
): Promise<EmDashRuntime> {
|
|
162
|
-
//
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
//
|
|
168
|
-
//
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
210
|
+
// Waiters poll rather than awaiting the initializing request's promise —
|
|
211
|
+
// workerd flags cross-request promise resolution (warnings + potential
|
|
212
|
+
// hangs). If the initializing request is cancelled mid-create (client
|
|
213
|
+
// disconnect tears down its continuation, skipping any `finally`), the
|
|
214
|
+
// anchored init keeps running under waitUntil and populates the cache;
|
|
215
|
+
// failing that, the stale lock is reclaimed after a deadline instead of
|
|
216
|
+
// hanging every subsequent request in the isolate until eviction.
|
|
217
|
+
const holder = getRuntimeHolder();
|
|
218
|
+
return initWithLock(
|
|
219
|
+
holder.lock,
|
|
220
|
+
() => holder.instance,
|
|
221
|
+
async (isCurrentClaim) => {
|
|
222
|
+
const deps = buildDependencies(config);
|
|
223
|
+
const runtime = await EmDashRuntime.create(deps, initTimings);
|
|
224
|
+
if (isCurrentClaim()) {
|
|
225
|
+
holder.instance = runtime;
|
|
226
|
+
} else {
|
|
227
|
+
// This init was reclaimed mid-flight (it ran past the deadline
|
|
228
|
+
// and a waiter started its own). Don't overwrite the
|
|
229
|
+
// reclaimer's published runtime, and stop this one's cron
|
|
230
|
+
// scheduler so it doesn't keep firing unreferenced. The
|
|
231
|
+
// runtime is still returned — it's fully functional for the
|
|
232
|
+
// request that built it.
|
|
233
|
+
runtime.stopCron().catch((error: unknown) => {
|
|
234
|
+
console.error("[emdash] failed to stop superseded runtime's cron:", error);
|
|
235
|
+
});
|
|
236
|
+
}
|
|
237
|
+
return runtime;
|
|
238
|
+
},
|
|
239
|
+
{
|
|
240
|
+
deadlineMs: RUNTIME_INIT_DEADLINE_MS,
|
|
241
|
+
anchor: (promise) => after(() => promise),
|
|
242
|
+
},
|
|
243
|
+
);
|
|
185
244
|
}
|
|
186
245
|
|
|
187
246
|
/**
|
|
@@ -338,7 +397,7 @@ export const onRequest = defineMiddleware(async (context, next) => {
|
|
|
338
397
|
// Do a one-time lightweight probe using the same getDb() instance the
|
|
339
398
|
// page will use: if the migrations table doesn't exist, no migrations
|
|
340
399
|
// have ever run -- redirect to the setup wizard.
|
|
341
|
-
if (!
|
|
400
|
+
if (!isSetupVerified()) {
|
|
342
401
|
const t0 = performance.now();
|
|
343
402
|
try {
|
|
344
403
|
const { getDb } = await import("../loader.js");
|
|
@@ -348,10 +407,19 @@ export const onRequest = defineMiddleware(async (context, next) => {
|
|
|
348
407
|
.selectAll()
|
|
349
408
|
.limit(1)
|
|
350
409
|
.execute();
|
|
351
|
-
|
|
352
|
-
} catch {
|
|
353
|
-
//
|
|
354
|
-
|
|
410
|
+
markSetupVerified();
|
|
411
|
+
} catch (error) {
|
|
412
|
+
// Only a genuinely-missing migrations table means a fresh,
|
|
413
|
+
// un-set-up database — redirect to the setup wizard.
|
|
414
|
+
if (isMissingTableError(error)) {
|
|
415
|
+
return context.redirect("/_emdash/admin/setup");
|
|
416
|
+
}
|
|
417
|
+
// Any other failure (transient D1/replica error, timeout, cold-start
|
|
418
|
+
// race, locked SQLite) must NOT be read as "fresh install" — doing so
|
|
419
|
+
// bounces real visitors on a set-up site to /_emdash/admin/setup.
|
|
420
|
+
// Leave the flag unset so a later request can re-verify, and fall
|
|
421
|
+
// through to render the page normally.
|
|
422
|
+
console.error("Setup probe failed (non-fatal):", error);
|
|
355
423
|
}
|
|
356
424
|
timings.push({ name: "setup", dur: performance.now() - t0, desc: "Setup probe" });
|
|
357
425
|
}
|
|
@@ -368,7 +436,7 @@ export const onRequest = defineMiddleware(async (context, next) => {
|
|
|
368
436
|
const t0 = performance.now();
|
|
369
437
|
try {
|
|
370
438
|
const runtime = await getRuntime(config, initSubTimings);
|
|
371
|
-
|
|
439
|
+
markSetupVerified();
|
|
372
440
|
const handlePublicPluginApiRoute = createPublicPluginApiRouteHandler(runtime);
|
|
373
441
|
// eslint-disable-next-line typescript/no-unsafe-type-assertion -- partial object; getPageRuntime() only checks for the page-contribution methods
|
|
374
442
|
locals.emdash = {
|
|
@@ -403,7 +471,10 @@ export const onRequest = defineMiddleware(async (context, next) => {
|
|
|
403
471
|
timings.push({ name: "render", dur: performance.now() - t0, desc: "Page render" });
|
|
404
472
|
timings.push({ name: "mw", dur: performance.now() - mwStart, desc: "Total middleware" });
|
|
405
473
|
pushMetricsTimings(timings, metrics);
|
|
406
|
-
|
|
474
|
+
// Server-Timing only sees pre-stream queries; the stream-end
|
|
475
|
+
// wrapper (instrumentation-gated, no-op otherwise) emits the
|
|
476
|
+
// final counters once the body finishes streaming.
|
|
477
|
+
return wrapBodyForStreamMetrics(finalizeResponse(response, timings));
|
|
407
478
|
};
|
|
408
479
|
if (anonScoped) {
|
|
409
480
|
const parent = getRequestContext();
|
|
@@ -448,7 +519,7 @@ export const onRequest = defineMiddleware(async (context, next) => {
|
|
|
448
519
|
for (const sub of initSubTimings) timings.push(sub);
|
|
449
520
|
|
|
450
521
|
// Runtime init runs migrations, so the DB is guaranteed set up
|
|
451
|
-
|
|
522
|
+
markSetupVerified();
|
|
452
523
|
|
|
453
524
|
// The manifest is no longer pre-loaded here. It's admin-only
|
|
454
525
|
// content that public/anonymous requests never read, and
|
|
@@ -570,7 +641,10 @@ export const onRequest = defineMiddleware(async (context, next) => {
|
|
|
570
641
|
timings.push({ name: "render", dur: performance.now() - t0, desc: "Page render" });
|
|
571
642
|
timings.push({ name: "mw", dur: performance.now() - mwStart, desc: "Total middleware" });
|
|
572
643
|
pushMetricsTimings(timings, metrics);
|
|
573
|
-
|
|
644
|
+
// Server-Timing only sees pre-stream queries; the stream-end
|
|
645
|
+
// wrapper (instrumentation-gated, no-op otherwise) emits the
|
|
646
|
+
// final counters once the body finishes streaming.
|
|
647
|
+
return wrapBodyForStreamMetrics(finalizeResponse(response, timings));
|
|
574
648
|
};
|
|
575
649
|
|
|
576
650
|
if (scoped) {
|
|
@@ -170,6 +170,7 @@ const imgProps: Record<string, unknown> = {
|
|
|
170
170
|
height: finalHeight,
|
|
171
171
|
alt: finalAlt,
|
|
172
172
|
loading: priority ? "eager" : "lazy",
|
|
173
|
+
fetchpriority: priority ? "high" : undefined,
|
|
173
174
|
decoding: "async",
|
|
174
175
|
style: placeholderStyle ? `${baseStyle} ${placeholderStyle}` : baseStyle,
|
|
175
176
|
...attrs,
|
|
@@ -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) {
|
|
@@ -178,8 +178,13 @@ const MIGRATION_RACE_PATTERN = new RegExp(
|
|
|
178
178
|
"i",
|
|
179
179
|
);
|
|
180
180
|
|
|
181
|
-
/**
|
|
182
|
-
|
|
181
|
+
/**
|
|
182
|
+
* How long to wait for a concurrent migrator to finish before giving up.
|
|
183
|
+
* Exported because the db init lock's reclaim deadline must comfortably
|
|
184
|
+
* exceed it (see DB_INIT_DEADLINE_MS in emdash-runtime.ts) — a healthy
|
|
185
|
+
* init can legitimately block this long inside waitForConcurrentMigrator.
|
|
186
|
+
*/
|
|
187
|
+
export const MIGRATION_RACE_WAIT_MS = 10_000;
|
|
183
188
|
/** Polling interval while waiting for a concurrent migrator. */
|
|
184
189
|
const MIGRATION_RACE_POLL_MS = 100;
|
|
185
190
|
|