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
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"relations-CcFwDJdJ.mjs","names":[],"sources":["../src/api/handlers/relations.ts"],"sourcesContent":["import type { Kysely } from \"kysely\";\n\nimport { ContentRepository } from \"../../database/repositories/content.js\";\nimport {\n\tRelationRepository,\n\ttype ContentReference,\n\ttype CreateRelationInput,\n\ttype Relation,\n} from \"../../database/repositories/relation.js\";\nimport { InvalidCursorError } from \"../../database/repositories/types.js\";\nimport type { ContentItem } from \"../../database/repositories/types.js\";\nimport type { Database } from \"../../database/types.js\";\nimport { resolveConfiguredLocale } from \"../../i18n/config.js\";\nimport { SchemaRegistry } from \"../../schema/registry.js\";\nimport type { ApiResult } from \"../types.js\";\n\n/** Map an edge-read failure: a bad pagination cursor is a 400 client error,\n * everything else is the generic 500-shaped reference-read error. */\nfunction referencesGetError(error: unknown): ApiResult<never> {\n\tif (error instanceof InvalidCursorError) {\n\t\treturn { success: false, error: { code: \"INVALID_CURSOR\", message: error.message } };\n\t}\n\treturn {\n\t\tsuccess: false,\n\t\terror: { code: \"REFERENCES_GET_ERROR\", message: \"Failed to get references\" },\n\t};\n}\n\n/** True for SQLite UNIQUE / Postgres unique_violation messages (matches the\n * fingerprint used in the content handlers). Narrow enough not to catch NOT\n * NULL / CHECK violations whose messages also say \"constraint\". */\nfunction isUniqueViolation(error: unknown): boolean {\n\tconst message = error instanceof Error ? error.message.toLowerCase() : \"\";\n\treturn message.includes(\"unique constraint failed\") || message.includes(\"duplicate key\");\n}\n\nexport async function handleRelationCreate(\n\tdb: Kysely<Database>,\n\tinput: CreateRelationInput,\n): Promise<ApiResult<{ relation: Relation }>> {\n\ttry {\n\t\tconst repo = new RelationRepository(db);\n\n\t\t// Invariant: a relation must point at collections that exist. There is no\n\t\t// SQL FK (group-linking precludes it), so a ghost collection would yield a\n\t\t// structurally-valid-but-permanently-useless relation. Skip when\n\t\t// `translationOf` is set — structural fields are then inherited from an\n\t\t// already-validated source, and the input collections are ignored.\n\t\tif (!input.translationOf) {\n\t\t\tif (!input.parentCollection || !input.childCollection) {\n\t\t\t\treturn {\n\t\t\t\t\tsuccess: false,\n\t\t\t\t\terror: {\n\t\t\t\t\t\tcode: \"VALIDATION_ERROR\",\n\t\t\t\t\t\tmessage:\n\t\t\t\t\t\t\t\"parentCollection and childCollection are required unless translationOf is set\",\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t}\n\t\t\tconst registry = new SchemaRegistry(db);\n\t\t\tfor (const collection of [input.parentCollection, input.childCollection]) {\n\t\t\t\tif (!(await registry.getCollection(collection))) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tsuccess: false,\n\t\t\t\t\t\terror: {\n\t\t\t\t\t\t\tcode: \"COLLECTION_NOT_FOUND\",\n\t\t\t\t\t\t\tmessage: `Collection '${collection}' not found`,\n\t\t\t\t\t\t},\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tconst relation = await repo.create({\n\t\t\t...input,\n\t\t\tlocale: input.locale ? resolveConfiguredLocale(input.locale) : undefined,\n\t\t});\n\t\treturn { success: true, data: { relation } };\n\t} catch (error) {\n\t\t// A bad `translationOf` makes the repo throw loudly rather than mint an\n\t\t// unlinked relation — surface it as 404, not a generic 500.\n\t\tif (\n\t\t\terror instanceof Error &&\n\t\t\terror.message.includes(\"Source relation for translation not found\")\n\t\t) {\n\t\t\treturn {\n\t\t\t\tsuccess: false,\n\t\t\t\terror: { code: \"NOT_FOUND\", message: \"Source relation for translation not found\" },\n\t\t\t};\n\t\t}\n\t\t// UNIQUE(name, locale) collision, or a second translation for an\n\t\t// already-present (translation_group, locale) — both are client conflicts.\n\t\tif (isUniqueViolation(error)) {\n\t\t\treturn {\n\t\t\t\tsuccess: false,\n\t\t\t\terror: {\n\t\t\t\t\tcode: \"CONFLICT\",\n\t\t\t\t\tmessage: \"A relation with this name or locale already exists\",\n\t\t\t\t},\n\t\t\t};\n\t\t}\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\terror: { code: \"RELATION_CREATE_ERROR\", message: \"Failed to create relation\" },\n\t\t};\n\t}\n}\n\nexport async function handleRelationGet(\n\tdb: Kysely<Database>,\n\tid: string,\n): Promise<ApiResult<{ relation: Relation }>> {\n\ttry {\n\t\tconst repo = new RelationRepository(db);\n\t\tconst relation = await repo.findById(id);\n\t\tif (!relation) {\n\t\t\treturn { success: false, error: { code: \"NOT_FOUND\", message: \"Relation not found\" } };\n\t\t}\n\t\treturn { success: true, data: { relation } };\n\t} catch {\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\terror: { code: \"RELATION_GET_ERROR\", message: \"Failed to get relation\" },\n\t\t};\n\t}\n}\n\nexport async function handleRelationList(\n\tdb: Kysely<Database>,\n\topts: { locale?: string },\n): Promise<ApiResult<{ relations: Relation[] }>> {\n\ttry {\n\t\tconst repo = new RelationRepository(db);\n\t\tconst locale = opts.locale ? resolveConfiguredLocale(opts.locale) : undefined;\n\t\tconst relations = await repo.list(locale);\n\t\treturn { success: true, data: { relations } };\n\t} catch {\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\terror: { code: \"RELATION_LIST_ERROR\", message: \"Failed to list relations\" },\n\t\t};\n\t}\n}\n\nexport async function handleRelationUpdate(\n\tdb: Kysely<Database>,\n\tid: string,\n\tinput: { parentLabel?: string; childLabel?: string },\n): Promise<ApiResult<{ relation: Relation }>> {\n\ttry {\n\t\tconst repo = new RelationRepository(db);\n\t\tconst relation = await repo.update(id, input);\n\t\tif (!relation) {\n\t\t\treturn { success: false, error: { code: \"NOT_FOUND\", message: \"Relation not found\" } };\n\t\t}\n\t\treturn { success: true, data: { relation } };\n\t} catch {\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\terror: { code: \"RELATION_UPDATE_ERROR\", message: \"Failed to update relation\" },\n\t\t};\n\t}\n}\n\nexport async function handleRelationDelete(\n\tdb: Kysely<Database>,\n\tid: string,\n): Promise<ApiResult<{ deleted: true }>> {\n\ttry {\n\t\tconst repo = new RelationRepository(db);\n\t\tconst deleted = await repo.delete(id);\n\t\tif (!deleted) {\n\t\t\treturn { success: false, error: { code: \"NOT_FOUND\", message: \"Relation not found\" } };\n\t\t}\n\t\treturn { success: true, data: { deleted: true } };\n\t} catch {\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\terror: { code: \"RELATION_DELETE_ERROR\", message: \"Failed to delete relation\" },\n\t\t};\n\t}\n}\n\nexport async function handleRelationTranslations(\n\tdb: Kysely<Database>,\n\tid: string,\n): Promise<\n\tApiResult<{\n\t\ttranslationGroup: string;\n\t\ttranslations: {\n\t\t\tid: string;\n\t\t\tname: string;\n\t\t\tlocale: string;\n\t\t\tparentLabel: string;\n\t\t\tchildLabel: string;\n\t\t}[];\n\t}>\n> {\n\ttry {\n\t\tconst repo = new RelationRepository(db);\n\t\tconst relation = await repo.findById(id);\n\t\tif (!relation) {\n\t\t\treturn { success: false, error: { code: \"NOT_FOUND\", message: \"Relation not found\" } };\n\t\t}\n\t\tconst siblings = await repo.findTranslations(relation.translationGroup);\n\t\treturn {\n\t\t\tsuccess: true,\n\t\t\tdata: {\n\t\t\t\ttranslationGroup: relation.translationGroup,\n\t\t\t\ttranslations: siblings.map((r) => ({\n\t\t\t\t\tid: r.id,\n\t\t\t\t\tname: r.name,\n\t\t\t\t\tlocale: r.locale,\n\t\t\t\t\tparentLabel: r.parentLabel,\n\t\t\t\t\tchildLabel: r.childLabel,\n\t\t\t\t})),\n\t\t\t},\n\t\t};\n\t} catch {\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\terror: { code: \"RELATION_TRANSLATIONS_ERROR\", message: \"Failed to get translations\" },\n\t\t};\n\t}\n}\n\nexport type EntryRef = {\n\tid: string;\n\tslug: string | null;\n\tcollection: string;\n\t/** The actual locale of the resolved variant — see `pickVariant`. */\n\tlocale: string | null;\n\tsortOrder?: number;\n};\n\n/** Resolve a relation from an id OR its translation_group. */\nasync function resolveRelation(\n\trepo: RelationRepository,\n\tidOrGroup: string,\n): Promise<Relation | null> {\n\tconst byId = await repo.findById(idOrGroup);\n\tif (byId) return byId;\n\tconst group = await repo.findTranslations(idOrGroup);\n\treturn group[0] ?? null;\n}\n\n/**\n * Pick the locale variant matching `locale`, falling back to the first entry\n * (lowest locale code). The fallback is intentional — an edge is keyed by\n * `translation_group`, so a referenced entry that exists only in another locale\n * is still a real reference — but the returned ref carries the variant's actual\n * `locale` so callers never mistake a fallback for the requested locale.\n */\nfunction pickVariant(items: ContentItem[], locale: string | null): ContentItem | undefined {\n\treturn items.find((i) => i.locale === locale) ?? items[0];\n}\n\n/**\n * Resolve edge groups to loadable entries in `collection` at `locale`.\n * Dangling groups (no surviving entry) are skipped — cleanup is a later slice.\n *\n * All groups are loaded in one batched query (chunked at `SQL_BATCH_SIZE`)\n * rather than a `findTranslations` per edge, so a parent with N children costs\n * a constant number of queries, not N+1. Edge order (the caller's `sort_order`)\n * is preserved by iterating `edges`.\n *\n * `includeDrafts` is false for callers without `content:read_drafts`: the load\n * is restricted to published entries so a draft/scheduled entry referenced by an\n * edge is skipped exactly like a dangling one, never leaking its id/slug/locale.\n */\nasync function resolveEntries(\n\tcontent: ContentRepository,\n\tcollection: string,\n\tedges: ContentReference[],\n\tpick: (e: ContentReference) => string,\n\tlocale: string | null,\n\tincludeDrafts: boolean,\n): Promise<EntryRef[]> {\n\tconst groups = edges.map(pick);\n\tconst all = await content.findTranslationsForGroups(collection, groups, {\n\t\tpublishedOnly: !includeDrafts,\n\t});\n\n\t// Group the flat variant list by translation_group so each edge can pick its\n\t// own locale variant.\n\tconst variantsByGroup = new Map<string, ContentItem[]>();\n\tfor (const item of all) {\n\t\tif (item.translationGroup == null) continue;\n\t\tconst list = variantsByGroup.get(item.translationGroup);\n\t\tif (list) list.push(item);\n\t\telse variantsByGroup.set(item.translationGroup, [item]);\n\t}\n\n\tconst refs: EntryRef[] = [];\n\tfor (const edge of edges) {\n\t\tconst variants = variantsByGroup.get(pick(edge));\n\t\tif (!variants) continue;\n\t\tconst entry = pickVariant(variants, locale);\n\t\tif (!entry) continue;\n\t\trefs.push({\n\t\t\tid: entry.id,\n\t\t\tslug: entry.slug,\n\t\t\tcollection,\n\t\t\tlocale: entry.locale,\n\t\t\tsortOrder: edge.sortOrder,\n\t\t});\n\t}\n\treturn refs;\n}\n\n/** Pagination inputs for the edge read endpoints. */\nexport type PageOptions = { limit?: number; cursor?: string };\n\nexport async function handleReferenceChildrenGet(\n\tdb: Kysely<Database>,\n\tcollection: string,\n\tentryId: string,\n\trelation: string,\n\tpage: PageOptions = {},\n\tincludeDrafts = false,\n): Promise<ApiResult<{ children: EntryRef[]; nextCursor?: string }>> {\n\ttry {\n\t\tconst repo = new RelationRepository(db);\n\t\tconst content = new ContentRepository(db);\n\n\t\tconst rel = await resolveRelation(repo, relation);\n\t\tif (!rel)\n\t\t\treturn { success: false, error: { code: \"NOT_FOUND\", message: \"Relation not found\" } };\n\t\tif (collection !== rel.parentCollection) {\n\t\t\treturn {\n\t\t\t\tsuccess: false,\n\t\t\t\terror: {\n\t\t\t\t\tcode: \"VALIDATION_ERROR\",\n\t\t\t\t\tmessage: \"Entry is not the parent side of this relation\",\n\t\t\t\t},\n\t\t\t};\n\t\t}\n\n\t\tconst entry = await content.findByIdOrSlug(collection, entryId);\n\t\t// A caller without draft access must not anchor on a non-published entry —\n\t\t// return NOT_FOUND (not 403) so they can't probe draft ids by status code,\n\t\t// mirroring the single-item content read.\n\t\tif (!entry?.translationGroup || (!includeDrafts && entry.status !== \"published\")) {\n\t\t\treturn { success: false, error: { code: \"NOT_FOUND\", message: \"Content entry not found\" } };\n\t\t}\n\n\t\tconst edges = await repo.getChildrenPage(rel.translationGroup, entry.translationGroup, page);\n\t\tconst children = await resolveEntries(\n\t\t\tcontent,\n\t\t\trel.childCollection,\n\t\t\tedges.items,\n\t\t\t(e) => e.childGroup,\n\t\t\tentry.locale,\n\t\t\tincludeDrafts,\n\t\t);\n\t\treturn { success: true, data: { children, nextCursor: edges.nextCursor } };\n\t} catch (error) {\n\t\treturn referencesGetError(error);\n\t}\n}\n\nexport async function handleReferenceChildrenSet(\n\tdb: Kysely<Database>,\n\tcollection: string,\n\tentryId: string,\n\trelation: string,\n\tchildIds: string[],\n): Promise<ApiResult<{ children: EntryRef[]; nextCursor?: string }>> {\n\ttry {\n\t\tconst repo = new RelationRepository(db);\n\t\tconst content = new ContentRepository(db);\n\n\t\tconst rel = await resolveRelation(repo, relation);\n\t\tif (!rel)\n\t\t\treturn { success: false, error: { code: \"NOT_FOUND\", message: \"Relation not found\" } };\n\t\tif (collection !== rel.parentCollection) {\n\t\t\treturn {\n\t\t\t\tsuccess: false,\n\t\t\t\terror: {\n\t\t\t\t\tcode: \"VALIDATION_ERROR\",\n\t\t\t\t\tmessage: \"Entry is not the parent side of this relation\",\n\t\t\t\t},\n\t\t\t};\n\t\t}\n\n\t\tconst entry = await content.findByIdOrSlug(collection, entryId);\n\t\tif (!entry?.translationGroup) {\n\t\t\treturn { success: false, error: { code: \"NOT_FOUND\", message: \"Content entry not found\" } };\n\t\t}\n\n\t\t// Resolve every child within the relation's child_collection in one batch\n\t\t// (constant queries, not an N+1 of point lookups for a set up to 1000). A\n\t\t// child id that does not resolve there fails collection-agreement\n\t\t// (invariant 3); order is preserved by iterating the caller's `childIds`.\n\t\tconst resolvedChildren = await content.findManyByIdOrSlug(rel.childCollection, childIds);\n\t\tconst childGroups: string[] = [];\n\t\tfor (const childId of childIds) {\n\t\t\tconst child = resolvedChildren.get(childId);\n\t\t\tif (!child?.translationGroup) {\n\t\t\t\treturn {\n\t\t\t\t\tsuccess: false,\n\t\t\t\t\terror: {\n\t\t\t\t\t\tcode: \"NOT_FOUND\",\n\t\t\t\t\t\tmessage: `Child entry '${childId}' not found in ${rel.childCollection}`,\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t}\n\t\t\tchildGroups.push(child.translationGroup);\n\t\t}\n\n\t\tawait repo.setChildren(rel.translationGroup, entry.translationGroup, childGroups);\n\n\t\t// Return the first page of the new set, mirroring the GET shape. The actor\n\t\t// holds an edit permission (gated by the route), so draft children are\n\t\t// included in the echo.\n\t\tconst edges = await repo.getChildrenPage(rel.translationGroup, entry.translationGroup);\n\t\tconst children = await resolveEntries(\n\t\t\tcontent,\n\t\t\trel.childCollection,\n\t\t\tedges.items,\n\t\t\t(e) => e.childGroup,\n\t\t\tentry.locale,\n\t\t\ttrue,\n\t\t);\n\t\treturn { success: true, data: { children, nextCursor: edges.nextCursor } };\n\t} catch {\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\terror: { code: \"REFERENCES_SET_ERROR\", message: \"Failed to set references\" },\n\t\t};\n\t}\n}\n\nexport async function handleReferenceParentsGet(\n\tdb: Kysely<Database>,\n\tcollection: string,\n\tentryId: string,\n\trelation: string,\n\tpage: PageOptions = {},\n\tincludeDrafts = false,\n): Promise<ApiResult<{ parents: EntryRef[]; nextCursor?: string }>> {\n\ttry {\n\t\tconst repo = new RelationRepository(db);\n\t\tconst content = new ContentRepository(db);\n\n\t\tconst rel = await resolveRelation(repo, relation);\n\t\tif (!rel)\n\t\t\treturn { success: false, error: { code: \"NOT_FOUND\", message: \"Relation not found\" } };\n\t\tif (collection !== rel.childCollection) {\n\t\t\treturn {\n\t\t\t\tsuccess: false,\n\t\t\t\terror: {\n\t\t\t\t\tcode: \"VALIDATION_ERROR\",\n\t\t\t\t\tmessage: \"Entry is not the child side of this relation\",\n\t\t\t\t},\n\t\t\t};\n\t\t}\n\n\t\tconst entry = await content.findByIdOrSlug(collection, entryId);\n\t\t// Same draft-anchor guard as the children read: a non-draft-reader anchoring\n\t\t// on an unpublished entry gets NOT_FOUND, not its backlinks.\n\t\tif (!entry?.translationGroup || (!includeDrafts && entry.status !== \"published\")) {\n\t\t\treturn { success: false, error: { code: \"NOT_FOUND\", message: \"Content entry not found\" } };\n\t\t}\n\n\t\tconst edges = await repo.getParentsPage(rel.translationGroup, entry.translationGroup, page);\n\t\tconst parents = await resolveEntries(\n\t\t\tcontent,\n\t\t\trel.parentCollection,\n\t\t\tedges.items,\n\t\t\t(e) => e.parentGroup,\n\t\t\tentry.locale,\n\t\t\tincludeDrafts,\n\t\t);\n\t\treturn { success: true, data: { parents, nextCursor: edges.nextCursor } };\n\t} catch (error) {\n\t\treturn referencesGetError(error);\n\t}\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"relations-KKDSLUwS.mjs","names":[],"sources":["../src/api/handlers/relations.ts"],"sourcesContent":["import type { Kysely } from \"kysely\";\n\nimport { ContentRepository } from \"../../database/repositories/content.js\";\nimport {\n\tRelationRepository,\n\ttype ContentReference,\n\ttype CreateRelationInput,\n\ttype Relation,\n} from \"../../database/repositories/relation.js\";\nimport { InvalidCursorError } from \"../../database/repositories/types.js\";\nimport type { ContentItem } from \"../../database/repositories/types.js\";\nimport type { Database } from \"../../database/types.js\";\nimport { resolveConfiguredLocale } from \"../../i18n/config.js\";\nimport { SchemaRegistry } from \"../../schema/registry.js\";\nimport type { ApiResult } from \"../types.js\";\n\n/** Map an edge-read failure: a bad pagination cursor is a 400 client error,\n * everything else is the generic 500-shaped reference-read error. */\nfunction referencesGetError(error: unknown): ApiResult<never> {\n\tif (error instanceof InvalidCursorError) {\n\t\treturn { success: false, error: { code: \"INVALID_CURSOR\", message: error.message } };\n\t}\n\treturn {\n\t\tsuccess: false,\n\t\terror: { code: \"REFERENCES_GET_ERROR\", message: \"Failed to get references\" },\n\t};\n}\n\n/** True for SQLite UNIQUE / Postgres unique_violation messages (matches the\n * fingerprint used in the content handlers). Narrow enough not to catch NOT\n * NULL / CHECK violations whose messages also say \"constraint\". */\nfunction isUniqueViolation(error: unknown): boolean {\n\tconst message = error instanceof Error ? error.message.toLowerCase() : \"\";\n\treturn message.includes(\"unique constraint failed\") || message.includes(\"duplicate key\");\n}\n\nexport async function handleRelationCreate(\n\tdb: Kysely<Database>,\n\tinput: CreateRelationInput,\n): Promise<ApiResult<{ relation: Relation }>> {\n\ttry {\n\t\tconst repo = new RelationRepository(db);\n\n\t\t// Invariant: a relation must point at collections that exist. There is no\n\t\t// SQL FK (group-linking precludes it), so a ghost collection would yield a\n\t\t// structurally-valid-but-permanently-useless relation. Skip when\n\t\t// `translationOf` is set — structural fields are then inherited from an\n\t\t// already-validated source, and the input collections are ignored.\n\t\tif (!input.translationOf) {\n\t\t\tif (!input.parentCollection || !input.childCollection) {\n\t\t\t\treturn {\n\t\t\t\t\tsuccess: false,\n\t\t\t\t\terror: {\n\t\t\t\t\t\tcode: \"VALIDATION_ERROR\",\n\t\t\t\t\t\tmessage:\n\t\t\t\t\t\t\t\"parentCollection and childCollection are required unless translationOf is set\",\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t}\n\t\t\tconst registry = new SchemaRegistry(db);\n\t\t\tfor (const collection of [input.parentCollection, input.childCollection]) {\n\t\t\t\tif (!(await registry.getCollection(collection))) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tsuccess: false,\n\t\t\t\t\t\terror: {\n\t\t\t\t\t\t\tcode: \"COLLECTION_NOT_FOUND\",\n\t\t\t\t\t\t\tmessage: `Collection '${collection}' not found`,\n\t\t\t\t\t\t},\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tconst relation = await repo.create({\n\t\t\t...input,\n\t\t\tlocale: input.locale ? resolveConfiguredLocale(input.locale) : undefined,\n\t\t});\n\t\treturn { success: true, data: { relation } };\n\t} catch (error) {\n\t\t// A bad `translationOf` makes the repo throw loudly rather than mint an\n\t\t// unlinked relation — surface it as 404, not a generic 500.\n\t\tif (\n\t\t\terror instanceof Error &&\n\t\t\terror.message.includes(\"Source relation for translation not found\")\n\t\t) {\n\t\t\treturn {\n\t\t\t\tsuccess: false,\n\t\t\t\terror: { code: \"NOT_FOUND\", message: \"Source relation for translation not found\" },\n\t\t\t};\n\t\t}\n\t\t// UNIQUE(name, locale) collision, or a second translation for an\n\t\t// already-present (translation_group, locale) — both are client conflicts.\n\t\tif (isUniqueViolation(error)) {\n\t\t\treturn {\n\t\t\t\tsuccess: false,\n\t\t\t\terror: {\n\t\t\t\t\tcode: \"CONFLICT\",\n\t\t\t\t\tmessage: \"A relation with this name or locale already exists\",\n\t\t\t\t},\n\t\t\t};\n\t\t}\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\terror: { code: \"RELATION_CREATE_ERROR\", message: \"Failed to create relation\" },\n\t\t};\n\t}\n}\n\nexport async function handleRelationGet(\n\tdb: Kysely<Database>,\n\tid: string,\n): Promise<ApiResult<{ relation: Relation }>> {\n\ttry {\n\t\tconst repo = new RelationRepository(db);\n\t\tconst relation = await repo.findById(id);\n\t\tif (!relation) {\n\t\t\treturn { success: false, error: { code: \"NOT_FOUND\", message: \"Relation not found\" } };\n\t\t}\n\t\treturn { success: true, data: { relation } };\n\t} catch {\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\terror: { code: \"RELATION_GET_ERROR\", message: \"Failed to get relation\" },\n\t\t};\n\t}\n}\n\nexport async function handleRelationList(\n\tdb: Kysely<Database>,\n\topts: { locale?: string },\n): Promise<ApiResult<{ relations: Relation[] }>> {\n\ttry {\n\t\tconst repo = new RelationRepository(db);\n\t\tconst locale = opts.locale ? resolveConfiguredLocale(opts.locale) : undefined;\n\t\tconst relations = await repo.list(locale);\n\t\treturn { success: true, data: { relations } };\n\t} catch {\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\terror: { code: \"RELATION_LIST_ERROR\", message: \"Failed to list relations\" },\n\t\t};\n\t}\n}\n\nexport async function handleRelationUpdate(\n\tdb: Kysely<Database>,\n\tid: string,\n\tinput: { parentLabel?: string; childLabel?: string },\n): Promise<ApiResult<{ relation: Relation }>> {\n\ttry {\n\t\tconst repo = new RelationRepository(db);\n\t\tconst relation = await repo.update(id, input);\n\t\tif (!relation) {\n\t\t\treturn { success: false, error: { code: \"NOT_FOUND\", message: \"Relation not found\" } };\n\t\t}\n\t\treturn { success: true, data: { relation } };\n\t} catch {\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\terror: { code: \"RELATION_UPDATE_ERROR\", message: \"Failed to update relation\" },\n\t\t};\n\t}\n}\n\nexport async function handleRelationDelete(\n\tdb: Kysely<Database>,\n\tid: string,\n): Promise<ApiResult<{ deleted: true }>> {\n\ttry {\n\t\tconst repo = new RelationRepository(db);\n\t\tconst deleted = await repo.delete(id);\n\t\tif (!deleted) {\n\t\t\treturn { success: false, error: { code: \"NOT_FOUND\", message: \"Relation not found\" } };\n\t\t}\n\t\treturn { success: true, data: { deleted: true } };\n\t} catch {\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\terror: { code: \"RELATION_DELETE_ERROR\", message: \"Failed to delete relation\" },\n\t\t};\n\t}\n}\n\nexport async function handleRelationTranslations(\n\tdb: Kysely<Database>,\n\tid: string,\n): Promise<\n\tApiResult<{\n\t\ttranslationGroup: string;\n\t\ttranslations: {\n\t\t\tid: string;\n\t\t\tname: string;\n\t\t\tlocale: string;\n\t\t\tparentLabel: string;\n\t\t\tchildLabel: string;\n\t\t}[];\n\t}>\n> {\n\ttry {\n\t\tconst repo = new RelationRepository(db);\n\t\tconst relation = await repo.findById(id);\n\t\tif (!relation) {\n\t\t\treturn { success: false, error: { code: \"NOT_FOUND\", message: \"Relation not found\" } };\n\t\t}\n\t\tconst siblings = await repo.findTranslations(relation.translationGroup);\n\t\treturn {\n\t\t\tsuccess: true,\n\t\t\tdata: {\n\t\t\t\ttranslationGroup: relation.translationGroup,\n\t\t\t\ttranslations: siblings.map((r) => ({\n\t\t\t\t\tid: r.id,\n\t\t\t\t\tname: r.name,\n\t\t\t\t\tlocale: r.locale,\n\t\t\t\t\tparentLabel: r.parentLabel,\n\t\t\t\t\tchildLabel: r.childLabel,\n\t\t\t\t})),\n\t\t\t},\n\t\t};\n\t} catch {\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\terror: { code: \"RELATION_TRANSLATIONS_ERROR\", message: \"Failed to get translations\" },\n\t\t};\n\t}\n}\n\nexport type EntryRef = {\n\tid: string;\n\tslug: string | null;\n\tcollection: string;\n\t/** The actual locale of the resolved variant — see `pickVariant`. */\n\tlocale: string | null;\n\tsortOrder?: number;\n};\n\n/** Resolve a relation from an id OR its translation_group. */\nasync function resolveRelation(\n\trepo: RelationRepository,\n\tidOrGroup: string,\n): Promise<Relation | null> {\n\tconst byId = await repo.findById(idOrGroup);\n\tif (byId) return byId;\n\tconst group = await repo.findTranslations(idOrGroup);\n\treturn group[0] ?? null;\n}\n\n/**\n * Pick the locale variant matching `locale`, falling back to the first entry\n * (lowest locale code). The fallback is intentional — an edge is keyed by\n * `translation_group`, so a referenced entry that exists only in another locale\n * is still a real reference — but the returned ref carries the variant's actual\n * `locale` so callers never mistake a fallback for the requested locale.\n */\nfunction pickVariant(items: ContentItem[], locale: string | null): ContentItem | undefined {\n\treturn items.find((i) => i.locale === locale) ?? items[0];\n}\n\n/**\n * Resolve edge groups to loadable entries in `collection` at `locale`.\n * Dangling groups (no surviving entry) are skipped — cleanup is a later slice.\n *\n * All groups are loaded in one batched query (chunked at `SQL_BATCH_SIZE`)\n * rather than a `findTranslations` per edge, so a parent with N children costs\n * a constant number of queries, not N+1. Edge order (the caller's `sort_order`)\n * is preserved by iterating `edges`.\n *\n * `includeDrafts` is false for callers without `content:read_drafts`: the load\n * is restricted to published entries so a draft/scheduled entry referenced by an\n * edge is skipped exactly like a dangling one, never leaking its id/slug/locale.\n */\nasync function resolveEntries(\n\tcontent: ContentRepository,\n\tcollection: string,\n\tedges: ContentReference[],\n\tpick: (e: ContentReference) => string,\n\tlocale: string | null,\n\tincludeDrafts: boolean,\n): Promise<EntryRef[]> {\n\tconst groups = edges.map(pick);\n\tconst all = await content.findTranslationsForGroups(collection, groups, {\n\t\tpublishedOnly: !includeDrafts,\n\t});\n\n\t// Group the flat variant list by translation_group so each edge can pick its\n\t// own locale variant.\n\tconst variantsByGroup = new Map<string, ContentItem[]>();\n\tfor (const item of all) {\n\t\tif (item.translationGroup == null) continue;\n\t\tconst list = variantsByGroup.get(item.translationGroup);\n\t\tif (list) list.push(item);\n\t\telse variantsByGroup.set(item.translationGroup, [item]);\n\t}\n\n\tconst refs: EntryRef[] = [];\n\tfor (const edge of edges) {\n\t\tconst variants = variantsByGroup.get(pick(edge));\n\t\tif (!variants) continue;\n\t\tconst entry = pickVariant(variants, locale);\n\t\tif (!entry) continue;\n\t\trefs.push({\n\t\t\tid: entry.id,\n\t\t\tslug: entry.slug,\n\t\t\tcollection,\n\t\t\tlocale: entry.locale,\n\t\t\tsortOrder: edge.sortOrder,\n\t\t});\n\t}\n\treturn refs;\n}\n\n/** Pagination inputs for the edge read endpoints. */\nexport type PageOptions = { limit?: number; cursor?: string };\n\nexport async function handleReferenceChildrenGet(\n\tdb: Kysely<Database>,\n\tcollection: string,\n\tentryId: string,\n\trelation: string,\n\tpage: PageOptions = {},\n\tincludeDrafts = false,\n): Promise<ApiResult<{ children: EntryRef[]; nextCursor?: string }>> {\n\ttry {\n\t\tconst repo = new RelationRepository(db);\n\t\tconst content = new ContentRepository(db);\n\n\t\tconst rel = await resolveRelation(repo, relation);\n\t\tif (!rel)\n\t\t\treturn { success: false, error: { code: \"NOT_FOUND\", message: \"Relation not found\" } };\n\t\tif (collection !== rel.parentCollection) {\n\t\t\treturn {\n\t\t\t\tsuccess: false,\n\t\t\t\terror: {\n\t\t\t\t\tcode: \"VALIDATION_ERROR\",\n\t\t\t\t\tmessage: \"Entry is not the parent side of this relation\",\n\t\t\t\t},\n\t\t\t};\n\t\t}\n\n\t\tconst entry = await content.findByIdOrSlug(collection, entryId);\n\t\t// A caller without draft access must not anchor on a non-published entry —\n\t\t// return NOT_FOUND (not 403) so they can't probe draft ids by status code,\n\t\t// mirroring the single-item content read.\n\t\tif (!entry?.translationGroup || (!includeDrafts && entry.status !== \"published\")) {\n\t\t\treturn { success: false, error: { code: \"NOT_FOUND\", message: \"Content entry not found\" } };\n\t\t}\n\n\t\tconst edges = await repo.getChildrenPage(rel.translationGroup, entry.translationGroup, page);\n\t\tconst children = await resolveEntries(\n\t\t\tcontent,\n\t\t\trel.childCollection,\n\t\t\tedges.items,\n\t\t\t(e) => e.childGroup,\n\t\t\tentry.locale,\n\t\t\tincludeDrafts,\n\t\t);\n\t\treturn { success: true, data: { children, nextCursor: edges.nextCursor } };\n\t} catch (error) {\n\t\treturn referencesGetError(error);\n\t}\n}\n\nexport async function handleReferenceChildrenSet(\n\tdb: Kysely<Database>,\n\tcollection: string,\n\tentryId: string,\n\trelation: string,\n\tchildIds: string[],\n): Promise<ApiResult<{ children: EntryRef[]; nextCursor?: string }>> {\n\ttry {\n\t\tconst repo = new RelationRepository(db);\n\t\tconst content = new ContentRepository(db);\n\n\t\tconst rel = await resolveRelation(repo, relation);\n\t\tif (!rel)\n\t\t\treturn { success: false, error: { code: \"NOT_FOUND\", message: \"Relation not found\" } };\n\t\tif (collection !== rel.parentCollection) {\n\t\t\treturn {\n\t\t\t\tsuccess: false,\n\t\t\t\terror: {\n\t\t\t\t\tcode: \"VALIDATION_ERROR\",\n\t\t\t\t\tmessage: \"Entry is not the parent side of this relation\",\n\t\t\t\t},\n\t\t\t};\n\t\t}\n\n\t\tconst entry = await content.findByIdOrSlug(collection, entryId);\n\t\tif (!entry?.translationGroup) {\n\t\t\treturn { success: false, error: { code: \"NOT_FOUND\", message: \"Content entry not found\" } };\n\t\t}\n\n\t\t// Resolve every child within the relation's child_collection in one batch\n\t\t// (constant queries, not an N+1 of point lookups for a set up to 1000). A\n\t\t// child id that does not resolve there fails collection-agreement\n\t\t// (invariant 3); order is preserved by iterating the caller's `childIds`.\n\t\tconst resolvedChildren = await content.findManyByIdOrSlug(rel.childCollection, childIds);\n\t\tconst childGroups: string[] = [];\n\t\tfor (const childId of childIds) {\n\t\t\tconst child = resolvedChildren.get(childId);\n\t\t\tif (!child?.translationGroup) {\n\t\t\t\treturn {\n\t\t\t\t\tsuccess: false,\n\t\t\t\t\terror: {\n\t\t\t\t\t\tcode: \"NOT_FOUND\",\n\t\t\t\t\t\tmessage: `Child entry '${childId}' not found in ${rel.childCollection}`,\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t}\n\t\t\tchildGroups.push(child.translationGroup);\n\t\t}\n\n\t\tawait repo.setChildren(rel.translationGroup, entry.translationGroup, childGroups);\n\n\t\t// Return the first page of the new set, mirroring the GET shape. The actor\n\t\t// holds an edit permission (gated by the route), so draft children are\n\t\t// included in the echo.\n\t\tconst edges = await repo.getChildrenPage(rel.translationGroup, entry.translationGroup);\n\t\tconst children = await resolveEntries(\n\t\t\tcontent,\n\t\t\trel.childCollection,\n\t\t\tedges.items,\n\t\t\t(e) => e.childGroup,\n\t\t\tentry.locale,\n\t\t\ttrue,\n\t\t);\n\t\treturn { success: true, data: { children, nextCursor: edges.nextCursor } };\n\t} catch {\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\terror: { code: \"REFERENCES_SET_ERROR\", message: \"Failed to set references\" },\n\t\t};\n\t}\n}\n\nexport async function handleReferenceParentsGet(\n\tdb: Kysely<Database>,\n\tcollection: string,\n\tentryId: string,\n\trelation: string,\n\tpage: PageOptions = {},\n\tincludeDrafts = false,\n): Promise<ApiResult<{ parents: EntryRef[]; nextCursor?: string }>> {\n\ttry {\n\t\tconst repo = new RelationRepository(db);\n\t\tconst content = new ContentRepository(db);\n\n\t\tconst rel = await resolveRelation(repo, relation);\n\t\tif (!rel)\n\t\t\treturn { success: false, error: { code: \"NOT_FOUND\", message: \"Relation not found\" } };\n\t\tif (collection !== rel.childCollection) {\n\t\t\treturn {\n\t\t\t\tsuccess: false,\n\t\t\t\terror: {\n\t\t\t\t\tcode: \"VALIDATION_ERROR\",\n\t\t\t\t\tmessage: \"Entry is not the child side of this relation\",\n\t\t\t\t},\n\t\t\t};\n\t\t}\n\n\t\tconst entry = await content.findByIdOrSlug(collection, entryId);\n\t\t// Same draft-anchor guard as the children read: a non-draft-reader anchoring\n\t\t// on an unpublished entry gets NOT_FOUND, not its backlinks.\n\t\tif (!entry?.translationGroup || (!includeDrafts && entry.status !== \"published\")) {\n\t\t\treturn { success: false, error: { code: \"NOT_FOUND\", message: \"Content entry not found\" } };\n\t\t}\n\n\t\tconst edges = await repo.getParentsPage(rel.translationGroup, entry.translationGroup, page);\n\t\tconst parents = await resolveEntries(\n\t\t\tcontent,\n\t\t\trel.parentCollection,\n\t\t\tedges.items,\n\t\t\t(e) => e.parentGroup,\n\t\t\tentry.locale,\n\t\t\tincludeDrafts,\n\t\t);\n\t\treturn { success: true, data: { parents, nextCursor: edges.nextCursor } };\n\t} catch (error) {\n\t\treturn referencesGetError(error);\n\t}\n}\n"],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { St as roleLevel, vt as httpUrl, yt as localeCode } from "./media-
|
|
1
|
+
import { o as RESERVED_BYLINE_FIELD_SLUGS } from "./types-BMXnRIrX.mjs";
|
|
2
|
+
import { St as roleLevel, vt as httpUrl, yt as localeCode } from "./media-C1EIZKh1.mjs";
|
|
3
3
|
import { z } from "zod";
|
|
4
4
|
|
|
5
5
|
//#region src/api/schemas/auth.ts
|
|
@@ -306,4 +306,4 @@ const referenceParentsResponseSchema = z.object({
|
|
|
306
306
|
|
|
307
307
|
//#endregion
|
|
308
308
|
export { inviteCreateBody as A, wpMediaImportBody as C, wpRewriteUrlsBody as D, wpPrepareBody as E, passkeyRegisterVerifyBody as F, passkeyRenameBody as I, passkeyVerifyBody as L, magicLinkSendBody as M, passkeyOptionsBody as N, authMeActionBody as O, passkeyRegisterOptionsBody as P, signupCompleteBody as R, importProbeBody as S, wpPluginExecuteBody as T, atprotoLoginBody as _, relationDefSchema as a, setupAtprotoAdminBody as b, relationTranslationsSchema as c, bylineFieldCreateBody as d, bylineFieldDefinitionSchema as f, bylineFieldUsageResponseSchema as g, bylineFieldUpdateBody as h, referenceParentsResponseSchema as i, inviteRegisterOptionsBody as j, inviteCompleteBody as k, setReferenceChildrenBody as l, bylineFieldReorderBody as m, entryRefSchema as n, relationListResponseSchema as o, bylineFieldListResponseSchema as p, referenceChildrenResponseSchema as r, relationResponseSchema as s, createRelationBody as t, updateRelationBody as u, setupAdminBody as v, wpPluginAnalyzeBody as w, setupBody as x, setupAdminVerifyBody as y, signupRequestBody as z };
|
|
309
|
-
//# sourceMappingURL=relations-
|
|
309
|
+
//# sourceMappingURL=relations-rOmbndUJ.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"relations-C4htk5sb.mjs","names":["authenticatorTransport","registrationCredential"],"sources":["../src/api/schemas/auth.ts","../src/api/schemas/import.ts","../src/api/schemas/setup.ts","../src/api/schemas/byline-fields.ts","../src/api/schemas/relations.ts"],"sourcesContent":["import { z } from \"zod\";\n\nimport { roleLevel } from \"./common.js\";\n\n// ---------------------------------------------------------------------------\n// WebAuthn credential schemas (matching @emdash-cms/auth/passkey types)\n// ---------------------------------------------------------------------------\n\nconst authenticatorTransport = z.enum([\"usb\", \"nfc\", \"ble\", \"internal\", \"hybrid\"]);\n\n/** RegistrationResponse — sent by the browser after navigator.credentials.create() */\nconst registrationCredential = z.object({\n\tid: z.string(),\n\trawId: z.string(),\n\ttype: z.literal(\"public-key\"),\n\tresponse: z.object({\n\t\tclientDataJSON: z.string(),\n\t\tattestationObject: z.string(),\n\t\ttransports: z.array(authenticatorTransport).optional(),\n\t}),\n\tauthenticatorAttachment: z.enum([\"platform\", \"cross-platform\"]).optional(),\n});\n\n/** AuthenticationResponse — sent by the browser after navigator.credentials.get() */\nconst authenticationCredential = z.object({\n\tid: z.string(),\n\trawId: z.string(),\n\ttype: z.literal(\"public-key\"),\n\tresponse: z.object({\n\t\tclientDataJSON: z.string(),\n\t\tauthenticatorData: z.string(),\n\t\tsignature: z.string(),\n\t\tuserHandle: z.string().optional(),\n\t}),\n\tauthenticatorAttachment: z.enum([\"platform\", \"cross-platform\"]).optional(),\n});\n\n// ---------------------------------------------------------------------------\n// Auth: Input schemas\n// ---------------------------------------------------------------------------\n\nexport const signupRequestBody = z\n\t.object({\n\t\temail: z.email(),\n\t})\n\t.meta({ id: \"SignupRequestBody\" });\n\nexport const signupCompleteBody = z\n\t.object({\n\t\ttoken: z.string().min(1),\n\t\tcredential: registrationCredential,\n\t\tname: z.string().optional(),\n\t})\n\t.meta({ id: \"SignupCompleteBody\" });\n\nexport const inviteCreateBody = z\n\t.object({\n\t\temail: z.email(),\n\t\trole: roleLevel.optional(),\n\t})\n\t.meta({ id: \"InviteCreateBody\" });\n\nexport const inviteRegisterOptionsBody = z\n\t.object({\n\t\ttoken: z.string().min(1),\n\t\tname: z.string().optional(),\n\t})\n\t.meta({ id: \"InviteRegisterOptionsBody\" });\n\nexport const inviteCompleteBody = z\n\t.object({\n\t\ttoken: z.string().min(1),\n\t\tcredential: registrationCredential,\n\t\tname: z.string().optional(),\n\t})\n\t.meta({ id: \"InviteCompleteBody\" });\n\nexport const magicLinkSendBody = z\n\t.object({\n\t\temail: z.email(),\n\t})\n\t.meta({ id: \"MagicLinkSendBody\" });\n\nexport const passkeyOptionsBody = z\n\t.object({\n\t\temail: z.email().optional(),\n\t})\n\t.meta({ id: \"PasskeyOptionsBody\" });\n\nexport const passkeyVerifyBody = z\n\t.object({\n\t\tcredential: authenticationCredential,\n\t})\n\t.meta({ id: \"PasskeyVerifyBody\" });\n\nexport const passkeyRegisterOptionsBody = z\n\t.object({\n\t\tname: z.string().optional(),\n\t})\n\t.meta({ id: \"PasskeyRegisterOptionsBody\" });\n\nexport const passkeyRegisterVerifyBody = z\n\t.object({\n\t\tcredential: registrationCredential,\n\t\tname: z.string().optional(),\n\t})\n\t.meta({ id: \"PasskeyRegisterVerifyBody\" });\n\nexport const passkeyRenameBody = z\n\t.object({\n\t\tname: z.string().min(1),\n\t})\n\t.meta({ id: \"PasskeyRenameBody\" });\n\nexport const authMeActionBody = z\n\t.object({\n\t\taction: z.string().min(1),\n\t})\n\t.meta({ id: \"AuthMeActionBody\" });\n","import { z } from \"zod\";\n\nimport { httpUrl } from \"./common.js\";\n\n// ---------------------------------------------------------------------------\n// Import\n// ---------------------------------------------------------------------------\n\nexport const importProbeBody = z.object({\n\turl: httpUrl,\n});\n\nexport const wpPluginAnalyzeBody = z.object({\n\turl: httpUrl,\n\ttoken: z.string().min(1),\n});\n\nexport const wpPluginExecuteBody = z.object({\n\turl: httpUrl,\n\ttoken: z.string().min(1),\n\tconfig: z.record(z.string(), z.unknown()),\n\t// --- Chunked mode (issue #475). Absent phase = single-shot legacy run. ---\n\t// The admin drives the import in a loop of bounded requests; cross-chunk\n\t// state travels with the client so the server stays stateless.\n\tphase: z.enum([\"content\", \"comments\", \"finalize\"]).optional(),\n\t/** Position within the phase: post-type index + WP page (content), page (comments) */\n\tcursor: z\n\t\t.object({\n\t\t\tpostTypeIndex: z.number().int().min(0).default(0),\n\t\t\tpage: z.number().int().min(1).default(1),\n\t\t})\n\t\t.optional(),\n\t/** WP post ID -> created EmDash item, accumulated across content chunks */\n\tidMap: z\n\t\t.record(z.string(), z.object({ id: z.string().min(1), collection: z.string().min(1) }))\n\t\t.optional(),\n\t/** Source translation group -> EmDash item ID, accumulated across content chunks */\n\ttranslationGroups: z.record(z.string(), z.string().min(1)).optional(),\n\t/** WP comment ID -> EmDash root comment ID, accumulated across comment chunks */\n\tcommentRoots: z.record(z.string(), z.string().min(1)).optional(),\n});\n\nexport const wpPrepareBody = z.object({\n\tpostTypes: z.array(\n\t\tz.object({\n\t\t\tname: z.string().min(1),\n\t\t\tcollection: z.string().min(1),\n\t\t\tfields: z\n\t\t\t\t.array(\n\t\t\t\t\tz.object({\n\t\t\t\t\t\tslug: z.string().min(1),\n\t\t\t\t\t\tlabel: z.string().min(1),\n\t\t\t\t\t\ttype: z.string().min(1),\n\t\t\t\t\t\trequired: z.boolean(),\n\t\t\t\t\t\tsearchable: z.boolean().optional(),\n\t\t\t\t\t}),\n\t\t\t\t)\n\t\t\t\t.optional(),\n\t\t}),\n\t),\n});\n\nexport const wpMediaImportBody = z.object({\n\tattachments: z.array(z.record(z.string(), z.unknown())),\n\tstream: z.boolean().optional(),\n});\n\nexport const wpRewriteUrlsBody = z.object({\n\turlMap: z.record(z.string(), z.string()),\n\tcollections: z.array(z.string()).optional(),\n});\n","import { z } from \"zod\";\n\n// ---------------------------------------------------------------------------\n// Setup\n// ---------------------------------------------------------------------------\n\n/** Registration credential — duplicated reference for setup flow.\n * The canonical definition lives in auth.ts but setup needs it independently\n * because setup runs before auth is configured. */\nconst authenticatorTransport = z.enum([\"usb\", \"nfc\", \"ble\", \"internal\", \"hybrid\"]);\n\nconst registrationCredential = z.object({\n\tid: z.string(),\n\trawId: z.string(),\n\ttype: z.literal(\"public-key\"),\n\tresponse: z.object({\n\t\tclientDataJSON: z.string(),\n\t\tattestationObject: z.string(),\n\t\ttransports: z.array(authenticatorTransport).optional(),\n\t}),\n\tauthenticatorAttachment: z.enum([\"platform\", \"cross-platform\"]).optional(),\n});\n\nexport const setupBody = z.object({\n\ttitle: z.string().min(1),\n\ttagline: z.string().optional(),\n\tincludeContent: z.boolean(),\n});\n\nexport const setupAdminBody = z.object({\n\temail: z.email(),\n\tname: z.string().optional(),\n});\n\nexport const setupAdminVerifyBody = z.object({\n\tcredential: registrationCredential,\n});\n\nexport const atprotoLoginBody = z.object({\n\thandle: z.string().trim().min(1),\n});\n\nexport const setupAtprotoAdminBody = z.object({\n\thandle: z.string().trim().min(1),\n});\n","/**\n * Zod schemas for the byline-fields admin API (Discussion #1174, Phase 4).\n *\n * Reserved-slug + identifier validation runs at the zod layer so the\n * route returns a clean 400 (`VALIDATION_ERROR` from `parseBody`) rather\n * than bubbling a registry-level `BylineSchemaError` (\"RESERVED_SLUG\" /\n * \"INVALID_SLUG\"). The registry repeats the same checks for non-HTTP\n * callers (seeds, scripts) — see `BylineSchemaRegistry.validateSlug`.\n *\n * Field types are constrained to the v1 subset declared in\n * `BYLINE_FIELD_TYPES`. Adding a type to the union there will require a\n * corresponding update to this enum.\n */\n\nimport { z } from \"zod\";\n\nimport { BYLINE_FIELD_TYPES, RESERVED_BYLINE_FIELD_SLUGS } from \"../../schema/types.js\";\n\n/**\n * Slug pattern for byline field definitions — matches the identifier rule\n * used by `validateIdentifier` (and `slugPattern` in `common.ts`).\n * Lowercase letters, digits, and underscores; must start with a letter.\n */\nconst bylineFieldSlugPattern = /^[a-z][a-z0-9_]*$/;\n\n/** Hard cap on a slug — mirrors `BylineSchemaRegistry.MAX_SLUG_LENGTH`. */\nconst MAX_SLUG_LENGTH = 63;\n/** Hard cap on a label — mirrors `BylineSchemaRegistry.MAX_LABEL_LENGTH`. */\nconst MAX_LABEL_LENGTH = 200;\n/** Hard cap on a select field's `options` list. */\nconst MAX_SELECT_OPTIONS = 200;\n\nconst RESERVED_SET: ReadonlySet<string> = new Set(RESERVED_BYLINE_FIELD_SLUGS);\n\n// Enumerate the v1 byline field types explicitly so zod gets the exact\n// literal union for `z.infer<>`. Mirrors `BYLINE_FIELD_TYPES`; CI's\n// type-checker catches drift via the satisfies/import below.\nconst bylineFieldTypeValues = z.enum([\"string\", \"text\", \"url\", \"boolean\", \"select\"]);\n// Compile-time guard: a drift here trips the satisfies check.\ntype _BylineFieldTypeDriftCheck =\n\t(typeof BYLINE_FIELD_TYPES)[number] extends z.infer<typeof bylineFieldTypeValues>\n\t\t? z.infer<typeof bylineFieldTypeValues> extends (typeof BYLINE_FIELD_TYPES)[number]\n\t\t\t? true\n\t\t\t: never\n\t\t: never;\nconst _bylineFieldTypeDriftCheck: _BylineFieldTypeDriftCheck = true;\nvoid _bylineFieldTypeDriftCheck;\n\n/**\n * Validation payload for a byline custom field. v1 only exposes\n * `options` (used by `select`-type fields). Empty/duplicate options are\n * rejected at the registry layer; the zod layer only enforces shape and\n * caps. Future field types may add keys here.\n */\nconst bylineFieldValidationSchema = z\n\t.object({\n\t\toptions: z\n\t\t\t.array(z.string().min(1))\n\t\t\t.min(1, \"select options must contain at least one entry\")\n\t\t\t.max(MAX_SELECT_OPTIONS, `select options cannot exceed ${MAX_SELECT_OPTIONS} entries`)\n\t\t\t.optional(),\n\t})\n\t.strict()\n\t.nullable();\n\n/**\n * Slug validation chain shared by create + reorder bodies. Centralised so\n * the reserved-slug message and pattern are identical everywhere.\n */\nconst bylineFieldSlug = z\n\t.string()\n\t.min(1, \"Byline field slug is required\")\n\t.max(MAX_SLUG_LENGTH, `Byline field slug must be ${MAX_SLUG_LENGTH} characters or less`)\n\t.regex(\n\t\tbylineFieldSlugPattern,\n\t\t\"Byline field slug must contain only lowercase letters, digits, and underscores, and start with a letter\",\n\t)\n\t.refine((slug) => !RESERVED_SET.has(slug), {\n\t\t// Surface the offending slug in the validation issue path-message\n\t\t// for easier debugging from the admin UI's error toast.\n\t\tmessage: \"Byline field slug is reserved\",\n\t});\n\nconst bylineFieldLabel = z\n\t.string()\n\t.min(1, \"Byline field label is required\")\n\t.max(MAX_LABEL_LENGTH, `Byline field label must be ${MAX_LABEL_LENGTH} characters or less`);\n\n// ---------------------------------------------------------------------------\n// Request bodies\n// ---------------------------------------------------------------------------\n\nexport const bylineFieldCreateBody = z\n\t.object({\n\t\tslug: bylineFieldSlug,\n\t\tlabel: bylineFieldLabel,\n\t\ttype: bylineFieldTypeValues,\n\t\trequired: z.boolean().optional(),\n\t\t/**\n\t\t * Whether values are stored per-locale (translatable, default) or\n\t\t * shared across the translation group. See `BylineFieldDefinition`.\n\t\t */\n\t\ttranslatable: z.boolean().optional(),\n\t\tvalidation: bylineFieldValidationSchema.optional(),\n\t\tsortOrder: z.number().int().min(0).optional(),\n\t})\n\t.strict()\n\t.meta({ id: \"BylineFieldCreateBody\" });\n\n/**\n * Update body. `slug` and `type` are intentionally absent — both are\n * immutable post-create (changing them would invalidate stored values).\n * `translatable` flips are gated at the registry layer when value rows\n * exist (`TRANSLATABLE_LOCKED`).\n */\nexport const bylineFieldUpdateBody = z\n\t.object({\n\t\tlabel: bylineFieldLabel.optional(),\n\t\trequired: z.boolean().optional(),\n\t\ttranslatable: z.boolean().optional(),\n\t\tvalidation: bylineFieldValidationSchema.optional(),\n\t\tsortOrder: z.number().int().min(0).optional(),\n\t})\n\t.strict()\n\t.meta({ id: \"BylineFieldUpdateBody\" });\n\nexport const bylineFieldReorderBody = z\n\t.object({\n\t\t/**\n\t\t * Exact set of currently registered slugs in the desired order.\n\t\t * The registry rejects any drift (`REORDER_MISMATCH`); the zod\n\t\t * layer enforces slug shape only. An empty array is permitted —\n\t\t * `reorderFields([])` is a valid no-op when zero fields are\n\t\t * registered (registry contract). Rejecting empty here would\n\t\t * produce a spurious 400 for an admin UI that submits a reorder\n\t\t * after deleting the last field.\n\t\t */\n\t\tslugs: z.array(bylineFieldSlug),\n\t})\n\t.strict()\n\t.meta({ id: \"BylineFieldReorderBody\" });\n\n// ---------------------------------------------------------------------------\n// Response shapes\n// ---------------------------------------------------------------------------\n\nexport const bylineFieldDefinitionSchema = z\n\t.object({\n\t\tid: z.string(),\n\t\tslug: z.string(),\n\t\tlabel: z.string(),\n\t\ttype: bylineFieldTypeValues,\n\t\trequired: z.boolean(),\n\t\ttranslatable: z.boolean(),\n\t\tvalidation: z\n\t\t\t.object({\n\t\t\t\toptions: z.array(z.string()).optional(),\n\t\t\t})\n\t\t\t.nullable(),\n\t\tsortOrder: z.number().int(),\n\t\tcreatedAt: z.string(),\n\t\tupdatedAt: z.string(),\n\t})\n\t.meta({ id: \"BylineFieldDefinition\" });\n\nexport const bylineFieldListResponseSchema = z\n\t.object({\n\t\titems: z.array(bylineFieldDefinitionSchema),\n\t})\n\t.meta({ id: \"BylineFieldListResponse\" });\n\n/**\n * Response shape for `GET /api/admin/byline-fields/[slug]/usage`.\n *\n * `translatableValueCount` counts rows in `_emdash_byline_field_values`.\n * `groupValueCount` counts rows in `_emdash_byline_field_group_values`.\n * `totalAffectedRows` is the sum — what the destructive-delete confirm\n * dialog surfaces. Both individual counts are exposed for diagnostic\n * value (e.g. inconsistency with the field's current `translatable`\n * flag would show non-zero on the \"wrong\" side).\n */\nexport const bylineFieldUsageResponseSchema = z\n\t.object({\n\t\ttranslatableValueCount: z.number().int().nonnegative(),\n\t\tgroupValueCount: z.number().int().nonnegative(),\n\t\ttotalAffectedRows: z.number().int().nonnegative(),\n\t})\n\t.meta({ id: \"BylineFieldUsageResponse\" });\n","import { z } from \"zod\";\n\nimport { localeCode } from \"./common.js\";\n\nconst slugPattern = /^[a-z][a-z0-9_]*$/;\nconst collectionSlug = z\n\t.string()\n\t.min(1)\n\t.max(63)\n\t.regex(slugPattern, \"Invalid collection slug format\");\n\nexport const createRelationBody = z\n\t.object({\n\t\tname: z\n\t\t\t.string()\n\t\t\t.min(1)\n\t\t\t.max(63)\n\t\t\t.regex(slugPattern, \"Name must be lowercase alphanumeric with underscores\"),\n\t\tparentCollection: collectionSlug.optional(),\n\t\tchildCollection: collectionSlug.optional(),\n\t\tparentLabel: z.string().min(1).max(200),\n\t\tchildLabel: z.string().min(1).max(200),\n\t\tlocale: localeCode.optional(),\n\t\ttranslationOf: z.string().min(1).optional(),\n\t})\n\t// A translation inherits its structural fields (name, parentCollection,\n\t// childCollection) from the source relation, so the handler ignores any\n\t// collections supplied alongside `translationOf`. Require them only when\n\t// minting a base relation, so callers aren't forced to pass discarded values.\n\t.refine(\n\t\t(body) =>\n\t\t\tbody.translationOf !== undefined ||\n\t\t\t(body.parentCollection !== undefined && body.childCollection !== undefined),\n\t\t{ message: \"parentCollection and childCollection are required unless translationOf is set\" },\n\t)\n\t.meta({ id: \"CreateRelationBody\" });\n\nexport const updateRelationBody = z\n\t.object({\n\t\tparentLabel: z.string().min(1).max(200).optional(),\n\t\tchildLabel: z.string().min(1).max(200).optional(),\n\t})\n\t// Reject empty payloads: an update touching no field is a client mistake, not\n\t// a successful no-op. Without this, `{}` validates and the handler returns 200\n\t// with the unchanged row, so a typo'd payload looks like it landed.\n\t.refine((body) => body.parentLabel !== undefined || body.childLabel !== undefined, {\n\t\tmessage: \"At least one of parentLabel or childLabel is required\",\n\t})\n\t.meta({ id: \"UpdateRelationBody\" });\n\nexport const setReferenceChildrenBody = z\n\t.object({ childIds: z.array(z.string().min(1)).max(1000) })\n\t.meta({ id: \"SetReferenceChildrenBody\" });\n\nexport const relationDefSchema = z\n\t.object({\n\t\tid: z.string(),\n\t\tname: z.string(),\n\t\tparentCollection: z.string(),\n\t\tchildCollection: z.string(),\n\t\tparentLabel: z.string(),\n\t\tchildLabel: z.string(),\n\t\tlocale: z.string(),\n\t\ttranslationGroup: z.string(),\n\t})\n\t.meta({ id: \"RelationDef\" });\n\nexport const relationListResponseSchema = z\n\t.object({ relations: z.array(relationDefSchema) })\n\t.meta({ id: \"RelationListResponse\" });\n\nexport const relationResponseSchema = z\n\t.object({ relation: relationDefSchema })\n\t.meta({ id: \"RelationResponse\" });\n\nexport const relationTranslationsSchema = z\n\t.object({\n\t\ttranslationGroup: z.string(),\n\t\ttranslations: z.array(\n\t\t\tz.object({\n\t\t\t\tid: z.string(),\n\t\t\t\tname: z.string(),\n\t\t\t\tlocale: z.string(),\n\t\t\t\tparentLabel: z.string(),\n\t\t\t\tchildLabel: z.string(),\n\t\t\t}),\n\t\t),\n\t})\n\t.meta({ id: \"RelationTranslations\" });\n\nexport const entryRefSchema = z\n\t.object({\n\t\tid: z.string(),\n\t\tslug: z.string().nullable(),\n\t\tcollection: z.string(),\n\t\t// The actual locale of the resolved variant. When no variant matches the\n\t\t// requesting entry's locale, the ref falls back to another locale's row;\n\t\t// this field makes that substitution explicit instead of silently\n\t\t// presenting a wrong-locale entry under the requested context.\n\t\tlocale: z.string().nullable(),\n\t\tsortOrder: z.number().int().optional(),\n\t})\n\t.meta({ id: \"ReferenceEntryRef\" });\n\nexport const referenceChildrenResponseSchema = z\n\t.object({ children: z.array(entryRefSchema), nextCursor: z.string().optional() })\n\t.meta({ id: \"ReferenceChildrenResponse\" });\n\nexport const referenceParentsResponseSchema = z\n\t.object({ parents: z.array(entryRefSchema), nextCursor: z.string().optional() })\n\t.meta({ id: \"ReferenceParentsResponse\" });\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"relations-rOmbndUJ.mjs","names":["authenticatorTransport","registrationCredential"],"sources":["../src/api/schemas/auth.ts","../src/api/schemas/import.ts","../src/api/schemas/setup.ts","../src/api/schemas/byline-fields.ts","../src/api/schemas/relations.ts"],"sourcesContent":["import { z } from \"zod\";\n\nimport { roleLevel } from \"./common.js\";\n\n// ---------------------------------------------------------------------------\n// WebAuthn credential schemas (matching @emdash-cms/auth/passkey types)\n// ---------------------------------------------------------------------------\n\nconst authenticatorTransport = z.enum([\"usb\", \"nfc\", \"ble\", \"internal\", \"hybrid\"]);\n\n/** RegistrationResponse — sent by the browser after navigator.credentials.create() */\nconst registrationCredential = z.object({\n\tid: z.string(),\n\trawId: z.string(),\n\ttype: z.literal(\"public-key\"),\n\tresponse: z.object({\n\t\tclientDataJSON: z.string(),\n\t\tattestationObject: z.string(),\n\t\ttransports: z.array(authenticatorTransport).optional(),\n\t}),\n\tauthenticatorAttachment: z.enum([\"platform\", \"cross-platform\"]).optional(),\n});\n\n/** AuthenticationResponse — sent by the browser after navigator.credentials.get() */\nconst authenticationCredential = z.object({\n\tid: z.string(),\n\trawId: z.string(),\n\ttype: z.literal(\"public-key\"),\n\tresponse: z.object({\n\t\tclientDataJSON: z.string(),\n\t\tauthenticatorData: z.string(),\n\t\tsignature: z.string(),\n\t\tuserHandle: z.string().optional(),\n\t}),\n\tauthenticatorAttachment: z.enum([\"platform\", \"cross-platform\"]).optional(),\n});\n\n// ---------------------------------------------------------------------------\n// Auth: Input schemas\n// ---------------------------------------------------------------------------\n\nexport const signupRequestBody = z\n\t.object({\n\t\temail: z.email(),\n\t})\n\t.meta({ id: \"SignupRequestBody\" });\n\nexport const signupCompleteBody = z\n\t.object({\n\t\ttoken: z.string().min(1),\n\t\tcredential: registrationCredential,\n\t\tname: z.string().optional(),\n\t})\n\t.meta({ id: \"SignupCompleteBody\" });\n\nexport const inviteCreateBody = z\n\t.object({\n\t\temail: z.email(),\n\t\trole: roleLevel.optional(),\n\t})\n\t.meta({ id: \"InviteCreateBody\" });\n\nexport const inviteRegisterOptionsBody = z\n\t.object({\n\t\ttoken: z.string().min(1),\n\t\tname: z.string().optional(),\n\t})\n\t.meta({ id: \"InviteRegisterOptionsBody\" });\n\nexport const inviteCompleteBody = z\n\t.object({\n\t\ttoken: z.string().min(1),\n\t\tcredential: registrationCredential,\n\t\tname: z.string().optional(),\n\t})\n\t.meta({ id: \"InviteCompleteBody\" });\n\nexport const magicLinkSendBody = z\n\t.object({\n\t\temail: z.email(),\n\t})\n\t.meta({ id: \"MagicLinkSendBody\" });\n\nexport const passkeyOptionsBody = z\n\t.object({\n\t\temail: z.email().optional(),\n\t})\n\t.meta({ id: \"PasskeyOptionsBody\" });\n\nexport const passkeyVerifyBody = z\n\t.object({\n\t\tcredential: authenticationCredential,\n\t})\n\t.meta({ id: \"PasskeyVerifyBody\" });\n\nexport const passkeyRegisterOptionsBody = z\n\t.object({\n\t\tname: z.string().optional(),\n\t})\n\t.meta({ id: \"PasskeyRegisterOptionsBody\" });\n\nexport const passkeyRegisterVerifyBody = z\n\t.object({\n\t\tcredential: registrationCredential,\n\t\tname: z.string().optional(),\n\t})\n\t.meta({ id: \"PasskeyRegisterVerifyBody\" });\n\nexport const passkeyRenameBody = z\n\t.object({\n\t\tname: z.string().min(1),\n\t})\n\t.meta({ id: \"PasskeyRenameBody\" });\n\nexport const authMeActionBody = z\n\t.object({\n\t\taction: z.string().min(1),\n\t})\n\t.meta({ id: \"AuthMeActionBody\" });\n","import { z } from \"zod\";\n\nimport { httpUrl } from \"./common.js\";\n\n// ---------------------------------------------------------------------------\n// Import\n// ---------------------------------------------------------------------------\n\nexport const importProbeBody = z.object({\n\turl: httpUrl,\n});\n\nexport const wpPluginAnalyzeBody = z.object({\n\turl: httpUrl,\n\ttoken: z.string().min(1),\n});\n\nexport const wpPluginExecuteBody = z.object({\n\turl: httpUrl,\n\ttoken: z.string().min(1),\n\tconfig: z.record(z.string(), z.unknown()),\n\t// --- Chunked mode (issue #475). Absent phase = single-shot legacy run. ---\n\t// The admin drives the import in a loop of bounded requests; cross-chunk\n\t// state travels with the client so the server stays stateless.\n\tphase: z.enum([\"content\", \"comments\", \"finalize\"]).optional(),\n\t/** Position within the phase: post-type index + WP page (content), page (comments) */\n\tcursor: z\n\t\t.object({\n\t\t\tpostTypeIndex: z.number().int().min(0).default(0),\n\t\t\tpage: z.number().int().min(1).default(1),\n\t\t})\n\t\t.optional(),\n\t/** WP post ID -> created EmDash item, accumulated across content chunks */\n\tidMap: z\n\t\t.record(z.string(), z.object({ id: z.string().min(1), collection: z.string().min(1) }))\n\t\t.optional(),\n\t/** Source translation group -> EmDash item ID, accumulated across content chunks */\n\ttranslationGroups: z.record(z.string(), z.string().min(1)).optional(),\n\t/** WP comment ID -> EmDash root comment ID, accumulated across comment chunks */\n\tcommentRoots: z.record(z.string(), z.string().min(1)).optional(),\n});\n\nexport const wpPrepareBody = z.object({\n\tpostTypes: z.array(\n\t\tz.object({\n\t\t\tname: z.string().min(1),\n\t\t\tcollection: z.string().min(1),\n\t\t\tfields: z\n\t\t\t\t.array(\n\t\t\t\t\tz.object({\n\t\t\t\t\t\tslug: z.string().min(1),\n\t\t\t\t\t\tlabel: z.string().min(1),\n\t\t\t\t\t\ttype: z.string().min(1),\n\t\t\t\t\t\trequired: z.boolean(),\n\t\t\t\t\t\tsearchable: z.boolean().optional(),\n\t\t\t\t\t}),\n\t\t\t\t)\n\t\t\t\t.optional(),\n\t\t}),\n\t),\n});\n\nexport const wpMediaImportBody = z.object({\n\tattachments: z.array(z.record(z.string(), z.unknown())),\n\tstream: z.boolean().optional(),\n});\n\nexport const wpRewriteUrlsBody = z.object({\n\turlMap: z.record(z.string(), z.string()),\n\tcollections: z.array(z.string()).optional(),\n});\n","import { z } from \"zod\";\n\n// ---------------------------------------------------------------------------\n// Setup\n// ---------------------------------------------------------------------------\n\n/** Registration credential — duplicated reference for setup flow.\n * The canonical definition lives in auth.ts but setup needs it independently\n * because setup runs before auth is configured. */\nconst authenticatorTransport = z.enum([\"usb\", \"nfc\", \"ble\", \"internal\", \"hybrid\"]);\n\nconst registrationCredential = z.object({\n\tid: z.string(),\n\trawId: z.string(),\n\ttype: z.literal(\"public-key\"),\n\tresponse: z.object({\n\t\tclientDataJSON: z.string(),\n\t\tattestationObject: z.string(),\n\t\ttransports: z.array(authenticatorTransport).optional(),\n\t}),\n\tauthenticatorAttachment: z.enum([\"platform\", \"cross-platform\"]).optional(),\n});\n\nexport const setupBody = z.object({\n\ttitle: z.string().min(1),\n\ttagline: z.string().optional(),\n\tincludeContent: z.boolean(),\n});\n\nexport const setupAdminBody = z.object({\n\temail: z.email(),\n\tname: z.string().optional(),\n});\n\nexport const setupAdminVerifyBody = z.object({\n\tcredential: registrationCredential,\n});\n\nexport const atprotoLoginBody = z.object({\n\thandle: z.string().trim().min(1),\n});\n\nexport const setupAtprotoAdminBody = z.object({\n\thandle: z.string().trim().min(1),\n});\n","/**\n * Zod schemas for the byline-fields admin API (Discussion #1174, Phase 4).\n *\n * Reserved-slug + identifier validation runs at the zod layer so the\n * route returns a clean 400 (`VALIDATION_ERROR` from `parseBody`) rather\n * than bubbling a registry-level `BylineSchemaError` (\"RESERVED_SLUG\" /\n * \"INVALID_SLUG\"). The registry repeats the same checks for non-HTTP\n * callers (seeds, scripts) — see `BylineSchemaRegistry.validateSlug`.\n *\n * Field types are constrained to the v1 subset declared in\n * `BYLINE_FIELD_TYPES`. Adding a type to the union there will require a\n * corresponding update to this enum.\n */\n\nimport { z } from \"zod\";\n\nimport { BYLINE_FIELD_TYPES, RESERVED_BYLINE_FIELD_SLUGS } from \"../../schema/types.js\";\n\n/**\n * Slug pattern for byline field definitions — matches the identifier rule\n * used by `validateIdentifier` (and `slugPattern` in `common.ts`).\n * Lowercase letters, digits, and underscores; must start with a letter.\n */\nconst bylineFieldSlugPattern = /^[a-z][a-z0-9_]*$/;\n\n/** Hard cap on a slug — mirrors `BylineSchemaRegistry.MAX_SLUG_LENGTH`. */\nconst MAX_SLUG_LENGTH = 63;\n/** Hard cap on a label — mirrors `BylineSchemaRegistry.MAX_LABEL_LENGTH`. */\nconst MAX_LABEL_LENGTH = 200;\n/** Hard cap on a select field's `options` list. */\nconst MAX_SELECT_OPTIONS = 200;\n\nconst RESERVED_SET: ReadonlySet<string> = new Set(RESERVED_BYLINE_FIELD_SLUGS);\n\n// Enumerate the v1 byline field types explicitly so zod gets the exact\n// literal union for `z.infer<>`. Mirrors `BYLINE_FIELD_TYPES`; CI's\n// type-checker catches drift via the satisfies/import below.\nconst bylineFieldTypeValues = z.enum([\"string\", \"text\", \"url\", \"boolean\", \"select\"]);\n// Compile-time guard: a drift here trips the satisfies check.\ntype _BylineFieldTypeDriftCheck =\n\t(typeof BYLINE_FIELD_TYPES)[number] extends z.infer<typeof bylineFieldTypeValues>\n\t\t? z.infer<typeof bylineFieldTypeValues> extends (typeof BYLINE_FIELD_TYPES)[number]\n\t\t\t? true\n\t\t\t: never\n\t\t: never;\nconst _bylineFieldTypeDriftCheck: _BylineFieldTypeDriftCheck = true;\nvoid _bylineFieldTypeDriftCheck;\n\n/**\n * Validation payload for a byline custom field. v1 only exposes\n * `options` (used by `select`-type fields). Empty/duplicate options are\n * rejected at the registry layer; the zod layer only enforces shape and\n * caps. Future field types may add keys here.\n */\nconst bylineFieldValidationSchema = z\n\t.object({\n\t\toptions: z\n\t\t\t.array(z.string().min(1))\n\t\t\t.min(1, \"select options must contain at least one entry\")\n\t\t\t.max(MAX_SELECT_OPTIONS, `select options cannot exceed ${MAX_SELECT_OPTIONS} entries`)\n\t\t\t.optional(),\n\t})\n\t.strict()\n\t.nullable();\n\n/**\n * Slug validation chain shared by create + reorder bodies. Centralised so\n * the reserved-slug message and pattern are identical everywhere.\n */\nconst bylineFieldSlug = z\n\t.string()\n\t.min(1, \"Byline field slug is required\")\n\t.max(MAX_SLUG_LENGTH, `Byline field slug must be ${MAX_SLUG_LENGTH} characters or less`)\n\t.regex(\n\t\tbylineFieldSlugPattern,\n\t\t\"Byline field slug must contain only lowercase letters, digits, and underscores, and start with a letter\",\n\t)\n\t.refine((slug) => !RESERVED_SET.has(slug), {\n\t\t// Surface the offending slug in the validation issue path-message\n\t\t// for easier debugging from the admin UI's error toast.\n\t\tmessage: \"Byline field slug is reserved\",\n\t});\n\nconst bylineFieldLabel = z\n\t.string()\n\t.min(1, \"Byline field label is required\")\n\t.max(MAX_LABEL_LENGTH, `Byline field label must be ${MAX_LABEL_LENGTH} characters or less`);\n\n// ---------------------------------------------------------------------------\n// Request bodies\n// ---------------------------------------------------------------------------\n\nexport const bylineFieldCreateBody = z\n\t.object({\n\t\tslug: bylineFieldSlug,\n\t\tlabel: bylineFieldLabel,\n\t\ttype: bylineFieldTypeValues,\n\t\trequired: z.boolean().optional(),\n\t\t/**\n\t\t * Whether values are stored per-locale (translatable, default) or\n\t\t * shared across the translation group. See `BylineFieldDefinition`.\n\t\t */\n\t\ttranslatable: z.boolean().optional(),\n\t\tvalidation: bylineFieldValidationSchema.optional(),\n\t\tsortOrder: z.number().int().min(0).optional(),\n\t})\n\t.strict()\n\t.meta({ id: \"BylineFieldCreateBody\" });\n\n/**\n * Update body. `slug` and `type` are intentionally absent — both are\n * immutable post-create (changing them would invalidate stored values).\n * `translatable` flips are gated at the registry layer when value rows\n * exist (`TRANSLATABLE_LOCKED`).\n */\nexport const bylineFieldUpdateBody = z\n\t.object({\n\t\tlabel: bylineFieldLabel.optional(),\n\t\trequired: z.boolean().optional(),\n\t\ttranslatable: z.boolean().optional(),\n\t\tvalidation: bylineFieldValidationSchema.optional(),\n\t\tsortOrder: z.number().int().min(0).optional(),\n\t})\n\t.strict()\n\t.meta({ id: \"BylineFieldUpdateBody\" });\n\nexport const bylineFieldReorderBody = z\n\t.object({\n\t\t/**\n\t\t * Exact set of currently registered slugs in the desired order.\n\t\t * The registry rejects any drift (`REORDER_MISMATCH`); the zod\n\t\t * layer enforces slug shape only. An empty array is permitted —\n\t\t * `reorderFields([])` is a valid no-op when zero fields are\n\t\t * registered (registry contract). Rejecting empty here would\n\t\t * produce a spurious 400 for an admin UI that submits a reorder\n\t\t * after deleting the last field.\n\t\t */\n\t\tslugs: z.array(bylineFieldSlug),\n\t})\n\t.strict()\n\t.meta({ id: \"BylineFieldReorderBody\" });\n\n// ---------------------------------------------------------------------------\n// Response shapes\n// ---------------------------------------------------------------------------\n\nexport const bylineFieldDefinitionSchema = z\n\t.object({\n\t\tid: z.string(),\n\t\tslug: z.string(),\n\t\tlabel: z.string(),\n\t\ttype: bylineFieldTypeValues,\n\t\trequired: z.boolean(),\n\t\ttranslatable: z.boolean(),\n\t\tvalidation: z\n\t\t\t.object({\n\t\t\t\toptions: z.array(z.string()).optional(),\n\t\t\t})\n\t\t\t.nullable(),\n\t\tsortOrder: z.number().int(),\n\t\tcreatedAt: z.string(),\n\t\tupdatedAt: z.string(),\n\t})\n\t.meta({ id: \"BylineFieldDefinition\" });\n\nexport const bylineFieldListResponseSchema = z\n\t.object({\n\t\titems: z.array(bylineFieldDefinitionSchema),\n\t})\n\t.meta({ id: \"BylineFieldListResponse\" });\n\n/**\n * Response shape for `GET /api/admin/byline-fields/[slug]/usage`.\n *\n * `translatableValueCount` counts rows in `_emdash_byline_field_values`.\n * `groupValueCount` counts rows in `_emdash_byline_field_group_values`.\n * `totalAffectedRows` is the sum — what the destructive-delete confirm\n * dialog surfaces. Both individual counts are exposed for diagnostic\n * value (e.g. inconsistency with the field's current `translatable`\n * flag would show non-zero on the \"wrong\" side).\n */\nexport const bylineFieldUsageResponseSchema = z\n\t.object({\n\t\ttranslatableValueCount: z.number().int().nonnegative(),\n\t\tgroupValueCount: z.number().int().nonnegative(),\n\t\ttotalAffectedRows: z.number().int().nonnegative(),\n\t})\n\t.meta({ id: \"BylineFieldUsageResponse\" });\n","import { z } from \"zod\";\n\nimport { localeCode } from \"./common.js\";\n\nconst slugPattern = /^[a-z][a-z0-9_]*$/;\nconst collectionSlug = z\n\t.string()\n\t.min(1)\n\t.max(63)\n\t.regex(slugPattern, \"Invalid collection slug format\");\n\nexport const createRelationBody = z\n\t.object({\n\t\tname: z\n\t\t\t.string()\n\t\t\t.min(1)\n\t\t\t.max(63)\n\t\t\t.regex(slugPattern, \"Name must be lowercase alphanumeric with underscores\"),\n\t\tparentCollection: collectionSlug.optional(),\n\t\tchildCollection: collectionSlug.optional(),\n\t\tparentLabel: z.string().min(1).max(200),\n\t\tchildLabel: z.string().min(1).max(200),\n\t\tlocale: localeCode.optional(),\n\t\ttranslationOf: z.string().min(1).optional(),\n\t})\n\t// A translation inherits its structural fields (name, parentCollection,\n\t// childCollection) from the source relation, so the handler ignores any\n\t// collections supplied alongside `translationOf`. Require them only when\n\t// minting a base relation, so callers aren't forced to pass discarded values.\n\t.refine(\n\t\t(body) =>\n\t\t\tbody.translationOf !== undefined ||\n\t\t\t(body.parentCollection !== undefined && body.childCollection !== undefined),\n\t\t{ message: \"parentCollection and childCollection are required unless translationOf is set\" },\n\t)\n\t.meta({ id: \"CreateRelationBody\" });\n\nexport const updateRelationBody = z\n\t.object({\n\t\tparentLabel: z.string().min(1).max(200).optional(),\n\t\tchildLabel: z.string().min(1).max(200).optional(),\n\t})\n\t// Reject empty payloads: an update touching no field is a client mistake, not\n\t// a successful no-op. Without this, `{}` validates and the handler returns 200\n\t// with the unchanged row, so a typo'd payload looks like it landed.\n\t.refine((body) => body.parentLabel !== undefined || body.childLabel !== undefined, {\n\t\tmessage: \"At least one of parentLabel or childLabel is required\",\n\t})\n\t.meta({ id: \"UpdateRelationBody\" });\n\nexport const setReferenceChildrenBody = z\n\t.object({ childIds: z.array(z.string().min(1)).max(1000) })\n\t.meta({ id: \"SetReferenceChildrenBody\" });\n\nexport const relationDefSchema = z\n\t.object({\n\t\tid: z.string(),\n\t\tname: z.string(),\n\t\tparentCollection: z.string(),\n\t\tchildCollection: z.string(),\n\t\tparentLabel: z.string(),\n\t\tchildLabel: z.string(),\n\t\tlocale: z.string(),\n\t\ttranslationGroup: z.string(),\n\t})\n\t.meta({ id: \"RelationDef\" });\n\nexport const relationListResponseSchema = z\n\t.object({ relations: z.array(relationDefSchema) })\n\t.meta({ id: \"RelationListResponse\" });\n\nexport const relationResponseSchema = z\n\t.object({ relation: relationDefSchema })\n\t.meta({ id: \"RelationResponse\" });\n\nexport const relationTranslationsSchema = z\n\t.object({\n\t\ttranslationGroup: z.string(),\n\t\ttranslations: z.array(\n\t\t\tz.object({\n\t\t\t\tid: z.string(),\n\t\t\t\tname: z.string(),\n\t\t\t\tlocale: z.string(),\n\t\t\t\tparentLabel: z.string(),\n\t\t\t\tchildLabel: z.string(),\n\t\t\t}),\n\t\t),\n\t})\n\t.meta({ id: \"RelationTranslations\" });\n\nexport const entryRefSchema = z\n\t.object({\n\t\tid: z.string(),\n\t\tslug: z.string().nullable(),\n\t\tcollection: z.string(),\n\t\t// The actual locale of the resolved variant. When no variant matches the\n\t\t// requesting entry's locale, the ref falls back to another locale's row;\n\t\t// this field makes that substitution explicit instead of silently\n\t\t// presenting a wrong-locale entry under the requested context.\n\t\tlocale: z.string().nullable(),\n\t\tsortOrder: z.number().int().optional(),\n\t})\n\t.meta({ id: \"ReferenceEntryRef\" });\n\nexport const referenceChildrenResponseSchema = z\n\t.object({ children: z.array(entryRefSchema), nextCursor: z.string().optional() })\n\t.meta({ id: \"ReferenceChildrenResponse\" });\n\nexport const referenceParentsResponseSchema = z\n\t.object({ parents: z.array(entryRefSchema), nextCursor: z.string().optional() })\n\t.meta({ id: \"ReferenceParentsResponse\" });\n"],"mappings":"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"}
|
|
@@ -101,4 +101,4 @@ function clearRequestCacheEntry(key) {
|
|
|
101
101
|
|
|
102
102
|
//#endregion
|
|
103
103
|
export { setRequestCacheEntry as i, peekRequestCache as n, requestCached as r, clearRequestCacheEntry as t };
|
|
104
|
-
//# sourceMappingURL=request-cache-
|
|
104
|
+
//# sourceMappingURL=request-cache-DAZZmesc.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"request-cache-
|
|
1
|
+
{"version":3,"file":"request-cache-DAZZmesc.mjs","names":[],"sources":["../src/request-cache.ts"],"sourcesContent":["/**\n * Per-request query cache\n *\n * Deduplicates identical database queries within a single page render.\n * Uses the ALS request context as a WeakMap key so the cache is\n * automatically GC'd when the request completes.\n *\n * When no request context is available (e.g. local dev without D1\n * replicas), queries bypass the cache — local SQLite is fast enough\n * that deduplication doesn't matter.\n *\n * The WeakMap is stored on globalThis with a Symbol key to guarantee\n * a singleton even when bundlers duplicate this module across chunks\n * (same pattern as request-context.ts).\n */\n\nimport type { EmDashRequestContext } from \"./request-context.js\";\nimport { getRequestContext } from \"./request-context.js\";\n\ntype CacheStore = WeakMap<EmDashRequestContext, Map<string, Promise<unknown>>>;\n\nconst STORE_KEY = Symbol.for(\"emdash:request-cache\");\nconst g = globalThis as Record<symbol, unknown>;\nconst store: CacheStore =\n\t// eslint-disable-next-line typescript/no-unsafe-type-assertion -- globalThis singleton pattern (see request-context.ts)\n\t(g[STORE_KEY] as CacheStore | undefined) ??\n\t(() => {\n\t\tconst wm: CacheStore = new WeakMap();\n\t\tg[STORE_KEY] = wm;\n\t\treturn wm;\n\t})();\n\n/**\n * Return a cached result for `key` if one exists in the current\n * request scope, otherwise call `fn`, cache its promise, and return it.\n *\n * Caches the *promise*, not the resolved value, so concurrent calls\n * with the same key share a single in-flight query.\n */\nexport function requestCached<T>(key: string, fn: () => Promise<T>): Promise<T> {\n\tconst ctx = getRequestContext();\n\tif (!ctx) return fn();\n\n\tlet cache = store.get(ctx);\n\tif (!cache) {\n\t\tcache = new Map();\n\t\tstore.set(ctx, cache);\n\t}\n\n\tconst existing = cache.get(key);\n\tif (existing) {\n\t\tif (ctx.metrics) ctx.metrics.cacheHits += 1;\n\t\t// eslint-disable-next-line typescript/no-unsafe-type-assertion -- heterogeneous cache; key namespacing guarantees the stored promise resolves to T\n\t\treturn existing as Promise<T>;\n\t}\n\tif (ctx.metrics) ctx.metrics.cacheMisses += 1;\n\n\tconst promise = Promise.resolve()\n\t\t.then(fn)\n\t\t.catch((error) => {\n\t\t\tcache.delete(key);\n\t\t\tthrow error;\n\t\t});\n\tcache.set(key, promise);\n\treturn promise;\n}\n\n/**\n * Look up an entry in the request-scoped cache without inserting one.\n *\n * Returns the in-flight or resolved promise if the key exists in the\n * current request, otherwise `undefined`. Callers can use this to\n * opportunistically satisfy a narrower query (e.g. `getSiteSetting(\"seo\")`)\n * from a broader one (`getSiteSettings()`) that's already been loaded\n * by a parent template — avoiding a redundant round-trip.\n *\n * No-ops outside a request context.\n */\nexport function peekRequestCache<T>(key: string): Promise<T> | undefined {\n\tconst ctx = getRequestContext();\n\tif (!ctx) return undefined;\n\tconst cache = store.get(ctx);\n\t// eslint-disable-next-line typescript/no-unsafe-type-assertion -- heterogeneous cache; caller is responsible for using a T-compatible key\n\treturn cache?.get(key) as Promise<T> | undefined;\n}\n\n/**\n * Pre-populate the request-scoped cache with a resolved value.\n *\n * Internal helper shared between hydration paths (taxonomy terms,\n * bylines, etc.) that already have the data in hand and want downstream\n * callers using `requestCached(key, ...)` to skip the database entirely.\n * Not exported from the package entrypoint — keep it internal until we\n * have a documented plugin/extension surface for hydration.\n *\n * No-ops outside a request context (local dev without ALS).\n *\n * Does not overwrite an existing entry — if a query for this key is already\n * in flight, its promise wins.\n */\nexport function setRequestCacheEntry<T>(key: string, value: T): void {\n\tconst ctx = getRequestContext();\n\tif (!ctx) return;\n\n\tlet cache = store.get(ctx);\n\tif (!cache) {\n\t\tcache = new Map();\n\t\tstore.set(ctx, cache);\n\t}\n\n\tif (cache.has(key)) return;\n\tcache.set(key, Promise.resolve(value));\n}\n\n/**\n * Remove a key from the request-scoped cache.\n *\n * Used by write paths that need to invalidate a downstream read cache —\n * `setRequestCacheEntry` deliberately doesn't overwrite, and `requestCached`\n * returns the cached promise even after the underlying data has changed.\n * Without an explicit clear, a `read → write → read` sequence in a single\n * request can return stale data on the second read.\n *\n * Concrete case: `BylineRepository.update` invalidates\n * `byline-field-group-values:${translation_group}` after writing a\n * non-translatable custom-field value, so the post-update `findById`\n * (and any later reads in the same request) see the fresh value.\n *\n * No-ops outside a request context.\n */\nexport function clearRequestCacheEntry(key: string): void {\n\tconst ctx = getRequestContext();\n\tif (!ctx) return;\n\tconst cache = store.get(ctx);\n\tcache?.delete(key);\n}\n"],"mappings":";;;AAqBA,MAAM,YAAY,OAAO,IAAI,uBAAuB;AACpD,MAAM,IAAI;AACV,MAAM,QAEJ,EAAE,qBACI;CACN,MAAM,qBAAiB,IAAI,SAAS;AACpC,GAAE,aAAa;AACf,QAAO;IACJ;;;;;;;;AASL,SAAgB,cAAiB,KAAa,IAAkC;CAC/E,MAAM,MAAM,mBAAmB;AAC/B,KAAI,CAAC,IAAK,QAAO,IAAI;CAErB,IAAI,QAAQ,MAAM,IAAI,IAAI;AAC1B,KAAI,CAAC,OAAO;AACX,0BAAQ,IAAI,KAAK;AACjB,QAAM,IAAI,KAAK,MAAM;;CAGtB,MAAM,WAAW,MAAM,IAAI,IAAI;AAC/B,KAAI,UAAU;AACb,MAAI,IAAI,QAAS,KAAI,QAAQ,aAAa;AAE1C,SAAO;;AAER,KAAI,IAAI,QAAS,KAAI,QAAQ,eAAe;CAE5C,MAAM,UAAU,QAAQ,SAAS,CAC/B,KAAK,GAAG,CACR,OAAO,UAAU;AACjB,QAAM,OAAO,IAAI;AACjB,QAAM;GACL;AACH,OAAM,IAAI,KAAK,QAAQ;AACvB,QAAO;;;;;;;;;;;;;AAcR,SAAgB,iBAAoB,KAAqC;CACxE,MAAM,MAAM,mBAAmB;AAC/B,KAAI,CAAC,IAAK,QAAO;AAGjB,QAFc,MAAM,IAAI,IAAI,EAEd,IAAI,IAAI;;;;;;;;;;;;;;;;AAiBvB,SAAgB,qBAAwB,KAAa,OAAgB;CACpE,MAAM,MAAM,mBAAmB;AAC/B,KAAI,CAAC,IAAK;CAEV,IAAI,QAAQ,MAAM,IAAI,IAAI;AAC1B,KAAI,CAAC,OAAO;AACX,0BAAQ,IAAI,KAAK;AACjB,QAAM,IAAI,KAAK,MAAM;;AAGtB,KAAI,MAAM,IAAI,IAAI,CAAE;AACpB,OAAM,IAAI,KAAK,QAAQ,QAAQ,MAAM,CAAC;;;;;;;;;;;;;;;;;;AAmBvC,SAAgB,uBAAuB,KAAmB;CACzD,MAAM,MAAM,mBAAmB;AAC/B,KAAI,CAAC,IAAK;AAEV,CADc,MAAM,IAAI,IAAI,EACrB,OAAO,IAAI"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { n as normalizeTrustedHeaders, t as getTrustedProxyHeaders } from "./trusted-proxy-
|
|
1
|
+
import { n as normalizeTrustedHeaders, t as getTrustedProxyHeaders } from "./trusted-proxy-BTM6UxqD.mjs";
|
|
2
2
|
|
|
3
3
|
//#region src/plugins/request-meta.ts
|
|
4
4
|
/**
|
|
@@ -137,4 +137,4 @@ function sanitizeHeadersForSandbox(headers) {
|
|
|
137
137
|
|
|
138
138
|
//#endregion
|
|
139
139
|
export { sanitizeHeadersForSandbox as n, extractRequestMeta as t };
|
|
140
|
-
//# sourceMappingURL=request-meta-
|
|
140
|
+
//# sourceMappingURL=request-meta-BgjUQLQ-.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"request-meta-
|
|
1
|
+
{"version":3,"file":"request-meta-BgjUQLQ-.mjs","names":[],"sources":["../src/plugins/request-meta.ts"],"sourcesContent":["/**\n * Request Metadata Extraction\n *\n * Extracts normalized metadata (IP, user agent, referer, geo) from\n * incoming requests. Used by plugin route handlers to access request\n * context without touching raw headers.\n *\n */\n\nimport type { EmDashConfig } from \"../astro/integration/runtime.js\";\nimport { getTrustedProxyHeaders, normalizeTrustedHeaders } from \"../auth/trusted-proxy.js\";\nimport type { GeoInfo, RequestMeta } from \"./types.js\";\n\n/**\n * Cloudflare Workers `cf` object shape (subset we use).\n * Present on requests when running on Cloudflare Workers.\n */\ninterface CfProperties {\n\tcountry?: string;\n\tregion?: string;\n\tcity?: string;\n}\n\n/**\n * Loose validation for IPv4 and IPv6 addresses.\n * Accepts digits, hex chars, dots, and colons — rejects anything else\n * (e.g. HTML tags, scripts, or other non-IP garbage in spoofed headers).\n */\nconst IP_PATTERN = /^[\\da-fA-F.:]+$/;\n\n/**\n * Extract the first IP from an X-Forwarded-For header value.\n * The header may contain a comma-separated list of IPs; the first\n * entry is the original client IP.\n *\n * Returns null if the extracted value doesn't look like an IP address.\n */\nfunction parseFirstForwardedIp(header: string): string | null {\n\tconst first = header.split(\",\")[0];\n\tconst trimmed = first?.trim();\n\tif (!trimmed) return null;\n\treturn IP_PATTERN.test(trimmed) ? trimmed : null;\n}\n\n/**\n * Read an IP from an operator-declared trusted header. XFF-style headers\n * (any name ending in `forwarded-for`) are parsed as comma-separated lists\n * and the first entry is used; everything else is treated as a single\n * trimmed value.\n */\nfunction readIpFromHeader(headers: Headers, name: string): string | null {\n\tconst value = headers.get(name);\n\tif (!value) return null;\n\tif (name.endsWith(\"forwarded-for\")) {\n\t\treturn parseFirstForwardedIp(value);\n\t}\n\tconst trimmed = value.trim();\n\tif (!trimmed) return null;\n\treturn IP_PATTERN.test(trimmed) ? trimmed : null;\n}\n\n/**\n * Get the Cloudflare `cf` object from the request, if present.\n * Returns undefined when not running on Cloudflare Workers.\n */\nfunction getCfObject(request: Request): CfProperties | undefined {\n\treturn (request as unknown as { cf?: CfProperties }).cf;\n}\n\n/**\n * Extract geographic information from the Cloudflare `cf` object\n * attached to the request. Returns null when not running on CF Workers.\n */\nfunction extractGeo(cf: CfProperties | undefined): GeoInfo | null {\n\tif (!cf) return null;\n\n\tconst country = cf.country ?? null;\n\tconst region = cf.region ?? null;\n\tconst city = cf.city ?? null;\n\n\t// Only return geo if at least one field is populated\n\tif (country === null && region === null && city === null) return null;\n\n\treturn { country, region, city };\n}\n\n/**\n * Extract normalized request metadata from a Request object.\n *\n * IP resolution order:\n * 1. `CF-Connecting-IP` — trusted only when a `cf` object is present on the\n * request. CF edge overwrites any client-supplied value, so this is the\n * cryptographically trustworthy path on Workers. Operator-declared\n * trusted headers cannot override it.\n * 2. `X-Forwarded-For` first entry — trusted only with a `cf` object.\n * 3. Operator-declared trusted proxy headers (from `config.trustedProxyHeaders`\n * or the `EMDASH_TRUSTED_PROXY_HEADERS` env var), tried in order. Used as\n * the primary source off-CF and as a fill-in on CF.\n * 4. `null`\n *\n * The second argument accepts either the EmDash config or a pre-resolved\n * list of trusted headers, so callers that already have the list don't have\n * to round-trip through the config every request.\n */\nexport function extractRequestMeta(\n\trequest: Request,\n\tconfigOrTrustedHeaders?: EmDashConfig | null | { trustedProxyHeaders?: string[] } | string[],\n): RequestMeta {\n\tconst headers = request.headers;\n\tconst cf = getCfObject(request);\n\tconst trusted = resolveTrustedHeaders(configOrTrustedHeaders);\n\n\tlet ip: string | null = null;\n\n\t// On Cloudflare, prefer the cryptographically trustworthy headers first.\n\tif (cf) {\n\t\tconst cfIp = headers.get(\"cf-connecting-ip\")?.trim();\n\t\tif (cfIp && IP_PATTERN.test(cfIp)) {\n\t\t\tip = cfIp;\n\t\t}\n\t\tif (!ip) {\n\t\t\tconst xff = headers.get(\"x-forwarded-for\");\n\t\t\tip = xff ? parseFirstForwardedIp(xff) : null;\n\t\t}\n\t}\n\n\t// Fall through to operator-declared trusted headers. On CF this fills\n\t// in when the CF headers are absent; off-CF it's the primary source.\n\tif (!ip) {\n\t\tfor (const name of trusted) {\n\t\t\tconst value = readIpFromHeader(headers, name);\n\t\t\tif (value) {\n\t\t\t\tip = value;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\tconst userAgent = headers.get(\"user-agent\")?.trim() || null;\n\tconst referer = headers.get(\"referer\")?.trim() || null;\n\tconst geo = extractGeo(cf);\n\n\treturn { ip, userAgent, referer, geo };\n}\n\nfunction resolveTrustedHeaders(\n\tvalue: EmDashConfig | null | { trustedProxyHeaders?: string[] } | string[] | undefined,\n): string[] {\n\tif (Array.isArray(value)) {\n\t\t// Apply the same RFC 7230 validation the config/env path does so a\n\t\t// caller passing a pre-resolved list with bad entries can't crash\n\t\t// `Headers.get()` downstream.\n\t\treturn normalizeTrustedHeaders(value);\n\t}\n\treturn getTrustedProxyHeaders(value);\n}\n\n// =============================================================================\n// Header Sanitization for Sandbox\n// =============================================================================\n\n/**\n * Headers that must never cross the RPC boundary to sandboxed plugins.\n * Session tokens, auth credentials, and infrastructure headers are stripped\n * to prevent malicious plugins from exfiltrating sensitive data.\n */\nconst SANDBOX_STRIPPED_HEADERS = new Set([\n\t\"cookie\",\n\t\"set-cookie\",\n\t\"authorization\",\n\t\"proxy-authorization\",\n\t\"cf-access-jwt-assertion\",\n\t\"cf-access-client-id\",\n\t\"cf-access-client-secret\",\n\t\"x-emdash-request\",\n]);\n\n/**\n * Copy request headers into a plain object, stripping sensitive headers\n * that must not be exposed to sandboxed plugin code.\n */\nexport function sanitizeHeadersForSandbox(headers: Headers): Record<string, string> {\n\tconst safe: Record<string, string> = {};\n\theaders.forEach((value, key) => {\n\t\tif (!SANDBOX_STRIPPED_HEADERS.has(key)) {\n\t\t\tsafe[key] = value;\n\t\t}\n\t});\n\treturn safe;\n}\n"],"mappings":";;;;;;;;AA4BA,MAAM,aAAa;;;;;;;;AASnB,SAAS,sBAAsB,QAA+B;CAE7D,MAAM,UADQ,OAAO,MAAM,IAAI,CAAC,IACT,MAAM;AAC7B,KAAI,CAAC,QAAS,QAAO;AACrB,QAAO,WAAW,KAAK,QAAQ,GAAG,UAAU;;;;;;;;AAS7C,SAAS,iBAAiB,SAAkB,MAA6B;CACxE,MAAM,QAAQ,QAAQ,IAAI,KAAK;AAC/B,KAAI,CAAC,MAAO,QAAO;AACnB,KAAI,KAAK,SAAS,gBAAgB,CACjC,QAAO,sBAAsB,MAAM;CAEpC,MAAM,UAAU,MAAM,MAAM;AAC5B,KAAI,CAAC,QAAS,QAAO;AACrB,QAAO,WAAW,KAAK,QAAQ,GAAG,UAAU;;;;;;AAO7C,SAAS,YAAY,SAA4C;AAChE,QAAQ,QAA6C;;;;;;AAOtD,SAAS,WAAW,IAA8C;AACjE,KAAI,CAAC,GAAI,QAAO;CAEhB,MAAM,UAAU,GAAG,WAAW;CAC9B,MAAM,SAAS,GAAG,UAAU;CAC5B,MAAM,OAAO,GAAG,QAAQ;AAGxB,KAAI,YAAY,QAAQ,WAAW,QAAQ,SAAS,KAAM,QAAO;AAEjE,QAAO;EAAE;EAAS;EAAQ;EAAM;;;;;;;;;;;;;;;;;;;;AAqBjC,SAAgB,mBACf,SACA,wBACc;CACd,MAAM,UAAU,QAAQ;CACxB,MAAM,KAAK,YAAY,QAAQ;CAC/B,MAAM,UAAU,sBAAsB,uBAAuB;CAE7D,IAAI,KAAoB;AAGxB,KAAI,IAAI;EACP,MAAM,OAAO,QAAQ,IAAI,mBAAmB,EAAE,MAAM;AACpD,MAAI,QAAQ,WAAW,KAAK,KAAK,CAChC,MAAK;AAEN,MAAI,CAAC,IAAI;GACR,MAAM,MAAM,QAAQ,IAAI,kBAAkB;AAC1C,QAAK,MAAM,sBAAsB,IAAI,GAAG;;;AAM1C,KAAI,CAAC,GACJ,MAAK,MAAM,QAAQ,SAAS;EAC3B,MAAM,QAAQ,iBAAiB,SAAS,KAAK;AAC7C,MAAI,OAAO;AACV,QAAK;AACL;;;CAKH,MAAM,YAAY,QAAQ,IAAI,aAAa,EAAE,MAAM,IAAI;CACvD,MAAM,UAAU,QAAQ,IAAI,UAAU,EAAE,MAAM,IAAI;CAClD,MAAM,MAAM,WAAW,GAAG;AAE1B,QAAO;EAAE;EAAI;EAAW;EAAS;EAAK;;AAGvC,SAAS,sBACR,OACW;AACX,KAAI,MAAM,QAAQ,MAAM,CAIvB,QAAO,wBAAwB,MAAM;AAEtC,QAAO,uBAAuB,MAAM;;;;;;;AAYrC,MAAM,2BAA2B,IAAI,IAAI;CACxC;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA,CAAC;;;;;AAMF,SAAgB,0BAA0B,SAA0C;CACnF,MAAM,OAA+B,EAAE;AACvC,SAAQ,SAAS,OAAO,QAAQ;AAC/B,MAAI,CAAC,yBAAyB,IAAI,IAAI,CACrC,MAAK,OAAO;GAEZ;AACF,QAAO"}
|
|
@@ -34,8 +34,40 @@ function resolveLocaleChain(explicit) {
|
|
|
34
34
|
return getFallbackChain(locale);
|
|
35
35
|
}
|
|
36
36
|
const REPEATED_SLASHES = /\/{2,}/g;
|
|
37
|
+
const DATE_TOKEN = /\{(year|month|day|hour|minute|second)\}/g;
|
|
38
|
+
const OFFSETLESS_DATETIME = /^(\d{4}-\d{2}-\d{2})[ T](\d{2}:\d{2}(?::\d{2}(?:\.\d+)?)?)$/;
|
|
39
|
+
const pad2 = (n) => String(n).padStart(2, "0");
|
|
40
|
+
function parseUtcDate(date) {
|
|
41
|
+
if (date instanceof Date) return date;
|
|
42
|
+
const offsetless = OFFSETLESS_DATETIME.exec(date);
|
|
43
|
+
return new Date(offsetless ? `${offsetless[1]}T${offsetless[2]}Z` : date);
|
|
44
|
+
}
|
|
37
45
|
/**
|
|
38
|
-
*
|
|
46
|
+
* Substitute WordPress-style date tokens (`{year}`, `{month}`, `{day}`,
|
|
47
|
+
* `{hour}`, `{minute}`, `{second}`) from a publish date. Month/day/time parts
|
|
48
|
+
* are zero-padded, mirroring WordPress (`%monthnum%`, `%day%`, ...). Tokens are
|
|
49
|
+
* left untouched when no valid date is available, so callers without a date
|
|
50
|
+
* (or unpublished entries) never produce a half-resolved URL.
|
|
51
|
+
*/
|
|
52
|
+
function applyDateTokens(path, date) {
|
|
53
|
+
const d = date == null ? null : parseUtcDate(date);
|
|
54
|
+
if (!d || Number.isNaN(d.getTime())) return path;
|
|
55
|
+
const parts = {
|
|
56
|
+
year: String(d.getUTCFullYear()),
|
|
57
|
+
month: pad2(d.getUTCMonth() + 1),
|
|
58
|
+
day: pad2(d.getUTCDate()),
|
|
59
|
+
hour: pad2(d.getUTCHours()),
|
|
60
|
+
minute: pad2(d.getUTCMinutes()),
|
|
61
|
+
second: pad2(d.getUTCSeconds())
|
|
62
|
+
};
|
|
63
|
+
return path.replace(DATE_TOKEN, (match, key) => parts[key] ?? match);
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Interpolate a collection `url_pattern` with a row's slug, id and publish date.
|
|
67
|
+
*
|
|
68
|
+
* Supported tokens: `{slug}`, `{id}`, and the date tokens `{year}`,
|
|
69
|
+
* `{month}`, `{day}`, `{hour}`, `{minute}`, `{second}` (resolved from `date`,
|
|
70
|
+
* for WordPress-style permalinks like `/{year}/{month}/{day}/{slug}.html`).
|
|
39
71
|
*
|
|
40
72
|
* Falls back to `/{collection}/{slug}` when no pattern is configured.
|
|
41
73
|
* Does NOT apply any locale prefix — pass the result through
|
|
@@ -43,8 +75,9 @@ const REPEATED_SLASHES = /\/{2,}/g;
|
|
|
43
75
|
* `localizePath` helper below) to add the locale segment.
|
|
44
76
|
*/
|
|
45
77
|
function interpolateUrlPattern(options) {
|
|
46
|
-
const { pattern, collection, slug, id } = options;
|
|
47
|
-
let path = (pattern ?? `/${encodeURIComponent(collection)}/{slug}`).
|
|
78
|
+
const { pattern, collection, slug, id, date } = options;
|
|
79
|
+
let path = (pattern ?? `/${encodeURIComponent(collection)}/{slug}`).replaceAll("{slug}", encodeURIComponent(slug)).replaceAll("{id}", encodeURIComponent(id));
|
|
80
|
+
path = applyDateTokens(path, date);
|
|
48
81
|
path = path.replace(REPEATED_SLASHES, "/");
|
|
49
82
|
if (path.length > 1 && path.endsWith("/")) path = path.slice(0, -1);
|
|
50
83
|
if (!path.startsWith("/")) path = `/${path}`;
|
|
@@ -140,4 +173,4 @@ function normalizePath(path) {
|
|
|
140
173
|
|
|
141
174
|
//#endregion
|
|
142
175
|
export { resolveLocaleChain as i, localizePath as n, resolveLocale as r, interpolateUrlPattern as t };
|
|
143
|
-
//# sourceMappingURL=resolve-
|
|
176
|
+
//# sourceMappingURL=resolve-Cy0aWSRj.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolve-Cy0aWSRj.mjs","names":[],"sources":["../src/i18n/resolve.ts"],"sourcesContent":["/**\n * Shared locale-resolution helpers.\n *\n * Matches the pattern used by `query.ts` for content: an explicit locale wins,\n * otherwise we fall back to the request-context locale, otherwise to\n * `defaultLocale` when i18n is enabled, otherwise to `undefined` (meaning \"do\n * not filter by locale\" — legacy single-locale behaviour).\n */\n\nimport { getRequestContext } from \"../request-context.js\";\nimport { getFallbackChain, getI18nConfig, isI18nEnabled } from \"./config.js\";\n\n/**\n * Resolve the locale to use for a query given an optional explicit value.\n * Returns `undefined` when no locale information is available; callers should\n * treat that as \"do not filter by locale\".\n */\nexport function resolveLocale(explicit?: string): string | undefined {\n\tif (explicit !== undefined) return explicit;\n\tconst ctxLocale = getRequestContext()?.locale;\n\tif (ctxLocale !== undefined) return ctxLocale;\n\tconst cfg = getI18nConfig();\n\tif (cfg && isI18nEnabled()) return cfg.defaultLocale;\n\treturn undefined;\n}\n\n/**\n * Fallback chain to try when looking up a single item. When i18n is disabled\n * or the locale is unspecified, returns a single-element array (or empty when\n * no locale resolves) so callers can iterate uniformly.\n */\nexport function resolveLocaleChain(explicit?: string): string[] {\n\tconst locale = resolveLocale(explicit);\n\tif (locale === undefined) return [];\n\tif (!isI18nEnabled()) return [locale];\n\treturn getFallbackChain(locale);\n}\n\nconst REPEATED_SLASHES = /\\/{2,}/g;\nconst DATE_TOKEN = /\\{(year|month|day|hour|minute|second)\\}/g;\n// SQLite-style datetime without timezone info (\"2023-05-08 10:00:00\").\n// Stored values are UTC; without this, `new Date()` would parse them in the\n// server's local zone and the same row could yield different URLs per host.\nconst OFFSETLESS_DATETIME = /^(\\d{4}-\\d{2}-\\d{2})[ T](\\d{2}:\\d{2}(?::\\d{2}(?:\\.\\d+)?)?)$/;\nconst pad2 = (n: number) => String(n).padStart(2, \"0\");\n\nfunction parseUtcDate(date: string | Date): Date {\n\tif (date instanceof Date) return date;\n\tconst offsetless = OFFSETLESS_DATETIME.exec(date);\n\treturn new Date(offsetless ? `${offsetless[1]}T${offsetless[2]}Z` : date);\n}\n\n/**\n * Substitute WordPress-style date tokens (`{year}`, `{month}`, `{day}`,\n * `{hour}`, `{minute}`, `{second}`) from a publish date. Month/day/time parts\n * are zero-padded, mirroring WordPress (`%monthnum%`, `%day%`, ...). Tokens are\n * left untouched when no valid date is available, so callers without a date\n * (or unpublished entries) never produce a half-resolved URL.\n */\nfunction applyDateTokens(path: string, date: string | Date | null | undefined): string {\n\tconst d = date == null ? null : parseUtcDate(date);\n\tif (!d || Number.isNaN(d.getTime())) return path;\n\tconst parts: Record<string, string> = {\n\t\tyear: String(d.getUTCFullYear()),\n\t\tmonth: pad2(d.getUTCMonth() + 1),\n\t\tday: pad2(d.getUTCDate()),\n\t\thour: pad2(d.getUTCHours()),\n\t\tminute: pad2(d.getUTCMinutes()),\n\t\tsecond: pad2(d.getUTCSeconds()),\n\t};\n\treturn path.replace(DATE_TOKEN, (match, key: string) => parts[key] ?? match);\n}\n\n/**\n * Interpolate a collection `url_pattern` with a row's slug, id and publish date.\n *\n * Supported tokens: `{slug}`, `{id}`, and the date tokens `{year}`,\n * `{month}`, `{day}`, `{hour}`, `{minute}`, `{second}` (resolved from `date`,\n * for WordPress-style permalinks like `/{year}/{month}/{day}/{slug}.html`).\n *\n * Falls back to `/{collection}/{slug}` when no pattern is configured.\n * Does NOT apply any locale prefix — pass the result through\n * Astro's `getRelativeLocaleUrl` / `getAbsoluteLocaleUrl` (or the\n * `localizePath` helper below) to add the locale segment.\n */\nexport function interpolateUrlPattern(options: {\n\tpattern: string | null;\n\tcollection: string;\n\tslug: string;\n\tid: string;\n\t/** Publish date used for date tokens; tokens stay literal when absent. */\n\tdate?: string | Date | null;\n}): string {\n\tconst { pattern, collection, slug, id, date } = options;\n\tconst basePattern = pattern ?? `/${encodeURIComponent(collection)}/{slug}`;\n\tlet path = basePattern\n\t\t.replaceAll(\"{slug}\", encodeURIComponent(slug))\n\t\t.replaceAll(\"{id}\", encodeURIComponent(id));\n\tpath = applyDateTokens(path, date);\n\tpath = path.replace(REPEATED_SLASHES, \"/\");\n\tif (path.length > 1 && path.endsWith(\"/\")) path = path.slice(0, -1);\n\tif (!path.startsWith(\"/\")) path = `/${path}`;\n\treturn path;\n}\n\n/**\n * Apply a locale prefix to a path, honouring the user's Astro `i18n`\n * routing config (`prefixDefaultLocale`, custom `path`/`codes` mappings).\n *\n * Reads the resolved config from `astro:config/server`, which is always\n * available regardless of whether i18n is enabled -- so this function\n * works in both i18n and non-i18n builds without tripping Astro's\n * `i18nNotEnabled` resolver (the case with importing `astro:i18n`).\n *\n * Returns:\n * - The original `path` when i18n is not configured.\n * - The original `path` for the default locale when\n * `prefixDefaultLocale` is false.\n * - `/{segment}{path}` for any other configured locale, where\n * `{segment}` is the locale's custom `path` if one is set,\n * otherwise the locale code.\n * - `null` when the row's locale isn't in the configured list.\n * Callers should drop the entry: a sitemap link to a route the\n * site can't serve is worse than no link at all (search engines\n * get a 404 / soft-404 and downrank the page).\n *\n * Falls back to `getI18nConfig()` (EmDash's mirror of the same config,\n * populated at runtime startup) when `astro:config/server` is\n * unavailable -- e.g. running outside an Astro build context, such as\n * in vitest.\n */\nexport async function localizePath(path: string, locale: string): Promise<string | null> {\n\tconst segment = await resolveLocaleSegment(locale);\n\tif (segment === undefined) return null;\n\tif (segment === null || segment === \"\") return normalizePath(path);\n\treturn normalizePath(`/${segment}${path}`);\n}\n\n/**\n * Resolve the URL segment to use for a locale.\n *\n * Returns:\n * - `null` when i18n isn't configured (caller should not prefix).\n * - `\"\"` when the locale is the default locale and\n * `prefixDefaultLocale` is false (caller should not prefix).\n * - The locale's custom `path` value, or the locale string itself.\n * - `undefined` when the locale isn't in the configured list --\n * the row points at a route the site can't serve.\n */\nasync function resolveLocaleSegment(locale: string): Promise<string | null | undefined> {\n\tconst i18n = await readAstroI18nConfig();\n\tif (!i18n || !i18n.locales || i18n.locales.length <= 1) return null;\n\n\tconst isDefault = locale === i18n.defaultLocale;\n\tif (isDefault && !i18n.prefixDefaultLocale) return \"\";\n\n\t// When the locale has a custom `path`/`codes` mapping, use the path\n\t// for the URL segment. Otherwise use the locale code directly.\n\tfor (const entry of i18n.locales) {\n\t\tif (typeof entry === \"string\") {\n\t\t\tif (entry === locale) return entry;\n\t\t} else if (entry.codes.includes(locale)) {\n\t\t\treturn entry.path;\n\t\t}\n\t}\n\n\treturn undefined;\n}\n\ninterface AstroI18nConfig {\n\tdefaultLocale: string;\n\tlocales: Array<string | { codes: readonly string[]; path: string }>;\n\tprefixDefaultLocale?: boolean;\n}\n\nlet astroI18nCache: AstroI18nConfig | null | undefined;\n\nasync function readAstroI18nConfig(): Promise<AstroI18nConfig | null> {\n\tif (astroI18nCache !== undefined) return astroI18nCache;\n\n\ttry {\n\t\tconst mod = (await import(\"astro:config/server\")) as {\n\t\t\ti18n?: {\n\t\t\t\tdefaultLocale: string;\n\t\t\t\tlocales: Array<string | { codes: readonly string[]; path: string }>;\n\t\t\t\trouting?: { prefixDefaultLocale?: boolean } | string;\n\t\t\t};\n\t\t};\n\t\tif (!mod.i18n) {\n\t\t\tastroI18nCache = null;\n\t\t\treturn null;\n\t\t}\n\t\tconst routing = mod.i18n.routing;\n\t\tastroI18nCache = {\n\t\t\tdefaultLocale: mod.i18n.defaultLocale,\n\t\t\tlocales: mod.i18n.locales,\n\t\t\tprefixDefaultLocale:\n\t\t\t\ttypeof routing === \"object\" ? (routing.prefixDefaultLocale ?? false) : false,\n\t\t};\n\t\treturn astroI18nCache;\n\t} catch {\n\t\t// `astro:config/server` isn't resolvable (e.g. running under vitest\n\t\t// outside an Astro build). Fall back to EmDash's runtime config,\n\t\t// which is populated at startup via the same astroConfig object.\n\t\tconst cfg = getI18nConfig();\n\t\tif (!cfg || !isI18nEnabled()) {\n\t\t\tastroI18nCache = null;\n\t\t\treturn null;\n\t\t}\n\t\tastroI18nCache = {\n\t\t\tdefaultLocale: cfg.defaultLocale,\n\t\t\tlocales: cfg.locales,\n\t\t\tprefixDefaultLocale: cfg.prefixDefaultLocale,\n\t\t};\n\t\treturn astroI18nCache;\n\t}\n}\n\n/** @internal -- exposed for tests to reset the module-level cache. */\nexport function _resetAstroI18nCacheForTests(): void {\n\tastroI18nCache = undefined;\n}\n\nfunction normalizePath(path: string): string {\n\tlet p = path.replace(REPEATED_SLASHES, \"/\");\n\tif (p.length > 1 && p.endsWith(\"/\")) p = p.slice(0, -1);\n\tif (!p.startsWith(\"/\")) p = `/${p}`;\n\treturn p;\n}\n"],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { t as Database } from "./types-
|
|
1
|
+
import { t as Database } from "./types-tJWDK__M.mjs";
|
|
2
2
|
import { Kysely } from "kysely";
|
|
3
3
|
import { Migrator } from "kysely/migration";
|
|
4
4
|
|
|
@@ -64,4 +64,4 @@ declare function rollbackMigration(db: Kysely<Database>, options?: MigrationOpti
|
|
|
64
64
|
}>;
|
|
65
65
|
//#endregion
|
|
66
66
|
export { getMigrationStatus as a, getExactMigrationStatus as i, MIGRATION_NAMES as n, rollbackMigration as o, MigrationStatus as r, runMigrations as s, ExactMigrationStatus as t };
|
|
67
|
-
//# sourceMappingURL=runner-
|
|
67
|
+
//# sourceMappingURL=runner-CfwysRM0.d.mts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runner-
|
|
1
|
+
{"version":3,"file":"runner-CfwysRM0.d.mts","names":[],"sources":["../src/database/migrations/runner.ts"],"mappings":";;;;;;cAmKa,eAAA;AAAA,UAeI,eAAA;EAChB,OAAA;EACA,OAAA;AAAA;AAAA,UAGgB,oBAAA;EAChB,YAAA;EACA,OAAA;EACA,cAAA;AAAA;AAAA,UAyBgB,gBAAA;EAChB,oBAAA;EAsBqB;;;;;EAhBrB,UAAA;AAAA;;;;iBAgBqB,kBAAA,CACrB,EAAA,EAAI,MAAA,CAAO,QAAA,GACX,OAAA,GAAU,gBAAA,GACR,OAAA,CAAQ,eAAA;AAwJX;;;;;AAAA,iBAAsB,uBAAA,CACrB,EAAA,EAAI,MAAA,CAAO,QAAA,GACX,OAAA,GAAU,gBAAA,GACR,OAAA,CAAQ,oBAAA;;;;;;;;;;;;;;AAiDX;;;;;;;iBAAsB,aAAA,CACrB,EAAA,EAAI,MAAA,CAAO,QAAA,GACX,OAAA,GAAU,gBAAA,GACR,OAAA;EAAU,OAAA;AAAA;;;;iBA0DS,iBAAA,CACrB,EAAA,EAAI,MAAA,CAAO,QAAA,GACX,OAAA,GAAU,gBAAA,GACR,OAAA;EAAU,UAAA;AAAA"}
|