emdash 0.16.0 → 0.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{adapters-C4yd_UJR.d.mts → adapters-C5AWLJSD.d.mts} +1 -1
- package/dist/{adapters-C4yd_UJR.d.mts.map → adapters-C5AWLJSD.d.mts.map} +1 -1
- package/dist/{allowed-origins-D0fFk9a6.mjs → allowed-origins-CyYLEJkp.mjs} +2 -2
- package/dist/{allowed-origins-D0fFk9a6.mjs.map → allowed-origins-CyYLEJkp.mjs.map} +1 -1
- package/dist/api/route-utils.d.mts +3 -3
- package/dist/api/route-utils.mjs +16 -16
- package/dist/api/schemas/index.d.mts +2 -2
- package/dist/api/schemas/index.mjs +3 -3
- package/dist/{api-BNKqxyFX.mjs → api-Dmz40c2V.mjs} +44 -22
- package/dist/api-Dmz40c2V.mjs.map +1 -0
- package/dist/{api-tokens-ucpcNXDt.mjs → api-tokens-VrXNiNvV.mjs} +2 -2
- package/dist/{api-tokens-ucpcNXDt.mjs.map → api-tokens-VrXNiNvV.mjs.map} +1 -1
- package/dist/{apply-BOPaD-s9.mjs → apply-CgamLmed.mjs} +93 -31
- package/dist/apply-CgamLmed.mjs.map +1 -0
- package/dist/astro/index.d.mts +10 -10
- package/dist/astro/index.mjs +19 -3
- package/dist/astro/index.mjs.map +1 -1
- package/dist/astro/middleware/auth.d.mts +9 -9
- package/dist/astro/middleware/auth.mjs +6 -6
- package/dist/astro/middleware/redirect.d.mts.map +1 -1
- package/dist/astro/middleware/redirect.mjs +9 -5
- package/dist/astro/middleware/redirect.mjs.map +1 -1
- package/dist/astro/middleware/request-context.mjs +2 -2
- package/dist/astro/middleware/setup.mjs +1 -1
- package/dist/astro/middleware.mjs +66 -65
- package/dist/astro/middleware.mjs.map +1 -1
- package/dist/astro/routes/api/admin/allowed-domains/_domain_.mjs +5 -5
- package/dist/astro/routes/api/admin/allowed-domains/index.mjs +5 -5
- package/dist/astro/routes/api/admin/api-tokens/_id_.mjs +4 -4
- package/dist/astro/routes/api/admin/api-tokens/index.mjs +5 -5
- package/dist/astro/routes/api/admin/byline-fields/_slug_/usage.d.mts +8 -0
- package/dist/astro/routes/api/admin/byline-fields/_slug_/usage.d.mts.map +1 -0
- package/dist/astro/routes/api/admin/byline-fields/_slug_/usage.mjs +23 -0
- package/dist/astro/routes/api/admin/byline-fields/_slug_/usage.mjs.map +1 -0
- package/dist/astro/routes/api/admin/byline-fields/_slug_.d.mts +10 -0
- package/dist/astro/routes/api/admin/byline-fields/_slug_.d.mts.map +1 -0
- package/dist/astro/routes/api/admin/byline-fields/_slug_.mjs +55 -0
- package/dist/astro/routes/api/admin/byline-fields/_slug_.mjs.map +1 -0
- package/dist/astro/routes/api/admin/byline-fields/index.d.mts +9 -0
- package/dist/astro/routes/api/admin/byline-fields/index.d.mts.map +1 -0
- package/dist/astro/routes/api/admin/byline-fields/index.mjs +43 -0
- package/dist/astro/routes/api/admin/byline-fields/index.mjs.map +1 -0
- package/dist/astro/routes/api/admin/byline-fields/reorder.d.mts +8 -0
- package/dist/astro/routes/api/admin/byline-fields/reorder.d.mts.map +1 -0
- package/dist/astro/routes/api/admin/byline-fields/reorder.mjs +27 -0
- package/dist/astro/routes/api/admin/byline-fields/reorder.mjs.map +1 -0
- package/dist/astro/routes/api/admin/bylines/_id_/index.d.mts.map +1 -1
- package/dist/astro/routes/api/admin/bylines/_id_/index.mjs +27 -28
- package/dist/astro/routes/api/admin/bylines/_id_/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/bylines/_id_/translations.mjs +13 -12
- package/dist/astro/routes/api/admin/bylines/_id_/translations.mjs.map +1 -1
- package/dist/astro/routes/api/admin/bylines/index.mjs +15 -13
- package/dist/astro/routes/api/admin/bylines/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/comments/_id_/status.mjs +10 -10
- package/dist/astro/routes/api/admin/comments/_id_.mjs +5 -5
- package/dist/astro/routes/api/admin/comments/bulk.mjs +8 -8
- package/dist/astro/routes/api/admin/comments/counts.mjs +5 -5
- package/dist/astro/routes/api/admin/comments/index.mjs +8 -8
- package/dist/astro/routes/api/admin/hooks/exclusive/_hookName_.mjs +4 -4
- package/dist/astro/routes/api/admin/hooks/exclusive/index.mjs +3 -3
- package/dist/astro/routes/api/admin/oauth-clients/_id_.mjs +4 -4
- package/dist/astro/routes/api/admin/oauth-clients/index.mjs +4 -4
- package/dist/astro/routes/api/admin/plugins/_id_/disable.mjs +35 -34
- package/dist/astro/routes/api/admin/plugins/_id_/disable.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/_id_/enable.mjs +35 -34
- package/dist/astro/routes/api/admin/plugins/_id_/enable.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/_id_/index.mjs +34 -33
- package/dist/astro/routes/api/admin/plugins/_id_/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/_id_/uninstall.mjs +34 -33
- package/dist/astro/routes/api/admin/plugins/_id_/uninstall.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/_id_/update.mjs +34 -33
- package/dist/astro/routes/api/admin/plugins/_id_/update.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/index.mjs +34 -33
- package/dist/astro/routes/api/admin/plugins/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/marketplace/_id_/icon.mjs +3 -3
- package/dist/astro/routes/api/admin/plugins/marketplace/_id_/index.mjs +34 -33
- 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 +34 -33
- package/dist/astro/routes/api/admin/plugins/marketplace/_id_/install.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/marketplace/index.mjs +34 -33
- package/dist/astro/routes/api/admin/plugins/marketplace/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/registry/_id_/uninstall.mjs +34 -33
- 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 +35 -34
- package/dist/astro/routes/api/admin/plugins/registry/_id_/update.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/registry/artifact.mjs +34 -33
- package/dist/astro/routes/api/admin/plugins/registry/artifact.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/registry/install.mjs +35 -34
- package/dist/astro/routes/api/admin/plugins/registry/install.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/updates.mjs +34 -33
- package/dist/astro/routes/api/admin/plugins/updates.mjs.map +1 -1
- package/dist/astro/routes/api/admin/themes/marketplace/_id_/index.mjs +34 -33
- 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 +3 -3
- package/dist/astro/routes/api/admin/themes/marketplace/index.mjs +34 -33
- package/dist/astro/routes/api/admin/themes/marketplace/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/users/_id_/disable.mjs +2 -2
- package/dist/astro/routes/api/admin/users/_id_/enable.mjs +2 -2
- package/dist/astro/routes/api/admin/users/_id_/index.mjs +5 -5
- package/dist/astro/routes/api/admin/users/_id_/send-recovery.mjs +3 -3
- package/dist/astro/routes/api/admin/users/index.mjs +5 -5
- package/dist/astro/routes/api/auth/dev-bypass.mjs +5 -5
- package/dist/astro/routes/api/auth/invite/accept.mjs +2 -2
- package/dist/astro/routes/api/auth/invite/complete.mjs +9 -9
- package/dist/astro/routes/api/auth/invite/index.mjs +6 -6
- package/dist/astro/routes/api/auth/invite/register-options.mjs +8 -8
- package/dist/astro/routes/api/auth/logout.mjs +3 -3
- package/dist/astro/routes/api/auth/magic-link/send.mjs +8 -8
- package/dist/astro/routes/api/auth/magic-link/verify.mjs +3 -3
- package/dist/astro/routes/api/auth/me.d.mts.map +1 -1
- package/dist/astro/routes/api/auth/me.mjs +18 -11
- package/dist/astro/routes/api/auth/me.mjs.map +1 -1
- package/dist/astro/routes/api/auth/mode.mjs +1 -1
- package/dist/astro/routes/api/auth/oauth/_provider_/callback.mjs +3 -3
- package/dist/astro/routes/api/auth/oauth/_provider_.mjs +2 -2
- package/dist/astro/routes/api/auth/passkey/_id_.mjs +5 -5
- package/dist/astro/routes/api/auth/passkey/index.mjs +2 -2
- package/dist/astro/routes/api/auth/passkey/options.mjs +10 -10
- package/dist/astro/routes/api/auth/passkey/register/options.mjs +8 -8
- package/dist/astro/routes/api/auth/passkey/register/verify.mjs +9 -9
- package/dist/astro/routes/api/auth/passkey/verify.mjs +9 -9
- package/dist/astro/routes/api/auth/signup/complete.mjs +9 -9
- package/dist/astro/routes/api/auth/signup/request.mjs +8 -8
- package/dist/astro/routes/api/auth/signup/verify.mjs +2 -2
- package/dist/astro/routes/api/comments/_collection_/_contentId_/index.mjs +11 -11
- package/dist/astro/routes/api/content/_collection_/_id_/compare.mjs +3 -3
- package/dist/astro/routes/api/content/_collection_/_id_/discard-draft.mjs +3 -3
- package/dist/astro/routes/api/content/_collection_/_id_/duplicate.mjs +3 -3
- package/dist/astro/routes/api/content/_collection_/_id_/permanent.mjs +3 -3
- package/dist/astro/routes/api/content/_collection_/_id_/preview-url.mjs +9 -9
- package/dist/astro/routes/api/content/_collection_/_id_/publish.mjs +6 -6
- package/dist/astro/routes/api/content/_collection_/_id_/restore.mjs +3 -3
- package/dist/astro/routes/api/content/_collection_/_id_/revisions.mjs +3 -3
- package/dist/astro/routes/api/content/_collection_/_id_/schedule.mjs +6 -6
- package/dist/astro/routes/api/content/_collection_/_id_/terms/_taxonomy_.d.mts.map +1 -1
- package/dist/astro/routes/api/content/_collection_/_id_/terms/_taxonomy_.mjs +18 -13
- package/dist/astro/routes/api/content/_collection_/_id_/terms/_taxonomy_.mjs.map +1 -1
- package/dist/astro/routes/api/content/_collection_/_id_/translations.mjs +3 -3
- package/dist/astro/routes/api/content/_collection_/_id_/unpublish.mjs +3 -3
- package/dist/astro/routes/api/content/_collection_/_id_.d.mts.map +1 -1
- package/dist/astro/routes/api/content/_collection_/_id_.mjs +9 -7
- package/dist/astro/routes/api/content/_collection_/_id_.mjs.map +1 -1
- package/dist/astro/routes/api/content/_collection_/index.mjs +6 -6
- package/dist/astro/routes/api/content/_collection_/trash.mjs +6 -6
- package/dist/astro/routes/api/dashboard.mjs +7 -7
- package/dist/astro/routes/api/dev/emails.mjs +3 -3
- package/dist/astro/routes/api/import/probe.d.mts +3 -3
- package/dist/astro/routes/api/import/probe.mjs +10 -10
- package/dist/astro/routes/api/import/wordpress/analyze.mjs +4 -4
- package/dist/astro/routes/api/import/wordpress/execute.d.mts +9 -9
- package/dist/astro/routes/api/import/wordpress/execute.mjs +11 -10
- package/dist/astro/routes/api/import/wordpress/execute.mjs.map +1 -1
- package/dist/astro/routes/api/import/wordpress/media.mjs +8 -8
- package/dist/astro/routes/api/import/wordpress/prepare.mjs +9 -9
- package/dist/astro/routes/api/import/wordpress/rewrite-urls.mjs +8 -8
- package/dist/astro/routes/api/import/wordpress-plugin/analyze.d.mts +1 -1
- package/dist/astro/routes/api/import/wordpress-plugin/analyze.mjs +10 -10
- package/dist/astro/routes/api/import/wordpress-plugin/execute.d.mts +1 -1
- package/dist/astro/routes/api/import/wordpress-plugin/execute.mjs +13 -11
- 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 +34 -30
- package/dist/astro/routes/api/mcp.mjs.map +1 -1
- package/dist/astro/routes/api/media/_id_/confirm.mjs +6 -6
- package/dist/astro/routes/api/media/_id_.mjs +6 -6
- package/dist/astro/routes/api/media/file/_...key_.mjs +2 -2
- package/dist/astro/routes/api/media/providers/_providerId_/_itemId_.mjs +3 -3
- package/dist/astro/routes/api/media/providers/_providerId_/index.mjs +3 -3
- package/dist/astro/routes/api/media/providers/index.mjs +3 -3
- package/dist/astro/routes/api/media/upload-url.mjs +8 -8
- package/dist/astro/routes/api/media.d.mts.map +1 -1
- package/dist/astro/routes/api/media.mjs +13 -12
- package/dist/astro/routes/api/media.mjs.map +1 -1
- package/dist/astro/routes/api/menus/_name_/items/_id_.mjs +7 -7
- package/dist/astro/routes/api/menus/_name_/items.mjs +7 -7
- package/dist/astro/routes/api/menus/_name_/reorder.mjs +7 -7
- package/dist/astro/routes/api/menus/_name_/translations.mjs +7 -7
- package/dist/astro/routes/api/menus/_name_.mjs +7 -7
- package/dist/astro/routes/api/menus/index.mjs +7 -7
- package/dist/astro/routes/api/oauth/authorize.mjs +6 -6
- package/dist/astro/routes/api/oauth/device/authorize.mjs +6 -6
- package/dist/astro/routes/api/oauth/device/code.mjs +9 -9
- package/dist/astro/routes/api/oauth/device/token.mjs +8 -8
- package/dist/astro/routes/api/oauth/register.mjs +3 -3
- package/dist/astro/routes/api/oauth/token/refresh.mjs +6 -6
- package/dist/astro/routes/api/oauth/token/revoke.mjs +6 -6
- package/dist/astro/routes/api/oauth/token.mjs +6 -6
- package/dist/astro/routes/api/openapi.json.mjs +10 -7
- 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 +8 -8
- package/dist/astro/routes/api/redirects/404s/summary.mjs +8 -8
- package/dist/astro/routes/api/redirects/_id_.mjs +9 -9
- package/dist/astro/routes/api/redirects/index.mjs +9 -9
- package/dist/astro/routes/api/revisions/_revisionId_/index.mjs +3 -3
- package/dist/astro/routes/api/revisions/_revisionId_/restore.mjs +3 -3
- package/dist/astro/routes/api/schema/collections/_slug_/fields/_fieldSlug_.mjs +34 -33
- 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 +34 -33
- 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 +34 -33
- package/dist/astro/routes/api/schema/collections/_slug_/fields/reorder.mjs.map +1 -1
- package/dist/astro/routes/api/schema/collections/_slug_/index.mjs +34 -33
- package/dist/astro/routes/api/schema/collections/_slug_/index.mjs.map +1 -1
- package/dist/astro/routes/api/schema/collections/index.mjs +34 -33
- package/dist/astro/routes/api/schema/collections/index.mjs.map +1 -1
- package/dist/astro/routes/api/schema/index.mjs +6 -6
- package/dist/astro/routes/api/schema/orphans/_slug_.mjs +34 -33
- package/dist/astro/routes/api/schema/orphans/_slug_.mjs.map +1 -1
- package/dist/astro/routes/api/schema/orphans/index.mjs +34 -33
- package/dist/astro/routes/api/schema/orphans/index.mjs.map +1 -1
- package/dist/astro/routes/api/search/enable.mjs +9 -9
- package/dist/astro/routes/api/search/index.mjs +8 -8
- package/dist/astro/routes/api/search/rebuild.mjs +9 -9
- package/dist/astro/routes/api/search/stats.mjs +6 -6
- package/dist/astro/routes/api/search/suggest.mjs +8 -8
- package/dist/astro/routes/api/sections/_slug_.mjs +8 -8
- package/dist/astro/routes/api/sections/index.mjs +8 -8
- package/dist/astro/routes/api/settings/email.mjs +4 -4
- package/dist/astro/routes/api/settings.mjs +11 -11
- package/dist/astro/routes/api/setup/admin-verify.mjs +10 -10
- package/dist/astro/routes/api/setup/admin.mjs +9 -9
- package/dist/astro/routes/api/setup/dev-bypass.mjs +24 -23
- 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 +24 -23
- package/dist/astro/routes/api/setup/index.mjs.map +1 -1
- package/dist/astro/routes/api/setup/status.mjs +4 -4
- package/dist/astro/routes/api/snapshot.mjs +5 -5
- package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_/translations.mjs +12 -12
- package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_.mjs +12 -12
- package/dist/astro/routes/api/taxonomies/_name_/terms/index.mjs +12 -12
- package/dist/astro/routes/api/taxonomies/index.mjs +12 -12
- package/dist/astro/routes/api/themes/preview.mjs +5 -5
- package/dist/astro/routes/api/typegen.mjs +5 -5
- package/dist/astro/routes/api/well-known/auth.mjs +1 -1
- package/dist/astro/routes/api/well-known/oauth-authorization-server.mjs +2 -2
- package/dist/astro/routes/api/well-known/oauth-protected-resource.mjs +2 -2
- package/dist/astro/routes/api/widget-areas/_name_/reorder.mjs +6 -6
- package/dist/astro/routes/api/widget-areas/_name_/widgets/_id_.mjs +8 -8
- package/dist/astro/routes/api/widget-areas/_name_/widgets.mjs +8 -8
- package/dist/astro/routes/api/widget-areas/_name_.mjs +5 -5
- package/dist/astro/routes/api/widget-areas/index.mjs +8 -8
- package/dist/astro/routes/api/widget-components.mjs +3 -3
- package/dist/astro/routes/robots.txt.mjs +6 -6
- package/dist/astro/routes/sitemap-_collection_.xml.mjs +8 -8
- package/dist/astro/routes/sitemap.xml.mjs +7 -7
- package/dist/astro/types.d.mts +13 -12
- package/dist/astro/types.d.mts.map +1 -1
- package/dist/auth/providers/github.d.mts +1 -1
- package/dist/auth/providers/google.d.mts +1 -1
- package/dist/{authorize-Bn4S4DUT.mjs → authorize-_wWM_44T.mjs} +2 -2
- package/dist/{authorize-Bn4S4DUT.mjs.map → authorize-_wWM_44T.mjs.map} +1 -1
- package/dist/byline-BrIVWLm-.mjs +925 -0
- package/dist/byline-BrIVWLm-.mjs.map +1 -0
- package/dist/{bylines-B2_XmnSU.d.mts → byline-fields-BNy7Ng1U.d.mts} +154 -26
- package/dist/byline-fields-BNy7Ng1U.d.mts.map +1 -0
- package/dist/byline-fields-DC3Wkk-U.mjs +123 -0
- package/dist/byline-fields-DC3Wkk-U.mjs.map +1 -0
- package/dist/byline-fields-Dr-xcb6S.mjs +238 -0
- package/dist/byline-fields-Dr-xcb6S.mjs.map +1 -0
- package/dist/byline-registry-CxK5g559.mjs +406 -0
- package/dist/byline-registry-CxK5g559.mjs.map +1 -0
- package/dist/{bylines-n6nykUyI.mjs → bylines-C_POWmGT.mjs} +25 -11
- package/dist/{bylines-n6nykUyI.mjs.map → bylines-C_POWmGT.mjs.map} +1 -1
- package/dist/bylines-sqExMElV.mjs +204 -0
- package/dist/bylines-sqExMElV.mjs.map +1 -0
- package/dist/{cache-BcI1yUjR.mjs → cache-wsDkA8ru.mjs} +2 -2
- package/dist/{cache-BcI1yUjR.mjs.map → cache-wsDkA8ru.mjs.map} +1 -1
- package/dist/{challenge-store-Dng1SxKT.mjs → challenge-store-DGwuCc4R.mjs} +1 -1
- package/dist/{challenge-store-Dng1SxKT.mjs.map → challenge-store-DGwuCc4R.mjs.map} +1 -1
- package/dist/{chunks-cYG4SnIP.mjs → chunks-BAYkM-CF.mjs} +2 -2
- package/dist/{chunks-cYG4SnIP.mjs.map → chunks-BAYkM-CF.mjs.map} +1 -1
- package/dist/cli/index.mjs +29 -23
- package/dist/cli/index.mjs.map +1 -1
- package/dist/client/cf-access.d.mts +1 -1
- package/dist/client/index.d.mts +2 -1
- package/dist/client/index.d.mts.map +1 -1
- package/dist/client/index.mjs +4 -2
- package/dist/client/index.mjs.map +1 -1
- package/dist/{comment-C76G-9tz.mjs → comment-Cd29aktf.mjs} +2 -2
- package/dist/{comment-C76G-9tz.mjs.map → comment-Cd29aktf.mjs.map} +1 -1
- package/dist/{comments-CCxFFGY1.mjs → comments-B7ufhkxN.mjs} +3 -3
- package/dist/{comments-CCxFFGY1.mjs.map → comments-B7ufhkxN.mjs.map} +1 -1
- package/dist/{components-Dx3DM0gg.mjs → components-CTfpu3PZ.mjs} +1 -1
- package/dist/{components-Dx3DM0gg.mjs.map → components-CTfpu3PZ.mjs.map} +1 -1
- package/dist/{content-8voQNTXX.mjs → content-BbqKo3Kc.mjs} +22 -3
- package/dist/content-BbqKo3Kc.mjs.map +1 -0
- package/dist/{context-B7qiYrz2.mjs → context-BsF1rhoI.mjs} +9 -9
- package/dist/{context-B7qiYrz2.mjs.map → context-BsF1rhoI.mjs.map} +1 -1
- package/dist/{cron-Bd3b3iuj.mjs → cron-DZovZUnC.mjs} +1 -1
- package/dist/{cron-Bd3b3iuj.mjs.map → cron-DZovZUnC.mjs.map} +1 -1
- package/dist/{dashboard-BeaFSPpx.mjs → dashboard-BwIX9r-X.mjs} +4 -4
- package/dist/{dashboard-BeaFSPpx.mjs.map → dashboard-BwIX9r-X.mjs.map} +1 -1
- package/dist/db/index.d.mts +3 -3
- package/dist/db/index.mjs +1 -1
- package/dist/db/libsql.d.mts +1 -1
- package/dist/db/postgres.d.mts +1 -1
- package/dist/db/sqlite.d.mts +1 -1
- package/dist/{db-errors-BiYqoX-n.mjs → db-errors-CtzxKBxe.mjs} +1 -1
- package/dist/{db-errors-BiYqoX-n.mjs.map → db-errors-CtzxKBxe.mjs.map} +1 -1
- package/dist/{default-BvTAYCzx.mjs → default-xLFNSsZ9.mjs} +1 -1
- package/dist/{default-BvTAYCzx.mjs.map → default-xLFNSsZ9.mjs.map} +1 -1
- package/dist/{device-flow-B9oG8PwP.mjs → device-flow-ptLrVINd.mjs} +4 -4
- package/dist/{device-flow-B9oG8PwP.mjs.map → device-flow-ptLrVINd.mjs.map} +1 -1
- package/dist/{email-console-CubRll9q.mjs → email-console-DHT2Fbpj.mjs} +1 -1
- package/dist/{email-console-CubRll9q.mjs.map → email-console-DHT2Fbpj.mjs.map} +1 -1
- package/dist/{error-ChfADBuu.mjs → error-npZWBSb7.mjs} +7 -3
- package/dist/error-npZWBSb7.mjs.map +1 -0
- package/dist/{escape-Cg6kMELH.mjs → escape-bIyGoW5W.mjs} +1 -1
- package/dist/{escape-Cg6kMELH.mjs.map → escape-bIyGoW5W.mjs.map} +1 -1
- package/dist/{fts-manager-C_b-4x8u.mjs → fts-manager-DmUAk-kQ.mjs} +2 -2
- package/dist/{fts-manager-C_b-4x8u.mjs.map → fts-manager-DmUAk-kQ.mjs.map} +1 -1
- package/dist/{hash-DlUxGhQS.mjs → hash-9w3pd3-m.mjs} +1 -1
- package/dist/{hash-DlUxGhQS.mjs.map → hash-9w3pd3-m.mjs.map} +1 -1
- package/dist/{import-DG80rC_I.mjs → import-Dh8bWmyq.mjs} +3 -3
- package/dist/{import-DG80rC_I.mjs.map → import-Dh8bWmyq.mjs.map} +1 -1
- package/dist/{index-BPZFAcgE.d.mts → index-CjKdMZ3U.d.mts} +39 -17
- package/dist/index-CjKdMZ3U.d.mts.map +1 -0
- package/dist/{index-CC42STEm.d.mts → index-D60_SzHG.d.mts} +3 -3
- package/dist/{index-CC42STEm.d.mts.map → index-D60_SzHG.d.mts.map} +1 -1
- package/dist/index.d.mts +17 -17
- package/dist/index.mjs +55 -54
- package/dist/{load-CLFRjk9r.mjs → load-DsoLq7ex.mjs} +2 -2
- package/dist/{load-CLFRjk9r.mjs.map → load-DsoLq7ex.mjs.map} +1 -1
- package/dist/{loader-D-vIJjfY.mjs → loader-CJ6lWO0d.mjs} +75 -19
- package/dist/loader-CJ6lWO0d.mjs.map +1 -0
- package/dist/{manifest-schema-Czqf0TLu.mjs → manifest-schema-Cj-YrzrF.mjs} +1 -1
- package/dist/{manifest-schema-Czqf0TLu.mjs.map → manifest-schema-Cj-YrzrF.mjs.map} +1 -1
- package/dist/media/index.d.mts +1 -1
- package/dist/media/index.mjs +2 -2
- package/dist/media/local-runtime.d.mts +11 -11
- package/dist/media/local-runtime.mjs +5 -5
- package/dist/{media-allowlist-BNloC69x.mjs → media-allowlist-CMcoYIjQ.mjs} +2 -2
- package/dist/{media-allowlist-BNloC69x.mjs.map → media-allowlist-CMcoYIjQ.mjs.map} +1 -1
- package/dist/{media-CKQd8AYU.mjs → media-jk_HzzOl.mjs} +7 -2
- package/dist/media-jk_HzzOl.mjs.map +1 -0
- package/dist/{menus-arUNspyU.mjs → menus-B-5-3aon.mjs} +2 -2
- package/dist/{menus-arUNspyU.mjs.map → menus-B-5-3aon.mjs.map} +1 -1
- package/dist/{menus-C-nWT5Tu.mjs → menus-CyMO6GBx.mjs} +27 -11
- package/dist/menus-CyMO6GBx.mjs.map +1 -0
- package/dist/{mime-KV5TqkMN.mjs → mime-CCEzze7W.mjs} +1 -1
- package/dist/{mime-KV5TqkMN.mjs.map → mime-CCEzze7W.mjs.map} +1 -1
- package/dist/{mode-CaaiebZI.mjs → mode-BjlXswIw.mjs} +1 -1
- package/dist/{mode-CaaiebZI.mjs.map → mode-BjlXswIw.mjs.map} +1 -1
- package/dist/{normalize-CN5kRSMC.mjs → normalize-DVV8nbrL.mjs} +1 -1
- package/dist/{normalize-CN5kRSMC.mjs.map → normalize-DVV8nbrL.mjs.map} +1 -1
- package/dist/{oauth-authorization-CTMeVfvj.mjs → oauth-authorization-DvBAL75d.mjs} +4 -4
- package/dist/{oauth-authorization-CTMeVfvj.mjs.map → oauth-authorization-DvBAL75d.mjs.map} +1 -1
- package/dist/{oauth-clients-eJCbkVSG.mjs → oauth-clients-8mPDStMv.mjs} +1 -1
- package/dist/{oauth-clients-eJCbkVSG.mjs.map → oauth-clients-8mPDStMv.mjs.map} +1 -1
- package/dist/{oauth-state-store-vOSdOeGe.mjs → oauth-state-store-BJ7YtrfD.mjs} +1 -1
- package/dist/{oauth-state-store-vOSdOeGe.mjs.map → oauth-state-store-BJ7YtrfD.mjs.map} +1 -1
- package/dist/{oauth-user-lookup-3JwsVw6N.mjs → oauth-user-lookup-BdDSDvjF.mjs} +1 -1
- package/dist/{oauth-user-lookup-3JwsVw6N.mjs.map → oauth-user-lookup-BdDSDvjF.mjs.map} +1 -1
- package/dist/{options-DhV-gwJb.d.mts → options-tb7DJROi.d.mts} +3 -3
- package/dist/{options-DhV-gwJb.d.mts.map → options-tb7DJROi.d.mts.map} +1 -1
- package/dist/page/index.d.mts +2 -2
- package/dist/{parse-DHbXfvxO.mjs → parse-4zO5Y2DL.mjs} +2 -2
- package/dist/{parse-DHbXfvxO.mjs.map → parse-4zO5Y2DL.mjs.map} +1 -1
- package/dist/{passkey-config-BloQOT3y.mjs → passkey-config-BDVM86Tj.mjs} +1 -1
- package/dist/{passkey-config-BloQOT3y.mjs.map → passkey-config-BDVM86Tj.mjs.map} +1 -1
- package/dist/{placeholder-KCkkCtgQ.d.mts → placeholder-B9lUUEmj.d.mts} +1 -1
- package/dist/{placeholder-KCkkCtgQ.d.mts.map → placeholder-B9lUUEmj.d.mts.map} +1 -1
- package/dist/{placeholder-LqmHqvBw.mjs → placeholder-BZxr8W1j.mjs} +1 -1
- package/dist/{placeholder-LqmHqvBw.mjs.map → placeholder-BZxr8W1j.mjs.map} +1 -1
- package/dist/plugin-types.d.mts +1 -1
- package/dist/plugin-utils.d.mts +9 -9
- package/dist/plugins/adapt-sandbox-entry.d.mts +9 -9
- package/dist/plugins/adapt-sandbox-entry.mjs +2 -2
- package/dist/{preview-D4z0WONU.mjs → preview-BfuRkVKW.mjs} +2 -2
- package/dist/{preview-D4z0WONU.mjs.map → preview-BfuRkVKW.mjs.map} +1 -1
- package/dist/{public-url-CUWWFME2.mjs → public-url-egRHCy1m.mjs} +1 -1
- package/dist/{public-url-CUWWFME2.mjs.map → public-url-egRHCy1m.mjs.map} +1 -1
- package/dist/{query-7m6-l0f_.mjs → query-CuvjwhrE.mjs} +12 -12
- package/dist/{query-7m6-l0f_.mjs.map → query-CuvjwhrE.mjs.map} +1 -1
- package/dist/{rate-limit-D8RAXN8b.mjs → rate-limit-D6VQqBk_.mjs} +2 -2
- package/dist/{rate-limit-D8RAXN8b.mjs.map → rate-limit-D6VQqBk_.mjs.map} +1 -1
- package/dist/{redirect-CjfDGrTd.mjs → redirect-BZUJltlj.mjs} +2 -2
- package/dist/{redirect-CjfDGrTd.mjs.map → redirect-BZUJltlj.mjs.map} +1 -1
- package/dist/{redirect-BINiRYq4.mjs → redirect-Cw3JTlmj.mjs} +1 -1
- package/dist/{redirect-BINiRYq4.mjs.map → redirect-Cw3JTlmj.mjs.map} +1 -1
- package/dist/{redirects-COMLwsV5.mjs → redirects-C0L9JUk4.mjs} +19 -6
- package/dist/redirects-C0L9JUk4.mjs.map +1 -0
- package/dist/{redirects-CowoEHdE.mjs → redirects-DnYuqsEf.mjs} +3 -3
- package/dist/{redirects-CowoEHdE.mjs.map → redirects-DnYuqsEf.mjs.map} +1 -1
- package/dist/{registry-Cyp-dx6J.mjs → registry-Dn6gsx3L.mjs} +13 -5
- package/dist/{registry-Cyp-dx6J.mjs.map → registry-Dn6gsx3L.mjs.map} +1 -1
- package/dist/{request-cache-dzCt8TZB.mjs → request-cache-BYMs-BGX.mjs} +23 -2
- package/dist/{request-cache-dzCt8TZB.mjs.map → request-cache-BYMs-BGX.mjs.map} +1 -1
- package/dist/{request-meta-C_Cjii-T.mjs → request-meta-7ByVLxB-.mjs} +2 -2
- package/dist/{request-meta-C_Cjii-T.mjs.map → request-meta-7ByVLxB-.mjs.map} +1 -1
- package/dist/{resolve-D6sM-SgF.mjs → resolve-BqYMVG0D.mjs} +1 -1
- package/dist/{resolve-D6sM-SgF.mjs.map → resolve-BqYMVG0D.mjs.map} +1 -1
- package/dist/{runner-DSQBurMS.d.mts → runner-DM1yR5qd.d.mts} +2 -2
- package/dist/{runner-DSQBurMS.d.mts.map → runner-DM1yR5qd.d.mts.map} +1 -1
- package/dist/{runner-Drnvs96u.mjs → runner-eAgyIkeg.mjs} +284 -158
- package/dist/runner-eAgyIkeg.mjs.map +1 -0
- package/dist/runtime.d.mts +10 -10
- package/dist/runtime.mjs +2 -2
- package/dist/{schema-CI9mYPX3.mjs → schema--mYZX4D7.mjs} +5 -5
- package/dist/{schema-CI9mYPX3.mjs.map → schema--mYZX4D7.mjs.map} +1 -1
- package/dist/{search-DKz_mGBP.mjs → search-C6U_NvZI.mjs} +4 -4
- package/dist/{search-DKz_mGBP.mjs.map → search-C6U_NvZI.mjs.map} +1 -1
- package/dist/{secrets-rPdhEBkD.mjs → secrets-YYbTgB1w.mjs} +1 -1
- package/dist/{secrets-rPdhEBkD.mjs.map → secrets-YYbTgB1w.mjs.map} +1 -1
- package/dist/{sections-DBbCDIAT.mjs → sections-Ba-rJLKb.mjs} +3 -3
- package/dist/{sections-DBbCDIAT.mjs.map → sections-Ba-rJLKb.mjs.map} +1 -1
- package/dist/seed/index.d.mts +2 -2
- package/dist/seed/index.mjs +18 -17
- package/dist/seo/index.d.mts +1 -1
- package/dist/{seo-BGCyDlkb.mjs → seo-BTzb5ksq.mjs} +2 -2
- package/dist/{seo-BGCyDlkb.mjs.map → seo-BTzb5ksq.mjs.map} +1 -1
- package/dist/{seo-Dq707mNQ.mjs → seo-DfjLvu8i.mjs} +1 -1
- package/dist/{seo-Dq707mNQ.mjs.map → seo-DfjLvu8i.mjs.map} +1 -1
- package/dist/{service-B0H7U1Y9.mjs → service-Cn-kIfZn.mjs} +3 -3
- package/dist/{service-B0H7U1Y9.mjs.map → service-Cn-kIfZn.mjs.map} +1 -1
- package/dist/{settings-DfwNyQkf.mjs → settings-C65OSm41.mjs} +3 -3
- package/dist/{settings-DfwNyQkf.mjs.map → settings-C65OSm41.mjs.map} +1 -1
- package/dist/{settings-BSXRtTzk.mjs → settings-ChlQbwU0.mjs} +4 -4
- package/dist/{settings-BSXRtTzk.mjs.map → settings-ChlQbwU0.mjs.map} +1 -1
- package/dist/{setup-complete-MzzN9u0b.mjs → setup-complete-VoEZfasi.mjs} +1 -1
- package/dist/{setup-complete-MzzN9u0b.mjs.map → setup-complete-VoEZfasi.mjs.map} +1 -1
- package/dist/{setup-nonce-DXuriHsg.mjs → setup-nonce-Bm0uKqmf.mjs} +1 -1
- package/dist/{setup-nonce-DXuriHsg.mjs.map → setup-nonce-Bm0uKqmf.mjs.map} +1 -1
- package/dist/{site-url-xkhw1tcz.mjs → site-url-Cm8-sJy7.mjs} +1 -1
- package/dist/{site-url-xkhw1tcz.mjs.map → site-url-Cm8-sJy7.mjs.map} +1 -1
- package/dist/{ssrf-MZ-zrG6-.mjs → ssrf-BsVGIE0Z.mjs} +1 -1
- package/dist/{ssrf-MZ-zrG6-.mjs.map → ssrf-BsVGIE0Z.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/{taxonomies-CcvrMLbR.mjs → taxonomies-CgpzAU6F.mjs} +8 -8
- package/dist/{taxonomies-CcvrMLbR.mjs.map → taxonomies-CgpzAU6F.mjs.map} +1 -1
- package/dist/{taxonomies-4vx0nmMr.mjs → taxonomies-D72gTOg_.mjs} +4 -4
- package/dist/{taxonomies-4vx0nmMr.mjs.map → taxonomies-D72gTOg_.mjs.map} +1 -1
- package/dist/{taxonomy-zqGQUqgu.mjs → taxonomy-BBK-UAEo.mjs} +3 -3
- package/dist/{taxonomy-zqGQUqgu.mjs.map → taxonomy-BBK-UAEo.mjs.map} +1 -1
- package/dist/{tokens-N8otWMmj.mjs → tokens-Bx2afeT-.mjs} +1 -1
- package/dist/{tokens-N8otWMmj.mjs.map → tokens-Bx2afeT-.mjs.map} +1 -1
- package/dist/{transport-B6CHddbu.mjs → transport--Ck3RBin.mjs} +1 -1
- package/dist/{transport-B6CHddbu.mjs.map → transport--Ck3RBin.mjs.map} +1 -1
- package/dist/{transport-C2MGqtL6.d.mts → transport-OnMNbsIA.d.mts} +1 -1
- package/dist/{transport-C2MGqtL6.d.mts.map → transport-OnMNbsIA.d.mts.map} +1 -1
- package/dist/{trusted-proxy-97pajC2f.mjs → trusted-proxy-B4AfnoAp.mjs} +1 -1
- package/dist/{trusted-proxy-97pajC2f.mjs.map → trusted-proxy-B4AfnoAp.mjs.map} +1 -1
- package/dist/types-D8bhH891.mjs +125 -0
- package/dist/{types-DSZl1Dsv.mjs.map → types-D8bhH891.mjs.map} +1 -1
- package/dist/{types-DGHWRQgr.d.mts → types-DMwSpvcw.d.mts} +2 -2
- package/dist/{types-DGHWRQgr.d.mts.map → types-DMwSpvcw.d.mts.map} +1 -1
- package/dist/{types-bYmRn_Uy.d.mts → types-DWnN7weG.d.mts} +1 -1
- package/dist/{types-bYmRn_Uy.d.mts.map → types-DWnN7weG.d.mts.map} +1 -1
- package/dist/{types-Dgo6y-Ut.d.mts → types-DX6v9KzJ.d.mts} +1 -1
- package/dist/{types-Dgo6y-Ut.d.mts.map → types-DX6v9KzJ.d.mts.map} +1 -1
- package/dist/{types-DaqNzqVt.d.mts → types-DawhLFwy.d.mts} +35 -1
- package/dist/{types-DaqNzqVt.d.mts.map → types-DawhLFwy.d.mts.map} +1 -1
- package/dist/{types-CpUuGcd5.d.mts → types-DbCWhHet.d.mts} +8 -2
- package/dist/{types-CpUuGcd5.d.mts.map → types-DbCWhHet.d.mts.map} +1 -1
- package/dist/{types-Cd9UCu3t.mjs → types-DpFmlNyB.mjs} +1 -1
- package/dist/{types-Cd9UCu3t.mjs.map → types-DpFmlNyB.mjs.map} +1 -1
- package/dist/{types-D599-ruj.d.mts → types-Qa7-HJJC.d.mts} +1 -1
- package/dist/{types-D599-ruj.d.mts.map → types-Qa7-HJJC.d.mts.map} +1 -1
- package/dist/{types-B0bmgwMG.mjs → types-SF1DwGf2.mjs} +2 -2
- package/dist/types-SF1DwGf2.mjs.map +1 -0
- package/dist/{types-DaYDYW6g.d.mts → types-i8_uzhMD.d.mts} +40 -2
- package/dist/types-i8_uzhMD.d.mts.map +1 -0
- package/dist/{types-CkDSF81F.d.mts → types-kwqCOUxj.d.mts} +1 -1
- package/dist/{types-CkDSF81F.d.mts.map → types-kwqCOUxj.d.mts.map} +1 -1
- package/dist/{user-hUSOaIJy.mjs → user-X4rtyO4Y.mjs} +2 -2
- package/dist/{user-hUSOaIJy.mjs.map → user-X4rtyO4Y.mjs.map} +1 -1
- package/dist/{utils-C3wTAP-P.mjs → utils-C4Ih4DML.mjs} +1 -1
- package/dist/{utils-C3wTAP-P.mjs.map → utils-C4Ih4DML.mjs.map} +1 -1
- package/dist/{validate-IGltez8n.mjs → validate-DactmcJG.mjs} +23 -3
- package/dist/validate-DactmcJG.mjs.map +1 -0
- package/dist/{validate-DQtHw9NT.d.mts → validate-Dy6nkNls.d.mts} +25 -5
- package/dist/{validate-DQtHw9NT.d.mts.map → validate-Dy6nkNls.d.mts.map} +1 -1
- package/dist/{validation-Bmymau7y.mjs → validation-BYA4i85b.mjs} +6 -6
- package/dist/{validation-Bmymau7y.mjs.map → validation-BYA4i85b.mjs.map} +1 -1
- package/dist/version-FGcv0ooe.mjs +7 -0
- package/dist/{version-BTc87L3L.mjs.map → version-FGcv0ooe.mjs.map} +1 -1
- package/dist/{widgets-yHQa4c6c.mjs → widgets-DG-1jxnz.mjs} +3 -3
- package/dist/{widgets-yHQa4c6c.mjs.map → widgets-DG-1jxnz.mjs.map} +1 -1
- package/dist/{zod-generator-B80aap1J.mjs → zod-generator-BNAObjSt.mjs} +3 -3
- package/dist/{zod-generator-B80aap1J.mjs.map → zod-generator-BNAObjSt.mjs.map} +1 -1
- package/package.json +7 -7
- package/src/api/errors.ts +7 -0
- package/src/api/handlers/byline-fields.ts +212 -0
- package/src/api/handlers/bylines.ts +126 -5
- package/src/api/handlers/content.ts +43 -2
- package/src/api/handlers/media.ts +2 -0
- package/src/api/openapi/document.ts +3 -0
- package/src/api/schemas/byline-fields.ts +188 -0
- package/src/api/schemas/bylines.ts +42 -0
- package/src/api/schemas/content.ts +2 -0
- package/src/api/schemas/index.ts +1 -0
- package/src/api/schemas/media.ts +2 -0
- package/src/astro/integration/routes.ts +27 -0
- package/src/astro/middleware/redirect.ts +5 -1
- package/src/astro/routes/api/admin/byline-fields/[slug]/usage.ts +36 -0
- package/src/astro/routes/api/admin/byline-fields/[slug].ts +92 -0
- package/src/astro/routes/api/admin/byline-fields/index.ts +66 -0
- package/src/astro/routes/api/admin/byline-fields/reorder.ts +39 -0
- package/src/astro/routes/api/admin/bylines/[id]/index.ts +23 -21
- package/src/astro/routes/api/admin/bylines/index.ts +1 -0
- package/src/astro/routes/api/auth/me.ts +21 -10
- package/src/astro/routes/api/content/[collection]/[id]/terms/[taxonomy].ts +15 -3
- package/src/astro/routes/api/content/[collection]/[id].ts +3 -1
- package/src/astro/routes/api/media.ts +1 -0
- package/src/astro/types.ts +1 -0
- package/src/bylines/field-defs-cache.ts +138 -0
- package/src/bylines/index.ts +37 -4
- package/src/cli/commands/content.ts +4 -2
- package/src/client/index.ts +4 -1
- package/src/components/InlinePortableTextEditor.tsx +69 -0
- package/src/content/converters/portable-text-to-prosemirror.ts +7 -0
- package/src/content/converters/prosemirror-to-portable-text.ts +16 -0
- package/src/content/converters/types.ts +10 -0
- package/src/database/migrations/041_content_locale_list_index.ts +47 -0
- package/src/database/migrations/042_byline_fields.ts +157 -0
- package/src/database/migrations/runner.ts +4 -0
- package/src/database/repositories/byline.ts +758 -50
- package/src/database/repositories/content.ts +43 -3
- package/src/database/repositories/media.ts +14 -0
- package/src/database/repositories/types.ts +38 -0
- package/src/database/types.ts +44 -0
- package/src/emdash-runtime.ts +4 -1
- package/src/index.ts +1 -0
- package/src/loader.ts +98 -10
- package/src/mcp/server.ts +10 -1
- package/src/request-cache.ts +23 -0
- package/src/schema/byline-registry.ts +671 -0
- package/src/schema/registry.ts +14 -0
- package/src/schema/types.ts +133 -0
- package/src/seed/apply.ts +101 -14
- package/src/seed/types.ts +21 -0
- package/src/seed/validate.ts +39 -0
- package/dist/api-BNKqxyFX.mjs.map +0 -1
- package/dist/apply-BOPaD-s9.mjs.map +0 -1
- package/dist/byline-BDylH_m4.mjs +0 -404
- package/dist/byline-BDylH_m4.mjs.map +0 -1
- package/dist/bylines-B2_XmnSU.d.mts.map +0 -1
- package/dist/bylines-B7TFEvFf.mjs +0 -118
- package/dist/bylines-B7TFEvFf.mjs.map +0 -1
- package/dist/content-8voQNTXX.mjs.map +0 -1
- package/dist/error-ChfADBuu.mjs.map +0 -1
- package/dist/index-BPZFAcgE.d.mts.map +0 -1
- package/dist/loader-D-vIJjfY.mjs.map +0 -1
- package/dist/media-CKQd8AYU.mjs.map +0 -1
- package/dist/menus-C-nWT5Tu.mjs.map +0 -1
- package/dist/redirects-COMLwsV5.mjs.map +0 -1
- package/dist/runner-Drnvs96u.mjs.map +0 -1
- package/dist/setup-Cf_TyOv5.mjs +0 -137
- package/dist/setup-Cf_TyOv5.mjs.map +0 -1
- package/dist/types-B0bmgwMG.mjs.map +0 -1
- package/dist/types-DSZl1Dsv.mjs +0 -83
- package/dist/types-DaYDYW6g.d.mts.map +0 -1
- package/dist/validate-IGltez8n.mjs.map +0 -1
- package/dist/version-BTc87L3L.mjs +0 -7
- /package/dist/{api-tokens-iPIHAY8N.mjs → api-tokens-B6VgoE6M.mjs} +0 -0
- /package/dist/{ssrf-BIcd-aXW.mjs → ssrf-BvgVcfNQ.mjs} +0 -0
- /package/dist/{types-1NNkmTIn.mjs → types-Cj2S6FuC.mjs} +0 -0
|
@@ -1,11 +1,57 @@
|
|
|
1
1
|
import type { Kysely } from "kysely";
|
|
2
2
|
|
|
3
|
-
import {
|
|
4
|
-
|
|
3
|
+
import {
|
|
4
|
+
BylineRepository,
|
|
5
|
+
type CreateBylineInput,
|
|
6
|
+
type UpdateBylineInput,
|
|
7
|
+
} from "../../database/repositories/byline.js";
|
|
8
|
+
import { EmDashValidationError, type BylineSummary } from "../../database/repositories/types.js";
|
|
5
9
|
import type { Database } from "../../database/types.js";
|
|
6
10
|
import { getI18nConfig } from "../../i18n/config.js";
|
|
7
11
|
import type { ApiResult } from "../types.js";
|
|
8
12
|
|
|
13
|
+
// `undefined → null` so a missing field in the create payload matches the
|
|
14
|
+
// repo's stored `null` (BylineRepository normalises with `?? null` on write).
|
|
15
|
+
const norm = (v: string | null | undefined): string | null => v ?? null;
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Whether the existing byline row's fixed columns match a fresh-create
|
|
19
|
+
* payload after null/undefined normalisation. Used by the D1 create-retry
|
|
20
|
+
* recovery branch.
|
|
21
|
+
*/
|
|
22
|
+
function bylineFixedFieldsMatch(
|
|
23
|
+
existing: BylineSummary,
|
|
24
|
+
input: CreateBylineInput,
|
|
25
|
+
effectiveLocale: string,
|
|
26
|
+
): boolean {
|
|
27
|
+
return (
|
|
28
|
+
existing.displayName === input.displayName &&
|
|
29
|
+
norm(existing.bio) === norm(input.bio) &&
|
|
30
|
+
norm(existing.avatarMediaId) === norm(input.avatarMediaId) &&
|
|
31
|
+
norm(existing.websiteUrl) === norm(input.websiteUrl) &&
|
|
32
|
+
norm(existing.userId) === norm(input.userId) &&
|
|
33
|
+
existing.isGuest === (input.isGuest ?? false) &&
|
|
34
|
+
existing.locale === effectiveLocale
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Whether every key in `existing` appears in `input` with the same value.
|
|
40
|
+
* Allows `input` to contain additional keys (the partial-write recovery
|
|
41
|
+
* case); rejects on a divergent value or a key the input omits.
|
|
42
|
+
*/
|
|
43
|
+
function existingCustomFieldsAreSubsetOf(
|
|
44
|
+
existing: Record<string, unknown>,
|
|
45
|
+
input: Record<string, unknown> | undefined,
|
|
46
|
+
): boolean {
|
|
47
|
+
if (!input) return Object.keys(existing).length === 0;
|
|
48
|
+
for (const [slug, value] of Object.entries(existing)) {
|
|
49
|
+
if (!Object.hasOwn(input, slug)) return false;
|
|
50
|
+
if (input[slug] !== value) return false;
|
|
51
|
+
}
|
|
52
|
+
return true;
|
|
53
|
+
}
|
|
54
|
+
|
|
9
55
|
/**
|
|
10
56
|
* Reject locales the site doesn't configure. Returns `null` when the locale
|
|
11
57
|
* is fine (omitted, or matches `locales` in the i18n config, or i18n isn't
|
|
@@ -135,10 +181,30 @@ export async function handleBylineCreate(
|
|
|
135
181
|
}
|
|
136
182
|
|
|
137
183
|
// Duplicate guard: same (slug, locale) — matches the DB unique key
|
|
138
|
-
//
|
|
139
|
-
// when the caller omits `locale`, mirroring the column DEFAULT.
|
|
184
|
+
// from migration 040.
|
|
140
185
|
const existing = await repo.findBySlug(input.slug, { locale: effectiveLocale });
|
|
141
186
|
if (existing) {
|
|
187
|
+
// D1 has no transactions, so a crash between the byline insert
|
|
188
|
+
// and the per-field writes leaves a partial row that's
|
|
189
|
+
// otherwise unrecoverable. Treat a same-identity retry that
|
|
190
|
+
// provides customFields as completing the abandoned create.
|
|
191
|
+
// Recovery requires fixed-column + translation-group +
|
|
192
|
+
// subset-customFields match; anything else collapses to a
|
|
193
|
+
// standard duplicate-slug conflict.
|
|
194
|
+
const expectedTranslationGroup = sourceGroup ?? existing.id;
|
|
195
|
+
const inputHasFields = !!input.customFields && Object.keys(input.customFields).length > 0;
|
|
196
|
+
if (
|
|
197
|
+
inputHasFields &&
|
|
198
|
+
bylineFixedFieldsMatch(existing, input, effectiveLocale) &&
|
|
199
|
+
existing.translationGroup === expectedTranslationGroup &&
|
|
200
|
+
existingCustomFieldsAreSubsetOf(existing.customFields ?? {}, input.customFields)
|
|
201
|
+
) {
|
|
202
|
+
const recovered = await repo.update(existing.id, {
|
|
203
|
+
customFields: input.customFields,
|
|
204
|
+
});
|
|
205
|
+
if (recovered) return { success: true, data: recovered };
|
|
206
|
+
}
|
|
207
|
+
|
|
142
208
|
return {
|
|
143
209
|
success: false,
|
|
144
210
|
error: {
|
|
@@ -152,10 +218,65 @@ export async function handleBylineCreate(
|
|
|
152
218
|
|
|
153
219
|
const byline = await repo.create(input);
|
|
154
220
|
return { success: true, data: byline };
|
|
155
|
-
} catch {
|
|
221
|
+
} catch (error) {
|
|
222
|
+
// Mirror handleBylineUpdate: surface customFields validation
|
|
223
|
+
// errors as 400 rather than swallowing them as a generic 500.
|
|
224
|
+
if (error instanceof EmDashValidationError) {
|
|
225
|
+
return {
|
|
226
|
+
success: false,
|
|
227
|
+
error: { code: "VALIDATION_ERROR", message: error.message },
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
console.error("[BYLINE_CREATE_ERROR]", error);
|
|
156
231
|
return {
|
|
157
232
|
success: false,
|
|
158
233
|
error: { code: "BYLINE_CREATE_ERROR", message: "Failed to create byline" },
|
|
159
234
|
};
|
|
160
235
|
}
|
|
161
236
|
}
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* Update an existing byline. Forwards every field on `UpdateBylineInput`
|
|
240
|
+
* to `BylineRepository.update`, including the Phase 3 `customFields`
|
|
241
|
+
* map; per-field type validation lives in the repo, which throws
|
|
242
|
+
* `EmDashValidationError` on unknown slugs, type mismatches, or
|
|
243
|
+
* `select`-choice misses. This handler translates that into a clean
|
|
244
|
+
* `VALIDATION_ERROR` (400 via `mapErrorStatus`).
|
|
245
|
+
*
|
|
246
|
+
* Returns `NOT_FOUND` when the byline id doesn't resolve. Generic
|
|
247
|
+
* failures surface as `BYLINE_UPDATE_ERROR` (500) without leaking the
|
|
248
|
+
* underlying message.
|
|
249
|
+
*/
|
|
250
|
+
export async function handleBylineUpdate(
|
|
251
|
+
db: Kysely<Database>,
|
|
252
|
+
id: string,
|
|
253
|
+
input: UpdateBylineInput,
|
|
254
|
+
): Promise<ApiResult<BylineSummary>> {
|
|
255
|
+
try {
|
|
256
|
+
const repo = new BylineRepository(db);
|
|
257
|
+
const byline = await repo.update(id, input);
|
|
258
|
+
if (!byline) {
|
|
259
|
+
return {
|
|
260
|
+
success: false,
|
|
261
|
+
error: { code: "NOT_FOUND", message: "Byline not found" },
|
|
262
|
+
};
|
|
263
|
+
}
|
|
264
|
+
return { success: true, data: byline };
|
|
265
|
+
} catch (error) {
|
|
266
|
+
// Unknown-key + type-mismatch + select-choice writes throw
|
|
267
|
+
// EmDashValidationError (Phase 3, see BylineRepository.update).
|
|
268
|
+
// Map to a clean 400 — the error message names the offending
|
|
269
|
+
// slug/type, which is safe to surface to the admin client.
|
|
270
|
+
if (error instanceof EmDashValidationError) {
|
|
271
|
+
return {
|
|
272
|
+
success: false,
|
|
273
|
+
error: { code: "VALIDATION_ERROR", message: error.message },
|
|
274
|
+
};
|
|
275
|
+
}
|
|
276
|
+
console.error("[BYLINE_UPDATE_ERROR]", error);
|
|
277
|
+
return {
|
|
278
|
+
success: false,
|
|
279
|
+
error: { code: "BYLINE_UPDATE_ERROR", message: "Failed to update byline" },
|
|
280
|
+
};
|
|
281
|
+
}
|
|
282
|
+
}
|
|
@@ -295,6 +295,34 @@ export interface TrashedContentItem {
|
|
|
295
295
|
deletedAt: string;
|
|
296
296
|
}
|
|
297
297
|
|
|
298
|
+
/**
|
|
299
|
+
* Resolve the columns a content-list search should match against. Always
|
|
300
|
+
* includes `slug` (a standard column) and adds the `title`/`name` display
|
|
301
|
+
* fields when the collection actually defines them, mirroring the admin's
|
|
302
|
+
* item-title resolution (title -> name -> slug). Returning only existing
|
|
303
|
+
* columns avoids "no such column" errors on collections without them.
|
|
304
|
+
*/
|
|
305
|
+
async function resolveSearchColumns(db: Kysely<Database>, collection: string): Promise<string[]> {
|
|
306
|
+
const columns = ["slug"];
|
|
307
|
+
const row = await db
|
|
308
|
+
.selectFrom("_emdash_collections")
|
|
309
|
+
.select("id")
|
|
310
|
+
.where("slug", "=", collection)
|
|
311
|
+
.executeTakeFirst();
|
|
312
|
+
if (!row) return columns;
|
|
313
|
+
|
|
314
|
+
const fields = await db
|
|
315
|
+
.selectFrom("_emdash_fields")
|
|
316
|
+
.select("slug")
|
|
317
|
+
.where("collection_id", "=", row.id)
|
|
318
|
+
.execute();
|
|
319
|
+
const fieldSlugs = new Set(fields.map((f) => f.slug));
|
|
320
|
+
for (const candidate of ["title", "name"]) {
|
|
321
|
+
if (fieldSlugs.has(candidate)) columns.push(candidate);
|
|
322
|
+
}
|
|
323
|
+
return columns;
|
|
324
|
+
}
|
|
325
|
+
|
|
298
326
|
/**
|
|
299
327
|
* Create content list handler
|
|
300
328
|
*/
|
|
@@ -308,14 +336,26 @@ export async function handleContentList(
|
|
|
308
336
|
orderBy?: string;
|
|
309
337
|
order?: "asc" | "desc";
|
|
310
338
|
locale?: string;
|
|
339
|
+
q?: string;
|
|
311
340
|
},
|
|
312
341
|
): Promise<ApiResult<ContentListResponse>> {
|
|
313
342
|
try {
|
|
314
343
|
const repo = new ContentRepository(db);
|
|
315
|
-
const where: {
|
|
344
|
+
const where: {
|
|
345
|
+
status?: string;
|
|
346
|
+
locale?: string;
|
|
347
|
+
q?: string;
|
|
348
|
+
searchColumns?: string[];
|
|
349
|
+
} = {};
|
|
316
350
|
if (params.status) where.status = params.status;
|
|
317
351
|
if (params.locale) where.locale = params.locale;
|
|
318
352
|
|
|
353
|
+
const q = params.q?.trim();
|
|
354
|
+
if (q) {
|
|
355
|
+
where.q = q;
|
|
356
|
+
where.searchColumns = await resolveSearchColumns(db, collection);
|
|
357
|
+
}
|
|
358
|
+
|
|
319
359
|
const result = await repo.findMany(collection, {
|
|
320
360
|
cursor: params.cursor,
|
|
321
361
|
limit: params.limit || 50,
|
|
@@ -655,6 +695,7 @@ export async function handleContentUpdate(
|
|
|
655
695
|
status?: string;
|
|
656
696
|
authorId?: string | null;
|
|
657
697
|
bylines?: ContentBylineInput[];
|
|
698
|
+
locale?: string;
|
|
658
699
|
_rev?: string;
|
|
659
700
|
seo?: ContentSeoInput;
|
|
660
701
|
publishedAt?: string | null;
|
|
@@ -682,7 +723,7 @@ export async function handleContentUpdate(
|
|
|
682
723
|
const repo = new ContentRepository(db);
|
|
683
724
|
|
|
684
725
|
// Resolve slug → ID if needed
|
|
685
|
-
const resolvedId = (await resolveId(repo, collection, id)) ?? id;
|
|
726
|
+
const resolvedId = (await resolveId(repo, collection, id, body.locale)) ?? id;
|
|
686
727
|
|
|
687
728
|
// Wrap content + SEO writes in a transaction for atomicity.
|
|
688
729
|
// The _rev check is inside the transaction so the read-then-write
|
|
@@ -27,6 +27,7 @@ export async function handleMediaList(
|
|
|
27
27
|
cursor?: string;
|
|
28
28
|
limit?: number;
|
|
29
29
|
mimeType?: string | readonly string[];
|
|
30
|
+
q?: string;
|
|
30
31
|
},
|
|
31
32
|
): Promise<ApiResult<MediaListResponse>> {
|
|
32
33
|
try {
|
|
@@ -35,6 +36,7 @@ export async function handleMediaList(
|
|
|
35
36
|
cursor: params.cursor,
|
|
36
37
|
limit: Math.min(params.limit || 50, 100),
|
|
37
38
|
mimeType: params.mimeType,
|
|
39
|
+
q: params.q,
|
|
38
40
|
});
|
|
39
41
|
|
|
40
42
|
return {
|
|
@@ -257,6 +257,9 @@ const contentPaths = {
|
|
|
257
257
|
collection: z.string().meta({ description: "Collection slug" }),
|
|
258
258
|
id: z.string().meta({ description: "Content ID or slug" }),
|
|
259
259
|
}),
|
|
260
|
+
query: z.object({
|
|
261
|
+
locale: z.string().optional().meta({ description: "Locale filter" }),
|
|
262
|
+
}),
|
|
260
263
|
},
|
|
261
264
|
requestBody: {
|
|
262
265
|
content: { [JSON_CONTENT]: { schema: contentUpdateBody } },
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Zod schemas for the byline-fields admin API (Discussion #1174, Phase 4).
|
|
3
|
+
*
|
|
4
|
+
* Reserved-slug + identifier validation runs at the zod layer so the
|
|
5
|
+
* route returns a clean 400 (`VALIDATION_ERROR` from `parseBody`) rather
|
|
6
|
+
* than bubbling a registry-level `BylineSchemaError` ("RESERVED_SLUG" /
|
|
7
|
+
* "INVALID_SLUG"). The registry repeats the same checks for non-HTTP
|
|
8
|
+
* callers (seeds, scripts) — see `BylineSchemaRegistry.validateSlug`.
|
|
9
|
+
*
|
|
10
|
+
* Field types are constrained to the v1 subset declared in
|
|
11
|
+
* `BYLINE_FIELD_TYPES`. Adding a type to the union there will require a
|
|
12
|
+
* corresponding update to this enum.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import { z } from "zod";
|
|
16
|
+
|
|
17
|
+
import { BYLINE_FIELD_TYPES, RESERVED_BYLINE_FIELD_SLUGS } from "../../schema/types.js";
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Slug pattern for byline field definitions — matches the identifier rule
|
|
21
|
+
* used by `validateIdentifier` (and `slugPattern` in `common.ts`).
|
|
22
|
+
* Lowercase letters, digits, and underscores; must start with a letter.
|
|
23
|
+
*/
|
|
24
|
+
const bylineFieldSlugPattern = /^[a-z][a-z0-9_]*$/;
|
|
25
|
+
|
|
26
|
+
/** Hard cap on a slug — mirrors `BylineSchemaRegistry.MAX_SLUG_LENGTH`. */
|
|
27
|
+
const MAX_SLUG_LENGTH = 63;
|
|
28
|
+
/** Hard cap on a label — mirrors `BylineSchemaRegistry.MAX_LABEL_LENGTH`. */
|
|
29
|
+
const MAX_LABEL_LENGTH = 200;
|
|
30
|
+
/** Hard cap on a select field's `options` list. */
|
|
31
|
+
const MAX_SELECT_OPTIONS = 200;
|
|
32
|
+
|
|
33
|
+
const RESERVED_SET: ReadonlySet<string> = new Set(RESERVED_BYLINE_FIELD_SLUGS);
|
|
34
|
+
|
|
35
|
+
// Enumerate the v1 byline field types explicitly so zod gets the exact
|
|
36
|
+
// literal union for `z.infer<>`. Mirrors `BYLINE_FIELD_TYPES`; CI's
|
|
37
|
+
// type-checker catches drift via the satisfies/import below.
|
|
38
|
+
const bylineFieldTypeValues = z.enum(["string", "text", "url", "boolean", "select"]);
|
|
39
|
+
// Compile-time guard: a drift here trips the satisfies check.
|
|
40
|
+
type _BylineFieldTypeDriftCheck =
|
|
41
|
+
(typeof BYLINE_FIELD_TYPES)[number] extends z.infer<typeof bylineFieldTypeValues>
|
|
42
|
+
? z.infer<typeof bylineFieldTypeValues> extends (typeof BYLINE_FIELD_TYPES)[number]
|
|
43
|
+
? true
|
|
44
|
+
: never
|
|
45
|
+
: never;
|
|
46
|
+
const _bylineFieldTypeDriftCheck: _BylineFieldTypeDriftCheck = true;
|
|
47
|
+
void _bylineFieldTypeDriftCheck;
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Validation payload for a byline custom field. v1 only exposes
|
|
51
|
+
* `options` (used by `select`-type fields). Empty/duplicate options are
|
|
52
|
+
* rejected at the registry layer; the zod layer only enforces shape and
|
|
53
|
+
* caps. Future field types may add keys here.
|
|
54
|
+
*/
|
|
55
|
+
const bylineFieldValidationSchema = z
|
|
56
|
+
.object({
|
|
57
|
+
options: z
|
|
58
|
+
.array(z.string().min(1))
|
|
59
|
+
.min(1, "select options must contain at least one entry")
|
|
60
|
+
.max(MAX_SELECT_OPTIONS, `select options cannot exceed ${MAX_SELECT_OPTIONS} entries`)
|
|
61
|
+
.optional(),
|
|
62
|
+
})
|
|
63
|
+
.strict()
|
|
64
|
+
.nullable();
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Slug validation chain shared by create + reorder bodies. Centralised so
|
|
68
|
+
* the reserved-slug message and pattern are identical everywhere.
|
|
69
|
+
*/
|
|
70
|
+
const bylineFieldSlug = z
|
|
71
|
+
.string()
|
|
72
|
+
.min(1, "Byline field slug is required")
|
|
73
|
+
.max(MAX_SLUG_LENGTH, `Byline field slug must be ${MAX_SLUG_LENGTH} characters or less`)
|
|
74
|
+
.regex(
|
|
75
|
+
bylineFieldSlugPattern,
|
|
76
|
+
"Byline field slug must contain only lowercase letters, digits, and underscores, and start with a letter",
|
|
77
|
+
)
|
|
78
|
+
.refine((slug) => !RESERVED_SET.has(slug), {
|
|
79
|
+
// Surface the offending slug in the validation issue path-message
|
|
80
|
+
// for easier debugging from the admin UI's error toast.
|
|
81
|
+
message: "Byline field slug is reserved",
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
const bylineFieldLabel = z
|
|
85
|
+
.string()
|
|
86
|
+
.min(1, "Byline field label is required")
|
|
87
|
+
.max(MAX_LABEL_LENGTH, `Byline field label must be ${MAX_LABEL_LENGTH} characters or less`);
|
|
88
|
+
|
|
89
|
+
// ---------------------------------------------------------------------------
|
|
90
|
+
// Request bodies
|
|
91
|
+
// ---------------------------------------------------------------------------
|
|
92
|
+
|
|
93
|
+
export const bylineFieldCreateBody = z
|
|
94
|
+
.object({
|
|
95
|
+
slug: bylineFieldSlug,
|
|
96
|
+
label: bylineFieldLabel,
|
|
97
|
+
type: bylineFieldTypeValues,
|
|
98
|
+
required: z.boolean().optional(),
|
|
99
|
+
/**
|
|
100
|
+
* Whether values are stored per-locale (translatable, default) or
|
|
101
|
+
* shared across the translation group. See `BylineFieldDefinition`.
|
|
102
|
+
*/
|
|
103
|
+
translatable: z.boolean().optional(),
|
|
104
|
+
validation: bylineFieldValidationSchema.optional(),
|
|
105
|
+
sortOrder: z.number().int().min(0).optional(),
|
|
106
|
+
})
|
|
107
|
+
.strict()
|
|
108
|
+
.meta({ id: "BylineFieldCreateBody" });
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Update body. `slug` and `type` are intentionally absent — both are
|
|
112
|
+
* immutable post-create (changing them would invalidate stored values).
|
|
113
|
+
* `translatable` flips are gated at the registry layer when value rows
|
|
114
|
+
* exist (`TRANSLATABLE_LOCKED`).
|
|
115
|
+
*/
|
|
116
|
+
export const bylineFieldUpdateBody = z
|
|
117
|
+
.object({
|
|
118
|
+
label: bylineFieldLabel.optional(),
|
|
119
|
+
required: z.boolean().optional(),
|
|
120
|
+
translatable: z.boolean().optional(),
|
|
121
|
+
validation: bylineFieldValidationSchema.optional(),
|
|
122
|
+
sortOrder: z.number().int().min(0).optional(),
|
|
123
|
+
})
|
|
124
|
+
.strict()
|
|
125
|
+
.meta({ id: "BylineFieldUpdateBody" });
|
|
126
|
+
|
|
127
|
+
export const bylineFieldReorderBody = z
|
|
128
|
+
.object({
|
|
129
|
+
/**
|
|
130
|
+
* Exact set of currently registered slugs in the desired order.
|
|
131
|
+
* The registry rejects any drift (`REORDER_MISMATCH`); the zod
|
|
132
|
+
* layer enforces slug shape only. An empty array is permitted —
|
|
133
|
+
* `reorderFields([])` is a valid no-op when zero fields are
|
|
134
|
+
* registered (registry contract). Rejecting empty here would
|
|
135
|
+
* produce a spurious 400 for an admin UI that submits a reorder
|
|
136
|
+
* after deleting the last field.
|
|
137
|
+
*/
|
|
138
|
+
slugs: z.array(bylineFieldSlug),
|
|
139
|
+
})
|
|
140
|
+
.strict()
|
|
141
|
+
.meta({ id: "BylineFieldReorderBody" });
|
|
142
|
+
|
|
143
|
+
// ---------------------------------------------------------------------------
|
|
144
|
+
// Response shapes
|
|
145
|
+
// ---------------------------------------------------------------------------
|
|
146
|
+
|
|
147
|
+
export const bylineFieldDefinitionSchema = z
|
|
148
|
+
.object({
|
|
149
|
+
id: z.string(),
|
|
150
|
+
slug: z.string(),
|
|
151
|
+
label: z.string(),
|
|
152
|
+
type: bylineFieldTypeValues,
|
|
153
|
+
required: z.boolean(),
|
|
154
|
+
translatable: z.boolean(),
|
|
155
|
+
validation: z
|
|
156
|
+
.object({
|
|
157
|
+
options: z.array(z.string()).optional(),
|
|
158
|
+
})
|
|
159
|
+
.nullable(),
|
|
160
|
+
sortOrder: z.number().int(),
|
|
161
|
+
createdAt: z.string(),
|
|
162
|
+
updatedAt: z.string(),
|
|
163
|
+
})
|
|
164
|
+
.meta({ id: "BylineFieldDefinition" });
|
|
165
|
+
|
|
166
|
+
export const bylineFieldListResponseSchema = z
|
|
167
|
+
.object({
|
|
168
|
+
items: z.array(bylineFieldDefinitionSchema),
|
|
169
|
+
})
|
|
170
|
+
.meta({ id: "BylineFieldListResponse" });
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Response shape for `GET /api/admin/byline-fields/[slug]/usage`.
|
|
174
|
+
*
|
|
175
|
+
* `translatableValueCount` counts rows in `_emdash_byline_field_values`.
|
|
176
|
+
* `groupValueCount` counts rows in `_emdash_byline_field_group_values`.
|
|
177
|
+
* `totalAffectedRows` is the sum — what the destructive-delete confirm
|
|
178
|
+
* dialog surfaces. Both individual counts are exposed for diagnostic
|
|
179
|
+
* value (e.g. inconsistency with the field's current `translatable`
|
|
180
|
+
* flag would show non-zero on the "wrong" side).
|
|
181
|
+
*/
|
|
182
|
+
export const bylineFieldUsageResponseSchema = z
|
|
183
|
+
.object({
|
|
184
|
+
translatableValueCount: z.number().int().nonnegative(),
|
|
185
|
+
groupValueCount: z.number().int().nonnegative(),
|
|
186
|
+
totalAffectedRows: z.number().int().nonnegative(),
|
|
187
|
+
})
|
|
188
|
+
.meta({ id: "BylineFieldUsageResponse" });
|
|
@@ -12,6 +12,13 @@ export const bylineSummarySchema = z
|
|
|
12
12
|
displayName: z.string(),
|
|
13
13
|
bio: z.string().nullable(),
|
|
14
14
|
avatarMediaId: z.string().nullable(),
|
|
15
|
+
/**
|
|
16
|
+
* Avatar media storage key + alt, folded in by the media join during
|
|
17
|
+
* content byline hydration. Null on the plain byline finders, which
|
|
18
|
+
* don't join media.
|
|
19
|
+
*/
|
|
20
|
+
avatarStorageKey: z.string().nullish(),
|
|
21
|
+
avatarAlt: z.string().nullish(),
|
|
15
22
|
websiteUrl: z.string().nullable(),
|
|
16
23
|
userId: z.string().nullable(),
|
|
17
24
|
isGuest: z.boolean(),
|
|
@@ -25,6 +32,16 @@ export const bylineSummarySchema = z
|
|
|
25
32
|
* source. Nullable in storage for backwards compatibility.
|
|
26
33
|
*/
|
|
27
34
|
translationGroup: z.string().nullable(),
|
|
35
|
+
/**
|
|
36
|
+
* Byline custom-field values (Discussion #1174). Keys are slugs
|
|
37
|
+
* registered via the byline-fields admin API; values follow
|
|
38
|
+
* `CustomFieldValue` (`string | boolean | null`). Always present
|
|
39
|
+
* on hydrated responses — empty `{}` when no fields are
|
|
40
|
+
* registered (Phase 3 AC #6). Marked optional in the schema for
|
|
41
|
+
* historic-payload compatibility with pre-Phase-3 clients that
|
|
42
|
+
* may not send the key on writes; hydration always populates it.
|
|
43
|
+
*/
|
|
44
|
+
customFields: z.record(z.string(), z.union([z.string(), z.boolean(), z.null()])).optional(),
|
|
28
45
|
})
|
|
29
46
|
.meta({ id: "BylineSummary" });
|
|
30
47
|
|
|
@@ -83,6 +100,19 @@ export const bylineCreateBody = z
|
|
|
83
100
|
* rather than minting a fresh one. Requires `locale`.
|
|
84
101
|
*/
|
|
85
102
|
translationOf: z.string().min(1).optional(),
|
|
103
|
+
/**
|
|
104
|
+
* Byline custom-field values (Discussion #1174, Phase 6 — create-flow
|
|
105
|
+
* parity with update). Keys are field slugs; values are unknown at
|
|
106
|
+
* the API layer because the per-field type contract lives in the
|
|
107
|
+
* registry and would require an extra query to enforce here. The
|
|
108
|
+
* repository's `coerceFieldValue` validates against the field's
|
|
109
|
+
* type and throws `EmDashValidationError` on mismatch — the route
|
|
110
|
+
* maps that to a 400 `VALIDATION_ERROR`. Reserved-slug write
|
|
111
|
+
* attempts fall out as `EmDashValidationError("Unknown byline
|
|
112
|
+
* custom field …")` because no registered field claims a reserved
|
|
113
|
+
* slug.
|
|
114
|
+
*/
|
|
115
|
+
customFields: z.record(z.string(), z.unknown()).optional(),
|
|
86
116
|
})
|
|
87
117
|
.meta({ id: "BylineCreateBody" });
|
|
88
118
|
|
|
@@ -120,6 +150,18 @@ export const bylineUpdateBody = z
|
|
|
120
150
|
websiteUrl: httpUrl.nullish(),
|
|
121
151
|
userId: z.string().nullish(),
|
|
122
152
|
isGuest: z.boolean().optional(),
|
|
153
|
+
/**
|
|
154
|
+
* Byline custom-field values (Discussion #1174, Phase 3+4). Keys
|
|
155
|
+
* are field slugs; values are unknown at the API layer because
|
|
156
|
+
* the per-field type contract lives in the registry and would
|
|
157
|
+
* require an extra query to enforce here. The repository's
|
|
158
|
+
* `coerceFieldValue` validates against the field's type and
|
|
159
|
+
* throws `EmDashValidationError` on mismatch — the route maps
|
|
160
|
+
* that to a 400 `VALIDATION_ERROR`. Reserved-slug write attempts
|
|
161
|
+
* fall out as `EmDashValidationError("Unknown byline custom
|
|
162
|
+
* field …")` because no registered field claims a reserved slug.
|
|
163
|
+
*/
|
|
164
|
+
customFields: z.record(z.string(), z.unknown()).optional(),
|
|
123
165
|
})
|
|
124
166
|
.meta({ id: "BylineUpdateBody" });
|
|
125
167
|
|
|
@@ -24,6 +24,8 @@ export const contentListQuery = cursorPaginationQuery
|
|
|
24
24
|
orderBy: z.string().optional(),
|
|
25
25
|
order: z.enum(["asc", "desc"]).optional(),
|
|
26
26
|
locale: localeCode.optional(),
|
|
27
|
+
/** Case-insensitive substring search across the collection's title/name/slug. */
|
|
28
|
+
q: z.string().trim().min(1).max(200).optional(),
|
|
27
29
|
})
|
|
28
30
|
.meta({ id: "ContentListQuery" });
|
|
29
31
|
|
package/src/api/schemas/index.ts
CHANGED
package/src/api/schemas/media.ts
CHANGED
|
@@ -21,6 +21,8 @@ const mimeTypeFilter = z
|
|
|
21
21
|
export const mediaListQuery = cursorPaginationQuery
|
|
22
22
|
.extend({
|
|
23
23
|
mimeType: mimeTypeFilter,
|
|
24
|
+
/** Case-insensitive filename substring search (also matches extensions). */
|
|
25
|
+
q: z.string().trim().min(1).max(200).optional(),
|
|
24
26
|
})
|
|
25
27
|
.meta({ id: "MediaListQuery" });
|
|
26
28
|
|
|
@@ -457,6 +457,33 @@ export function injectCoreRoutes(injectRoute: InjectRoute): void {
|
|
|
457
457
|
entrypoint: resolveRoute("api/admin/bylines/[id]/translations.ts"),
|
|
458
458
|
});
|
|
459
459
|
|
|
460
|
+
// Byline custom-field schema routes (Discussion #1174, Phase 4).
|
|
461
|
+
// Order matters: the static `reorder` route must precede the dynamic
|
|
462
|
+
// `[slug]` route so Astro's resolver dispatches POST /byline-fields/reorder
|
|
463
|
+
// to the reorder handler instead of treating "reorder" as a slug. The
|
|
464
|
+
// `reorder` slug is also reserved at the data layer
|
|
465
|
+
// (RESERVED_BYLINE_FIELD_SLUGS) so the registry rejects field creation
|
|
466
|
+
// with that name — defence in depth.
|
|
467
|
+
injectRoute({
|
|
468
|
+
pattern: "/_emdash/api/admin/byline-fields",
|
|
469
|
+
entrypoint: resolveRoute("api/admin/byline-fields/index.ts"),
|
|
470
|
+
});
|
|
471
|
+
|
|
472
|
+
injectRoute({
|
|
473
|
+
pattern: "/_emdash/api/admin/byline-fields/reorder",
|
|
474
|
+
entrypoint: resolveRoute("api/admin/byline-fields/reorder.ts"),
|
|
475
|
+
});
|
|
476
|
+
|
|
477
|
+
injectRoute({
|
|
478
|
+
pattern: "/_emdash/api/admin/byline-fields/[slug]",
|
|
479
|
+
entrypoint: resolveRoute("api/admin/byline-fields/[slug].ts"),
|
|
480
|
+
});
|
|
481
|
+
|
|
482
|
+
injectRoute({
|
|
483
|
+
pattern: "/_emdash/api/admin/byline-fields/[slug]/usage",
|
|
484
|
+
entrypoint: resolveRoute("api/admin/byline-fields/[slug]/usage.ts"),
|
|
485
|
+
});
|
|
486
|
+
|
|
460
487
|
injectRoute({
|
|
461
488
|
pattern: "/_emdash/api/admin/users/[id]",
|
|
462
489
|
entrypoint: resolveRoute("api/admin/users/[id]/index.ts"),
|
|
@@ -74,7 +74,11 @@ export const onRequest = defineMiddleware(async (context, next) => {
|
|
|
74
74
|
}
|
|
75
75
|
|
|
76
76
|
// 1. Exact match (O(1) Map lookup)
|
|
77
|
-
|
|
77
|
+
let exact = cached.exact.get(pathname);
|
|
78
|
+
if (!exact && pathname.length > 1) {
|
|
79
|
+
const alt = pathname.endsWith("/") ? pathname.slice(0, -1) : `${pathname}/`;
|
|
80
|
+
exact = cached.exact.get(alt);
|
|
81
|
+
}
|
|
78
82
|
if (exact) {
|
|
79
83
|
const dest = exact.destination;
|
|
80
84
|
if (dest.startsWith("//") || dest.startsWith("/\\")) return next();
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Byline field usage counts.
|
|
3
|
+
*
|
|
4
|
+
* GET /_emdash/api/admin/byline-fields/{slug}/usage
|
|
5
|
+
*
|
|
6
|
+
* Returns `{ translatableValueCount, groupValueCount, totalAffectedRows }`.
|
|
7
|
+
* Backs the destructive-delete confirm dialog in the admin UI (Phase 5).
|
|
8
|
+
* Thin wrapper around `handleBylineFieldUsage`.
|
|
9
|
+
*
|
|
10
|
+
* Phase 4 of Discussion #1174.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import type { APIRoute } from "astro";
|
|
14
|
+
|
|
15
|
+
import { requirePerm } from "#api/authorize.js";
|
|
16
|
+
import { apiError, requireDb, unwrapResult } from "#api/error.js";
|
|
17
|
+
import { handleBylineFieldUsage } from "#api/handlers/byline-fields.js";
|
|
18
|
+
|
|
19
|
+
export const prerender = false;
|
|
20
|
+
|
|
21
|
+
// GET requires `schema:read` (Editor+); see byline-fields/index.ts GET
|
|
22
|
+
// for rationale on the read/manage split.
|
|
23
|
+
export const GET: APIRoute = async ({ params, locals }) => {
|
|
24
|
+
const { emdash, user } = locals;
|
|
25
|
+
const denied = requirePerm(user, "schema:read");
|
|
26
|
+
if (denied) return denied;
|
|
27
|
+
|
|
28
|
+
const dbErr = requireDb(emdash?.db);
|
|
29
|
+
if (dbErr) return dbErr;
|
|
30
|
+
|
|
31
|
+
const slug = params.slug;
|
|
32
|
+
if (!slug) return apiError("MISSING_PARAM", "Field slug is required", 400);
|
|
33
|
+
|
|
34
|
+
const result = await handleBylineFieldUsage(emdash.db, slug);
|
|
35
|
+
return unwrapResult(result);
|
|
36
|
+
};
|