emdash 0.37.0 → 0.38.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/{activation-K0kGBWuJ.mjs → activation-DyNTe_Tl.mjs} +3 -3
- package/dist/{activation-K0kGBWuJ.mjs.map → activation-DyNTe_Tl.mjs.map} +1 -1
- package/dist/{adapters-BDQwg236.d.mts → adapters-DCEgOBXi.d.mts} +1 -1
- package/dist/{adapters-BDQwg236.d.mts.map → adapters-DCEgOBXi.d.mts.map} +1 -1
- package/dist/{allowed-origins-BGglilcs.mjs → allowed-origins-GFUVavRj.mjs} +2 -2
- package/dist/{allowed-origins-BGglilcs.mjs.map → allowed-origins-GFUVavRj.mjs.map} +1 -1
- package/dist/api/route-utils.d.mts +3 -3
- package/dist/api/route-utils.mjs +23 -22
- package/dist/api/route-utils.mjs.map +1 -1
- package/dist/api/schemas/index.d.mts +2 -2
- package/dist/api/schemas/index.mjs +5 -5
- package/dist/{api-Dz6rgoa3.mjs → api-BvxJmnFY.mjs} +141 -87
- package/dist/api-BvxJmnFY.mjs.map +1 -0
- package/dist/{api-tokens-BSsQACNe.mjs → api-tokens-xpGqMHrC.mjs} +2 -2
- package/dist/{api-tokens-BSsQACNe.mjs.map → api-tokens-xpGqMHrC.mjs.map} +1 -1
- package/dist/{apply-B4SIOxR1.mjs → apply-DLmM3R7f.mjs} +25 -21
- package/dist/apply-DLmM3R7f.mjs.map +1 -0
- package/dist/{config-it29yDLA.mjs → artifact-fetch-P2JXVwOq.mjs} +8 -199
- package/dist/artifact-fetch-P2JXVwOq.mjs.map +1 -0
- package/dist/astro/index.d.mts +12 -12
- package/dist/astro/index.d.mts.map +1 -1
- package/dist/astro/index.mjs +37 -11
- package/dist/astro/index.mjs.map +1 -1
- package/dist/astro/middleware/auth.d.mts +10 -10
- package/dist/astro/middleware/auth.mjs +6 -6
- package/dist/astro/middleware/media-usage-write-fence.mjs +3 -3
- package/dist/astro/middleware/redirect.mjs +7 -5
- package/dist/astro/middleware/redirect.mjs.map +1 -1
- package/dist/astro/middleware/request-context.mjs +3 -3
- package/dist/astro/middleware/setup.mjs +1 -1
- package/dist/astro/middleware.d.mts +10 -10
- package/dist/astro/middleware.d.mts.map +1 -1
- package/dist/astro/middleware.mjs +154 -125
- package/dist/astro/middleware.mjs.map +1 -1
- package/dist/astro/routes/api/admin/allowed-domains/_domain_.mjs +6 -6
- package/dist/astro/routes/api/admin/allowed-domains/index.mjs +6 -6
- 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 +9 -9
- package/dist/astro/routes/api/admin/byline-fields/index.mjs +9 -9
- package/dist/astro/routes/api/admin/byline-fields/reorder.mjs +9 -9
- package/dist/astro/routes/api/admin/bylines/_id_/index.mjs +16 -16
- package/dist/astro/routes/api/admin/bylines/_id_/translations.mjs +16 -16
- package/dist/astro/routes/api/admin/bylines/index.mjs +16 -16
- package/dist/astro/routes/api/admin/comments/_id_/status.mjs +11 -11
- package/dist/astro/routes/api/admin/comments/_id_.mjs +3 -3
- package/dist/astro/routes/api/admin/comments/bulk.mjs +8 -8
- package/dist/astro/routes/api/admin/comments/counts.mjs +3 -3
- package/dist/astro/routes/api/admin/comments/index.mjs +8 -8
- package/dist/astro/routes/api/admin/hooks/exclusive/_hookName_.mjs +4 -4
- package/dist/astro/routes/api/admin/hooks/exclusive/index.mjs +3 -3
- package/dist/astro/routes/api/admin/media-usage/activation.mjs +13 -13
- package/dist/astro/routes/api/admin/media-usage/collection-deletions/index.mjs +15 -15
- package/dist/astro/routes/api/admin/media-usage/collection-deletions/retry.mjs +15 -15
- package/dist/astro/routes/api/admin/media-usage/progress.mjs +13 -13
- package/dist/astro/routes/api/admin/media-usage/repair.mjs +16 -16
- package/dist/astro/routes/api/admin/media-usage/work/index.mjs +15 -15
- package/dist/astro/routes/api/admin/media-usage/work/retry.mjs +15 -15
- 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 +56 -53
- package/dist/astro/routes/api/admin/plugins/_id_/disable.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/_id_/enable.mjs +56 -53
- package/dist/astro/routes/api/admin/plugins/_id_/enable.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/_id_/index.mjs +54 -51
- package/dist/astro/routes/api/admin/plugins/_id_/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/_id_/mcp.mjs +4 -4
- package/dist/astro/routes/api/admin/plugins/_id_/settings.mjs +54 -51
- package/dist/astro/routes/api/admin/plugins/_id_/settings.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/_id_/uninstall.mjs +55 -52
- package/dist/astro/routes/api/admin/plugins/_id_/uninstall.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/_id_/update.mjs +55 -52
- package/dist/astro/routes/api/admin/plugins/_id_/update.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/index.mjs +54 -51
- 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 +54 -51
- 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 +55 -52
- package/dist/astro/routes/api/admin/plugins/marketplace/_id_/install.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/marketplace/index.mjs +54 -51
- package/dist/astro/routes/api/admin/plugins/marketplace/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/registry/_id_/uninstall.mjs +55 -52
- 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 +56 -53
- package/dist/astro/routes/api/admin/plugins/registry/_id_/update.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/registry/artifact.mjs +5 -4
- package/dist/astro/routes/api/admin/plugins/registry/artifact.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/registry/install.mjs +56 -53
- package/dist/astro/routes/api/admin/plugins/registry/install.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/registry/verify.mjs +55 -52
- package/dist/astro/routes/api/admin/plugins/registry/verify.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/updates.mjs +54 -51
- package/dist/astro/routes/api/admin/plugins/updates.mjs.map +1 -1
- package/dist/astro/routes/api/admin/themes/marketplace/_id_/index.mjs +54 -51
- 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 +54 -51
- 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 +6 -6
- package/dist/astro/routes/api/admin/users/_id_/send-recovery.mjs +3 -3
- package/dist/astro/routes/api/admin/users/index.mjs +6 -6
- 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 +11 -11
- package/dist/astro/routes/api/auth/invite/index.mjs +8 -8
- package/dist/astro/routes/api/auth/invite/register-options.mjs +10 -10
- package/dist/astro/routes/api/auth/logout.mjs +2 -2
- package/dist/astro/routes/api/auth/magic-link/send.mjs +10 -10
- package/dist/astro/routes/api/auth/magic-link/verify.mjs +2 -2
- package/dist/astro/routes/api/auth/me.mjs +7 -7
- package/dist/astro/routes/api/auth/mode.mjs +2 -2
- 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 +6 -6
- package/dist/astro/routes/api/auth/passkey/index.mjs +1 -1
- package/dist/astro/routes/api/auth/passkey/options.mjs +12 -12
- package/dist/astro/routes/api/auth/passkey/register/options.mjs +10 -10
- package/dist/astro/routes/api/auth/passkey/register/verify.mjs +11 -11
- package/dist/astro/routes/api/auth/passkey/verify.mjs +11 -11
- package/dist/astro/routes/api/auth/signup/complete.mjs +11 -11
- package/dist/astro/routes/api/auth/signup/request.mjs +10 -10
- package/dist/astro/routes/api/auth/signup/verify.mjs +1 -1
- package/dist/astro/routes/api/comments/_collection_/_contentId_/index.mjs +12 -12
- package/dist/astro/routes/api/comments/_collection_/_contentId_/reactions.mjs +11 -11
- package/dist/astro/routes/api/content/_collection_/_id_/compare.mjs +2 -2
- package/dist/astro/routes/api/content/_collection_/_id_/discard-draft.d.mts.map +1 -1
- package/dist/astro/routes/api/content/_collection_/_id_/discard-draft.mjs +13 -8
- package/dist/astro/routes/api/content/_collection_/_id_/discard-draft.mjs.map +1 -1
- package/dist/astro/routes/api/content/_collection_/_id_/duplicate.mjs +3 -3
- package/dist/astro/routes/api/content/_collection_/_id_/lock.d.mts +10 -0
- package/dist/astro/routes/api/content/_collection_/_id_/lock.d.mts.map +1 -0
- package/dist/astro/routes/api/content/_collection_/_id_/lock.mjs +66 -0
- package/dist/astro/routes/api/content/_collection_/_id_/lock.mjs.map +1 -0
- package/dist/astro/routes/api/content/_collection_/_id_/permanent.mjs +2 -2
- package/dist/astro/routes/api/content/_collection_/_id_/preview-url.mjs +11 -11
- package/dist/astro/routes/api/content/_collection_/_id_/publish.d.mts.map +1 -1
- package/dist/astro/routes/api/content/_collection_/_id_/publish.mjs +14 -9
- package/dist/astro/routes/api/content/_collection_/_id_/publish.mjs.map +1 -1
- package/dist/astro/routes/api/content/_collection_/_id_/references/_relation_/children.mjs +19 -17
- package/dist/astro/routes/api/content/_collection_/_id_/references/_relation_/children.mjs.map +1 -1
- package/dist/astro/routes/api/content/_collection_/_id_/references/_relation_/parents.mjs +19 -17
- package/dist/astro/routes/api/content/_collection_/_id_/references/_relation_/parents.mjs.map +1 -1
- package/dist/astro/routes/api/content/_collection_/_id_/restore.mjs +3 -3
- package/dist/astro/routes/api/content/_collection_/_id_/revisions.mjs +2 -2
- package/dist/astro/routes/api/content/_collection_/_id_/schedule.d.mts.map +1 -1
- package/dist/astro/routes/api/content/_collection_/_id_/schedule.mjs +15 -8
- package/dist/astro/routes/api/content/_collection_/_id_/schedule.mjs.map +1 -1
- package/dist/astro/routes/api/content/_collection_/_id_/terms/_taxonomy_.mjs +15 -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 +2 -2
- package/dist/astro/routes/api/content/_collection_/_id_/unpublish.d.mts.map +1 -1
- package/dist/astro/routes/api/content/_collection_/_id_/unpublish.mjs +13 -8
- package/dist/astro/routes/api/content/_collection_/_id_/unpublish.mjs.map +1 -1
- package/dist/astro/routes/api/content/_collection_/_id_.d.mts.map +1 -1
- package/dist/astro/routes/api/content/_collection_/_id_.mjs +23 -11
- 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 +14 -9
- package/dist/astro/routes/api/content/_collection_/index.mjs.map +1 -1
- package/dist/astro/routes/api/content/_collection_/trash.mjs +7 -7
- package/dist/astro/routes/api/dashboard.mjs +6 -6
- 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 +16 -16
- package/dist/astro/routes/api/import/wordpress/analyze.mjs +3 -3
- package/dist/astro/routes/api/import/wordpress/execute.d.mts +11 -11
- package/dist/astro/routes/api/import/wordpress/execute.mjs +14 -13
- package/dist/astro/routes/api/import/wordpress/execute.mjs.map +1 -1
- package/dist/astro/routes/api/import/wordpress/media.d.mts +10 -10
- package/dist/astro/routes/api/import/wordpress/media.mjs +11 -11
- package/dist/astro/routes/api/import/wordpress/prepare.mjs +10 -10
- package/dist/astro/routes/api/import/wordpress/rewrite-urls.d.mts +11 -11
- package/dist/astro/routes/api/import/wordpress/rewrite-urls.mjs +13 -13
- package/dist/astro/routes/api/import/wordpress-plugin/analyze.d.mts +1 -1
- package/dist/astro/routes/api/import/wordpress-plugin/analyze.mjs +16 -16
- package/dist/astro/routes/api/import/wordpress-plugin/execute.d.mts +11 -11
- package/dist/astro/routes/api/import/wordpress-plugin/execute.mjs +27 -26
- package/dist/astro/routes/api/import/wordpress-plugin/execute.mjs.map +1 -1
- package/dist/astro/routes/api/manifest.mjs +4 -4
- package/dist/astro/routes/api/mcp.mjs +71 -55
- package/dist/astro/routes/api/mcp.mjs.map +1 -1
- package/dist/astro/routes/api/media/_id_/confirm.mjs +10 -10
- package/dist/astro/routes/api/media/_id_/replace.mjs +8 -8
- package/dist/astro/routes/api/media/_id_/upload.mjs +5 -5
- package/dist/astro/routes/api/media/_id_/usage.mjs +18 -18
- package/dist/astro/routes/api/media/_id_.mjs +17 -17
- package/dist/astro/routes/api/media/file/_...key_.mjs +1 -1
- package/dist/astro/routes/api/media/folders/_id_.mjs +8 -8
- package/dist/astro/routes/api/media/folders/index.mjs +8 -8
- 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 +9 -9
- package/dist/astro/routes/api/media.mjs +21 -21
- package/dist/astro/routes/api/menus/_name_/items/_id_.mjs +9 -9
- package/dist/astro/routes/api/menus/_name_/items.mjs +9 -9
- package/dist/astro/routes/api/menus/_name_/reorder.mjs +9 -9
- package/dist/astro/routes/api/menus/_name_/translations.mjs +9 -9
- package/dist/astro/routes/api/menus/_name_.mjs +9 -9
- package/dist/astro/routes/api/menus/index.mjs +9 -9
- 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 +84 -18
- package/dist/astro/routes/api/openapi.json.mjs.map +1 -1
- package/dist/astro/routes/api/plugins/_pluginId_/_...path_.mjs +4 -4
- package/dist/astro/routes/api/redirects/404s/index.mjs +12 -11
- package/dist/astro/routes/api/redirects/404s/index.mjs.map +1 -1
- package/dist/astro/routes/api/redirects/404s/summary.mjs +12 -11
- package/dist/astro/routes/api/redirects/404s/summary.mjs.map +1 -1
- package/dist/astro/routes/api/redirects/_id_.mjs +13 -12
- package/dist/astro/routes/api/redirects/_id_.mjs.map +1 -1
- package/dist/astro/routes/api/redirects/index.mjs +13 -12
- package/dist/astro/routes/api/redirects/index.mjs.map +1 -1
- package/dist/astro/routes/api/relations/_id_/index.mjs +19 -17
- package/dist/astro/routes/api/relations/_id_/index.mjs.map +1 -1
- package/dist/astro/routes/api/relations/_id_/translations.mjs +14 -12
- package/dist/astro/routes/api/relations/_id_/translations.mjs.map +1 -1
- package/dist/astro/routes/api/relations/index.mjs +19 -17
- package/dist/astro/routes/api/relations/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 +3 -3
- package/dist/astro/routes/api/schema/collections/_slug_/fields/_fieldSlug_.mjs +54 -51
- 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 +54 -51
- 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 +54 -51
- package/dist/astro/routes/api/schema/collections/_slug_/fields/reorder.mjs.map +1 -1
- package/dist/astro/routes/api/schema/collections/_slug_/index.mjs +54 -51
- package/dist/astro/routes/api/schema/collections/_slug_/index.mjs.map +1 -1
- package/dist/astro/routes/api/schema/collections/index.mjs +54 -51
- package/dist/astro/routes/api/schema/collections/index.mjs.map +1 -1
- package/dist/astro/routes/api/schema/collections/reorder.mjs +54 -51
- package/dist/astro/routes/api/schema/collections/reorder.mjs.map +1 -1
- package/dist/astro/routes/api/schema/index.mjs +13 -11
- package/dist/astro/routes/api/schema/index.mjs.map +1 -1
- package/dist/astro/routes/api/schema/orphans/_slug_.mjs +54 -51
- package/dist/astro/routes/api/schema/orphans/_slug_.mjs.map +1 -1
- package/dist/astro/routes/api/schema/orphans/index.mjs +54 -51
- package/dist/astro/routes/api/schema/orphans/index.mjs.map +1 -1
- package/dist/astro/routes/api/search/enable.mjs +12 -11
- package/dist/astro/routes/api/search/enable.mjs.map +1 -1
- package/dist/astro/routes/api/search/index.mjs +11 -10
- package/dist/astro/routes/api/search/index.mjs.map +1 -1
- package/dist/astro/routes/api/search/rebuild.mjs +12 -11
- package/dist/astro/routes/api/search/rebuild.mjs.map +1 -1
- package/dist/astro/routes/api/search/stats.mjs +7 -6
- package/dist/astro/routes/api/search/stats.mjs.map +1 -1
- package/dist/astro/routes/api/search/suggest.mjs +11 -10
- package/dist/astro/routes/api/search/suggest.mjs.map +1 -1
- package/dist/astro/routes/api/sections/_slug_.mjs +11 -10
- package/dist/astro/routes/api/sections/_slug_.mjs.map +1 -1
- package/dist/astro/routes/api/sections/index.mjs +11 -10
- package/dist/astro/routes/api/sections/index.mjs.map +1 -1
- package/dist/astro/routes/api/settings/backups/archives/_name_.mjs +7 -6
- package/dist/astro/routes/api/settings/backups/archives/_name_.mjs.map +1 -1
- package/dist/astro/routes/api/settings/backups/archives/index.mjs +6 -5
- package/dist/astro/routes/api/settings/backups/archives/index.mjs.map +1 -1
- package/dist/astro/routes/api/settings/backups/export.mjs +7 -6
- package/dist/astro/routes/api/settings/backups/export.mjs.map +1 -1
- package/dist/astro/routes/api/settings/backups/index.mjs +8 -7
- package/dist/astro/routes/api/settings/backups/index.mjs.map +1 -1
- package/dist/astro/routes/api/settings/email.mjs +4 -4
- package/dist/astro/routes/api/settings.mjs +14 -14
- package/dist/astro/routes/api/setup/admin-verify.mjs +12 -12
- package/dist/astro/routes/api/setup/admin.mjs +11 -11
- package/dist/astro/routes/api/setup/dev-bypass.mjs +33 -31
- package/dist/astro/routes/api/setup/dev-bypass.mjs.map +1 -1
- package/dist/astro/routes/api/setup/dev-reset.mjs +2 -2
- package/dist/astro/routes/api/setup/index.mjs +33 -31
- 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 +8 -7
- package/dist/astro/routes/api/snapshot.mjs.map +1 -1
- package/dist/astro/routes/api/taxonomies/_name_/reorder.mjs +16 -15
- package/dist/astro/routes/api/taxonomies/_name_/reorder.mjs.map +1 -1
- package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_/translations.mjs +16 -15
- 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 -15
- package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_.mjs.map +1 -1
- package/dist/astro/routes/api/taxonomies/_name_/terms/index.mjs +16 -15
- package/dist/astro/routes/api/taxonomies/_name_/terms/index.mjs.map +1 -1
- package/dist/astro/routes/api/taxonomies/_name_/translations.mjs +15 -14
- package/dist/astro/routes/api/taxonomies/_name_/translations.mjs.map +1 -1
- package/dist/astro/routes/api/taxonomies/_name_.mjs +16 -15
- package/dist/astro/routes/api/taxonomies/_name_.mjs.map +1 -1
- package/dist/astro/routes/api/taxonomies/index.mjs +16 -15
- package/dist/astro/routes/api/taxonomies/index.mjs.map +1 -1
- package/dist/astro/routes/api/themes/preview.mjs +5 -5
- package/dist/astro/routes/api/typegen.mjs +4 -4
- 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 -8
- package/dist/astro/routes/api/widget-areas/_name_/widgets/_id_.mjs +12 -12
- package/dist/astro/routes/api/widget-areas/_name_/widgets.mjs +12 -12
- package/dist/astro/routes/api/widget-areas/_name_.mjs +7 -7
- package/dist/astro/routes/api/widget-areas/index.mjs +12 -12
- package/dist/astro/routes/api/widget-components.mjs +2 -2
- package/dist/astro/routes/robots.txt.mjs +6 -6
- package/dist/astro/routes/sitemap-_collection_.xml.mjs +11 -10
- package/dist/astro/routes/sitemap-_collection_.xml.mjs.map +1 -1
- package/dist/astro/routes/sitemap.xml.mjs +7 -7
- package/dist/astro/types.d.mts +32 -17
- 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-Bkf_UHhD.mjs → authorize-C2QHlWSS.mjs} +2 -2
- package/dist/{authorize-Bkf_UHhD.mjs.map → authorize-C2QHlWSS.mjs.map} +1 -1
- package/dist/{backup-rwVAl9NI.mjs → backup-oS8ft5Cm.mjs} +5 -5
- package/dist/{backup-rwVAl9NI.mjs.map → backup-oS8ft5Cm.mjs.map} +1 -1
- package/dist/{bundle-C8S2Zl6U.mjs → bundle-CL0JjIPx.mjs} +4 -4
- package/dist/{bundle-C8S2Zl6U.mjs.map → bundle-CL0JjIPx.mjs.map} +1 -1
- package/dist/{byline-DuhF7NWl.mjs → byline-Vdi85CsZ.mjs} +6 -6
- package/dist/{byline-DuhF7NWl.mjs.map → byline-Vdi85CsZ.mjs.map} +1 -1
- package/dist/{byline-fields-BovY4KYM.mjs → byline-fields-DPVRFMz2.mjs} +2 -2
- package/dist/{byline-fields-BovY4KYM.mjs.map → byline-fields-DPVRFMz2.mjs.map} +1 -1
- package/dist/{byline-registry-Bpu9-MVs.mjs → byline-registry-BxDGIO0I.mjs} +2 -2
- package/dist/{byline-registry-Bpu9-MVs.mjs.map → byline-registry-BxDGIO0I.mjs.map} +1 -1
- package/dist/{bylines-CJ5nd6Lw.mjs → bylines-BX8QhcTk.mjs} +7 -7
- package/dist/{bylines-CJ5nd6Lw.mjs.map → bylines-BX8QhcTk.mjs.map} +1 -1
- package/dist/{bylines-RwBAeOF1.mjs → bylines-w-E1IEQd.mjs} +3 -3
- package/dist/{bylines-RwBAeOF1.mjs.map → bylines-w-E1IEQd.mjs.map} +1 -1
- package/dist/{cache-BF5Kvn59.mjs → cache--7HKu5Xm.mjs} +4 -4
- package/dist/{cache-BF5Kvn59.mjs.map → cache--7HKu5Xm.mjs.map} +1 -1
- package/dist/{capture-triggers-CNW1q3HK.mjs → capture-triggers-CeAsC76Z.mjs} +2 -2
- package/dist/{capture-triggers-CNW1q3HK.mjs.map → capture-triggers-CeAsC76Z.mjs.map} +1 -1
- package/dist/{challenge-store-DQN_Yrck.mjs → challenge-store-BIOak-tp.mjs} +1 -1
- package/dist/{challenge-store-DQN_Yrck.mjs.map → challenge-store-BIOak-tp.mjs.map} +1 -1
- package/dist/{chrome-tags-D8fiZG94.mjs → chrome-tags-DzDQBCjX.mjs} +1 -1
- package/dist/{chrome-tags-D8fiZG94.mjs.map → chrome-tags-DzDQBCjX.mjs.map} +1 -1
- package/dist/{chunks-C4szrD8o.mjs → chunks-VG_tyqnP.mjs} +2 -2
- package/dist/{chunks-C4szrD8o.mjs.map → chunks-VG_tyqnP.mjs.map} +1 -1
- package/dist/cli/index.mjs +66 -38
- package/dist/cli/index.mjs.map +1 -1
- package/dist/client/cf-access.d.mts +1 -1
- package/dist/client/index.d.mts +17 -7
- package/dist/client/index.d.mts.map +1 -1
- package/dist/client/index.mjs +17 -12
- package/dist/client/index.mjs.map +1 -1
- package/dist/{collection-deletion-Bj07NHbj.mjs → collection-deletion-BCwaWTDw.mjs} +4 -4
- package/dist/{collection-deletion-Bj07NHbj.mjs.map → collection-deletion-BCwaWTDw.mjs.map} +1 -1
- package/dist/collection-slugs-cache-7lTmNzeA.mjs +85 -0
- package/dist/collection-slugs-cache-7lTmNzeA.mjs.map +1 -0
- package/dist/{comment-reaction-BhrvSHml.mjs → comment-reaction-CDyvPQRj.mjs} +2 -2
- package/dist/{comment-reaction-BhrvSHml.mjs.map → comment-reaction-CDyvPQRj.mjs.map} +1 -1
- package/dist/{comments-Ct4ensnf.mjs → comments-VzmVLyaC.mjs} +1 -1
- package/dist/{comments-Ct4ensnf.mjs.map → comments-VzmVLyaC.mjs.map} +1 -1
- package/dist/{components-DJbo1z0S.mjs → components-CL6Wkdk-.mjs} +1 -1
- package/dist/{components-DJbo1z0S.mjs.map → components-CL6Wkdk-.mjs.map} +1 -1
- package/dist/config--eWjQJE5.mjs +217 -0
- package/dist/config--eWjQJE5.mjs.map +1 -0
- package/dist/{index-BJNMCWmu.d.mts → config-CGAhyOjP.d.mts} +138 -47
- package/dist/config-CGAhyOjP.d.mts.map +1 -0
- package/dist/{config-B9eZ340f.d.mts → config-ChFzshGd.d.mts} +1 -1
- package/dist/{config-B9eZ340f.d.mts.map → config-ChFzshGd.d.mts.map} +1 -1
- package/dist/{content-DjvM0T92.mjs → content-CNfMWuhY.mjs} +121 -5
- package/dist/content-CNfMWuhY.mjs.map +1 -0
- package/dist/{content-list-query-Btqd4uV2.d.mts → content-list-query-B8d4UQp9.d.mts} +1 -1
- package/dist/{content-list-query-Btqd4uV2.d.mts.map → content-list-query-B8d4UQp9.d.mts.map} +1 -1
- package/dist/{content-refresh-Bwp-8yGy.mjs → content-refresh-GTMyi2Xy.mjs} +8 -8
- package/dist/{content-refresh-Bwp-8yGy.mjs.map → content-refresh-GTMyi2Xy.mjs.map} +1 -1
- package/dist/{content-repair-Czdp7jz5.mjs → content-repair-CIMt5C0U.mjs} +4 -4
- package/dist/{content-repair-Czdp7jz5.mjs.map → content-repair-CIMt5C0U.mjs.map} +1 -1
- package/dist/{context-CX6gxOLW.mjs → context-C9PB8vGd.mjs} +265 -25
- package/dist/context-C9PB8vGd.mjs.map +1 -0
- package/dist/{cron-C6o7VppJ.mjs → cron-DHAy9oyq.mjs} +1 -1
- package/dist/{cron-C6o7VppJ.mjs.map → cron-DHAy9oyq.mjs.map} +1 -1
- package/dist/{dashboard-C2kTeeRI.mjs → dashboard-BNSvAN8A.mjs} +4 -4
- package/dist/{dashboard-C2kTeeRI.mjs.map → dashboard-BNSvAN8A.mjs.map} +1 -1
- package/dist/db/index.d.mts +3 -3
- package/dist/db/index.mjs +2 -2
- package/dist/db/libsql-migrations.d.mts +1 -1
- package/dist/db/libsql-migrations.mjs +5 -5
- package/dist/db/libsql.d.mts +1 -1
- package/dist/db/postgres-migrations.d.mts +1 -1
- package/dist/db/postgres-migrations.mjs +5 -5
- package/dist/db/postgres.d.mts +1 -1
- package/dist/db/sqlite-migrations.d.mts +1 -1
- package/dist/db/sqlite-migrations.mjs +5 -5
- package/dist/db/sqlite.d.mts +1 -1
- package/dist/db/sqlite.mjs +1 -1
- package/dist/{default-Clra32mw.mjs → default-ByZ0JqZo.mjs} +1 -1
- package/dist/{default-Clra32mw.mjs.map → default-ByZ0JqZo.mjs.map} +1 -1
- package/dist/{deferred-tasks-CvDETTJO.d.mts → deferred-tasks-Cu4NSJpa.d.mts} +1 -1
- package/dist/{deferred-tasks-CvDETTJO.d.mts.map → deferred-tasks-Cu4NSJpa.d.mts.map} +1 -1
- package/dist/{dev-typegen-DzOPfsNj.mjs → dev-typegen-DHT7lcMU.mjs} +1 -1
- package/dist/{dev-typegen-DzOPfsNj.mjs.map → dev-typegen-DHT7lcMU.mjs.map} +1 -1
- package/dist/{device-flow-D2oCWvLJ.mjs → device-flow-Cf6bhCCT.mjs} +4 -4
- package/dist/{device-flow-D2oCWvLJ.mjs.map → device-flow-Cf6bhCCT.mjs.map} +1 -1
- package/dist/{dialect-helpers-BSbfaO3F.mjs → dialect-helpers-BcQvkHgn.mjs} +83 -2
- package/dist/dialect-helpers-BcQvkHgn.mjs.map +1 -0
- package/dist/{direct-executor-Bfa5_ToE.mjs → direct-executor-yAyUGSqB.mjs} +3 -3
- package/dist/{direct-executor-Bfa5_ToE.mjs.map → direct-executor-yAyUGSqB.mjs.map} +1 -1
- package/dist/{dist-89xCrGqi.mjs → dist-BAsh8dbf.mjs} +1 -1
- package/dist/{dist-89xCrGqi.mjs.map → dist-BAsh8dbf.mjs.map} +1 -1
- package/dist/{email-console-Dzb6uGYa.mjs → email-console-DNup1Fku.mjs} +1 -1
- package/dist/{email-console-Dzb6uGYa.mjs.map → email-console-DNup1Fku.mjs.map} +1 -1
- package/dist/{enrich-BX0IDp4z.mjs → enrich-t2Xvjdqa.mjs} +3 -3
- package/dist/{enrich-BX0IDp4z.mjs.map → enrich-t2Xvjdqa.mjs.map} +1 -1
- package/dist/entry-lock-BEr8gDkG.mjs +163 -0
- package/dist/entry-lock-BEr8gDkG.mjs.map +1 -0
- package/dist/{relations-DnRK4YIT.d.mts → entry-lock-CGAtrwAR.d.mts} +92 -37
- package/dist/entry-lock-CGAtrwAR.d.mts.map +1 -0
- package/dist/{redirects-BLNOWQTn.mjs → entry-lock-DIYHAaSw.mjs} +57 -14
- package/dist/entry-lock-DIYHAaSw.mjs.map +1 -0
- package/dist/entry-locks-BEcX7ET0.mjs +167 -0
- package/dist/entry-locks-BEcX7ET0.mjs.map +1 -0
- package/dist/{error-DFrQjppn.mjs → error-BDcFyoRt.mjs} +2 -2
- package/dist/{error-DFrQjppn.mjs.map → error-BDcFyoRt.mjs.map} +1 -1
- package/dist/{errors-DsVoDUjJ.mjs → errors-DvMdNrgf.mjs} +8 -1
- package/dist/errors-DvMdNrgf.mjs.map +1 -0
- package/dist/{escape-HmHTC1Is.mjs → escape-B3asJC6W.mjs} +1 -1
- package/dist/{escape-HmHTC1Is.mjs.map → escape-B3asJC6W.mjs.map} +1 -1
- package/dist/{field-defs-cache-BM4SIRqH.mjs → field-defs-cache-Cf5FHK0M.mjs} +5 -5
- package/dist/{field-defs-cache-BM4SIRqH.mjs.map → field-defs-cache-Cf5FHK0M.mjs.map} +1 -1
- package/dist/{fts-manager-Do1BlW2r.mjs → fts-manager-iddym8cd.mjs} +4 -4
- package/dist/{fts-manager-Do1BlW2r.mjs.map → fts-manager-iddym8cd.mjs.map} +1 -1
- package/dist/{hash-3JJPlHF2.mjs → hash-BRweX6jz.mjs} +1 -1
- package/dist/{hash-3JJPlHF2.mjs.map → hash-BRweX6jz.mjs.map} +1 -1
- package/dist/{hook-result-DCh2WUpe.d.mts → hook-result-BrshYHLx.d.mts} +1 -1
- package/dist/{hook-result-DCh2WUpe.d.mts.map → hook-result-BrshYHLx.d.mts.map} +1 -1
- package/dist/{hreflang-B6hbAuuO.d.mts → hreflang-CQpu5bMy.d.mts} +2 -2
- package/dist/{hreflang-B6hbAuuO.d.mts.map → hreflang-CQpu5bMy.d.mts.map} +1 -1
- package/dist/{hreflang-DQbPZliA.mjs → hreflang-DshnweTC.mjs} +9 -8
- package/dist/{hreflang-DQbPZliA.mjs.map → hreflang-DshnweTC.mjs.map} +1 -1
- package/dist/{identity-DksvEazf.mjs → identity-CjGKDq8J.mjs} +3 -3
- package/dist/{identity-DksvEazf.mjs.map → identity-CjGKDq8J.mjs.map} +1 -1
- package/dist/{import-CJpaBBBT.mjs → import-D96g2otw.mjs} +5 -5
- package/dist/{import-CJpaBBBT.mjs.map → import-D96g2otw.mjs.map} +1 -1
- package/dist/{index-Du8K7bWa.d.mts → index-1ECYpfiF.d.mts} +3 -3
- package/dist/{index-Du8K7bWa.d.mts.map → index-1ECYpfiF.d.mts.map} +1 -1
- package/dist/index.d.mts +22 -22
- package/dist/index.mjs +81 -78
- package/dist/{init-lock-DJkX6Hto.mjs → init-lock-CFNBe_iH.mjs} +1 -1
- package/dist/{init-lock-DJkX6Hto.mjs.map → init-lock-CFNBe_iH.mjs.map} +1 -1
- package/dist/{load-CawHjTOH.mjs → load-DPtY9cZo.mjs} +2 -2
- package/dist/{load-CawHjTOH.mjs.map → load-DPtY9cZo.mjs.map} +1 -1
- package/dist/{loader-Z8vl7zTq.mjs → loader-WJi6GFRn.mjs} +46 -8
- package/dist/loader-WJi6GFRn.mjs.map +1 -0
- package/dist/{manifest-builder-COtzuca2.mjs → manifest-builder-BfNlGQIA.mjs} +2 -2
- package/dist/{manifest-builder-COtzuca2.mjs.map → manifest-builder-BfNlGQIA.mjs.map} +1 -1
- package/dist/{manifest-schema-BNWwR8Vd.mjs → manifest-schema-CILooI5J.mjs} +1 -1
- package/dist/{manifest-schema-BNWwR8Vd.mjs.map → manifest-schema-CILooI5J.mjs.map} +1 -1
- package/dist/media/image-endpoint.mjs +1 -1
- package/dist/media/index.d.mts +1 -1
- package/dist/media/index.mjs +3 -3
- package/dist/media/local-runtime.d.mts +12 -12
- package/dist/media/local-runtime.mjs +5 -5
- package/dist/{media-BHjus86Y.mjs → media-C1EIZKh1.mjs} +1 -1
- package/dist/{media-BHjus86Y.mjs.map → media-C1EIZKh1.mjs.map} +1 -1
- package/dist/{media-allowlist-CoTBWoDp.mjs → media-allowlist-elXJgb_K.mjs} +2 -2
- package/dist/{media-allowlist-CoTBWoDp.mjs.map → media-allowlist-elXJgb_K.mjs.map} +1 -1
- package/dist/{media-folders-BGkATs8n.mjs → media-folders-DASfX_DH.mjs} +1 -1
- package/dist/{media-folders-BGkATs8n.mjs.map → media-folders-DASfX_DH.mjs.map} +1 -1
- package/dist/{media-upload-BCidR-EY.mjs → media-upload-C7_AQJ5v.mjs} +8 -8
- package/dist/{media-upload-BCidR-EY.mjs.map → media-upload-C7_AQJ5v.mjs.map} +1 -1
- package/dist/{media-url-DHoPr0hq.mjs → media-url-8dVl1loq.mjs} +19 -2
- package/dist/media-url-8dVl1loq.mjs.map +1 -0
- package/dist/{media-usage-CdY5jhSR.mjs → media-usage-C1EswMTq.mjs} +9 -9
- package/dist/{media-usage-CdY5jhSR.mjs.map → media-usage-C1EswMTq.mjs.map} +1 -1
- package/dist/{media-usage-activation-BgeMtK5C.mjs → media-usage-activation-CrHNltlL.mjs} +3 -3
- package/dist/{media-usage-activation-BgeMtK5C.mjs.map → media-usage-activation-CrHNltlL.mjs.map} +1 -1
- package/dist/{media-usage-work-D6D9sMCA.mjs → media-usage-work-C5B1zT1c.mjs} +2 -2
- package/dist/{media-usage-work-D6D9sMCA.mjs.map → media-usage-work-C5B1zT1c.mjs.map} +1 -1
- package/dist/{media-usage-work-CnGCdHxx.mjs → media-usage-work-IkQx_Yz6.mjs} +4 -4
- package/dist/{media-usage-work-CnGCdHxx.mjs.map → media-usage-work-IkQx_Yz6.mjs.map} +1 -1
- package/dist/{media-usage-write-fence-hjeD4u7s.mjs → media-usage-write-fence-B9anjOSg.mjs} +3 -3
- package/dist/{media-usage-write-fence-hjeD4u7s.mjs.map → media-usage-write-fence-B9anjOSg.mjs.map} +1 -1
- package/dist/{menus-6qSwTNxG.mjs → menus-D8mC4eaN.mjs} +115 -136
- package/dist/menus-D8mC4eaN.mjs.map +1 -0
- package/dist/{menus-uvPLXMZf.mjs → menus-UdwjHZJC.mjs} +11 -3
- package/dist/{menus-uvPLXMZf.mjs.map → menus-UdwjHZJC.mjs.map} +1 -1
- package/dist/migrations/index.d.mts +1 -1
- package/dist/migrations/index.mjs +4 -4
- package/dist/{mime-CUIG6x84.mjs → mime-DYpsOAny.mjs} +1 -1
- package/dist/{mime-CUIG6x84.mjs.map → mime-DYpsOAny.mjs.map} +1 -1
- package/dist/{mode-DN_WneRx.mjs → mode-Dm4BHhRH.mjs} +1 -1
- package/dist/{mode-DN_WneRx.mjs.map → mode-Dm4BHhRH.mjs.map} +1 -1
- package/dist/{node-sqlite-compat-BuJXIeMz.mjs → node-sqlite-compat-2sezm-Zd.mjs} +1 -1
- package/dist/{node-sqlite-compat-BuJXIeMz.mjs.map → node-sqlite-compat-2sezm-Zd.mjs.map} +1 -1
- package/dist/{normalize-C2xNjTSG.mjs → normalize-4nkKGsuW.mjs} +1 -1
- package/dist/{normalize-C2xNjTSG.mjs.map → normalize-4nkKGsuW.mjs.map} +1 -1
- package/dist/{oauth-authorization-Dj6Kwc21.mjs → oauth-authorization-BxE_lURD.mjs} +4 -4
- package/dist/{oauth-authorization-Dj6Kwc21.mjs.map → oauth-authorization-BxE_lURD.mjs.map} +1 -1
- package/dist/{oauth-clients-FD7I0J8m.mjs → oauth-clients-DJIdOdq0.mjs} +1 -1
- package/dist/{oauth-clients-FD7I0J8m.mjs.map → oauth-clients-DJIdOdq0.mjs.map} +1 -1
- package/dist/{oauth-state-store-DkmDOmHs.mjs → oauth-state-store-CsdxP57n.mjs} +1 -1
- package/dist/{oauth-state-store-DkmDOmHs.mjs.map → oauth-state-store-CsdxP57n.mjs.map} +1 -1
- package/dist/{oauth-user-lookup-CvIwGpYd.mjs → oauth-user-lookup-HzzW-dkF.mjs} +1 -1
- package/dist/{oauth-user-lookup-CvIwGpYd.mjs.map → oauth-user-lookup-HzzW-dkF.mjs.map} +1 -1
- package/dist/object-cache/memory.d.mts +1 -1
- package/dist/{options-BHPeIbBd.mjs → options-D1FBiAv1.mjs} +60 -5
- package/dist/options-D1FBiAv1.mjs.map +1 -0
- package/dist/{options-CYb4y7hM.d.mts → options-D8Y0VHc7.d.mts} +9 -3
- package/dist/options-D8Y0VHc7.d.mts.map +1 -0
- package/dist/page/index.d.mts +2 -2
- package/dist/page/index.d.mts.map +1 -1
- package/dist/page/index.mjs +12 -0
- package/dist/page/index.mjs.map +1 -1
- package/dist/{parse-Ckpg-Qfp.mjs → parse-WRg5C3NX.mjs} +2 -2
- package/dist/{parse-Ckpg-Qfp.mjs.map → parse-WRg5C3NX.mjs.map} +1 -1
- package/dist/{passkey-config-O_lj3y0k.mjs → passkey-config-qIdO-wF6.mjs} +1 -1
- package/dist/{passkey-config-O_lj3y0k.mjs.map → passkey-config-qIdO-wF6.mjs.map} +1 -1
- package/dist/{patterns-D9iDO3j8.mjs → patterns-DC8CLptu.mjs} +1 -1
- package/dist/{patterns-D9iDO3j8.mjs.map → patterns-DC8CLptu.mjs.map} +1 -1
- package/dist/{placeholder-4X9BrRrp.d.mts → placeholder-COrvARyD.d.mts} +1 -1
- package/dist/{placeholder-4X9BrRrp.d.mts.map → placeholder-COrvARyD.d.mts.map} +1 -1
- package/dist/plugin-types.d.mts +3 -3
- package/dist/plugin-types.d.mts.map +1 -1
- package/dist/plugin-utils.d.mts +10 -10
- package/dist/plugins/adapt-sandbox-entry.d.mts +10 -10
- package/dist/plugins/adapt-sandbox-entry.mjs +2 -2
- package/dist/{policy-Dhtwntrt.mjs → policy-XCfb-IE9.mjs} +2 -2
- package/dist/{policy-Dhtwntrt.mjs.map → policy-XCfb-IE9.mjs.map} +1 -1
- package/dist/{portable-text-U85hOafW.mjs → portable-text-BS3d5n-0.mjs} +1 -1
- package/dist/{portable-text-U85hOafW.mjs.map → portable-text-BS3d5n-0.mjs.map} +1 -1
- package/dist/{preview-B_vJLvf8.mjs → preview-BxwsGgGp.mjs} +2 -2
- package/dist/{preview-B_vJLvf8.mjs.map → preview-BxwsGgGp.mjs.map} +1 -1
- package/dist/{protocol-JdD2YhY9.d.mts → protocol-CLn58-nw.d.mts} +2 -2
- package/dist/{protocol-JdD2YhY9.d.mts.map → protocol-CLn58-nw.d.mts.map} +1 -1
- package/dist/{public-url-CarhZJgf.mjs → public-url-FWWAvnre.mjs} +1 -1
- package/dist/{public-url-CarhZJgf.mjs.map → public-url-FWWAvnre.mjs.map} +1 -1
- package/dist/{query-BZKZcG5b.mjs → query-DygOte9M.mjs} +25 -16
- package/dist/query-DygOte9M.mjs.map +1 -0
- package/dist/{query-BndaFxxp.mjs → query-gtXT03Wc.mjs} +4 -4
- package/dist/{query-BndaFxxp.mjs.map → query-gtXT03Wc.mjs.map} +1 -1
- package/dist/{rate-limit-BZmATC6W.mjs → rate-limit-CQUPm0dh.mjs} +2 -2
- package/dist/{rate-limit-BZmATC6W.mjs.map → rate-limit-CQUPm0dh.mjs.map} +1 -1
- package/dist/{redirect-CzqnLxK-.mjs → redirect-D1cWafi6.mjs} +1 -1
- package/dist/{redirect-CzqnLxK-.mjs.map → redirect-D1cWafi6.mjs.map} +1 -1
- package/dist/{redirect-CZkbozu9.mjs → redirect-DId44BS1.mjs} +19 -6
- package/dist/redirect-DId44BS1.mjs.map +1 -0
- package/dist/{redirects-CqzNM0KM.mjs → redirects-DN-ZE33W.mjs} +5 -5
- package/dist/{redirects-CqzNM0KM.mjs.map → redirects-DN-ZE33W.mjs.map} +1 -1
- package/dist/{registry-AZAsRsor.mjs → registry-DTqaqxed.mjs} +26 -10
- package/dist/registry-DTqaqxed.mjs.map +1 -0
- package/dist/{relation-04DfKRTO.mjs → relation-DxgCHOBw.mjs} +2 -2
- package/dist/{relation-04DfKRTO.mjs.map → relation-DxgCHOBw.mjs.map} +1 -1
- package/dist/{relations-CcFwDJdJ.mjs → relations-KKDSLUwS.mjs} +4 -4
- package/dist/{relations-CcFwDJdJ.mjs.map → relations-KKDSLUwS.mjs.map} +1 -1
- package/dist/{relations-C4htk5sb.mjs → relations-rOmbndUJ.mjs} +3 -3
- package/dist/{relations-C4htk5sb.mjs.map → relations-rOmbndUJ.mjs.map} +1 -1
- package/dist/{request-cache-DH9zdCOD.mjs → request-cache-DAZZmesc.mjs} +1 -1
- package/dist/{request-cache-DH9zdCOD.mjs.map → request-cache-DAZZmesc.mjs.map} +1 -1
- package/dist/request-context.d.mts +1 -1
- package/dist/{request-meta-DYxLlnmz.mjs → request-meta-BgjUQLQ-.mjs} +2 -2
- package/dist/{request-meta-DYxLlnmz.mjs.map → request-meta-BgjUQLQ-.mjs.map} +1 -1
- package/dist/{resolve-prZ3mP7l.mjs → resolve-Cy0aWSRj.mjs} +37 -4
- package/dist/resolve-Cy0aWSRj.mjs.map +1 -0
- package/dist/{runner-YKfIMnaF.d.mts → runner-CfwysRM0.d.mts} +2 -2
- package/dist/{runner-YKfIMnaF.d.mts.map → runner-CfwysRM0.d.mts.map} +1 -1
- package/dist/{runner-BLIDKpmA.mjs → runner-nEzvnogG.mjs} +419 -295
- package/dist/runner-nEzvnogG.mjs.map +1 -0
- package/dist/runtime.d.mts +11 -11
- package/dist/runtime.mjs +3 -2
- package/dist/runtime.mjs.map +1 -1
- package/dist/{schema-CGnBeLiW.mjs → schema-CRu38Pr5.mjs} +3 -3
- package/dist/{schema-CGnBeLiW.mjs.map → schema-CRu38Pr5.mjs.map} +1 -1
- package/dist/{schema-DYr-Vd-L.mjs → schema-DifxndJx.mjs} +4 -4
- package/dist/{schema-DYr-Vd-L.mjs.map → schema-DifxndJx.mjs.map} +1 -1
- package/dist/{scopes-BhWvBavj.mjs → scopes-D5A1OZbq.mjs} +3 -3
- package/dist/{scopes-BhWvBavj.mjs.map → scopes-D5A1OZbq.mjs.map} +1 -1
- package/dist/{search-C-qDk4kx.mjs → search-DEPFSBFq.mjs} +4 -4
- package/dist/{search-C-qDk4kx.mjs.map → search-DEPFSBFq.mjs.map} +1 -1
- package/dist/{secrets-rEtHt-6z.mjs → secrets-CdfzLdoO.mjs} +3 -3
- package/dist/{secrets-rEtHt-6z.mjs.map → secrets-CdfzLdoO.mjs.map} +1 -1
- package/dist/{sections-B_nYvlwn.mjs → sections-3X52kmIR.mjs} +2 -2
- package/dist/{sections-B_nYvlwn.mjs.map → sections-3X52kmIR.mjs.map} +1 -1
- package/dist/seed/index.d.mts +2 -2
- package/dist/seed/index.mjs +26 -24
- package/dist/seo/index.d.mts +3 -3
- package/dist/seo/index.d.mts.map +1 -1
- package/dist/seo/index.mjs +18 -19
- package/dist/seo/index.mjs.map +1 -1
- package/dist/{seo-926NRIgt.mjs → seo-Bw68KxRc.mjs} +2 -2
- package/dist/{seo-926NRIgt.mjs.map → seo-Bw68KxRc.mjs.map} +1 -1
- package/dist/{seo-CVWkdv6x.mjs → seo-C4AmbsMU.mjs} +3 -2
- package/dist/seo-C4AmbsMU.mjs.map +1 -0
- package/dist/{service-CJl3ZAYs.mjs → service-J_-Vgo7R.mjs} +2 -2
- package/dist/{service-CJl3ZAYs.mjs.map → service-J_-Vgo7R.mjs.map} +1 -1
- package/dist/{session-user-BlMgqCHS.mjs → session-user-CbnMMwk6.mjs} +1 -1
- package/dist/{session-user-BlMgqCHS.mjs.map → session-user-CbnMMwk6.mjs.map} +1 -1
- package/dist/{settings-Cwm6o2jY.mjs → settings-AnEFYICn.mjs} +3 -3
- package/dist/{settings-Cwm6o2jY.mjs.map → settings-AnEFYICn.mjs.map} +1 -1
- package/dist/{settings--wobrkkC.mjs → settings-DcMjREe5.mjs} +6 -6
- package/dist/{settings--wobrkkC.mjs.map → settings-DcMjREe5.mjs.map} +1 -1
- package/dist/{setup-complete-DQbClIN2.mjs → setup-complete-BClXXTvr.mjs} +2 -2
- package/dist/{setup-complete-DQbClIN2.mjs.map → setup-complete-BClXXTvr.mjs.map} +1 -1
- package/dist/{setup-nonce-DZCFS2sn.mjs → setup-nonce-BheRa4RG.mjs} +1 -1
- package/dist/{setup-nonce-DZCFS2sn.mjs.map → setup-nonce-BheRa4RG.mjs.map} +1 -1
- package/dist/{single-flight-cache-BPuGPdcN.mjs → single-flight-cache-jaswDzmQ.mjs} +2 -2
- package/dist/{single-flight-cache-BPuGPdcN.mjs.map → single-flight-cache-jaswDzmQ.mjs.map} +1 -1
- package/dist/{site-url-BrxA_E9H.mjs → site-url-Bqf-ea3N.mjs} +3 -3
- package/dist/{site-url-BrxA_E9H.mjs.map → site-url-Bqf-ea3N.mjs.map} +1 -1
- package/dist/{snapshot--OCDTqdb.mjs → snapshot-C4CtXntb.mjs} +51 -35
- package/dist/snapshot-C4CtXntb.mjs.map +1 -0
- package/dist/{ssrf-5sIM5jzl.mjs → ssrf-gl4gFNhw.mjs} +148 -91
- package/dist/ssrf-gl4gFNhw.mjs.map +1 -0
- package/dist/{state-BpFVsJZB.mjs → state-1F6IOhdQ.mjs} +1 -1
- package/dist/{state-BpFVsJZB.mjs.map → state-1F6IOhdQ.mjs.map} +1 -1
- package/dist/{status-B777-dXz.mjs → status-Cenfk_r5.mjs} +1 -1
- package/dist/{status-B777-dXz.mjs.map → status-Cenfk_r5.mjs.map} +1 -1
- package/dist/storage/local.d.mts +1 -1
- package/dist/storage/local.mjs +1 -1
- package/dist/storage/s3.d.mts +1 -1
- package/dist/storage/s3.mjs +1 -1
- package/dist/{target-BmR0iTwz.mjs → target-CRzeTs8G.mjs} +1 -1
- package/dist/{target-BmR0iTwz.mjs.map → target-CRzeTs8G.mjs.map} +1 -1
- package/dist/{taxonomies-DkAkMupr.mjs → taxonomies-BOdxuZpV.mjs} +11 -4
- package/dist/taxonomies-BOdxuZpV.mjs.map +1 -0
- package/dist/{taxonomies-Wfy_Lg12.mjs → taxonomies-NcFDq5Gg.mjs} +23 -14
- package/dist/taxonomies-NcFDq5Gg.mjs.map +1 -0
- package/dist/{taxonomy-tJepplLL.mjs → taxonomy-DP1vny4K.mjs} +11 -3
- package/dist/{taxonomy-tJepplLL.mjs.map → taxonomy-DP1vny4K.mjs.map} +1 -1
- package/dist/{tokens-BCO1oruF.mjs → tokens-CDk8ox9p.mjs} +1 -1
- package/dist/{tokens-BCO1oruF.mjs.map → tokens-CDk8ox9p.mjs.map} +1 -1
- package/dist/{transport-xh6YKW2G.d.mts → transport-BVn4tVb9.d.mts} +1 -1
- package/dist/{transport-xh6YKW2G.d.mts.map → transport-BVn4tVb9.d.mts.map} +1 -1
- package/dist/{transport-Dr3qtwXC.mjs → transport-DP0JI-8i.mjs} +1 -1
- package/dist/{transport-Dr3qtwXC.mjs.map → transport-DP0JI-8i.mjs.map} +1 -1
- package/dist/{trusted-proxy-BR5F1Otp.mjs → trusted-proxy-BTM6UxqD.mjs} +1 -1
- package/dist/{trusted-proxy-BR5F1Otp.mjs.map → trusted-proxy-BTM6UxqD.mjs.map} +1 -1
- package/dist/{types-CXFkwEGC.d.mts → types-2n848aVW.d.mts} +1 -1
- package/dist/{types-CXFkwEGC.d.mts.map → types-2n848aVW.d.mts.map} +1 -1
- package/dist/{types-75KIqzL9.mjs → types-BMXnRIrX.mjs} +4 -2
- package/dist/types-BMXnRIrX.mjs.map +1 -0
- package/dist/{types-B6GrPic4.d.mts → types-BouXpOsa.d.mts} +115 -4
- package/dist/types-BouXpOsa.d.mts.map +1 -0
- package/dist/{types-3qNFPlci.mjs → types-ByG2coLw.mjs} +1 -1
- package/dist/{types-3qNFPlci.mjs.map → types-ByG2coLw.mjs.map} +1 -1
- package/dist/types-CQPWhPxE.mjs.map +1 -1
- package/dist/{types-CDtkNSFQ.d.mts → types-DEfNJ__A.d.mts} +1 -1
- package/dist/{types-CDtkNSFQ.d.mts.map → types-DEfNJ__A.d.mts.map} +1 -1
- package/dist/{types-xDMtUFnO.d.mts → types-DKcKSbtB.d.mts} +23 -7
- package/dist/types-DKcKSbtB.d.mts.map +1 -0
- package/dist/{types-C00oyCZp.d.mts → types-DRYs7uTL.d.mts} +1 -1
- package/dist/{types-C00oyCZp.d.mts.map → types-DRYs7uTL.d.mts.map} +1 -1
- package/dist/{types-DczELMop.d.mts → types-DaEg7KX2.d.mts} +1 -1
- package/dist/{types-DczELMop.d.mts.map → types-DaEg7KX2.d.mts.map} +1 -1
- package/dist/{types-BuHW4xDE.d.mts → types-LU8utpP_.d.mts} +6 -3
- package/dist/types-LU8utpP_.d.mts.map +1 -0
- package/dist/{types-CPeXo1wF.d.mts → types-VpYfPUxN.d.mts} +1 -1
- package/dist/{types-CPeXo1wF.d.mts.map → types-VpYfPUxN.d.mts.map} +1 -1
- package/dist/{types-DM3vioBY.mjs → types-c9GP7Dj5.mjs} +1 -1
- package/dist/{types-DM3vioBY.mjs.map → types-c9GP7Dj5.mjs.map} +1 -1
- package/dist/{types-FV23hEoW.d.mts → types-tJWDK__M.d.mts} +14 -1
- package/dist/types-tJWDK__M.d.mts.map +1 -0
- package/dist/{upload-attempts-BsqoQ1fn.mjs → upload-attempts-C6S2y-lp.mjs} +1 -1
- package/dist/{upload-attempts-BsqoQ1fn.mjs.map → upload-attempts-C6S2y-lp.mjs.map} +1 -1
- package/dist/{url-pattern-D4c2czpJ.mjs → url-pattern-UYtxVTuj.mjs} +1 -1
- package/dist/{url-pattern-D4c2czpJ.mjs.map → url-pattern-UYtxVTuj.mjs.map} +1 -1
- package/dist/{user-BTZ40aq6.mjs → user-DIsIXogT.mjs} +2 -2
- package/dist/{user-BTZ40aq6.mjs.map → user-DIsIXogT.mjs.map} +1 -1
- package/dist/{utils-BKvNjjhY.mjs → utils-BicP5Qbg.mjs} +2 -2
- package/dist/{utils-BKvNjjhY.mjs.map → utils-BicP5Qbg.mjs.map} +1 -1
- package/dist/{validate-DE_LRwo9.mjs → validate-D8VPn4Hv.mjs} +8 -3
- package/dist/validate-D8VPn4Hv.mjs.map +1 -0
- package/dist/{validate-DUP27OYD.d.mts → validate-Df6Dvwbw.d.mts} +12 -7
- package/dist/validate-Df6Dvwbw.d.mts.map +1 -0
- package/dist/{validation-BMImFJ11.mjs → validation-CzMJn9Ku.mjs} +13 -11
- package/dist/{validation-BMImFJ11.mjs.map → validation-CzMJn9Ku.mjs.map} +1 -1
- package/dist/version-CK67_SXX.mjs +7 -0
- package/dist/{version-Bii3suaO.mjs.map → version-CK67_SXX.mjs.map} +1 -1
- package/dist/{widgets-D3gJ10xU.mjs → widgets-RFVAxQl3.mjs} +5 -5
- package/dist/{widgets-D3gJ10xU.mjs.map → widgets-RFVAxQl3.mjs.map} +1 -1
- package/dist/{wxr-taxonomies-B2Og_6rU.d.mts → wxr-taxonomies-BX4yQL9s.d.mts} +1 -1
- package/dist/{wxr-taxonomies-B2Og_6rU.d.mts.map → wxr-taxonomies-BX4yQL9s.d.mts.map} +1 -1
- package/dist/{wxr-taxonomies-Cxngsjwo.mjs → wxr-taxonomies-Csdp7yde.mjs} +4 -4
- package/dist/{wxr-taxonomies-Cxngsjwo.mjs.map → wxr-taxonomies-Csdp7yde.mjs.map} +1 -1
- package/dist/{zod-generator-BuYSQJB7.mjs → zod-generator-CNRGdnBY.mjs} +3 -3
- package/dist/{zod-generator-BuYSQJB7.mjs.map → zod-generator-CNRGdnBY.mjs.map} +1 -1
- package/package.json +12 -10
- package/src/api/errors.ts +7 -0
- package/src/api/handlers/content.ts +66 -79
- package/src/api/handlers/entry-lock.ts +206 -0
- package/src/api/handlers/manifest.ts +1 -0
- package/src/api/handlers/marketplace.ts +28 -20
- package/src/api/handlers/menus.ts +9 -0
- package/src/api/handlers/registry.ts +13 -8
- package/src/api/handlers/revision.ts +2 -1
- package/src/api/handlers/seo.ts +10 -1
- package/src/api/handlers/snapshot.ts +84 -72
- package/src/api/handlers/taxonomies.ts +9 -0
- package/src/api/openapi/document.ts +111 -6
- package/src/api/schemas/content.ts +8 -0
- package/src/api/schemas/entry-lock.ts +48 -0
- package/src/api/schemas/index.ts +1 -0
- package/src/api/schemas/schema.ts +10 -1
- package/src/api/types.ts +2 -0
- package/src/astro/integration/index.ts +9 -6
- package/src/astro/integration/routes.ts +5 -0
- package/src/astro/integration/runtime.ts +13 -5
- package/src/astro/integration/vite-config.ts +30 -0
- package/src/astro/middleware.ts +16 -0
- package/src/astro/routes/api/content/[collection]/[id]/discard-draft.ts +10 -0
- package/src/astro/routes/api/content/[collection]/[id]/lock.ts +133 -0
- package/src/astro/routes/api/content/[collection]/[id]/publish.ts +11 -1
- package/src/astro/routes/api/content/[collection]/[id]/schedule.ts +20 -0
- package/src/astro/routes/api/content/[collection]/[id]/unpublish.ts +10 -0
- package/src/astro/routes/api/content/[collection]/[id].ts +27 -2
- package/src/astro/routes/api/content/[collection]/index.ts +3 -0
- package/src/astro/routes/sitemap-[collection].xml.ts +4 -0
- package/src/astro/types.ts +13 -3
- package/src/cli/commands/content.ts +31 -5
- package/src/cli/commands/export-seed.ts +2 -0
- package/src/client/index.ts +34 -7
- package/src/components/EmDashBodyEnd.astro +4 -1
- package/src/components/EmDashBodyStart.astro +4 -1
- package/src/components/EmDashHead.astro +35 -16
- package/src/components/Gallery.astro +18 -4
- package/src/components/InlineEditor.astro +3 -1
- package/src/components/InlinePortableTextEditor.tsx +106 -11
- package/src/components/PortableText.astro +4 -0
- package/src/components/Table.astro +147 -62
- package/src/config/errors.ts +13 -0
- package/src/content/converters/portable-text-to-prosemirror.ts +26 -2
- package/src/content/converters/prosemirror-to-portable-text.ts +35 -6
- package/src/content/converters/types.ts +10 -0
- package/src/database/dialect-helpers.ts +125 -0
- package/src/database/migrations/075_entry_edit_locks.ts +44 -0
- package/src/database/migrations/076_collection_nav_group.ts +22 -0
- package/src/database/migrations/077_plugin_storage_revisions.ts +89 -0
- package/src/database/migrations/runner.ts +6 -0
- package/src/database/repositories/content.ts +170 -1
- package/src/database/repositories/entry-locks.ts +257 -0
- package/src/database/repositories/options.ts +69 -5
- package/src/database/repositories/plugin-storage.ts +159 -0
- package/src/database/repositories/redirect.ts +17 -6
- package/src/database/repositories/taxonomy.ts +8 -0
- package/src/database/repositories/types.ts +3 -0
- package/src/database/types.ts +15 -1
- package/src/emdash-runtime.ts +117 -50
- package/src/i18n/resolve.ts +44 -4
- package/src/index.ts +14 -0
- package/src/loader.ts +35 -4
- package/src/mcp/server.ts +23 -5
- package/src/media/responsive.ts +23 -0
- package/src/media/usage/content-refresh.ts +2 -1
- package/src/menus/index.ts +17 -21
- package/src/page/seo-contributions.ts +78 -1
- package/src/page/seo-panel.ts +47 -0
- package/src/plugin-types.ts +9 -0
- package/src/plugins/conditional-storage.ts +30 -0
- package/src/plugins/context.ts +49 -17
- package/src/plugins/hooks.ts +7 -1
- package/src/plugins/index.ts +9 -0
- package/src/plugins/manager.ts +5 -2
- package/src/plugins/sandbox/types.ts +16 -2
- package/src/plugins/storage-query.ts +45 -0
- package/src/plugins/storage-update.ts +96 -0
- package/src/plugins/types.ts +114 -0
- package/src/query.ts +29 -3
- package/src/registry/config.ts +130 -27
- package/src/registry/types.ts +5 -6
- package/src/schema/collection-slugs-cache.ts +157 -0
- package/src/schema/registry.ts +19 -0
- package/src/schema/types.ts +25 -6
- package/src/security/ssrf.ts +167 -141
- package/src/seed/apply.ts +4 -0
- package/src/seed/types.ts +7 -2
- package/src/seed/validate.ts +18 -1
- package/src/seo/hreflang.ts +1 -0
- package/src/seo/index.ts +5 -10
- package/src/seo/media-url.ts +26 -0
- package/src/taxonomies/term-counts.ts +22 -5
- package/dist/api-Dz6rgoa3.mjs.map +0 -1
- package/dist/apply-B4SIOxR1.mjs.map +0 -1
- package/dist/config-it29yDLA.mjs.map +0 -1
- package/dist/content-DjvM0T92.mjs.map +0 -1
- package/dist/context-CX6gxOLW.mjs.map +0 -1
- package/dist/dialect-helpers-BSbfaO3F.mjs.map +0 -1
- package/dist/errors-DsVoDUjJ.mjs.map +0 -1
- package/dist/index-BJNMCWmu.d.mts.map +0 -1
- package/dist/loader-Z8vl7zTq.mjs.map +0 -1
- package/dist/media-url-DHoPr0hq.mjs.map +0 -1
- package/dist/menus-6qSwTNxG.mjs.map +0 -1
- package/dist/options-BHPeIbBd.mjs.map +0 -1
- package/dist/options-CYb4y7hM.d.mts.map +0 -1
- package/dist/query-BZKZcG5b.mjs.map +0 -1
- package/dist/redirect-CZkbozu9.mjs.map +0 -1
- package/dist/redirects-BLNOWQTn.mjs.map +0 -1
- package/dist/registry-AZAsRsor.mjs.map +0 -1
- package/dist/relations-DnRK4YIT.d.mts.map +0 -1
- package/dist/resolve-prZ3mP7l.mjs.map +0 -1
- package/dist/runner-BLIDKpmA.mjs.map +0 -1
- package/dist/seo-CVWkdv6x.mjs.map +0 -1
- package/dist/snapshot--OCDTqdb.mjs.map +0 -1
- package/dist/ssrf-5sIM5jzl.mjs.map +0 -1
- package/dist/taxonomies-DkAkMupr.mjs.map +0 -1
- package/dist/taxonomies-Wfy_Lg12.mjs.map +0 -1
- package/dist/types-75KIqzL9.mjs.map +0 -1
- package/dist/types-B6GrPic4.d.mts.map +0 -1
- package/dist/types-BuHW4xDE.d.mts.map +0 -1
- package/dist/types-FV23hEoW.d.mts.map +0 -1
- package/dist/types-xDMtUFnO.d.mts.map +0 -1
- package/dist/validate-DE_LRwo9.mjs.map +0 -1
- package/dist/validate-DUP27OYD.d.mts.map +0 -1
- package/dist/version-Bii3suaO.mjs +0 -7
- /package/dist/{api-tokens-BfYts-sq.mjs → api-tokens-B_lfpmH3.mjs} +0 -0
- /package/dist/{ssrf-Dg3cIT-b.mjs → ssrf-TQhaljuI.mjs} +0 -0
- /package/dist/{types-DfuTR6dL.mjs → types-A2cN6a4a.mjs} +0 -0
|
@@ -868,6 +868,7 @@ export async function findNonTranslatableSiblingContentIds(
|
|
|
868
868
|
updatedContentId: string,
|
|
869
869
|
translationGroup: string | null | undefined,
|
|
870
870
|
updatedData: Record<string, unknown> | undefined,
|
|
871
|
+
options: { absentAsCleared?: boolean } = {},
|
|
871
872
|
): Promise<string[]> {
|
|
872
873
|
if (!isI18nEnabled() || !updatedData || !translationGroup) return [];
|
|
873
874
|
|
|
@@ -887,7 +888,7 @@ export async function findNonTranslatableSiblingContentIds(
|
|
|
887
888
|
.execute();
|
|
888
889
|
|
|
889
890
|
const touchedNonTranslatableSlugs = fields
|
|
890
|
-
.filter((field) => field.slug in updatedData)
|
|
891
|
+
.filter((field) => options.absentAsCleared || field.slug in updatedData)
|
|
891
892
|
.map((field) => field.slug);
|
|
892
893
|
if (touchedNonTranslatableSlugs.length === 0) return [];
|
|
893
894
|
|
package/src/menus/index.ts
CHANGED
|
@@ -14,7 +14,7 @@ import { sql } from "kysely";
|
|
|
14
14
|
import { menuTag } from "../cache/chrome-tags.js";
|
|
15
15
|
import type { Database } from "../database/types.js";
|
|
16
16
|
import { validateIdentifier } from "../database/validate.js";
|
|
17
|
-
import { resolveLocale, resolveLocaleChain } from "../i18n/resolve.js";
|
|
17
|
+
import { interpolateUrlPattern, resolveLocale, resolveLocaleChain } from "../i18n/resolve.js";
|
|
18
18
|
import { getDb } from "../loader.js";
|
|
19
19
|
import { cachedQuery, CacheNamespace } from "../object-cache/index.js";
|
|
20
20
|
import type { CacheHint } from "../query.js";
|
|
@@ -332,21 +332,10 @@ function resolveMenuItem(
|
|
|
332
332
|
};
|
|
333
333
|
}
|
|
334
334
|
|
|
335
|
-
const SLUG_PLACEHOLDER = /\{slug\}/g;
|
|
336
|
-
const ID_PLACEHOLDER = /\{id\}/g;
|
|
337
|
-
|
|
338
|
-
/**
|
|
339
|
-
* Interpolate a URL pattern with entry data
|
|
340
|
-
*
|
|
341
|
-
* Replaces `{slug}` and `{id}` placeholders.
|
|
342
|
-
*/
|
|
343
|
-
function interpolateUrlPattern(pattern: string, slug: string, id: string): string {
|
|
344
|
-
return pattern.replace(SLUG_PLACEHOLDER, slug).replace(ID_PLACEHOLDER, id);
|
|
345
|
-
}
|
|
346
|
-
|
|
347
335
|
interface ContentReferenceRow {
|
|
348
336
|
id: string;
|
|
349
337
|
slug: string;
|
|
338
|
+
published_at: string | null;
|
|
350
339
|
locale: string;
|
|
351
340
|
translation_group: string;
|
|
352
341
|
}
|
|
@@ -354,6 +343,7 @@ interface ContentReferenceRow {
|
|
|
354
343
|
interface ResolvedContentReference {
|
|
355
344
|
id: string;
|
|
356
345
|
slug: string;
|
|
346
|
+
publishedAt: string | null;
|
|
357
347
|
}
|
|
358
348
|
|
|
359
349
|
type ContentReferenceLookup = Map<string, Map<string, ResolvedContentReference>>;
|
|
@@ -371,7 +361,7 @@ async function resolveContentReferences(
|
|
|
371
361
|
validateIdentifier(collection, "menu item collection");
|
|
372
362
|
for (const batch of chunks([...referenceGroups], SQL_BATCH_SIZE)) {
|
|
373
363
|
const result = await sql<ContentReferenceRow>`
|
|
374
|
-
SELECT id, slug, locale, translation_group
|
|
364
|
+
SELECT id, slug, published_at, locale, translation_group
|
|
375
365
|
FROM ${sql.ref(`ec_${collection}`)}
|
|
376
366
|
WHERE translation_group IN (${sql.join(batch)})
|
|
377
367
|
`.execute(db);
|
|
@@ -383,16 +373,18 @@ async function resolveContentReferences(
|
|
|
383
373
|
}
|
|
384
374
|
}
|
|
385
375
|
for (const [referenceGroup, row] of localized) {
|
|
386
|
-
lookup.set(referenceGroup, { id: row.id, slug: row.slug });
|
|
376
|
+
lookup.set(referenceGroup, { id: row.id, slug: row.slug, publishedAt: row.published_at });
|
|
387
377
|
}
|
|
388
378
|
|
|
389
379
|
const unresolved = [...referenceGroups].filter((id) => !lookup.has(id));
|
|
390
380
|
for (const batch of chunks(unresolved, SQL_BATCH_SIZE)) {
|
|
391
|
-
const result = await sql<
|
|
392
|
-
SELECT id, slug FROM ${sql.ref(`ec_${collection}`)}
|
|
381
|
+
const result = await sql<Pick<ContentReferenceRow, "id" | "slug" | "published_at">>`
|
|
382
|
+
SELECT id, slug, published_at FROM ${sql.ref(`ec_${collection}`)}
|
|
393
383
|
WHERE id IN (${sql.join(batch)})
|
|
394
384
|
`.execute(db);
|
|
395
|
-
for (const row of result.rows)
|
|
385
|
+
for (const row of result.rows) {
|
|
386
|
+
lookup.set(row.id, { id: row.id, slug: row.slug, publishedAt: row.published_at });
|
|
387
|
+
}
|
|
396
388
|
}
|
|
397
389
|
} catch (error) {
|
|
398
390
|
console.error(`Failed to resolve content URLs for ${collection}:`, error);
|
|
@@ -437,9 +429,13 @@ function resolveContentUrl(
|
|
|
437
429
|
if (!referenceGroup) return null;
|
|
438
430
|
const row = contentLookup.get(collection)?.get(referenceGroup);
|
|
439
431
|
if (!row) return null;
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
432
|
+
return interpolateUrlPattern({
|
|
433
|
+
pattern: urlPatterns.get(collection) ?? null,
|
|
434
|
+
collection,
|
|
435
|
+
slug: row.slug,
|
|
436
|
+
id: row.id,
|
|
437
|
+
date: row.publishedAt,
|
|
438
|
+
});
|
|
443
439
|
}
|
|
444
440
|
|
|
445
441
|
interface TaxonomyReferenceRow {
|
|
@@ -5,15 +5,22 @@
|
|
|
5
5
|
* `[...plugin, ...site, ...base]` and feeds it to `resolvePageMetadata()`,
|
|
6
6
|
* which is first-wins. That ordering means plugin contributions override
|
|
7
7
|
* site-level ones override base ones for any given key — base values are
|
|
8
|
-
* the fallback, not the source of truth.
|
|
8
|
+
* the fallback, not the source of truth. For content pages, the entry's
|
|
9
|
+
* SEO panel values are overlaid onto the page context before the base
|
|
10
|
+
* contributions (and JSON-LD) are generated, so editor-set values
|
|
11
|
+
* override the template-provided fields.
|
|
9
12
|
*
|
|
10
13
|
* This replaces the per-template SEO.astro components, eliminating
|
|
11
14
|
* the class of XSS bugs where templates hand-rolled JSON-LD serialization.
|
|
12
15
|
*/
|
|
13
16
|
|
|
17
|
+
import type { ContentSeo } from "../database/repositories/types.js";
|
|
14
18
|
import type { PageMetadataContribution, PublicPageContext } from "../plugins/types.js";
|
|
19
|
+
import { buildSeoImageUrl, resolveSeoCanonicalUrl } from "../seo/media-url.js";
|
|
20
|
+
import { getSiteSettings } from "../settings/index.js";
|
|
15
21
|
import type { SeoSettings } from "../settings/types.js";
|
|
16
22
|
import { buildBlogPostingJsonLd, buildWebSiteJsonLd } from "./jsonld.js";
|
|
23
|
+
import { peekSeoPanel } from "./seo-panel.js";
|
|
17
24
|
|
|
18
25
|
/**
|
|
19
26
|
* Generate base metadata contributions from a page context's SEO data.
|
|
@@ -147,6 +154,76 @@ export function generateBaseSeoContributions(
|
|
|
147
154
|
return contributions;
|
|
148
155
|
}
|
|
149
156
|
|
|
157
|
+
/**
|
|
158
|
+
* Resolve the page context for rendering: overlay the entry's SEO panel
|
|
159
|
+
* values when they were primed for this request.
|
|
160
|
+
*
|
|
161
|
+
* Used by `<EmDashHead>`, `<EmDashBodyStart>`, and `<EmDashBodyEnd>` so
|
|
162
|
+
* head tags, JSON-LD, and every plugin hook — head and body fragments
|
|
163
|
+
* alike — see the same overlaid context. Returns the context unchanged
|
|
164
|
+
* for non-content pages or when nothing was primed. The peek is a
|
|
165
|
+
* request-cache read; site settings are only consulted when a panel
|
|
166
|
+
* exists (and are request-cached themselves), so this adds no queries.
|
|
167
|
+
*/
|
|
168
|
+
export async function resolveSeoPanelPage(
|
|
169
|
+
page: PublicPageContext,
|
|
170
|
+
siteUrl?: string,
|
|
171
|
+
): Promise<PublicPageContext> {
|
|
172
|
+
if (!page.content) return page;
|
|
173
|
+
const seo = await peekSeoPanel(page.content.collection, page.content.id);
|
|
174
|
+
if (!seo) return page;
|
|
175
|
+
const resolvedSiteUrl =
|
|
176
|
+
siteUrl ||
|
|
177
|
+
page.siteUrl ||
|
|
178
|
+
(await getSiteSettings()).url ||
|
|
179
|
+
(URL.canParse(page.url) ? new URL(page.url).origin : "");
|
|
180
|
+
return applySeoPanelToPageContext(page, seo, { siteUrl: resolvedSiteUrl });
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Overlay a content entry's SEO panel data onto the page context.
|
|
185
|
+
*
|
|
186
|
+
* `<EmDashHead>` applies this overlay before anything consumes the context:
|
|
187
|
+
* editor-set panel values override whatever the template passed in, and
|
|
188
|
+
* because the overlaid context feeds plugin hooks, the base contributions,
|
|
189
|
+
* and the JSON-LD builders alike, structured data and head tags always
|
|
190
|
+
* agree. Plugins still override the rendered output via first-wins dedup.
|
|
191
|
+
*
|
|
192
|
+
* The `<title>` element itself stays the template's responsibility —
|
|
193
|
+
* head components can't replace it — so `seo.title` feeds
|
|
194
|
+
* `og:title` / `twitter:title` / the JSON-LD headline only. Templates that
|
|
195
|
+
* want the panel title in `<title>` keep using `getSeoMeta()`.
|
|
196
|
+
*
|
|
197
|
+
* Unset panel fields fall back to the template-provided values, so pages
|
|
198
|
+
* without SEO data are unaffected.
|
|
199
|
+
*/
|
|
200
|
+
export function applySeoPanelToPageContext(
|
|
201
|
+
page: PublicPageContext,
|
|
202
|
+
seo: ContentSeo,
|
|
203
|
+
options: { siteUrl?: string | null } = {},
|
|
204
|
+
): PublicPageContext {
|
|
205
|
+
const siteUrl = options.siteUrl ?? undefined;
|
|
206
|
+
const image = seo.image ? buildSeoImageUrl(seo.image, siteUrl) : null;
|
|
207
|
+
const canonical = seo.canonical ? resolveSeoCanonicalUrl(seo.canonical, siteUrl) : null;
|
|
208
|
+
|
|
209
|
+
return {
|
|
210
|
+
...page,
|
|
211
|
+
description: seo.description || page.description,
|
|
212
|
+
canonical: canonical || page.canonical,
|
|
213
|
+
// Mirror the resolved image into the top-level field too, so consumers
|
|
214
|
+
// reading page.image (e.g. page:metadata hooks) agree with og:image and
|
|
215
|
+
// the JSON-LD graph.
|
|
216
|
+
image: image || page.image,
|
|
217
|
+
seo: {
|
|
218
|
+
...page.seo,
|
|
219
|
+
ogTitle: seo.title || page.seo?.ogTitle,
|
|
220
|
+
ogDescription: seo.description || page.seo?.ogDescription,
|
|
221
|
+
ogImage: image || page.seo?.ogImage,
|
|
222
|
+
robots: seo.noIndex ? "noindex, nofollow" : page.seo?.robots,
|
|
223
|
+
},
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
|
|
150
227
|
/**
|
|
151
228
|
* Generate site-level SEO metadata contributions from SiteSettings.seo.
|
|
152
229
|
*
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Request-scoped hand-off of SEO panel data from the entry query to the
|
|
3
|
+
* render components.
|
|
4
|
+
*
|
|
5
|
+
* The loader's single-entry path already folds the `_emdash_seo` row into
|
|
6
|
+
* the entry query as a JSON subselect, so the panel data is in hand when an
|
|
7
|
+
* entry is fetched — it primes this cache, and `<EmDashHead>` (plus the body
|
|
8
|
+
* fragment components) pick the data up with a plain map read. No code path
|
|
9
|
+
* here ever queries the database.
|
|
10
|
+
*
|
|
11
|
+
* Kept as a leaf module (request-cache only) so the loader and the query
|
|
12
|
+
* layer can prime without importing the page-context machinery, which pulls
|
|
13
|
+
* in site settings and would create an import cycle back into the loader.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import type { ContentSeo } from "../database/repositories/types.js";
|
|
17
|
+
import { peekRequestCache, setRequestCacheEntry } from "../request-cache.js";
|
|
18
|
+
|
|
19
|
+
function seoPanelCacheKey(collection: string, id: string): string {
|
|
20
|
+
return `seo-panel:${collection}:${id}`;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Prime the request-scoped SEO panel cache for a content entry.
|
|
25
|
+
*
|
|
26
|
+
* Called wherever an entry's folded SEO data materializes: the loader's
|
|
27
|
+
* single-entry path (fresh query) and the object-cache revive path in
|
|
28
|
+
* `getEmDashEntry` (warm hit, where the loader never runs). No-ops outside
|
|
29
|
+
* a request context; never overwrites an already-primed value.
|
|
30
|
+
*/
|
|
31
|
+
export function primeSeoPanel(collection: string, id: string, seo: ContentSeo): void {
|
|
32
|
+
setRequestCacheEntry(seoPanelCacheKey(collection, id), seo);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Read the SEO panel data primed for a content entry in this request.
|
|
37
|
+
*
|
|
38
|
+
* Returns `null` when nothing was primed — either the entry has no SEO
|
|
39
|
+
* row, or it was not fetched through an EmDash loader in this request
|
|
40
|
+
* (e.g. prerendered pages, or a hand-rolled query). Callers treat null as
|
|
41
|
+
* "no overlay"; this never falls back to a database lookup, so the
|
|
42
|
+
* logged-out hot path gains zero queries.
|
|
43
|
+
*/
|
|
44
|
+
export async function peekSeoPanel(collection: string, id: string): Promise<ContentSeo | null> {
|
|
45
|
+
const primed = peekRequestCache<ContentSeo>(seoPanelCacheKey(collection, id));
|
|
46
|
+
return primed ? await primed : null;
|
|
47
|
+
}
|
package/src/plugin-types.ts
CHANGED
|
@@ -43,6 +43,7 @@ import type { ZodType } from "zod";
|
|
|
43
43
|
|
|
44
44
|
import type { SandboxHookErrorEnvelope } from "./plugins/sandbox/hook-result.js";
|
|
45
45
|
import type {
|
|
46
|
+
ActorInfo,
|
|
46
47
|
CommentAfterCreateEvent,
|
|
47
48
|
CommentAfterCreateHandler,
|
|
48
49
|
CommentAfterModerateEvent,
|
|
@@ -262,6 +263,7 @@ export interface SandboxedContentBeforeSaveConfig extends Omit<
|
|
|
262
263
|
}
|
|
263
264
|
|
|
264
265
|
export type { SandboxHookErrorEnvelope };
|
|
266
|
+
export type { NumericDelta, UpdateIfArgs, UpdateIfResult } from "./plugins/types.js";
|
|
265
267
|
|
|
266
268
|
/**
|
|
267
269
|
* Re-export of event types so plugin authors can reference them
|
|
@@ -272,6 +274,7 @@ export type { SandboxHookErrorEnvelope };
|
|
|
272
274
|
* portable `.d.mts`.
|
|
273
275
|
*/
|
|
274
276
|
export type {
|
|
277
|
+
ActorInfo,
|
|
275
278
|
CommentAfterCreateEvent,
|
|
276
279
|
CommentAfterModerateEvent,
|
|
277
280
|
CommentBeforeCreateEvent,
|
|
@@ -294,3 +297,9 @@ export type {
|
|
|
294
297
|
PluginContext,
|
|
295
298
|
UninstallEvent,
|
|
296
299
|
};
|
|
300
|
+
|
|
301
|
+
export type {
|
|
302
|
+
VersionedValue,
|
|
303
|
+
ConditionalWriteResult,
|
|
304
|
+
ConditionalDeleteResult,
|
|
305
|
+
} from "./plugins/types.js";
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
const MAX_KEY_LENGTH = 1024;
|
|
2
|
+
const MAX_REVISION_LENGTH = 128;
|
|
3
|
+
const MAX_VALUE_BYTES = 1024 * 1024;
|
|
4
|
+
|
|
5
|
+
export function assertStorageKey(key: unknown, maxLength = MAX_KEY_LENGTH): asserts key is string {
|
|
6
|
+
if (typeof key !== "string" || key.length === 0 || key.length > maxLength) {
|
|
7
|
+
throw new TypeError(`Storage key must be a nonempty string of at most ${maxLength} characters`);
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function assertStorageRevision(revision: unknown): asserts revision is string {
|
|
12
|
+
if (
|
|
13
|
+
typeof revision !== "string" ||
|
|
14
|
+
revision.length === 0 ||
|
|
15
|
+
revision.length > MAX_REVISION_LENGTH
|
|
16
|
+
) {
|
|
17
|
+
throw new TypeError("Storage revision must be a nonempty string of at most 128 characters");
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function serializeConditionalValue(value: unknown): string {
|
|
22
|
+
const serialized = JSON.stringify(value);
|
|
23
|
+
if (serialized === undefined) {
|
|
24
|
+
throw new TypeError("Storage value must be JSON serializable");
|
|
25
|
+
}
|
|
26
|
+
if (new TextEncoder().encode(serialized).byteLength > MAX_VALUE_BYTES) {
|
|
27
|
+
throw new TypeError("Conditional storage value must not exceed 1 MiB of JSON");
|
|
28
|
+
}
|
|
29
|
+
return serialized;
|
|
30
|
+
}
|
package/src/plugins/context.ts
CHANGED
|
@@ -9,6 +9,7 @@ import type { Kysely } from "kysely";
|
|
|
9
9
|
import { ulid } from "ulidx";
|
|
10
10
|
|
|
11
11
|
import { ContentRepository } from "../database/repositories/content.js";
|
|
12
|
+
import { EntryLockRepository } from "../database/repositories/entry-locks.js";
|
|
12
13
|
import { MediaRepository } from "../database/repositories/media.js";
|
|
13
14
|
import { OptionsRepository } from "../database/repositories/options.js";
|
|
14
15
|
import { PluginStorageRepository } from "../database/repositories/plugin-storage.js";
|
|
@@ -27,6 +28,7 @@ import { enrichImageMetadata } from "../media/enrich.js";
|
|
|
27
28
|
import { markContentMediaUsageCollectionStaleSafely } from "../media/usage/content-refresh.js";
|
|
28
29
|
import { invalidateSiteSettingsCache } from "../settings/index.js";
|
|
29
30
|
import type { Storage } from "../storage/types.js";
|
|
31
|
+
import { assertStorageKey } from "./conditional-storage.js";
|
|
30
32
|
import { CronAccessImpl } from "./cron.js";
|
|
31
33
|
import type { EmailPipeline } from "./email.js";
|
|
32
34
|
import type {
|
|
@@ -76,6 +78,18 @@ export function createKVAccess(optionsRepo: OptionsRepository, pluginId: string)
|
|
|
76
78
|
async get<T>(key: string): Promise<T | null> {
|
|
77
79
|
return optionsRepo.get<T>(`${prefix}${key}`);
|
|
78
80
|
},
|
|
81
|
+
async getVersioned<T>(key: string) {
|
|
82
|
+
assertStorageKey(key);
|
|
83
|
+
return optionsRepo.getVersioned<T>(`${prefix}${key}`);
|
|
84
|
+
},
|
|
85
|
+
async compareAndSet(key, expectedRevision, value) {
|
|
86
|
+
assertStorageKey(key);
|
|
87
|
+
return optionsRepo.compareAndSet(`${prefix}${key}`, expectedRevision, value);
|
|
88
|
+
},
|
|
89
|
+
async compareAndDelete(key, expectedRevision) {
|
|
90
|
+
assertStorageKey(key);
|
|
91
|
+
return optionsRepo.compareAndDelete(`${prefix}${key}`, expectedRevision);
|
|
92
|
+
},
|
|
79
93
|
|
|
80
94
|
async set(key: string, value: unknown): Promise<void> {
|
|
81
95
|
await optionsRepo.set(`${prefix}${key}`, value);
|
|
@@ -118,6 +132,9 @@ function createStorageCollection<T>(
|
|
|
118
132
|
|
|
119
133
|
return {
|
|
120
134
|
get: (id) => repo.get(id),
|
|
135
|
+
getVersioned: (id) => repo.getVersioned(id),
|
|
136
|
+
compareAndSet: (id, expectedRevision, data) => repo.compareAndSet(id, expectedRevision, data),
|
|
137
|
+
compareAndDelete: (id, expectedRevision) => repo.compareAndDelete(id, expectedRevision),
|
|
121
138
|
put: (id, data) => repo.put(id, data),
|
|
122
139
|
delete: (id) => repo.delete(id),
|
|
123
140
|
exists: (id) => repo.exists(id),
|
|
@@ -125,6 +142,7 @@ function createStorageCollection<T>(
|
|
|
125
142
|
putMany: (items) => repo.putMany(items),
|
|
126
143
|
deleteMany: (ids) => repo.deleteMany(ids),
|
|
127
144
|
count: (where) => repo.count(where),
|
|
145
|
+
updateIf: (id, updateArgs) => repo.updateIf(id, updateArgs),
|
|
128
146
|
|
|
129
147
|
// Query returns PaginatedResult instead of the old format
|
|
130
148
|
async query(options?: QueryOptions): Promise<PaginatedResult<{ id: string; data: T }>> {
|
|
@@ -500,6 +518,9 @@ export function createContentAccessWithWrite(
|
|
|
500
518
|
const contentRepo = new ContentRepository(db);
|
|
501
519
|
const deleted = await contentRepo.delete(collection, id);
|
|
502
520
|
if (deleted) {
|
|
521
|
+
// A trashed entry can no longer be opened, so its holder can never
|
|
522
|
+
// release the lease itself. Mirrors handleContentDelete.
|
|
523
|
+
await new EntryLockRepository(db).releaseEntry(collection, id);
|
|
503
524
|
await markContentMediaUsageCollectionStaleSafely(db, collection, "CONTENT_USAGE_STALE");
|
|
504
525
|
}
|
|
505
526
|
return deleted;
|
|
@@ -706,11 +727,31 @@ function isHostAllowed(host: string, allowedHosts: string[]): boolean {
|
|
|
706
727
|
});
|
|
707
728
|
}
|
|
708
729
|
|
|
730
|
+
function tryParsePluginHttpTarget(url: string): URL | null {
|
|
731
|
+
try {
|
|
732
|
+
return new URL(url);
|
|
733
|
+
} catch {
|
|
734
|
+
return null;
|
|
735
|
+
}
|
|
736
|
+
}
|
|
737
|
+
|
|
738
|
+
async function validatePluginHttpTarget(pluginId: string, url: string): Promise<URL> {
|
|
739
|
+
try {
|
|
740
|
+
return await resolveAndValidateExternalUrl(url);
|
|
741
|
+
} catch (error) {
|
|
742
|
+
const message = error instanceof SsrfError ? error.message : "SSRF validation failed";
|
|
743
|
+
const target = tryParsePluginHttpTarget(url);
|
|
744
|
+
throw new Error(
|
|
745
|
+
`Plugin "${pluginId}": blocked fetch to "${target ? target.hostname : "invalid URL"}": ${message}`,
|
|
746
|
+
{ cause: error },
|
|
747
|
+
);
|
|
748
|
+
}
|
|
749
|
+
}
|
|
750
|
+
|
|
709
751
|
/**
|
|
710
|
-
* Create HTTP access with host validation.
|
|
752
|
+
* Create HTTP access with host validation and SSRF protection.
|
|
711
753
|
*
|
|
712
|
-
* Uses redirect: "manual" to re-validate each redirect target
|
|
713
|
-
* the allowedHosts list, preventing redirects to unauthorized hosts.
|
|
754
|
+
* Uses redirect: "manual" to re-validate each redirect target before dispatch.
|
|
714
755
|
*/
|
|
715
756
|
export function createHttpAccess(pluginId: string, allowedHosts: string[]): HttpAccess {
|
|
716
757
|
return {
|
|
@@ -727,13 +768,14 @@ export function createHttpAccess(pluginId: string, allowedHosts: string[]): Http
|
|
|
727
768
|
let currentInit = init;
|
|
728
769
|
|
|
729
770
|
for (let i = 0; i <= MAX_PLUGIN_REDIRECTS; i++) {
|
|
730
|
-
const
|
|
731
|
-
if (!isHostAllowed(hostname, allowedHosts)) {
|
|
771
|
+
const target = tryParsePluginHttpTarget(currentUrl);
|
|
772
|
+
if (target && !isHostAllowed(target.hostname, allowedHosts)) {
|
|
732
773
|
throw new Error(
|
|
733
|
-
`Plugin "${pluginId}" is not allowed to fetch from host "${hostname}". ` +
|
|
774
|
+
`Plugin "${pluginId}" is not allowed to fetch from host "${target.hostname}". ` +
|
|
734
775
|
`Allowed hosts: ${allowedHosts.join(", ")}`,
|
|
735
776
|
);
|
|
736
777
|
}
|
|
778
|
+
await validatePluginHttpTarget(pluginId, currentUrl);
|
|
737
779
|
|
|
738
780
|
const response = await globalThis.fetch(currentUrl, {
|
|
739
781
|
...currentInit,
|
|
@@ -778,17 +820,7 @@ export function createUnrestrictedHttpAccess(pluginId: string): HttpAccess {
|
|
|
778
820
|
let currentInit = init;
|
|
779
821
|
|
|
780
822
|
for (let i = 0; i <= MAX_PLUGIN_REDIRECTS; i++) {
|
|
781
|
-
|
|
782
|
-
// endpoints, wildcard DNS, resolved-IP private ranges).
|
|
783
|
-
try {
|
|
784
|
-
await resolveAndValidateExternalUrl(currentUrl);
|
|
785
|
-
} catch (e) {
|
|
786
|
-
const msg = e instanceof SsrfError ? e.message : "SSRF validation failed";
|
|
787
|
-
throw new Error(
|
|
788
|
-
`Plugin "${pluginId}": blocked fetch to "${new URL(currentUrl).hostname}": ${msg}`,
|
|
789
|
-
{ cause: e },
|
|
790
|
-
);
|
|
791
|
-
}
|
|
823
|
+
await validatePluginHttpTarget(pluginId, currentUrl);
|
|
792
824
|
|
|
793
825
|
const response = await globalThis.fetch(currentUrl, {
|
|
794
826
|
...currentInit,
|
package/src/plugins/hooks.ts
CHANGED
|
@@ -15,6 +15,7 @@ import type {
|
|
|
15
15
|
ResolvedPlugin,
|
|
16
16
|
ResolvedHook,
|
|
17
17
|
PluginContext,
|
|
18
|
+
ActorInfo,
|
|
18
19
|
ContentHookEvent,
|
|
19
20
|
ContentDeleteEvent,
|
|
20
21
|
ContentStateChangeEvent,
|
|
@@ -488,13 +489,15 @@ export class HookPipeline {
|
|
|
488
489
|
/**
|
|
489
490
|
* Run content:beforeSave hooks
|
|
490
491
|
* Returns modified content from the pipeline. `id` is the existing item's
|
|
491
|
-
* ID when updating.
|
|
492
|
+
* ID when updating. `actor` is the authenticated user that triggered the
|
|
493
|
+
* save, when one is available.
|
|
492
494
|
*/
|
|
493
495
|
async runContentBeforeSave(
|
|
494
496
|
content: Record<string, unknown>,
|
|
495
497
|
collection: string,
|
|
496
498
|
isNew: boolean,
|
|
497
499
|
id?: string,
|
|
500
|
+
actor?: ActorInfo,
|
|
498
501
|
): Promise<{
|
|
499
502
|
content: Record<string, unknown>;
|
|
500
503
|
results: HookResult<Record<string, unknown>>[];
|
|
@@ -511,6 +514,7 @@ export class HookPipeline {
|
|
|
511
514
|
isNew,
|
|
512
515
|
};
|
|
513
516
|
if (id !== undefined) event.id = id;
|
|
517
|
+
if (actor !== undefined) event.actor = { ...actor };
|
|
514
518
|
const ctx = this.getContext(hook.pluginId);
|
|
515
519
|
const start = Date.now();
|
|
516
520
|
|
|
@@ -550,6 +554,7 @@ export class HookPipeline {
|
|
|
550
554
|
content: Record<string, unknown>,
|
|
551
555
|
collection: string,
|
|
552
556
|
isNew: boolean,
|
|
557
|
+
actor?: ActorInfo,
|
|
553
558
|
): Promise<HookResult<void>[]> {
|
|
554
559
|
const hooks = this.getTypedHooks("content:afterSave");
|
|
555
560
|
const results: HookResult<void>[] = [];
|
|
@@ -557,6 +562,7 @@ export class HookPipeline {
|
|
|
557
562
|
for (const hook of hooks) {
|
|
558
563
|
const { handler } = hook;
|
|
559
564
|
const event: ContentHookEvent = { content, collection, isNew };
|
|
565
|
+
if (actor !== undefined) event.actor = { ...actor };
|
|
560
566
|
const ctx = this.getContext(hook.pluginId);
|
|
561
567
|
const start = Date.now();
|
|
562
568
|
|
package/src/plugins/index.ts
CHANGED
|
@@ -101,6 +101,8 @@ export type {
|
|
|
101
101
|
SandboxSaveRejectedError,
|
|
102
102
|
} from "./sandbox/index.js";
|
|
103
103
|
|
|
104
|
+
export { StorageSerializationError } from "./storage-query.js";
|
|
105
|
+
|
|
104
106
|
// Types
|
|
105
107
|
export type {
|
|
106
108
|
// Core types
|
|
@@ -118,6 +120,12 @@ export type {
|
|
|
118
120
|
// Context APIs
|
|
119
121
|
PluginContext,
|
|
120
122
|
StorageCollection,
|
|
123
|
+
NumericDelta,
|
|
124
|
+
UpdateIfArgs,
|
|
125
|
+
UpdateIfResult,
|
|
126
|
+
VersionedValue,
|
|
127
|
+
ConditionalWriteResult,
|
|
128
|
+
ConditionalDeleteResult,
|
|
121
129
|
KVAccess,
|
|
122
130
|
ContentAccess,
|
|
123
131
|
ContentAccessWithWrite,
|
|
@@ -145,6 +153,7 @@ export type {
|
|
|
145
153
|
HookName,
|
|
146
154
|
ResolvedHook,
|
|
147
155
|
ResolvedPluginHooks,
|
|
156
|
+
ActorInfo,
|
|
148
157
|
ContentHookEvent,
|
|
149
158
|
ContentDeleteEvent,
|
|
150
159
|
ContentPublishStateChangeEvent,
|
package/src/plugins/manager.ts
CHANGED
|
@@ -26,6 +26,7 @@ import {
|
|
|
26
26
|
} from "./hooks.js";
|
|
27
27
|
import { PluginRouteRegistry, type RouteResult, type InvokeRouteOptions } from "./routes.js";
|
|
28
28
|
import type {
|
|
29
|
+
ActorInfo,
|
|
29
30
|
PluginDefinition,
|
|
30
31
|
ResolvedPlugin,
|
|
31
32
|
PluginStorageConfig,
|
|
@@ -306,12 +307,13 @@ export class PluginManager {
|
|
|
306
307
|
collection: string,
|
|
307
308
|
isNew: boolean,
|
|
308
309
|
id?: string,
|
|
310
|
+
actor?: ActorInfo,
|
|
309
311
|
): Promise<{
|
|
310
312
|
content: Record<string, unknown>;
|
|
311
313
|
results: HookResult<Record<string, unknown>>[];
|
|
312
314
|
}> {
|
|
313
315
|
this.ensureInitialized();
|
|
314
|
-
return this.hookPipeline!.runContentBeforeSave(content, collection, isNew, id);
|
|
316
|
+
return this.hookPipeline!.runContentBeforeSave(content, collection, isNew, id, actor);
|
|
315
317
|
}
|
|
316
318
|
|
|
317
319
|
/**
|
|
@@ -321,9 +323,10 @@ export class PluginManager {
|
|
|
321
323
|
content: Record<string, unknown>,
|
|
322
324
|
collection: string,
|
|
323
325
|
isNew: boolean,
|
|
326
|
+
actor?: ActorInfo,
|
|
324
327
|
): Promise<HookResult<void>[]> {
|
|
325
328
|
this.ensureInitialized();
|
|
326
|
-
return this.hookPipeline!.runContentAfterSave(content, collection, isNew);
|
|
329
|
+
return this.hookPipeline!.runContentAfterSave(content, collection, isNew, actor);
|
|
327
330
|
}
|
|
328
331
|
|
|
329
332
|
/**
|
|
@@ -236,6 +236,15 @@ export interface SandboxRunner {
|
|
|
236
236
|
*/
|
|
237
237
|
isHealthy(): boolean;
|
|
238
238
|
|
|
239
|
+
/**
|
|
240
|
+
* Why the runner cannot run plugins, once isAvailable() or isHealthy()
|
|
241
|
+
* has returned false. A lowercase clause without a final period: callers
|
|
242
|
+
* append it to their own message after a colon.
|
|
243
|
+
*
|
|
244
|
+
* Making this required breaks runners implemented outside this repository.
|
|
245
|
+
*/
|
|
246
|
+
unavailableReason?(): string;
|
|
247
|
+
|
|
239
248
|
/**
|
|
240
249
|
* Load a sandboxed plugin from code.
|
|
241
250
|
*
|
|
@@ -260,6 +269,11 @@ export interface SandboxRunner {
|
|
|
260
269
|
terminateAll(): Promise<void>;
|
|
261
270
|
}
|
|
262
271
|
|
|
272
|
+
export function withUnavailableReason(message: string, runner: SandboxRunner | null): string {
|
|
273
|
+
const reason = runner?.unavailableReason?.();
|
|
274
|
+
return reason ? `${message}: ${reason}` : message;
|
|
275
|
+
}
|
|
276
|
+
|
|
263
277
|
/**
|
|
264
278
|
* Error thrown when the sandbox runtime is unavailable.
|
|
265
279
|
* This happens when the sidecar process has crashed or hasn't started.
|
|
@@ -273,11 +287,11 @@ export class SandboxUnavailableError extends Error {
|
|
|
273
287
|
|
|
274
288
|
/**
|
|
275
289
|
* Factory function type for creating sandbox runners.
|
|
276
|
-
* Exported by platform adapters (e.g., @emdash-cms/
|
|
290
|
+
* Exported by platform adapters (e.g., @emdash-cms/cloudflare/sandbox).
|
|
277
291
|
*
|
|
278
292
|
* @example
|
|
279
293
|
* ```typescript
|
|
280
|
-
* // In @emdash-cms/
|
|
294
|
+
* // In @emdash-cms/cloudflare/sandbox
|
|
281
295
|
* export const createSandboxRunner: SandboxRunnerFactory = (options) => {
|
|
282
296
|
* return new CloudflareSandboxRunner(options);
|
|
283
297
|
* };
|
|
@@ -25,6 +25,38 @@ export class StorageQueryError extends Error {
|
|
|
25
25
|
}
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
+
/**
|
|
29
|
+
* Error thrown when a guarded `updateIf` loses a concurrent race by aborting
|
|
30
|
+
* rather than resolving to `{ applied: false }`.
|
|
31
|
+
*
|
|
32
|
+
* `updateIf`'s `{ applied: false }` contract (row absent OR guard failed)
|
|
33
|
+
* assumes READ COMMITTED — the default. There, a losing concurrent writer
|
|
34
|
+
* re-evaluates the guard against the winner's freshly committed row and
|
|
35
|
+
* cleanly resolves to `{ applied: false }`. Two aborts escape that contract:
|
|
36
|
+
*
|
|
37
|
+
* - `40001` (serialization_failure), only above READ COMMITTED, where the
|
|
38
|
+
* loser cannot re-read against a newer snapshot.
|
|
39
|
+
* - `40P01` (deadlock_detected), at any isolation level, when transactions
|
|
40
|
+
* take row locks in opposite order.
|
|
41
|
+
*
|
|
42
|
+
* This error surfaces either abort so the caller can retry the write.
|
|
43
|
+
*
|
|
44
|
+
* The no-oversell SAFETY invariant holds either way: a losing writer NEVER
|
|
45
|
+
* applies its update — it either sees `{ applied: false }` or throws here.
|
|
46
|
+
*/
|
|
47
|
+
export class StorageSerializationError extends Error {
|
|
48
|
+
readonly code = "STORAGE_SERIALIZATION_FAILURE";
|
|
49
|
+
readonly retryable = true;
|
|
50
|
+
/** The Postgres SQLSTATE that triggered this error (`40001` / `40P01`). */
|
|
51
|
+
readonly sqlState?: string;
|
|
52
|
+
|
|
53
|
+
constructor(message: string, options?: { cause?: unknown; sqlState?: string }) {
|
|
54
|
+
super(message, { cause: options?.cause });
|
|
55
|
+
this.name = "StorageSerializationError";
|
|
56
|
+
this.sqlState = options?.sqlState;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
28
60
|
/**
|
|
29
61
|
* Check if a value is a range filter
|
|
30
62
|
*/
|
|
@@ -213,6 +245,17 @@ export function buildCondition(
|
|
|
213
245
|
if (value.lt !== undefined) pushBound("<", value.lt);
|
|
214
246
|
if (value.lte !== undefined) pushBound("<=", value.lte);
|
|
215
247
|
|
|
248
|
+
// A filter with no defined bound contributes no SQL. Returning it would
|
|
249
|
+
// widen the caller's predicate to "match everything" — survivable in a
|
|
250
|
+
// read, but it strips the guard off a conditional write.
|
|
251
|
+
if (conditions.length === 0) {
|
|
252
|
+
throw new StorageQueryError(
|
|
253
|
+
`Range filter for field '${field}' has no defined bound`,
|
|
254
|
+
field,
|
|
255
|
+
"Provide at least one of gt, gte, lt, or lte, or omit the field.",
|
|
256
|
+
);
|
|
257
|
+
}
|
|
258
|
+
|
|
216
259
|
return {
|
|
217
260
|
sql: conditions.join(" AND "),
|
|
218
261
|
params,
|
|
@@ -238,6 +281,8 @@ export function buildWhereClause(
|
|
|
238
281
|
|
|
239
282
|
for (const [field, value] of Object.entries(where)) {
|
|
240
283
|
const condition = buildCondition(db, field, value);
|
|
284
|
+
// An empty slot in the join would emit `<cond> AND ` and fail to parse.
|
|
285
|
+
if (!condition.sql) continue;
|
|
241
286
|
conditions.push(condition.sql);
|
|
242
287
|
params.push(...condition.params);
|
|
243
288
|
}
|