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
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reclaimable initialization lock for isolate-lifetime singletons.
|
|
3
|
+
*
|
|
4
|
+
* Guards "first request initializes, everyone else waits" sections
|
|
5
|
+
* (runtime creation, database init) against a workerd failure mode: if the
|
|
6
|
+
* request that owns the initialization is cancelled mid-await (client
|
|
7
|
+
* disconnect, context teardown), its continuation — including any `finally`
|
|
8
|
+
* that would release the lock — never runs. A plain boolean or shared
|
|
9
|
+
* promise then stays stuck forever and every subsequent request in the
|
|
10
|
+
* isolate hangs until the platform kills it (observed as 524s at the
|
|
11
|
+
* 100-second wall limit, with the isolate poisoned until eviction).
|
|
12
|
+
*
|
|
13
|
+
* This lock instead records *when* the owner started. Waiters poll — we
|
|
14
|
+
* deliberately never await a promise created by another request, which
|
|
15
|
+
* workerd flags — and if the owner has held the lock past `deadlineMs`,
|
|
16
|
+
* the next waiter assumes the owner is dead, reclaims the lock, and runs
|
|
17
|
+
* the initialization itself. Waiters also give up after `maxWaitMs` so a
|
|
18
|
+
* request degrades to an error response rather than hanging.
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
export interface InitLock {
|
|
22
|
+
/** Epoch ms when the current owner claimed the lock, or null when free. */
|
|
23
|
+
ownerStartedAt: number | null;
|
|
24
|
+
/**
|
|
25
|
+
* Monotonic claim counter identifying the current owner. Release is
|
|
26
|
+
* gated on it: a slow owner that finishes after a waiter has reclaimed
|
|
27
|
+
* the lock must not clear the reclaimer's claim — that would let yet
|
|
28
|
+
* another caller claim the lock and start a third concurrent init.
|
|
29
|
+
*/
|
|
30
|
+
generation: number;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function createInitLock(): InitLock {
|
|
34
|
+
return { ownerStartedAt: null, generation: 0 };
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export interface InitLockOptions {
|
|
38
|
+
/**
|
|
39
|
+
* Reclaim the lock if the owner has held it longer than this. Must be
|
|
40
|
+
* comfortably above the slowest legitimate init (cold migrations on a
|
|
41
|
+
* contended D1, including the concurrent-migrator wait) — a too-short
|
|
42
|
+
* deadline risks two concurrent inits, a too-long one delays recovery
|
|
43
|
+
* of a poisoned isolate. Nested locks must compose: an outer lock's
|
|
44
|
+
* deadline must exceed the deadline of any lock its init acquires.
|
|
45
|
+
*/
|
|
46
|
+
deadlineMs?: number;
|
|
47
|
+
/** Waiter poll interval. */
|
|
48
|
+
pollMs?: number;
|
|
49
|
+
/**
|
|
50
|
+
* Give up waiting after this long and throw instead of hanging.
|
|
51
|
+
* Defaults to `deadlineMs` plus headroom so a waiter always survives
|
|
52
|
+
* long enough to reclaim a dead owner before giving up.
|
|
53
|
+
*/
|
|
54
|
+
maxWaitMs?: number;
|
|
55
|
+
/**
|
|
56
|
+
* Called with the in-flight init promise (errors pre-swallowed) so the
|
|
57
|
+
* caller can hand it to the host's lifetime extender (waitUntil via
|
|
58
|
+
* `after()`). If the owning request is cancelled mid-init, the anchored
|
|
59
|
+
* promise keeps the context alive: init completes, populates the cache,
|
|
60
|
+
* and the `finally` below releases the lock — preventing the poisoning
|
|
61
|
+
* instead of merely recovering from it via reclaim.
|
|
62
|
+
*/
|
|
63
|
+
anchor?: (promise: Promise<void>) => void;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const DEFAULT_DEADLINE_MS = 15_000;
|
|
67
|
+
const DEFAULT_POLL_MS = 50;
|
|
68
|
+
const MAX_WAIT_HEADROOM_MS = 15_000;
|
|
69
|
+
|
|
70
|
+
function sleep(ms: number): Promise<void> {
|
|
71
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Return the cached value if present, otherwise initialize it under the
|
|
76
|
+
* lock. `init` is responsible for storing the value so that `getCached`
|
|
77
|
+
* returns it on subsequent calls — waiters re-check `getCached` after the
|
|
78
|
+
* owner finishes rather than sharing the owner's promise.
|
|
79
|
+
*
|
|
80
|
+
* `init` receives an `isCurrentClaim` predicate and must gate its cache
|
|
81
|
+
* publication on it: a slow init that was reclaimed past the deadline
|
|
82
|
+
* must not overwrite the value published by the reclaimer (for the
|
|
83
|
+
* runtime singleton that would orphan the reclaimer's active cron
|
|
84
|
+
* scheduler). A losing init should also tear down any side resources it
|
|
85
|
+
* started, since its result will never be published.
|
|
86
|
+
*/
|
|
87
|
+
export async function initWithLock<T>(
|
|
88
|
+
lock: InitLock,
|
|
89
|
+
getCached: () => T | null | undefined,
|
|
90
|
+
init: (isCurrentClaim: () => boolean) => Promise<T>,
|
|
91
|
+
options?: InitLockOptions,
|
|
92
|
+
): Promise<T> {
|
|
93
|
+
const deadlineMs = options?.deadlineMs ?? DEFAULT_DEADLINE_MS;
|
|
94
|
+
const pollMs = options?.pollMs ?? DEFAULT_POLL_MS;
|
|
95
|
+
const maxWaitMs = options?.maxWaitMs ?? deadlineMs + MAX_WAIT_HEADROOM_MS;
|
|
96
|
+
// Date.now() is deliberate and only works because every loop iteration
|
|
97
|
+
// awaits: in workerd the clock only advances across I/O, so a sync spin
|
|
98
|
+
// would never observe the deadline. Don't "optimize" away the sleep.
|
|
99
|
+
const waitStart = Date.now();
|
|
100
|
+
|
|
101
|
+
for (;;) {
|
|
102
|
+
const cached = getCached();
|
|
103
|
+
if (cached !== null && cached !== undefined) {
|
|
104
|
+
return cached;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const ownerStartedAt = lock.ownerStartedAt;
|
|
108
|
+
if (ownerStartedAt === null || Date.now() - ownerStartedAt > deadlineMs) {
|
|
109
|
+
// Free, or the owner has been gone past the deadline — claim it.
|
|
110
|
+
// Synchronous between awaits, so two waiters can't both claim.
|
|
111
|
+
lock.generation += 1;
|
|
112
|
+
const claim = lock.generation;
|
|
113
|
+
lock.ownerStartedAt = Date.now();
|
|
114
|
+
try {
|
|
115
|
+
// Promise.resolve().then(...) so a synchronous throw from
|
|
116
|
+
// init still becomes a rejection after the anchor attaches.
|
|
117
|
+
const isCurrentClaim = () => lock.generation === claim;
|
|
118
|
+
const initPromise = Promise.resolve().then(() => init(isCurrentClaim));
|
|
119
|
+
options?.anchor?.(
|
|
120
|
+
initPromise.then(
|
|
121
|
+
() => undefined,
|
|
122
|
+
() => undefined,
|
|
123
|
+
),
|
|
124
|
+
);
|
|
125
|
+
return await initPromise;
|
|
126
|
+
} finally {
|
|
127
|
+
// If this request dies mid-init unanchored this never runs;
|
|
128
|
+
// the next waiter reclaims after deadlineMs instead. Release
|
|
129
|
+
// only while still the current owner: a reclaimer may have
|
|
130
|
+
// taken the lock while this (slow) init was running, and
|
|
131
|
+
// clearing its claim would admit a third concurrent init.
|
|
132
|
+
if (lock.generation === claim) {
|
|
133
|
+
lock.ownerStartedAt = null;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
if (Date.now() - waitStart > maxWaitMs) {
|
|
139
|
+
throw new Error(`initWithLock: timed out after ${maxWaitMs}ms waiting for initialization`);
|
|
140
|
+
}
|
|
141
|
+
await sleep(pollMs);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
@@ -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"}
|