emdash 0.19.0 → 0.21.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{adapters-C5AWLJSD.d.mts → adapters-BxSmgtbF.d.mts} +1 -1
- package/dist/{adapters-C5AWLJSD.d.mts.map → adapters-BxSmgtbF.d.mts.map} +1 -1
- package/dist/{allowed-origins-CyYLEJkp.mjs → allowed-origins-BqC8cul8.mjs} +2 -2
- package/dist/{allowed-origins-CyYLEJkp.mjs.map → allowed-origins-BqC8cul8.mjs.map} +1 -1
- package/dist/api/route-utils.d.mts +3 -3
- package/dist/api/route-utils.mjs +13 -12
- package/dist/api/route-utils.mjs.map +1 -1
- package/dist/api/schemas/index.d.mts +1 -1
- package/dist/api/schemas/index.mjs +3 -2
- package/dist/{api-BZ6bhjYs.mjs → api-DxjIV2o8.mjs} +46 -15
- package/dist/api-DxjIV2o8.mjs.map +1 -0
- package/dist/{api-tokens-VrXNiNvV.mjs → api-tokens-BFFkB0jB.mjs} +2 -2
- package/dist/{api-tokens-VrXNiNvV.mjs.map → api-tokens-BFFkB0jB.mjs.map} +1 -1
- package/dist/{apply-hQkKKBCf.mjs → apply-CLjxheyb.mjs} +12 -12
- package/dist/{apply-hQkKKBCf.mjs.map → apply-CLjxheyb.mjs.map} +1 -1
- package/dist/astro/index.d.mts +10 -10
- package/dist/astro/index.d.mts.map +1 -1
- package/dist/astro/index.mjs +50 -15
- package/dist/astro/index.mjs.map +1 -1
- package/dist/astro/middleware/auth.d.mts +9 -9
- package/dist/astro/middleware/auth.mjs +5 -5
- package/dist/astro/middleware/redirect.d.mts.map +1 -1
- package/dist/astro/middleware/redirect.mjs +11 -2
- package/dist/astro/middleware/redirect.mjs.map +1 -1
- package/dist/astro/middleware/request-context.mjs +3 -2
- package/dist/astro/middleware/request-context.mjs.map +1 -1
- package/dist/astro/middleware/setup.mjs +1 -1
- package/dist/astro/middleware.d.mts +1 -1
- package/dist/astro/middleware.d.mts.map +1 -1
- package/dist/astro/middleware.mjs +91 -137
- package/dist/astro/middleware.mjs.map +1 -1
- package/dist/astro/routes/api/admin/allowed-domains/_domain_.mjs +5 -4
- package/dist/astro/routes/api/admin/allowed-domains/_domain_.mjs.map +1 -1
- package/dist/astro/routes/api/admin/allowed-domains/index.mjs +5 -4
- package/dist/astro/routes/api/admin/allowed-domains/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/api-tokens/_id_.mjs +3 -3
- package/dist/astro/routes/api/admin/api-tokens/index.mjs +4 -4
- package/dist/astro/routes/api/admin/byline-fields/_slug_/usage.mjs +4 -4
- package/dist/astro/routes/api/admin/byline-fields/_slug_.mjs +8 -7
- package/dist/astro/routes/api/admin/byline-fields/_slug_.mjs.map +1 -1
- package/dist/astro/routes/api/admin/byline-fields/index.mjs +8 -7
- package/dist/astro/routes/api/admin/byline-fields/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/byline-fields/reorder.mjs +8 -7
- package/dist/astro/routes/api/admin/byline-fields/reorder.mjs.map +1 -1
- package/dist/astro/routes/api/admin/bylines/_id_/index.mjs +14 -12
- package/dist/astro/routes/api/admin/bylines/_id_/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/bylines/_id_/translations.mjs +14 -12
- package/dist/astro/routes/api/admin/bylines/_id_/translations.mjs.map +1 -1
- package/dist/astro/routes/api/admin/bylines/index.mjs +14 -12
- package/dist/astro/routes/api/admin/bylines/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/comments/_id_/status.mjs +9 -8
- package/dist/astro/routes/api/admin/comments/_id_/status.mjs.map +1 -1
- package/dist/astro/routes/api/admin/comments/_id_.mjs +3 -3
- package/dist/astro/routes/api/admin/comments/bulk.mjs +7 -6
- package/dist/astro/routes/api/admin/comments/bulk.mjs.map +1 -1
- package/dist/astro/routes/api/admin/comments/counts.mjs +3 -3
- package/dist/astro/routes/api/admin/comments/index.mjs +7 -6
- package/dist/astro/routes/api/admin/comments/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/hooks/exclusive/_hookName_.mjs +3 -3
- package/dist/astro/routes/api/admin/hooks/exclusive/index.mjs +2 -2
- 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 +29 -27
- package/dist/astro/routes/api/admin/plugins/_id_/disable.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/_id_/enable.mjs +29 -27
- package/dist/astro/routes/api/admin/plugins/_id_/enable.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/_id_/index.mjs +28 -26
- package/dist/astro/routes/api/admin/plugins/_id_/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/_id_/uninstall.mjs +28 -26
- package/dist/astro/routes/api/admin/plugins/_id_/uninstall.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/_id_/update.mjs +28 -26
- package/dist/astro/routes/api/admin/plugins/_id_/update.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/index.mjs +28 -26
- package/dist/astro/routes/api/admin/plugins/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/marketplace/_id_/icon.mjs +2 -2
- package/dist/astro/routes/api/admin/plugins/marketplace/_id_/index.mjs +28 -26
- package/dist/astro/routes/api/admin/plugins/marketplace/_id_/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/marketplace/_id_/install.mjs +28 -26
- package/dist/astro/routes/api/admin/plugins/marketplace/_id_/install.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/marketplace/index.mjs +28 -26
- package/dist/astro/routes/api/admin/plugins/marketplace/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/registry/_id_/uninstall.mjs +28 -26
- package/dist/astro/routes/api/admin/plugins/registry/_id_/uninstall.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/registry/_id_/update.mjs +29 -27
- package/dist/astro/routes/api/admin/plugins/registry/_id_/update.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/registry/artifact.mjs +28 -26
- package/dist/astro/routes/api/admin/plugins/registry/artifact.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/registry/install.mjs +29 -27
- package/dist/astro/routes/api/admin/plugins/registry/install.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/updates.mjs +28 -26
- package/dist/astro/routes/api/admin/plugins/updates.mjs.map +1 -1
- package/dist/astro/routes/api/admin/themes/marketplace/_id_/index.mjs +28 -26
- package/dist/astro/routes/api/admin/themes/marketplace/_id_/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/themes/marketplace/_id_/thumbnail.mjs +2 -2
- package/dist/astro/routes/api/admin/themes/marketplace/index.mjs +28 -26
- package/dist/astro/routes/api/admin/themes/marketplace/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/users/_id_/disable.mjs +1 -1
- package/dist/astro/routes/api/admin/users/_id_/enable.mjs +1 -1
- package/dist/astro/routes/api/admin/users/_id_/index.mjs +5 -4
- package/dist/astro/routes/api/admin/users/_id_/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/users/_id_/send-recovery.mjs +2 -2
- package/dist/astro/routes/api/admin/users/index.mjs +5 -4
- package/dist/astro/routes/api/admin/users/index.mjs.map +1 -1
- package/dist/astro/routes/api/auth/dev-bypass.mjs +3 -3
- package/dist/astro/routes/api/auth/invite/accept.mjs +1 -1
- package/dist/astro/routes/api/auth/invite/complete.mjs +9 -8
- package/dist/astro/routes/api/auth/invite/complete.mjs.map +1 -1
- package/dist/astro/routes/api/auth/invite/index.mjs +6 -5
- package/dist/astro/routes/api/auth/invite/index.mjs.map +1 -1
- package/dist/astro/routes/api/auth/invite/register-options.mjs +8 -7
- package/dist/astro/routes/api/auth/invite/register-options.mjs.map +1 -1
- package/dist/astro/routes/api/auth/logout.mjs +2 -2
- package/dist/astro/routes/api/auth/magic-link/send.mjs +8 -7
- package/dist/astro/routes/api/auth/magic-link/send.mjs.map +1 -1
- package/dist/astro/routes/api/auth/magic-link/verify.mjs +2 -2
- package/dist/astro/routes/api/auth/me.mjs +5 -4
- package/dist/astro/routes/api/auth/me.mjs.map +1 -1
- package/dist/astro/routes/api/auth/mode.mjs +1 -1
- package/dist/astro/routes/api/auth/oauth/_provider_/callback.mjs +3 -3
- package/dist/astro/routes/api/auth/oauth/_provider_.mjs +2 -2
- package/dist/astro/routes/api/auth/passkey/_id_.mjs +5 -4
- package/dist/astro/routes/api/auth/passkey/_id_.mjs.map +1 -1
- package/dist/astro/routes/api/auth/passkey/index.mjs +1 -1
- package/dist/astro/routes/api/auth/passkey/options.mjs +10 -9
- package/dist/astro/routes/api/auth/passkey/options.mjs.map +1 -1
- package/dist/astro/routes/api/auth/passkey/register/options.mjs +8 -7
- package/dist/astro/routes/api/auth/passkey/register/options.mjs.map +1 -1
- package/dist/astro/routes/api/auth/passkey/register/verify.mjs +9 -8
- package/dist/astro/routes/api/auth/passkey/register/verify.mjs.map +1 -1
- package/dist/astro/routes/api/auth/passkey/verify.mjs +9 -8
- package/dist/astro/routes/api/auth/passkey/verify.mjs.map +1 -1
- package/dist/astro/routes/api/auth/signup/complete.mjs +9 -8
- package/dist/astro/routes/api/auth/signup/complete.mjs.map +1 -1
- package/dist/astro/routes/api/auth/signup/request.mjs +8 -7
- package/dist/astro/routes/api/auth/signup/request.mjs.map +1 -1
- package/dist/astro/routes/api/auth/signup/verify.mjs +1 -1
- package/dist/astro/routes/api/comments/_collection_/_contentId_/index.mjs +11 -9
- package/dist/astro/routes/api/comments/_collection_/_contentId_/index.mjs.map +1 -1
- package/dist/astro/routes/api/content/_collection_/_id_/compare.mjs +2 -2
- package/dist/astro/routes/api/content/_collection_/_id_/discard-draft.mjs +2 -2
- package/dist/astro/routes/api/content/_collection_/_id_/duplicate.mjs +2 -2
- package/dist/astro/routes/api/content/_collection_/_id_/permanent.mjs +2 -2
- package/dist/astro/routes/api/content/_collection_/_id_/preview-url.mjs +10 -8
- package/dist/astro/routes/api/content/_collection_/_id_/preview-url.mjs.map +1 -1
- package/dist/astro/routes/api/content/_collection_/_id_/publish.mjs +6 -5
- package/dist/astro/routes/api/content/_collection_/_id_/publish.mjs.map +1 -1
- package/dist/astro/routes/api/content/_collection_/_id_/restore.mjs +2 -2
- package/dist/astro/routes/api/content/_collection_/_id_/revisions.mjs +2 -2
- package/dist/astro/routes/api/content/_collection_/_id_/schedule.mjs +6 -5
- package/dist/astro/routes/api/content/_collection_/_id_/schedule.mjs.map +1 -1
- package/dist/astro/routes/api/content/_collection_/_id_/terms/_taxonomy_.mjs +10 -9
- package/dist/astro/routes/api/content/_collection_/_id_/terms/_taxonomy_.mjs.map +1 -1
- package/dist/astro/routes/api/content/_collection_/_id_/translations.mjs +2 -2
- package/dist/astro/routes/api/content/_collection_/_id_/unpublish.mjs +2 -2
- package/dist/astro/routes/api/content/_collection_/_id_.mjs +6 -5
- package/dist/astro/routes/api/content/_collection_/_id_.mjs.map +1 -1
- package/dist/astro/routes/api/content/_collection_/authors.mjs +2 -2
- package/dist/astro/routes/api/content/_collection_/index.mjs +6 -5
- package/dist/astro/routes/api/content/_collection_/index.mjs.map +1 -1
- package/dist/astro/routes/api/content/_collection_/trash.mjs +6 -5
- package/dist/astro/routes/api/content/_collection_/trash.mjs.map +1 -1
- package/dist/astro/routes/api/dashboard.mjs +3 -3
- package/dist/astro/routes/api/dev/emails.mjs +2 -2
- package/dist/astro/routes/api/import/probe.d.mts +3 -3
- package/dist/astro/routes/api/import/probe.mjs +10 -9
- package/dist/astro/routes/api/import/probe.mjs.map +1 -1
- package/dist/astro/routes/api/import/wordpress/analyze.mjs +3 -3
- package/dist/astro/routes/api/import/wordpress/execute.d.mts +9 -9
- package/dist/astro/routes/api/import/wordpress/execute.mjs +10 -9
- package/dist/astro/routes/api/import/wordpress/execute.mjs.map +1 -1
- package/dist/astro/routes/api/import/wordpress/media.mjs +8 -7
- package/dist/astro/routes/api/import/wordpress/media.mjs.map +1 -1
- package/dist/astro/routes/api/import/wordpress/prepare.mjs +9 -8
- package/dist/astro/routes/api/import/wordpress/prepare.mjs.map +1 -1
- package/dist/astro/routes/api/import/wordpress/rewrite-urls.mjs +8 -7
- package/dist/astro/routes/api/import/wordpress/rewrite-urls.mjs.map +1 -1
- package/dist/astro/routes/api/import/wordpress-plugin/analyze.d.mts +1 -1
- package/dist/astro/routes/api/import/wordpress-plugin/analyze.mjs +10 -9
- package/dist/astro/routes/api/import/wordpress-plugin/analyze.mjs.map +1 -1
- package/dist/astro/routes/api/import/wordpress-plugin/execute.d.mts +1 -1
- package/dist/astro/routes/api/import/wordpress-plugin/execute.mjs +14 -12
- package/dist/astro/routes/api/import/wordpress-plugin/execute.mjs.map +1 -1
- package/dist/astro/routes/api/manifest.mjs +3 -3
- package/dist/astro/routes/api/mcp.mjs +20 -19
- package/dist/astro/routes/api/mcp.mjs.map +1 -1
- package/dist/astro/routes/api/media/_id_/confirm.mjs +6 -5
- package/dist/astro/routes/api/media/_id_/confirm.mjs.map +1 -1
- package/dist/astro/routes/api/media/_id_.mjs +6 -5
- package/dist/astro/routes/api/media/_id_.mjs.map +1 -1
- package/dist/astro/routes/api/media/file/_...key_.mjs +1 -1
- package/dist/astro/routes/api/media/providers/_providerId_/_itemId_.mjs +2 -2
- package/dist/astro/routes/api/media/providers/_providerId_/index.mjs +2 -2
- package/dist/astro/routes/api/media/providers/index.mjs +2 -2
- package/dist/astro/routes/api/media/upload-url.mjs +8 -7
- package/dist/astro/routes/api/media/upload-url.mjs.map +1 -1
- package/dist/astro/routes/api/media.mjs +10 -9
- package/dist/astro/routes/api/media.mjs.map +1 -1
- package/dist/astro/routes/api/menus/_name_/items/_id_.mjs +6 -5
- package/dist/astro/routes/api/menus/_name_/items/_id_.mjs.map +1 -1
- package/dist/astro/routes/api/menus/_name_/items.mjs +6 -5
- package/dist/astro/routes/api/menus/_name_/items.mjs.map +1 -1
- package/dist/astro/routes/api/menus/_name_/reorder.mjs +6 -5
- package/dist/astro/routes/api/menus/_name_/reorder.mjs.map +1 -1
- package/dist/astro/routes/api/menus/_name_/translations.mjs +6 -5
- package/dist/astro/routes/api/menus/_name_/translations.mjs.map +1 -1
- package/dist/astro/routes/api/menus/_name_.mjs +6 -5
- package/dist/astro/routes/api/menus/_name_.mjs.map +1 -1
- package/dist/astro/routes/api/menus/index.mjs +6 -5
- package/dist/astro/routes/api/menus/index.mjs.map +1 -1
- package/dist/astro/routes/api/oauth/authorize.mjs +6 -6
- package/dist/astro/routes/api/oauth/device/authorize.mjs +5 -5
- package/dist/astro/routes/api/oauth/device/code.mjs +8 -8
- package/dist/astro/routes/api/oauth/device/token.mjs +7 -7
- package/dist/astro/routes/api/oauth/register.mjs +2 -2
- package/dist/astro/routes/api/oauth/token/refresh.mjs +5 -5
- package/dist/astro/routes/api/oauth/token/revoke.mjs +5 -5
- package/dist/astro/routes/api/oauth/token.mjs +5 -5
- package/dist/astro/routes/api/openapi.json.mjs +3 -2
- 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 +7 -6
- package/dist/astro/routes/api/redirects/404s/index.mjs.map +1 -1
- package/dist/astro/routes/api/redirects/404s/summary.mjs +7 -6
- package/dist/astro/routes/api/redirects/404s/summary.mjs.map +1 -1
- package/dist/astro/routes/api/redirects/_id_.mjs +8 -7
- package/dist/astro/routes/api/redirects/_id_.mjs.map +1 -1
- package/dist/astro/routes/api/redirects/index.mjs +8 -7
- package/dist/astro/routes/api/redirects/index.mjs.map +1 -1
- package/dist/astro/routes/api/revisions/_revisionId_/index.mjs +2 -2
- package/dist/astro/routes/api/revisions/_revisionId_/restore.mjs +2 -2
- package/dist/astro/routes/api/schema/collections/_slug_/fields/_fieldSlug_.mjs +28 -26
- package/dist/astro/routes/api/schema/collections/_slug_/fields/_fieldSlug_.mjs.map +1 -1
- package/dist/astro/routes/api/schema/collections/_slug_/fields/index.mjs +28 -26
- package/dist/astro/routes/api/schema/collections/_slug_/fields/index.mjs.map +1 -1
- package/dist/astro/routes/api/schema/collections/_slug_/fields/reorder.mjs +28 -26
- package/dist/astro/routes/api/schema/collections/_slug_/fields/reorder.mjs.map +1 -1
- package/dist/astro/routes/api/schema/collections/_slug_/index.mjs +28 -26
- package/dist/astro/routes/api/schema/collections/_slug_/index.mjs.map +1 -1
- package/dist/astro/routes/api/schema/collections/index.mjs +28 -26
- package/dist/astro/routes/api/schema/collections/index.mjs.map +1 -1
- package/dist/astro/routes/api/schema/index.mjs +8 -13
- package/dist/astro/routes/api/schema/index.mjs.map +1 -1
- package/dist/astro/routes/api/schema/orphans/_slug_.mjs +28 -26
- package/dist/astro/routes/api/schema/orphans/_slug_.mjs.map +1 -1
- package/dist/astro/routes/api/schema/orphans/index.mjs +28 -26
- package/dist/astro/routes/api/schema/orphans/index.mjs.map +1 -1
- package/dist/astro/routes/api/search/enable.mjs +9 -8
- package/dist/astro/routes/api/search/enable.mjs.map +1 -1
- package/dist/astro/routes/api/search/index.mjs +8 -7
- package/dist/astro/routes/api/search/index.mjs.map +1 -1
- package/dist/astro/routes/api/search/rebuild.mjs +9 -8
- package/dist/astro/routes/api/search/rebuild.mjs.map +1 -1
- package/dist/astro/routes/api/search/stats.mjs +5 -5
- package/dist/astro/routes/api/search/suggest.mjs +8 -7
- package/dist/astro/routes/api/search/suggest.mjs.map +1 -1
- package/dist/astro/routes/api/sections/_slug_.mjs +8 -7
- package/dist/astro/routes/api/sections/_slug_.mjs.map +1 -1
- package/dist/astro/routes/api/sections/index.mjs +8 -7
- package/dist/astro/routes/api/sections/index.mjs.map +1 -1
- package/dist/astro/routes/api/settings/email.mjs +3 -3
- package/dist/astro/routes/api/settings.mjs +11 -9
- package/dist/astro/routes/api/settings.mjs.map +1 -1
- package/dist/astro/routes/api/setup/admin-verify.mjs +10 -9
- package/dist/astro/routes/api/setup/admin-verify.mjs.map +1 -1
- package/dist/astro/routes/api/setup/admin.mjs +9 -8
- package/dist/astro/routes/api/setup/admin.mjs.map +1 -1
- package/dist/astro/routes/api/setup/dev-bypass.mjs +19 -18
- package/dist/astro/routes/api/setup/dev-bypass.mjs.map +1 -1
- package/dist/astro/routes/api/setup/dev-reset.mjs +1 -1
- package/dist/astro/routes/api/setup/index.mjs +20 -18
- package/dist/astro/routes/api/setup/index.mjs.map +1 -1
- package/dist/astro/routes/api/setup/status.mjs +3 -3
- package/dist/astro/routes/api/snapshot.mjs +5 -4
- package/dist/astro/routes/api/snapshot.mjs.map +1 -1
- package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_/translations.mjs +11 -10
- package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_/translations.mjs.map +1 -1
- package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_.mjs +11 -10
- package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_.mjs.map +1 -1
- package/dist/astro/routes/api/taxonomies/_name_/terms/index.mjs +11 -10
- package/dist/astro/routes/api/taxonomies/_name_/terms/index.mjs.map +1 -1
- package/dist/astro/routes/api/taxonomies/index.mjs +11 -10
- package/dist/astro/routes/api/taxonomies/index.mjs.map +1 -1
- package/dist/astro/routes/api/themes/preview.mjs +5 -4
- package/dist/astro/routes/api/themes/preview.mjs.map +1 -1
- package/dist/astro/routes/api/typegen.mjs +4 -4
- package/dist/astro/routes/api/well-known/auth.mjs +1 -1
- package/dist/astro/routes/api/well-known/oauth-authorization-server.mjs +2 -2
- package/dist/astro/routes/api/well-known/oauth-protected-resource.mjs +2 -2
- package/dist/astro/routes/api/widget-areas/_name_/reorder.mjs +6 -5
- package/dist/astro/routes/api/widget-areas/_name_/reorder.mjs.map +1 -1
- package/dist/astro/routes/api/widget-areas/_name_/widgets/_id_.mjs +9 -7
- package/dist/astro/routes/api/widget-areas/_name_/widgets/_id_.mjs.map +1 -1
- package/dist/astro/routes/api/widget-areas/_name_/widgets.mjs +9 -7
- package/dist/astro/routes/api/widget-areas/_name_/widgets.mjs.map +1 -1
- package/dist/astro/routes/api/widget-areas/_name_.mjs +5 -4
- package/dist/astro/routes/api/widget-areas/_name_.mjs.map +1 -1
- package/dist/astro/routes/api/widget-areas/index.mjs +9 -7
- package/dist/astro/routes/api/widget-areas/index.mjs.map +1 -1
- package/dist/astro/routes/api/widget-components.mjs +2 -2
- package/dist/astro/routes/robots.txt.mjs +5 -4
- package/dist/astro/routes/robots.txt.mjs.map +1 -1
- package/dist/astro/routes/sitemap-_collection_.xml.d.mts.map +1 -1
- package/dist/astro/routes/sitemap-_collection_.xml.mjs +15 -7
- package/dist/astro/routes/sitemap-_collection_.xml.mjs.map +1 -1
- package/dist/astro/routes/sitemap.xml.mjs +6 -5
- package/dist/astro/routes/sitemap.xml.mjs.map +1 -1
- package/dist/astro/types.d.mts +12 -12
- package/dist/auth/providers/github.d.mts +1 -1
- package/dist/auth/providers/google.d.mts +1 -1
- package/dist/{authorize-C_8t2KGa.mjs → authorize-D5gfBVU5.mjs} +2 -2
- package/dist/{authorize-C_8t2KGa.mjs.map → authorize-D5gfBVU5.mjs.map} +1 -1
- package/dist/{byline-DUx48sJp.mjs → byline-V_Qp1Ziw.mjs} +27 -14
- package/dist/byline-V_Qp1Ziw.mjs.map +1 -0
- package/dist/{byline-fields-51kg6Vuv.mjs → byline-fields-B0NO1yUB.mjs} +3 -3
- package/dist/{byline-fields-51kg6Vuv.mjs.map → byline-fields-B0NO1yUB.mjs.map} +1 -1
- package/dist/{byline-fields-DYXKDuNX.d.mts → byline-fields-CQJRIQkn.d.mts} +36 -32
- package/dist/byline-fields-CQJRIQkn.d.mts.map +1 -0
- package/dist/{byline-fields-C_OsR-KF.mjs → byline-fields-nBVqK_Ff.mjs} +2 -2
- package/dist/{byline-fields-C_OsR-KF.mjs.map → byline-fields-nBVqK_Ff.mjs.map} +1 -1
- package/dist/{byline-registry-CWP7I71B.mjs → byline-registry-DedidtqC.mjs} +2 -2
- package/dist/{byline-registry-CWP7I71B.mjs.map → byline-registry-DedidtqC.mjs.map} +1 -1
- package/dist/{bylines-Cx5n-WqP.mjs → bylines-B2NWnIwS.mjs} +2 -2
- package/dist/{bylines-Cx5n-WqP.mjs.map → bylines-B2NWnIwS.mjs.map} +1 -1
- package/dist/{bylines-wurS258E.mjs → bylines-DfGDnred.mjs} +7 -7
- package/dist/{bylines-wurS258E.mjs.map → bylines-DfGDnred.mjs.map} +1 -1
- package/dist/{cache-B_HzASVT.mjs → cache-DTTHWD8n.mjs} +1 -1
- package/dist/{cache-B_HzASVT.mjs.map → cache-DTTHWD8n.mjs.map} +1 -1
- package/dist/{challenge-store-DGwuCc4R.mjs → challenge-store-woE0bbCf.mjs} +1 -1
- package/dist/{challenge-store-DGwuCc4R.mjs.map → challenge-store-woE0bbCf.mjs.map} +1 -1
- package/dist/cli/index.mjs +22 -20
- package/dist/cli/index.mjs.map +1 -1
- package/dist/client/cf-access.d.mts +1 -1
- package/dist/client/index.d.mts +1 -1
- package/dist/client/index.mjs +1 -1
- package/dist/{comments-CJ0RZsYR.mjs → comments-D2hNuxNa.mjs} +1 -1
- package/dist/{comments-CJ0RZsYR.mjs.map → comments-D2hNuxNa.mjs.map} +1 -1
- package/dist/{components-CTfpu3PZ.mjs → components-DYKp2gmo.mjs} +1 -1
- package/dist/{components-CTfpu3PZ.mjs.map → components-DYKp2gmo.mjs.map} +1 -1
- package/dist/{context-GG52SPgh.mjs → context-Cm4pt1Ws.mjs} +5 -5
- package/dist/{context-GG52SPgh.mjs.map → context-Cm4pt1Ws.mjs.map} +1 -1
- package/dist/{cron-BJ2ClIlj.mjs → cron-DdEVrQ2Y.mjs} +1 -1
- package/dist/{cron-BJ2ClIlj.mjs.map → cron-DdEVrQ2Y.mjs.map} +1 -1
- package/dist/{dashboard-2JgAMWxK.mjs → dashboard-C-UYpps0.mjs} +1 -1
- package/dist/{dashboard-2JgAMWxK.mjs.map → dashboard-C-UYpps0.mjs.map} +1 -1
- package/dist/database/instrumentation.d.mts +10 -1
- package/dist/database/instrumentation.d.mts.map +1 -1
- package/dist/database/instrumentation.mjs +13 -1
- package/dist/database/instrumentation.mjs.map +1 -1
- package/dist/db/index.d.mts +3 -3
- package/dist/db/libsql.d.mts +1 -1
- package/dist/db/postgres.d.mts +1 -1
- package/dist/db/sqlite.d.mts +1 -1
- package/dist/{db-errors-CtzxKBxe.mjs → db-errors-BluWkwGI.mjs} +1 -1
- package/dist/{db-errors-CtzxKBxe.mjs.map → db-errors-BluWkwGI.mjs.map} +1 -1
- package/dist/{default-xLFNSsZ9.mjs → default-NHGuJzQ3.mjs} +1 -1
- package/dist/{default-xLFNSsZ9.mjs.map → default-NHGuJzQ3.mjs.map} +1 -1
- package/dist/{device-flow-s6_q3T7A.mjs → device-flow-BQApWgnW.mjs} +4 -4
- package/dist/{device-flow-s6_q3T7A.mjs.map → device-flow-BQApWgnW.mjs.map} +1 -1
- package/dist/{email-console-DHT2Fbpj.mjs → email-console-BbU3RbWv.mjs} +1 -1
- package/dist/{email-console-DHT2Fbpj.mjs.map → email-console-BbU3RbWv.mjs.map} +1 -1
- package/dist/{error-RwM4dD35.mjs → error-CNn_w7jf.mjs} +1 -1
- package/dist/{error-RwM4dD35.mjs.map → error-CNn_w7jf.mjs.map} +1 -1
- package/dist/{escape-bIyGoW5W.mjs → escape-DPgcxcpL.mjs} +1 -1
- package/dist/{escape-bIyGoW5W.mjs.map → escape-DPgcxcpL.mjs.map} +1 -1
- package/dist/{fts-manager-1RgHmopc.mjs → fts-manager-Cx5z8jdA.mjs} +1 -1
- package/dist/{fts-manager-1RgHmopc.mjs.map → fts-manager-Cx5z8jdA.mjs.map} +1 -1
- package/dist/{hash-9w3pd3-m.mjs → hash-DlvIFn0b.mjs} +1 -1
- package/dist/{hash-9w3pd3-m.mjs.map → hash-DlvIFn0b.mjs.map} +1 -1
- package/dist/{import-Dh8bWmyq.mjs → import-KyxT1Mbs.mjs} +3 -3
- package/dist/{import-Dh8bWmyq.mjs.map → import-KyxT1Mbs.mjs.map} +1 -1
- package/dist/{index-FfiTQJq2.d.mts → index-D2VAiumu.d.mts} +46 -15
- package/dist/{index-FfiTQJq2.d.mts.map → index-D2VAiumu.d.mts.map} +1 -1
- package/dist/{index-BpYeJO1E.d.mts → index-uT2yR66F.d.mts} +3 -3
- package/dist/{index-BpYeJO1E.d.mts.map → index-uT2yR66F.d.mts.map} +1 -1
- package/dist/index.d.mts +16 -16
- package/dist/index.mjs +48 -46
- package/dist/init-lock-DlBHjf9-.mjs +83 -0
- package/dist/init-lock-DlBHjf9-.mjs.map +1 -0
- package/dist/{load-B84ohfBk.mjs → load-Dq91b_DK.mjs} +1 -1
- package/dist/{load-B84ohfBk.mjs.map → load-Dq91b_DK.mjs.map} +1 -1
- package/dist/{loader-CpZKpFz0.mjs → loader-BqWjcH3h.mjs} +12 -15
- package/dist/loader-BqWjcH3h.mjs.map +1 -0
- package/dist/{manifest-schema-Cj-YrzrF.mjs → manifest-schema-DFPeqMAn.mjs} +55 -2
- package/dist/manifest-schema-DFPeqMAn.mjs.map +1 -0
- package/dist/media/index.d.mts +1 -1
- package/dist/media/index.mjs +2 -2
- package/dist/media/local-runtime.d.mts +11 -11
- package/dist/media/local-runtime.mjs +4 -3
- package/dist/media/local-runtime.mjs.map +1 -1
- package/dist/{media-allowlist-CMcoYIjQ.mjs → media-allowlist-_A0SuDn4.mjs} +2 -2
- package/dist/{media-allowlist-CMcoYIjQ.mjs.map → media-allowlist-_A0SuDn4.mjs.map} +1 -1
- package/dist/media-url-CqLd69IO.mjs +26 -0
- package/dist/media-url-CqLd69IO.mjs.map +1 -0
- package/dist/{menus-Dp9xporj.mjs → menus-Ryk9L7fT.mjs} +10 -37
- package/dist/menus-Ryk9L7fT.mjs.map +1 -0
- package/dist/{mime-CCEzze7W.mjs → mime-YbtlEtvS.mjs} +1 -1
- package/dist/{mime-CCEzze7W.mjs.map → mime-YbtlEtvS.mjs.map} +1 -1
- package/dist/{mode-BjlXswIw.mjs → mode-CGXzIbD8.mjs} +1 -1
- package/dist/{mode-BjlXswIw.mjs.map → mode-CGXzIbD8.mjs.map} +1 -1
- package/dist/{normalize-CK5o04zr.mjs → normalize-DKsg36ty.mjs} +1 -1
- package/dist/{normalize-CK5o04zr.mjs.map → normalize-DKsg36ty.mjs.map} +1 -1
- package/dist/{oauth-authorization-1aPAYjiC.mjs → oauth-authorization-C2kVyjXI.mjs} +4 -4
- package/dist/{oauth-authorization-1aPAYjiC.mjs.map → oauth-authorization-C2kVyjXI.mjs.map} +1 -1
- package/dist/{oauth-clients-8mPDStMv.mjs → oauth-clients-BC873NCV.mjs} +1 -1
- package/dist/{oauth-clients-8mPDStMv.mjs.map → oauth-clients-BC873NCV.mjs.map} +1 -1
- package/dist/{oauth-state-store-BJ7YtrfD.mjs → oauth-state-store-Cd--TUaq.mjs} +1 -1
- package/dist/{oauth-state-store-BJ7YtrfD.mjs.map → oauth-state-store-Cd--TUaq.mjs.map} +1 -1
- package/dist/{oauth-user-lookup-BdDSDvjF.mjs → oauth-user-lookup-e4wOvDud.mjs} +1 -1
- package/dist/{oauth-user-lookup-BdDSDvjF.mjs.map → oauth-user-lookup-e4wOvDud.mjs.map} +1 -1
- package/dist/{options-D4MnavW_.d.mts → options-9kLgkE8m.d.mts} +3 -3
- package/dist/{options-D4MnavW_.d.mts.map → options-9kLgkE8m.d.mts.map} +1 -1
- package/dist/page/index.d.mts +2 -2
- package/dist/{parse-CrGndy1A.mjs → parse-DzSrk1t8.mjs} +2 -2
- package/dist/{parse-CrGndy1A.mjs.map → parse-DzSrk1t8.mjs.map} +1 -1
- package/dist/{passkey-config-BDVM86Tj.mjs → passkey-config-BpjbE_Uv.mjs} +1 -1
- package/dist/{passkey-config-BDVM86Tj.mjs.map → passkey-config-BpjbE_Uv.mjs.map} +1 -1
- package/dist/{placeholder-BZxr8W1j.mjs → placeholder-2xumZh4g.mjs} +1 -1
- package/dist/{placeholder-BZxr8W1j.mjs.map → placeholder-2xumZh4g.mjs.map} +1 -1
- package/dist/{placeholder-B9lUUEmj.d.mts → placeholder-BevVKfay.d.mts} +1 -1
- package/dist/{placeholder-B9lUUEmj.d.mts.map → placeholder-BevVKfay.d.mts.map} +1 -1
- package/dist/plugin-types.d.mts +1 -1
- package/dist/plugin-utils.d.mts +9 -9
- package/dist/plugins/adapt-sandbox-entry.d.mts +9 -9
- package/dist/plugins/adapt-sandbox-entry.mjs +2 -2
- package/dist/{preview-BfuRkVKW.mjs → preview-Dqv2hwXr.mjs} +2 -2
- package/dist/{preview-BfuRkVKW.mjs.map → preview-Dqv2hwXr.mjs.map} +1 -1
- package/dist/{public-url-egRHCy1m.mjs → public-url-D_zARuvZ.mjs} +1 -1
- package/dist/{public-url-egRHCy1m.mjs.map → public-url-D_zARuvZ.mjs.map} +1 -1
- package/dist/{query-BFQ029Ts.mjs → query-Crm038Mc.mjs} +21 -11
- package/dist/query-Crm038Mc.mjs.map +1 -0
- package/dist/{rate-limit-ClFFUga6.mjs → rate-limit-hRTBqmw1.mjs} +2 -2
- package/dist/{rate-limit-ClFFUga6.mjs.map → rate-limit-hRTBqmw1.mjs.map} +1 -1
- package/dist/{redirect-Cw3JTlmj.mjs → redirect-C-OOkyku.mjs} +1 -1
- package/dist/{redirect-Cw3JTlmj.mjs.map → redirect-C-OOkyku.mjs.map} +1 -1
- package/dist/{redirects-DEygMrRO.mjs → redirects-6Zg2SoYo.mjs} +11 -10
- package/dist/redirects-6Zg2SoYo.mjs.map +1 -0
- package/dist/{redirects-OIu6vQ2i.mjs → redirects-CP3TnTLO.mjs} +20 -14
- package/dist/redirects-CP3TnTLO.mjs.map +1 -0
- package/dist/{registry-brYh-rAT.mjs → registry-diMzD1Wf.mjs} +3 -3
- package/dist/{registry-brYh-rAT.mjs.map → registry-diMzD1Wf.mjs.map} +1 -1
- package/dist/{request-cache-D32LpnmI.mjs → request-cache-UwmBAiUK.mjs} +1 -1
- package/dist/{request-cache-D32LpnmI.mjs.map → request-cache-UwmBAiUK.mjs.map} +1 -1
- package/dist/request-context.d.mts +7 -0
- package/dist/request-context.d.mts.map +1 -1
- package/dist/request-context.mjs +2 -1
- package/dist/request-context.mjs.map +1 -1
- package/dist/{request-meta-7ByVLxB-.mjs → request-meta-DPechd0W.mjs} +2 -2
- package/dist/{request-meta-7ByVLxB-.mjs.map → request-meta-DPechd0W.mjs.map} +1 -1
- package/dist/{resolve-BqYMVG0D.mjs → resolve-B3NUUtVY.mjs} +1 -1
- package/dist/{resolve-BqYMVG0D.mjs.map → resolve-B3NUUtVY.mjs.map} +1 -1
- package/dist/{runner-BcRuXq_h.d.mts → runner-C8vcbvCe.d.mts} +2 -2
- package/dist/{runner-BcRuXq_h.d.mts.map → runner-C8vcbvCe.d.mts.map} +1 -1
- package/dist/runtime.d.mts +10 -10
- package/dist/runtime.mjs +1 -1
- package/dist/{schema-CS7Eg5gh.mjs → schema-BDOkd3OU.mjs} +4 -4
- package/dist/{schema-CS7Eg5gh.mjs.map → schema-BDOkd3OU.mjs.map} +1 -1
- package/dist/{search-o-aQzHI1.mjs → search-Bs_J_EW-.mjs} +3 -3
- package/dist/{search-o-aQzHI1.mjs.map → search-Bs_J_EW-.mjs.map} +1 -1
- package/dist/{secrets-C_ZtRos3.mjs → secrets-C8xmE6mR.mjs} +21 -11
- package/dist/secrets-C8xmE6mR.mjs.map +1 -0
- package/dist/{sections-DhsZ0ns9.mjs → sections-P0zuBlyz.mjs} +2 -2
- package/dist/{sections-DhsZ0ns9.mjs.map → sections-P0zuBlyz.mjs.map} +1 -1
- package/dist/seed/index.d.mts +2 -2
- package/dist/seed/index.mjs +14 -13
- package/dist/seo/index.d.mts +1 -1
- package/dist/seo/index.d.mts.map +1 -1
- package/dist/seo/index.mjs +3 -12
- package/dist/seo/index.mjs.map +1 -1
- package/dist/{seo-DfjLvu8i.mjs → seo-CLhm-Fmb.mjs} +4 -3
- package/dist/seo-CLhm-Fmb.mjs.map +1 -0
- package/dist/{seo-B5e6y9Wk.mjs → seo-DpNgGQjF.mjs} +1 -1
- package/dist/{seo-B5e6y9Wk.mjs.map → seo-DpNgGQjF.mjs.map} +1 -1
- package/dist/{service-DAxg8RPR.mjs → service-CDQQnT8W.mjs} +2 -2
- package/dist/{service-DAxg8RPR.mjs.map → service-CDQQnT8W.mjs.map} +1 -1
- package/dist/{settings-B1p-gPUK.mjs → settings-BjBsmVAo.mjs} +32 -30
- package/dist/settings-BjBsmVAo.mjs.map +1 -0
- package/dist/{settings-DIsbHTRE.mjs → settings-sO0Fif4p.mjs} +2 -2
- package/dist/{settings-DIsbHTRE.mjs.map → settings-sO0Fif4p.mjs.map} +1 -1
- package/dist/{setup-complete-Yuv78yua.mjs → setup-complete-CMMr-oZU.mjs} +1 -1
- package/dist/{setup-complete-Yuv78yua.mjs.map → setup-complete-CMMr-oZU.mjs.map} +1 -1
- package/dist/{setup-nonce-Bm0uKqmf.mjs → setup-nonce-169xl4fV.mjs} +1 -1
- package/dist/{setup-nonce-Bm0uKqmf.mjs.map → setup-nonce-169xl4fV.mjs.map} +1 -1
- package/dist/single-flight-cache-C0UV1Npg.mjs +104 -0
- package/dist/single-flight-cache-C0UV1Npg.mjs.map +1 -0
- package/dist/{site-url-mEVmwIFi.mjs → site-url-vtsuOvSD.mjs} +1 -1
- package/dist/{site-url-mEVmwIFi.mjs.map → site-url-vtsuOvSD.mjs.map} +1 -1
- package/dist/{ssrf-BsVGIE0Z.mjs → ssrf-XO05Voq6.mjs} +1 -1
- package/dist/{ssrf-BsVGIE0Z.mjs.map → ssrf-XO05Voq6.mjs.map} +1 -1
- package/dist/status-2gZklYuj.mjs +30 -0
- package/dist/status-2gZklYuj.mjs.map +1 -0
- package/dist/storage/local.d.mts +1 -1
- package/dist/storage/local.mjs +2 -2
- package/dist/storage/s3.d.mts +1 -1
- package/dist/storage/s3.mjs +1 -1
- package/dist/{taxonomies-BEW7S5AI.mjs → taxonomies-BBxYA38v.mjs} +49 -12
- package/dist/taxonomies-BBxYA38v.mjs.map +1 -0
- package/dist/{taxonomies-UusDXv3C.mjs → taxonomies-DuESHWKI.mjs} +2 -2
- package/dist/{taxonomies-UusDXv3C.mjs.map → taxonomies-DuESHWKI.mjs.map} +1 -1
- package/dist/{tokens-Bx2afeT-.mjs → tokens-DMkVjxrx.mjs} +1 -1
- package/dist/{tokens-Bx2afeT-.mjs.map → tokens-DMkVjxrx.mjs.map} +1 -1
- package/dist/{transport--Ck3RBin.mjs → transport-1cIrOb1Y.mjs} +1 -1
- package/dist/{transport--Ck3RBin.mjs.map → transport-1cIrOb1Y.mjs.map} +1 -1
- package/dist/{transport-BwQeeY2p.d.mts → transport-jdvsZEIt.d.mts} +1 -1
- package/dist/{transport-BwQeeY2p.d.mts.map → transport-jdvsZEIt.d.mts.map} +1 -1
- package/dist/{trusted-proxy-B4AfnoAp.mjs → trusted-proxy-CHp41Fjj.mjs} +1 -1
- package/dist/{trusted-proxy-B4AfnoAp.mjs.map → trusted-proxy-CHp41Fjj.mjs.map} +1 -1
- package/dist/{types-DWnN7weG.d.mts → types-BFgYtuKd.d.mts} +1 -1
- package/dist/{types-DWnN7weG.d.mts.map → types-BFgYtuKd.d.mts.map} +1 -1
- package/dist/{types-DZk_y-MU.mjs → types-BIduXPJk.mjs} +1 -1
- package/dist/types-BIduXPJk.mjs.map +1 -0
- package/dist/{types-WVmpZBJV.d.mts → types-BTnnBYVX.d.mts} +2 -2
- package/dist/{types-WVmpZBJV.d.mts.map → types-BTnnBYVX.d.mts.map} +1 -1
- package/dist/types-BoRm8-pp.mjs +3 -0
- package/dist/{types-DbCWhHet.d.mts → types-Bzfk2yC8.d.mts} +2 -2
- package/dist/types-Bzfk2yC8.d.mts.map +1 -0
- package/dist/{types-Qa7-HJJC.d.mts → types-CkEuk-Zr.d.mts} +1 -1
- package/dist/{types-Qa7-HJJC.d.mts.map → types-CkEuk-Zr.d.mts.map} +1 -1
- package/dist/{types-DMwSpvcw.d.mts → types-DO7whVYU.d.mts} +9 -3
- package/dist/{types-DMwSpvcw.d.mts.map → types-DO7whVYU.d.mts.map} +1 -1
- package/dist/{types-DX6v9KzJ.d.mts → types-DdkL6fyv.d.mts} +1 -1
- package/dist/{types-DX6v9KzJ.d.mts.map → types-DdkL6fyv.d.mts.map} +1 -1
- package/dist/{types-DpFmlNyB.mjs → types-DejCHqWT.mjs} +1 -1
- package/dist/{types-DpFmlNyB.mjs.map → types-DejCHqWT.mjs.map} +1 -1
- package/dist/{types-OT_Es5mp.d.mts → types-Del0VMij.d.mts} +1 -1
- package/dist/{types-OT_Es5mp.d.mts.map → types-Del0VMij.d.mts.map} +1 -1
- package/dist/{types-kwqCOUxj.d.mts → types-u_XxjbS8.d.mts} +1 -1
- package/dist/{types-kwqCOUxj.d.mts.map → types-u_XxjbS8.d.mts.map} +1 -1
- package/dist/{utils-C4Ih4DML.mjs → utils-C4M981Br.mjs} +1 -1
- package/dist/{utils-C4Ih4DML.mjs.map → utils-C4M981Br.mjs.map} +1 -1
- package/dist/{validate-ZP9Dvg0P.mjs → validate-DGhQPXzI.mjs} +2 -2
- package/dist/{validate-ZP9Dvg0P.mjs.map → validate-DGhQPXzI.mjs.map} +1 -1
- package/dist/{validate-BPAHUSge.d.mts → validate-cJOiOvT2.d.mts} +5 -5
- package/dist/{validate-BPAHUSge.d.mts.map → validate-cJOiOvT2.d.mts.map} +1 -1
- package/dist/{validation-CE5i4q0c.mjs → validation-DVHjPM1M.mjs} +5 -5
- package/dist/{validation-CE5i4q0c.mjs.map → validation-DVHjPM1M.mjs.map} +1 -1
- package/dist/version-BOjj_cfz.mjs +7 -0
- package/dist/{version-Dw0JXu45.mjs.map → version-BOjj_cfz.mjs.map} +1 -1
- package/dist/{widgets-ClEnYQCH.mjs → widgets-Ci6hLwfO.mjs} +47 -44
- package/dist/widgets-Ci6hLwfO.mjs.map +1 -0
- package/dist/{zod-generator-Djo_VHCt.mjs → zod-generator-CarzgPAu.mjs} +2 -2
- package/dist/{zod-generator-Djo_VHCt.mjs.map → zod-generator-CarzgPAu.mjs.map} +1 -1
- package/package.json +10 -10
- package/src/api/handlers/marketplace.ts +2 -5
- package/src/api/handlers/redirects.ts +24 -13
- package/src/api/handlers/registry.ts +70 -0
- package/src/api/handlers/seo.ts +9 -1
- package/src/api/schemas/redirects.ts +11 -4
- package/src/api/schemas/schema.ts +13 -1
- package/src/astro/integration/index.ts +44 -8
- package/src/astro/integration/routes.ts +46 -9
- package/src/astro/middleware/redirect.ts +12 -0
- package/src/astro/middleware.ts +20 -6
- package/src/astro/routes/api/schema/index.ts +7 -15
- package/src/astro/routes/sitemap-[collection].xml.ts +13 -2
- package/src/bylines/field-defs-cache.ts +70 -20
- package/src/cli/commands/bundle-utils.ts +2 -0
- package/src/cli/commands/doctor.ts +1 -1
- package/src/cli/commands/secrets.ts +2 -2
- package/src/config/secrets.ts +28 -14
- package/src/database/instrumentation.ts +13 -0
- package/src/emdash-runtime.ts +31 -25
- package/src/loader.ts +24 -15
- package/src/plugins/manifest-schema.ts +75 -0
- package/src/plugins/marketplace.ts +2 -5
- package/src/plugins/types.ts +12 -0
- package/src/query.ts +13 -2
- package/src/redirects/status.ts +27 -0
- package/src/request-context.ts +8 -0
- package/src/schema/types.ts +11 -1
- package/src/seo/index.ts +2 -28
- package/src/seo/media-url.ts +32 -0
- package/src/settings/index.ts +32 -40
- package/src/taxonomies/index.ts +78 -12
- package/src/utils/single-flight-cache.ts +194 -0
- package/src/widgets/index.ts +57 -54
- package/dist/api-BZ6bhjYs.mjs.map +0 -1
- package/dist/byline-DUx48sJp.mjs.map +0 -1
- package/dist/byline-fields-DYXKDuNX.d.mts.map +0 -1
- package/dist/loader-CpZKpFz0.mjs.map +0 -1
- package/dist/manifest-schema-Cj-YrzrF.mjs.map +0 -1
- package/dist/menus-Dp9xporj.mjs.map +0 -1
- package/dist/query-BFQ029Ts.mjs.map +0 -1
- package/dist/redirects-DEygMrRO.mjs.map +0 -1
- package/dist/redirects-OIu6vQ2i.mjs.map +0 -1
- package/dist/secrets-C_ZtRos3.mjs.map +0 -1
- package/dist/seo-DfjLvu8i.mjs.map +0 -1
- package/dist/settings-B1p-gPUK.mjs.map +0 -1
- package/dist/taxonomies-BEW7S5AI.mjs.map +0 -1
- package/dist/types-Cj2S6FuC.mjs +0 -3
- package/dist/types-DZk_y-MU.mjs.map +0 -1
- package/dist/types-DbCWhHet.d.mts.map +0 -1
- package/dist/version-Dw0JXu45.mjs +0 -7
- package/dist/widgets-ClEnYQCH.mjs.map +0 -1
- /package/dist/{api-tokens-B6VgoE6M.mjs → api-tokens-C7ywRx7l.mjs} +0 -0
- /package/dist/{ssrf-BvgVcfNQ.mjs → ssrf-CRZGzjdL.mjs} +0 -0
|
@@ -23,6 +23,7 @@ import {
|
|
|
23
23
|
matchCachedPatterns,
|
|
24
24
|
setCachedRedirects,
|
|
25
25
|
} from "../../redirects/cache.js";
|
|
26
|
+
import { isTerminalStatus } from "../../redirects/status.js";
|
|
26
27
|
|
|
27
28
|
/** Paths that should never be intercepted by redirects */
|
|
28
29
|
const SKIP_PREFIXES = ["/_emdash", "/_image"];
|
|
@@ -80,6 +81,12 @@ export const onRequest = defineMiddleware(async (context, next) => {
|
|
|
80
81
|
exact = cached.exact.get(alt);
|
|
81
82
|
}
|
|
82
83
|
if (exact) {
|
|
84
|
+
// Terminal statuses (410 Gone / 451): serve the status directly,
|
|
85
|
+
// with no Location header.
|
|
86
|
+
if (isTerminalStatus(exact.type)) {
|
|
87
|
+
repo.recordHit(exact.id).catch(() => {});
|
|
88
|
+
return new Response(null, { status: exact.type });
|
|
89
|
+
}
|
|
83
90
|
const dest = exact.destination;
|
|
84
91
|
if (dest.startsWith("//") || dest.startsWith("/\\")) return next();
|
|
85
92
|
repo.recordHit(exact.id).catch(() => {});
|
|
@@ -91,6 +98,11 @@ export const onRequest = defineMiddleware(async (context, next) => {
|
|
|
91
98
|
const patternMatch = matchCachedPatterns(cached.patterns, pathname);
|
|
92
99
|
if (patternMatch) {
|
|
93
100
|
const { redirect, destination } = patternMatch;
|
|
101
|
+
// Terminal statuses (410 Gone / 451): serve the status directly.
|
|
102
|
+
if (isTerminalStatus(redirect.type)) {
|
|
103
|
+
repo.recordHit(redirect.id).catch(() => {});
|
|
104
|
+
return new Response(null, { status: redirect.type });
|
|
105
|
+
}
|
|
94
106
|
if (destination.startsWith("//") || destination.startsWith("/\\")) return next();
|
|
95
107
|
repo.recordHit(redirect.id).catch(() => {});
|
|
96
108
|
const code = isRedirectCode(redirect.type) ? redirect.type : 301;
|
package/src/astro/middleware.ts
CHANGED
|
@@ -333,6 +333,9 @@ function pushMetricsTimings(
|
|
|
333
333
|
timings.push({ name: "db.last", dur: metrics.dbLastOffset, desc: "Last query at" });
|
|
334
334
|
}
|
|
335
335
|
}
|
|
336
|
+
if (metrics.rpcCount > 0) {
|
|
337
|
+
timings.push({ name: "rpc.count", dur: metrics.rpcCount, desc: "DB round trips" });
|
|
338
|
+
}
|
|
336
339
|
if (metrics.cacheHits + metrics.cacheMisses > 0) {
|
|
337
340
|
timings.push({ name: "cache.hit", dur: metrics.cacheHits, desc: "Cache hits" });
|
|
338
341
|
timings.push({ name: "cache.miss", dur: metrics.cacheMisses, desc: "Cache misses" });
|
|
@@ -510,9 +513,15 @@ export const onRequest = defineMiddleware(async (context, next) => {
|
|
|
510
513
|
? { ...parent, db: anonScoped.db }
|
|
511
514
|
: { editMode: false, db: anonScoped.db, metrics };
|
|
512
515
|
return runWithContext(ctx, async () => {
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
+
// commit() in finally: the write reached the primary independently
|
|
517
|
+
// of render, so the bookmark cookie must be persisted even if
|
|
518
|
+
// render throws -- otherwise a write-then-failed-render leaves the
|
|
519
|
+
// next request able to read pre-write state off a lagging replica.
|
|
520
|
+
try {
|
|
521
|
+
return await runAnon();
|
|
522
|
+
} finally {
|
|
523
|
+
anonScoped.commit();
|
|
524
|
+
}
|
|
516
525
|
});
|
|
517
526
|
}
|
|
518
527
|
return runAnon();
|
|
@@ -681,9 +690,14 @@ export const onRequest = defineMiddleware(async (context, next) => {
|
|
|
681
690
|
? { ...parent, db: scoped.db }
|
|
682
691
|
: { editMode: false, db: scoped.db, metrics };
|
|
683
692
|
return runWithContext(ctx, async () => {
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
693
|
+
// commit() in finally: persist the bookmark cookie even if render
|
|
694
|
+
// throws -- the write already reached the primary, so a failed
|
|
695
|
+
// render must not strand the next request on a stale replica read.
|
|
696
|
+
try {
|
|
697
|
+
return await renderAndFinalize();
|
|
698
|
+
} finally {
|
|
699
|
+
scoped.commit();
|
|
700
|
+
}
|
|
687
701
|
});
|
|
688
702
|
}
|
|
689
703
|
|
|
@@ -13,7 +13,7 @@ import type { APIRoute } from "astro";
|
|
|
13
13
|
import { hashString } from "emdash";
|
|
14
14
|
|
|
15
15
|
import { requirePerm } from "#api/authorize.js";
|
|
16
|
-
import { handleError, requireDb } from "#api/error.js";
|
|
16
|
+
import { apiSuccess, handleError, requireDb } from "#api/error.js";
|
|
17
17
|
import { SchemaRegistry } from "#schema/registry.js";
|
|
18
18
|
import { generateTypeScript } from "#schema/zod-generator.js";
|
|
19
19
|
|
|
@@ -89,20 +89,12 @@ import type { PortableTextBlock } from "emdash";
|
|
|
89
89
|
|
|
90
90
|
const version = await hashString(JSON.stringify(schemaExport));
|
|
91
91
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
status: 200,
|
|
99
|
-
headers: {
|
|
100
|
-
"Content-Type": "application/json",
|
|
101
|
-
"Cache-Control": "private, no-store",
|
|
102
|
-
"X-Schema-Version": version,
|
|
103
|
-
},
|
|
104
|
-
},
|
|
105
|
-
);
|
|
92
|
+
const response = apiSuccess({
|
|
93
|
+
...schemaExport,
|
|
94
|
+
version,
|
|
95
|
+
});
|
|
96
|
+
response.headers.set("X-Schema-Version", version);
|
|
97
|
+
return response;
|
|
106
98
|
} catch (error) {
|
|
107
99
|
return handleError(error, "Schema export failed", "SCHEMA_EXPORT_ERROR");
|
|
108
100
|
}
|
|
@@ -23,6 +23,7 @@ import { getSiteSettingsWithDb } from "#settings/index.js";
|
|
|
23
23
|
|
|
24
24
|
import { getI18nConfig, isI18nEnabled } from "../../i18n/config.js";
|
|
25
25
|
import { interpolateUrlPattern, localizePath } from "../../i18n/resolve.js";
|
|
26
|
+
import { buildSeoImageUrl } from "../../seo/media-url.js";
|
|
26
27
|
|
|
27
28
|
export const prerender = false;
|
|
28
29
|
|
|
@@ -112,8 +113,8 @@ export const GET: APIRoute = async ({ params, locals, url }) => {
|
|
|
112
113
|
const lines: string[] = ['<?xml version="1.0" encoding="UTF-8"?>'];
|
|
113
114
|
lines.push(
|
|
114
115
|
useXhtml
|
|
115
|
-
? '<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:xhtml="http://www.w3.org/1999/xhtml">'
|
|
116
|
-
: '<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">',
|
|
116
|
+
? '<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:image="http://www.google.com/schemas/sitemap-image/1.1">'
|
|
117
|
+
: '<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:image="http://www.google.com/schemas/sitemap-image/1.1">',
|
|
117
118
|
);
|
|
118
119
|
|
|
119
120
|
const writeUrl = async (entry: Entry, siblings: Entry[] | null) => {
|
|
@@ -127,6 +128,16 @@ export const GET: APIRoute = async ({ params, locals, url }) => {
|
|
|
127
128
|
lines.push(` <loc>${escapeXml(loc)}</loc>`);
|
|
128
129
|
lines.push(` <lastmod>${escapeXml(entry.updatedAt)}</lastmod>`);
|
|
129
130
|
|
|
131
|
+
// Google image sitemap extension: advertise the entry's SEO
|
|
132
|
+
// image (the same "preferred image" used for og:image) so it
|
|
133
|
+
// can be discovered and indexed for Google Images.
|
|
134
|
+
if (entry.image) {
|
|
135
|
+
const imageLoc = buildSeoImageUrl(entry.image, siteUrl);
|
|
136
|
+
lines.push(" <image:image>");
|
|
137
|
+
lines.push(` <image:loc>${escapeXml(imageLoc)}</image:loc>`);
|
|
138
|
+
lines.push(" </image:image>");
|
|
139
|
+
}
|
|
140
|
+
|
|
130
141
|
if (useXhtml && siblings && siblings.length > 1) {
|
|
131
142
|
// Emit one xhtml:link per sibling (including self -- Google
|
|
132
143
|
// recommends including the page's own hreflang annotation).
|
|
@@ -8,8 +8,12 @@
|
|
|
8
8
|
* but are read on every byline hydration (admin pages, content rendering,
|
|
9
9
|
* API responses). Caching at the isolate level drops the SELECT-from-
|
|
10
10
|
* `_emdash_byline_fields` from once-per-hydration to once-per-isolate-
|
|
11
|
-
* after-bump. The cache holds
|
|
12
|
-
*
|
|
11
|
+
* after-bump. The cache holds the resolved *value* behind a reclaimable
|
|
12
|
+
* single-flight lock (see `utils/single-flight-cache.ts`), never an
|
|
13
|
+
* in-flight promise: concurrent cold-isolate readers coalesce onto one
|
|
14
|
+
* query by polling the published value, so a reader whose request is
|
|
15
|
+
* cancelled mid-query can never strand later byline hydrations on the
|
|
16
|
+
* isolate (the workerd never-settling-promise hazard that produced 524s).
|
|
13
17
|
*
|
|
14
18
|
* Stored on globalThis under `Symbol.for("emdash:byline-field-defs")` so
|
|
15
19
|
* Vite SSR chunk duplication can't produce two independent caches (same
|
|
@@ -50,17 +54,23 @@
|
|
|
50
54
|
|
|
51
55
|
import type { Kysely } from "kysely";
|
|
52
56
|
|
|
57
|
+
import { after } from "../after.js";
|
|
53
58
|
import type { Database } from "../database/types.js";
|
|
54
59
|
import { requestCached } from "../request-cache.js";
|
|
55
60
|
import { getRequestContext } from "../request-context.js";
|
|
56
61
|
import { BylineSchemaRegistry } from "../schema/byline-registry.js";
|
|
57
62
|
import type { BylineFieldDefinition } from "../schema/types.js";
|
|
63
|
+
import { createInitLock, type InitLock, initWithLock } from "../utils/init-lock.js";
|
|
58
64
|
|
|
59
65
|
interface FieldDefsHolder {
|
|
60
|
-
/**
|
|
61
|
-
|
|
62
|
-
/**
|
|
66
|
+
/** Last resolved defs, valid only when `hasValue` is true. */
|
|
67
|
+
value: BylineFieldDefinition[] | null;
|
|
68
|
+
/** Presence flag, separate from `value` so an empty-array result still caches. */
|
|
69
|
+
hasValue: boolean;
|
|
70
|
+
/** Persisted-version value that `value` was fetched against. */
|
|
63
71
|
cachedVersion: number;
|
|
72
|
+
/** Reclaimable single-flight lock so a cancelled owner can't wedge readers. */
|
|
73
|
+
lock: InitLock;
|
|
64
74
|
}
|
|
65
75
|
|
|
66
76
|
const HOLDER_KEY = Symbol.for("emdash:byline-field-defs");
|
|
@@ -69,7 +79,12 @@ const holder: FieldDefsHolder =
|
|
|
69
79
|
// eslint-disable-next-line typescript/no-unsafe-type-assertion -- globalThis singleton pattern (see request-cache.ts)
|
|
70
80
|
(g[HOLDER_KEY] as FieldDefsHolder | undefined) ??
|
|
71
81
|
(() => {
|
|
72
|
-
const h: FieldDefsHolder = {
|
|
82
|
+
const h: FieldDefsHolder = {
|
|
83
|
+
value: null,
|
|
84
|
+
hasValue: false,
|
|
85
|
+
cachedVersion: -1,
|
|
86
|
+
lock: createInitLock(),
|
|
87
|
+
};
|
|
73
88
|
g[HOLDER_KEY] = h;
|
|
74
89
|
return h;
|
|
75
90
|
})();
|
|
@@ -77,6 +92,16 @@ const holder: FieldDefsHolder =
|
|
|
77
92
|
const REQUEST_CACHE_KEY_VERSION = "byline-fields-version";
|
|
78
93
|
const REQUEST_CACHE_KEY_DEFS_PREFIX = "byline-field-defs:";
|
|
79
94
|
|
|
95
|
+
/**
|
|
96
|
+
* Reclaim window for the single-flight lock: if an owner holds it past
|
|
97
|
+
* this without publishing (e.g. its request was cancelled and the
|
|
98
|
+
* anchored fetch hasn't completed yet), the next reader reclaims and
|
|
99
|
+
* refetches. `listFields` is a single fast SELECT, so this only needs to
|
|
100
|
+
* cover a genuinely slow/stranded query. Mutable solely so tests can
|
|
101
|
+
* shorten it; production never changes it.
|
|
102
|
+
*/
|
|
103
|
+
let reclaimDeadlineMs = 10_000;
|
|
104
|
+
|
|
80
105
|
/**
|
|
81
106
|
* Read the persisted `options.byline_fields_version` counter. Cached for
|
|
82
107
|
* the duration of the current request via `requestCached`. Returns `0`
|
|
@@ -107,19 +132,29 @@ export async function getBylineFieldDefs(db: Kysely<Database>): Promise<BylineFi
|
|
|
107
132
|
if (isolated || dirty) {
|
|
108
133
|
return new BylineSchemaRegistry(db).listFields();
|
|
109
134
|
}
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
135
|
+
// Per-isolate single-flight cache keyed on the persisted version.
|
|
136
|
+
// Coalesce concurrent cold readers via the lock and read the
|
|
137
|
+
// published value; never await another request's in-flight promise
|
|
138
|
+
// (a cancelled owner would otherwise strand every later byline
|
|
139
|
+
// hydration on the isolate). The fetch is anchored so a cancelled
|
|
140
|
+
// originator still drives it to completion and populates the cache.
|
|
141
|
+
return initWithLock<BylineFieldDefinition[]>(
|
|
142
|
+
holder.lock,
|
|
143
|
+
() => (holder.hasValue && holder.cachedVersion === version ? holder.value : null),
|
|
144
|
+
(isCurrentClaim) =>
|
|
145
|
+
(async () => {
|
|
146
|
+
const defs = await new BylineSchemaRegistry(db).listFields();
|
|
147
|
+
// Publish only while still the current claim, and never
|
|
148
|
+
// regress over a newer version a concurrent reader stored.
|
|
149
|
+
if (isCurrentClaim() && version >= holder.cachedVersion) {
|
|
150
|
+
holder.value = defs;
|
|
151
|
+
holder.hasValue = true;
|
|
152
|
+
holder.cachedVersion = version;
|
|
153
|
+
}
|
|
154
|
+
return defs;
|
|
155
|
+
})(),
|
|
156
|
+
{ deadlineMs: reclaimDeadlineMs, anchor: (promise) => after(() => promise) },
|
|
157
|
+
);
|
|
123
158
|
});
|
|
124
159
|
}
|
|
125
160
|
|
|
@@ -133,6 +168,21 @@ export async function getBylineFieldDefs(db: Kysely<Database>): Promise<BylineFi
|
|
|
133
168
|
* coordination that lets other isolates see the change.
|
|
134
169
|
*/
|
|
135
170
|
export function resetBylineFieldDefsCacheForTests(): void {
|
|
136
|
-
holder.
|
|
171
|
+
holder.value = null;
|
|
172
|
+
holder.hasValue = false;
|
|
137
173
|
holder.cachedVersion = -1;
|
|
174
|
+
holder.lock.ownerStartedAt = null;
|
|
175
|
+
holder.lock.generation = 0;
|
|
176
|
+
reclaimDeadlineMs = 10_000;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Test-only: shorten the single-flight reclaim window so a "stranded
|
|
181
|
+
* owner" scenario can be exercised without waiting out the production
|
|
182
|
+
* deadline. Reset by `resetBylineFieldDefsCacheForTests`.
|
|
183
|
+
*
|
|
184
|
+
* @internal
|
|
185
|
+
*/
|
|
186
|
+
export function setBylineFieldDefsReclaimDeadlineForTests(ms: number): void {
|
|
187
|
+
reclaimDeadlineMs = ms;
|
|
138
188
|
}
|
|
@@ -13,6 +13,7 @@ import { pipeline } from "node:stream/promises";
|
|
|
13
13
|
import { imageSize } from "image-size";
|
|
14
14
|
import { packTar } from "modern-tar/fs";
|
|
15
15
|
|
|
16
|
+
import { capabilitiesToDeclaredAccess } from "../../plugins/types.js";
|
|
16
17
|
import type {
|
|
17
18
|
PluginManifest,
|
|
18
19
|
ResolvedPlugin,
|
|
@@ -151,6 +152,7 @@ export function extractManifest(plugin: ResolvedPlugin): PluginManifest {
|
|
|
151
152
|
return {
|
|
152
153
|
id: plugin.id,
|
|
153
154
|
version: plugin.version,
|
|
155
|
+
declaredAccess: capabilitiesToDeclaredAccess(plugin.capabilities, plugin.allowedHosts),
|
|
154
156
|
capabilities: plugin.capabilities,
|
|
155
157
|
allowedHosts: plugin.allowedHosts,
|
|
156
158
|
storage: plugin.storage,
|
|
@@ -124,7 +124,7 @@ async function checkDatabase(dbPath: string): Promise<CheckResult[]> {
|
|
|
124
124
|
try {
|
|
125
125
|
const usersResult = await sql<{
|
|
126
126
|
count: number;
|
|
127
|
-
}>`SELECT COUNT(id) as count FROM
|
|
127
|
+
}>`SELECT COUNT(id) as count FROM users`.execute(db);
|
|
128
128
|
const count = usersResult.rows[0]?.count ?? 0;
|
|
129
129
|
results.push({
|
|
130
130
|
name: "users",
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Pure (no-DB) commands for working with EmDash secrets:
|
|
5
5
|
*
|
|
6
6
|
* - `emdash secrets generate` — emits a fresh `EMDASH_ENCRYPTION_KEY`.
|
|
7
|
-
* Optionally writes it to
|
|
7
|
+
* Optionally writes it to a local-secrets file (`.env`).
|
|
8
8
|
* - `emdash secrets fingerprint <key>` — prints the kid for a key,
|
|
9
9
|
* useful in CI for verifying what's been deployed without exposing
|
|
10
10
|
* the raw value.
|
|
@@ -87,7 +87,7 @@ const generateCommand = defineCommand({
|
|
|
87
87
|
write: {
|
|
88
88
|
type: "string",
|
|
89
89
|
description:
|
|
90
|
-
"Optional path to write the key to (e.g. .
|
|
90
|
+
"Optional path to write the key to (e.g. .env). " +
|
|
91
91
|
"Won't overwrite an existing entry without --force.",
|
|
92
92
|
},
|
|
93
93
|
force: {
|
package/src/config/secrets.ts
CHANGED
|
@@ -31,9 +31,15 @@ import { sha256 } from "@oslojs/crypto/sha2";
|
|
|
31
31
|
import { encodeHexLowerCase } from "@oslojs/encoding";
|
|
32
32
|
import type { Kysely } from "kysely";
|
|
33
33
|
|
|
34
|
+
import { after } from "../after.js";
|
|
34
35
|
import { OptionsRepository } from "../database/repositories/options.js";
|
|
35
36
|
import type { Database } from "../database/types.js";
|
|
36
37
|
import { decodeBase64url, encodeBase64url } from "../utils/base64.js";
|
|
38
|
+
import {
|
|
39
|
+
createSingleFlightCache,
|
|
40
|
+
type SingleFlightCache,
|
|
41
|
+
singleFlightCached,
|
|
42
|
+
} from "../utils/single-flight-cache.js";
|
|
37
43
|
|
|
38
44
|
/** v1 encryption key prefix. Bumping requires a separate KDF version. */
|
|
39
45
|
export const ENCRYPTION_KEY_PREFIX = "emdash_enc_v1_";
|
|
@@ -370,17 +376,23 @@ export async function validateEncryptionKeyAtStartup(env?: SecretsEnv): Promise<
|
|
|
370
376
|
*
|
|
371
377
|
* Lives on `globalThis` so module-duplication during SSR bundling can't
|
|
372
378
|
* fragment the cache. See `request-context.ts` for the same pattern.
|
|
379
|
+
*
|
|
380
|
+
* Each db gets its own poison-immune single-flight cache (see
|
|
381
|
+
* `utils/single-flight-cache.ts`): the resolved *value* is cached, never an
|
|
382
|
+
* in-flight promise, so a request cancelled mid-resolve can't strand later
|
|
383
|
+
* preview/comment requests on the isolate.
|
|
373
384
|
*/
|
|
374
385
|
// Versioned to prevent cache fragmentation if `ResolvedSecrets`'s shape
|
|
375
386
|
// ever changes. Bump the suffix on incompatible changes so a co-resident
|
|
376
|
-
// older build doesn't read a newer-shape value.
|
|
377
|
-
|
|
387
|
+
// older build doesn't read a newer-shape value. Bumped to @2 when the cached
|
|
388
|
+
// value changed from a bare promise to a single-flight cache.
|
|
389
|
+
const SECRETS_CACHE_KEY = Symbol.for("@emdash-cms/core/secrets-cache@2");
|
|
378
390
|
|
|
379
391
|
interface SecretsCacheHolder {
|
|
380
|
-
cache: WeakMap<Kysely<Database>,
|
|
392
|
+
cache: WeakMap<Kysely<Database>, SingleFlightCache<ResolvedSecrets>>;
|
|
381
393
|
}
|
|
382
394
|
|
|
383
|
-
function getSecretsCache(): WeakMap<Kysely<Database>,
|
|
395
|
+
function getSecretsCache(): WeakMap<Kysely<Database>, SingleFlightCache<ResolvedSecrets>> {
|
|
384
396
|
// eslint-disable-next-line typescript/no-unsafe-type-assertion -- globalThis singleton pattern
|
|
385
397
|
const holder = globalThis as Record<symbol, SecretsCacheHolder | undefined>;
|
|
386
398
|
let entry = holder[SECRETS_CACHE_KEY];
|
|
@@ -397,19 +409,21 @@ function getSecretsCache(): WeakMap<Kysely<Database>, Promise<ResolvedSecrets>>
|
|
|
397
409
|
* env / re-query options on every request.
|
|
398
410
|
*
|
|
399
411
|
* The cache is keyed by `Kysely` instance, so playground / per-DO / per-test
|
|
400
|
-
* databases each get their own resolution.
|
|
412
|
+
* databases each get their own resolution. Concurrent cold callers coalesce
|
|
413
|
+
* onto one resolution via the single-flight lock; a failed resolution
|
|
414
|
+
* propagates to the caller and releases the lock so the next caller retries.
|
|
401
415
|
*/
|
|
402
416
|
export function resolveSecretsCached(db: Kysely<Database>): Promise<ResolvedSecrets> {
|
|
403
|
-
const
|
|
404
|
-
|
|
405
|
-
if (
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
417
|
+
const caches = getSecretsCache();
|
|
418
|
+
let cache = caches.get(db);
|
|
419
|
+
if (!cache) {
|
|
420
|
+
cache = createSingleFlightCache<ResolvedSecrets>();
|
|
421
|
+
caches.set(db, cache);
|
|
422
|
+
}
|
|
423
|
+
return singleFlightCached(cache, () => resolveSecrets({ db }), {
|
|
424
|
+
anchor: (promise) => after(() => promise),
|
|
425
|
+
ownerTimeoutMs: 30_000,
|
|
410
426
|
});
|
|
411
|
-
cache.set(db, promise);
|
|
412
|
-
return promise;
|
|
413
427
|
}
|
|
414
428
|
|
|
415
429
|
/**
|
|
@@ -110,3 +110,16 @@ function kyselyLog(event: LogEvent): void {
|
|
|
110
110
|
export function kyselyLogOption(): Logger {
|
|
111
111
|
return kyselyLog;
|
|
112
112
|
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Record physical database round trips for the current request.
|
|
116
|
+
*
|
|
117
|
+
* Called by backends that batch (the DO SQL driver coalesces same-turn SELECTs
|
|
118
|
+
* into one RPC), so we can see round-trip count separately from logical query
|
|
119
|
+
* count (`dbCount`, bumped by the Kysely log hook). No-op outside a request or
|
|
120
|
+
* when metrics aren't attached (e.g. migrations on the singleton).
|
|
121
|
+
*/
|
|
122
|
+
export function recordRpc(count = 1): void {
|
|
123
|
+
const ctx = getRequestContext();
|
|
124
|
+
if (ctx?.metrics) ctx.metrics.rpcCount += count;
|
|
125
|
+
}
|
package/src/emdash-runtime.ts
CHANGED
|
@@ -45,6 +45,7 @@ import type {
|
|
|
45
45
|
import type { FieldType } from "./schema/types.js";
|
|
46
46
|
import { hashString } from "./utils/hash.js";
|
|
47
47
|
import { createInitLock, type InitLock, initWithLock } from "./utils/init-lock.js";
|
|
48
|
+
import { createSingleFlightCache, singleFlightCached } from "./utils/single-flight-cache.js";
|
|
48
49
|
import { COMMIT, VERSION } from "./version.js";
|
|
49
50
|
|
|
50
51
|
const LEADING_SLASH_PATTERN = /^\//;
|
|
@@ -417,12 +418,12 @@ export class EmDashRuntime {
|
|
|
417
418
|
private pluginStates: Map<string, string>;
|
|
418
419
|
|
|
419
420
|
/**
|
|
420
|
-
*
|
|
421
|
-
*
|
|
422
|
-
*
|
|
421
|
+
* Isolate-lifetime guard so FTS indexes are verified at most once per
|
|
422
|
+
* worker rather than on every admin request. See ensureSearchHealthy().
|
|
423
|
+
* Uses the poison-immune single-flight cache (never a shared awaitable
|
|
424
|
+
* promise) so a cancelled first caller can't wedge later ones.
|
|
423
425
|
*/
|
|
424
|
-
private
|
|
425
|
-
private _searchHealthPromise: Promise<void> | null = null;
|
|
426
|
+
private readonly _searchHealthCache = createSingleFlightCache<void>();
|
|
426
427
|
|
|
427
428
|
/** Current hook pipeline. Use the `hooks` getter for external access. */
|
|
428
429
|
get hooks(): HookPipeline {
|
|
@@ -2228,27 +2229,32 @@ export class EmDashRuntime {
|
|
|
2228
2229
|
* defend against FTS not existing yet (pre-setup).
|
|
2229
2230
|
*/
|
|
2230
2231
|
async ensureSearchHealthy(): Promise<void> {
|
|
2231
|
-
|
|
2232
|
-
|
|
2233
|
-
if (!isSqlite(this._db))
|
|
2234
|
-
|
|
2235
|
-
|
|
2232
|
+
// Non-SQLite has no FTS to verify; the check is a cheap synchronous
|
|
2233
|
+
// branch, no need to cache it.
|
|
2234
|
+
if (!isSqlite(this._db)) return;
|
|
2235
|
+
try {
|
|
2236
|
+
await singleFlightCached(
|
|
2237
|
+
this._searchHealthCache,
|
|
2238
|
+
async () => {
|
|
2239
|
+
try {
|
|
2240
|
+
const ftsManager = new FTSManager(this._db);
|
|
2241
|
+
const repaired = await ftsManager.verifyAndRepairAll();
|
|
2242
|
+
if (repaired > 0) {
|
|
2243
|
+
console.log(`Repaired ${repaired} corrupted FTS index(es)`);
|
|
2244
|
+
}
|
|
2245
|
+
} catch {
|
|
2246
|
+
// FTS tables may not exist yet (pre-setup). Non-fatal — cache
|
|
2247
|
+
// the "checked" state regardless so we don't re-scan.
|
|
2248
|
+
}
|
|
2249
|
+
},
|
|
2250
|
+
{ anchor: (promise) => after(() => promise), ownerTimeoutMs: 30_000 },
|
|
2251
|
+
);
|
|
2252
|
+
} catch {
|
|
2253
|
+
// This check is best-effort and must never fail the calling request.
|
|
2254
|
+
// The inner body already swallows verify errors; this guards the
|
|
2255
|
+
// outer failure modes (owner timeout, waiter give-up) so a slow FTS
|
|
2256
|
+
// scan degrades to "unverified", not a 500 on admin/search routes.
|
|
2236
2257
|
}
|
|
2237
|
-
this._searchHealthPromise = (async () => {
|
|
2238
|
-
try {
|
|
2239
|
-
const ftsManager = new FTSManager(this._db);
|
|
2240
|
-
const repaired = await ftsManager.verifyAndRepairAll();
|
|
2241
|
-
if (repaired > 0) {
|
|
2242
|
-
console.log(`Repaired ${repaired} corrupted FTS index(es)`);
|
|
2243
|
-
}
|
|
2244
|
-
} catch {
|
|
2245
|
-
// FTS tables may not exist yet (pre-setup). Non-fatal.
|
|
2246
|
-
} finally {
|
|
2247
|
-
this._searchHealthChecked = true;
|
|
2248
|
-
this._searchHealthPromise = null;
|
|
2249
|
-
}
|
|
2250
|
-
})();
|
|
2251
|
-
return this._searchHealthPromise;
|
|
2252
2258
|
}
|
|
2253
2259
|
|
|
2254
2260
|
// =========================================================================
|
package/src/loader.ts
CHANGED
|
@@ -680,7 +680,12 @@ export function emdashLoader(): LiveLoader<EntryData, EntryFilter, CollectionFil
|
|
|
680
680
|
|
|
681
681
|
// Separate taxonomy / byline filters from field filters
|
|
682
682
|
let result: { rows: Record<string, unknown>[] };
|
|
683
|
-
|
|
683
|
+
// Taxonomy filters AND together: each entry constrains the base
|
|
684
|
+
// row to match at least one of its slugs *within that taxonomy*.
|
|
685
|
+
// Term slugs are unique only within a taxonomy, so every filter
|
|
686
|
+
// keeps its own `name` and emits its own `EXISTS` clause rather
|
|
687
|
+
// than pooling slugs into one `IN`.
|
|
688
|
+
const taxonomyFilters: { name: string; slugs: string[] }[] = [];
|
|
684
689
|
// A byline filter matches entries credited to any of the given
|
|
685
690
|
// byline translation groups via the `_emdash_content_bylines`
|
|
686
691
|
// junction table. `null` means no byline filter; an empty
|
|
@@ -710,14 +715,8 @@ export function emdashLoader(): LiveLoader<EntryData, EntryFilter, CollectionFil
|
|
|
710
715
|
);
|
|
711
716
|
continue;
|
|
712
717
|
}
|
|
713
|
-
if (taxonomyFilter) {
|
|
714
|
-
console.warn(
|
|
715
|
-
`[emdash] where filter: only one taxonomy is supported per query, "${key}" ignored`,
|
|
716
|
-
);
|
|
717
|
-
continue;
|
|
718
|
-
}
|
|
719
718
|
const slugs = Array.isArray(value) ? value : [value];
|
|
720
|
-
|
|
719
|
+
taxonomyFilters.push({ name: key, slugs });
|
|
721
720
|
} else {
|
|
722
721
|
fieldFilters[key] = value;
|
|
723
722
|
}
|
|
@@ -729,7 +728,7 @@ export function emdashLoader(): LiveLoader<EntryData, EntryFilter, CollectionFil
|
|
|
729
728
|
// SQL on both dialects).
|
|
730
729
|
if (
|
|
731
730
|
(bylineFilter && bylineFilter.groups.length === 0) ||
|
|
732
|
-
(
|
|
731
|
+
taxonomyFilters.some((f) => f.slugs.length === 0)
|
|
733
732
|
) {
|
|
734
733
|
return { entries: [], cacheHint: { tags: [type] } };
|
|
735
734
|
}
|
|
@@ -753,16 +752,26 @@ export function emdashLoader(): LiveLoader<EntryData, EntryFilter, CollectionFil
|
|
|
753
752
|
const fieldCondsSQL =
|
|
754
753
|
fieldConds.length > 0 ? sql`${sql.join(fieldConds, sql` AND `)}` : null;
|
|
755
754
|
|
|
756
|
-
|
|
757
|
-
|
|
755
|
+
// One `EXISTS` per taxonomy, AND'd together: an entry must be
|
|
756
|
+
// tagged with a matching term in *every* requested taxonomy.
|
|
757
|
+
// Each clause pins its own `t.name`, so slugs never pool
|
|
758
|
+
// across taxonomies (they're only unique within one).
|
|
759
|
+
const taxonomyCond =
|
|
760
|
+
taxonomyFilters.length > 0
|
|
761
|
+
? sql`${sql.join(
|
|
762
|
+
taxonomyFilters.map(
|
|
763
|
+
(f) => sql`AND EXISTS (
|
|
758
764
|
SELECT 1 FROM content_taxonomies ct
|
|
759
765
|
INNER JOIN taxonomies t ON t.id = ct.taxonomy_id
|
|
760
766
|
WHERE ct.collection = ${type}
|
|
761
767
|
AND ct.entry_id = ${sql.ref(tableName)}.id
|
|
762
|
-
AND t.name = ${
|
|
763
|
-
AND t.slug IN (${sql.join(
|
|
764
|
-
)
|
|
765
|
-
|
|
768
|
+
AND t.name = ${f.name}
|
|
769
|
+
AND t.slug IN (${sql.join(f.slugs.map((s) => sql`${s}`))})
|
|
770
|
+
)`,
|
|
771
|
+
),
|
|
772
|
+
sql` `,
|
|
773
|
+
)}`
|
|
774
|
+
: sql``;
|
|
766
775
|
|
|
767
776
|
// `_emdash_content_bylines.byline_id` stores the byline's
|
|
768
777
|
// translation_group (migration 040), so a credit spans every
|