emdash 0.17.2 → 0.19.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.d.mts +2 -2
- package/dist/api/route-utils.mjs +14 -14
- package/dist/api/schemas/index.d.mts +2 -2
- package/dist/api/schemas/index.mjs +3 -3
- package/dist/{api-B7GATEYo.mjs → api-BZ6bhjYs.mjs} +88 -16
- package/dist/api-BZ6bhjYs.mjs.map +1 -0
- package/dist/{apply-BrVqULFe.mjs → apply-hQkKKBCf.mjs} +23 -23
- package/dist/apply-hQkKKBCf.mjs.map +1 -0
- package/dist/astro/index.d.mts +8 -8
- package/dist/astro/index.d.mts.map +1 -1
- package/dist/astro/index.mjs +113 -23
- package/dist/astro/index.mjs.map +1 -1
- package/dist/astro/middleware/auth.d.mts +7 -7
- package/dist/astro/middleware/auth.mjs +2 -2
- package/dist/astro/middleware/redirect.mjs +4 -4
- package/dist/astro/middleware/request-context.mjs +2 -2
- package/dist/astro/middleware.d.mts +26 -4
- package/dist/astro/middleware.d.mts.map +1 -1
- package/dist/astro/middleware.mjs +414 -215
- package/dist/astro/middleware.mjs.map +1 -1
- package/dist/astro/routes/api/admin/allowed-domains/_domain_.mjs +5 -5
- package/dist/astro/routes/api/admin/allowed-domains/index.mjs +5 -5
- package/dist/astro/routes/api/admin/api-tokens/_id_.mjs +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 +5 -5
- package/dist/astro/routes/api/admin/byline-fields/_slug_.mjs +8 -8
- package/dist/astro/routes/api/admin/byline-fields/index.mjs +8 -8
- package/dist/astro/routes/api/admin/byline-fields/reorder.mjs +8 -8
- package/dist/astro/routes/api/admin/bylines/_id_/index.mjs +12 -12
- package/dist/astro/routes/api/admin/bylines/_id_/translations.mjs +12 -12
- package/dist/astro/routes/api/admin/bylines/index.mjs +12 -12
- package/dist/astro/routes/api/admin/comments/_id_/status.mjs +11 -11
- package/dist/astro/routes/api/admin/comments/_id_.mjs +5 -5
- package/dist/astro/routes/api/admin/comments/bulk.mjs +8 -8
- package/dist/astro/routes/api/admin/comments/counts.mjs +5 -5
- package/dist/astro/routes/api/admin/comments/index.mjs +8 -8
- package/dist/astro/routes/api/admin/hooks/exclusive/_hookName_.mjs +5 -5
- package/dist/astro/routes/api/admin/hooks/exclusive/index.mjs +4 -4
- 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 +31 -31
- package/dist/astro/routes/api/admin/plugins/_id_/enable.mjs +31 -31
- package/dist/astro/routes/api/admin/plugins/_id_/index.mjs +30 -30
- package/dist/astro/routes/api/admin/plugins/_id_/uninstall.mjs +30 -30
- package/dist/astro/routes/api/admin/plugins/_id_/update.mjs +30 -30
- package/dist/astro/routes/api/admin/plugins/index.mjs +30 -30
- package/dist/astro/routes/api/admin/plugins/marketplace/_id_/icon.mjs +3 -3
- package/dist/astro/routes/api/admin/plugins/marketplace/_id_/index.mjs +30 -30
- package/dist/astro/routes/api/admin/plugins/marketplace/_id_/install.mjs +30 -30
- package/dist/astro/routes/api/admin/plugins/marketplace/index.mjs +30 -30
- package/dist/astro/routes/api/admin/plugins/registry/_id_/uninstall.mjs +30 -30
- package/dist/astro/routes/api/admin/plugins/registry/_id_/update.mjs +31 -31
- package/dist/astro/routes/api/admin/plugins/registry/artifact.mjs +30 -30
- package/dist/astro/routes/api/admin/plugins/registry/install.mjs +31 -31
- package/dist/astro/routes/api/admin/plugins/updates.mjs +30 -30
- package/dist/astro/routes/api/admin/themes/marketplace/_id_/index.mjs +30 -30
- package/dist/astro/routes/api/admin/themes/marketplace/_id_/thumbnail.mjs +3 -3
- package/dist/astro/routes/api/admin/themes/marketplace/index.mjs +30 -30
- package/dist/astro/routes/api/admin/users/_id_/disable.mjs +3 -3
- package/dist/astro/routes/api/admin/users/_id_/enable.mjs +2 -2
- package/dist/astro/routes/api/admin/users/_id_/index.mjs +6 -6
- package/dist/astro/routes/api/admin/users/_id_/send-recovery.mjs +4 -4
- package/dist/astro/routes/api/admin/users/index.mjs +5 -5
- package/dist/astro/routes/api/auth/dev-bypass.mjs +3 -3
- package/dist/astro/routes/api/auth/invite/accept.mjs +2 -2
- package/dist/astro/routes/api/auth/invite/complete.mjs +6 -6
- package/dist/astro/routes/api/auth/invite/index.mjs +7 -7
- package/dist/astro/routes/api/auth/invite/register-options.mjs +6 -6
- package/dist/astro/routes/api/auth/logout.mjs +2 -2
- package/dist/astro/routes/api/auth/magic-link/send.mjs +8 -8
- package/dist/astro/routes/api/auth/magic-link/verify.mjs +2 -2
- package/dist/astro/routes/api/auth/me.mjs +6 -6
- package/dist/astro/routes/api/auth/oauth/_provider_/callback.mjs +2 -2
- package/dist/astro/routes/api/auth/passkey/_id_.mjs +5 -5
- package/dist/astro/routes/api/auth/passkey/index.mjs +2 -2
- package/dist/astro/routes/api/auth/passkey/options.mjs +7 -7
- package/dist/astro/routes/api/auth/passkey/register/options.mjs +6 -6
- package/dist/astro/routes/api/auth/passkey/register/verify.mjs +6 -6
- package/dist/astro/routes/api/auth/passkey/verify.mjs +6 -6
- package/dist/astro/routes/api/auth/signup/complete.mjs +6 -6
- package/dist/astro/routes/api/auth/signup/request.mjs +8 -8
- package/dist/astro/routes/api/auth/signup/verify.mjs +2 -2
- package/dist/astro/routes/api/comments/_collection_/_contentId_/index.mjs +11 -11
- package/dist/astro/routes/api/content/_collection_/_id_/compare.mjs +3 -3
- package/dist/astro/routes/api/content/_collection_/_id_/discard-draft.mjs +6 -5
- package/dist/astro/routes/api/content/_collection_/_id_/discard-draft.mjs.map +1 -1
- 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 +8 -8
- package/dist/astro/routes/api/content/_collection_/_id_/publish.mjs +9 -8
- package/dist/astro/routes/api/content/_collection_/_id_/publish.mjs.map +1 -1
- 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.d.mts.map +1 -1
- package/dist/astro/routes/api/content/_collection_/_id_/schedule.mjs +12 -10
- package/dist/astro/routes/api/content/_collection_/_id_/schedule.mjs.map +1 -1
- package/dist/astro/routes/api/content/_collection_/_id_/terms/_taxonomy_.mjs +11 -11
- package/dist/astro/routes/api/content/_collection_/_id_/translations.mjs +3 -3
- package/dist/astro/routes/api/content/_collection_/_id_/unpublish.mjs +6 -5
- package/dist/astro/routes/api/content/_collection_/_id_/unpublish.mjs.map +1 -1
- package/dist/astro/routes/api/content/_collection_/_id_.mjs +9 -8
- package/dist/astro/routes/api/content/_collection_/_id_.mjs.map +1 -1
- package/dist/astro/routes/api/content/_collection_/authors.d.mts +8 -0
- package/dist/astro/routes/api/content/_collection_/authors.d.mts.map +1 -0
- package/dist/astro/routes/api/content/_collection_/authors.mjs +19 -0
- package/dist/astro/routes/api/content/_collection_/authors.mjs.map +1 -0
- package/dist/astro/routes/api/content/_collection_/index.mjs +6 -6
- package/dist/astro/routes/api/content/_collection_/trash.mjs +6 -6
- package/dist/astro/routes/api/dashboard.mjs +7 -7
- package/dist/astro/routes/api/dev/emails.mjs +2 -2
- package/dist/astro/routes/api/import/probe.d.mts +2 -2
- package/dist/astro/routes/api/import/probe.mjs +6 -6
- package/dist/astro/routes/api/import/wordpress/analyze.mjs +4 -4
- package/dist/astro/routes/api/import/wordpress/execute.d.mts +7 -7
- package/dist/astro/routes/api/import/wordpress/execute.mjs +9 -9
- package/dist/astro/routes/api/import/wordpress/media.mjs +6 -6
- package/dist/astro/routes/api/import/wordpress/prepare.mjs +9 -9
- package/dist/astro/routes/api/import/wordpress/rewrite-urls.mjs +8 -8
- package/dist/astro/routes/api/import/wordpress-plugin/analyze.mjs +6 -6
- package/dist/astro/routes/api/import/wordpress-plugin/execute.mjs +9 -9
- package/dist/astro/routes/api/manifest.mjs +3 -3
- package/dist/astro/routes/api/mcp.mjs +28 -28
- package/dist/astro/routes/api/media/_id_/confirm.mjs +6 -6
- package/dist/astro/routes/api/media/_id_.mjs +6 -6
- package/dist/astro/routes/api/media/file/_...key_.mjs +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 +6 -6
- package/dist/astro/routes/api/media.mjs +7 -7
- package/dist/astro/routes/api/menus/_name_/items/_id_.mjs +7 -7
- package/dist/astro/routes/api/menus/_name_/items.mjs +7 -7
- package/dist/astro/routes/api/menus/_name_/reorder.mjs +7 -7
- package/dist/astro/routes/api/menus/_name_/translations.mjs +7 -7
- package/dist/astro/routes/api/menus/_name_.mjs +7 -7
- package/dist/astro/routes/api/menus/index.mjs +7 -7
- package/dist/astro/routes/api/oauth/authorize.mjs +1 -1
- package/dist/astro/routes/api/oauth/device/authorize.mjs +4 -4
- package/dist/astro/routes/api/oauth/device/code.mjs +5 -5
- package/dist/astro/routes/api/oauth/device/token.mjs +5 -5
- package/dist/astro/routes/api/oauth/register.mjs +2 -2
- package/dist/astro/routes/api/oauth/token/refresh.mjs +4 -4
- package/dist/astro/routes/api/oauth/token/revoke.mjs +4 -4
- package/dist/astro/routes/api/oauth/token.mjs +4 -4
- package/dist/astro/routes/api/openapi.json.mjs +17 -3
- package/dist/astro/routes/api/openapi.json.mjs.map +1 -1
- package/dist/astro/routes/api/plugins/_pluginId_/_...path_.mjs +3 -3
- package/dist/astro/routes/api/redirects/404s/index.mjs +9 -9
- package/dist/astro/routes/api/redirects/404s/summary.mjs +9 -9
- package/dist/astro/routes/api/redirects/_id_.mjs +10 -10
- package/dist/astro/routes/api/redirects/index.mjs +10 -10
- package/dist/astro/routes/api/revisions/_revisionId_/index.mjs +3 -3
- package/dist/astro/routes/api/revisions/_revisionId_/restore.mjs +3 -3
- package/dist/astro/routes/api/schema/collections/_slug_/fields/_fieldSlug_.mjs +30 -30
- package/dist/astro/routes/api/schema/collections/_slug_/fields/index.mjs +30 -30
- package/dist/astro/routes/api/schema/collections/_slug_/fields/reorder.mjs +30 -30
- package/dist/astro/routes/api/schema/collections/_slug_/index.mjs +30 -30
- package/dist/astro/routes/api/schema/collections/index.mjs +30 -30
- package/dist/astro/routes/api/schema/index.mjs +6 -6
- package/dist/astro/routes/api/schema/orphans/_slug_.mjs +30 -30
- package/dist/astro/routes/api/schema/orphans/index.mjs +30 -30
- package/dist/astro/routes/api/search/enable.mjs +9 -9
- package/dist/astro/routes/api/search/index.mjs +8 -8
- package/dist/astro/routes/api/search/rebuild.mjs +9 -9
- package/dist/astro/routes/api/search/stats.mjs +6 -6
- package/dist/astro/routes/api/search/suggest.mjs +8 -8
- package/dist/astro/routes/api/sections/_slug_.mjs +8 -8
- package/dist/astro/routes/api/sections/index.mjs +8 -8
- package/dist/astro/routes/api/settings/email.mjs +5 -5
- package/dist/astro/routes/api/settings.mjs +12 -12
- package/dist/astro/routes/api/setup/admin-verify.mjs +6 -6
- package/dist/astro/routes/api/setup/admin.mjs +6 -6
- package/dist/astro/routes/api/setup/dev-bypass.mjs +18 -18
- package/dist/astro/routes/api/setup/dev-reset.mjs +3 -3
- package/dist/astro/routes/api/setup/index.mjs +21 -21
- package/dist/astro/routes/api/setup/status.mjs +3 -3
- package/dist/astro/routes/api/snapshot.mjs +5 -5
- package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_/translations.mjs +11 -11
- package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_.mjs +11 -11
- package/dist/astro/routes/api/taxonomies/_name_/terms/index.mjs +11 -11
- package/dist/astro/routes/api/taxonomies/index.mjs +11 -11
- package/dist/astro/routes/api/themes/preview.mjs +5 -5
- package/dist/astro/routes/api/typegen.mjs +5 -5
- package/dist/astro/routes/api/well-known/auth.mjs +1 -1
- package/dist/astro/routes/api/widget-areas/_name_/reorder.mjs +6 -6
- package/dist/astro/routes/api/widget-areas/_name_/widgets/_id_.mjs +8 -8
- package/dist/astro/routes/api/widget-areas/_name_/widgets.mjs +8 -8
- package/dist/astro/routes/api/widget-areas/_name_.mjs +5 -5
- package/dist/astro/routes/api/widget-areas/index.mjs +8 -8
- package/dist/astro/routes/api/widget-components.mjs +2 -2
- package/dist/astro/routes/robots.txt.mjs +6 -6
- package/dist/astro/routes/sitemap-_collection_.xml.mjs +6 -6
- package/dist/astro/routes/sitemap.xml.mjs +6 -6
- package/dist/astro/types.d.mts +15 -8
- package/dist/astro/types.d.mts.map +1 -1
- package/dist/{authorize-CLTmOUyx.mjs → authorize-C_8t2KGa.mjs} +2 -2
- package/dist/{authorize-CLTmOUyx.mjs.map → authorize-C_8t2KGa.mjs.map} +1 -1
- package/dist/{byline-CAhk4FrG.mjs → byline-DUx48sJp.mjs} +6 -6
- package/dist/{byline-CAhk4FrG.mjs.map → byline-DUx48sJp.mjs.map} +1 -1
- package/dist/{byline-fields-Dr-xcb6S.mjs → byline-fields-51kg6Vuv.mjs} +3 -3
- package/dist/{byline-fields-Dr-xcb6S.mjs.map → byline-fields-51kg6Vuv.mjs.map} +1 -1
- package/dist/{byline-fields-DC3Wkk-U.mjs → byline-fields-C_OsR-KF.mjs} +2 -2
- package/dist/{byline-fields-DC3Wkk-U.mjs.map → byline-fields-C_OsR-KF.mjs.map} +1 -1
- package/dist/{byline-fields-CR5hGLMw.d.mts → byline-fields-DYXKDuNX.d.mts} +53 -29
- package/dist/byline-fields-DYXKDuNX.d.mts.map +1 -0
- package/dist/{byline-registry-CxK5g559.mjs → byline-registry-CWP7I71B.mjs} +3 -3
- package/dist/{byline-registry-CxK5g559.mjs.map → byline-registry-CWP7I71B.mjs.map} +1 -1
- package/dist/{bylines-CbrD7STW.mjs → bylines-Cx5n-WqP.mjs} +3 -3
- package/dist/{bylines-CbrD7STW.mjs.map → bylines-Cx5n-WqP.mjs.map} +1 -1
- package/dist/{bylines-DCczH3AV.mjs → bylines-wurS258E.mjs} +50 -6
- package/dist/{bylines-DCczH3AV.mjs.map → bylines-wurS258E.mjs.map} +1 -1
- package/dist/{cache-DIHHyPkt.mjs → cache-B_HzASVT.mjs} +3 -3
- package/dist/{cache-DIHHyPkt.mjs.map → cache-B_HzASVT.mjs.map} +1 -1
- package/dist/{chunks-DnnHlRG3.mjs → chunks-BerYVuve.mjs} +2 -2
- package/dist/{chunks-DnnHlRG3.mjs.map → chunks-BerYVuve.mjs.map} +1 -1
- package/dist/cli/index.mjs +40 -27
- package/dist/cli/index.mjs.map +1 -1
- package/dist/client/cf-access.d.mts +1 -1
- package/dist/client/index.d.mts +1 -1
- package/dist/{comment-DkAfGX9E.mjs → comment-sqQxNpN3.mjs} +2 -2
- package/dist/{comment-DkAfGX9E.mjs.map → comment-sqQxNpN3.mjs.map} +1 -1
- package/dist/{comments-DLFnXs7J.mjs → comments-CJ0RZsYR.mjs} +3 -3
- package/dist/{comments-DLFnXs7J.mjs.map → comments-CJ0RZsYR.mjs.map} +1 -1
- package/dist/{content-C7aJ7keg.mjs → content-BIlVx-RX.mjs} +132 -43
- package/dist/content-BIlVx-RX.mjs.map +1 -0
- package/dist/{context-Ca0HkaIh.mjs → context-GG52SPgh.mjs} +10 -10
- package/dist/{context-Ca0HkaIh.mjs.map → context-GG52SPgh.mjs.map} +1 -1
- package/dist/{cron-DZovZUnC.mjs → cron-BJ2ClIlj.mjs} +4 -3
- package/dist/cron-BJ2ClIlj.mjs.map +1 -0
- package/dist/{dashboard-BrfLIsX1.mjs → dashboard-2JgAMWxK.mjs} +4 -4
- package/dist/{dashboard-BrfLIsX1.mjs.map → dashboard-2JgAMWxK.mjs.map} +1 -1
- package/dist/db/index.d.mts +2 -2
- package/dist/db/index.mjs +1 -1
- package/dist/{device-flow-ptLrVINd.mjs → device-flow-s6_q3T7A.mjs} +2 -2
- package/dist/{device-flow-ptLrVINd.mjs.map → device-flow-s6_q3T7A.mjs.map} +1 -1
- package/dist/{error-Bk9s3Ism.mjs → error-RwM4dD35.mjs} +2 -2
- package/dist/{error-Bk9s3Ism.mjs.map → error-RwM4dD35.mjs.map} +1 -1
- package/dist/{fts-manager-XpDfbIKo.mjs → fts-manager-1RgHmopc.mjs} +2 -2
- package/dist/{fts-manager-XpDfbIKo.mjs.map → fts-manager-1RgHmopc.mjs.map} +1 -1
- package/dist/{index-D60_SzHG.d.mts → index-BpYeJO1E.d.mts} +2 -2
- package/dist/{index-D60_SzHG.d.mts.map → index-BpYeJO1E.d.mts.map} +1 -1
- package/dist/{index-C8ciqSMJ.d.mts → index-FfiTQJq2.d.mts} +202 -20
- package/dist/index-FfiTQJq2.d.mts.map +1 -0
- package/dist/index.d.mts +9 -9
- package/dist/index.mjs +43 -43
- package/dist/{load-CF5oETkh.mjs → load-B84ohfBk.mjs} +2 -2
- package/dist/{load-CF5oETkh.mjs.map → load-B84ohfBk.mjs.map} +1 -1
- package/dist/{loader-BxyvbrZP.mjs → loader-CpZKpFz0.mjs} +32 -30
- package/dist/loader-CpZKpFz0.mjs.map +1 -0
- package/dist/media/index.mjs +1 -1
- package/dist/media/local-runtime.d.mts +7 -7
- package/dist/media/local-runtime.mjs +6 -6
- package/dist/{media-Cyz5BhSN.mjs → media-JOf3pNkw.mjs} +2 -2
- package/dist/{media-Cyz5BhSN.mjs.map → media-JOf3pNkw.mjs.map} +1 -1
- package/dist/{menus-PFp8FDuO.mjs → menus-DX4_E01q.mjs} +3 -3
- package/dist/{menus-PFp8FDuO.mjs.map → menus-DX4_E01q.mjs.map} +1 -1
- package/dist/{menus-CIdZ_Q6U.mjs → menus-Dp9xporj.mjs} +112 -16
- package/dist/menus-Dp9xporj.mjs.map +1 -0
- package/dist/{normalize-DVV8nbrL.mjs → normalize-CK5o04zr.mjs} +2 -2
- package/dist/{normalize-DVV8nbrL.mjs.map → normalize-CK5o04zr.mjs.map} +1 -1
- package/dist/{oauth-authorization-DvBAL75d.mjs → oauth-authorization-1aPAYjiC.mjs} +2 -2
- package/dist/{oauth-authorization-DvBAL75d.mjs.map → oauth-authorization-1aPAYjiC.mjs.map} +1 -1
- package/dist/{options-BL4X94qY.mjs → options-BPCVnesz.mjs} +1 -1
- package/dist/{options-BL4X94qY.mjs.map → options-BPCVnesz.mjs.map} +1 -1
- package/dist/{options-tb7DJROi.d.mts → options-D4MnavW_.d.mts} +3 -3
- package/dist/{options-tb7DJROi.d.mts.map → options-D4MnavW_.d.mts.map} +1 -1
- package/dist/{parse-B-K21lvm.mjs → parse-CrGndy1A.mjs} +2 -2
- package/dist/{parse-B-K21lvm.mjs.map → parse-CrGndy1A.mjs.map} +1 -1
- package/dist/{patterns-CqG5Ya3i.mjs → patterns-p-RBdTbM.mjs} +1 -1
- package/dist/{patterns-CqG5Ya3i.mjs.map → patterns-p-RBdTbM.mjs.map} +1 -1
- package/dist/plugin-utils.d.mts +7 -7
- package/dist/plugins/adapt-sandbox-entry.d.mts +7 -7
- package/dist/{query-Cc649nDl.mjs → query-BFQ029Ts.mjs} +21 -15
- package/dist/query-BFQ029Ts.mjs.map +1 -0
- package/dist/{rate-limit-BI1OdpQH.mjs → rate-limit-ClFFUga6.mjs} +2 -2
- package/dist/{rate-limit-BI1OdpQH.mjs.map → rate-limit-ClFFUga6.mjs.map} +1 -1
- package/dist/{redirect-C-FeA4j9.mjs → redirect-CRWIt8Zj.mjs} +3 -3
- package/dist/{redirect-C-FeA4j9.mjs.map → redirect-CRWIt8Zj.mjs.map} +1 -1
- package/dist/{redirects-C0L9JUk4.mjs → redirects-DEygMrRO.mjs} +25 -3
- package/dist/redirects-DEygMrRO.mjs.map +1 -0
- package/dist/{redirects-C1UgU9E0.mjs → redirects-OIu6vQ2i.mjs} +5 -5
- package/dist/{redirects-C1UgU9E0.mjs.map → redirects-OIu6vQ2i.mjs.map} +1 -1
- package/dist/{registry-C-T_PWgp.mjs → registry-brYh-rAT.mjs} +6 -6
- package/dist/{registry-C-T_PWgp.mjs.map → registry-brYh-rAT.mjs.map} +1 -1
- package/dist/{request-cache-BYMs-BGX.mjs → request-cache-D32LpnmI.mjs} +1 -1
- package/dist/{request-cache-BYMs-BGX.mjs.map → request-cache-D32LpnmI.mjs.map} +1 -1
- package/dist/{runner-BiuUfx-V.mjs → runner--4wMWwKM.mjs} +224 -168
- package/dist/runner--4wMWwKM.mjs.map +1 -0
- package/dist/{runner-DM1yR5qd.d.mts → runner-BcRuXq_h.d.mts} +2 -2
- package/dist/{runner-DM1yR5qd.d.mts.map → runner-BcRuXq_h.d.mts.map} +1 -1
- package/dist/runtime.d.mts +7 -7
- package/dist/runtime.mjs +2 -2
- package/dist/{schema-BpCJh2lU.mjs → schema-CS7Eg5gh.mjs} +5 -5
- package/dist/{schema-BpCJh2lU.mjs.map → schema-CS7Eg5gh.mjs.map} +1 -1
- package/dist/{search-BrF7k0Ho.mjs → search-o-aQzHI1.mjs} +4 -4
- package/dist/{search-BrF7k0Ho.mjs.map → search-o-aQzHI1.mjs.map} +1 -1
- package/dist/{secrets-YYbTgB1w.mjs → secrets-C_ZtRos3.mjs} +2 -2
- package/dist/{secrets-YYbTgB1w.mjs.map → secrets-C_ZtRos3.mjs.map} +1 -1
- package/dist/{sections-8DEa-dWt.mjs → sections-DhsZ0ns9.mjs} +3 -3
- package/dist/{sections-8DEa-dWt.mjs.map → sections-DhsZ0ns9.mjs.map} +1 -1
- package/dist/seed/index.d.mts +2 -2
- package/dist/seed/index.mjs +16 -16
- package/dist/seo/index.d.mts +1 -1
- package/dist/{seo-CKr7pLfA.mjs → seo-B5e6y9Wk.mjs} +2 -2
- package/dist/{seo-CKr7pLfA.mjs.map → seo-B5e6y9Wk.mjs.map} +1 -1
- package/dist/{service-9P2cdyR_.mjs → service-DAxg8RPR.mjs} +2 -2
- package/dist/{service-9P2cdyR_.mjs.map → service-DAxg8RPR.mjs.map} +1 -1
- package/dist/{settings-Jro4YcUb.mjs → settings-B1p-gPUK.mjs} +5 -5
- package/dist/{settings-Jro4YcUb.mjs.map → settings-B1p-gPUK.mjs.map} +1 -1
- package/dist/{settings-DYVzINdn.mjs → settings-DIsbHTRE.mjs} +3 -3
- package/dist/{settings-DYVzINdn.mjs.map → settings-DIsbHTRE.mjs.map} +1 -1
- package/dist/{setup-complete-VoEZfasi.mjs → setup-complete-Yuv78yua.mjs} +2 -2
- package/dist/{setup-complete-VoEZfasi.mjs.map → setup-complete-Yuv78yua.mjs.map} +1 -1
- package/dist/{site-url-Cm8-sJy7.mjs → site-url-mEVmwIFi.mjs} +2 -2
- package/dist/{site-url-Cm8-sJy7.mjs.map → site-url-mEVmwIFi.mjs.map} +1 -1
- package/dist/{taxonomies-CGD6y79Q.mjs → taxonomies-BEW7S5AI.mjs} +10 -8
- package/dist/taxonomies-BEW7S5AI.mjs.map +1 -0
- package/dist/{taxonomies-C0bVme_m.mjs → taxonomies-UusDXv3C.mjs} +4 -4
- package/dist/{taxonomies-C0bVme_m.mjs.map → taxonomies-UusDXv3C.mjs.map} +1 -1
- package/dist/{taxonomy-Db5xwphL.mjs → taxonomy-CdllE4oq.mjs} +3 -3
- package/dist/{taxonomy-Db5xwphL.mjs.map → taxonomy-CdllE4oq.mjs.map} +1 -1
- package/dist/{transaction-NQj4VJ7Z.mjs → transaction-x2tJQ-A1.mjs} +1 -1
- package/dist/{transaction-NQj4VJ7Z.mjs.map → transaction-x2tJQ-A1.mjs.map} +1 -1
- package/dist/{transport-OnMNbsIA.d.mts → transport-BwQeeY2p.d.mts} +1 -1
- package/dist/{transport-OnMNbsIA.d.mts.map → transport-BwQeeY2p.d.mts.map} +1 -1
- package/dist/{types-CfyYQ7eY.mjs → types-BXSUSAjt.mjs} +16 -3
- package/dist/{types-CfyYQ7eY.mjs.map → types-BXSUSAjt.mjs.map} +1 -1
- package/dist/{types-D8bhH891.mjs → types-DZk_y-MU.mjs} +1 -1
- package/dist/{types-D8bhH891.mjs.map → types-DZk_y-MU.mjs.map} +1 -1
- package/dist/{types-DawhLFwy.d.mts → types-OT_Es5mp.d.mts} +26 -1
- package/dist/{types-DawhLFwy.d.mts.map → types-OT_Es5mp.d.mts.map} +1 -1
- package/dist/{types-i8_uzhMD.d.mts → types-WVmpZBJV.d.mts} +18 -3
- package/dist/types-WVmpZBJV.d.mts.map +1 -0
- package/dist/{user-tLdHUEXV.mjs → user-C0um7wrg.mjs} +18 -2
- package/dist/user-C0um7wrg.mjs.map +1 -0
- package/dist/{validate-Dy6nkNls.d.mts → validate-BPAHUSge.d.mts} +10 -2
- package/dist/validate-BPAHUSge.d.mts.map +1 -0
- package/dist/{validate-DWmnRg6E.mjs → validate-ZP9Dvg0P.mjs} +6 -3
- package/dist/validate-ZP9Dvg0P.mjs.map +1 -0
- package/dist/{validation-BQ_TP-On.mjs → validation-CE5i4q0c.mjs} +5 -5
- package/dist/{validation-BQ_TP-On.mjs.map → validation-CE5i4q0c.mjs.map} +1 -1
- package/dist/version-Dw0JXu45.mjs +7 -0
- package/dist/{version-CgcnMvqS.mjs.map → version-Dw0JXu45.mjs.map} +1 -1
- package/dist/{widgets-DzlINGI6.mjs → widgets-ClEnYQCH.mjs} +2 -2
- package/dist/{widgets-DzlINGI6.mjs.map → widgets-ClEnYQCH.mjs.map} +1 -1
- package/dist/{zod-generator-MMm56Prt.mjs → zod-generator-Djo_VHCt.mjs} +4 -3
- package/dist/zod-generator-Djo_VHCt.mjs.map +1 -0
- package/package.json +7 -7
- package/src/api/handlers/content.ts +107 -8
- package/src/api/handlers/index.ts +2 -0
- package/src/api/openapi/document.ts +25 -0
- package/src/api/schemas/content.ts +33 -0
- package/src/astro/integration/index.ts +98 -0
- package/src/astro/integration/routes.ts +6 -0
- package/src/astro/integration/virtual-modules.ts +39 -0
- package/src/astro/integration/vite-config.ts +12 -0
- package/src/astro/middleware/stream-end-metrics.ts +96 -0
- package/src/astro/middleware.ts +107 -31
- package/src/astro/routes/api/content/[collection]/[id]/discard-draft.ts +4 -2
- package/src/astro/routes/api/content/[collection]/[id]/publish.ts +4 -2
- package/src/astro/routes/api/content/[collection]/[id]/schedule.ts +8 -4
- package/src/astro/routes/api/content/[collection]/[id]/unpublish.ts +4 -2
- package/src/astro/routes/api/content/[collection]/[id].ts +4 -2
- package/src/astro/routes/api/content/[collection]/authors.ts +34 -0
- package/src/astro/types.ts +8 -1
- package/src/bylines/index.ts +57 -0
- package/src/cli/commands/export-seed.ts +28 -12
- package/src/components/EmDashImage.astro +23 -4
- package/src/components/Image.astro +20 -3
- package/src/database/migrations/043_content_references.ts +121 -0
- package/src/database/migrations/runner.ts +9 -2
- package/src/database/repositories/content.ts +225 -67
- package/src/database/repositories/index.ts +7 -0
- package/src/database/repositories/relation.ts +467 -0
- package/src/database/repositories/types.ts +31 -0
- package/src/database/repositories/user.ts +18 -0
- package/src/database/types.ts +34 -0
- package/src/emdash-runtime.ts +318 -168
- package/src/index.ts +8 -1
- package/src/loader.ts +67 -34
- package/src/media/responsive.ts +125 -0
- package/src/menus/index.ts +27 -9
- package/src/plugins/cron.ts +3 -2
- package/src/plugins/hooks.ts +35 -6
- package/src/plugins/index.ts +5 -0
- package/src/plugins/manager.ts +1 -0
- package/src/plugins/scheduler/node.ts +9 -2
- package/src/query.ts +32 -5
- package/src/scheduled-publish.ts +153 -0
- package/src/schema/zod-generator.ts +6 -2
- package/src/seed/apply.ts +16 -6
- package/src/seed/types.ts +9 -0
- package/src/seed/validate.ts +15 -0
- package/src/taxonomies/index.ts +13 -8
- package/src/utils/init-lock.ts +143 -0
- package/src/virtual-modules.d.ts +11 -0
- package/dist/api-B7GATEYo.mjs.map +0 -1
- package/dist/apply-BrVqULFe.mjs.map +0 -1
- package/dist/byline-fields-CR5hGLMw.d.mts.map +0 -1
- package/dist/content-C7aJ7keg.mjs.map +0 -1
- package/dist/cron-DZovZUnC.mjs.map +0 -1
- package/dist/index-C8ciqSMJ.d.mts.map +0 -1
- package/dist/loader-BxyvbrZP.mjs.map +0 -1
- package/dist/menus-CIdZ_Q6U.mjs.map +0 -1
- package/dist/query-Cc649nDl.mjs.map +0 -1
- package/dist/redirects-C0L9JUk4.mjs.map +0 -1
- package/dist/runner-BiuUfx-V.mjs.map +0 -1
- package/dist/taxonomies-CGD6y79Q.mjs.map +0 -1
- package/dist/types-i8_uzhMD.d.mts.map +0 -1
- package/dist/user-tLdHUEXV.mjs.map +0 -1
- package/dist/validate-DWmnRg6E.mjs.map +0 -1
- package/dist/validate-Dy6nkNls.d.mts.map +0 -1
- package/dist/version-CgcnMvqS.mjs +0 -7
- package/dist/zod-generator-MMm56Prt.mjs.map +0 -1
- package/src/plugins/scheduler/piggyback.ts +0 -71
|
@@ -1,70 +1,70 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { i as runMigrations, t as MIGRATION_RACE_WAIT_MS } from "../runner--4wMWwKM.mjs";
|
|
2
2
|
import { t as validateIdentifier } from "../validate-VPnKoIzW.mjs";
|
|
3
3
|
import { o as isSqlite } from "../dialect-helpers-DRI5pyY3.mjs";
|
|
4
4
|
import { i as setI18nConfig } from "../config-CVssduLe.mjs";
|
|
5
|
-
import { _ as
|
|
6
|
-
import { r as RevisionRepository } from "../content-
|
|
5
|
+
import { _ as resolveExclusiveHooks, g as createHookPipeline, m as EmailPipeline, p as PluginRouteRegistry, v as definePlugin, y as after } from "../menus-Dp9xporj.mjs";
|
|
6
|
+
import { r as RevisionRepository, t as ContentRepository } from "../content-BIlVx-RX.mjs";
|
|
7
7
|
import "../base64-CqR-7kqF.mjs";
|
|
8
|
-
import "../types-
|
|
9
|
-
import { t as MediaRepository } from "../media-
|
|
10
|
-
import "../user-
|
|
11
|
-
import "../taxonomy-
|
|
12
|
-
import "../comment-
|
|
13
|
-
import { t as OptionsRepository } from "../options-
|
|
14
|
-
import "../context-
|
|
15
|
-
import "../menus-
|
|
16
|
-
import "../redirect-
|
|
8
|
+
import "../types-BXSUSAjt.mjs";
|
|
9
|
+
import { t as MediaRepository } from "../media-JOf3pNkw.mjs";
|
|
10
|
+
import "../user-C0um7wrg.mjs";
|
|
11
|
+
import "../taxonomy-CdllE4oq.mjs";
|
|
12
|
+
import "../comment-sqQxNpN3.mjs";
|
|
13
|
+
import { t as OptionsRepository } from "../options-BPCVnesz.mjs";
|
|
14
|
+
import "../context-GG52SPgh.mjs";
|
|
15
|
+
import "../menus-DX4_E01q.mjs";
|
|
16
|
+
import "../redirect-CRWIt8Zj.mjs";
|
|
17
17
|
import { createRequestMetrics, getRequestContext, runWithContext } from "../request-context.mjs";
|
|
18
|
-
import { r as requestCached } from "../request-cache-
|
|
19
|
-
import "../byline-registry-
|
|
20
|
-
import "../byline-
|
|
21
|
-
import {
|
|
18
|
+
import { r as requestCached } from "../request-cache-D32LpnmI.mjs";
|
|
19
|
+
import "../byline-registry-CWP7I71B.mjs";
|
|
20
|
+
import "../byline-DUx48sJp.mjs";
|
|
21
|
+
import { n as normalizeMediaValue } from "../normalize-CK5o04zr.mjs";
|
|
22
22
|
import "../placeholder-BZxr8W1j.mjs";
|
|
23
|
-
import "../seo-
|
|
23
|
+
import "../seo-B5e6y9Wk.mjs";
|
|
24
24
|
import { n as isMissingTableError } from "../db-errors-CtzxKBxe.mjs";
|
|
25
|
-
import { $ as
|
|
26
|
-
import "../dashboard-
|
|
25
|
+
import { $ as handleContentGet, B as handleMediaUpdate, G as handleContentAuthors, H as handleRevisionList, I as handleMediaCreate, J as handleContentCountTrashed, K as handleContentCompare, L as handleMediaDelete, Q as handleContentDuplicate, R as handleMediaGet, S as PluginStateRepository, U as handleRevisionRestore, V as handleRevisionGet, X as handleContentDelete, Y as handleContentCreate, Z as handleContentDiscardDraft, _ as loadBundleFromR2, at as handleContentRestore, ct as handleContentUnpublish, dt as validateRev, et as handleContentGetIncludingTrashed, it as handleContentPublish, lt as handleContentUnschedule, nt as handleContentListTrashed, ot as handleContentSchedule, q as handleContentCountScheduled, rt as handleContentPermanentDelete, s as normalizeRegistryConfig, st as handleContentTranslations, tt as handleContentList, ut as handleContentUpdate, z as handleMediaList } from "../api-BZ6bhjYs.mjs";
|
|
26
|
+
import "../dashboard-2JgAMWxK.mjs";
|
|
27
27
|
import { n as hashString } from "../hash-9w3pd3-m.mjs";
|
|
28
|
-
import { t as FTSManager } from "../fts-manager-
|
|
29
|
-
import { n as SchemaRegistry } from "../registry-
|
|
28
|
+
import { t as FTSManager } from "../fts-manager-1RgHmopc.mjs";
|
|
29
|
+
import { n as SchemaRegistry } from "../registry-brYh-rAT.mjs";
|
|
30
30
|
import { createRecorder, flushRecorder, isInstrumentationEnabled, kyselyLogOption } from "../database/instrumentation.mjs";
|
|
31
|
-
import { r as getDb } from "../loader-
|
|
32
|
-
import "../schema-
|
|
33
|
-
import "../zod-generator-
|
|
31
|
+
import { r as getDb } from "../loader-CpZKpFz0.mjs";
|
|
32
|
+
import "../schema-CS7Eg5gh.mjs";
|
|
33
|
+
import "../zod-generator-Djo_VHCt.mjs";
|
|
34
34
|
import "../seo-DfjLvu8i.mjs";
|
|
35
|
-
import "../sections-
|
|
36
|
-
import { o as invalidateSiteSettingsCache } from "../settings-
|
|
37
|
-
import "../settings-
|
|
35
|
+
import "../sections-DhsZ0ns9.mjs";
|
|
36
|
+
import { o as invalidateSiteSettingsCache } from "../settings-B1p-gPUK.mjs";
|
|
37
|
+
import "../settings-DIsbHTRE.mjs";
|
|
38
38
|
import "../resolve-BqYMVG0D.mjs";
|
|
39
|
-
import "../taxonomies-
|
|
40
|
-
import "../taxonomies-
|
|
39
|
+
import "../taxonomies-BEW7S5AI.mjs";
|
|
40
|
+
import "../taxonomies-UusDXv3C.mjs";
|
|
41
41
|
import { r as normalizeManifestRoute } from "../manifest-schema-Cj-YrzrF.mjs";
|
|
42
42
|
import "../types-Cj2S6FuC.mjs";
|
|
43
43
|
import "../ssrf-BsVGIE0Z.mjs";
|
|
44
|
-
import "../error-
|
|
45
|
-
import "../parse-
|
|
46
|
-
import "../redirects-
|
|
47
|
-
import "../byline-fields-
|
|
48
|
-
import { a as invalidateUrlPatternCache } from "../query-
|
|
44
|
+
import "../error-RwM4dD35.mjs";
|
|
45
|
+
import "../parse-CrGndy1A.mjs";
|
|
46
|
+
import "../redirects-DEygMrRO.mjs";
|
|
47
|
+
import "../byline-fields-51kg6Vuv.mjs";
|
|
48
|
+
import { a as invalidateUrlPatternCache } from "../query-BFQ029Ts.mjs";
|
|
49
49
|
import "../import-Dh8bWmyq.mjs";
|
|
50
50
|
import { t as getTrustedProxyHeaders } from "../trusted-proxy-B4AfnoAp.mjs";
|
|
51
51
|
import { n as sanitizeHeadersForSandbox, t as extractRequestMeta } from "../request-meta-7ByVLxB-.mjs";
|
|
52
52
|
import "../ssrf-BvgVcfNQ.mjs";
|
|
53
|
-
import { n as CronExecutor } from "../cron-
|
|
53
|
+
import { n as CronExecutor } from "../cron-BJ2ClIlj.mjs";
|
|
54
54
|
import { r as devConsoleEmailDeliver, t as DEV_CONSOLE_EMAIL_PLUGIN_ID } from "../email-console-DHT2Fbpj.mjs";
|
|
55
55
|
import "../utils-C4Ih4DML.mjs";
|
|
56
56
|
import "../tokens-Bx2afeT-.mjs";
|
|
57
57
|
import "../preview-BfuRkVKW.mjs";
|
|
58
|
-
import "../bylines-
|
|
59
|
-
import "../widgets-
|
|
60
|
-
import "../apply-
|
|
61
|
-
import "../load-
|
|
62
|
-
import "../search-
|
|
58
|
+
import "../bylines-wurS258E.mjs";
|
|
59
|
+
import "../widgets-ClEnYQCH.mjs";
|
|
60
|
+
import "../apply-hQkKKBCf.mjs";
|
|
61
|
+
import "../load-B84ohfBk.mjs";
|
|
62
|
+
import "../search-o-aQzHI1.mjs";
|
|
63
63
|
import "../index.mjs";
|
|
64
|
-
import { n as VERSION, t as COMMIT } from "../version-
|
|
64
|
+
import { n as VERSION, t as COMMIT } from "../version-Dw0JXu45.mjs";
|
|
65
65
|
import { t as getAuthMode } from "../mode-BjlXswIw.mjs";
|
|
66
66
|
import { t as cleanupExpiredChallenges } from "../challenge-store-DGwuCc4R.mjs";
|
|
67
|
-
import { a as validateEncryptionKeyAtStartup } from "../secrets-
|
|
67
|
+
import { a as validateEncryptionKeyAtStartup } from "../secrets-C_ZtRos3.mjs";
|
|
68
68
|
import { Kysely, sql } from "kysely";
|
|
69
69
|
import { defineMiddleware } from "astro:middleware";
|
|
70
70
|
import virtualConfig from "virtual:emdash/config";
|
|
@@ -73,9 +73,64 @@ import { mediaProviders } from "virtual:emdash/media-providers";
|
|
|
73
73
|
import { plugins } from "virtual:emdash/plugins";
|
|
74
74
|
import * as virtualSandboxRunnerModule from "virtual:emdash/sandbox-runner";
|
|
75
75
|
import { sandboxedPlugins } from "virtual:emdash/sandboxed-plugins";
|
|
76
|
+
import { createScheduler } from "virtual:emdash/scheduler";
|
|
76
77
|
import { createStorage } from "virtual:emdash/storage";
|
|
77
78
|
import { createKyselyAdapter } from "@emdash-cms/auth/adapters/kysely";
|
|
78
79
|
|
|
80
|
+
//#region src/utils/init-lock.ts
|
|
81
|
+
function createInitLock() {
|
|
82
|
+
return {
|
|
83
|
+
ownerStartedAt: null,
|
|
84
|
+
generation: 0
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
const DEFAULT_DEADLINE_MS = 15e3;
|
|
88
|
+
const DEFAULT_POLL_MS = 50;
|
|
89
|
+
const MAX_WAIT_HEADROOM_MS = 15e3;
|
|
90
|
+
function sleep(ms) {
|
|
91
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Return the cached value if present, otherwise initialize it under the
|
|
95
|
+
* lock. `init` is responsible for storing the value so that `getCached`
|
|
96
|
+
* returns it on subsequent calls — waiters re-check `getCached` after the
|
|
97
|
+
* owner finishes rather than sharing the owner's promise.
|
|
98
|
+
*
|
|
99
|
+
* `init` receives an `isCurrentClaim` predicate and must gate its cache
|
|
100
|
+
* publication on it: a slow init that was reclaimed past the deadline
|
|
101
|
+
* must not overwrite the value published by the reclaimer (for the
|
|
102
|
+
* runtime singleton that would orphan the reclaimer's active cron
|
|
103
|
+
* scheduler). A losing init should also tear down any side resources it
|
|
104
|
+
* started, since its result will never be published.
|
|
105
|
+
*/
|
|
106
|
+
async function initWithLock(lock, getCached, init, options) {
|
|
107
|
+
const deadlineMs = options?.deadlineMs ?? DEFAULT_DEADLINE_MS;
|
|
108
|
+
const pollMs = options?.pollMs ?? DEFAULT_POLL_MS;
|
|
109
|
+
const maxWaitMs = options?.maxWaitMs ?? deadlineMs + MAX_WAIT_HEADROOM_MS;
|
|
110
|
+
const waitStart = Date.now();
|
|
111
|
+
for (;;) {
|
|
112
|
+
const cached = getCached();
|
|
113
|
+
if (cached !== null && cached !== void 0) return cached;
|
|
114
|
+
const ownerStartedAt = lock.ownerStartedAt;
|
|
115
|
+
if (ownerStartedAt === null || Date.now() - ownerStartedAt > deadlineMs) {
|
|
116
|
+
lock.generation += 1;
|
|
117
|
+
const claim = lock.generation;
|
|
118
|
+
lock.ownerStartedAt = Date.now();
|
|
119
|
+
try {
|
|
120
|
+
const isCurrentClaim = () => lock.generation === claim;
|
|
121
|
+
const initPromise = Promise.resolve().then(() => init(isCurrentClaim));
|
|
122
|
+
options?.anchor?.(initPromise.then(() => void 0, () => void 0));
|
|
123
|
+
return await initPromise;
|
|
124
|
+
} finally {
|
|
125
|
+
if (lock.generation === claim) lock.ownerStartedAt = null;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
if (Date.now() - waitStart > maxWaitMs) throw new Error(`initWithLock: timed out after ${maxWaitMs}ms waiting for initialization`);
|
|
129
|
+
await sleep(pollMs);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
//#endregion
|
|
79
134
|
//#region src/cleanup.ts
|
|
80
135
|
/**
|
|
81
136
|
* System cleanup
|
|
@@ -195,115 +250,70 @@ async function defaultCommentModerate(event, _ctx) {
|
|
|
195
250
|
}
|
|
196
251
|
|
|
197
252
|
//#endregion
|
|
198
|
-
//#region src/
|
|
199
|
-
/**
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
253
|
+
//#region src/scheduled-publish.ts
|
|
254
|
+
/**
|
|
255
|
+
* Default cap on items promoted per collection in a single sweep. Bounds the
|
|
256
|
+
* publish/webhook fan-out of one tick so a large backlog can't exhaust a Worker
|
|
257
|
+
* invocation's CPU/subrequest budget; the remainder drains on later ticks.
|
|
258
|
+
*/
|
|
259
|
+
const SCHEDULED_PUBLISH_BATCH_LIMIT = 100;
|
|
260
|
+
/**
|
|
261
|
+
* Publish every content item whose `scheduled_at` is in the past.
|
|
262
|
+
*
|
|
263
|
+
* Iterates all collections, finds due items (`findReadyToPublish` returns both
|
|
264
|
+
* scheduled drafts and published entries with pending scheduled changes), and
|
|
265
|
+
* publishes each. `publish()` clears `scheduled_at`, so a second sweep is a
|
|
266
|
+
* no-op — safe to run on every tick.
|
|
267
|
+
*
|
|
268
|
+
* Bounded per collection by `limit` (default `SCHEDULED_PUBLISH_BATCH_LIMIT`):
|
|
269
|
+
* a large backlog drains across successive ticks rather than in one unbounded
|
|
270
|
+
* pass. After each collection's batch, `onPublished` (if given) is awaited so
|
|
271
|
+
* cache-tag invalidation happens incrementally, not just at the very end.
|
|
272
|
+
*
|
|
273
|
+
* Returns every item it promoted so request-less callers (the Cloudflare
|
|
274
|
+
* `scheduled()` handler) can also act on the full set.
|
|
275
|
+
*/
|
|
276
|
+
async function publishDueContent(db, options = {}) {
|
|
277
|
+
const { publish, onPublished, limit = SCHEDULED_PUBLISH_BATCH_LIMIT } = options;
|
|
278
|
+
const published = [];
|
|
279
|
+
let collections;
|
|
280
|
+
try {
|
|
281
|
+
collections = await new SchemaRegistry(db).listCollections();
|
|
282
|
+
} catch (error) {
|
|
283
|
+
console.error("[scheduled-publish] Failed to list collections:", error);
|
|
284
|
+
return published;
|
|
285
|
+
}
|
|
286
|
+
const repo = new ContentRepository(db);
|
|
287
|
+
const doPublish = publish ?? ((collection, id, opts) => handleContentPublish(db, collection, id, opts));
|
|
288
|
+
const batchLimit = limit > 0 ? limit : void 0;
|
|
289
|
+
for (const collection of collections) try {
|
|
290
|
+
const due = await repo.findReadyToPublish(collection.slug, batchLimit);
|
|
291
|
+
const batch = [];
|
|
292
|
+
for (const item of due) {
|
|
293
|
+
const publishedAt = item.publishedAt == null ? item.scheduledAt ?? void 0 : void 0;
|
|
294
|
+
const result = await doPublish(collection.slug, item.id, {
|
|
295
|
+
publishedAt,
|
|
296
|
+
requireScheduledDue: true
|
|
297
|
+
});
|
|
298
|
+
if (result.success) batch.push({
|
|
299
|
+
collection: collection.slug,
|
|
300
|
+
id: item.id
|
|
301
|
+
});
|
|
302
|
+
else if (result.error?.code === "NOT_DUE") {} else console.error(`[scheduled-publish] Failed to publish ${collection.slug}/${item.id}:`, result.error);
|
|
229
303
|
}
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
let delayMs;
|
|
237
|
-
if (nextDue) {
|
|
238
|
-
const dueAt = new Date(nextDue).getTime();
|
|
239
|
-
delayMs = Math.max(dueAt - Date.now(), MIN_INTERVAL_MS);
|
|
240
|
-
delayMs = Math.min(delayMs, MAX_INTERVAL_MS);
|
|
241
|
-
} else delayMs = MAX_INTERVAL_MS;
|
|
242
|
-
this.timer = setTimeout(() => {
|
|
243
|
-
if (!this.running) return;
|
|
244
|
-
this.executeTick();
|
|
245
|
-
}, delayMs);
|
|
246
|
-
if (this.timer && typeof this.timer === "object" && "unref" in this.timer) this.timer.unref();
|
|
247
|
-
}).catch((error) => {
|
|
248
|
-
console.error("[cron:node] Failed to get next due time:", error);
|
|
249
|
-
if (this.running) {
|
|
250
|
-
this.timer = setTimeout(() => this.arm(), MAX_INTERVAL_MS);
|
|
251
|
-
if (this.timer && typeof this.timer === "object" && "unref" in this.timer) this.timer.unref();
|
|
304
|
+
if (batch.length > 0) {
|
|
305
|
+
published.push(...batch);
|
|
306
|
+
if (onPublished) try {
|
|
307
|
+
await onPublished(batch);
|
|
308
|
+
} catch (error) {
|
|
309
|
+
console.error(`[scheduled-publish] onPublished failed after "${collection.slug}" batch:`, error);
|
|
252
310
|
}
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
if (!this.running) return;
|
|
257
|
-
const tasks = [this.executor.tick(), this.executor.recoverStaleLocks()];
|
|
258
|
-
if (this.systemCleanup) tasks.push(this.systemCleanup());
|
|
259
|
-
Promise.allSettled(tasks).then((results) => {
|
|
260
|
-
for (const r of results) if (r.status === "rejected") console.error("[cron:node] Tick task failed:", r.reason);
|
|
261
|
-
}).finally(() => {
|
|
262
|
-
if (this.running) this.arm();
|
|
263
|
-
});
|
|
264
|
-
}
|
|
265
|
-
};
|
|
266
|
-
|
|
267
|
-
//#endregion
|
|
268
|
-
//#region src/plugins/scheduler/piggyback.ts
|
|
269
|
-
/** Minimum interval between tick attempts (ms) */
|
|
270
|
-
const DEBOUNCE_MS = 60 * 1e3;
|
|
271
|
-
var PiggybackScheduler = class {
|
|
272
|
-
lastTickAt = 0;
|
|
273
|
-
running = false;
|
|
274
|
-
systemCleanup = null;
|
|
275
|
-
constructor(executor) {
|
|
276
|
-
this.executor = executor;
|
|
277
|
-
}
|
|
278
|
-
setSystemCleanup(fn) {
|
|
279
|
-
this.systemCleanup = fn;
|
|
280
|
-
}
|
|
281
|
-
start() {
|
|
282
|
-
this.running = true;
|
|
283
|
-
}
|
|
284
|
-
stop() {
|
|
285
|
-
this.running = false;
|
|
286
|
-
}
|
|
287
|
-
/**
|
|
288
|
-
* No-op for piggyback — tick happens on next request.
|
|
289
|
-
*/
|
|
290
|
-
reschedule() {}
|
|
291
|
-
/**
|
|
292
|
-
* Call this from middleware on each request.
|
|
293
|
-
* Debounced: only actually ticks if enough time has passed.
|
|
294
|
-
*/
|
|
295
|
-
onRequest() {
|
|
296
|
-
if (!this.running) return;
|
|
297
|
-
const now = Date.now();
|
|
298
|
-
if (now - this.lastTickAt < DEBOUNCE_MS) return;
|
|
299
|
-
this.lastTickAt = now;
|
|
300
|
-
const tasks = [this.executor.tick(), this.executor.recoverStaleLocks()];
|
|
301
|
-
if (this.systemCleanup) tasks.push(this.systemCleanup());
|
|
302
|
-
Promise.allSettled(tasks).then((results) => {
|
|
303
|
-
for (const r of results) if (r.status === "rejected") console.error("[cron:piggyback] Tick task failed:", r.reason);
|
|
304
|
-
});
|
|
311
|
+
}
|
|
312
|
+
} catch (error) {
|
|
313
|
+
console.error(`[scheduled-publish] Sweep failed for "${collection.slug}":`, error);
|
|
305
314
|
}
|
|
306
|
-
|
|
315
|
+
return published;
|
|
316
|
+
}
|
|
307
317
|
|
|
308
318
|
//#endregion
|
|
309
319
|
//#region src/emdash-runtime.ts
|
|
@@ -381,8 +391,35 @@ const FIELD_TYPE_TO_KIND = {
|
|
|
381
391
|
function contentItemToRecord(item) {
|
|
382
392
|
return { ...item };
|
|
383
393
|
}
|
|
384
|
-
|
|
385
|
-
|
|
394
|
+
/**
|
|
395
|
+
* Db init lock reclaim deadline. Derived from the migration race wait so
|
|
396
|
+
* they can't drift apart: a healthy init can legitimately block for the
|
|
397
|
+
* full MIGRATION_RACE_WAIT_MS inside waitForConcurrentMigrator, plus cold
|
|
398
|
+
* connect and migrator work, before it should be presumed dead. The outer
|
|
399
|
+
* runtime init lock (middleware.ts) must use a strictly larger deadline —
|
|
400
|
+
* it wraps create() → getDatabase() → this lock, and equal deadlines would
|
|
401
|
+
* let the outer reclaim while the inner is legitimately still working.
|
|
402
|
+
*/
|
|
403
|
+
const DB_INIT_DEADLINE_MS = MIGRATION_RACE_WAIT_MS + 2e4;
|
|
404
|
+
/**
|
|
405
|
+
* Db cache + its init lock live on globalThis behind a Symbol: the bundler
|
|
406
|
+
* can duplicate this module across SSR chunks (same reasoning as
|
|
407
|
+
* request-cache.ts), and a duplicated cache/lock would mean concurrent
|
|
408
|
+
* independent db inits — and duplicate migrators — per isolate.
|
|
409
|
+
*/
|
|
410
|
+
const DB_HOLDER_KEY = Symbol.for("emdash:db-cache");
|
|
411
|
+
const globalSymbolStore = globalThis;
|
|
412
|
+
function getDbHolder() {
|
|
413
|
+
let holder = globalSymbolStore[DB_HOLDER_KEY];
|
|
414
|
+
if (!holder) {
|
|
415
|
+
holder = {
|
|
416
|
+
cache: /* @__PURE__ */ new Map(),
|
|
417
|
+
lock: createInitLock()
|
|
418
|
+
};
|
|
419
|
+
globalSymbolStore[DB_HOLDER_KEY] = holder;
|
|
420
|
+
}
|
|
421
|
+
return holder;
|
|
422
|
+
}
|
|
386
423
|
const storageCache = /* @__PURE__ */ new Map();
|
|
387
424
|
const sandboxedPluginCache = /* @__PURE__ */ new Map();
|
|
388
425
|
/**
|
|
@@ -495,12 +532,54 @@ var EmDashRuntime = class EmDashRuntime {
|
|
|
495
532
|
return this.runtimeDeps.sandboxBypassed === true;
|
|
496
533
|
}
|
|
497
534
|
/**
|
|
498
|
-
*
|
|
499
|
-
*
|
|
500
|
-
* execute even when no dedicated scheduler is available.
|
|
535
|
+
* Publish any content whose scheduled time has passed.
|
|
536
|
+
* Returns the items promoted so callers can invalidate their cache tags.
|
|
501
537
|
*/
|
|
502
|
-
|
|
503
|
-
|
|
538
|
+
async publishScheduled() {
|
|
539
|
+
return publishDueContent(this.db, { publish: (collection, id, options) => this.handleContentPublish(collection, id, options) });
|
|
540
|
+
}
|
|
541
|
+
/**
|
|
542
|
+
* Run the full scheduled-maintenance batch: cron tasks, scheduled
|
|
543
|
+
* publishing, and system cleanup. For request-less drivers — the
|
|
544
|
+
* Cloudflare `scheduled()` handler invokes this from a Cron Trigger.
|
|
545
|
+
* (On Node the timer-based scheduler drives the same work itself.)
|
|
546
|
+
*
|
|
547
|
+
* Each step is independent and non-fatal. Returns the content promoted
|
|
548
|
+
* by the publishing sweep so the caller can purge edge-cache tags.
|
|
549
|
+
*
|
|
550
|
+
* `onPublished` (optional) is awaited after each collection's batch so a
|
|
551
|
+
* request-less driver can invalidate edge-cache tags incrementally rather
|
|
552
|
+
* than only after the whole sweep — bounding stale-cache exposure if the
|
|
553
|
+
* runtime is killed mid-sweep.
|
|
554
|
+
*/
|
|
555
|
+
async runScheduledTasks(options = {}) {
|
|
556
|
+
if (this.cronExecutor) {
|
|
557
|
+
try {
|
|
558
|
+
await this.cronExecutor.tick();
|
|
559
|
+
} catch (error) {
|
|
560
|
+
console.error("[cron] Tick failed:", error);
|
|
561
|
+
}
|
|
562
|
+
try {
|
|
563
|
+
await this.cronExecutor.recoverStaleLocks();
|
|
564
|
+
} catch (error) {
|
|
565
|
+
console.error("[cron] Stale lock recovery failed:", error);
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
let published = [];
|
|
569
|
+
try {
|
|
570
|
+
published = await publishDueContent(this.db, {
|
|
571
|
+
publish: (collection, id, opts) => this.handleContentPublish(collection, id, opts),
|
|
572
|
+
onPublished: options.onPublished
|
|
573
|
+
});
|
|
574
|
+
} catch (error) {
|
|
575
|
+
console.error("[scheduled-publish] Sweep failed:", error);
|
|
576
|
+
}
|
|
577
|
+
try {
|
|
578
|
+
await runSystemCleanup(this.db, this.storage ?? void 0);
|
|
579
|
+
} catch (error) {
|
|
580
|
+
console.error("[cleanup] System cleanup failed:", error);
|
|
581
|
+
}
|
|
582
|
+
return { published };
|
|
504
583
|
}
|
|
505
584
|
/**
|
|
506
585
|
* Stop the cron scheduler gracefully.
|
|
@@ -795,19 +874,13 @@ var EmDashRuntime = class EmDashRuntime {
|
|
|
795
874
|
await phase("rt.secrets", "Validate encryption key", () => validateEncryptionKeyAtStartup());
|
|
796
875
|
const storage = EmDashRuntime.getStorage(deps);
|
|
797
876
|
let pluginStates = /* @__PURE__ */ new Map();
|
|
798
|
-
|
|
877
|
+
let siteInfo;
|
|
878
|
+
await Promise.all([phase("rt.plugins", "Plugin states", async () => {
|
|
799
879
|
try {
|
|
800
880
|
const states = await db.selectFrom("_plugin_state").select(["plugin_id", "status"]).execute();
|
|
801
881
|
pluginStates = new Map(states.map((s) => [s.plugin_id, s.status]));
|
|
802
882
|
} catch {}
|
|
803
|
-
})
|
|
804
|
-
const enabledPlugins = /* @__PURE__ */ new Set();
|
|
805
|
-
for (const plugin of deps.plugins) {
|
|
806
|
-
const status = pluginStates.get(plugin.id);
|
|
807
|
-
if (status === void 0 || status === "active") enabledPlugins.add(plugin.id);
|
|
808
|
-
}
|
|
809
|
-
let siteInfo;
|
|
810
|
-
await phase("rt.site", "Site info options", async () => {
|
|
883
|
+
}), phase("rt.site", "Site info options", async () => {
|
|
811
884
|
try {
|
|
812
885
|
const siteOpts = await new OptionsRepository(db).getMany([
|
|
813
886
|
"emdash:site_title",
|
|
@@ -820,7 +893,12 @@ var EmDashRuntime = class EmDashRuntime {
|
|
|
820
893
|
locale: siteOpts.get("emdash:locale") ?? void 0
|
|
821
894
|
};
|
|
822
895
|
} catch {}
|
|
823
|
-
});
|
|
896
|
+
})]);
|
|
897
|
+
const enabledPlugins = /* @__PURE__ */ new Set();
|
|
898
|
+
for (const plugin of deps.plugins) {
|
|
899
|
+
const status = pluginStates.get(plugin.id);
|
|
900
|
+
if (status === void 0 || status === "active") enabledPlugins.add(plugin.id);
|
|
901
|
+
}
|
|
824
902
|
const allPipelinePlugins = [...deps.plugins];
|
|
825
903
|
const bypassedPluginsList = [];
|
|
826
904
|
if (import.meta.env.DEV) try {
|
|
@@ -881,8 +959,10 @@ var EmDashRuntime = class EmDashRuntime {
|
|
|
881
959
|
};
|
|
882
960
|
const pipeline = createHookPipeline(enabledPluginList, pipelineFactoryOptions);
|
|
883
961
|
const sandboxedPlugins = await phase("rt.sandbox", "Sandboxed plugins", () => EmDashRuntime.loadSandboxedPlugins(deps, db, storage));
|
|
884
|
-
|
|
885
|
-
if (deps.config.
|
|
962
|
+
const installedTierPhases = [];
|
|
963
|
+
if (deps.config.marketplace && storage && !deps.sandboxBypassed) installedTierPhases.push(phase("rt.market", "Marketplace plugins", () => EmDashRuntime.loadInstalledSandboxedPlugins("marketplace", db, storage, deps, sandboxedPlugins)));
|
|
964
|
+
if (deps.config.experimental?.registry && storage) installedTierPhases.push(phase("rt.registry", "Registry plugins", () => EmDashRuntime.loadInstalledSandboxedPlugins("registry", db, storage, deps, sandboxedPlugins)));
|
|
965
|
+
if (installedTierPhases.length > 0) await Promise.all(installedTierPhases);
|
|
886
966
|
const mediaProviders = /* @__PURE__ */ new Map();
|
|
887
967
|
const mediaProviderEntries = deps.mediaProviderEntries ?? [];
|
|
888
968
|
const providerContext = {
|
|
@@ -909,6 +989,7 @@ var EmDashRuntime = class EmDashRuntime {
|
|
|
909
989
|
});
|
|
910
990
|
let cronExecutor = null;
|
|
911
991
|
let cronScheduler = null;
|
|
992
|
+
const runtimeRef = { current: null };
|
|
912
993
|
await phase("rt.cron", "Cron init (recovery deferred post-response)", async () => {
|
|
913
994
|
try {
|
|
914
995
|
cronExecutor = new CronExecutor(db, invokeCronHook);
|
|
@@ -921,22 +1002,30 @@ var EmDashRuntime = class EmDashRuntime {
|
|
|
921
1002
|
console.error("[cron] Failed to recover stale task locks:", error);
|
|
922
1003
|
}
|
|
923
1004
|
});
|
|
924
|
-
if (
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
1005
|
+
if (deps.createScheduler) {
|
|
1006
|
+
const scheduler = deps.createScheduler(cronExecutor);
|
|
1007
|
+
cronScheduler = scheduler;
|
|
1008
|
+
scheduler.setSystemCleanup(async () => {
|
|
1009
|
+
try {
|
|
1010
|
+
const runtime = runtimeRef.current;
|
|
1011
|
+
await publishDueContent(db, { publish: runtime ? (collection, id, options) => runtime.handleContentPublish(collection, id, options) : void 0 });
|
|
1012
|
+
} catch (error) {
|
|
1013
|
+
console.error("[scheduled-publish] Sweep failed:", error);
|
|
1014
|
+
}
|
|
1015
|
+
try {
|
|
1016
|
+
await runSystemCleanup(db, storage ?? void 0);
|
|
1017
|
+
} catch (error) {
|
|
1018
|
+
console.error("[cleanup] System cleanup failed:", error);
|
|
1019
|
+
}
|
|
1020
|
+
});
|
|
1021
|
+
pipeline.setContextFactory({ cronReschedule: () => cronScheduler?.reschedule() });
|
|
1022
|
+
scheduler.start();
|
|
1023
|
+
}
|
|
935
1024
|
} catch (error) {
|
|
936
1025
|
console.warn("[cron] Failed to initialize cron system:", error);
|
|
937
1026
|
}
|
|
938
1027
|
});
|
|
939
|
-
|
|
1028
|
+
const runtime = new EmDashRuntime({
|
|
940
1029
|
db,
|
|
941
1030
|
storage,
|
|
942
1031
|
configuredPlugins: [...deps.plugins, ...bypassedPluginsList],
|
|
@@ -956,6 +1045,8 @@ var EmDashRuntime = class EmDashRuntime {
|
|
|
956
1045
|
runtimeDeps: deps,
|
|
957
1046
|
pipelineRef
|
|
958
1047
|
});
|
|
1048
|
+
runtimeRef.current = runtime;
|
|
1049
|
+
return runtime;
|
|
959
1050
|
}
|
|
960
1051
|
/**
|
|
961
1052
|
* Get a media provider by ID
|
|
@@ -987,10 +1078,8 @@ var EmDashRuntime = class EmDashRuntime {
|
|
|
987
1078
|
throw new Error("EmDash database not configured. Either configure database in astro.config.mjs or use emdashLoader in live.config.ts");
|
|
988
1079
|
}
|
|
989
1080
|
const cacheKey = dbConfig.entrypoint;
|
|
990
|
-
const
|
|
991
|
-
|
|
992
|
-
if (dbInitPromise) return dbInitPromise;
|
|
993
|
-
dbInitPromise = (async () => {
|
|
1081
|
+
const holder = getDbHolder();
|
|
1082
|
+
return initWithLock(holder.lock, () => holder.cache.get(cacheKey), async (isCurrentClaim) => {
|
|
994
1083
|
const db = new Kysely({
|
|
995
1084
|
dialect: deps.createDialect(dbConfig.config),
|
|
996
1085
|
log: kyselyLogOption()
|
|
@@ -1006,9 +1095,9 @@ var EmDashRuntime = class EmDashRuntime {
|
|
|
1006
1095
|
}
|
|
1007
1096
|
})();
|
|
1008
1097
|
if (collectionCount.count === 0 && !setupDone) {
|
|
1009
|
-
const { applySeed } = await import("../apply-
|
|
1010
|
-
const { loadSeed } = await import("../load-
|
|
1011
|
-
const { validateSeed } = await import("../validate-
|
|
1098
|
+
const { applySeed } = await import("../apply-hQkKKBCf.mjs").then((n) => n.n);
|
|
1099
|
+
const { loadSeed } = await import("../load-B84ohfBk.mjs").then((n) => n.r);
|
|
1100
|
+
const { validateSeed } = await import("../validate-ZP9Dvg0P.mjs").then((n) => n.n);
|
|
1012
1101
|
const seed = await loadSeed();
|
|
1013
1102
|
if (validateSeed(seed).valid) {
|
|
1014
1103
|
await applySeed(db, seed, { onConflict: "skip" });
|
|
@@ -1016,14 +1105,12 @@ var EmDashRuntime = class EmDashRuntime {
|
|
|
1016
1105
|
}
|
|
1017
1106
|
}
|
|
1018
1107
|
} catch {}
|
|
1019
|
-
|
|
1108
|
+
if (isCurrentClaim()) holder.cache.set(cacheKey, db);
|
|
1020
1109
|
return db;
|
|
1021
|
-
}
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
}
|
|
1025
|
-
dbInitPromise = null;
|
|
1026
|
-
}
|
|
1110
|
+
}, {
|
|
1111
|
+
deadlineMs: DB_INIT_DEADLINE_MS,
|
|
1112
|
+
anchor: (promise) => after(() => promise)
|
|
1113
|
+
});
|
|
1027
1114
|
}
|
|
1028
1115
|
/**
|
|
1029
1116
|
* Get or create storage instance
|
|
@@ -1282,6 +1369,7 @@ var EmDashRuntime = class EmDashRuntime {
|
|
|
1282
1369
|
pipeline,
|
|
1283
1370
|
isActive: () => true,
|
|
1284
1371
|
getOption: (key) => optionsRepo.get(key),
|
|
1372
|
+
getOptions: (keys) => optionsRepo.getMany(keys),
|
|
1285
1373
|
setOption: (key, value) => optionsRepo.set(key, value),
|
|
1286
1374
|
deleteOption: async (key) => {
|
|
1287
1375
|
await optionsRepo.delete(key);
|
|
@@ -1484,6 +1572,9 @@ var EmDashRuntime = class EmDashRuntime {
|
|
|
1484
1572
|
async handleContentList(collection, params) {
|
|
1485
1573
|
return handleContentList(this.db, collection, params);
|
|
1486
1574
|
}
|
|
1575
|
+
async handleContentAuthors(collection) {
|
|
1576
|
+
return handleContentAuthors(this.db, collection);
|
|
1577
|
+
}
|
|
1487
1578
|
async handleContentGet(collection, id, locale) {
|
|
1488
1579
|
const result = await handleContentGet(this.db, collection, id, locale);
|
|
1489
1580
|
return this.hydrateDraftData(result);
|
|
@@ -1540,7 +1631,7 @@ var EmDashRuntime = class EmDashRuntime {
|
|
|
1540
1631
|
if (this.hooks.hasHooks("content:beforeSave")) processedData = (await this.hooks.runContentBeforeSave(body.data, collection, true)).content;
|
|
1541
1632
|
processedData = await this.runSandboxedBeforeSave(processedData, collection, true);
|
|
1542
1633
|
processedData = await this.normalizeMediaFields(collection, processedData);
|
|
1543
|
-
const { validateContentData } = await import("../validation-
|
|
1634
|
+
const { validateContentData } = await import("../validation-CE5i4q0c.mjs");
|
|
1544
1635
|
const validation = await validateContentData(this.db, collection, processedData, { partial: false });
|
|
1545
1636
|
if (!validation.ok) return {
|
|
1546
1637
|
success: false,
|
|
@@ -1556,7 +1647,7 @@ var EmDashRuntime = class EmDashRuntime {
|
|
|
1556
1647
|
return result;
|
|
1557
1648
|
}
|
|
1558
1649
|
async handleContentUpdate(collection, id, body) {
|
|
1559
|
-
const { ContentRepository } = await import("../content-
|
|
1650
|
+
const { ContentRepository } = await import("../content-BIlVx-RX.mjs").then((n) => n.n);
|
|
1560
1651
|
const repo = new ContentRepository(this.db);
|
|
1561
1652
|
const resolvedItem = await repo.findByIdOrSlug(collection, id, body.locale);
|
|
1562
1653
|
const resolvedId = resolvedItem?.id ?? id;
|
|
@@ -1583,7 +1674,7 @@ var EmDashRuntime = class EmDashRuntime {
|
|
|
1583
1674
|
if (this.hooks.hasHooks("content:beforeSave")) processedData = (await this.hooks.runContentBeforeSave(bodyWithoutRev.data, collection, false)).content;
|
|
1584
1675
|
processedData = await this.runSandboxedBeforeSave(processedData, collection, false);
|
|
1585
1676
|
processedData = await this.normalizeMediaFields(collection, processedData);
|
|
1586
|
-
const { validateContentData } = await import("../validation-
|
|
1677
|
+
const { validateContentData } = await import("../validation-CE5i4q0c.mjs");
|
|
1587
1678
|
const validation = await validateContentData(this.db, collection, processedData, { partial: true });
|
|
1588
1679
|
if (!validation.ok) return {
|
|
1589
1680
|
success: false,
|
|
@@ -2123,6 +2214,70 @@ function createPublicMediaUrlResolver(storage) {
|
|
|
2123
2214
|
return (key) => resolvePublicMediaUrl(storage, key);
|
|
2124
2215
|
}
|
|
2125
2216
|
|
|
2217
|
+
//#endregion
|
|
2218
|
+
//#region src/astro/middleware/stream-end-metrics.ts
|
|
2219
|
+
/**
|
|
2220
|
+
* Stream-end metrics
|
|
2221
|
+
*
|
|
2222
|
+
* Server-Timing db.* counters are snapshotted when middleware's next()
|
|
2223
|
+
* returns — but at that point only the response *headers* are final.
|
|
2224
|
+
* Astro streams the body afterwards, and components rendered during
|
|
2225
|
+
* streaming issue further DB queries that the headers can never report.
|
|
2226
|
+
*
|
|
2227
|
+
* This module wraps the response body in an identity TransformStream and
|
|
2228
|
+
* snapshots the request metrics in flush(), i.e. when the body actually
|
|
2229
|
+
* finishes streaming. The metrics object lives on the request context
|
|
2230
|
+
* (AsyncLocalStorage) and is mutated in-place by the Kysely log hook, so
|
|
2231
|
+
* a reference captured before wrapping observes every post-header query.
|
|
2232
|
+
* The snapshot is emitted as prefixed NDJSON on stdout (same transport as
|
|
2233
|
+
* [emdash-query-log] — console.log works in both Node and workerd).
|
|
2234
|
+
*
|
|
2235
|
+
* Gated on isInstrumentationEnabled() (EMDASH_QUERY_LOG=1): zero overhead
|
|
2236
|
+
* in normal production traffic.
|
|
2237
|
+
*/
|
|
2238
|
+
const STREAM_END_PREFIX = "[emdash-stream-end]";
|
|
2239
|
+
/**
|
|
2240
|
+
* Astro attaches AstroCookies to outgoing responses via a well-known global
|
|
2241
|
+
* symbol. Constructing a new Response drops non-header metadata, so the
|
|
2242
|
+
* symbol must be forwarded explicitly or `cookies.set()` calls are silently
|
|
2243
|
+
* dropped. Same pattern as finalizeResponse in ../middleware.ts.
|
|
2244
|
+
*/
|
|
2245
|
+
const ASTRO_COOKIES_SYMBOL$1 = Symbol.for("astro.cookies");
|
|
2246
|
+
/**
|
|
2247
|
+
* Wrap a response body so the FINAL request metrics are emitted when the
|
|
2248
|
+
* body finishes streaming. Returns the response unchanged when
|
|
2249
|
+
* instrumentation is disabled, the body is null, or no request metrics
|
|
2250
|
+
* are attached (e.g. outside the middleware's ALS context).
|
|
2251
|
+
*/
|
|
2252
|
+
function wrapBodyForStreamMetrics(response) {
|
|
2253
|
+
if (!isInstrumentationEnabled()) return response;
|
|
2254
|
+
if (!response.body) return response;
|
|
2255
|
+
const ctx = getRequestContext();
|
|
2256
|
+
const metrics = ctx?.metrics;
|
|
2257
|
+
if (!metrics) return response;
|
|
2258
|
+
const recorder = ctx?.queryRecorder;
|
|
2259
|
+
const transform = new TransformStream({ flush() {
|
|
2260
|
+
const snapshot = {
|
|
2261
|
+
route: recorder?.route,
|
|
2262
|
+
method: recorder?.method,
|
|
2263
|
+
phase: recorder?.phase,
|
|
2264
|
+
totalMs: performance.now() - metrics.start,
|
|
2265
|
+
dbCount: metrics.dbCount,
|
|
2266
|
+
dbTotalMs: metrics.dbTotalMs,
|
|
2267
|
+
dbFirstOffset: metrics.dbFirstOffset,
|
|
2268
|
+
dbLastOffset: metrics.dbLastOffset,
|
|
2269
|
+
cacheHits: metrics.cacheHits,
|
|
2270
|
+
cacheMisses: metrics.cacheMisses
|
|
2271
|
+
};
|
|
2272
|
+
console.log(`${STREAM_END_PREFIX} ${JSON.stringify(snapshot)}`);
|
|
2273
|
+
} });
|
|
2274
|
+
const wrapped = new Response(response.body.pipeThrough(transform), response);
|
|
2275
|
+
const astroCookies = Reflect.get(response, ASTRO_COOKIES_SYMBOL$1);
|
|
2276
|
+
if (astroCookies !== void 0) Reflect.set(wrapped, ASTRO_COOKIES_SYMBOL$1, astroCookies);
|
|
2277
|
+
wrapped.headers.delete("Content-Length");
|
|
2278
|
+
return wrapped;
|
|
2279
|
+
}
|
|
2280
|
+
|
|
2126
2281
|
//#endregion
|
|
2127
2282
|
//#region src/astro/public-plugin-api-routes.ts
|
|
2128
2283
|
function pluginRouteNotFound() {
|
|
@@ -2149,10 +2304,14 @@ function createPublicPluginApiRouteHandler(runtime) {
|
|
|
2149
2304
|
* Thin wrapper that initializes EmDashRuntime and attaches it to locals.
|
|
2150
2305
|
* All heavy lifting happens in EmDashRuntime.
|
|
2151
2306
|
*/
|
|
2152
|
-
|
|
2153
|
-
|
|
2154
|
-
|
|
2155
|
-
let
|
|
2307
|
+
/**
|
|
2308
|
+
* Runtime init lock reclaim deadline. Must be strictly larger than the db
|
|
2309
|
+
* init deadline: this lock wraps EmDashRuntime.create() → getDatabase() →
|
|
2310
|
+
* the db init lock, and equal deadlines would let this outer lock reclaim
|
|
2311
|
+
* (spawning a second cron scheduler and sandbox runner) while the inner db
|
|
2312
|
+
* init is legitimately still working through a contended migration.
|
|
2313
|
+
*/
|
|
2314
|
+
const RUNTIME_INIT_DEADLINE_MS = DB_INIT_DEADLINE_MS + 15e3;
|
|
2156
2315
|
/**
|
|
2157
2316
|
* Whether we've verified the database has been set up.
|
|
2158
2317
|
* On a fresh deployment the first request may hit a public page, bypassing
|
|
@@ -2177,6 +2336,27 @@ function markSetupVerified() {
|
|
|
2177
2336
|
setupFlagStore[SETUP_VERIFIED_KEY] = true;
|
|
2178
2337
|
}
|
|
2179
2338
|
/**
|
|
2339
|
+
* The runtime singleton and its init lock live on globalThis behind a
|
|
2340
|
+
* Symbol — same reasoning as SETUP_VERIFIED_KEY above: the bundler can
|
|
2341
|
+
* duplicate this module across SSR chunks, and a duplicated instance/lock
|
|
2342
|
+
* would mean multiple runtimes (each with its own cron scheduler) per
|
|
2343
|
+
* isolate, initializing and reclaiming independently.
|
|
2344
|
+
*/
|
|
2345
|
+
const RUNTIME_HOLDER_KEY = Symbol.for("emdash:runtime-holder");
|
|
2346
|
+
function getRuntimeHolder() {
|
|
2347
|
+
let holder = setupFlagStore[RUNTIME_HOLDER_KEY];
|
|
2348
|
+
if (!holder) {
|
|
2349
|
+
holder = {
|
|
2350
|
+
instance: null,
|
|
2351
|
+
lock: createInitLock()
|
|
2352
|
+
};
|
|
2353
|
+
setupFlagStore[RUNTIME_HOLDER_KEY] = holder;
|
|
2354
|
+
}
|
|
2355
|
+
return holder;
|
|
2356
|
+
}
|
|
2357
|
+
/** Whether i18n config has been initialized from the virtual module */
|
|
2358
|
+
let i18nInitialized = false;
|
|
2359
|
+
/**
|
|
2180
2360
|
* Get EmDash configuration from virtual module
|
|
2181
2361
|
*/
|
|
2182
2362
|
function getConfig() {
|
|
@@ -2207,6 +2387,7 @@ function buildDependencies(config) {
|
|
|
2207
2387
|
plugins: getPlugins(),
|
|
2208
2388
|
createDialect,
|
|
2209
2389
|
createStorage,
|
|
2390
|
+
createScheduler,
|
|
2210
2391
|
sandboxEnabled: sandboxModule.sandboxEnabled,
|
|
2211
2392
|
sandboxBypassed: sandboxModule.sandboxBypassed ?? false,
|
|
2212
2393
|
sandboxedPluginEntries: sandboxedPlugins || [],
|
|
@@ -2223,20 +2404,38 @@ function buildDependencies(config) {
|
|
|
2223
2404
|
* as "warm, nothing to report".
|
|
2224
2405
|
*/
|
|
2225
2406
|
async function getRuntime(config, initTimings) {
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
await new Promise((resolve) => setTimeout(resolve, 50));
|
|
2229
|
-
return getRuntime(config, initTimings);
|
|
2230
|
-
}
|
|
2231
|
-
runtimeInitializing = true;
|
|
2232
|
-
try {
|
|
2407
|
+
const holder = getRuntimeHolder();
|
|
2408
|
+
return initWithLock(holder.lock, () => holder.instance, async (isCurrentClaim) => {
|
|
2233
2409
|
const deps = buildDependencies(config);
|
|
2234
2410
|
const runtime = await EmDashRuntime.create(deps, initTimings);
|
|
2235
|
-
|
|
2411
|
+
if (isCurrentClaim()) holder.instance = runtime;
|
|
2412
|
+
else runtime.stopCron().catch((error) => {
|
|
2413
|
+
console.error("[emdash] failed to stop superseded runtime's cron:", error);
|
|
2414
|
+
});
|
|
2236
2415
|
return runtime;
|
|
2237
|
-
}
|
|
2238
|
-
|
|
2239
|
-
|
|
2416
|
+
}, {
|
|
2417
|
+
deadlineMs: RUNTIME_INIT_DEADLINE_MS,
|
|
2418
|
+
anchor: (promise) => after(() => promise)
|
|
2419
|
+
});
|
|
2420
|
+
}
|
|
2421
|
+
/**
|
|
2422
|
+
* Run scheduled maintenance (cron tasks, scheduled publishing, system cleanup)
|
|
2423
|
+
* outside any request. Resolves the runtime from the build-time virtual config
|
|
2424
|
+
* and the cached singleton — the same instance request handlers use.
|
|
2425
|
+
*
|
|
2426
|
+
* Wired into a platform heartbeat that is not a request: the Cloudflare Worker's
|
|
2427
|
+
* `scheduled()` handler (Cron Trigger) calls this. On Node the runtime's own
|
|
2428
|
+
* timer-based scheduler already drives the same work, so this isn't needed there.
|
|
2429
|
+
*
|
|
2430
|
+
* Returns the content promoted by the publishing sweep so the caller can purge
|
|
2431
|
+
* edge-cache tags for it. `onPublished` (optional) is awaited after each
|
|
2432
|
+
* collection's batch so the caller can invalidate edge-cache tags incrementally
|
|
2433
|
+
* rather than only after the whole sweep.
|
|
2434
|
+
*/
|
|
2435
|
+
async function runScheduledTasks(options = {}) {
|
|
2436
|
+
const config = getConfig();
|
|
2437
|
+
if (!config) return { published: [] };
|
|
2438
|
+
return (await getRuntime(config)).runScheduledTasks(options);
|
|
2240
2439
|
}
|
|
2241
2440
|
/**
|
|
2242
2441
|
* Astro attaches AstroCookies to outgoing responses via a well-known global
|
|
@@ -2342,7 +2541,7 @@ const onRequest = defineMiddleware(async (context, next) => {
|
|
|
2342
2541
|
if (!isSetupVerified()) {
|
|
2343
2542
|
const t0 = performance.now();
|
|
2344
2543
|
try {
|
|
2345
|
-
const { getDb } = await import("../loader-
|
|
2544
|
+
const { getDb } = await import("../loader-CpZKpFz0.mjs").then((n) => n.i);
|
|
2346
2545
|
await (await getDb()).selectFrom("_emdash_migrations").selectAll().limit(1).execute();
|
|
2347
2546
|
markSetupVerified();
|
|
2348
2547
|
} catch (error) {
|
|
@@ -2397,7 +2596,7 @@ const onRequest = defineMiddleware(async (context, next) => {
|
|
|
2397
2596
|
desc: "Total middleware"
|
|
2398
2597
|
});
|
|
2399
2598
|
pushMetricsTimings(timings, metrics);
|
|
2400
|
-
return finalizeResponse(response, timings);
|
|
2599
|
+
return wrapBodyForStreamMetrics(finalizeResponse(response, timings));
|
|
2401
2600
|
};
|
|
2402
2601
|
if (anonScoped) {
|
|
2403
2602
|
const parent = getRequestContext();
|
|
@@ -2511,7 +2710,7 @@ const onRequest = defineMiddleware(async (context, next) => {
|
|
|
2511
2710
|
desc: "Total middleware"
|
|
2512
2711
|
});
|
|
2513
2712
|
pushMetricsTimings(timings, metrics);
|
|
2514
|
-
return finalizeResponse(response, timings);
|
|
2713
|
+
return wrapBodyForStreamMetrics(finalizeResponse(response, timings));
|
|
2515
2714
|
};
|
|
2516
2715
|
if (scoped) {
|
|
2517
2716
|
const parent = getRequestContext();
|
|
@@ -2559,5 +2758,5 @@ const onRequest = defineMiddleware(async (context, next) => {
|
|
|
2559
2758
|
});
|
|
2560
2759
|
|
|
2561
2760
|
//#endregion
|
|
2562
|
-
export { onRequest as default, onRequest };
|
|
2761
|
+
export { onRequest as default, onRequest, runScheduledTasks };
|
|
2563
2762
|
//# sourceMappingURL=middleware.mjs.map
|