emdash 0.20.0 → 0.22.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-BzIHV3sw.d.mts → adapters-hUy8vOB-.d.mts} +1 -1
- package/dist/{adapters-BzIHV3sw.d.mts.map → adapters-hUy8vOB-.d.mts.map} +1 -1
- package/dist/after-B1IIdH3Y.mjs +29 -0
- package/dist/after-B1IIdH3Y.mjs.map +1 -0
- package/dist/{allowed-origins-B1u7Qnvg.mjs → allowed-origins-DjlhyfNN.mjs} +2 -2
- package/dist/{allowed-origins-B1u7Qnvg.mjs.map → allowed-origins-DjlhyfNN.mjs.map} +1 -1
- package/dist/api/route-utils.d.mts +3 -3
- package/dist/api/route-utils.mjs +20 -18
- package/dist/api/route-utils.mjs.map +1 -1
- package/dist/api/schemas/index.d.mts +2 -2
- package/dist/api/schemas/index.mjs +4 -3
- package/dist/{api-DStv36ik.mjs → api-BDuM4bEy.mjs} +31 -25
- package/dist/api-BDuM4bEy.mjs.map +1 -0
- package/dist/{api-tokens-DPfhPu5V.mjs → api-tokens-ViYKeIp9.mjs} +13 -3
- package/dist/api-tokens-ViYKeIp9.mjs.map +1 -0
- package/dist/{apply-Dr7snAMT.mjs → apply-wDqQoxX4.mjs} +18 -18
- package/dist/{apply-Dr7snAMT.mjs.map → apply-wDqQoxX4.mjs.map} +1 -1
- package/dist/astro/image-endpoint.d.mts +8 -0
- package/dist/astro/image-endpoint.d.mts.map +1 -0
- package/dist/astro/image-endpoint.mjs +55 -0
- package/dist/astro/image-endpoint.mjs.map +1 -0
- package/dist/astro/index.d.mts +36 -11
- package/dist/astro/index.d.mts.map +1 -1
- package/dist/astro/index.mjs +160 -35
- package/dist/astro/index.mjs.map +1 -1
- package/dist/astro/middleware/auth.d.mts +9 -9
- package/dist/astro/middleware/auth.d.mts.map +1 -1
- package/dist/astro/middleware/auth.mjs +12 -10
- package/dist/astro/middleware/auth.mjs.map +1 -1
- package/dist/astro/middleware/redirect.d.mts.map +1 -1
- package/dist/astro/middleware/redirect.mjs +14 -5
- package/dist/astro/middleware/redirect.mjs.map +1 -1
- package/dist/astro/middleware/request-context.mjs +5 -4
- 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 +157 -80
- package/dist/astro/middleware.mjs.map +1 -1
- package/dist/astro/routes/api/admin/allowed-domains/_domain_.mjs +7 -6
- package/dist/astro/routes/api/admin/allowed-domains/_domain_.mjs.map +1 -1
- package/dist/astro/routes/api/admin/allowed-domains/index.mjs +7 -6
- package/dist/astro/routes/api/admin/allowed-domains/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/api-tokens/_id_.mjs +5 -5
- package/dist/astro/routes/api/admin/api-tokens/index.mjs +6 -6
- package/dist/astro/routes/api/admin/byline-fields/_slug_/usage.mjs +6 -6
- package/dist/astro/routes/api/admin/byline-fields/_slug_.mjs +10 -9
- package/dist/astro/routes/api/admin/byline-fields/_slug_.mjs.map +1 -1
- package/dist/astro/routes/api/admin/byline-fields/index.mjs +10 -9
- package/dist/astro/routes/api/admin/byline-fields/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/byline-fields/reorder.mjs +10 -9
- package/dist/astro/routes/api/admin/byline-fields/reorder.mjs.map +1 -1
- package/dist/astro/routes/api/admin/bylines/_id_/index.mjs +17 -14
- package/dist/astro/routes/api/admin/bylines/_id_/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/bylines/_id_/translations.mjs +17 -14
- package/dist/astro/routes/api/admin/bylines/_id_/translations.mjs.map +1 -1
- package/dist/astro/routes/api/admin/bylines/index.mjs +17 -14
- package/dist/astro/routes/api/admin/bylines/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/comments/_id_/status.mjs +15 -12
- package/dist/astro/routes/api/admin/comments/_id_/status.mjs.map +1 -1
- package/dist/astro/routes/api/admin/comments/_id_.mjs +8 -6
- package/dist/astro/routes/api/admin/comments/_id_.mjs.map +1 -1
- package/dist/astro/routes/api/admin/comments/bulk.mjs +12 -9
- package/dist/astro/routes/api/admin/comments/bulk.mjs.map +1 -1
- package/dist/astro/routes/api/admin/comments/counts.mjs +8 -6
- package/dist/astro/routes/api/admin/comments/counts.mjs.map +1 -1
- package/dist/astro/routes/api/admin/comments/index.mjs +12 -9
- package/dist/astro/routes/api/admin/comments/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/hooks/exclusive/_hookName_.mjs +6 -6
- package/dist/astro/routes/api/admin/hooks/exclusive/index.mjs +5 -5
- package/dist/astro/routes/api/admin/oauth-clients/_id_.mjs +5 -5
- package/dist/astro/routes/api/admin/oauth-clients/index.mjs +5 -5
- package/dist/astro/routes/api/admin/plugins/_id_/disable.mjs +40 -37
- package/dist/astro/routes/api/admin/plugins/_id_/disable.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/_id_/enable.mjs +40 -37
- package/dist/astro/routes/api/admin/plugins/_id_/enable.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/_id_/index.mjs +39 -36
- package/dist/astro/routes/api/admin/plugins/_id_/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/_id_/uninstall.mjs +39 -36
- package/dist/astro/routes/api/admin/plugins/_id_/uninstall.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/_id_/update.mjs +39 -36
- package/dist/astro/routes/api/admin/plugins/_id_/update.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/index.mjs +39 -36
- package/dist/astro/routes/api/admin/plugins/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/marketplace/_id_/icon.mjs +4 -4
- package/dist/astro/routes/api/admin/plugins/marketplace/_id_/index.mjs +39 -36
- 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 +39 -36
- package/dist/astro/routes/api/admin/plugins/marketplace/_id_/install.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/marketplace/index.mjs +39 -36
- package/dist/astro/routes/api/admin/plugins/marketplace/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/registry/_id_/uninstall.mjs +39 -36
- 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 +40 -37
- package/dist/astro/routes/api/admin/plugins/registry/_id_/update.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/registry/artifact.mjs +39 -36
- package/dist/astro/routes/api/admin/plugins/registry/artifact.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/registry/install.mjs +40 -37
- package/dist/astro/routes/api/admin/plugins/registry/install.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/updates.mjs +39 -36
- package/dist/astro/routes/api/admin/plugins/updates.mjs.map +1 -1
- package/dist/astro/routes/api/admin/themes/marketplace/_id_/index.mjs +39 -36
- 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 +4 -4
- package/dist/astro/routes/api/admin/themes/marketplace/index.mjs +39 -36
- package/dist/astro/routes/api/admin/themes/marketplace/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/users/_id_/disable.mjs +4 -4
- package/dist/astro/routes/api/admin/users/_id_/enable.mjs +3 -3
- package/dist/astro/routes/api/admin/users/_id_/index.mjs +8 -7
- package/dist/astro/routes/api/admin/users/_id_/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/users/_id_/send-recovery.mjs +5 -5
- package/dist/astro/routes/api/admin/users/index.mjs +7 -6
- package/dist/astro/routes/api/admin/users/index.mjs.map +1 -1
- package/dist/astro/routes/api/auth/dev-bypass.mjs +6 -6
- package/dist/astro/routes/api/auth/invite/accept.mjs +3 -3
- package/dist/astro/routes/api/auth/invite/complete.mjs +12 -11
- package/dist/astro/routes/api/auth/invite/complete.mjs.map +1 -1
- package/dist/astro/routes/api/auth/invite/index.mjs +9 -8
- package/dist/astro/routes/api/auth/invite/index.mjs.map +1 -1
- package/dist/astro/routes/api/auth/invite/register-options.mjs +11 -10
- package/dist/astro/routes/api/auth/invite/register-options.mjs.map +1 -1
- package/dist/astro/routes/api/auth/logout.mjs +4 -4
- package/dist/astro/routes/api/auth/magic-link/send.mjs +11 -10
- package/dist/astro/routes/api/auth/magic-link/send.mjs.map +1 -1
- package/dist/astro/routes/api/auth/magic-link/verify.mjs +4 -4
- package/dist/astro/routes/api/auth/me.mjs +8 -7
- 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 +4 -4
- package/dist/astro/routes/api/auth/oauth/_provider_.mjs +2 -2
- package/dist/astro/routes/api/auth/passkey/_id_.mjs +7 -6
- package/dist/astro/routes/api/auth/passkey/_id_.mjs.map +1 -1
- package/dist/astro/routes/api/auth/passkey/index.mjs +3 -3
- package/dist/astro/routes/api/auth/passkey/options.mjs +13 -12
- package/dist/astro/routes/api/auth/passkey/options.mjs.map +1 -1
- package/dist/astro/routes/api/auth/passkey/register/options.mjs +11 -10
- package/dist/astro/routes/api/auth/passkey/register/options.mjs.map +1 -1
- package/dist/astro/routes/api/auth/passkey/register/verify.mjs +12 -11
- package/dist/astro/routes/api/auth/passkey/register/verify.mjs.map +1 -1
- package/dist/astro/routes/api/auth/passkey/verify.mjs +12 -11
- package/dist/astro/routes/api/auth/passkey/verify.mjs.map +1 -1
- package/dist/astro/routes/api/auth/signup/complete.mjs +12 -11
- package/dist/astro/routes/api/auth/signup/complete.mjs.map +1 -1
- package/dist/astro/routes/api/auth/signup/request.mjs +11 -10
- package/dist/astro/routes/api/auth/signup/request.mjs.map +1 -1
- package/dist/astro/routes/api/auth/signup/verify.mjs +3 -3
- package/dist/astro/routes/api/comments/_collection_/_contentId_/index.mjs +16 -13
- package/dist/astro/routes/api/comments/_collection_/_contentId_/index.mjs.map +1 -1
- package/dist/astro/routes/api/comments/_collection_/_contentId_/reactions.d.mts +9 -0
- package/dist/astro/routes/api/comments/_collection_/_contentId_/reactions.d.mts.map +1 -0
- package/dist/astro/routes/api/comments/_collection_/_contentId_/reactions.mjs +179 -0
- package/dist/astro/routes/api/comments/_collection_/_contentId_/reactions.mjs.map +1 -0
- package/dist/astro/routes/api/content/_collection_/_id_/compare.mjs +4 -4
- package/dist/astro/routes/api/content/_collection_/_id_/discard-draft.mjs +4 -4
- package/dist/astro/routes/api/content/_collection_/_id_/duplicate.mjs +4 -4
- package/dist/astro/routes/api/content/_collection_/_id_/permanent.mjs +4 -4
- package/dist/astro/routes/api/content/_collection_/_id_/preview-url.mjs +13 -11
- package/dist/astro/routes/api/content/_collection_/_id_/preview-url.mjs.map +1 -1
- package/dist/astro/routes/api/content/_collection_/_id_/publish.mjs +8 -7
- package/dist/astro/routes/api/content/_collection_/_id_/publish.mjs.map +1 -1
- package/dist/astro/routes/api/content/_collection_/_id_/restore.mjs +4 -4
- package/dist/astro/routes/api/content/_collection_/_id_/revisions.mjs +4 -4
- package/dist/astro/routes/api/content/_collection_/_id_/schedule.mjs +8 -7
- package/dist/astro/routes/api/content/_collection_/_id_/schedule.mjs.map +1 -1
- package/dist/astro/routes/api/content/_collection_/_id_/terms/_taxonomy_.mjs +17 -14
- package/dist/astro/routes/api/content/_collection_/_id_/terms/_taxonomy_.mjs.map +1 -1
- package/dist/astro/routes/api/content/_collection_/_id_/translations.mjs +4 -4
- package/dist/astro/routes/api/content/_collection_/_id_/unpublish.mjs +4 -4
- package/dist/astro/routes/api/content/_collection_/_id_.mjs +8 -7
- package/dist/astro/routes/api/content/_collection_/_id_.mjs.map +1 -1
- package/dist/astro/routes/api/content/_collection_/authors.mjs +4 -4
- package/dist/astro/routes/api/content/_collection_/index.mjs +8 -7
- package/dist/astro/routes/api/content/_collection_/index.mjs.map +1 -1
- package/dist/astro/routes/api/content/_collection_/trash.mjs +8 -7
- package/dist/astro/routes/api/content/_collection_/trash.mjs.map +1 -1
- package/dist/astro/routes/api/dashboard.mjs +10 -8
- package/dist/astro/routes/api/dashboard.mjs.map +1 -1
- package/dist/astro/routes/api/dev/emails.mjs +4 -4
- package/dist/astro/routes/api/import/probe.d.mts +3 -3
- package/dist/astro/routes/api/import/probe.mjs +12 -11
- package/dist/astro/routes/api/import/probe.mjs.map +1 -1
- package/dist/astro/routes/api/import/wordpress/analyze.mjs +5 -5
- package/dist/astro/routes/api/import/wordpress/execute.d.mts +9 -9
- package/dist/astro/routes/api/import/wordpress/execute.mjs +16 -14
- package/dist/astro/routes/api/import/wordpress/execute.mjs.map +1 -1
- package/dist/astro/routes/api/import/wordpress/media.mjs +10 -9
- package/dist/astro/routes/api/import/wordpress/media.mjs.map +1 -1
- package/dist/astro/routes/api/import/wordpress/prepare.mjs +11 -10
- package/dist/astro/routes/api/import/wordpress/prepare.mjs.map +1 -1
- package/dist/astro/routes/api/import/wordpress/rewrite-urls.mjs +10 -9
- 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 +12 -11
- package/dist/astro/routes/api/import/wordpress-plugin/analyze.mjs.map +1 -1
- package/dist/astro/routes/api/import/wordpress-plugin/callback.mjs +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 +18 -15
- package/dist/astro/routes/api/import/wordpress-plugin/execute.mjs.map +1 -1
- package/dist/astro/routes/api/manifest.mjs +5 -5
- package/dist/astro/routes/api/mcp.mjs +213 -45
- package/dist/astro/routes/api/mcp.mjs.map +1 -1
- package/dist/astro/routes/api/media/_id_/confirm.mjs +8 -7
- package/dist/astro/routes/api/media/_id_/confirm.mjs.map +1 -1
- package/dist/astro/routes/api/media/_id_.mjs +8 -7
- package/dist/astro/routes/api/media/_id_.mjs.map +1 -1
- package/dist/astro/routes/api/media/file/_...key_.mjs +3 -3
- package/dist/astro/routes/api/media/providers/_providerId_/_itemId_.mjs +4 -4
- package/dist/astro/routes/api/media/providers/_providerId_/index.mjs +4 -4
- package/dist/astro/routes/api/media/providers/index.mjs +4 -4
- package/dist/astro/routes/api/media/upload-url.mjs +10 -9
- package/dist/astro/routes/api/media/upload-url.mjs.map +1 -1
- package/dist/astro/routes/api/media.mjs +13 -12
- package/dist/astro/routes/api/media.mjs.map +1 -1
- package/dist/astro/routes/api/menus/_name_/items/_id_.mjs +11 -8
- package/dist/astro/routes/api/menus/_name_/items/_id_.mjs.map +1 -1
- package/dist/astro/routes/api/menus/_name_/items.mjs +11 -8
- package/dist/astro/routes/api/menus/_name_/items.mjs.map +1 -1
- package/dist/astro/routes/api/menus/_name_/reorder.mjs +11 -8
- package/dist/astro/routes/api/menus/_name_/reorder.mjs.map +1 -1
- package/dist/astro/routes/api/menus/_name_/translations.mjs +11 -8
- package/dist/astro/routes/api/menus/_name_/translations.mjs.map +1 -1
- package/dist/astro/routes/api/menus/_name_.mjs +11 -8
- package/dist/astro/routes/api/menus/_name_.mjs.map +1 -1
- package/dist/astro/routes/api/menus/index.mjs +11 -8
- 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 +7 -7
- package/dist/astro/routes/api/oauth/device/code.mjs +10 -10
- package/dist/astro/routes/api/oauth/device/token.mjs +9 -9
- package/dist/astro/routes/api/oauth/register.mjs +4 -4
- package/dist/astro/routes/api/oauth/token/refresh.mjs +7 -7
- package/dist/astro/routes/api/oauth/token/revoke.mjs +7 -7
- package/dist/astro/routes/api/oauth/token.mjs +7 -7
- package/dist/astro/routes/api/openapi.json.mjs +5 -4
- package/dist/astro/routes/api/openapi.json.mjs.map +1 -1
- package/dist/astro/routes/api/plugins/_pluginId_/_...path_.mjs +5 -5
- package/dist/astro/routes/api/redirects/404s/index.mjs +11 -10
- package/dist/astro/routes/api/redirects/404s/index.mjs.map +1 -1
- package/dist/astro/routes/api/redirects/404s/summary.mjs +11 -10
- package/dist/astro/routes/api/redirects/404s/summary.mjs.map +1 -1
- package/dist/astro/routes/api/redirects/_id_.mjs +12 -11
- package/dist/astro/routes/api/redirects/_id_.mjs.map +1 -1
- package/dist/astro/routes/api/redirects/index.mjs +12 -11
- package/dist/astro/routes/api/redirects/index.mjs.map +1 -1
- package/dist/astro/routes/api/revisions/_revisionId_/index.mjs +4 -4
- package/dist/astro/routes/api/revisions/_revisionId_/restore.mjs +4 -4
- package/dist/astro/routes/api/schema/collections/_slug_/fields/_fieldSlug_.mjs +39 -36
- 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 +39 -36
- 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 +39 -36
- package/dist/astro/routes/api/schema/collections/_slug_/fields/reorder.mjs.map +1 -1
- package/dist/astro/routes/api/schema/collections/_slug_/index.mjs +39 -36
- package/dist/astro/routes/api/schema/collections/_slug_/index.mjs.map +1 -1
- package/dist/astro/routes/api/schema/collections/index.mjs +39 -36
- package/dist/astro/routes/api/schema/collections/index.mjs.map +1 -1
- package/dist/astro/routes/api/schema/index.mjs +7 -7
- package/dist/astro/routes/api/schema/orphans/_slug_.mjs +39 -36
- package/dist/astro/routes/api/schema/orphans/_slug_.mjs.map +1 -1
- package/dist/astro/routes/api/schema/orphans/index.mjs +39 -36
- package/dist/astro/routes/api/schema/orphans/index.mjs.map +1 -1
- package/dist/astro/routes/api/search/enable.mjs +11 -10
- package/dist/astro/routes/api/search/enable.mjs.map +1 -1
- package/dist/astro/routes/api/search/index.mjs +10 -9
- package/dist/astro/routes/api/search/index.mjs.map +1 -1
- package/dist/astro/routes/api/search/rebuild.mjs +11 -10
- package/dist/astro/routes/api/search/rebuild.mjs.map +1 -1
- package/dist/astro/routes/api/search/stats.mjs +7 -7
- package/dist/astro/routes/api/search/suggest.mjs +10 -9
- package/dist/astro/routes/api/search/suggest.mjs.map +1 -1
- package/dist/astro/routes/api/sections/_slug_.mjs +10 -9
- package/dist/astro/routes/api/sections/_slug_.mjs.map +1 -1
- package/dist/astro/routes/api/sections/index.mjs +10 -9
- package/dist/astro/routes/api/sections/index.mjs.map +1 -1
- package/dist/astro/routes/api/settings/email.mjs +6 -6
- package/dist/astro/routes/api/settings.mjs +16 -13
- package/dist/astro/routes/api/settings.mjs.map +1 -1
- package/dist/astro/routes/api/setup/admin-verify.mjs +13 -12
- package/dist/astro/routes/api/setup/admin-verify.mjs.map +1 -1
- package/dist/astro/routes/api/setup/admin.mjs +12 -11
- package/dist/astro/routes/api/setup/admin.mjs.map +1 -1
- package/dist/astro/routes/api/setup/dev-bypass.d.mts.map +1 -1
- package/dist/astro/routes/api/setup/dev-bypass.mjs +29 -26
- package/dist/astro/routes/api/setup/dev-bypass.mjs.map +1 -1
- package/dist/astro/routes/api/setup/dev-reset.mjs +4 -4
- package/dist/astro/routes/api/setup/index.mjs +29 -26
- package/dist/astro/routes/api/setup/index.mjs.map +1 -1
- package/dist/astro/routes/api/setup/status.mjs +5 -5
- package/dist/astro/routes/api/snapshot.d.mts.map +1 -1
- package/dist/astro/routes/api/snapshot.mjs +10 -8
- package/dist/astro/routes/api/snapshot.mjs.map +1 -1
- package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_/translations.mjs +16 -13
- package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_/translations.mjs.map +1 -1
- package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_.mjs +16 -13
- package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_.mjs.map +1 -1
- package/dist/astro/routes/api/taxonomies/_name_/terms/index.mjs +16 -13
- package/dist/astro/routes/api/taxonomies/_name_/terms/index.mjs.map +1 -1
- package/dist/astro/routes/api/taxonomies/index.mjs +16 -13
- package/dist/astro/routes/api/taxonomies/index.mjs.map +1 -1
- package/dist/astro/routes/api/themes/preview.mjs +8 -7
- package/dist/astro/routes/api/themes/preview.mjs.map +1 -1
- package/dist/astro/routes/api/typegen.mjs +6 -6
- package/dist/astro/routes/api/well-known/auth.mjs +2 -2
- 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 +8 -7
- package/dist/astro/routes/api/widget-areas/_name_/reorder.mjs.map +1 -1
- package/dist/astro/routes/api/widget-areas/_name_/widgets/_id_.mjs +11 -10
- package/dist/astro/routes/api/widget-areas/_name_/widgets/_id_.mjs.map +1 -1
- package/dist/astro/routes/api/widget-areas/_name_/widgets.mjs +11 -10
- package/dist/astro/routes/api/widget-areas/_name_/widgets.mjs.map +1 -1
- package/dist/astro/routes/api/widget-areas/_name_.mjs +7 -7
- package/dist/astro/routes/api/widget-areas/index.mjs +11 -10
- package/dist/astro/routes/api/widget-areas/index.mjs.map +1 -1
- package/dist/astro/routes/api/widget-components.mjs +4 -4
- package/dist/astro/routes/robots.txt.mjs +10 -8
- package/dist/astro/routes/robots.txt.mjs.map +1 -1
- package/dist/astro/routes/sitemap-_collection_.xml.mjs +13 -11
- package/dist/astro/routes/sitemap-_collection_.xml.mjs.map +1 -1
- package/dist/astro/routes/sitemap.xml.mjs +11 -9
- package/dist/astro/routes/sitemap.xml.mjs.map +1 -1
- package/dist/astro/types.d.mts +16 -12
- package/dist/astro/types.d.mts.map +1 -1
- package/dist/auth/providers/github.d.mts +1 -1
- package/dist/auth/providers/google.d.mts +1 -1
- package/dist/{authorize-DsMSVSaY.mjs → authorize-C0EYoUeV.mjs} +2 -2
- package/dist/{authorize-DsMSVSaY.mjs.map → authorize-C0EYoUeV.mjs.map} +1 -1
- package/dist/{base64-CqR-7kqF.mjs → base64-CmWvODNW.mjs} +1 -1
- package/dist/{base64-CqR-7kqF.mjs.map → base64-CmWvODNW.mjs.map} +1 -1
- package/dist/{byline-DUx48sJp.mjs → byline-CC0WS4Gu.mjs} +40 -18
- package/dist/byline-CC0WS4Gu.mjs.map +1 -0
- package/dist/{byline-fields-8TMtkBnH.mjs → byline-fields-53i9Et0x.mjs} +3 -3
- package/dist/{byline-fields-8TMtkBnH.mjs.map → byline-fields-53i9Et0x.mjs.map} +1 -1
- package/dist/{byline-fields--WxSNS79.mjs → byline-fields-DNp0HNKc.mjs} +2 -2
- package/dist/{byline-fields--WxSNS79.mjs.map → byline-fields-DNp0HNKc.mjs.map} +1 -1
- package/dist/{byline-fields-DbibsvTl.d.mts → byline-fields-jy07PZJM.d.mts} +9 -4
- package/dist/byline-fields-jy07PZJM.d.mts.map +1 -0
- package/dist/{byline-registry-CWP7I71B.mjs → byline-registry-BOjqDOim.mjs} +3 -3
- package/dist/{byline-registry-CWP7I71B.mjs.map → byline-registry-BOjqDOim.mjs.map} +1 -1
- package/dist/{bylines-s8c2DXbH.mjs → bylines-CCO1CYnH.mjs} +8 -8
- package/dist/{bylines-s8c2DXbH.mjs.map → bylines-CCO1CYnH.mjs.map} +1 -1
- package/dist/{bylines-BdxWCnPL.mjs → bylines-DGekMGGm.mjs} +10 -4
- package/dist/{bylines-BdxWCnPL.mjs.map → bylines-DGekMGGm.mjs.map} +1 -1
- package/dist/{cache-B_HzASVT.mjs → cache-pXTpun6s.mjs} +3 -3
- package/dist/{cache-B_HzASVT.mjs.map → cache-pXTpun6s.mjs.map} +1 -1
- package/dist/{challenge-store-DXX3rfdI.mjs → challenge-store-C6E_kWTs.mjs} +1 -1
- package/dist/{challenge-store-DXX3rfdI.mjs.map → challenge-store-C6E_kWTs.mjs.map} +1 -1
- package/dist/{chunks-BerYVuve.mjs → chunks-SyjZaYwV.mjs} +2 -2
- package/dist/{chunks-BerYVuve.mjs.map → chunks-SyjZaYwV.mjs.map} +1 -1
- package/dist/cli/index.mjs +29 -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/client/index.mjs +2 -1
- package/dist/client/index.mjs.map +1 -1
- package/dist/{comment-sqQxNpN3.mjs → comment-80UyJJUR.mjs} +11 -3
- package/dist/comment-80UyJJUR.mjs.map +1 -0
- package/dist/comment-reaction-B6AdcpXw.mjs +85 -0
- package/dist/comment-reaction-B6AdcpXw.mjs.map +1 -0
- package/dist/{comments-Vkivawyl.mjs → comments-CtPkT2tp.mjs} +3 -3
- package/dist/{comments-Vkivawyl.mjs.map → comments-CtPkT2tp.mjs.map} +1 -1
- package/dist/{components-CK0cuUoH.mjs → components-D6ZnrzbB.mjs} +1 -1
- package/dist/{components-CK0cuUoH.mjs.map → components-D6ZnrzbB.mjs.map} +1 -1
- package/dist/{content-BIlVx-RX.mjs → content-2PTDNnoh.mjs} +22 -7
- package/dist/content-2PTDNnoh.mjs.map +1 -0
- package/dist/{context-Y7BRkWes.mjs → context-f1__jpzF.mjs} +11 -11
- package/dist/{context-Y7BRkWes.mjs.map → context-f1__jpzF.mjs.map} +1 -1
- package/dist/{cron-BJ2ClIlj.mjs → cron-CQPxBjYs.mjs} +1 -1
- package/dist/{cron-BJ2ClIlj.mjs.map → cron-CQPxBjYs.mjs.map} +1 -1
- package/dist/{dashboard-2JgAMWxK.mjs → dashboard-BOESNcwE.mjs} +4 -4
- package/dist/{dashboard-2JgAMWxK.mjs.map → dashboard-BOESNcwE.mjs.map} +1 -1
- package/dist/database/instrumentation.d.mts +19 -0
- package/dist/database/instrumentation.d.mts.map +1 -1
- package/dist/database/instrumentation.mjs +8 -1
- package/dist/database/instrumentation.mjs.map +1 -1
- package/dist/db/index.d.mts +3 -3
- package/dist/db/index.mjs +1 -1
- 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-CrC5w3Jz.mjs} +1 -1
- package/dist/{db-errors-CtzxKBxe.mjs.map → db-errors-CrC5w3Jz.mjs.map} +1 -1
- package/dist/{default-IlBaTFxM.mjs → default-CpBEPn6a.mjs} +1 -1
- package/dist/{default-IlBaTFxM.mjs.map → default-CpBEPn6a.mjs.map} +1 -1
- package/dist/{device-flow-R23SIbQ2.mjs → device-flow-Bn-qiDrw.mjs} +5 -5
- package/dist/{device-flow-R23SIbQ2.mjs.map → device-flow-Bn-qiDrw.mjs.map} +1 -1
- package/dist/{email-console-DHT2Fbpj.mjs → email-console-B9VS6eN4.mjs} +1 -1
- package/dist/{email-console-DHT2Fbpj.mjs.map → email-console-B9VS6eN4.mjs.map} +1 -1
- package/dist/{error-RwM4dD35.mjs → error-BQ1pxs0L.mjs} +2 -2
- package/dist/{error-RwM4dD35.mjs.map → error-BQ1pxs0L.mjs.map} +1 -1
- package/dist/{escape-Ds07EEyu.mjs → escape-BtbJWyaW.mjs} +1 -1
- package/dist/{escape-Ds07EEyu.mjs.map → escape-BtbJWyaW.mjs.map} +1 -1
- package/dist/{fts-manager-1RgHmopc.mjs → fts-manager-DtiWqwNJ.mjs} +2 -2
- package/dist/{fts-manager-1RgHmopc.mjs.map → fts-manager-DtiWqwNJ.mjs.map} +1 -1
- package/dist/{hash-9w3pd3-m.mjs → hash-BowcuPwv.mjs} +1 -1
- package/dist/{hash-9w3pd3-m.mjs.map → hash-BowcuPwv.mjs.map} +1 -1
- package/dist/{import-Dh8bWmyq.mjs → import-DqSGOlmR.mjs} +4 -4
- package/dist/{import-Dh8bWmyq.mjs.map → import-DqSGOlmR.mjs.map} +1 -1
- package/dist/{index-B1keaX5Y.d.mts → index-C2dLNT6S.d.mts} +169 -14
- package/dist/index-C2dLNT6S.d.mts.map +1 -0
- package/dist/{index-DR56od45.d.mts → index-ZDEwR7qW.d.mts} +3 -3
- package/dist/{index-DR56od45.d.mts.map → index-ZDEwR7qW.d.mts.map} +1 -1
- package/dist/index.d.mts +18 -17
- package/dist/index.mjs +63 -59
- package/dist/init-lock-6b309ZrF.mjs +56 -0
- package/dist/init-lock-6b309ZrF.mjs.map +1 -0
- package/dist/{load-BBetCvLC.mjs → load-Dtoo7KcJ.mjs} +2 -2
- package/dist/{load-BBetCvLC.mjs.map → load-Dtoo7KcJ.mjs.map} +1 -1
- package/dist/{loader-ZN1ll-d-.mjs → loader-C8Z48Uof.mjs} +4 -4
- package/dist/{loader-ZN1ll-d-.mjs.map → loader-C8Z48Uof.mjs.map} +1 -1
- package/dist/{manifest-schema-BtwbL_vj.mjs → manifest-schema-DDSbwkAL.mjs} +1 -1
- package/dist/{manifest-schema-BtwbL_vj.mjs.map → manifest-schema-DDSbwkAL.mjs.map} +1 -1
- package/dist/media/image-endpoint.d.mts +74 -0
- package/dist/media/image-endpoint.d.mts.map +1 -0
- package/dist/media/image-endpoint.mjs +162 -0
- package/dist/media/image-endpoint.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 +9 -7
- package/dist/media/local-runtime.mjs.map +1 -1
- package/dist/{media-JOf3pNkw.mjs → media-Bw0sA6rb.mjs} +2 -2
- package/dist/{media-JOf3pNkw.mjs.map → media-Bw0sA6rb.mjs.map} +1 -1
- package/dist/{media-allowlist-Dknq-OFY.mjs → media-allowlist-DunzrKFM.mjs} +2 -2
- package/dist/{media-allowlist-Dknq-OFY.mjs.map → media-allowlist-DunzrKFM.mjs.map} +1 -1
- package/dist/{media-url-VClf8glU.mjs → media-url-S22B6aPr.mjs} +1 -1
- package/dist/{media-url-VClf8glU.mjs.map → media-url-S22B6aPr.mjs.map} +1 -1
- package/dist/{menus-DX4_E01q.mjs → menus-CYs0WZoL.mjs} +20 -6
- package/dist/menus-CYs0WZoL.mjs.map +1 -0
- package/dist/{menus-DrQLusqj.mjs → menus-DOs1MQJg.mjs} +120 -20
- package/dist/menus-DOs1MQJg.mjs.map +1 -0
- package/dist/{mime-CCEzze7W.mjs → mime-DYpsOAny.mjs} +1 -1
- package/dist/{mime-CCEzze7W.mjs.map → mime-DYpsOAny.mjs.map} +1 -1
- package/dist/{mode-CO2vQHfq.mjs → mode-CFh8Dw8G.mjs} +1 -1
- package/dist/{mode-CO2vQHfq.mjs.map → mode-CFh8Dw8G.mjs.map} +1 -1
- package/dist/{normalize-CK5o04zr.mjs → normalize-Uam4_Vkr.mjs} +1 -1
- package/dist/{normalize-CK5o04zr.mjs.map → normalize-Uam4_Vkr.mjs.map} +1 -1
- package/dist/{oauth-authorization-Bw4NdF_S.mjs → oauth-authorization-BN-t83Uy.mjs} +5 -5
- package/dist/{oauth-authorization-Bw4NdF_S.mjs.map → oauth-authorization-BN-t83Uy.mjs.map} +1 -1
- package/dist/{oauth-clients-BGGFp57s.mjs → oauth-clients-R6I_V0qz.mjs} +1 -1
- package/dist/{oauth-clients-BGGFp57s.mjs.map → oauth-clients-R6I_V0qz.mjs.map} +1 -1
- package/dist/{oauth-state-store-97x0xtN2.mjs → oauth-state-store-Csoc6kkR.mjs} +1 -1
- package/dist/{oauth-state-store-97x0xtN2.mjs.map → oauth-state-store-Csoc6kkR.mjs.map} +1 -1
- package/dist/{oauth-user-lookup-B_vnZHKO.mjs → oauth-user-lookup-d7VYjTpx.mjs} +1 -1
- package/dist/{oauth-user-lookup-B_vnZHKO.mjs.map → oauth-user-lookup-d7VYjTpx.mjs.map} +1 -1
- package/dist/object-cache/memory.d.mts +15 -0
- package/dist/object-cache/memory.d.mts.map +1 -0
- package/dist/object-cache/memory.mjs +56 -0
- package/dist/object-cache/memory.mjs.map +1 -0
- package/dist/object-cache-SEb2IM4Z.mjs +373 -0
- package/dist/object-cache-SEb2IM4Z.mjs.map +1 -0
- package/dist/{options-DyYIYpPd.d.mts → options-DFFpvNJU.d.mts} +3 -3
- package/dist/{options-DyYIYpPd.d.mts.map → options-DFFpvNJU.d.mts.map} +1 -1
- package/dist/{options-BPCVnesz.mjs → options-DTTML-Tx.mjs} +1 -1
- package/dist/{options-BPCVnesz.mjs.map → options-DTTML-Tx.mjs.map} +1 -1
- package/dist/page/index.d.mts +2 -2
- package/dist/{parse-CrGndy1A.mjs → parse-qrHlnzTy.mjs} +2 -2
- package/dist/{parse-CrGndy1A.mjs.map → parse-qrHlnzTy.mjs.map} +1 -1
- package/dist/{passkey-config-C3QgnQnU.mjs → passkey-config-BJTbcnI5.mjs} +1 -1
- package/dist/{passkey-config-C3QgnQnU.mjs.map → passkey-config-BJTbcnI5.mjs.map} +1 -1
- package/dist/{patterns-p-RBdTbM.mjs → patterns-BKmjvM7K.mjs} +1 -1
- package/dist/{patterns-p-RBdTbM.mjs.map → patterns-BKmjvM7K.mjs.map} +1 -1
- package/dist/{placeholder-BZxr8W1j.mjs → placeholder-CIDCpyEY.mjs} +1 -1
- package/dist/{placeholder-BZxr8W1j.mjs.map → placeholder-CIDCpyEY.mjs.map} +1 -1
- package/dist/{placeholder-CVBv5z8k.d.mts → placeholder-CirPauNG.d.mts} +1 -1
- package/dist/{placeholder-CVBv5z8k.d.mts.map → placeholder-CirPauNG.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 +4 -2
- package/dist/plugins/adapt-sandbox-entry.mjs.map +1 -1
- package/dist/{transport-CmpLD7W3.mjs → portable-text-BIFhrU6T.mjs} +2 -135
- package/dist/portable-text-BIFhrU6T.mjs.map +1 -0
- package/dist/{preview-BfuRkVKW.mjs → preview-IDye9SPQ.mjs} +2 -2
- package/dist/{preview-BfuRkVKW.mjs.map → preview-IDye9SPQ.mjs.map} +1 -1
- package/dist/{public-url-BFVC2OTJ.mjs → public-url-8lFyQ8ZF.mjs} +1 -1
- package/dist/{public-url-BFVC2OTJ.mjs.map → public-url-8lFyQ8ZF.mjs.map} +1 -1
- package/dist/{query-CbUcI4Xk.mjs → query-B1RVFUNM.mjs} +159 -31
- package/dist/query-B1RVFUNM.mjs.map +1 -0
- package/dist/{rate-limit-C7hjdkS5.mjs → rate-limit-DfNAqIWW.mjs} +2 -2
- package/dist/{rate-limit-C7hjdkS5.mjs.map → rate-limit-DfNAqIWW.mjs.map} +1 -1
- package/dist/{redirect-B_q19j4v.mjs → redirect-B4wuX2A5.mjs} +1 -1
- package/dist/{redirect-B_q19j4v.mjs.map → redirect-B4wuX2A5.mjs.map} +1 -1
- package/dist/{redirect-CRWIt8Zj.mjs → redirect-Bifv_yHv.mjs} +3 -3
- package/dist/{redirect-CRWIt8Zj.mjs.map → redirect-Bifv_yHv.mjs.map} +1 -1
- package/dist/{redirects-DxVoR7PI.mjs → redirects-CT_vb3NV.mjs} +24 -18
- package/dist/redirects-CT_vb3NV.mjs.map +1 -0
- package/dist/{redirects-CCbCqCCd.mjs → redirects-DUvXgzCX.mjs} +14 -10
- package/dist/redirects-DUvXgzCX.mjs.map +1 -0
- package/dist/{registry-brYh-rAT.mjs → registry-CjK96fHD.mjs} +6 -6
- package/dist/{registry-brYh-rAT.mjs.map → registry-CjK96fHD.mjs.map} +1 -1
- package/dist/{request-cache-D32LpnmI.mjs → request-cache-KCNHp_RJ.mjs} +1 -1
- package/dist/{request-cache-D32LpnmI.mjs.map → request-cache-KCNHp_RJ.mjs.map} +1 -1
- package/dist/{request-meta-7ByVLxB-.mjs → request-meta-ei3ATilC.mjs} +2 -2
- package/dist/{request-meta-7ByVLxB-.mjs.map → request-meta-ei3ATilC.mjs.map} +1 -1
- package/dist/{resolve-BqYMVG0D.mjs → resolve-CpbBglV0.mjs} +1 -1
- package/dist/{resolve-BqYMVG0D.mjs.map → resolve-CpbBglV0.mjs.map} +1 -1
- package/dist/{runner--4wMWwKM.mjs → runner-DYYnW530.mjs} +201 -170
- package/dist/runner-DYYnW530.mjs.map +1 -0
- package/dist/{runner-DTdhuI9i.d.mts → runner-jdXtFEd3.d.mts} +2 -2
- package/dist/{runner-DTdhuI9i.d.mts.map → runner-jdXtFEd3.d.mts.map} +1 -1
- package/dist/runtime.d.mts +10 -10
- package/dist/runtime.mjs +3 -3
- package/dist/{schema-C1E70ug_.mjs → schema-5z2Jfnbm.mjs} +13 -8
- package/dist/schema-5z2Jfnbm.mjs.map +1 -0
- package/dist/{search-B3SGZw91.mjs → search-D9FkoM-k.mjs} +4 -4
- package/dist/{search-B3SGZw91.mjs.map → search-D9FkoM-k.mjs.map} +1 -1
- package/dist/{secrets-ChPTmy9x.mjs → secrets-BUE5UQys.mjs} +23 -13
- package/dist/secrets-BUE5UQys.mjs.map +1 -0
- package/dist/{sections-D_lVzwRZ.mjs → sections-DWYZo6HK.mjs} +3 -3
- package/dist/{sections-D_lVzwRZ.mjs.map → sections-DWYZo6HK.mjs.map} +1 -1
- package/dist/seed/index.d.mts +2 -2
- package/dist/seed/index.mjs +22 -20
- package/dist/seo/index.d.mts +1 -1
- package/dist/seo/index.mjs +1 -1
- package/dist/{seo-B5e6y9Wk.mjs → seo-Cu47j3mJ.mjs} +5 -2
- package/dist/seo-Cu47j3mJ.mjs.map +1 -0
- package/dist/{seo-D_LPkOtu.mjs → seo-DRnqnstF.mjs} +1 -1
- package/dist/{seo-D_LPkOtu.mjs.map → seo-DRnqnstF.mjs.map} +1 -1
- package/dist/{service-ChDcsTBs.mjs → service-DTmtqCnw.mjs} +3 -3
- package/dist/{service-ChDcsTBs.mjs.map → service-DTmtqCnw.mjs.map} +1 -1
- package/dist/session-user-DmtPMNa1.mjs +51 -0
- package/dist/session-user-DmtPMNa1.mjs.map +1 -0
- package/dist/{settings-Cv47v9u8.mjs → settings-DUrVDN0c.mjs} +3 -3
- package/dist/{settings-Cv47v9u8.mjs.map → settings-DUrVDN0c.mjs.map} +1 -1
- package/dist/settings-yaxu9mU-.mjs +245 -0
- package/dist/settings-yaxu9mU-.mjs.map +1 -0
- package/dist/{setup-complete-yvPE4OsP.mjs → setup-complete-BWFHzgvZ.mjs} +2 -2
- package/dist/{setup-complete-yvPE4OsP.mjs.map → setup-complete-BWFHzgvZ.mjs.map} +1 -1
- package/dist/{setup-nonce-C9aFzb94.mjs → setup-nonce-DFWG-J5c.mjs} +1 -1
- package/dist/{setup-nonce-C9aFzb94.mjs.map → setup-nonce-DFWG-J5c.mjs.map} +1 -1
- package/dist/single-flight-cache-B5p5cNOL.mjs +104 -0
- package/dist/single-flight-cache-B5p5cNOL.mjs.map +1 -0
- package/dist/{site-url-CnHlmAs9.mjs → site-url-BOTPgmeM.mjs} +2 -2
- package/dist/{site-url-CnHlmAs9.mjs.map → site-url-BOTPgmeM.mjs.map} +1 -1
- package/dist/{slugify-Cjh1ssOZ.mjs → slugify-Cce3dTdg.mjs} +1 -1
- package/dist/{slugify-Cjh1ssOZ.mjs.map → slugify-Cce3dTdg.mjs.map} +1 -1
- package/dist/{ssrf-BsVGIE0Z.mjs → ssrf-B0VeRLrp.mjs} +1 -1
- package/dist/{ssrf-BsVGIE0Z.mjs.map → ssrf-B0VeRLrp.mjs.map} +1 -1
- package/dist/status-CB2basWJ.mjs +30 -0
- package/dist/status-CB2basWJ.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-BdAmbOwx.mjs → taxonomies-Be9B1jEj.mjs} +156 -122
- package/dist/taxonomies-Be9B1jEj.mjs.map +1 -0
- package/dist/{taxonomies-BILwiyGk.mjs → taxonomies-CJmkEpdS.mjs} +7 -7
- package/dist/{taxonomies-BILwiyGk.mjs.map → taxonomies-CJmkEpdS.mjs.map} +1 -1
- package/dist/{taxonomy-CdllE4oq.mjs → taxonomy-B2HQuVf5.mjs} +19 -6
- package/dist/taxonomy-B2HQuVf5.mjs.map +1 -0
- package/dist/{tokens-Bx2afeT-.mjs → tokens-BvrJvIB6.mjs} +2 -2
- package/dist/{tokens-Bx2afeT-.mjs.map → tokens-BvrJvIB6.mjs.map} +1 -1
- package/dist/{transaction-x2tJQ-A1.mjs → transaction-qfqpPVpu.mjs} +1 -1
- package/dist/{transaction-x2tJQ-A1.mjs.map → transaction-qfqpPVpu.mjs.map} +1 -1
- package/dist/transport-B4rXnSTf.mjs +135 -0
- package/dist/transport-B4rXnSTf.mjs.map +1 -0
- package/dist/{transport-B7PPP2CC.d.mts → transport-k7YjfmEn.d.mts} +1 -1
- package/dist/{transport-B7PPP2CC.d.mts.map → transport-k7YjfmEn.d.mts.map} +1 -1
- package/dist/{trusted-proxy-B4AfnoAp.mjs → trusted-proxy-DY1_UqHr.mjs} +1 -1
- package/dist/{trusted-proxy-B4AfnoAp.mjs.map → trusted-proxy-DY1_UqHr.mjs.map} +1 -1
- package/dist/{types-CPAPl93j.d.mts → types-CIKX2HO5.d.mts} +2 -2
- package/dist/{types-CPAPl93j.d.mts.map → types-CIKX2HO5.d.mts.map} +1 -1
- package/dist/{types-D4kUqbHh.d.mts → types-CKNXt63n.d.mts} +1 -1
- package/dist/{types-D4kUqbHh.d.mts.map → types-CKNXt63n.d.mts.map} +1 -1
- package/dist/{types-DTniiNto.d.mts → types-CWGYDYqF.d.mts} +2 -2
- package/dist/{types-DTniiNto.d.mts.map → types-CWGYDYqF.d.mts.map} +1 -1
- package/dist/{types-BH8-30hc.d.mts → types-CgvhU-hF.d.mts} +1 -1
- package/dist/{types-BH8-30hc.d.mts.map → types-CgvhU-hF.d.mts.map} +1 -1
- package/dist/{types-BFgrqwSk.d.mts → types-CmivgZbp.d.mts} +1 -1
- package/dist/{types-BFgrqwSk.d.mts.map → types-CmivgZbp.d.mts.map} +1 -1
- package/dist/{types-BPzXTV9x.d.mts → types-Czg1S3gB.d.mts} +9 -1
- package/dist/{types-BPzXTV9x.d.mts.map → types-Czg1S3gB.d.mts.map} +1 -1
- package/dist/types-DCNNfeCv.d.mts +124 -0
- package/dist/types-DCNNfeCv.d.mts.map +1 -0
- package/dist/{types-BUUVn1zr.d.mts → types-DPCpkzvS.d.mts} +1 -1
- package/dist/{types-BUUVn1zr.d.mts.map → types-DPCpkzvS.d.mts.map} +1 -1
- package/dist/{types-S15DXXNi.d.mts → types-DXLVzV2w.d.mts} +1 -1
- package/dist/{types-S15DXXNi.d.mts.map → types-DXLVzV2w.d.mts.map} +1 -1
- package/dist/{types-BXSUSAjt.mjs → types-DXOIbece.mjs} +3 -3
- package/dist/{types-BXSUSAjt.mjs.map → types-DXOIbece.mjs.map} +1 -1
- package/dist/{types-DpFmlNyB.mjs → types-DYF2_Vf4.mjs} +1 -1
- package/dist/{types-DpFmlNyB.mjs.map → types-DYF2_Vf4.mjs.map} +1 -1
- package/dist/{types-DZk_y-MU.mjs → types-tM44hEcf.mjs} +1 -1
- package/dist/{types-DZk_y-MU.mjs.map → types-tM44hEcf.mjs.map} +1 -1
- package/dist/{user-C0um7wrg.mjs → user-Db-Rti_z.mjs} +3 -3
- package/dist/{user-C0um7wrg.mjs.map → user-Db-Rti_z.mjs.map} +1 -1
- package/dist/{utils-C4Ih4DML.mjs → utils-LbHcSRTj.mjs} +2 -2
- package/dist/{utils-C4Ih4DML.mjs.map → utils-LbHcSRTj.mjs.map} +1 -1
- package/dist/{validate-Bz4vqcX1.mjs → validate-Bwl64sxv.mjs} +3 -3
- package/dist/{validate-Bz4vqcX1.mjs.map → validate-Bwl64sxv.mjs.map} +1 -1
- package/dist/{validate-CNwkPWzz.d.mts → validate-CE2M0nvx.d.mts} +5 -5
- package/dist/{validate-CNwkPWzz.d.mts.map → validate-CE2M0nvx.d.mts.map} +1 -1
- package/dist/{validation-DgGTJm3u.mjs → validation-C_yOvFaO.mjs} +6 -6
- package/dist/{validation-DgGTJm3u.mjs.map → validation-C_yOvFaO.mjs.map} +1 -1
- package/dist/version-RnYXYjzD.mjs +7 -0
- package/dist/{version-D-5txk2m.mjs.map → version-RnYXYjzD.mjs.map} +1 -1
- package/dist/{widgets-DZfmAbE4.mjs → widgets-8GONuRHo.mjs} +4 -4
- package/dist/{widgets-DZfmAbE4.mjs.map → widgets-8GONuRHo.mjs.map} +1 -1
- package/dist/{zod-generator-Djo_VHCt.mjs → zod-generator-D481JjzD.mjs} +3 -3
- package/dist/{zod-generator-Djo_VHCt.mjs.map → zod-generator-D481JjzD.mjs.map} +1 -1
- package/package.json +18 -6
- package/src/api/handlers/api-tokens.ts +19 -0
- package/src/api/handlers/comment-reactions.ts +165 -0
- package/src/api/handlers/redirects.ts +24 -13
- package/src/api/handlers/schema.ts +8 -0
- package/src/api/schemas/comments.ts +10 -0
- package/src/api/schemas/redirects.ts +11 -4
- package/src/astro/image-endpoint.ts +84 -0
- package/src/astro/index.ts +6 -0
- package/src/astro/integration/index.ts +127 -30
- package/src/astro/integration/routes.ts +51 -9
- package/src/astro/integration/runtime.ts +65 -1
- package/src/astro/integration/virtual-modules.ts +32 -0
- package/src/astro/integration/vite-config.ts +16 -0
- package/src/astro/middleware/auth.ts +4 -3
- package/src/astro/middleware/redirect.ts +12 -0
- package/src/astro/middleware/stream-end-metrics.ts +11 -1
- package/src/astro/middleware.ts +41 -3
- package/src/astro/object-cache/adapters.ts +50 -0
- package/src/astro/prefetch.ts +77 -0
- package/src/astro/routes/api/comments/[collection]/[contentId]/reactions.ts +97 -0
- package/src/astro/routes/api/setup/dev-bypass.ts +5 -1
- package/src/astro/routes/api/snapshot.ts +3 -1
- package/src/astro/session-user.ts +57 -0
- package/src/astro/types.ts +1 -0
- package/src/bylines/field-defs-cache.ts +70 -20
- package/src/cli/commands/doctor.ts +1 -1
- package/src/comments/query.ts +78 -7
- package/src/comments/ranking.ts +58 -0
- package/src/components/Comments.astro +136 -1
- package/src/config/secrets.ts +28 -14
- package/src/database/instrumentation.ts +21 -1
- package/src/database/migrations/044_comment_reactions.ts +56 -0
- package/src/database/migrations/runner.ts +2 -0
- package/src/database/repositories/byline.ts +13 -0
- package/src/database/repositories/comment-reaction.ts +132 -0
- package/src/database/repositories/comment.ts +10 -0
- package/src/database/repositories/content.ts +25 -3
- package/src/database/repositories/menu.ts +13 -1
- package/src/database/repositories/seo.ts +3 -0
- package/src/database/repositories/taxonomy.ts +13 -1
- package/src/database/types.ts +9 -0
- package/src/emdash-runtime.ts +23 -9
- package/src/index.ts +22 -0
- package/src/mcp/server.ts +307 -20
- package/src/media/image-endpoint.ts +167 -0
- package/src/menus/index.ts +11 -4
- package/src/object-cache/codec.ts +73 -0
- package/src/object-cache/index.ts +495 -0
- package/src/object-cache/memory.ts +91 -0
- package/src/object-cache/types.ts +124 -0
- package/src/plugins/adapt-sandbox-entry.ts +11 -1
- package/src/query.ts +196 -17
- package/src/redirects/status.ts +27 -0
- package/src/schema/query.ts +11 -4
- package/src/settings/index.ts +30 -17
- package/src/taxonomies/index.ts +237 -165
- package/src/utils/{isolate-cache.ts → single-flight-cache.ts} +26 -21
- package/src/virtual-modules.d.ts +11 -0
- package/dist/api-DStv36ik.mjs.map +0 -1
- package/dist/api-tokens-DPfhPu5V.mjs.map +0 -1
- package/dist/byline-DUx48sJp.mjs.map +0 -1
- package/dist/byline-fields-DbibsvTl.d.mts.map +0 -1
- package/dist/comment-sqQxNpN3.mjs.map +0 -1
- package/dist/content-BIlVx-RX.mjs.map +0 -1
- package/dist/index-B1keaX5Y.d.mts.map +0 -1
- package/dist/menus-DX4_E01q.mjs.map +0 -1
- package/dist/menus-DrQLusqj.mjs.map +0 -1
- package/dist/query-CbUcI4Xk.mjs.map +0 -1
- package/dist/redirects-CCbCqCCd.mjs.map +0 -1
- package/dist/redirects-DxVoR7PI.mjs.map +0 -1
- package/dist/runner--4wMWwKM.mjs.map +0 -1
- package/dist/schema-C1E70ug_.mjs.map +0 -1
- package/dist/secrets-ChPTmy9x.mjs.map +0 -1
- package/dist/seo-B5e6y9Wk.mjs.map +0 -1
- package/dist/settings-DfxiWY_s.mjs +0 -411
- package/dist/settings-DfxiWY_s.mjs.map +0 -1
- package/dist/taxonomies-BdAmbOwx.mjs.map +0 -1
- package/dist/taxonomy-CdllE4oq.mjs.map +0 -1
- package/dist/transport-CmpLD7W3.mjs.map +0 -1
- package/dist/version-D-5txk2m.mjs +0 -7
- /package/dist/{api-tokens-Oq39ba-Z.mjs → api-tokens-BVH-H8Z9.mjs} +0 -0
- /package/dist/{ssrf-BvgVcfNQ.mjs → ssrf-Cz1e2QPn.mjs} +0 -0
- /package/dist/{types-CZI4E3qG.mjs → types-Bfr2Pj6z.mjs} +0 -0
package/src/comments/query.ts
CHANGED
|
@@ -7,15 +7,26 @@
|
|
|
7
7
|
|
|
8
8
|
import type { Kysely } from "kysely";
|
|
9
9
|
|
|
10
|
+
import { CommentReactionRepository } from "../database/repositories/comment-reaction.js";
|
|
10
11
|
import { CommentRepository } from "../database/repositories/comment.js";
|
|
11
12
|
import type { PublicComment } from "../database/repositories/comment.js";
|
|
12
13
|
import type { Database } from "../database/types.js";
|
|
13
14
|
import { getDb } from "../loader.js";
|
|
15
|
+
import { cachedQuery, CacheNamespace } from "../object-cache/index.js";
|
|
16
|
+
import { reactionScore } from "./ranking.js";
|
|
14
17
|
|
|
15
18
|
export interface GetCommentsOptions {
|
|
16
19
|
collection: string;
|
|
17
20
|
contentId: string;
|
|
18
21
|
threaded?: boolean;
|
|
22
|
+
/** Attach aggregate reaction counts to each comment. */
|
|
23
|
+
reactions?: boolean;
|
|
24
|
+
/**
|
|
25
|
+
* Order of top-level comments. `oldest` (default) preserves the existing
|
|
26
|
+
* chronological display; `best` ranks by Wilson-scored reactions (implies
|
|
27
|
+
* `reactions`). Replies always stay chronological.
|
|
28
|
+
*/
|
|
29
|
+
sort?: "oldest" | "best";
|
|
19
30
|
}
|
|
20
31
|
|
|
21
32
|
export interface GetCommentsResult {
|
|
@@ -38,8 +49,21 @@ export interface GetCommentsResult {
|
|
|
38
49
|
* ```
|
|
39
50
|
*/
|
|
40
51
|
export async function getComments(options: GetCommentsOptions): Promise<GetCommentsResult> {
|
|
41
|
-
|
|
42
|
-
|
|
52
|
+
// The result varies by every option getCommentsWithDb branches on, so all of
|
|
53
|
+
// them belong in the key. `best` implies reactions, so normalize the reaction
|
|
54
|
+
// flag — `{ sort: "best" }` and `{ sort: "best", reactions: true }` produce
|
|
55
|
+
// identical output and should share one entry.
|
|
56
|
+
const sort = options.sort ?? "oldest";
|
|
57
|
+
const withReactions = options.reactions || sort === "best";
|
|
58
|
+
const threaded = options.threaded ? "t" : "f";
|
|
59
|
+
return cachedQuery({
|
|
60
|
+
namespace: CacheNamespace.COMMENTS,
|
|
61
|
+
key: `comments:${options.collection}:${options.contentId}:${threaded}:${withReactions ? "r" : "n"}:${sort}`,
|
|
62
|
+
load: async () => {
|
|
63
|
+
const db = await getDb();
|
|
64
|
+
return getCommentsWithDb(db, options);
|
|
65
|
+
},
|
|
66
|
+
});
|
|
43
67
|
}
|
|
44
68
|
|
|
45
69
|
/**
|
|
@@ -65,16 +89,63 @@ export async function getCommentsWithDb(
|
|
|
65
89
|
limit: MAX_COMMENTS,
|
|
66
90
|
});
|
|
67
91
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
92
|
+
const items: PublicComment[] = options.threaded
|
|
93
|
+
? CommentRepository.assembleThreads(result.items).map((c) =>
|
|
94
|
+
CommentRepository.toPublicComment(c),
|
|
95
|
+
)
|
|
96
|
+
: result.items.map((c) => CommentRepository.toPublicComment(c));
|
|
97
|
+
|
|
98
|
+
// `best` sort needs reaction data, so it implies reactions.
|
|
99
|
+
if (options.reactions || options.sort === "best") {
|
|
100
|
+
await attachReactions(db, items);
|
|
101
|
+
if (options.sort === "best") {
|
|
102
|
+
sortByBest(items);
|
|
103
|
+
}
|
|
72
104
|
}
|
|
73
105
|
|
|
74
|
-
const items = result.items.map((c) => CommentRepository.toPublicComment(c));
|
|
75
106
|
return { items, total };
|
|
76
107
|
}
|
|
77
108
|
|
|
109
|
+
/**
|
|
110
|
+
* Attach aggregate reaction counts to a list of public comments (and their
|
|
111
|
+
* replies), in a single batched query.
|
|
112
|
+
*/
|
|
113
|
+
async function attachReactions(db: Kysely<Database>, items: PublicComment[]): Promise<void> {
|
|
114
|
+
const ids: string[] = [];
|
|
115
|
+
for (const comment of items) {
|
|
116
|
+
ids.push(comment.id);
|
|
117
|
+
if (comment.replies) {
|
|
118
|
+
for (const reply of comment.replies) ids.push(reply.id);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
if (ids.length === 0) return;
|
|
122
|
+
|
|
123
|
+
const counts = await new CommentReactionRepository(db).countsForComments(ids);
|
|
124
|
+
|
|
125
|
+
const assign = (comment: PublicComment) => {
|
|
126
|
+
const reactions = counts.get(comment.id);
|
|
127
|
+
if (reactions) comment.reactions = reactions;
|
|
128
|
+
};
|
|
129
|
+
for (const comment of items) {
|
|
130
|
+
assign(comment);
|
|
131
|
+
comment.replies?.forEach(assign);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Sort top-level comments by Wilson-scored reactions (descending), tie-broken
|
|
137
|
+
* by oldest-first to keep ordering stable.
|
|
138
|
+
*/
|
|
139
|
+
function sortByBest(items: PublicComment[]): void {
|
|
140
|
+
items.sort((a, b) => {
|
|
141
|
+
const scoreDelta = reactionScore(b.reactions ?? {}) - reactionScore(a.reactions ?? {});
|
|
142
|
+
if (scoreDelta !== 0) return scoreDelta;
|
|
143
|
+
if (a.createdAt < b.createdAt) return -1;
|
|
144
|
+
if (a.createdAt > b.createdAt) return 1;
|
|
145
|
+
return 0;
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
|
|
78
149
|
/**
|
|
79
150
|
* Get the count of approved comments for a content item.
|
|
80
151
|
*
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Comment ranking utilities (Tier 1 of the best-in-class comments RFC).
|
|
3
|
+
*
|
|
4
|
+
* Wilson score lower-bound (95% confidence) — the same primitive Reddit uses
|
|
5
|
+
* for its "Best" comment sort. Ranks by the statistical lower bound of the
|
|
6
|
+
* positive-reaction proportion rather than the raw count, so a comment with a
|
|
7
|
+
* couple of reactions can't outrank a heavily-reacted one until it earns
|
|
8
|
+
* confidence, and a late-but-popular comment still rises (submission time is
|
|
9
|
+
* irrelevant).
|
|
10
|
+
*
|
|
11
|
+
* Positive-only reactions (the recommended default) degrade gracefully: with
|
|
12
|
+
* `down = 0` the score still increases monotonically with `up` while penalising
|
|
13
|
+
* low-sample comments — wilson(1,0) ≈ 0.21, wilson(10,0) ≈ 0.73,
|
|
14
|
+
* wilson(200,0) ≈ 0.98.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
/** z for a 95% two-sided confidence interval. */
|
|
18
|
+
const DEFAULT_Z = 1.96;
|
|
19
|
+
|
|
20
|
+
/** Reactions that count against a comment when both signals are in use. */
|
|
21
|
+
const NEGATIVE_REACTIONS: ReadonlySet<string> = new Set(["dislike", "down"]);
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Wilson score lower bound of the positive proportion.
|
|
25
|
+
*
|
|
26
|
+
* @param up count of positive reactions
|
|
27
|
+
* @param down count of negative reactions
|
|
28
|
+
* @returns a score in [0, 1]; 0 when there are no reactions
|
|
29
|
+
*/
|
|
30
|
+
export function wilsonLowerBound(up: number, down: number, z: number = DEFAULT_Z): number {
|
|
31
|
+
const n = up + down;
|
|
32
|
+
if (n <= 0) return 0;
|
|
33
|
+
const phat = up / n;
|
|
34
|
+
const z2 = z * z;
|
|
35
|
+
const denom = 1 + z2 / n;
|
|
36
|
+
const centre = phat + z2 / (2 * n);
|
|
37
|
+
const margin = z * Math.sqrt((phat * (1 - phat) + z2 / (4 * n)) / n);
|
|
38
|
+
return (centre - margin) / denom;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Reduce a per-reaction count map to a single rank score via the Wilson
|
|
43
|
+
* lower bound. Any reaction not in {@link NEGATIVE_REACTIONS} is treated as
|
|
44
|
+
* positive, so the positive-only default (just `like`) works without special
|
|
45
|
+
* casing.
|
|
46
|
+
*/
|
|
47
|
+
export function reactionScore(counts: Record<string, number>): number {
|
|
48
|
+
let up = 0;
|
|
49
|
+
let down = 0;
|
|
50
|
+
for (const [reaction, count] of Object.entries(counts)) {
|
|
51
|
+
if (NEGATIVE_REACTIONS.has(reaction)) {
|
|
52
|
+
down += count;
|
|
53
|
+
} else {
|
|
54
|
+
up += count;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return wilsonLowerBound(up, down);
|
|
58
|
+
}
|
|
@@ -21,6 +21,10 @@ interface Props {
|
|
|
21
21
|
collection: string;
|
|
22
22
|
contentId: string;
|
|
23
23
|
threaded?: boolean;
|
|
24
|
+
/** Show a like/reaction button per comment (opt-in). */
|
|
25
|
+
reactions?: boolean;
|
|
26
|
+
/** Order of top-level comments: chronological (default) or Wilson-ranked. */
|
|
27
|
+
sort?: "oldest" | "best";
|
|
24
28
|
class?: string;
|
|
25
29
|
}
|
|
26
30
|
|
|
@@ -28,13 +32,15 @@ const {
|
|
|
28
32
|
collection,
|
|
29
33
|
contentId,
|
|
30
34
|
threaded = false,
|
|
35
|
+
reactions = false,
|
|
36
|
+
sort = "oldest",
|
|
31
37
|
class: className,
|
|
32
38
|
} = Astro.props;
|
|
33
39
|
|
|
34
40
|
const collectionInfo = await getCollectionInfo(collection);
|
|
35
41
|
const enabled = collectionInfo?.commentsEnabled ?? false;
|
|
36
42
|
const { items, total } = enabled
|
|
37
|
-
? await getComments({ collection, contentId, threaded })
|
|
43
|
+
? await getComments({ collection, contentId, threaded, reactions, sort })
|
|
38
44
|
: { items: [], total: 0 };
|
|
39
45
|
|
|
40
46
|
const URL_RE = /https?:\/\/[^\s<>"')\]]+/g;
|
|
@@ -62,15 +68,72 @@ function escapeHtml(text: string): string {
|
|
|
62
68
|
function formatBody(text: string): string {
|
|
63
69
|
return autoLinkUrls(escapeHtml(text));
|
|
64
70
|
}
|
|
71
|
+
|
|
72
|
+
// Progressive-enhancement script for reactions. Emitted verbatim (is:inline)
|
|
73
|
+
// only when `reactions` is enabled, so non-reaction pages ship zero extra JS.
|
|
74
|
+
// Avoids template literals internally so it survives the outer backticks.
|
|
75
|
+
const REACTION_SCRIPT = `
|
|
76
|
+
(() => {
|
|
77
|
+
const sections = document.querySelectorAll('[data-ec-comments][data-ec-reactions]');
|
|
78
|
+
sections.forEach((section) => {
|
|
79
|
+
const collection = section.getAttribute('data-collection');
|
|
80
|
+
const contentId = section.getAttribute('data-content-id');
|
|
81
|
+
if (!collection || !contentId) return;
|
|
82
|
+
const base = '/_emdash/api/comments/' + encodeURIComponent(collection) + '/' + encodeURIComponent(contentId) + '/reactions';
|
|
83
|
+
const headers = { 'X-EmDash-Request': '1' };
|
|
84
|
+
|
|
85
|
+
fetch(base, { headers: headers })
|
|
86
|
+
.then((r) => (r.ok ? r.json() : null))
|
|
87
|
+
.then((payload) => {
|
|
88
|
+
const viewer = payload && payload.data && payload.data.viewer;
|
|
89
|
+
if (!viewer) return;
|
|
90
|
+
Object.keys(viewer).forEach((commentId) => {
|
|
91
|
+
(viewer[commentId] || []).forEach((reaction) => {
|
|
92
|
+
const sel = '.ec-reaction[data-comment-id="' + commentId + '"][data-ec-reaction="' + reaction + '"]';
|
|
93
|
+
const btn = section.querySelector(sel);
|
|
94
|
+
if (btn) btn.setAttribute('aria-pressed', 'true');
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
})
|
|
98
|
+
.catch(() => {});
|
|
99
|
+
|
|
100
|
+
section.addEventListener('click', (event) => {
|
|
101
|
+
const btn = event.target.closest('.ec-reaction');
|
|
102
|
+
if (!btn || !section.contains(btn)) return;
|
|
103
|
+
const commentId = btn.getAttribute('data-comment-id');
|
|
104
|
+
const reaction = btn.getAttribute('data-ec-reaction');
|
|
105
|
+
if (!commentId || !reaction) return;
|
|
106
|
+
btn.disabled = true;
|
|
107
|
+
fetch(base, {
|
|
108
|
+
method: 'POST',
|
|
109
|
+
headers: Object.assign({ 'Content-Type': 'application/json' }, headers),
|
|
110
|
+
body: JSON.stringify({ commentId: commentId, reaction: reaction }),
|
|
111
|
+
})
|
|
112
|
+
.then((r) => (r.ok ? r.json() : null))
|
|
113
|
+
.then((payload) => {
|
|
114
|
+
const data = payload && payload.data;
|
|
115
|
+
if (!data) return;
|
|
116
|
+
btn.setAttribute('aria-pressed', data.reacted ? 'true' : 'false');
|
|
117
|
+
const countEl = btn.querySelector('[data-ec-reaction-count]');
|
|
118
|
+
if (countEl) countEl.textContent = String((data.counts && data.counts[reaction]) || 0);
|
|
119
|
+
})
|
|
120
|
+
.catch(() => {})
|
|
121
|
+
.finally(() => { btn.disabled = false; });
|
|
122
|
+
});
|
|
123
|
+
});
|
|
124
|
+
})();
|
|
125
|
+
`;
|
|
65
126
|
---
|
|
66
127
|
|
|
67
128
|
{
|
|
68
129
|
enabled && (
|
|
130
|
+
<Fragment>
|
|
69
131
|
<section
|
|
70
132
|
class:list={["ec-comments", className]}
|
|
71
133
|
data-ec-comments
|
|
72
134
|
data-collection={collection}
|
|
73
135
|
data-content-id={contentId}
|
|
136
|
+
{...(reactions ? { "data-ec-reactions": "" } : {})}
|
|
74
137
|
>
|
|
75
138
|
<h3 class="ec-comments-heading">
|
|
76
139
|
{total === 0
|
|
@@ -112,6 +175,25 @@ function formatBody(text: string): string {
|
|
|
112
175
|
class="ec-comment-body"
|
|
113
176
|
set:html={formatBody(comment.body)}
|
|
114
177
|
/>
|
|
178
|
+
{reactions && (
|
|
179
|
+
<div class="ec-comment-actions">
|
|
180
|
+
<button
|
|
181
|
+
type="button"
|
|
182
|
+
class="ec-reaction"
|
|
183
|
+
data-ec-reaction="like"
|
|
184
|
+
data-comment-id={comment.id}
|
|
185
|
+
aria-pressed="false"
|
|
186
|
+
>
|
|
187
|
+
<span class="ec-reaction-icon" aria-hidden="true">
|
|
188
|
+
♡
|
|
189
|
+
</span>
|
|
190
|
+
<span class="ec-reaction-label">Like</span>
|
|
191
|
+
<span class="ec-reaction-count" data-ec-reaction-count>
|
|
192
|
+
{comment.reactions?.like ?? 0}
|
|
193
|
+
</span>
|
|
194
|
+
</button>
|
|
195
|
+
</div>
|
|
196
|
+
)}
|
|
115
197
|
{threaded && comment.replies && comment.replies.length > 0 && (
|
|
116
198
|
<ol class="ec-comment-replies">
|
|
117
199
|
{comment.replies.map((reply: PublicComment) => (
|
|
@@ -153,6 +235,21 @@ function formatBody(text: string): string {
|
|
|
153
235
|
class="ec-comment-body"
|
|
154
236
|
set:html={formatBody(reply.body)}
|
|
155
237
|
/>
|
|
238
|
+
{reactions && (
|
|
239
|
+
<div class="ec-comment-actions">
|
|
240
|
+
<button
|
|
241
|
+
type="button"
|
|
242
|
+
class="ec-reaction"
|
|
243
|
+
data-ec-reaction="like"
|
|
244
|
+
data-comment-id={reply.id}
|
|
245
|
+
aria-pressed="false"
|
|
246
|
+
>
|
|
247
|
+
<span class="ec-reaction-icon" aria-hidden="true">♡</span>
|
|
248
|
+
<span class="ec-reaction-label">Like</span>
|
|
249
|
+
<span class="ec-reaction-count" data-ec-reaction-count>{reply.reactions?.like ?? 0}</span>
|
|
250
|
+
</button>
|
|
251
|
+
</div>
|
|
252
|
+
)}
|
|
156
253
|
</article>
|
|
157
254
|
</li>
|
|
158
255
|
))}
|
|
@@ -164,6 +261,8 @@ function formatBody(text: string): string {
|
|
|
164
261
|
</ol>
|
|
165
262
|
)}
|
|
166
263
|
</section>
|
|
264
|
+
{reactions && <script is:inline set:html={REACTION_SCRIPT} />}
|
|
265
|
+
</Fragment>
|
|
167
266
|
)
|
|
168
267
|
}
|
|
169
268
|
|
|
@@ -229,4 +328,40 @@ function formatBody(text: string): string {
|
|
|
229
328
|
white-space: pre-wrap;
|
|
230
329
|
word-break: break-word;
|
|
231
330
|
}
|
|
331
|
+
|
|
332
|
+
.ec-comment-actions {
|
|
333
|
+
margin-top: 0.5rem;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
.ec-reaction {
|
|
337
|
+
display: inline-flex;
|
|
338
|
+
align-items: center;
|
|
339
|
+
gap: 0.35rem;
|
|
340
|
+
font: inherit;
|
|
341
|
+
font-size: 0.875em;
|
|
342
|
+
color: inherit;
|
|
343
|
+
background: none;
|
|
344
|
+
border: var(--ec-comment-border);
|
|
345
|
+
border-radius: 999px;
|
|
346
|
+
padding: 0.15rem 0.6rem;
|
|
347
|
+
cursor: pointer;
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
.ec-reaction[aria-pressed="true"] {
|
|
351
|
+
border-color: currentColor;
|
|
352
|
+
font-weight: 600;
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
.ec-reaction[aria-pressed="true"] .ec-reaction-icon {
|
|
356
|
+
color: #e0245e;
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
.ec-reaction:disabled {
|
|
360
|
+
opacity: 0.5;
|
|
361
|
+
cursor: default;
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
.ec-reaction-count {
|
|
365
|
+
font-variant-numeric: tabular-nums;
|
|
366
|
+
}
|
|
232
367
|
</style>
|
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
|
/**
|
|
@@ -33,6 +33,19 @@ export interface QueryRecorder {
|
|
|
33
33
|
route: string;
|
|
34
34
|
method: string;
|
|
35
35
|
phase: string;
|
|
36
|
+
/**
|
|
37
|
+
* Set once the recorder has been emitted, so a flush is idempotent.
|
|
38
|
+
* Without this, a fallback flush and the stream-end flush could both
|
|
39
|
+
* fire and double-emit the events.
|
|
40
|
+
*/
|
|
41
|
+
flushed?: boolean;
|
|
42
|
+
/**
|
|
43
|
+
* Set when the response body is wrapped for stream-end metrics. The
|
|
44
|
+
* recorder is then flushed when the body finishes streaming (so it
|
|
45
|
+
* captures queries issued by components during streaming) rather than
|
|
46
|
+
* when middleware returns (headers ready, body not yet streamed).
|
|
47
|
+
*/
|
|
48
|
+
deferredFlush?: boolean;
|
|
36
49
|
}
|
|
37
50
|
|
|
38
51
|
export function createRecorder(route: string, method: string, phase: string): QueryRecorder {
|
|
@@ -60,9 +73,16 @@ export function recordEvent(
|
|
|
60
73
|
* harness pipes the child's stdout, filters lines beginning with
|
|
61
74
|
* QUERY_LOG_PREFIX, and writes them to its own file. Using stdout means
|
|
62
75
|
* the sink works uniformly in Node and in workerd (which has no fs).
|
|
76
|
+
*
|
|
77
|
+
* Idempotent: the first call emits and marks the recorder flushed, later
|
|
78
|
+
* calls no-op. For streamed responses the flush is deferred to stream end
|
|
79
|
+
* (see wrapBodyForStreamMetrics) so it captures queries issued while the
|
|
80
|
+
* body is still rendering; bodyless responses fall back to a flush when
|
|
81
|
+
* middleware returns.
|
|
63
82
|
*/
|
|
64
83
|
export function flushRecorder(rec: QueryRecorder): void {
|
|
65
|
-
if (rec.
|
|
84
|
+
if (rec.flushed) return;
|
|
85
|
+
rec.flushed = true;
|
|
66
86
|
for (const e of rec.events) {
|
|
67
87
|
console.log(`${QUERY_LOG_PREFIX} ${JSON.stringify(e)}`);
|
|
68
88
|
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import type { Kysely } from "kysely";
|
|
2
|
+
|
|
3
|
+
import { currentTimestamp } from "../dialect-helpers.js";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Comment reactions (Tier 1 of the best-in-class comments RFC).
|
|
7
|
+
*
|
|
8
|
+
* One row per (comment, voter, reaction). Toggle semantics are enforced by the
|
|
9
|
+
* unique index — a voter either has a given reaction on a comment or doesn't.
|
|
10
|
+
* `voter_hash` is a salted SHA-256 of the visitor's IP (same primitive as
|
|
11
|
+
* `_emdash_comments.ip_hash`), so no cleartext identity is stored.
|
|
12
|
+
*
|
|
13
|
+
* Additive and backward-compatible: a new table, no change to existing schema.
|
|
14
|
+
*/
|
|
15
|
+
export async function up(db: Kysely<unknown>): Promise<void> {
|
|
16
|
+
await db.schema
|
|
17
|
+
.createTable("_emdash_comment_reactions")
|
|
18
|
+
.ifNotExists()
|
|
19
|
+
.addColumn("id", "text", (col) => col.primaryKey())
|
|
20
|
+
.addColumn("comment_id", "text", (col) =>
|
|
21
|
+
col.notNull().references("_emdash_comments.id").onDelete("cascade"),
|
|
22
|
+
)
|
|
23
|
+
.addColumn("reaction", "text", (col) => col.notNull().defaultTo("like"))
|
|
24
|
+
.addColumn("voter_hash", "text", (col) => col.notNull())
|
|
25
|
+
.addColumn("created_at", "text", (col) => col.defaultTo(currentTimestamp(db)))
|
|
26
|
+
.execute();
|
|
27
|
+
|
|
28
|
+
// One reaction of a given type per voter per comment (toggle semantics).
|
|
29
|
+
await db.schema
|
|
30
|
+
.createIndex("idx_comment_reactions_unique")
|
|
31
|
+
.ifNotExists()
|
|
32
|
+
.on("_emdash_comment_reactions")
|
|
33
|
+
.columns(["comment_id", "voter_hash", "reaction"])
|
|
34
|
+
.unique()
|
|
35
|
+
.execute();
|
|
36
|
+
|
|
37
|
+
// Aggregate counts per comment (GROUP BY comment_id, reaction).
|
|
38
|
+
await db.schema
|
|
39
|
+
.createIndex("idx_comment_reactions_comment")
|
|
40
|
+
.ifNotExists()
|
|
41
|
+
.on("_emdash_comment_reactions")
|
|
42
|
+
.column("comment_id")
|
|
43
|
+
.execute();
|
|
44
|
+
|
|
45
|
+
// Per-voter rate limiting (recent reactions by a voter).
|
|
46
|
+
await db.schema
|
|
47
|
+
.createIndex("idx_comment_reactions_voter")
|
|
48
|
+
.ifNotExists()
|
|
49
|
+
.on("_emdash_comment_reactions")
|
|
50
|
+
.columns(["voter_hash", "created_at"])
|
|
51
|
+
.execute();
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export async function down(db: Kysely<unknown>): Promise<void> {
|
|
55
|
+
await db.schema.dropTable("_emdash_comment_reactions").execute();
|
|
56
|
+
}
|
|
@@ -45,6 +45,7 @@ import * as m040 from "./040_byline_i18n.js";
|
|
|
45
45
|
import * as m041 from "./041_content_locale_list_index.js";
|
|
46
46
|
import * as m042 from "./042_byline_fields.js";
|
|
47
47
|
import * as m043 from "./043_content_references.js";
|
|
48
|
+
import * as m044 from "./044_comment_reactions.js";
|
|
48
49
|
|
|
49
50
|
const MIGRATIONS: Readonly<Record<string, Migration>> = Object.freeze({
|
|
50
51
|
"001_initial": m001,
|
|
@@ -89,6 +90,7 @@ const MIGRATIONS: Readonly<Record<string, Migration>> = Object.freeze({
|
|
|
89
90
|
"041_content_locale_list_index": m041,
|
|
90
91
|
"042_byline_fields": m042,
|
|
91
92
|
"043_content_references": m043,
|
|
93
|
+
"044_comment_reactions": m044,
|
|
92
94
|
});
|
|
93
95
|
|
|
94
96
|
/** Total number of registered migrations. Exported for use in tests. */
|
|
@@ -2,6 +2,10 @@ import { sql, type Kysely, type Selectable } from "kysely";
|
|
|
2
2
|
import { ulid } from "ulidx";
|
|
3
3
|
|
|
4
4
|
import { getBylineFieldDefs } from "../../bylines/field-defs-cache.js";
|
|
5
|
+
import {
|
|
6
|
+
invalidateBylineObjectCache,
|
|
7
|
+
invalidateCollectionCache,
|
|
8
|
+
} from "../../object-cache/index.js";
|
|
5
9
|
import {
|
|
6
10
|
clearRequestCacheEntry,
|
|
7
11
|
peekRequestCache,
|
|
@@ -773,6 +777,7 @@ export class BylineRepository {
|
|
|
773
777
|
if (touchedGroupShared) {
|
|
774
778
|
clearRequestCacheEntry(`byline-field-group-values:${translationGroup}`);
|
|
775
779
|
}
|
|
780
|
+
invalidateBylineObjectCache();
|
|
776
781
|
|
|
777
782
|
const byline = await this.findById(id);
|
|
778
783
|
if (!byline) {
|
|
@@ -820,6 +825,7 @@ export class BylineRepository {
|
|
|
820
825
|
if (touchedGroupShared) {
|
|
821
826
|
clearRequestCacheEntry(`byline-field-group-values:${group}`);
|
|
822
827
|
}
|
|
828
|
+
invalidateBylineObjectCache();
|
|
823
829
|
|
|
824
830
|
return await this.findById(id);
|
|
825
831
|
}
|
|
@@ -908,6 +914,7 @@ export class BylineRepository {
|
|
|
908
914
|
}
|
|
909
915
|
});
|
|
910
916
|
|
|
917
|
+
invalidateBylineObjectCache();
|
|
911
918
|
return true;
|
|
912
919
|
}
|
|
913
920
|
|
|
@@ -1271,6 +1278,9 @@ export class BylineRepository {
|
|
|
1271
1278
|
SET primary_byline_id = ${firstByline}
|
|
1272
1279
|
WHERE id = ${targetContentId}
|
|
1273
1280
|
`.execute(this.db);
|
|
1281
|
+
|
|
1282
|
+
// Byline credits are folded into the target entry's cached payload.
|
|
1283
|
+
invalidateCollectionCache(collection);
|
|
1274
1284
|
}
|
|
1275
1285
|
|
|
1276
1286
|
/**
|
|
@@ -1365,6 +1375,9 @@ export class BylineRepository {
|
|
|
1365
1375
|
WHERE id = ${contentId}
|
|
1366
1376
|
`.execute(this.db);
|
|
1367
1377
|
|
|
1378
|
+
// Byline credits are folded into this entry's cached payload.
|
|
1379
|
+
invalidateCollectionCache(collectionSlug);
|
|
1380
|
+
|
|
1368
1381
|
return await this.getContentBylines(collectionSlug, contentId);
|
|
1369
1382
|
}
|
|
1370
1383
|
}
|