emdash 0.36.0 → 0.37.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-CzL3H752.d.mts → adapters-BDQwg236.d.mts} +4 -2
- package/dist/{adapters-CzL3H752.d.mts.map → adapters-BDQwg236.d.mts.map} +1 -1
- package/dist/{allowed-origins-maylGaHv.mjs → allowed-origins-BGglilcs.mjs} +2 -2
- package/dist/{allowed-origins-maylGaHv.mjs.map → allowed-origins-BGglilcs.mjs.map} +1 -1
- package/dist/api/route-utils.d.mts +3 -3
- package/dist/api/route-utils.mjs +17 -17
- package/dist/api/schemas/index.d.mts +2 -2
- package/dist/api/schemas/index.mjs +5 -5
- package/dist/api-Dz6rgoa3.mjs +10040 -0
- package/dist/api-Dz6rgoa3.mjs.map +1 -0
- package/dist/{api-tokens-9YrrCoE6.mjs → api-tokens-BSsQACNe.mjs} +2 -2
- package/dist/{api-tokens-9YrrCoE6.mjs.map → api-tokens-BSsQACNe.mjs.map} +1 -1
- package/dist/{apply-B_VMpJ2P.mjs → apply-B4SIOxR1.mjs} +18 -18
- package/dist/{apply-B_VMpJ2P.mjs.map → apply-B4SIOxR1.mjs.map} +1 -1
- package/dist/astro/image-endpoint.mjs +2 -2
- package/dist/astro/image-endpoint.mjs.map +1 -1
- package/dist/astro/index.d.mts +12 -12
- package/dist/astro/index.d.mts.map +1 -1
- package/dist/astro/index.mjs +110 -37
- 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 +2 -2
- package/dist/astro/middleware/redirect.mjs +3 -3
- package/dist/astro/middleware/request-context.mjs +2 -2
- 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 +157 -195
- 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.d.mts.map +1 -1
- package/dist/astro/routes/api/admin/api-tokens/index.mjs +5 -5
- package/dist/astro/routes/api/admin/api-tokens/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/byline-fields/_slug_/usage.mjs +3 -3
- package/dist/astro/routes/api/admin/byline-fields/_slug_.mjs +8 -8
- package/dist/astro/routes/api/admin/byline-fields/index.mjs +8 -8
- package/dist/astro/routes/api/admin/byline-fields/reorder.mjs +8 -8
- package/dist/astro/routes/api/admin/bylines/_id_/index.mjs +14 -14
- package/dist/astro/routes/api/admin/bylines/_id_/translations.mjs +14 -14
- package/dist/astro/routes/api/admin/bylines/index.mjs +14 -14
- package/dist/astro/routes/api/admin/comments/_id_/status.mjs +12 -12
- package/dist/astro/routes/api/admin/comments/_id_.mjs +5 -5
- package/dist/astro/routes/api/admin/comments/bulk.mjs +10 -10
- package/dist/astro/routes/api/admin/comments/counts.mjs +5 -5
- package/dist/astro/routes/api/admin/comments/index.mjs +10 -10
- package/dist/astro/routes/api/admin/hooks/exclusive/_hookName_.mjs +3 -3
- package/dist/astro/routes/api/admin/hooks/exclusive/index.mjs +2 -2
- package/dist/astro/routes/api/admin/media-usage/activation.mjs +10 -10
- package/dist/astro/routes/api/admin/media-usage/collection-deletions/index.mjs +13 -13
- package/dist/astro/routes/api/admin/media-usage/collection-deletions/retry.mjs +13 -13
- package/dist/astro/routes/api/admin/media-usage/progress.mjs +11 -11
- package/dist/astro/routes/api/admin/media-usage/repair.mjs +14 -14
- package/dist/astro/routes/api/admin/media-usage/work/index.mjs +13 -13
- package/dist/astro/routes/api/admin/media-usage/work/retry.mjs +13 -13
- package/dist/astro/routes/api/admin/oauth-clients/_id_.mjs +4 -4
- package/dist/astro/routes/api/admin/oauth-clients/_id_.mjs.map +1 -1
- package/dist/astro/routes/api/admin/oauth-clients/index.mjs +4 -4
- package/dist/astro/routes/api/admin/oauth-clients/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/_id_/disable.mjs +49 -49
- package/dist/astro/routes/api/admin/plugins/_id_/enable.mjs +49 -49
- package/dist/astro/routes/api/admin/plugins/_id_/index.mjs +47 -47
- package/dist/astro/routes/api/admin/plugins/_id_/mcp.mjs +4 -4
- package/dist/astro/routes/api/admin/plugins/_id_/settings.mjs +47 -47
- package/dist/astro/routes/api/admin/plugins/_id_/uninstall.mjs +48 -48
- package/dist/astro/routes/api/admin/plugins/_id_/update.mjs +48 -48
- package/dist/astro/routes/api/admin/plugins/index.mjs +47 -47
- package/dist/astro/routes/api/admin/plugins/marketplace/_id_/icon.mjs +2 -2
- package/dist/astro/routes/api/admin/plugins/marketplace/_id_/index.mjs +47 -47
- package/dist/astro/routes/api/admin/plugins/marketplace/_id_/install.mjs +48 -48
- package/dist/astro/routes/api/admin/plugins/marketplace/index.mjs +47 -47
- package/dist/astro/routes/api/admin/plugins/registry/_id_/uninstall.mjs +48 -48
- package/dist/astro/routes/api/admin/plugins/registry/_id_/update.d.mts.map +1 -1
- package/dist/astro/routes/api/admin/plugins/registry/_id_/update.mjs +54 -50
- package/dist/astro/routes/api/admin/plugins/registry/_id_/update.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/registry/artifact.mjs +17 -16
- package/dist/astro/routes/api/admin/plugins/registry/artifact.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/registry/install.d.mts.map +1 -1
- package/dist/astro/routes/api/admin/plugins/registry/install.mjs +55 -51
- package/dist/astro/routes/api/admin/plugins/registry/install.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/registry/verify.d.mts +8 -0
- package/dist/astro/routes/api/admin/plugins/registry/verify.d.mts.map +1 -0
- package/dist/astro/routes/api/admin/plugins/registry/verify.mjs +93 -0
- package/dist/astro/routes/api/admin/plugins/registry/verify.mjs.map +1 -0
- package/dist/astro/routes/api/admin/plugins/updates.mjs +47 -47
- package/dist/astro/routes/api/admin/themes/marketplace/_id_/index.mjs +47 -47
- package/dist/astro/routes/api/admin/themes/marketplace/_id_/thumbnail.mjs +2 -2
- package/dist/astro/routes/api/admin/themes/marketplace/index.mjs +47 -47
- 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 +2 -2
- 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 +10 -10
- package/dist/astro/routes/api/auth/invite/index.mjs +7 -7
- package/dist/astro/routes/api/auth/invite/register-options.mjs +9 -9
- package/dist/astro/routes/api/auth/logout.mjs +2 -2
- package/dist/astro/routes/api/auth/magic-link/send.mjs +9 -9
- 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 +3 -3
- 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 +11 -11
- package/dist/astro/routes/api/auth/passkey/register/options.mjs +9 -9
- package/dist/astro/routes/api/auth/passkey/register/verify.mjs +10 -10
- package/dist/astro/routes/api/auth/passkey/verify.mjs +10 -10
- package/dist/astro/routes/api/auth/signup/complete.mjs +10 -10
- package/dist/astro/routes/api/auth/signup/request.mjs +9 -9
- package/dist/astro/routes/api/auth/signup/verify.mjs +1 -1
- package/dist/astro/routes/api/comments/_collection_/_contentId_/index.mjs +13 -13
- package/dist/astro/routes/api/comments/_collection_/_contentId_/reactions.mjs +12 -12
- 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 +14 -5
- 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_/permanent.mjs +2 -2
- package/dist/astro/routes/api/content/_collection_/_id_/preview-url.mjs +10 -10
- package/dist/astro/routes/api/content/_collection_/_id_/publish.mjs +13 -10
- 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 +15 -15
- package/dist/astro/routes/api/content/_collection_/_id_/references/_relation_/parents.mjs +15 -15
- 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.mjs +8 -8
- package/dist/astro/routes/api/content/_collection_/_id_/terms/_taxonomy_.mjs +13 -13
- 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 +14 -5
- package/dist/astro/routes/api/content/_collection_/_id_/unpublish.mjs.map +1 -1
- package/dist/astro/routes/api/content/_collection_/_id_.mjs +8 -8
- package/dist/astro/routes/api/content/_collection_/authors.mjs +2 -2
- package/dist/astro/routes/api/content/_collection_/index.mjs +8 -8
- package/dist/astro/routes/api/content/_collection_/trash.mjs +7 -7
- package/dist/astro/routes/api/dashboard.mjs +7 -7
- 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 +15 -15
- package/dist/astro/routes/api/import/wordpress/analyze.mjs +2 -2
- package/dist/astro/routes/api/import/wordpress/execute.d.mts +11 -11
- package/dist/astro/routes/api/import/wordpress/execute.mjs +11 -11
- package/dist/astro/routes/api/import/wordpress/media.d.mts +10 -10
- package/dist/astro/routes/api/import/wordpress/media.mjs +9 -9
- package/dist/astro/routes/api/import/wordpress/prepare.mjs +9 -9
- package/dist/astro/routes/api/import/wordpress/rewrite-urls.d.mts +11 -11
- package/dist/astro/routes/api/import/wordpress/rewrite-urls.mjs +10 -10
- package/dist/astro/routes/api/import/wordpress-plugin/analyze.d.mts +1 -1
- package/dist/astro/routes/api/import/wordpress-plugin/analyze.mjs +15 -15
- package/dist/astro/routes/api/import/wordpress-plugin/execute.d.mts +11 -11
- package/dist/astro/routes/api/import/wordpress-plugin/execute.mjs +22 -22
- package/dist/astro/routes/api/manifest.mjs +3 -3
- package/dist/astro/routes/api/manifest.mjs.map +1 -1
- package/dist/astro/routes/api/mcp.mjs +188 -65
- package/dist/astro/routes/api/mcp.mjs.map +1 -1
- package/dist/astro/routes/api/media/_id_/confirm.mjs +9 -9
- package/dist/astro/routes/api/media/_id_/replace.d.mts +8 -0
- package/dist/astro/routes/api/media/_id_/replace.d.mts.map +1 -0
- package/dist/astro/routes/api/media/_id_/replace.mjs +91 -0
- package/dist/astro/routes/api/media/_id_/replace.mjs.map +1 -0
- package/dist/astro/routes/api/media/_id_/upload.mjs +5 -5
- package/dist/astro/routes/api/media/_id_/usage.mjs +16 -16
- package/dist/astro/routes/api/media/_id_.mjs +15 -15
- package/dist/astro/routes/api/media/file/_...key_.d.mts.map +1 -1
- package/dist/astro/routes/api/media/file/_...key_.mjs +3 -2
- package/dist/astro/routes/api/media/file/_...key_.mjs.map +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 +15 -13
- package/dist/astro/routes/api/media/upload-url.mjs.map +1 -1
- package/dist/astro/routes/api/media.d.mts.map +1 -1
- package/dist/astro/routes/api/media.mjs +47 -24
- package/dist/astro/routes/api/media.mjs.map +1 -1
- package/dist/astro/routes/api/menus/_name_/items/_id_.d.mts.map +1 -1
- package/dist/astro/routes/api/menus/_name_/items/_id_.mjs +20 -13
- package/dist/astro/routes/api/menus/_name_/items/_id_.mjs.map +1 -1
- package/dist/astro/routes/api/menus/_name_/items.d.mts.map +1 -1
- package/dist/astro/routes/api/menus/_name_/items.mjs +15 -11
- package/dist/astro/routes/api/menus/_name_/items.mjs.map +1 -1
- package/dist/astro/routes/api/menus/_name_/reorder.d.mts.map +1 -1
- package/dist/astro/routes/api/menus/_name_/reorder.mjs +15 -11
- package/dist/astro/routes/api/menus/_name_/reorder.mjs.map +1 -1
- package/dist/astro/routes/api/menus/_name_/translations.d.mts.map +1 -1
- package/dist/astro/routes/api/menus/_name_/translations.mjs +16 -12
- package/dist/astro/routes/api/menus/_name_/translations.mjs.map +1 -1
- package/dist/astro/routes/api/menus/_name_.d.mts.map +1 -1
- package/dist/astro/routes/api/menus/_name_.mjs +21 -14
- package/dist/astro/routes/api/menus/_name_.mjs.map +1 -1
- package/dist/astro/routes/api/menus/index.d.mts.map +1 -1
- package/dist/astro/routes/api/menus/index.mjs +15 -11
- package/dist/astro/routes/api/menus/index.mjs.map +1 -1
- package/dist/astro/routes/api/oauth/authorize.mjs +6 -6
- package/dist/astro/routes/api/oauth/device/authorize.mjs +5 -5
- package/dist/astro/routes/api/oauth/device/code.mjs +8 -8
- package/dist/astro/routes/api/oauth/device/token.mjs +7 -7
- package/dist/astro/routes/api/oauth/register.mjs +2 -2
- package/dist/astro/routes/api/oauth/token/refresh.mjs +5 -5
- package/dist/astro/routes/api/oauth/token/revoke.mjs +5 -5
- package/dist/astro/routes/api/oauth/token.mjs +5 -5
- package/dist/astro/routes/api/openapi.json.mjs +104 -38
- 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/relations/_id_/index.mjs +15 -15
- package/dist/astro/routes/api/relations/_id_/translations.mjs +10 -10
- package/dist/astro/routes/api/relations/index.mjs +15 -15
- 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 +47 -47
- package/dist/astro/routes/api/schema/collections/_slug_/fields/index.mjs +47 -47
- package/dist/astro/routes/api/schema/collections/_slug_/fields/reorder.mjs +47 -47
- package/dist/astro/routes/api/schema/collections/_slug_/index.mjs +47 -47
- package/dist/astro/routes/api/schema/collections/index.mjs +47 -47
- package/dist/astro/routes/api/schema/collections/reorder.mjs +47 -47
- package/dist/astro/routes/api/schema/index.mjs +8 -8
- package/dist/astro/routes/api/schema/orphans/_slug_.mjs +47 -47
- package/dist/astro/routes/api/schema/orphans/index.mjs +47 -47
- package/dist/astro/routes/api/search/enable.mjs +10 -10
- package/dist/astro/routes/api/search/index.mjs +9 -9
- package/dist/astro/routes/api/search/rebuild.mjs +10 -10
- package/dist/astro/routes/api/search/stats.mjs +5 -5
- package/dist/astro/routes/api/search/suggest.mjs +9 -9
- package/dist/astro/routes/api/sections/_slug_.mjs +9 -9
- package/dist/astro/routes/api/sections/index.mjs +9 -9
- package/dist/astro/routes/api/settings/backups/archives/_name_.mjs +5 -5
- package/dist/astro/routes/api/settings/backups/archives/index.mjs +4 -4
- package/dist/astro/routes/api/settings/backups/export.mjs +5 -5
- package/dist/astro/routes/api/settings/backups/index.mjs +6 -6
- package/dist/astro/routes/api/settings/email.mjs +4 -4
- package/dist/astro/routes/api/settings/email.mjs.map +1 -1
- package/dist/astro/routes/api/settings.d.mts.map +1 -1
- package/dist/astro/routes/api/settings.mjs +18 -14
- package/dist/astro/routes/api/settings.mjs.map +1 -1
- package/dist/astro/routes/api/setup/admin-verify.mjs +11 -11
- package/dist/astro/routes/api/setup/admin.mjs +10 -10
- package/dist/astro/routes/api/setup/dev-bypass.mjs +25 -25
- package/dist/astro/routes/api/setup/dev-reset.mjs +1 -1
- package/dist/astro/routes/api/setup/index.mjs +25 -25
- package/dist/astro/routes/api/setup/status.mjs +3 -3
- package/dist/astro/routes/api/snapshot.mjs +6 -6
- package/dist/astro/routes/api/taxonomies/_name_/reorder.d.mts.map +1 -1
- package/dist/astro/routes/api/taxonomies/_name_/reorder.mjs +19 -15
- package/dist/astro/routes/api/taxonomies/_name_/reorder.mjs.map +1 -1
- package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_/translations.d.mts.map +1 -1
- package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_/translations.mjs +20 -16
- package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_/translations.mjs.map +1 -1
- package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_.d.mts.map +1 -1
- package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_.mjs +24 -17
- package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_.mjs.map +1 -1
- package/dist/astro/routes/api/taxonomies/_name_/terms/index.d.mts.map +1 -1
- package/dist/astro/routes/api/taxonomies/_name_/terms/index.mjs +19 -15
- package/dist/astro/routes/api/taxonomies/_name_/terms/index.mjs.map +1 -1
- package/dist/astro/routes/api/taxonomies/_name_/translations.mjs +13 -13
- package/dist/astro/routes/api/taxonomies/_name_.d.mts.map +1 -1
- package/dist/astro/routes/api/taxonomies/_name_.mjs +25 -18
- package/dist/astro/routes/api/taxonomies/_name_.mjs.map +1 -1
- package/dist/astro/routes/api/taxonomies/index.d.mts.map +1 -1
- package/dist/astro/routes/api/taxonomies/index.mjs +19 -15
- package/dist/astro/routes/api/taxonomies/index.mjs.map +1 -1
- package/dist/astro/routes/api/themes/preview.mjs +4 -4
- package/dist/astro/routes/api/typegen.mjs +4 -4
- package/dist/astro/routes/api/well-known/auth.mjs +1 -1
- package/dist/astro/routes/api/well-known/oauth-authorization-server.mjs +2 -2
- package/dist/astro/routes/api/well-known/oauth-protected-resource.mjs +2 -2
- package/dist/astro/routes/api/widget-areas/_name_/reorder.d.mts.map +1 -1
- package/dist/astro/routes/api/widget-areas/_name_/reorder.mjs +10 -8
- package/dist/astro/routes/api/widget-areas/_name_/reorder.mjs.map +1 -1
- package/dist/astro/routes/api/widget-areas/_name_/widgets/_id_.d.mts.map +1 -1
- package/dist/astro/routes/api/widget-areas/_name_/widgets/_id_.mjs +16 -12
- package/dist/astro/routes/api/widget-areas/_name_/widgets/_id_.mjs.map +1 -1
- package/dist/astro/routes/api/widget-areas/_name_/widgets.d.mts.map +1 -1
- package/dist/astro/routes/api/widget-areas/_name_/widgets.mjs +14 -11
- package/dist/astro/routes/api/widget-areas/_name_/widgets.mjs.map +1 -1
- package/dist/astro/routes/api/widget-areas/_name_.d.mts.map +1 -1
- package/dist/astro/routes/api/widget-areas/_name_.mjs +7 -5
- package/dist/astro/routes/api/widget-areas/_name_.mjs.map +1 -1
- package/dist/astro/routes/api/widget-areas/index.d.mts.map +1 -1
- package/dist/astro/routes/api/widget-areas/index.mjs +14 -11
- package/dist/astro/routes/api/widget-areas/index.mjs.map +1 -1
- package/dist/astro/routes/api/widget-components.mjs +2 -2
- package/dist/astro/routes/robots.txt.mjs +5 -5
- package/dist/astro/routes/sitemap-_collection_.xml.mjs +8 -8
- package/dist/astro/routes/sitemap.xml.mjs +6 -6
- 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-ByYs-Uxs.mjs → authorize-Bkf_UHhD.mjs} +2 -2
- package/dist/{authorize-ByYs-Uxs.mjs.map → authorize-Bkf_UHhD.mjs.map} +1 -1
- package/dist/{backup-ChyHfIoX.mjs → backup-rwVAl9NI.mjs} +4 -4
- package/dist/{backup-ChyHfIoX.mjs.map → backup-rwVAl9NI.mjs.map} +1 -1
- package/dist/{bundle-DZFhFurR.mjs → bundle-C8S2Zl6U.mjs} +3 -3
- package/dist/{bundle-DZFhFurR.mjs.map → bundle-C8S2Zl6U.mjs.map} +1 -1
- package/dist/{byline-Cpnwrje1.mjs → byline-DuhF7NWl.mjs} +25 -12
- package/dist/byline-DuhF7NWl.mjs.map +1 -0
- package/dist/{byline-fields-CAyA_Umd.mjs → byline-fields-BovY4KYM.mjs} +1 -1
- package/dist/{byline-fields-CAyA_Umd.mjs.map → byline-fields-BovY4KYM.mjs.map} +1 -1
- package/dist/{bylines-BSo9B9RX.mjs → bylines-CJ5nd6Lw.mjs} +6 -6
- package/dist/{bylines-BSo9B9RX.mjs.map → bylines-CJ5nd6Lw.mjs.map} +1 -1
- package/dist/{bylines-CHjvehVX.mjs → bylines-RwBAeOF1.mjs} +3 -3
- package/dist/{bylines-CHjvehVX.mjs.map → bylines-RwBAeOF1.mjs.map} +1 -1
- package/dist/{cache-5VirJ2Cn.mjs → cache-BF5Kvn59.mjs} +2 -2
- package/dist/{cache-5VirJ2Cn.mjs.map → cache-BF5Kvn59.mjs.map} +1 -1
- package/dist/{challenge-store-D5pSY2S1.mjs → challenge-store-DQN_Yrck.mjs} +5 -3
- package/dist/challenge-store-DQN_Yrck.mjs.map +1 -0
- package/dist/chrome-tags-D8fiZG94.mjs +24 -0
- package/dist/chrome-tags-D8fiZG94.mjs.map +1 -0
- package/dist/{chunks-bNiX6_DR.mjs → chunks-C4szrD8o.mjs} +2 -2
- package/dist/{chunks-bNiX6_DR.mjs.map → chunks-C4szrD8o.mjs.map} +1 -1
- package/dist/cli/index.mjs +26 -26
- package/dist/client/cf-access.d.mts +1 -1
- package/dist/client/index.d.mts +2 -2
- package/dist/client/index.mjs +2 -2
- package/dist/{collection-deletion-m_oi2c0N.mjs → collection-deletion-Bj07NHbj.mjs} +2 -2
- package/dist/{collection-deletion-m_oi2c0N.mjs.map → collection-deletion-Bj07NHbj.mjs.map} +1 -1
- package/dist/{comment-reaction-CRuItEjt.mjs → comment-reaction-BhrvSHml.mjs} +2 -2
- package/dist/{comment-reaction-CRuItEjt.mjs.map → comment-reaction-BhrvSHml.mjs.map} +1 -1
- package/dist/{comment-DhvLEdhQ.mjs → comment-vxOzWbZN.mjs} +2 -2
- package/dist/{comment-DhvLEdhQ.mjs.map → comment-vxOzWbZN.mjs.map} +1 -1
- package/dist/{comments-CLj4bi8I.mjs → comments-Ct4ensnf.mjs} +2 -2
- package/dist/{comments-CLj4bi8I.mjs.map → comments-Ct4ensnf.mjs.map} +1 -1
- package/dist/{components-v4U4DT2y.mjs → components-DJbo1z0S.mjs} +1 -1
- package/dist/{components-v4U4DT2y.mjs.map → components-DJbo1z0S.mjs.map} +1 -1
- package/dist/{config-DrfghTPe.d.mts → config-B9eZ340f.d.mts} +1 -1
- package/dist/{config-DrfghTPe.d.mts.map → config-B9eZ340f.d.mts.map} +1 -1
- package/dist/config-it29yDLA.mjs +1163 -0
- package/dist/config-it29yDLA.mjs.map +1 -0
- package/dist/{content-CP-SeXNa.mjs → content-DjvM0T92.mjs} +84 -44
- package/dist/content-DjvM0T92.mjs.map +1 -0
- package/dist/{content-list-query-BhejKVqb.d.mts → content-list-query-Btqd4uV2.d.mts} +1 -1
- package/dist/{content-list-query-BhejKVqb.d.mts.map → content-list-query-Btqd4uV2.d.mts.map} +1 -1
- package/dist/{content-refresh-DLOfIhYc.mjs → content-refresh-Bwp-8yGy.mjs} +48 -21
- package/dist/content-refresh-Bwp-8yGy.mjs.map +1 -0
- package/dist/{content-repair-BCxzy0r4.mjs → content-repair-Czdp7jz5.mjs} +4 -4
- package/dist/{content-repair-BCxzy0r4.mjs.map → content-repair-Czdp7jz5.mjs.map} +1 -1
- package/dist/{context-BR5hRWiK.mjs → context-CX6gxOLW.mjs} +52 -17
- package/dist/context-CX6gxOLW.mjs.map +1 -0
- package/dist/{cron-CWfWrWKG.mjs → cron-C6o7VppJ.mjs} +1 -1
- package/dist/{cron-CWfWrWKG.mjs.map → cron-C6o7VppJ.mjs.map} +1 -1
- package/dist/{dashboard-CkIV2rnQ.mjs → dashboard-C2kTeeRI.mjs} +4 -4
- package/dist/{dashboard-CkIV2rnQ.mjs.map → dashboard-C2kTeeRI.mjs.map} +1 -1
- package/dist/db/index.d.mts +3 -3
- package/dist/db/index.mjs +1 -1
- package/dist/db/index.mjs.map +1 -1
- package/dist/db/libsql-migrations.d.mts +1 -1
- package/dist/db/libsql-migrations.mjs +4 -4
- package/dist/db/libsql.d.mts +1 -1
- package/dist/db/postgres-migrations.d.mts +1 -1
- package/dist/db/postgres-migrations.mjs +4 -4
- package/dist/db/postgres.d.mts +1 -1
- package/dist/db/postgres.d.mts.map +1 -1
- package/dist/db/postgres.mjs +19 -3
- package/dist/db/postgres.mjs.map +1 -1
- package/dist/db/sqlite-migrations.d.mts +1 -1
- package/dist/db/sqlite-migrations.mjs +4 -4
- package/dist/db/sqlite.d.mts +1 -1
- package/dist/db/sqlite.mjs +1 -1
- package/dist/{default-YMEfcQUx.mjs → default-Clra32mw.mjs} +1 -1
- package/dist/{default-YMEfcQUx.mjs.map → default-Clra32mw.mjs.map} +1 -1
- package/dist/{deferred-tasks-DfqxH5Xf.d.mts → deferred-tasks-CvDETTJO.d.mts} +1 -1
- package/dist/{deferred-tasks-DfqxH5Xf.d.mts.map → deferred-tasks-CvDETTJO.d.mts.map} +1 -1
- package/dist/dev-typegen-DzOPfsNj.mjs +29 -0
- package/dist/dev-typegen-DzOPfsNj.mjs.map +1 -0
- package/dist/{device-flow-CojjSBwb.mjs → device-flow-D2oCWvLJ.mjs} +4 -4
- package/dist/{device-flow-CojjSBwb.mjs.map → device-flow-D2oCWvLJ.mjs.map} +1 -1
- package/dist/{direct-executor-BWeWiRYB.mjs → direct-executor-Bfa5_ToE.mjs} +3 -3
- package/dist/{direct-executor-BWeWiRYB.mjs.map → direct-executor-Bfa5_ToE.mjs.map} +1 -1
- package/dist/{email-console-CEJgR_LB.mjs → email-console-Dzb6uGYa.mjs} +1 -1
- package/dist/{email-console-CEJgR_LB.mjs.map → email-console-Dzb6uGYa.mjs.map} +1 -1
- package/dist/{error-D9w94fjV.mjs → error-DFrQjppn.mjs} +2 -2
- package/dist/{error-D9w94fjV.mjs.map → error-DFrQjppn.mjs.map} +1 -1
- package/dist/{errors-n2j49uNf.mjs → errors-DsVoDUjJ.mjs} +3 -1
- package/dist/errors-DsVoDUjJ.mjs.map +1 -0
- package/dist/{escape-DN4Qmjsl.mjs → escape-HmHTC1Is.mjs} +1 -1
- package/dist/{escape-DN4Qmjsl.mjs.map → escape-HmHTC1Is.mjs.map} +1 -1
- package/dist/{field-defs-cache-Bh4q6oar.mjs → field-defs-cache-BM4SIRqH.mjs} +2 -2
- package/dist/{field-defs-cache-Bh4q6oar.mjs.map → field-defs-cache-BM4SIRqH.mjs.map} +1 -1
- package/dist/{fts-manager-BhOdW0bi.mjs → fts-manager-Do1BlW2r.mjs} +2 -2
- package/dist/{fts-manager-BhOdW0bi.mjs.map → fts-manager-Do1BlW2r.mjs.map} +1 -1
- package/dist/{hash-CTcngWvj.mjs → hash-3JJPlHF2.mjs} +1 -1
- package/dist/{hash-CTcngWvj.mjs.map → hash-3JJPlHF2.mjs.map} +1 -1
- package/dist/hook-result-DCh2WUpe.d.mts +31 -0
- package/dist/hook-result-DCh2WUpe.d.mts.map +1 -0
- package/dist/{hreflang-7pTHsLZJ.d.mts → hreflang-B6hbAuuO.d.mts} +2 -2
- package/dist/{hreflang-7pTHsLZJ.d.mts.map → hreflang-B6hbAuuO.d.mts.map} +1 -1
- package/dist/{hreflang-Huc6O5wa.mjs → hreflang-DQbPZliA.mjs} +6 -6
- package/dist/{hreflang-Huc6O5wa.mjs.map → hreflang-DQbPZliA.mjs.map} +1 -1
- package/dist/{identity-DXmb4aVp.mjs → identity-DksvEazf.mjs} +3 -3
- package/dist/{identity-DXmb4aVp.mjs.map → identity-DksvEazf.mjs.map} +1 -1
- package/dist/{import-C4_O3KXU.mjs → import-CJpaBBBT.mjs} +5 -5
- package/dist/{import-C4_O3KXU.mjs.map → import-CJpaBBBT.mjs.map} +1 -1
- package/dist/{index-DWbJrsAg.d.mts → index-BJNMCWmu.d.mts} +158 -49
- package/dist/index-BJNMCWmu.d.mts.map +1 -0
- package/dist/{index-6bRee8zb.d.mts → index-Du8K7bWa.d.mts} +3 -3
- package/dist/{index-6bRee8zb.d.mts.map → index-Du8K7bWa.d.mts.map} +1 -1
- package/dist/index.d.mts +22 -21
- package/dist/index.mjs +70 -70
- package/dist/{load-Bo7fZAbg.mjs → load-CawHjTOH.mjs} +2 -2
- package/dist/{load-Bo7fZAbg.mjs.map → load-CawHjTOH.mjs.map} +1 -1
- package/dist/{loader-ZsjE4paL.mjs → loader-Z8vl7zTq.mjs} +48 -13
- package/dist/loader-Z8vl7zTq.mjs.map +1 -0
- package/dist/{manifest-builder-QXuqvVMP.mjs → manifest-builder-COtzuca2.mjs} +2 -2
- package/dist/{manifest-builder-QXuqvVMP.mjs.map → manifest-builder-COtzuca2.mjs.map} +1 -1
- package/dist/{manifest-schema-CUYPfCEH.mjs → manifest-schema-BNWwR8Vd.mjs} +5 -5
- package/dist/manifest-schema-BNWwR8Vd.mjs.map +1 -0
- package/dist/media/image-endpoint.d.mts +4 -2
- package/dist/media/image-endpoint.d.mts.map +1 -1
- package/dist/media/image-endpoint.mjs +6 -4
- package/dist/media/image-endpoint.mjs.map +1 -1
- package/dist/media/index.d.mts +1 -1
- package/dist/media/index.mjs +1 -1
- package/dist/media/local-runtime.d.mts +12 -12
- package/dist/media/local-runtime.mjs +4 -4
- package/dist/{media-D6SeAfBl.mjs → media-BBm8Wg3f.mjs} +30 -2
- package/dist/media-BBm8Wg3f.mjs.map +1 -0
- package/dist/{media-BjwNuLEu.mjs → media-BHjus86Y.mjs} +35 -5
- package/dist/media-BHjus86Y.mjs.map +1 -0
- package/dist/{media-allowlist-D35v7bmL.mjs → media-allowlist-CoTBWoDp.mjs} +1 -1
- package/dist/{media-allowlist-D35v7bmL.mjs.map → media-allowlist-CoTBWoDp.mjs.map} +1 -1
- package/dist/{media-folders-D-0CmRZj.mjs → media-folders-BGkATs8n.mjs} +1 -1
- package/dist/{media-folders-D-0CmRZj.mjs.map → media-folders-BGkATs8n.mjs.map} +1 -1
- package/dist/{media-upload-C7bLXGcI.mjs → media-upload-BCidR-EY.mjs} +6 -6
- package/dist/{media-upload-C7bLXGcI.mjs.map → media-upload-BCidR-EY.mjs.map} +1 -1
- package/dist/{media-url-DH7giMx_.mjs → media-url-DHoPr0hq.mjs} +1 -1
- package/dist/{media-url-DH7giMx_.mjs.map → media-url-DHoPr0hq.mjs.map} +1 -1
- package/dist/{media-usage-BTRJvS6V.mjs → media-usage-CdY5jhSR.mjs} +8 -8
- package/dist/{media-usage-BTRJvS6V.mjs.map → media-usage-CdY5jhSR.mjs.map} +1 -1
- package/dist/{media-usage-activation-Dx0kPV6b.mjs → media-usage-activation-BgeMtK5C.mjs} +2 -2
- package/dist/{media-usage-activation-Dx0kPV6b.mjs.map → media-usage-activation-BgeMtK5C.mjs.map} +1 -1
- package/dist/{media-usage-work-DWb2XPMI.mjs → media-usage-work-CnGCdHxx.mjs} +4 -4
- package/dist/{media-usage-work-DWb2XPMI.mjs.map → media-usage-work-CnGCdHxx.mjs.map} +1 -1
- package/dist/{media-usage-work-C-fhM30c.mjs → media-usage-work-D6D9sMCA.mjs} +1 -1
- package/dist/{media-usage-work-C-fhM30c.mjs.map → media-usage-work-D6D9sMCA.mjs.map} +1 -1
- package/dist/{media-usage-write-fence-BwoJVRDC.mjs → media-usage-write-fence-hjeD4u7s.mjs} +2 -2
- package/dist/{media-usage-write-fence-BwoJVRDC.mjs.map → media-usage-write-fence-hjeD4u7s.mjs.map} +1 -1
- package/dist/{menus-CNg0QlDt.mjs → menus-6qSwTNxG.mjs} +346 -94
- package/dist/menus-6qSwTNxG.mjs.map +1 -0
- package/dist/{menus-CD7EFLwz.mjs → menus-uvPLXMZf.mjs} +3 -3
- package/dist/{menus-CD7EFLwz.mjs.map → menus-uvPLXMZf.mjs.map} +1 -1
- package/dist/migrations/index.d.mts +1 -1
- package/dist/migrations/index.mjs +3 -3
- package/dist/{mode-DaUM_MB2.mjs → mode-DN_WneRx.mjs} +1 -1
- package/dist/{mode-DaUM_MB2.mjs.map → mode-DN_WneRx.mjs.map} +1 -1
- package/dist/{node-sqlite-compat-Udb4Y-rs.mjs → node-sqlite-compat-BuJXIeMz.mjs} +1 -1
- package/dist/{node-sqlite-compat-Udb4Y-rs.mjs.map → node-sqlite-compat-BuJXIeMz.mjs.map} +1 -1
- package/dist/{normalize-CSxdKBVa.mjs → normalize-C2xNjTSG.mjs} +15 -5
- package/dist/normalize-C2xNjTSG.mjs.map +1 -0
- package/dist/{oauth-authorization-Dpsb-fMJ.mjs → oauth-authorization-Dj6Kwc21.mjs} +4 -4
- package/dist/{oauth-authorization-Dpsb-fMJ.mjs.map → oauth-authorization-Dj6Kwc21.mjs.map} +1 -1
- package/dist/{oauth-clients-Bxnoe_67.mjs → oauth-clients-FD7I0J8m.mjs} +1 -1
- package/dist/{oauth-clients-Bxnoe_67.mjs.map → oauth-clients-FD7I0J8m.mjs.map} +1 -1
- package/dist/{oauth-state-store-0C4s0K6w.mjs → oauth-state-store-DkmDOmHs.mjs} +1 -1
- package/dist/{oauth-state-store-0C4s0K6w.mjs.map → oauth-state-store-DkmDOmHs.mjs.map} +1 -1
- package/dist/{oauth-user-lookup-wlGYSeqX.mjs → oauth-user-lookup-CvIwGpYd.mjs} +1 -1
- package/dist/{oauth-user-lookup-wlGYSeqX.mjs.map → oauth-user-lookup-CvIwGpYd.mjs.map} +1 -1
- package/dist/object-cache/memory.d.mts +1 -1
- package/dist/{object-cache-71tPfV4A.mjs → object-cache-DVKnyOfy.mjs} +19 -3
- package/dist/object-cache-DVKnyOfy.mjs.map +1 -0
- package/dist/{options-BhZIeFY1.d.mts → options-CYb4y7hM.d.mts} +24 -11
- package/dist/options-CYb4y7hM.d.mts.map +1 -0
- package/dist/page/index.d.mts +2 -2
- package/dist/{parse-BRJg1kz8.mjs → parse-Ckpg-Qfp.mjs} +2 -2
- package/dist/{parse-BRJg1kz8.mjs.map → parse-Ckpg-Qfp.mjs.map} +1 -1
- package/dist/{passkey-config-B3P0nHRR.mjs → passkey-config-O_lj3y0k.mjs} +1 -1
- package/dist/{passkey-config-B3P0nHRR.mjs.map → passkey-config-O_lj3y0k.mjs.map} +1 -1
- package/dist/{placeholder-BR4ZhVJl.d.mts → placeholder-4X9BrRrp.d.mts} +1 -1
- package/dist/{placeholder-BR4ZhVJl.d.mts.map → placeholder-4X9BrRrp.d.mts.map} +1 -1
- package/dist/plugin-types.d.mts +8 -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-BVRganJQ.mjs → policy-Dhtwntrt.mjs} +2 -2
- package/dist/{policy-BVRganJQ.mjs.map → policy-Dhtwntrt.mjs.map} +1 -1
- package/dist/{portable-text-C8Tvp4_g.mjs → portable-text-U85hOafW.mjs} +1 -1
- package/dist/{portable-text-C8Tvp4_g.mjs.map → portable-text-U85hOafW.mjs.map} +1 -1
- package/dist/{preview-dn2dUyM0.mjs → preview-B_vJLvf8.mjs} +2 -2
- package/dist/{preview-dn2dUyM0.mjs.map → preview-B_vJLvf8.mjs.map} +1 -1
- package/dist/{protocol-CuBEsqgE.d.mts → protocol-JdD2YhY9.d.mts} +2 -2
- package/dist/{protocol-CuBEsqgE.d.mts.map → protocol-JdD2YhY9.d.mts.map} +1 -1
- package/dist/{public-url-DRz_AinV.mjs → public-url-CarhZJgf.mjs} +1 -1
- package/dist/{public-url-DRz_AinV.mjs.map → public-url-CarhZJgf.mjs.map} +1 -1
- package/dist/{query-D18vTdha.mjs → query-BZKZcG5b.mjs} +14 -14
- package/dist/{query-D18vTdha.mjs.map → query-BZKZcG5b.mjs.map} +1 -1
- package/dist/{query-tZDEdtCN.mjs → query-BndaFxxp.mjs} +4 -4
- package/dist/{query-tZDEdtCN.mjs.map → query-BndaFxxp.mjs.map} +1 -1
- package/dist/{rate-limit-on7KPo-v.mjs → rate-limit-BZmATC6W.mjs} +2 -2
- package/dist/{rate-limit-on7KPo-v.mjs.map → rate-limit-BZmATC6W.mjs.map} +1 -1
- package/dist/{redirect-DrbEmU9a.mjs → redirect-CzqnLxK-.mjs} +1 -1
- package/dist/{redirect-DrbEmU9a.mjs.map → redirect-CzqnLxK-.mjs.map} +1 -1
- package/dist/{redirects-CRIM55KH.mjs → redirects-BLNOWQTn.mjs} +63 -28
- package/dist/redirects-BLNOWQTn.mjs.map +1 -0
- package/dist/{redirects-BahWiu8Z.mjs → redirects-CqzNM0KM.mjs} +2 -2
- package/dist/{redirects-BahWiu8Z.mjs.map → redirects-CqzNM0KM.mjs.map} +1 -1
- package/dist/{registry-Cx-jEJOS.mjs → registry-AZAsRsor.mjs} +27 -9
- package/dist/registry-AZAsRsor.mjs.map +1 -0
- package/dist/{relation-A6wLF_DS.mjs → relation-04DfKRTO.mjs} +2 -2
- package/dist/{relation-A6wLF_DS.mjs.map → relation-04DfKRTO.mjs.map} +1 -1
- package/dist/{relations-BTPM2saV.mjs → relations-C4htk5sb.mjs} +7 -7
- package/dist/relations-C4htk5sb.mjs.map +1 -0
- package/dist/{relations-Cj5hZ6Zg.mjs → relations-CcFwDJdJ.mjs} +4 -4
- package/dist/{relations-Cj5hZ6Zg.mjs.map → relations-CcFwDJdJ.mjs.map} +1 -1
- package/dist/{relations-C7B46bcU.d.mts → relations-DnRK4YIT.d.mts} +175 -41
- package/dist/relations-DnRK4YIT.d.mts.map +1 -0
- package/dist/request-context.d.mts +1 -1
- package/dist/{request-meta-DRp5ENd_.mjs → request-meta-DYxLlnmz.mjs} +2 -2
- package/dist/{request-meta-DRp5ENd_.mjs.map → request-meta-DYxLlnmz.mjs.map} +1 -1
- package/dist/{resolve-DxUpTMmE.mjs → resolve-prZ3mP7l.mjs} +1 -1
- package/dist/{resolve-DxUpTMmE.mjs.map → resolve-prZ3mP7l.mjs.map} +1 -1
- package/dist/{runner-77GOZCnH.mjs → runner-BLIDKpmA.mjs} +351 -294
- package/dist/runner-BLIDKpmA.mjs.map +1 -0
- package/dist/{runner-zgqA_CqP.d.mts → runner-YKfIMnaF.d.mts} +3 -2
- package/dist/runner-YKfIMnaF.d.mts.map +1 -0
- package/dist/runtime.d.mts +11 -11
- package/dist/runtime.mjs +1 -1
- package/dist/{schema-BY-oVntF.mjs → schema-CGnBeLiW.mjs} +3 -3
- package/dist/{schema-BY-oVntF.mjs.map → schema-CGnBeLiW.mjs.map} +1 -1
- package/dist/{schema-Cw9kVK0I.mjs → schema-DYr-Vd-L.mjs} +5 -5
- package/dist/{schema-Cw9kVK0I.mjs.map → schema-DYr-Vd-L.mjs.map} +1 -1
- package/dist/{scopes-vMR1uIbt.mjs → scopes-BhWvBavj.mjs} +3 -3
- package/dist/{scopes-vMR1uIbt.mjs.map → scopes-BhWvBavj.mjs.map} +1 -1
- package/dist/{search-CfT3KxO5.mjs → search-C-qDk4kx.mjs} +4 -4
- package/dist/{search-CfT3KxO5.mjs.map → search-C-qDk4kx.mjs.map} +1 -1
- package/dist/{secrets-BH2Qow1-.mjs → secrets-rEtHt-6z.mjs} +1 -1
- package/dist/{secrets-BH2Qow1-.mjs.map → secrets-rEtHt-6z.mjs.map} +1 -1
- package/dist/{sections-DTfjyf1z.mjs → sections-B_nYvlwn.mjs} +2 -2
- package/dist/{sections-DTfjyf1z.mjs.map → sections-B_nYvlwn.mjs.map} +1 -1
- package/dist/seed/index.d.mts +2 -2
- package/dist/seed/index.mjs +18 -18
- package/dist/seo/index.d.mts +3 -3
- package/dist/seo/index.mjs +13 -13
- package/dist/{seo-Cm-dtvgk.mjs → seo-926NRIgt.mjs} +3 -3
- package/dist/{seo-Cm-dtvgk.mjs.map → seo-926NRIgt.mjs.map} +1 -1
- package/dist/{seo-BSiTIXzd.mjs → seo-CVWkdv6x.mjs} +1 -1
- package/dist/{seo-BSiTIXzd.mjs.map → seo-CVWkdv6x.mjs.map} +1 -1
- package/dist/{service-DYsDHEKe.mjs → service-CJl3ZAYs.mjs} +3 -3
- package/dist/{service-DYsDHEKe.mjs.map → service-CJl3ZAYs.mjs.map} +1 -1
- package/dist/{session-user-CNAfvsdw.mjs → session-user-BlMgqCHS.mjs} +1 -1
- package/dist/{session-user-CNAfvsdw.mjs.map → session-user-BlMgqCHS.mjs.map} +1 -1
- package/dist/{settings-BgN-0DT-.mjs → settings--wobrkkC.mjs} +18 -5
- package/dist/settings--wobrkkC.mjs.map +1 -0
- package/dist/{settings-DjtkUo__.mjs → settings-Cwm6o2jY.mjs} +3 -3
- package/dist/{settings-DjtkUo__.mjs.map → settings-Cwm6o2jY.mjs.map} +1 -1
- package/dist/{setup-complete-CcpXaPU7.mjs → setup-complete-DQbClIN2.mjs} +1 -1
- package/dist/{setup-complete-CcpXaPU7.mjs.map → setup-complete-DQbClIN2.mjs.map} +1 -1
- package/dist/{setup-nonce-Reyw30jg.mjs → setup-nonce-DZCFS2sn.mjs} +1 -1
- package/dist/{setup-nonce-Reyw30jg.mjs.map → setup-nonce-DZCFS2sn.mjs.map} +1 -1
- package/dist/{site-url-Cs_V9n3V.mjs → site-url-BrxA_E9H.mjs} +2 -2
- package/dist/{site-url-Cs_V9n3V.mjs.map → site-url-BrxA_E9H.mjs.map} +1 -1
- package/dist/{snapshot-DSB8P7Lm.mjs → snapshot--OCDTqdb.mjs} +1 -1
- package/dist/{snapshot-DSB8P7Lm.mjs.map → snapshot--OCDTqdb.mjs.map} +1 -1
- package/dist/{ssrf-DqebVE34.mjs → ssrf-5sIM5jzl.mjs} +4 -3
- package/dist/{ssrf-DqebVE34.mjs.map → ssrf-5sIM5jzl.mjs.map} +1 -1
- package/dist/{state-BJfU9Uzw.mjs → state-BpFVsJZB.mjs} +1 -1
- package/dist/{state-BJfU9Uzw.mjs.map → state-BpFVsJZB.mjs.map} +1 -1
- package/dist/{status-DDu8HIQl.mjs → status-B777-dXz.mjs} +1 -1
- package/dist/{status-DDu8HIQl.mjs.map → status-B777-dXz.mjs.map} +1 -1
- package/dist/storage/local.d.mts +2 -1
- package/dist/storage/local.d.mts.map +1 -1
- package/dist/storage/local.mjs +1 -1
- package/dist/storage/local.mjs.map +1 -1
- package/dist/storage/s3.d.mts +2 -1
- package/dist/storage/s3.d.mts.map +1 -1
- package/dist/storage/s3.mjs +3 -2
- package/dist/storage/s3.mjs.map +1 -1
- package/dist/{target-D0o26Azo.mjs → target-BmR0iTwz.mjs} +1 -1
- package/dist/{target-D0o26Azo.mjs.map → target-BmR0iTwz.mjs.map} +1 -1
- package/dist/{taxonomies-CPGxo-bn.mjs → taxonomies-DkAkMupr.mjs} +16 -13
- package/dist/taxonomies-DkAkMupr.mjs.map +1 -0
- package/dist/{taxonomies-kmyudNGP.mjs → taxonomies-Wfy_Lg12.mjs} +42 -16
- package/dist/taxonomies-Wfy_Lg12.mjs.map +1 -0
- package/dist/{taxonomy-8X09dLN5.mjs → taxonomy-tJepplLL.mjs} +4 -4
- package/dist/{taxonomy-8X09dLN5.mjs.map → taxonomy-tJepplLL.mjs.map} +1 -1
- package/dist/{tokens-gTS-IVUp.mjs → tokens-BCO1oruF.mjs} +1 -1
- package/dist/{tokens-gTS-IVUp.mjs.map → tokens-BCO1oruF.mjs.map} +1 -1
- package/dist/{transport-fX59xaJz.mjs → transport-Dr3qtwXC.mjs} +1 -1
- package/dist/{transport-fX59xaJz.mjs.map → transport-Dr3qtwXC.mjs.map} +1 -1
- package/dist/{transport-_6R1ub7t.d.mts → transport-xh6YKW2G.d.mts} +1 -1
- package/dist/{transport-_6R1ub7t.d.mts.map → transport-xh6YKW2G.d.mts.map} +1 -1
- package/dist/{trusted-proxy-fe6nEgR4.mjs → trusted-proxy-BR5F1Otp.mjs} +1 -1
- package/dist/{trusted-proxy-fe6nEgR4.mjs.map → trusted-proxy-BR5F1Otp.mjs.map} +1 -1
- package/dist/{types-BXUmsINL.mjs → types-3qNFPlci.mjs} +1 -1
- package/dist/{types-BXUmsINL.mjs.map → types-3qNFPlci.mjs.map} +1 -1
- package/dist/{types-Vg6f5i3s.d.mts → types-B6GrPic4.d.mts} +9 -3
- package/dist/{types-Vg6f5i3s.d.mts.map → types-B6GrPic4.d.mts.map} +1 -1
- package/dist/{types-DJQxln7q.d.mts → types-BuHW4xDE.d.mts} +11 -10
- package/dist/types-BuHW4xDE.d.mts.map +1 -0
- package/dist/{types-BzBd3PeX.d.mts → types-C00oyCZp.d.mts} +1 -1
- package/dist/{types-BzBd3PeX.d.mts.map → types-C00oyCZp.d.mts.map} +1 -1
- package/dist/{types-Blb-MRC3.d.mts → types-CDtkNSFQ.d.mts} +1 -1
- package/dist/{types-Blb-MRC3.d.mts.map → types-CDtkNSFQ.d.mts.map} +1 -1
- package/dist/{types-D5VVLr7J.d.mts → types-CPeXo1wF.d.mts} +1 -1
- package/dist/{types-D5VVLr7J.d.mts.map → types-CPeXo1wF.d.mts.map} +1 -1
- package/dist/types-CQPWhPxE.mjs.map +1 -1
- package/dist/{types-D_DWe7k9.d.mts → types-CXFkwEGC.d.mts} +3 -2
- package/dist/types-CXFkwEGC.d.mts.map +1 -0
- package/dist/{types-CLqvnd05.d.mts → types-DczELMop.d.mts} +1 -1
- package/dist/{types-CLqvnd05.d.mts.map → types-DczELMop.d.mts.map} +1 -1
- package/dist/types-DfuTR6dL.mjs +3 -0
- package/dist/{types-DHxzBjbD.d.mts → types-FV23hEoW.d.mts} +1 -1
- package/dist/{types-DHxzBjbD.d.mts.map → types-FV23hEoW.d.mts.map} +1 -1
- package/dist/{types-Br-ERaxh.d.mts → types-xDMtUFnO.d.mts} +1 -1
- package/dist/{types-Br-ERaxh.d.mts.map → types-xDMtUFnO.d.mts.map} +1 -1
- package/dist/{upload-attempts-CNyGSepg.mjs → upload-attempts-BsqoQ1fn.mjs} +1 -1
- package/dist/{upload-attempts-CNyGSepg.mjs.map → upload-attempts-BsqoQ1fn.mjs.map} +1 -1
- package/dist/{url-pattern-K-KdXcSe.mjs → url-pattern-D4c2czpJ.mjs} +1 -1
- package/dist/{url-pattern-K-KdXcSe.mjs.map → url-pattern-D4c2czpJ.mjs.map} +1 -1
- package/dist/{user-CtYY0tp2.mjs → user-BTZ40aq6.mjs} +2 -2
- package/dist/{user-CtYY0tp2.mjs.map → user-BTZ40aq6.mjs.map} +1 -1
- package/dist/{utils-HztC73hq.mjs → utils-BKvNjjhY.mjs} +1 -1
- package/dist/{utils-HztC73hq.mjs.map → utils-BKvNjjhY.mjs.map} +1 -1
- package/dist/{validate-Dd-IUjnZ.mjs → validate-DE_LRwo9.mjs} +2 -2
- package/dist/{validate-Dd-IUjnZ.mjs.map → validate-DE_LRwo9.mjs.map} +1 -1
- package/dist/{validate-DlqdOZXB.d.mts → validate-DUP27OYD.d.mts} +5 -5
- package/dist/{validate-DlqdOZXB.d.mts.map → validate-DUP27OYD.d.mts.map} +1 -1
- package/dist/{validation-D83n7Npi.mjs → validation-BMImFJ11.mjs} +8 -8
- package/dist/{validation-D83n7Npi.mjs.map → validation-BMImFJ11.mjs.map} +1 -1
- package/dist/version-Bii3suaO.mjs +7 -0
- package/dist/{version-ri-sCyAp.mjs.map → version-Bii3suaO.mjs.map} +1 -1
- package/dist/{widgets-CpmZd9Q-.mjs → widgets-D3gJ10xU.mjs} +17 -4
- package/dist/widgets-D3gJ10xU.mjs.map +1 -0
- package/dist/{wxr-taxonomies-BFd0y72_.d.mts → wxr-taxonomies-B2Og_6rU.d.mts} +1 -1
- package/dist/{wxr-taxonomies-BFd0y72_.d.mts.map → wxr-taxonomies-B2Og_6rU.d.mts.map} +1 -1
- package/dist/{wxr-taxonomies-Df4vxWcU.mjs → wxr-taxonomies-Cxngsjwo.mjs} +4 -4
- package/dist/{wxr-taxonomies-Df4vxWcU.mjs.map → wxr-taxonomies-Cxngsjwo.mjs.map} +1 -1
- package/dist/{zod-generator-DylzusHh.mjs → zod-generator-BuYSQJB7.mjs} +11 -7
- package/dist/zod-generator-BuYSQJB7.mjs.map +1 -0
- package/package.json +12 -9
- package/src/api/errors.ts +2 -0
- package/src/api/handlers/content.ts +49 -11
- package/src/api/handlers/index.ts +1 -0
- package/src/api/handlers/manifest.ts +161 -12
- package/src/api/handlers/media.ts +30 -0
- package/src/api/handlers/registry.ts +393 -289
- package/src/api/handlers/taxonomies.ts +16 -9
- package/src/api/openapi/document.ts +85 -5
- package/src/api/parse.ts +1 -1
- package/src/api/schemas/auth.ts +4 -4
- package/src/api/schemas/bylines.ts +3 -3
- package/src/api/schemas/comments.ts +1 -1
- package/src/api/schemas/common.ts +3 -2
- package/src/api/schemas/content.ts +78 -22
- package/src/api/schemas/media.ts +52 -0
- package/src/api/schemas/redirects.ts +6 -1
- package/src/api/schemas/schema.ts +4 -0
- package/src/api/schemas/setup.ts +1 -1
- package/src/api/schemas/taxonomies.ts +2 -2
- package/src/api/schemas/users.ts +1 -1
- package/src/api/types.ts +23 -10
- package/src/astro/dev-typegen.ts +35 -0
- package/src/astro/image-endpoint.ts +2 -2
- package/src/astro/integration/dev-typegen.ts +91 -0
- package/src/astro/integration/index.ts +9 -44
- package/src/astro/integration/routes.ts +5 -0
- package/src/astro/integration/vite-config.ts +21 -2
- package/src/astro/middleware.ts +5 -0
- package/src/astro/routes/api/admin/api-tokens/index.ts +4 -1
- package/src/astro/routes/api/admin/oauth-clients/[id].ts +1 -1
- package/src/astro/routes/api/admin/oauth-clients/index.ts +1 -1
- package/src/astro/routes/api/admin/plugins/registry/[id]/update.ts +4 -0
- package/src/astro/routes/api/admin/plugins/registry/artifact.ts +3 -7
- package/src/astro/routes/api/admin/plugins/registry/install.ts +4 -0
- package/src/astro/routes/api/admin/plugins/registry/verify.ts +60 -0
- package/src/astro/routes/api/content/[collection]/[id]/discard-draft.ts +8 -2
- package/src/astro/routes/api/content/[collection]/[id]/publish.ts +2 -1
- package/src/astro/routes/api/content/[collection]/[id]/unpublish.ts +6 -2
- package/src/astro/routes/api/manifest.ts +1 -1
- package/src/astro/routes/api/media/[id]/replace.ts +114 -0
- package/src/astro/routes/api/media/file/[...key].ts +4 -1
- package/src/astro/routes/api/media/upload-url.ts +8 -4
- package/src/astro/routes/api/media.ts +54 -8
- package/src/astro/routes/api/menus/[name]/items/[id].ts +7 -2
- package/src/astro/routes/api/menus/[name]/items.ts +4 -1
- package/src/astro/routes/api/menus/[name]/reorder.ts +4 -1
- package/src/astro/routes/api/menus/[name]/translations.ts +4 -1
- package/src/astro/routes/api/menus/[name].ts +7 -2
- package/src/astro/routes/api/menus/index.ts +4 -1
- package/src/astro/routes/api/settings/email.ts +1 -1
- package/src/astro/routes/api/settings.ts +4 -1
- package/src/astro/routes/api/taxonomies/[name]/reorder.ts +4 -1
- package/src/astro/routes/api/taxonomies/[name]/terms/[slug]/translations.ts +4 -1
- package/src/astro/routes/api/taxonomies/[name]/terms/[slug].ts +7 -2
- package/src/astro/routes/api/taxonomies/[name]/terms/index.ts +4 -1
- package/src/astro/routes/api/taxonomies/[name].ts +7 -2
- package/src/astro/routes/api/taxonomies/index.ts +4 -1
- package/src/astro/routes/api/widget-areas/[name]/reorder.ts +3 -1
- package/src/astro/routes/api/widget-areas/[name]/widgets/[id].ts +5 -2
- package/src/astro/routes/api/widget-areas/[name]/widgets.ts +3 -1
- package/src/astro/routes/api/widget-areas/[name].ts +3 -1
- package/src/astro/routes/api/widget-areas/index.ts +3 -1
- package/src/astro/types.ts +23 -5
- package/src/auth/challenge-store.ts +3 -1
- package/src/aws-sdk.d.ts +1 -0
- package/src/cache/chrome-tags.ts +24 -0
- package/src/components/EmDashImage.astro +2 -1
- package/src/components/EmDashMedia.astro +2 -1
- package/src/components/InlinePortableTextEditor.tsx +6 -1
- package/src/components/widgets/Archives.astro +2 -37
- package/src/content/converters/index.ts +2 -0
- package/src/content/converters/mark-safety.ts +1 -0
- package/src/content/converters/portable-text-identity.ts +139 -0
- package/src/content/converters/portable-text-to-prosemirror.ts +202 -69
- package/src/content/converters/prosemirror-to-portable-text.ts +96 -25
- package/src/content/converters/types.ts +1 -0
- package/src/database/migrations/017_authorization_codes.ts +14 -4
- package/src/database/migrations/074_content_deleted_scheduled_index.ts +55 -0
- package/src/database/migrations/runner.ts +3 -1
- package/src/database/repositories/byline.ts +32 -16
- package/src/database/repositories/content.ts +114 -47
- package/src/database/repositories/media-usage.ts +66 -37
- package/src/database/repositories/media.ts +60 -1
- package/src/database/repositories/plugin-storage.ts +74 -9
- package/src/database/repositories/types.ts +8 -7
- package/src/db/adapters.ts +8 -1
- package/src/db/postgres.ts +23 -0
- package/src/emdash-runtime.ts +80 -150
- package/src/fields/boolean.ts +1 -1
- package/src/fields/datetime.ts +1 -1
- package/src/fields/file.ts +1 -1
- package/src/fields/integer.ts +1 -1
- package/src/fields/json.ts +1 -1
- package/src/fields/multiselect.ts +1 -1
- package/src/fields/number.ts +1 -1
- package/src/fields/portable-text.ts +1 -1
- package/src/fields/richtext.ts +1 -1
- package/src/fields/select.ts +1 -1
- package/src/fields/slug.ts +1 -1
- package/src/fields/text.ts +1 -1
- package/src/fields/textarea.ts +1 -1
- package/src/fields/types.ts +2 -2
- package/src/index.ts +25 -3
- package/src/loader.ts +63 -10
- package/src/mcp/server.ts +228 -24
- package/src/media/image-endpoint.ts +5 -2
- package/src/media/normalize.ts +15 -4
- package/src/media/usage/cleanup.ts +9 -8
- package/src/menus/index.ts +16 -0
- package/src/object-cache/index.ts +44 -2
- package/src/plugin-types.ts +18 -1
- package/src/plugins/hooks.ts +4 -1
- package/src/plugins/index.ts +6 -0
- package/src/plugins/manager.ts +2 -1
- package/src/plugins/manifest-schema.ts +1 -1
- package/src/plugins/routes.ts +3 -1
- package/src/plugins/sandbox/hook-result.ts +52 -0
- package/src/plugins/sandbox/index.ts +10 -0
- package/src/plugins/types.ts +6 -0
- package/src/registry/artifact-checksum.ts +15 -0
- package/src/registry/artifact-verification.ts +85 -0
- package/src/registry/authoritative-records.ts +180 -0
- package/src/registry/record-labels.ts +28 -0
- package/src/schema/registry.ts +26 -3
- package/src/schema/zod-generator.ts +16 -13
- package/src/security/ssrf.ts +5 -2
- package/src/settings/index.ts +16 -0
- package/src/storage/local.ts +1 -0
- package/src/storage/s3.ts +2 -0
- package/src/storage/types.ts +2 -0
- package/src/taxonomies/index.ts +40 -20
- package/src/widgets/archives.ts +67 -0
- package/src/widgets/index.ts +16 -0
- package/dist/api-B0w3uBiG.mjs +0 -2269
- package/dist/api-B0w3uBiG.mjs.map +0 -1
- package/dist/byline-Cpnwrje1.mjs.map +0 -1
- package/dist/challenge-store-D5pSY2S1.mjs.map +0 -1
- package/dist/content-CP-SeXNa.mjs.map +0 -1
- package/dist/content-refresh-DLOfIhYc.mjs.map +0 -1
- package/dist/context-BR5hRWiK.mjs.map +0 -1
- package/dist/errors-n2j49uNf.mjs.map +0 -1
- package/dist/index-DWbJrsAg.d.mts.map +0 -1
- package/dist/loader-ZsjE4paL.mjs.map +0 -1
- package/dist/manifest-schema-CUYPfCEH.mjs.map +0 -1
- package/dist/media-BjwNuLEu.mjs.map +0 -1
- package/dist/media-D6SeAfBl.mjs.map +0 -1
- package/dist/menus-CNg0QlDt.mjs.map +0 -1
- package/dist/normalize-CSxdKBVa.mjs.map +0 -1
- package/dist/object-cache-71tPfV4A.mjs.map +0 -1
- package/dist/options-BhZIeFY1.d.mts.map +0 -1
- package/dist/redirects-CRIM55KH.mjs.map +0 -1
- package/dist/registry-BiO5WwPq.mjs +0 -2716
- package/dist/registry-BiO5WwPq.mjs.map +0 -1
- package/dist/registry-Cx-jEJOS.mjs.map +0 -1
- package/dist/relations-BTPM2saV.mjs.map +0 -1
- package/dist/relations-C7B46bcU.d.mts.map +0 -1
- package/dist/runner-77GOZCnH.mjs.map +0 -1
- package/dist/runner-zgqA_CqP.d.mts.map +0 -1
- package/dist/settings-BgN-0DT-.mjs.map +0 -1
- package/dist/taxonomies-CPGxo-bn.mjs.map +0 -1
- package/dist/taxonomies-kmyudNGP.mjs.map +0 -1
- package/dist/types-D6OcIp2P.mjs +0 -3
- package/dist/types-DJQxln7q.d.mts.map +0 -1
- package/dist/types-D_DWe7k9.d.mts.map +0 -1
- package/dist/version-ri-sCyAp.mjs +0 -7
- package/dist/widgets-CpmZd9Q-.mjs.map +0 -1
- package/dist/zod-generator-DylzusHh.mjs.map +0 -1
- /package/dist/{api-tokens-B5NHLNUN.mjs → api-tokens-BfYts-sq.mjs} +0 -0
- /package/dist/{ssrf-BPKzkm6O.mjs → ssrf-Dg3cIT-b.mjs} +0 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { t as INTERNAL_MEDIA_PREFIX } from "../normalize-
|
|
1
|
+
import { t as INTERNAL_MEDIA_PREFIX } from "../normalize-C2xNjTSG.mjs";
|
|
2
2
|
|
|
3
3
|
//#region src/media/image-endpoint.ts
|
|
4
4
|
/**
|
|
@@ -35,8 +35,10 @@ const DEFAULT_TRANSFORM_FORMAT = "webp";
|
|
|
35
35
|
const DEFAULT_TRANSFORM_QUALITY = 85;
|
|
36
36
|
/** Upper bound for a requested dimension; caps the work a single request asks for. */
|
|
37
37
|
const MAX_TRANSFORM_DIMENSION = 4e3;
|
|
38
|
-
/** Long-lived
|
|
38
|
+
/** Long-lived cache for content-addressed image URLs. */
|
|
39
39
|
const IMMUTABLE_IMAGE_CACHE = "public, max-age=31536000, immutable";
|
|
40
|
+
/** Cache policy for media keys that Replace original may overwrite. */
|
|
41
|
+
const MUTABLE_MEDIA_CACHE_CONTROL = "public, max-age=0, must-revalidate";
|
|
40
42
|
/**
|
|
41
43
|
* Raster types safe to render inline. Anything else (SVG, PDF, ...) is served
|
|
42
44
|
* as an attachment so it can't execute as an active document. Mirrors the
|
|
@@ -60,7 +62,7 @@ const SAFE_INLINE_IMAGE_TYPES = new Set([
|
|
|
60
62
|
function originalMediaHeaders(contentType) {
|
|
61
63
|
return {
|
|
62
64
|
"Content-Type": contentType,
|
|
63
|
-
"Cache-Control":
|
|
65
|
+
"Cache-Control": MUTABLE_MEDIA_CACHE_CONTROL,
|
|
64
66
|
"X-Content-Type-Options": "nosniff",
|
|
65
67
|
"Content-Security-Policy": "sandbox; default-src 'none'; img-src 'self'; style-src 'unsafe-inline'",
|
|
66
68
|
"Content-Disposition": SAFE_INLINE_IMAGE_TYPES.has(contentType) ? "inline" : "attachment"
|
|
@@ -184,5 +186,5 @@ function parseDimension(raw) {
|
|
|
184
186
|
}
|
|
185
187
|
|
|
186
188
|
//#endregion
|
|
187
|
-
export { ALLOWED_TRANSFORM_FORMATS, DEFAULT_TRANSFORM_FORMAT, DEFAULT_TRANSFORM_QUALITY, IMMUTABLE_IMAGE_CACHE, MAX_TRANSFORM_DIMENSION, isSafeTransformKey, isTransformFormat, matchInternalMediaKey, originalMediaHeaders, parseTransformParams, resolveTransformQuality };
|
|
189
|
+
export { ALLOWED_TRANSFORM_FORMATS, DEFAULT_TRANSFORM_FORMAT, DEFAULT_TRANSFORM_QUALITY, IMMUTABLE_IMAGE_CACHE, MAX_TRANSFORM_DIMENSION, MUTABLE_MEDIA_CACHE_CONTROL, isSafeTransformKey, isTransformFormat, matchInternalMediaKey, originalMediaHeaders, parseTransformParams, resolveTransformQuality };
|
|
188
190
|
//# sourceMappingURL=image-endpoint.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"image-endpoint.mjs","names":[],"sources":["../../src/media/image-endpoint.ts"],"sourcesContent":["/**\n * Portable helpers shared by the platform image-endpoint modules.\n *\n * EmDash wraps Astro's image endpoint (`image.endpoint`) so that source bytes\n * for EmDash media are read straight from the storage adapter instead of being\n * fetched over HTTP. The platform endpoint modules (Node: sharp via\n * `astro:assets`; Cloudflare: the `IMAGES` binding) do the actual transform;\n * this module holds the platform-agnostic bits they share: recognizing an\n * EmDash media URL and validating transform query params.\n *\n * Kept free of `astro:*` / `virtual:emdash/*` imports so it stays in the\n * precompiled package and can be unit-tested directly.\n */\n\nimport { INTERNAL_MEDIA_PREFIX } from \"./normalize.js\";\n\n/** Output formats the wrapped endpoint can produce on Cloudflare. */\nexport const ALLOWED_TRANSFORM_FORMATS = [\"webp\", \"avif\", \"jpeg\", \"png\"] as const;\n\n/** Default output format -- broad support, strong compression. */\nexport const DEFAULT_TRANSFORM_FORMAT: ImageTransformFormat = \"webp\";\n\n/**\n * Default output quality for lossy formats (WebP/AVIF/JPEG) when the request\n * doesn't specify one. Matches the default Cloudflare applies to URL-based\n * image transformations. The Images *binding* applies no default of its own\n * and encodes near-losslessly when quality is omitted (a 2048px WebP comes\n * out ~900 KB instead of ~100 KB), so the endpoint sends an explicit quality\n * for lossy output. PNG is exempt: an explicit PNG quality switches the\n * binding to lossy PNG8, which is not a safe default for a lossless format.\n */\nexport const DEFAULT_TRANSFORM_QUALITY = 85;\n\n/** Upper bound for a requested dimension; caps the work a single request asks for. */\nexport const MAX_TRANSFORM_DIMENSION = 4000;\n\n/** A format string accepted by {@link ImageTransformOptions.format}. */\nexport type ImageTransformFormat = (typeof ALLOWED_TRANSFORM_FORMATS)[number];\n\n/** Validated options for a single transform. */\nexport interface ImageTransformOptions {\n\twidth?: number;\n\theight?: number;\n\tformat: ImageTransformFormat;\n\t/**\n\t * Explicitly-requested quality (1-100), or `undefined` when the request\n\t * carried no `q`. Callers apply their own default per format (see\n\t * {@link DEFAULT_TRANSFORM_QUALITY}); lossless PNG deliberately gets none.\n\t */\n\tquality?: number;\n}\n\n/** Long-lived immutable cache -- transform output is deterministic per key+params. */\nexport const IMMUTABLE_IMAGE_CACHE = \"public, max-age=31536000, immutable\";\n\n/**\n * Raster types safe to render inline. Anything else (SVG, PDF, ...) is served\n * as an attachment so it can't execute as an active document. Mirrors the\n * `/_emdash/api/media/file/{key}` route's allowlist.\n */\nconst SAFE_INLINE_IMAGE_TYPES = new Set([\n\t\"image/jpeg\",\n\t\"image/png\",\n\t\"image/gif\",\n\t\"image/webp\",\n\t\"image/avif\",\n\t\"image/x-icon\",\n]);\n\n/**\n * Headers for streaming **original** stored bytes (the no-transform fallback).\n * Carries the same stored-XSS protections as the media file route: a sandbox\n * CSP, `nosniff`, and `Content-Disposition: attachment` for anything not on the\n * inline raster allowlist (so a stored SVG can't run scripts in the site\n * origin). Transformed output is always generated raster and doesn't need this.\n */\nexport function originalMediaHeaders(contentType: string): Record<string, string> {\n\treturn {\n\t\t\"Content-Type\": contentType,\n\t\t\"Cache-Control\": IMMUTABLE_IMAGE_CACHE,\n\t\t\"X-Content-Type-Options\": \"nosniff\",\n\t\t\"Content-Security-Policy\":\n\t\t\t\"sandbox; default-src 'none'; img-src 'self'; style-src 'unsafe-inline'\",\n\t\t\"Content-Disposition\": SAFE_INLINE_IMAGE_TYPES.has(contentType) ? \"inline\" : \"attachment\",\n\t};\n}\n\n/** Storage keys safe to serve: the flat `{ulid}{ext}` shape, no slashes/traversal. */\nconst SAFE_STORAGE_KEY = /^[A-Za-z0-9._-]+$/;\n\n/** Plain decimal digits only -- rejects \"1e3\", \"0x10\", \"+5\", whitespace. */\nconst DECIMAL_DIGITS = /^\\d+$/;\n\n/** Whether a storage key is safe to resolve against the storage backend. */\nexport function isSafeTransformKey(key: string): boolean {\n\treturn SAFE_STORAGE_KEY.test(key);\n}\n\n/**\n * If `href` points at the internal EmDash media route\n * (`/_emdash/api/media/file/{key}`) with a safe key, return the key; otherwise\n * `null` (the endpoint then delegates to the stock image endpoint for bundled\n * assets, allowed remote, and `publicUrl` media).\n *\n * The component absolutizes same-origin media (Astro only optimizes absolute,\n * remote-allowed URLs), so `href` is typically `https://site/_emdash/...` but\n * may be relative. We match on the **pathname** only and never fetch `href` —\n * the key is read from our own storage — so the host is irrelevant and can't be\n * an SSRF vector. A dummy base resolves both absolute and relative forms and\n * strips any query/fragment.\n */\nexport function matchInternalMediaKey(href: string | null | undefined): string | null {\n\tif (!href) return null;\n\tlet pathname: string;\n\ttry {\n\t\tpathname = new URL(href, \"http://localhost\").pathname;\n\t} catch {\n\t\treturn null;\n\t}\n\tif (!pathname.startsWith(INTERNAL_MEDIA_PREFIX)) return null;\n\tconst key = pathname.slice(INTERNAL_MEDIA_PREFIX.length);\n\tif (!key || !isSafeTransformKey(key)) return null;\n\treturn key;\n}\n\n/** Type guard for {@link ImageTransformFormat}. */\nexport function isTransformFormat(value: string): value is ImageTransformFormat {\n\treturn (ALLOWED_TRANSFORM_FORMATS as readonly string[]).includes(value);\n}\n\n/** Outcome of parsing transform query params: validated options or an error. */\nexport type ParsedTransformParams =\n\t| { ok: true; options: ImageTransformOptions }\n\t| { ok: false; message: string };\n\n/**\n * Resolve the quality to send to the image binding for a transform. An\n * explicitly-requested quality always wins. Otherwise lossy formats\n * (WebP/AVIF/JPEG) get {@link DEFAULT_TRANSFORM_QUALITY} because the Images\n * binding encodes near-losslessly when quality is omitted; lossless PNG gets\n * `undefined` because an explicit PNG quality switches the binding to lossy\n * PNG8, which is not a safe default for a lossless format.\n */\nexport function resolveTransformQuality(\n\tformat: ImageTransformFormat,\n\trequested: number | undefined,\n): number | undefined {\n\tif (requested !== undefined) return requested;\n\treturn format === \"png\" ? undefined : DEFAULT_TRANSFORM_QUALITY;\n}\n\n/**\n * Parse and validate `?w=&h=&f=&q=` query params. Width is required (it sizes\n * the rendition); dimensions are bounded so a request can't ask for an\n * unbounded or nonsensical transform. Format falls back to\n * {@link DEFAULT_TRANSFORM_FORMAT} when not requested. `q` is validated when\n * present but otherwise left `undefined` so the caller can apply a per-format\n * default (lossy formats get one, lossless PNG does not — see\n * {@link DEFAULT_TRANSFORM_QUALITY}).\n */\nexport function parseTransformParams(params: URLSearchParams): ParsedTransformParams {\n\tconst width = parseDimension(params.get(\"w\"));\n\tif (width === null) return { ok: false, message: \"Invalid 'w' (width)\" };\n\tif (width === undefined) return { ok: false, message: \"Missing 'w' (width)\" };\n\n\tconst height = parseDimension(params.get(\"h\"));\n\tif (height === null) return { ok: false, message: \"Invalid 'h' (height)\" };\n\n\tconst formatRaw = params.get(\"f\");\n\tlet format: ImageTransformFormat = DEFAULT_TRANSFORM_FORMAT;\n\tif (formatRaw !== null) {\n\t\tif (!isTransformFormat(formatRaw)) {\n\t\t\treturn { ok: false, message: `Unsupported 'f' (format): ${formatRaw}` };\n\t\t}\n\t\tformat = formatRaw;\n\t}\n\n\tlet quality: number | undefined;\n\tconst qualityRaw = params.get(\"q\");\n\tif (qualityRaw !== null) {\n\t\tconst q = Number(qualityRaw);\n\t\tif (!Number.isInteger(q) || q < 1 || q > 100) {\n\t\t\treturn { ok: false, message: \"Invalid 'q' (quality), expected 1-100\" };\n\t\t}\n\t\tquality = q;\n\t}\n\n\treturn { ok: true, options: { width, height, format, quality } };\n}\n\n/**\n * Parse a dimension query value.\n * - `undefined`: param absent\n * - `null`: present but invalid (non-integer, out of range)\n * - `number`: valid, within [1, MAX_TRANSFORM_DIMENSION]\n */\nfunction parseDimension(raw: string | null): number | undefined | null {\n\tif (raw === null) return undefined;\n\tif (!DECIMAL_DIGITS.test(raw)) return null;\n\tconst n = Number(raw);\n\tif (n < 1 || n > MAX_TRANSFORM_DIMENSION) return null;\n\treturn n;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;AAiBA,MAAa,4BAA4B;CAAC;CAAQ;CAAQ;CAAQ;CAAM;;AAGxE,MAAa,2BAAiD;;;;;;;;;;AAW9D,MAAa,4BAA4B;;AAGzC,MAAa,0BAA0B;;AAmBvC,MAAa,wBAAwB;;;;;;AAOrC,MAAM,0BAA0B,IAAI,IAAI;CACvC;CACA;CACA;CACA;CACA;CACA;CACA,CAAC;;;;;;;;AASF,SAAgB,qBAAqB,aAA6C;AACjF,QAAO;EACN,gBAAgB;EAChB,iBAAiB;EACjB,0BAA0B;EAC1B,2BACC;EACD,uBAAuB,wBAAwB,IAAI,YAAY,GAAG,WAAW;EAC7E;;;AAIF,MAAM,mBAAmB;;AAGzB,MAAM,iBAAiB;;AAGvB,SAAgB,mBAAmB,KAAsB;AACxD,QAAO,iBAAiB,KAAK,IAAI;;;;;;;;;;;;;;;AAgBlC,SAAgB,sBAAsB,MAAgD;AACrF,KAAI,CAAC,KAAM,QAAO;CAClB,IAAI;AACJ,KAAI;AACH,aAAW,IAAI,IAAI,MAAM,mBAAmB,CAAC;SACtC;AACP,SAAO;;AAER,KAAI,CAAC,SAAS,WAAW,sBAAsB,CAAE,QAAO;CACxD,MAAM,MAAM,SAAS,MAAM,sBAAsB,OAAO;AACxD,KAAI,CAAC,OAAO,CAAC,mBAAmB,IAAI,CAAE,QAAO;AAC7C,QAAO;;;AAIR,SAAgB,kBAAkB,OAA8C;AAC/E,QAAQ,0BAAgD,SAAS,MAAM;;;;;;;;;;AAgBxE,SAAgB,wBACf,QACA,WACqB;AACrB,KAAI,cAAc,OAAW,QAAO;AACpC,QAAO,WAAW,QAAQ,SAAY;;;;;;;;;;;AAYvC,SAAgB,qBAAqB,QAAgD;CACpF,MAAM,QAAQ,eAAe,OAAO,IAAI,IAAI,CAAC;AAC7C,KAAI,UAAU,KAAM,QAAO;EAAE,IAAI;EAAO,SAAS;EAAuB;AACxE,KAAI,UAAU,OAAW,QAAO;EAAE,IAAI;EAAO,SAAS;EAAuB;CAE7E,MAAM,SAAS,eAAe,OAAO,IAAI,IAAI,CAAC;AAC9C,KAAI,WAAW,KAAM,QAAO;EAAE,IAAI;EAAO,SAAS;EAAwB;CAE1E,MAAM,YAAY,OAAO,IAAI,IAAI;CACjC,IAAI,SAA+B;AACnC,KAAI,cAAc,MAAM;AACvB,MAAI,CAAC,kBAAkB,UAAU,CAChC,QAAO;GAAE,IAAI;GAAO,SAAS,6BAA6B;GAAa;AAExE,WAAS;;CAGV,IAAI;CACJ,MAAM,aAAa,OAAO,IAAI,IAAI;AAClC,KAAI,eAAe,MAAM;EACxB,MAAM,IAAI,OAAO,WAAW;AAC5B,MAAI,CAAC,OAAO,UAAU,EAAE,IAAI,IAAI,KAAK,IAAI,IACxC,QAAO;GAAE,IAAI;GAAO,SAAS;GAAyC;AAEvE,YAAU;;AAGX,QAAO;EAAE,IAAI;EAAM,SAAS;GAAE;GAAO;GAAQ;GAAQ;GAAS;EAAE;;;;;;;;AASjE,SAAS,eAAe,KAA+C;AACtE,KAAI,QAAQ,KAAM,QAAO;AACzB,KAAI,CAAC,eAAe,KAAK,IAAI,CAAE,QAAO;CACtC,MAAM,IAAI,OAAO,IAAI;AACrB,KAAI,IAAI,KAAK,IAAI,wBAAyB,QAAO;AACjD,QAAO"}
|
|
1
|
+
{"version":3,"file":"image-endpoint.mjs","names":[],"sources":["../../src/media/image-endpoint.ts"],"sourcesContent":["/**\n * Portable helpers shared by the platform image-endpoint modules.\n *\n * EmDash wraps Astro's image endpoint (`image.endpoint`) so that source bytes\n * for EmDash media are read straight from the storage adapter instead of being\n * fetched over HTTP. The platform endpoint modules (Node: sharp via\n * `astro:assets`; Cloudflare: the `IMAGES` binding) do the actual transform;\n * this module holds the platform-agnostic bits they share: recognizing an\n * EmDash media URL and validating transform query params.\n *\n * Kept free of `astro:*` / `virtual:emdash/*` imports so it stays in the\n * precompiled package and can be unit-tested directly.\n */\n\nimport { INTERNAL_MEDIA_PREFIX } from \"./normalize.js\";\n\n/** Output formats the wrapped endpoint can produce on Cloudflare. */\nexport const ALLOWED_TRANSFORM_FORMATS = [\"webp\", \"avif\", \"jpeg\", \"png\"] as const;\n\n/** Default output format -- broad support, strong compression. */\nexport const DEFAULT_TRANSFORM_FORMAT: ImageTransformFormat = \"webp\";\n\n/**\n * Default output quality for lossy formats (WebP/AVIF/JPEG) when the request\n * doesn't specify one. Matches the default Cloudflare applies to URL-based\n * image transformations. The Images *binding* applies no default of its own\n * and encodes near-losslessly when quality is omitted (a 2048px WebP comes\n * out ~900 KB instead of ~100 KB), so the endpoint sends an explicit quality\n * for lossy output. PNG is exempt: an explicit PNG quality switches the\n * binding to lossy PNG8, which is not a safe default for a lossless format.\n */\nexport const DEFAULT_TRANSFORM_QUALITY = 85;\n\n/** Upper bound for a requested dimension; caps the work a single request asks for. */\nexport const MAX_TRANSFORM_DIMENSION = 4000;\n\n/** A format string accepted by {@link ImageTransformOptions.format}. */\nexport type ImageTransformFormat = (typeof ALLOWED_TRANSFORM_FORMATS)[number];\n\n/** Validated options for a single transform. */\nexport interface ImageTransformOptions {\n\twidth?: number;\n\theight?: number;\n\tformat: ImageTransformFormat;\n\t/**\n\t * Explicitly-requested quality (1-100), or `undefined` when the request\n\t * carried no `q`. Callers apply their own default per format (see\n\t * {@link DEFAULT_TRANSFORM_QUALITY}); lossless PNG deliberately gets none.\n\t */\n\tquality?: number;\n}\n\n/** Long-lived cache for content-addressed image URLs. */\nexport const IMMUTABLE_IMAGE_CACHE = \"public, max-age=31536000, immutable\";\n\n/** Cache policy for media keys that Replace original may overwrite. */\nexport const MUTABLE_MEDIA_CACHE_CONTROL = \"public, max-age=0, must-revalidate\";\n\n/**\n * Raster types safe to render inline. Anything else (SVG, PDF, ...) is served\n * as an attachment so it can't execute as an active document. Mirrors the\n * `/_emdash/api/media/file/{key}` route's allowlist.\n */\nconst SAFE_INLINE_IMAGE_TYPES = new Set([\n\t\"image/jpeg\",\n\t\"image/png\",\n\t\"image/gif\",\n\t\"image/webp\",\n\t\"image/avif\",\n\t\"image/x-icon\",\n]);\n\n/**\n * Headers for streaming **original** stored bytes (the no-transform fallback).\n * Carries the same stored-XSS protections as the media file route: a sandbox\n * CSP, `nosniff`, and `Content-Disposition: attachment` for anything not on the\n * inline raster allowlist (so a stored SVG can't run scripts in the site\n * origin). Transformed output is always generated raster and doesn't need this.\n */\nexport function originalMediaHeaders(contentType: string): Record<string, string> {\n\treturn {\n\t\t\"Content-Type\": contentType,\n\t\t\"Cache-Control\": MUTABLE_MEDIA_CACHE_CONTROL,\n\t\t\"X-Content-Type-Options\": \"nosniff\",\n\t\t\"Content-Security-Policy\":\n\t\t\t\"sandbox; default-src 'none'; img-src 'self'; style-src 'unsafe-inline'\",\n\t\t\"Content-Disposition\": SAFE_INLINE_IMAGE_TYPES.has(contentType) ? \"inline\" : \"attachment\",\n\t};\n}\n\n/** Storage keys safe to serve: the flat `{ulid}{ext}` shape, no slashes/traversal. */\nconst SAFE_STORAGE_KEY = /^[A-Za-z0-9._-]+$/;\n\n/** Plain decimal digits only -- rejects \"1e3\", \"0x10\", \"+5\", whitespace. */\nconst DECIMAL_DIGITS = /^\\d+$/;\n\n/** Whether a storage key is safe to resolve against the storage backend. */\nexport function isSafeTransformKey(key: string): boolean {\n\treturn SAFE_STORAGE_KEY.test(key);\n}\n\n/**\n * If `href` points at the internal EmDash media route\n * (`/_emdash/api/media/file/{key}`) with a safe key, return the key; otherwise\n * `null` (the endpoint then delegates to the stock image endpoint for bundled\n * assets, allowed remote, and `publicUrl` media).\n *\n * The component absolutizes same-origin media (Astro only optimizes absolute,\n * remote-allowed URLs), so `href` is typically `https://site/_emdash/...` but\n * may be relative. We match on the **pathname** only and never fetch `href` —\n * the key is read from our own storage — so the host is irrelevant and can't be\n * an SSRF vector. A dummy base resolves both absolute and relative forms and\n * strips any query/fragment.\n */\nexport function matchInternalMediaKey(href: string | null | undefined): string | null {\n\tif (!href) return null;\n\tlet pathname: string;\n\ttry {\n\t\tpathname = new URL(href, \"http://localhost\").pathname;\n\t} catch {\n\t\treturn null;\n\t}\n\tif (!pathname.startsWith(INTERNAL_MEDIA_PREFIX)) return null;\n\tconst key = pathname.slice(INTERNAL_MEDIA_PREFIX.length);\n\tif (!key || !isSafeTransformKey(key)) return null;\n\treturn key;\n}\n\n/** Type guard for {@link ImageTransformFormat}. */\nexport function isTransformFormat(value: string): value is ImageTransformFormat {\n\treturn (ALLOWED_TRANSFORM_FORMATS as readonly string[]).includes(value);\n}\n\n/** Outcome of parsing transform query params: validated options or an error. */\nexport type ParsedTransformParams =\n\t| { ok: true; options: ImageTransformOptions }\n\t| { ok: false; message: string };\n\n/**\n * Resolve the quality to send to the image binding for a transform. An\n * explicitly-requested quality always wins. Otherwise lossy formats\n * (WebP/AVIF/JPEG) get {@link DEFAULT_TRANSFORM_QUALITY} because the Images\n * binding encodes near-losslessly when quality is omitted; lossless PNG gets\n * `undefined` because an explicit PNG quality switches the binding to lossy\n * PNG8, which is not a safe default for a lossless format.\n */\nexport function resolveTransformQuality(\n\tformat: ImageTransformFormat,\n\trequested: number | undefined,\n): number | undefined {\n\tif (requested !== undefined) return requested;\n\treturn format === \"png\" ? undefined : DEFAULT_TRANSFORM_QUALITY;\n}\n\n/**\n * Parse and validate `?w=&h=&f=&q=` query params. Width is required (it sizes\n * the rendition); dimensions are bounded so a request can't ask for an\n * unbounded or nonsensical transform. Format falls back to\n * {@link DEFAULT_TRANSFORM_FORMAT} when not requested. `q` is validated when\n * present but otherwise left `undefined` so the caller can apply a per-format\n * default (lossy formats get one, lossless PNG does not — see\n * {@link DEFAULT_TRANSFORM_QUALITY}).\n */\nexport function parseTransformParams(params: URLSearchParams): ParsedTransformParams {\n\tconst width = parseDimension(params.get(\"w\"));\n\tif (width === null) return { ok: false, message: \"Invalid 'w' (width)\" };\n\tif (width === undefined) return { ok: false, message: \"Missing 'w' (width)\" };\n\n\tconst height = parseDimension(params.get(\"h\"));\n\tif (height === null) return { ok: false, message: \"Invalid 'h' (height)\" };\n\n\tconst formatRaw = params.get(\"f\");\n\tlet format: ImageTransformFormat = DEFAULT_TRANSFORM_FORMAT;\n\tif (formatRaw !== null) {\n\t\tif (!isTransformFormat(formatRaw)) {\n\t\t\treturn { ok: false, message: `Unsupported 'f' (format): ${formatRaw}` };\n\t\t}\n\t\tformat = formatRaw;\n\t}\n\n\tlet quality: number | undefined;\n\tconst qualityRaw = params.get(\"q\");\n\tif (qualityRaw !== null) {\n\t\tconst q = Number(qualityRaw);\n\t\tif (!Number.isInteger(q) || q < 1 || q > 100) {\n\t\t\treturn { ok: false, message: \"Invalid 'q' (quality), expected 1-100\" };\n\t\t}\n\t\tquality = q;\n\t}\n\n\treturn { ok: true, options: { width, height, format, quality } };\n}\n\n/**\n * Parse a dimension query value.\n * - `undefined`: param absent\n * - `null`: present but invalid (non-integer, out of range)\n * - `number`: valid, within [1, MAX_TRANSFORM_DIMENSION]\n */\nfunction parseDimension(raw: string | null): number | undefined | null {\n\tif (raw === null) return undefined;\n\tif (!DECIMAL_DIGITS.test(raw)) return null;\n\tconst n = Number(raw);\n\tif (n < 1 || n > MAX_TRANSFORM_DIMENSION) return null;\n\treturn n;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;AAiBA,MAAa,4BAA4B;CAAC;CAAQ;CAAQ;CAAQ;CAAM;;AAGxE,MAAa,2BAAiD;;;;;;;;;;AAW9D,MAAa,4BAA4B;;AAGzC,MAAa,0BAA0B;;AAmBvC,MAAa,wBAAwB;;AAGrC,MAAa,8BAA8B;;;;;;AAO3C,MAAM,0BAA0B,IAAI,IAAI;CACvC;CACA;CACA;CACA;CACA;CACA;CACA,CAAC;;;;;;;;AASF,SAAgB,qBAAqB,aAA6C;AACjF,QAAO;EACN,gBAAgB;EAChB,iBAAiB;EACjB,0BAA0B;EAC1B,2BACC;EACD,uBAAuB,wBAAwB,IAAI,YAAY,GAAG,WAAW;EAC7E;;;AAIF,MAAM,mBAAmB;;AAGzB,MAAM,iBAAiB;;AAGvB,SAAgB,mBAAmB,KAAsB;AACxD,QAAO,iBAAiB,KAAK,IAAI;;;;;;;;;;;;;;;AAgBlC,SAAgB,sBAAsB,MAAgD;AACrF,KAAI,CAAC,KAAM,QAAO;CAClB,IAAI;AACJ,KAAI;AACH,aAAW,IAAI,IAAI,MAAM,mBAAmB,CAAC;SACtC;AACP,SAAO;;AAER,KAAI,CAAC,SAAS,WAAW,sBAAsB,CAAE,QAAO;CACxD,MAAM,MAAM,SAAS,MAAM,sBAAsB,OAAO;AACxD,KAAI,CAAC,OAAO,CAAC,mBAAmB,IAAI,CAAE,QAAO;AAC7C,QAAO;;;AAIR,SAAgB,kBAAkB,OAA8C;AAC/E,QAAQ,0BAAgD,SAAS,MAAM;;;;;;;;;;AAgBxE,SAAgB,wBACf,QACA,WACqB;AACrB,KAAI,cAAc,OAAW,QAAO;AACpC,QAAO,WAAW,QAAQ,SAAY;;;;;;;;;;;AAYvC,SAAgB,qBAAqB,QAAgD;CACpF,MAAM,QAAQ,eAAe,OAAO,IAAI,IAAI,CAAC;AAC7C,KAAI,UAAU,KAAM,QAAO;EAAE,IAAI;EAAO,SAAS;EAAuB;AACxE,KAAI,UAAU,OAAW,QAAO;EAAE,IAAI;EAAO,SAAS;EAAuB;CAE7E,MAAM,SAAS,eAAe,OAAO,IAAI,IAAI,CAAC;AAC9C,KAAI,WAAW,KAAM,QAAO;EAAE,IAAI;EAAO,SAAS;EAAwB;CAE1E,MAAM,YAAY,OAAO,IAAI,IAAI;CACjC,IAAI,SAA+B;AACnC,KAAI,cAAc,MAAM;AACvB,MAAI,CAAC,kBAAkB,UAAU,CAChC,QAAO;GAAE,IAAI;GAAO,SAAS,6BAA6B;GAAa;AAExE,WAAS;;CAGV,IAAI;CACJ,MAAM,aAAa,OAAO,IAAI,IAAI;AAClC,KAAI,eAAe,MAAM;EACxB,MAAM,IAAI,OAAO,WAAW;AAC5B,MAAI,CAAC,OAAO,UAAU,EAAE,IAAI,IAAI,KAAK,IAAI,IACxC,QAAO;GAAE,IAAI;GAAO,SAAS;GAAyC;AAEvE,YAAU;;AAGX,QAAO;EAAE,IAAI;EAAM,SAAS;GAAE;GAAO;GAAQ;GAAQ;GAAS;EAAE;;;;;;;;AASjE,SAAS,eAAe,KAA+C;AACtE,KAAI,QAAQ,KAAM,QAAO;AACzB,KAAI,CAAC,eAAe,KAAK,IAAI,CAAE,QAAO;CACtC,MAAM,IAAI,OAAO,IAAI;AACrB,KAAI,IAAI,KAAK,IAAI,wBAAyB,QAAO;AACjD,QAAO"}
|
package/dist/media/index.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { _ as MediaValue, a as ComponentEmbed, b as mediaItemToValue, c as EmbedResult, d as MediaListResult, f as MediaProvider, g as MediaUploadInput, h as MediaProviderItem, i as AudioEmbed, l as ImageEmbed, m as MediaProviderDescriptor, n as generatePlaceholder, o as CreateMediaProviderFn, p as MediaProviderCapabilities, r as normalizeMediaValue, s as EmbedOptions, t as PlaceholderData, u as MediaListOptions, v as ThumbnailOptions, y as VideoEmbed } from "../placeholder-
|
|
1
|
+
import { _ as MediaValue, a as ComponentEmbed, b as mediaItemToValue, c as EmbedResult, d as MediaListResult, f as MediaProvider, g as MediaUploadInput, h as MediaProviderItem, i as AudioEmbed, l as ImageEmbed, m as MediaProviderDescriptor, n as generatePlaceholder, o as CreateMediaProviderFn, p as MediaProviderCapabilities, r as normalizeMediaValue, s as EmbedOptions, t as PlaceholderData, u as MediaListOptions, v as ThumbnailOptions, y as VideoEmbed } from "../placeholder-4X9BrRrp.mjs";
|
|
2
2
|
|
|
3
3
|
//#region src/media/enrich.d.ts
|
|
4
4
|
/**
|
package/dist/media/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { n as normalizeFocalPoint } from "../focal-point-BeWFo6Xx.mjs";
|
|
2
|
-
import { n as normalizeMediaValue } from "../normalize-
|
|
2
|
+
import { n as normalizeMediaValue } from "../normalize-C2xNjTSG.mjs";
|
|
3
3
|
import "../dist-89xCrGqi.mjs";
|
|
4
4
|
import { n as generatePlaceholder, t as enrichImageMetadata } from "../enrich-BX0IDp4z.mjs";
|
|
5
5
|
|
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
import "../options-
|
|
2
|
-
import { t as Database } from "../types-
|
|
3
|
-
import "../types-
|
|
4
|
-
import "../relations-
|
|
5
|
-
import { h as MediaProviderItem, o as CreateMediaProviderFn } from "../placeholder-
|
|
6
|
-
import "../index-
|
|
7
|
-
import "../runner-
|
|
8
|
-
import "../index-
|
|
9
|
-
import { d as Storage } from "../types-
|
|
10
|
-
import "../types-
|
|
11
|
-
import "../hreflang-
|
|
12
|
-
import "../validate-
|
|
1
|
+
import "../options-CYb4y7hM.mjs";
|
|
2
|
+
import { t as Database } from "../types-FV23hEoW.mjs";
|
|
3
|
+
import "../types-B6GrPic4.mjs";
|
|
4
|
+
import "../relations-DnRK4YIT.mjs";
|
|
5
|
+
import { h as MediaProviderItem, o as CreateMediaProviderFn } from "../placeholder-4X9BrRrp.mjs";
|
|
6
|
+
import "../index-BJNMCWmu.mjs";
|
|
7
|
+
import "../runner-YKfIMnaF.mjs";
|
|
8
|
+
import "../index-Du8K7bWa.mjs";
|
|
9
|
+
import { d as Storage } from "../types-CXFkwEGC.mjs";
|
|
10
|
+
import "../types-DczELMop.mjs";
|
|
11
|
+
import "../hreflang-B6hbAuuO.mjs";
|
|
12
|
+
import "../validate-DUP27OYD.mjs";
|
|
13
13
|
import "../index.mjs";
|
|
14
14
|
import { Kysely } from "kysely";
|
|
15
15
|
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import "../dialect-helpers-BSbfaO3F.mjs";
|
|
2
2
|
import "../config-C3EBstHi.mjs";
|
|
3
3
|
import "../after-CBU2vkoO.mjs";
|
|
4
|
-
import "../object-cache-
|
|
4
|
+
import "../object-cache-DVKnyOfy.mjs";
|
|
5
5
|
import "../base64-CvLhUKQv.mjs";
|
|
6
6
|
import "../types-CQPWhPxE.mjs";
|
|
7
|
-
import { t as MediaRepository } from "../media-
|
|
7
|
+
import { t as MediaRepository } from "../media-BBm8Wg3f.mjs";
|
|
8
8
|
import "../options-BHPeIbBd.mjs";
|
|
9
9
|
import "../request-cache-DH9zdCOD.mjs";
|
|
10
|
-
import "../loader-
|
|
11
|
-
import {
|
|
10
|
+
import "../loader-Z8vl7zTq.mjs";
|
|
11
|
+
import { s as invalidateSiteSettingsCache } from "../settings--wobrkkC.mjs";
|
|
12
12
|
|
|
13
13
|
//#region src/media/local-runtime.ts
|
|
14
14
|
/**
|
|
@@ -57,7 +57,7 @@ var MediaRepository = class {
|
|
|
57
57
|
status: input.status ?? "ready",
|
|
58
58
|
created_at: now,
|
|
59
59
|
author_id: input.authorId ?? null,
|
|
60
|
-
folder_id: null
|
|
60
|
+
folder_id: input.folderId ?? null
|
|
61
61
|
};
|
|
62
62
|
await this.db.insertInto("media").values(row).execute();
|
|
63
63
|
return this.rowToItem(row);
|
|
@@ -149,6 +149,21 @@ var MediaRepository = class {
|
|
|
149
149
|
const row = await this.db.selectFrom("media").selectAll().where("filename", "=", filename).executeTakeFirst();
|
|
150
150
|
return row ? this.rowToItem(row) : null;
|
|
151
151
|
}
|
|
152
|
+
async findAvailableFilename(filename) {
|
|
153
|
+
const exists = async (candidate) => Boolean(await this.db.selectFrom("media").select("id").where(sql`lower(filename)`, "=", candidate.toLowerCase()).executeTakeFirst());
|
|
154
|
+
if (!await exists(filename)) return filename;
|
|
155
|
+
const extensionIndex = filename.lastIndexOf(".");
|
|
156
|
+
const hasExtension = extensionIndex > 0;
|
|
157
|
+
const extension = hasExtension ? filename.slice(extensionIndex) : "";
|
|
158
|
+
const stem = hasExtension ? filename.slice(0, extensionIndex) : filename;
|
|
159
|
+
let copyNumber = 2;
|
|
160
|
+
let candidate = `${stem}-${copyNumber}${extension}`;
|
|
161
|
+
while (await exists(candidate)) {
|
|
162
|
+
copyNumber += 1;
|
|
163
|
+
candidate = `${stem}-${copyNumber}${extension}`;
|
|
164
|
+
}
|
|
165
|
+
return candidate;
|
|
166
|
+
}
|
|
152
167
|
/**
|
|
153
168
|
* Find media by content hash
|
|
154
169
|
* Used for deduplication - same content = same hash
|
|
@@ -212,6 +227,19 @@ var MediaRepository = class {
|
|
|
212
227
|
if (Object.keys(updates).length > 0) await this.db.updateTable("media").set(updates).where("id", "=", id).execute();
|
|
213
228
|
return this.findById(id);
|
|
214
229
|
}
|
|
230
|
+
async replaceReadyFile(id, expectedStorageKey, input) {
|
|
231
|
+
const row = await this.db.updateTable("media").set({
|
|
232
|
+
size: input.size,
|
|
233
|
+
width: input.width,
|
|
234
|
+
height: input.height,
|
|
235
|
+
content_hash: input.contentHash,
|
|
236
|
+
blurhash: null,
|
|
237
|
+
dominant_color: null,
|
|
238
|
+
focal_x: null,
|
|
239
|
+
focal_y: null
|
|
240
|
+
}).where("id", "=", id).where("status", "=", "ready").where("storage_key", "=", expectedStorageKey).returningAll().executeTakeFirst();
|
|
241
|
+
return row ? this.rowToItem(row) : null;
|
|
242
|
+
}
|
|
215
243
|
/**
|
|
216
244
|
* Delete media item
|
|
217
245
|
*/
|
|
@@ -287,4 +315,4 @@ var MediaRepository = class {
|
|
|
287
315
|
|
|
288
316
|
//#endregion
|
|
289
317
|
export { MediaRepository as t };
|
|
290
|
-
//# sourceMappingURL=media-
|
|
318
|
+
//# sourceMappingURL=media-BBm8Wg3f.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"media-BBm8Wg3f.mjs","names":[],"sources":["../src/database/repositories/media.ts"],"sourcesContent":["import {\n\tsql,\n\ttype ExpressionBuilder,\n\ttype Kysely,\n\ttype SelectQueryBuilder,\n\ttype SqlBool,\n} from \"kysely\";\nimport { ulid } from \"ulidx\";\n\nimport { normalizeFocalPoint, type FocalPointUpdate } from \"../../media/focal-point.js\";\nimport type { Database, MediaRow } from \"../types.js\";\nimport type { FindManyResult } from \"./types.js\";\nimport { encodeCursor, decodeCursor } from \"./types.js\";\n\n/** Escape LIKE wildcard characters and the escape char itself in user-supplied values */\nfunction escapeLike(value: string): string {\n\treturn value.replaceAll(\"\\\\\", \"\\\\\\\\\").replaceAll(\"%\", \"\\\\%\").replaceAll(\"_\", \"\\\\_\");\n}\n\n/**\n * Normalize a mimeType filter (string or array) into a clean string[].\n * Entries that are empty strings are dropped.\n */\nfunction normalizeMimeFilter(input?: string | readonly string[]): string[] {\n\tif (!input) return [];\n\tconst arr = Array.isArray(input) ? input : [input];\n\treturn arr\n\t\t.filter((entry): entry is string => typeof entry === \"string\" && entry.length > 0)\n\t\t.map((entry) =>\n\t\t\tentry.endsWith(\"/\") ? entry.toLowerCase() : entry.split(\";\")[0].trim().toLowerCase(),\n\t\t);\n}\n\n/**\n * Build a WHERE clause that matches `mime_type` against any of the given\n * filter entries — exact equality for full MIMEs, LIKE prefix for entries\n * ending in \"/\".\n */\nfunction mimeMatchExpr(eb: ExpressionBuilder<Database, \"media\">, filters: string[]) {\n\treturn eb.or(\n\t\tfilters.map((entry) =>\n\t\t\tentry.endsWith(\"/\")\n\t\t\t\t? sql<SqlBool>`mime_type LIKE ${`${escapeLike(entry)}%`} ESCAPE '\\\\'`\n\t\t\t\t: eb(\"mime_type\", \"=\", entry),\n\t\t),\n\t);\n}\n\nexport type MediaStatus = \"pending\" | \"ready\" | \"failed\";\n\nexport interface MediaItem {\n\tid: string;\n\tfilename: string;\n\tmimeType: string;\n\tsize: number | null;\n\twidth: number | null;\n\theight: number | null;\n\tfocalX: number | null;\n\tfocalY: number | null;\n\talt: string | null;\n\tcaption: string | null;\n\tstorageKey: string;\n\tstatus: MediaStatus;\n\tcontentHash: string | null;\n\tblurhash: string | null;\n\tdominantColor: string | null;\n\tcreatedAt: string;\n\tauthorId: string | null;\n\tfolderId?: string | null;\n}\n\nexport interface CreateMediaInput {\n\tfilename: string;\n\tmimeType: string;\n\tsize?: number;\n\twidth?: number;\n\theight?: number;\n\talt?: string;\n\tcaption?: string;\n\tstorageKey: string;\n\tcontentHash?: string;\n\tblurhash?: string;\n\tdominantColor?: string;\n\tstatus?: MediaStatus;\n\tauthorId?: string;\n\tfolderId?: string | null;\n}\n\nexport interface FindManyMediaOptions {\n\tlimit?: number;\n\tcursor?: string;\n\t/** Filter by MIME type. Pass a string for a single prefix/exact, or an array to match any. Strings ending with \"/\" are treated as LIKE prefix matches; others are exact equality. */\n\tmimeType?: string | readonly string[];\n\tstatus?: MediaStatus | \"all\"; // Filter by status, defaults to \"ready\"\n\t/** Case-insensitive substring matched against the filename (covers filename and extension). */\n\tq?: string;\n\t/** Omit for all media, pass null for the Main library, or pass a folder ID. */\n\tfolderId?: string | null;\n}\n\nexport interface UpdateMediaInput extends FocalPointUpdate {\n\talt?: string;\n\tcaption?: string;\n\twidth?: number;\n\theight?: number;\n\tfolderId?: string | null;\n}\n\nexport interface ReplaceReadyMediaInput {\n\tsize: number;\n\twidth: number;\n\theight: number;\n\tcontentHash: string;\n}\n\nexport interface FindMediaPageOptions extends Omit<FindManyMediaOptions, \"cursor\"> {\n\tpage: number;\n}\n\nexport interface MediaPageResult {\n\titems: MediaItem[];\n\ttotalCount: number;\n}\n\nconst UPLOAD_ATTEMPT_CLEANUP_AGE_MS = 60 * 60 * 1000;\nconst UPLOAD_ATTEMPT_CLEANUP_BATCH_SIZE = 100;\n\n/**\n * Media repository for database operations\n */\nexport class MediaRepository {\n\tconstructor(private db: Kysely<Database>) {}\n\n\t/**\n\t * Create a new media item\n\t */\n\tasync create(input: CreateMediaInput): Promise<MediaItem> {\n\t\tconst id = ulid();\n\t\tconst now = new Date().toISOString();\n\n\t\tconst row: Omit<MediaRow, \"rowid\"> = {\n\t\t\tid,\n\t\t\tfilename: input.filename,\n\t\t\tmime_type: input.mimeType,\n\t\t\tsize: input.size ?? null,\n\t\t\twidth: input.width ?? null,\n\t\t\theight: input.height ?? null,\n\t\t\tfocal_x: null,\n\t\t\tfocal_y: null,\n\t\t\talt: input.alt ?? null,\n\t\t\tcaption: input.caption ?? null,\n\t\t\tstorage_key: input.storageKey,\n\t\t\tcontent_hash: input.contentHash ?? null,\n\t\t\tblurhash: input.blurhash ?? null,\n\t\t\tdominant_color: input.dominantColor ?? null,\n\t\t\tstatus: input.status ?? \"ready\",\n\t\t\tcreated_at: now,\n\t\t\tauthor_id: input.authorId ?? null,\n\t\t\tfolder_id: input.folderId ?? null,\n\t\t};\n\n\t\tawait this.db.insertInto(\"media\").values(row).execute();\n\n\t\treturn this.rowToItem(row);\n\t}\n\n\t/**\n\t * Create a pending media item (for signed URL upload flow)\n\t */\n\tasync createPending(input: {\n\t\tfilename: string;\n\t\tmimeType: string;\n\t\tsize?: number;\n\t\tstorageKey: string;\n\t\tcontentHash?: string;\n\t\tauthorId?: string;\n\t\tfolderId?: string | null;\n\t}): Promise<MediaItem> {\n\t\treturn this.create({\n\t\t\t...input,\n\t\t\tstatus: \"pending\",\n\t\t});\n\t}\n\n\tasync createUploadAttempt(mediaId: string, storageKey: string): Promise<void> {\n\t\tconst now = new Date().toISOString();\n\t\tawait this.db\n\t\t\t.insertInto(\"_emdash_media_upload_attempts\")\n\t\t\t.values({\n\t\t\t\tmedia_id: mediaId,\n\t\t\t\tstorage_key: storageKey,\n\t\t\t\tstatus: \"active\",\n\t\t\t\tcreated_at: now,\n\t\t\t\tupdated_at: now,\n\t\t\t})\n\t\t\t.execute();\n\t}\n\n\tasync hasUploadAttempt(storageKey: string): Promise<boolean> {\n\t\tconst row = await this.db\n\t\t\t.selectFrom(\"_emdash_media_upload_attempts\")\n\t\t\t.select(\"storage_key\")\n\t\t\t.where(\"storage_key\", \"=\", storageKey)\n\t\t\t.executeTakeFirst();\n\t\treturn row !== undefined;\n\t}\n\n\tasync claimUploadAttemptForCleanup(storageKey: string): Promise<boolean> {\n\t\tconst result = await this.db\n\t\t\t.updateTable(\"_emdash_media_upload_attempts\")\n\t\t\t.set({ status: \"cleanup\", updated_at: new Date().toISOString() })\n\t\t\t.where(\"storage_key\", \"=\", storageKey)\n\t\t\t.where((eb) =>\n\t\t\t\teb.not(\n\t\t\t\t\teb.exists(\n\t\t\t\t\t\teb\n\t\t\t\t\t\t\t.selectFrom(\"media\")\n\t\t\t\t\t\t\t.select(\"media.id\")\n\t\t\t\t\t\t\t.whereRef(\"media.storage_key\", \"=\", \"_emdash_media_upload_attempts.storage_key\"),\n\t\t\t\t\t),\n\t\t\t\t),\n\t\t\t)\n\t\t\t.executeTakeFirst();\n\n\t\treturn Number(result.numUpdatedRows ?? 0) > 0;\n\t}\n\n\tasync deleteUploadAttempt(storageKey: string): Promise<void> {\n\t\tawait this.db\n\t\t\t.deleteFrom(\"_emdash_media_upload_attempts\")\n\t\t\t.where(\"storage_key\", \"=\", storageKey)\n\t\t\t.execute();\n\t}\n\n\tasync deleteCompletedUploadAttempts(): Promise<number> {\n\t\tconst result = await this.db\n\t\t\t.deleteFrom(\"_emdash_media_upload_attempts\")\n\t\t\t.where((eb) =>\n\t\t\t\teb.exists(\n\t\t\t\t\teb\n\t\t\t\t\t\t.selectFrom(\"media\")\n\t\t\t\t\t\t.select(\"media.id\")\n\t\t\t\t\t\t.whereRef(\"media.id\", \"=\", \"_emdash_media_upload_attempts.media_id\")\n\t\t\t\t\t\t.whereRef(\"media.storage_key\", \"=\", \"_emdash_media_upload_attempts.storage_key\")\n\t\t\t\t\t\t.where(\"media.status\", \"=\", \"ready\"),\n\t\t\t\t),\n\t\t\t)\n\t\t\t.executeTakeFirst();\n\t\treturn Number(result.numDeletedRows ?? 0);\n\t}\n\n\tasync findUploadAttemptsForCleanup(\n\t\tmaxAgeMs: number = UPLOAD_ATTEMPT_CLEANUP_AGE_MS,\n\t\tlimit: number = UPLOAD_ATTEMPT_CLEANUP_BATCH_SIZE,\n\t): Promise<string[]> {\n\t\tconst cutoff = new Date(Date.now() - maxAgeMs).toISOString();\n\t\tconst rows = await this.db\n\t\t\t.selectFrom(\"_emdash_media_upload_attempts\")\n\t\t\t.select(\"storage_key\")\n\t\t\t.where((eb) => eb.or([eb(\"status\", \"=\", \"cleanup\"), eb(\"created_at\", \"<\", cutoff)]))\n\t\t\t.where((eb) =>\n\t\t\t\teb.not(\n\t\t\t\t\teb.exists(\n\t\t\t\t\t\teb\n\t\t\t\t\t\t\t.selectFrom(\"media\")\n\t\t\t\t\t\t\t.select(\"media.id\")\n\t\t\t\t\t\t\t.whereRef(\"media.storage_key\", \"=\", \"_emdash_media_upload_attempts.storage_key\"),\n\t\t\t\t\t),\n\t\t\t\t),\n\t\t\t)\n\t\t\t.orderBy(\"created_at\", \"asc\")\n\t\t\t.limit(limit)\n\t\t\t.execute();\n\n\t\treturn rows.map((row) => row.storage_key);\n\t}\n\n\tasync publishPendingStorageKey(\n\t\tid: string,\n\t\texpectedStorageKey: string,\n\t\tstorageKey: string,\n\t\tcontentHash?: string,\n\t): Promise<boolean> {\n\t\tconst result = await this.db\n\t\t\t.updateTable(\"media\")\n\t\t\t.set({\n\t\t\t\tstorage_key: storageKey,\n\t\t\t\t...(contentHash !== undefined ? { content_hash: contentHash } : {}),\n\t\t\t})\n\t\t\t.where(\"id\", \"=\", id)\n\t\t\t.where(\"status\", \"=\", \"pending\")\n\t\t\t.where(\"storage_key\", \"=\", expectedStorageKey)\n\t\t\t.where((eb) =>\n\t\t\t\teb.exists(\n\t\t\t\t\teb\n\t\t\t\t\t\t.selectFrom(\"_emdash_media_upload_attempts\")\n\t\t\t\t\t\t.select(\"storage_key\")\n\t\t\t\t\t\t.where(\"media_id\", \"=\", id)\n\t\t\t\t\t\t.where(\"storage_key\", \"=\", storageKey)\n\t\t\t\t\t\t.where(\"status\", \"=\", \"active\"),\n\t\t\t\t),\n\t\t\t)\n\t\t\t.executeTakeFirst();\n\n\t\treturn Number(result.numUpdatedRows ?? 0) > 0;\n\t}\n\n\t/**\n\t * Confirm upload (mark as ready)\n\t */\n\tasync confirmUpload(\n\t\tid: string,\n\t\tmetadata?: {\n\t\t\twidth?: number;\n\t\t\theight?: number;\n\t\t\tsize?: number;\n\t\t\tblurhash?: string;\n\t\t\tdominantColor?: string;\n\t\t\tcontentHash?: string | null;\n\t\t},\n\t\texpectedStorageKey?: string,\n\t): Promise<MediaItem | null> {\n\t\tconst updates: Partial<MediaRow> = {\n\t\t\tstatus: \"ready\",\n\t\t};\n\t\tif (metadata?.width !== undefined) updates.width = metadata.width;\n\t\tif (metadata?.height !== undefined) updates.height = metadata.height;\n\t\tif (metadata?.size !== undefined) updates.size = metadata.size;\n\t\tif (metadata?.blurhash !== undefined) updates.blurhash = metadata.blurhash;\n\t\tif (metadata?.dominantColor !== undefined) updates.dominant_color = metadata.dominantColor;\n\t\tif (metadata?.contentHash !== undefined) updates.content_hash = metadata.contentHash;\n\n\t\tlet query = this.db\n\t\t\t.updateTable(\"media\")\n\t\t\t.set(updates)\n\t\t\t.where(\"id\", \"=\", id)\n\t\t\t.where(\"status\", \"=\", \"pending\");\n\t\tif (expectedStorageKey !== undefined) {\n\t\t\tquery = query.where(\"storage_key\", \"=\", expectedStorageKey);\n\t\t}\n\n\t\tconst row = await query.returningAll().executeTakeFirst();\n\n\t\treturn row ? this.rowToItem(row) : null;\n\t}\n\n\t/**\n\t * Mark upload as failed\n\t */\n\tasync markFailed(id: string, expectedStorageKey?: string): Promise<MediaItem | null> {\n\t\tlet query = this.db.updateTable(\"media\").set({ status: \"failed\" }).where(\"id\", \"=\", id);\n\t\tif (expectedStorageKey !== undefined) {\n\t\t\tquery = query.where(\"status\", \"=\", \"pending\").where(\"storage_key\", \"=\", expectedStorageKey);\n\t\t}\n\n\t\tconst row = await query.returningAll().executeTakeFirst();\n\t\treturn row ? this.rowToItem(row) : null;\n\t}\n\n\t/**\n\t * Find media by ID\n\t */\n\tasync findById(id: string): Promise<MediaItem | null> {\n\t\tconst row = await this.db\n\t\t\t.selectFrom(\"media\")\n\t\t\t.selectAll()\n\t\t\t.where(\"id\", \"=\", id)\n\t\t\t.executeTakeFirst();\n\n\t\treturn row ? this.rowToItem(row) : null;\n\t}\n\n\t/**\n\t * Find media by filename\n\t * Useful for idempotent imports\n\t */\n\tasync findByFilename(filename: string): Promise<MediaItem | null> {\n\t\tconst row = await this.db\n\t\t\t.selectFrom(\"media\")\n\t\t\t.selectAll()\n\t\t\t.where(\"filename\", \"=\", filename)\n\t\t\t.executeTakeFirst();\n\n\t\treturn row ? this.rowToItem(row) : null;\n\t}\n\n\tasync findAvailableFilename(filename: string): Promise<string> {\n\t\tconst exists = async (candidate: string) =>\n\t\t\tBoolean(\n\t\t\t\tawait this.db\n\t\t\t\t\t.selectFrom(\"media\")\n\t\t\t\t\t.select(\"id\")\n\t\t\t\t\t.where(sql<string>`lower(filename)`, \"=\", candidate.toLowerCase())\n\t\t\t\t\t.executeTakeFirst(),\n\t\t\t);\n\t\tif (!(await exists(filename))) return filename;\n\n\t\tconst extensionIndex = filename.lastIndexOf(\".\");\n\t\tconst hasExtension = extensionIndex > 0;\n\t\tconst extension = hasExtension ? filename.slice(extensionIndex) : \"\";\n\t\tconst stem = hasExtension ? filename.slice(0, extensionIndex) : filename;\n\t\tlet copyNumber = 2;\n\t\tlet candidate = `${stem}-${copyNumber}${extension}`;\n\t\twhile (await exists(candidate)) {\n\t\t\tcopyNumber += 1;\n\t\t\tcandidate = `${stem}-${copyNumber}${extension}`;\n\t\t}\n\t\treturn candidate;\n\t}\n\n\t/**\n\t * Find media by content hash\n\t * Used for deduplication - same content = same hash\n\t */\n\tasync findByContentHash(contentHash: string): Promise<MediaItem | null> {\n\t\tconst row = await this.db\n\t\t\t.selectFrom(\"media\")\n\t\t\t.selectAll()\n\t\t\t.where(\"content_hash\", \"=\", contentHash)\n\t\t\t.where(\"status\", \"=\", \"ready\")\n\t\t\t.executeTakeFirst();\n\n\t\treturn row ? this.rowToItem(row) : null;\n\t}\n\n\t/**\n\t * Find many media items with cursor pagination\n\t *\n\t * Uses keyset pagination (cursor-based) for consistent results.\n\t * The cursor encodes the created_at and id of the last item.\n\t */\n\tasync findMany(options: FindManyMediaOptions = {}): Promise<FindManyResult<MediaItem>> {\n\t\tconst limit = Math.min(options.limit || 50, 100);\n\n\t\tlet query = this.applyListFilters(this.db.selectFrom(\"media\"), options)\n\t\t\t.selectAll()\n\t\t\t.orderBy(\"created_at\", \"desc\")\n\t\t\t.orderBy(\"id\", \"desc\")\n\t\t\t.limit(limit + 1);\n\n\t\t// Handle cursor-based pagination — throws on invalid cursor.\n\t\tif (options.cursor) {\n\t\t\tconst { orderValue: createdAt, id: cursorId } = decodeCursor(options.cursor);\n\n\t\t\t// Keyset pagination: get items where (created_at, id) < cursor\n\t\t\tquery = query.where((eb) =>\n\t\t\t\teb.or([\n\t\t\t\t\teb(\"created_at\", \"<\", createdAt),\n\t\t\t\t\teb.and([eb(\"created_at\", \"=\", createdAt), eb(\"id\", \"<\", cursorId)]),\n\t\t\t\t]),\n\t\t\t);\n\t\t}\n\n\t\tconst rows = await query.execute();\n\n\t\tconst hasMore = rows.length > limit;\n\t\tconst items = rows.slice(0, limit).map((row) => this.rowToItem(row));\n\n\t\tlet nextCursor: string | undefined;\n\t\tif (hasMore && items.length > 0) {\n\t\t\tconst lastItem = items.at(-1)!;\n\t\t\tnextCursor = encodeCursor(lastItem.createdAt, lastItem.id);\n\t\t}\n\n\t\treturn { items, nextCursor };\n\t}\n\n\tasync findPage(options: FindMediaPageOptions): Promise<MediaPageResult> {\n\t\tconst limit = Math.min(options.limit || 50, 100);\n\t\tconst offset = (options.page - 1) * limit;\n\t\tconst filtered = this.applyListFilters(this.db.selectFrom(\"media\"), options);\n\t\tconst rows = await filtered\n\t\t\t.selectAll()\n\t\t\t.orderBy(\"created_at\", \"desc\")\n\t\t\t.orderBy(\"id\", \"desc\")\n\t\t\t.limit(limit)\n\t\t\t.offset(offset)\n\t\t\t.execute();\n\t\tconst count = await filtered\n\t\t\t.select((eb) => eb.fn.count<number>(\"id\").as(\"count\"))\n\t\t\t.executeTakeFirst();\n\n\t\treturn {\n\t\t\titems: rows.map((row) => this.rowToItem(row)),\n\t\t\ttotalCount: Number(count?.count ?? 0),\n\t\t};\n\t}\n\n\t/**\n\t * Update media metadata\n\t */\n\tasync update(id: string, input: UpdateMediaInput): Promise<MediaItem | null> {\n\t\tconst existing = await this.findById(id);\n\t\tif (!existing) {\n\t\t\treturn null;\n\t\t}\n\n\t\tconst updates: Partial<MediaRow> = {};\n\t\tif (input.alt !== undefined) updates.alt = input.alt;\n\t\tif (input.caption !== undefined) updates.caption = input.caption;\n\t\tif (input.width !== undefined) updates.width = input.width;\n\t\tif (input.height !== undefined) updates.height = input.height;\n\t\tif (input.folderId !== undefined) updates.folder_id = input.folderId;\n\t\tif (input.focalX !== undefined && input.focalY !== undefined) {\n\t\t\tupdates.focal_x = input.focalX;\n\t\t\tupdates.focal_y = input.focalY;\n\t\t}\n\n\t\tif (Object.keys(updates).length > 0) {\n\t\t\tawait this.db.updateTable(\"media\").set(updates).where(\"id\", \"=\", id).execute();\n\t\t}\n\n\t\treturn this.findById(id);\n\t}\n\n\tasync replaceReadyFile(\n\t\tid: string,\n\t\texpectedStorageKey: string,\n\t\tinput: ReplaceReadyMediaInput,\n\t): Promise<MediaItem | null> {\n\t\tconst row = await this.db\n\t\t\t.updateTable(\"media\")\n\t\t\t.set({\n\t\t\t\tsize: input.size,\n\t\t\t\twidth: input.width,\n\t\t\t\theight: input.height,\n\t\t\t\tcontent_hash: input.contentHash,\n\t\t\t\tblurhash: null,\n\t\t\t\tdominant_color: null,\n\t\t\t\tfocal_x: null,\n\t\t\t\tfocal_y: null,\n\t\t\t})\n\t\t\t.where(\"id\", \"=\", id)\n\t\t\t.where(\"status\", \"=\", \"ready\")\n\t\t\t.where(\"storage_key\", \"=\", expectedStorageKey)\n\t\t\t.returningAll()\n\t\t\t.executeTakeFirst();\n\n\t\treturn row ? this.rowToItem(row) : null;\n\t}\n\n\t/**\n\t * Delete media item\n\t */\n\tasync deleteWithStorageKey(id: string): Promise<string | null> {\n\t\tconst deleted = await this.db\n\t\t\t.deleteFrom(\"media\")\n\t\t\t.where(\"id\", \"=\", id)\n\t\t\t.returning(\"storage_key\")\n\t\t\t.executeTakeFirst();\n\t\tif (deleted) return deleted.storage_key;\n\t\treturn null;\n\t}\n\n\tasync delete(id: string): Promise<boolean> {\n\t\treturn (await this.deleteWithStorageKey(id)) !== null;\n\t}\n\n\t/**\n\t * Count media items\n\t */\n\tasync count(mimeType?: string | readonly string[]): Promise<number> {\n\t\tconst filters = normalizeMimeFilter(mimeType);\n\t\tlet query = this.db.selectFrom(\"media\").select((eb) => eb.fn.count<number>(\"id\").as(\"count\"));\n\n\t\tif (filters.length > 0) {\n\t\t\tquery = query.where((eb) => mimeMatchExpr(eb, filters));\n\t\t}\n\n\t\tconst result = await query.executeTakeFirst();\n\t\treturn Number(result?.count || 0);\n\t}\n\n\tprivate applyListFilters<O>(\n\t\tquery: SelectQueryBuilder<Database, \"media\", O>,\n\t\toptions: Omit<FindManyMediaOptions, \"cursor\" | \"limit\">,\n\t): SelectQueryBuilder<Database, \"media\", O> {\n\t\tconst mimeFilters = normalizeMimeFilter(options.mimeType);\n\t\tif (mimeFilters.length > 0) {\n\t\t\tquery = query.where((eb) => mimeMatchExpr(eb, mimeFilters));\n\t\t}\n\n\t\tconst term = options.q?.trim();\n\t\tif (term) {\n\t\t\tconst pattern = `%${escapeLike(term)}%`;\n\t\t\tquery = query.where(\n\t\t\t\tsql<string>`lower(filename)`,\n\t\t\t\t\"like\",\n\t\t\t\tsql<string>`lower(${pattern}) escape '\\\\'`,\n\t\t\t);\n\t\t}\n\n\t\tif (options.status !== \"all\") {\n\t\t\tquery = query.where(\"status\", \"=\", options.status ?? \"ready\");\n\t\t}\n\n\t\tif (options.folderId === null) {\n\t\t\tquery = query.where(\"folder_id\", \"is\", null);\n\t\t} else if (options.folderId !== undefined) {\n\t\t\tquery = query.where(\"folder_id\", \"=\", options.folderId);\n\t\t}\n\n\t\treturn query;\n\t}\n\n\t/**\n\t * Delete pending uploads older than the given age.\n\t * Pending uploads that were never confirmed indicate abandoned upload flows.\n\t *\n\t * Returns the storage keys of deleted rows so callers can remove the\n\t * corresponding files from object storage.\n\t */\n\tasync cleanupPendingUploads(maxAgeMs: number = 60 * 60 * 1000): Promise<string[]> {\n\t\tconst cutoff = new Date(Date.now() - maxAgeMs).toISOString();\n\n\t\tconst rows = await this.db\n\t\t\t.deleteFrom(\"media\")\n\t\t\t.where(\"status\", \"=\", \"pending\")\n\t\t\t.where(\"created_at\", \"<\", cutoff)\n\t\t\t.returning(\"storage_key\")\n\t\t\t.execute();\n\n\t\treturn rows.map((r) => r.storage_key);\n\t}\n\n\t/**\n\t * Convert database row to MediaItem\n\t */\n\tprivate rowToItem(row: MediaRow): MediaItem {\n\t\tconst focalPoint = normalizeFocalPoint(row.focal_x, row.focal_y);\n\t\treturn {\n\t\t\tid: row.id,\n\t\t\tfilename: row.filename,\n\t\t\tmimeType: row.mime_type,\n\t\t\tsize: row.size,\n\t\t\twidth: row.width,\n\t\t\theight: row.height,\n\t\t\tfocalX: focalPoint?.focalX ?? null,\n\t\t\tfocalY: focalPoint?.focalY ?? null,\n\t\t\talt: row.alt,\n\t\t\tcaption: row.caption,\n\t\t\tstorageKey: row.storage_key,\n\t\t\tcontentHash: row.content_hash,\n\t\t\tblurhash: row.blurhash,\n\t\t\tdominantColor: row.dominant_color,\n\t\t\t// eslint-disable-next-line typescript/no-unsafe-type-assertion -- DB stores string; validated at insert but linter can't follow\n\t\t\tstatus: row.status as MediaStatus,\n\t\t\tcreatedAt: row.created_at,\n\t\t\tauthorId: row.author_id,\n\t\t\tfolderId: row.folder_id,\n\t\t};\n\t}\n}\n"],"mappings":"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"}
|
|
@@ -28,7 +28,7 @@ const slugPattern = /^[a-z][a-z0-9_]*$/;
|
|
|
28
28
|
/** Matches http(s) scheme at start of URL */
|
|
29
29
|
const HTTP_SCHEME_RE = /^https?:\/\//i;
|
|
30
30
|
/** Validates that a URL string uses http or https scheme. Rejects javascript:/data: URI XSS vectors. */
|
|
31
|
-
const httpUrl = z.
|
|
31
|
+
const httpUrl = z.url().refine((url) => HTTP_SCHEME_RE.test(url), "URL must use http or https");
|
|
32
32
|
/**
|
|
33
33
|
* BCP 47 locale code — language with optional script/region subtags (e.g. en, en-US, pt-BR, es-419, zh-Hant).
|
|
34
34
|
* Validation is case-insensitive, but the value is preserved verbatim because the site config, stored
|
|
@@ -43,7 +43,7 @@ const apiErrorSchema = z.object({
|
|
|
43
43
|
error: z.object({
|
|
44
44
|
code: z.string().meta({
|
|
45
45
|
description: "Machine-readable error code",
|
|
46
|
-
|
|
46
|
+
examples: ["NOT_FOUND"]
|
|
47
47
|
}),
|
|
48
48
|
message: z.string().meta({ description: "Human-readable error message" })
|
|
49
49
|
})
|
|
@@ -349,9 +349,34 @@ function mediaUploadUrlBody(maxSize) {
|
|
|
349
349
|
contentType: z.string().min(1, "contentType is required").regex(CONTENT_TYPE_RE, "Invalid content type"),
|
|
350
350
|
size: z.number().int().nonnegative().max(maxSize, `File size must not exceed ${formatFileSize(maxSize)}`),
|
|
351
351
|
contentHash: z.string().optional(),
|
|
352
|
-
fieldId: z.string().optional()
|
|
352
|
+
fieldId: z.string().optional(),
|
|
353
|
+
deduplicate: z.boolean().optional(),
|
|
354
|
+
ensureUniqueFilename: z.boolean().optional(),
|
|
355
|
+
folderId: mediaFolderIdSchema.nullable().optional()
|
|
353
356
|
}).meta({ id: "MediaUploadUrlBody" });
|
|
354
357
|
}
|
|
358
|
+
const mediaUploadDeduplicateForm = z.enum(["true", "false"]).default("true").transform((value) => value === "true");
|
|
359
|
+
const mediaUploadEnsureUniqueFilenameForm = z.enum(["true", "false"]).default("false").transform((value) => value === "true");
|
|
360
|
+
const mediaReplaceMetadataForm = z.object({
|
|
361
|
+
width: z.coerce.number().int().positive().max(Number.MAX_SAFE_INTEGER),
|
|
362
|
+
height: z.coerce.number().int().positive().max(Number.MAX_SAFE_INTEGER)
|
|
363
|
+
});
|
|
364
|
+
const binaryFileSchema = z.string().meta({ format: "binary" });
|
|
365
|
+
const mediaDirectUploadBody = z.object({
|
|
366
|
+
file: binaryFileSchema,
|
|
367
|
+
width: z.string().optional(),
|
|
368
|
+
height: z.string().optional(),
|
|
369
|
+
thumbnail: binaryFileSchema.optional(),
|
|
370
|
+
fieldId: z.string().optional(),
|
|
371
|
+
deduplicate: z.enum(["true", "false"]).optional(),
|
|
372
|
+
ensureUniqueFilename: z.enum(["true", "false"]).optional(),
|
|
373
|
+
folderId: z.union([mediaFolderIdSchema, z.literal("unfiled")]).optional()
|
|
374
|
+
}).meta({ id: "MediaDirectUploadBody" });
|
|
375
|
+
const mediaReplaceBody = z.object({
|
|
376
|
+
file: binaryFileSchema,
|
|
377
|
+
width: z.number().int().positive(),
|
|
378
|
+
height: z.number().int().positive()
|
|
379
|
+
}).meta({ id: "MediaReplaceBody" });
|
|
355
380
|
const mediaConfirmBody = z.object({
|
|
356
381
|
size: z.number().int().nonnegative().optional(),
|
|
357
382
|
width: z.number().int().positive().optional(),
|
|
@@ -424,11 +449,16 @@ const mediaExistingResponseSchema = z.object({
|
|
|
424
449
|
url: z.string()
|
|
425
450
|
}).meta({ id: "MediaExistingResponse" });
|
|
426
451
|
const mediaConfirmResponseSchema = z.object({ item: mediaItemSchema.extend({ url: z.string() }) }).meta({ id: "MediaConfirmResponse" });
|
|
452
|
+
const mediaUploadResponseSchema = z.object({
|
|
453
|
+
item: mediaItemSchema.extend({ url: z.string() }),
|
|
454
|
+
deduplicated: z.literal(true).optional()
|
|
455
|
+
}).meta({ id: "MediaUploadResponse" });
|
|
456
|
+
const mediaReplaceResponseSchema = z.object({ item: mediaItemSchema.extend({ url: z.string() }) }).meta({ id: "MediaReplaceResponse" });
|
|
427
457
|
const mediaStreamUploadResponseSchema = z.object({
|
|
428
458
|
uploaded: z.literal(true),
|
|
429
459
|
size: z.number().int().nonnegative()
|
|
430
460
|
}).meta({ id: "MediaStreamUploadResponse" });
|
|
431
461
|
|
|
432
462
|
//#endregion
|
|
433
|
-
export {
|
|
434
|
-
//# sourceMappingURL=media-
|
|
463
|
+
export { mediaUsageProgressSchema as $, mediaUploadEnsureUniqueFilenameForm as A, mediaUsageCollectionDeletionListQuery as B, mediaReplaceBody as C, slugPattern as Ct, mediaStreamUploadResponseSchema as D, mediaResponseSchema as E, mediaUsageActivationAdvanceResponseSchema as F, mediaUsageCollectionDeletionStateSchema as G, mediaUsageCollectionDeletionPhaseSchema as H, mediaUsageActivationConflictSchema as I, mediaUsageDetailsQuery as J, mediaUsageCoverageSchema as K, mediaUsageActivationStateSchema as L, mediaUploadUrlBody as M, mediaUploadUrlResponseSchema as N, mediaUpdateBody as O, mediaUsageActivationAdvanceBody as P, mediaUsageProgressAdvanceResponseSchema as Q, mediaUsageActivationStatusSchema as R, mediaReadResponseSchema as S, roleLevel as St, mediaReplaceResponseSchema as T, mediaUsageCollectionDeletionRetryBody as U, mediaUsageCollectionDeletionListResponseSchema as V, mediaUsageCollectionDeletionRetryResponseSchema as W, mediaUsageEntryDetailSchema as X, mediaUsageDetailsResponseSchema as Y, mediaUsageOccurrenceDetailSchema as Z, mediaListReadItemSchema as _, deleteResponseSchema as _t, mediaConfirmResponseSchema as a, mediaUsageSummarySchema as at, mediaProviderListQuery as b, localeFilterQuery as bt, mediaFolderBody as c, mediaUsageWorkListResponseSchema as ct, mediaFolderListResponseSchema as d, mediaUsageWorkRetryResponseSchema as dt, mediaUsageRepairBody as et, mediaFolderResponseSchema as f, mediaUsageWorkStateSchema as ft, mediaListQuery as g, cursorPaginationQuery as gt, mediaItemSchema as h, countResponseSchema as ht, mediaConfirmBody as i, mediaUsageSourceDetailSchema as it, mediaUploadResponseSchema as j, mediaUploadDeduplicateForm as k, mediaFolderIdSchema as l, mediaUsageWorkRetryBody as lt, mediaGetQuery as m, apiErrorSchema as mt, DEFAULT_MAX_UPLOAD_SIZE as n, mediaUsageRepairResponseSchema as nt, mediaDirectUploadBody as o, mediaUsageWorkItemSchema as ot, mediaFolderSchema as p, VALID_ROLE_LEVELS as pt, mediaUsageCoverageStatusSchema as q, formatFileSize as r, mediaUsageRepairStatusSchema as rt, mediaExistingResponseSchema as s, mediaUsageWorkListQuery as st, CONTENT_TYPE_RE as t, mediaUsageRepairCollectionSummarySchema as tt, mediaFolderListQuery as u, mediaUsageWorkRetryConflictSchema as ut, mediaListReadResponseSchema as v, httpUrl as vt, mediaReplaceMetadataForm as w, successEnvelope as wt, mediaReadItemSchema as x, offsetPaginationQuery as xt, mediaListResponseSchema as y, localeCode as yt, mediaUsageCollectionDeletionItemSchema as z };
|
|
464
|
+
//# sourceMappingURL=media-BHjus86Y.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"media-BHjus86Y.mjs","names":[],"sources":["../src/api/schemas/common.ts","../src/api/schemas/media-usage.ts","../src/api/schemas/media.ts"],"sourcesContent":["import { z } from \"zod\";\n\nimport { LOCALE_CODE_PATTERN } from \"../../i18n/config.js\";\n\n// ---------------------------------------------------------------------------\n// Role level\n// ---------------------------------------------------------------------------\n\n/** Valid role level values */\nexport const VALID_ROLE_LEVELS = new Set([10, 20, 30, 40, 50]);\n\n/** Role level — coerces string/number to valid RoleLevel (10|20|30|40|50) */\nexport const roleLevel = z.coerce\n\t.number()\n\t.int()\n\t.refine((n): n is 10 | 20 | 30 | 40 | 50 => VALID_ROLE_LEVELS.has(n), {\n\t\tmessage: \"Invalid role level. Must be 10, 20, 30, 40, or 50\",\n\t});\n\n// ---------------------------------------------------------------------------\n// Pagination\n// ---------------------------------------------------------------------------\n\n/** Pagination query params — cursor-based */\nexport const cursorPaginationQuery = z\n\t.object({\n\t\tcursor: z.string().max(2048).optional().meta({ description: \"Opaque cursor for pagination\" }),\n\t\tlimit: z.coerce.number().int().min(1).max(100).optional().default(50).meta({\n\t\t\tdescription: \"Maximum number of items to return (1-100, default 50)\",\n\t\t}),\n\t})\n\t.meta({ id: \"CursorPaginationQuery\" });\n\n/** Pagination query params — offset-based */\nexport const offsetPaginationQuery = z\n\t.object({\n\t\tlimit: z.coerce.number().int().min(1).max(100).optional().default(50),\n\t\toffset: z.coerce.number().int().min(0).optional().default(0),\n\t})\n\t.meta({ id: \"OffsetPaginationQuery\" });\n\n// ---------------------------------------------------------------------------\n// Shared primitives\n// ---------------------------------------------------------------------------\n\n/** Slug pattern: lowercase letters, digits, underscores; starts with letter */\nexport const slugPattern = /^[a-z][a-z0-9_]*$/;\n\n/** Matches http(s) scheme at start of URL */\nconst HTTP_SCHEME_RE = /^https?:\\/\\//i;\n\n/** Validates that a URL string uses http or https scheme. Rejects javascript:/data: URI XSS vectors. */\nexport const httpUrl = z\n\t.url()\n\t.refine((url) => HTTP_SCHEME_RE.test(url), \"URL must use http or https\");\n\n/**\n * BCP 47 locale code — language with optional script/region subtags (e.g. en, en-US, pt-BR, es-419, zh-Hant).\n * Validation is case-insensitive, but the value is preserved verbatim because the site config, stored\n * `locale` columns, and public query path all keep the raw BCP-47 casing.\n */\nexport const localeCode = z.string().regex(LOCALE_CODE_PATTERN, \"Invalid locale code\");\n\n/** Shared `?locale=xx` query shape for endpoints that filter by locale. */\nexport const localeFilterQuery = z\n\t.object({\n\t\tlocale: localeCode.optional(),\n\t})\n\t.meta({ id: \"LocaleFilterQuery\" });\n\n// ---------------------------------------------------------------------------\n// OpenAPI: Shared response schemas\n// ---------------------------------------------------------------------------\n\n/** Standard API error response */\nexport const apiErrorSchema = z\n\t.object({\n\t\tsuccess: z.literal(false).meta({ description: \"Discriminant: always false for errors\" }),\n\t\terror: z.object({\n\t\t\tcode: z\n\t\t\t\t.string()\n\t\t\t\t.meta({ description: \"Machine-readable error code\", examples: [\"NOT_FOUND\"] }),\n\t\t\tmessage: z.string().meta({ description: \"Human-readable error message\" }),\n\t\t}),\n\t})\n\t.meta({ id: \"ApiError\" });\n\n/** Wrap a data schema in the standard success envelope: { success: true, data: T } */\nexport function successEnvelope<T extends z.ZodType>(dataSchema: T) {\n\treturn z.object({\n\t\tsuccess: z.literal(true).meta({ description: \"Discriminant: always true for success\" }),\n\t\tdata: dataSchema,\n\t});\n}\n\n/** Standard delete response */\nexport const deleteResponseSchema = z.object({ deleted: z.literal(true) }).meta({\n\tid: \"DeleteResponse\",\n});\n\n/** Standard count response */\nexport const countResponseSchema = z\n\t.object({ count: z.number().int().min(0) })\n\t.meta({ id: \"CountResponse\" });\n","import { z } from \"zod\";\n\nimport { slugPattern } from \"./common.js\";\n\nexport const mediaUsageCoverageStatusSchema = z\n\t.enum([\"complete\", \"never\", \"running\", \"partial\", \"failed\", \"stale\", \"unknown\"])\n\t.meta({ id: \"MediaUsageCoverageStatus\" });\n\nexport const mediaUsageCoverageSchema = z\n\t.object({\n\t\tscope: z.literal(\"all_content_collections\"),\n\t\tstatus: mediaUsageCoverageStatusSchema,\n\t})\n\t.meta({ id: \"MediaUsageCoverage\" });\n\nexport const mediaUsageProgressSchema = z\n\t.object({\n\t\tstatus: z.enum([\"indexing\", \"ready\", \"needs_attention\"]),\n\t\treadyCollections: z.number().int().min(0),\n\t\ttotalCollections: z.number().int().min(0),\n\t})\n\t.meta({ id: \"MediaUsageProgress\" });\n\nexport const mediaUsageSummarySchema = z\n\t.object({\n\t\tcount: z.number().int().min(0).nullable(),\n\t\tcoverage: mediaUsageCoverageSchema,\n\t})\n\t.meta({ id: \"MediaUsageSummary\" });\n\nexport const mediaUsageDetailsQuery = z.object({\n\tcursor: z.string().min(1).max(2048).optional().meta({\n\t\tdescription: \"Opaque content-entry-group cursor\",\n\t}),\n\tlimit: z.coerce.number().int().min(1).max(100).optional().default(50).meta({\n\t\tdescription: \"Maximum number of content entry groups to return (1-100, default 50)\",\n\t}),\n});\n\nexport const mediaUsageOccurrenceDetailSchema = z\n\t.object({\n\t\tfieldSlug: z.string(),\n\t\tfieldPath: z.string(),\n\t\toccurrenceIndex: z.number().int().min(0),\n\t\treferenceType: z.enum([\"image_field\", \"file_field\", \"portable_text_image\", \"unknown\"]),\n\t})\n\t.meta({ id: \"MediaUsageOccurrenceDetail\" });\n\nexport const mediaUsageSourceDetailSchema = z\n\t.object({\n\t\tvariant: z.enum([\"columns\", \"draft_overlay\"]),\n\t\toccurrences: z.array(mediaUsageOccurrenceDetailSchema),\n\t})\n\t.meta({ id: \"MediaUsageSourceDetail\" });\n\nexport const mediaUsageEntryDetailSchema = z\n\t.object({\n\t\tcollection: z.string(),\n\t\tcontentId: z.string(),\n\t\ttitle: z.string().nullable(),\n\t\tslug: z.string().nullable(),\n\t\tlocale: z.string().nullable(),\n\t\tstatus: z.string().nullable(),\n\t\tscheduledAt: z.string().nullable(),\n\t\tdeletedAt: z.string().nullable(),\n\t\tsources: z.array(mediaUsageSourceDetailSchema),\n\t})\n\t.meta({ id: \"MediaUsageEntryDetail\" });\n\nexport const mediaUsageDetailsResponseSchema = z\n\t.object({\n\t\titems: z.array(mediaUsageEntryDetailSchema),\n\t\tnextCursor: z.string().optional(),\n\t\tcoverage: mediaUsageCoverageSchema,\n\t})\n\t.meta({ id: \"MediaUsageDetailsResponse\" });\n\nexport const mediaUsageRepairStatusSchema = z\n\t.enum([\"complete\", \"partial\", \"failed\", \"stale\"])\n\t.meta({ id: \"MediaUsageRepairStatus\" });\n\nconst mediaUsageRepairCollectionBody = z\n\t.object({\n\t\tscope: z.literal(\"collection\"),\n\t\tcollection: z.string().min(1).max(63).regex(slugPattern, \"Invalid collection slug\"),\n\t})\n\t.strict();\n\nconst mediaUsageRepairAllBody = z.object({ scope: z.literal(\"all\") }).strict();\n\nexport const mediaUsageRepairBody = z\n\t.discriminatedUnion(\"scope\", [mediaUsageRepairCollectionBody, mediaUsageRepairAllBody])\n\t.meta({ id: \"MediaUsageRepairBody\" });\n\nexport const mediaUsageRepairCollectionSummarySchema = z\n\t.object({\n\t\tcollection: z.string(),\n\t\tstatus: mediaUsageRepairStatusSchema,\n\t\tindexedSourceCount: z.number().int().min(0),\n\t\tfailedSourceCount: z.number().int().min(0),\n\t\tskippedSourceCount: z.number().int().min(0),\n\t\tdeletedSourceCount: z.number().int().min(0),\n\t\tlastErrorCode: z.string().nullable(),\n\t\tstartedAt: z.string(),\n\t\tcompletedAt: z.string().nullable(),\n\t})\n\t.meta({ id: \"MediaUsageRepairCollectionSummary\" });\n\nexport const mediaUsageRepairResponseSchema = z\n\t.object({\n\t\tstatus: mediaUsageRepairStatusSchema,\n\t\tindexedSourceCount: z.number().int().min(0),\n\t\tfailedSourceCount: z.number().int().min(0),\n\t\tskippedSourceCount: z.number().int().min(0),\n\t\tdeletedSourceCount: z.number().int().min(0),\n\t\tcollections: z.array(mediaUsageRepairCollectionSummarySchema),\n\t})\n\t.meta({ id: \"MediaUsageRepairResponse\" });\n\nexport const mediaUsageWorkStateSchema = z\n\t.enum([\"pending\", \"retry\", \"leased\", \"failed\"])\n\t.meta({ id: \"MediaUsageWorkState\" });\n\nexport const mediaUsageWorkListQuery = z.object({\n\tcollection: z.string().min(1).max(63).regex(slugPattern, \"Invalid collection slug\"),\n\tstate: mediaUsageWorkStateSchema.optional(),\n\tcursor: z.string().min(1).max(2048).optional().meta({\n\t\tdescription: \"Opaque work-page cursor\",\n\t}),\n\tlimit: z.coerce.number().int().min(1).max(100).optional().default(50).meta({\n\t\tdescription: \"Maximum number of work items to return (1-100, default 50)\",\n\t}),\n});\n\nexport const mediaUsageWorkItemSchema = z\n\t.object({\n\t\tcollectionId: z.string(),\n\t\tcollectionSlug: z.string(),\n\t\tcontentId: z.string(),\n\t\tstate: mediaUsageWorkStateSchema,\n\t\tattemptCount: z.number().int().min(0),\n\t\tnextAttemptAt: z.string(),\n\t\tleaseExpiresAt: z.string().nullable(),\n\t\tlastAttemptedAt: z.string().nullable(),\n\t\tlastErrorCode: z.string().nullable(),\n\t\tupdatedAt: z.string(),\n\t})\n\t.meta({ id: \"MediaUsageWorkItem\" });\n\nexport const mediaUsageWorkListResponseSchema = z\n\t.object({\n\t\titems: z.array(mediaUsageWorkItemSchema),\n\t\tnextCursor: z.string().optional(),\n\t})\n\t.meta({ id: \"MediaUsageWorkListResponse\" });\n\nconst boundedOpaqueMediaUsageId = z.string().min(1).max(2048);\n\nexport const mediaUsageWorkRetryBody = z\n\t.object({\n\t\tcollectionId: boundedOpaqueMediaUsageId.meta({\n\t\t\tdescription: \"Current immutable collection identity\",\n\t\t}),\n\t\tcontentId: boundedOpaqueMediaUsageId.meta({\n\t\t\tdescription: \"Content entry identity, including a deleted entry\",\n\t\t}),\n\t})\n\t.strict()\n\t.meta({ id: \"MediaUsageWorkRetryBody\" });\n\nexport const mediaUsageWorkRetryResponseSchema = z\n\t.object({\n\t\tchanged: z.boolean(),\n\t\titem: mediaUsageWorkItemSchema,\n\t})\n\t.meta({ id: \"MediaUsageWorkRetryResponse\" });\n\nexport const mediaUsageWorkRetryConflictSchema = z.object({\n\tsuccess: z.literal(false),\n\terror: z.discriminatedUnion(\"code\", [\n\t\tz.object({\n\t\t\tcode: z.literal(\"WORK_LEASE_ACTIVE\"),\n\t\t\tmessage: z.string(),\n\t\t\tdetails: z.object({ leaseExpiresAt: z.string() }),\n\t\t}),\n\t\tz.object({\n\t\t\tcode: z.literal(\"WORK_CHANGED\"),\n\t\t\tmessage: z.string(),\n\t\t}),\n\t]),\n});\n\nexport const mediaUsageActivationStateSchema = z\n\t.enum([\"expanded\", \"activating\", \"active\"])\n\t.meta({ id: \"MediaUsageActivationState\" });\n\nexport const mediaUsageActivationStatusSchema = z\n\t.object({\n\t\tstate: mediaUsageActivationStateSchema,\n\t\tcollectionCursor: z.string().nullable(),\n\t\tattemptCount: z.number().int().min(0),\n\t\tdrainConfirmedAt: z.string().nullable(),\n\t\tlastAttemptedAt: z.string().nullable(),\n\t\tlastErrorCode: z.literal(\"MEDIA_USAGE_ACTIVATION_FAILED\").nullable(),\n\t\tleaseExpiresAt: z.string().nullable(),\n\t\tactivatedAt: z.string().nullable(),\n\t\tupdatedAt: z.string(),\n\t})\n\t.meta({ id: \"MediaUsageActivationStatus\" });\n\nexport const mediaUsageActivationAdvanceBody = z\n\t.object({\n\t\twritersDrained: z.literal(true),\n\t})\n\t.strict()\n\t.meta({ id: \"MediaUsageActivationAdvanceBody\" });\n\nexport const mediaUsageActivationAdvanceResponseSchema = z\n\t.object({\n\t\toutcome: z.enum([\"activating\", \"active\"]),\n\t\tprocessedCollections: z.number().int().min(0).max(1),\n\t\tactivation: mediaUsageActivationStatusSchema,\n\t})\n\t.meta({ id: \"MediaUsageActivationAdvanceResponse\" });\n\nexport const mediaUsageProgressAdvanceResponseSchema = z\n\t.object({\n\t\tactivation: mediaUsageActivationStatusSchema,\n\t\tprogress: mediaUsageProgressSchema.nullable(),\n\t\tnextRequestInMs: z.union([z.literal(0), z.literal(30_000), z.null()]),\n\t})\n\t.meta({ id: \"MediaUsageProgressAdvanceResponse\" });\n\nexport const mediaUsageActivationConflictSchema = z.object({\n\tsuccess: z.literal(false),\n\terror: z.discriminatedUnion(\"code\", [\n\t\tz.object({\n\t\t\tcode: z.literal(\"MEDIA_USAGE_ACTIVATION_BUSY\"),\n\t\t\tmessage: z.string(),\n\t\t\tdetails: z.object({ leaseExpiresAt: z.string() }),\n\t\t}),\n\t\tz.object({\n\t\t\tcode: z.literal(\"MEDIA_USAGE_ACTIVATION_CONFLICT\"),\n\t\t\tmessage: z.string(),\n\t\t}),\n\t\tz.object({\n\t\t\tcode: z.literal(\"MEDIA_USAGE_ACTIVATION_VERSION_MISMATCH\"),\n\t\t\tmessage: z.string(),\n\t\t}),\n\t]),\n});\n\nexport const mediaUsageCollectionDeletionStateSchema = z\n\t.enum([\"pending\", \"retry\", \"leased\", \"failed\"])\n\t.meta({ id: \"MediaUsageCollectionDeletionState\" });\nexport const mediaUsageCollectionDeletionPhaseSchema = z\n\t.enum([\"fence\", \"registry\", \"table\", \"work\", \"sources\", \"status\", \"finalize\"])\n\t.meta({ id: \"MediaUsageCollectionDeletionPhase\" });\nexport const mediaUsageCollectionDeletionListQuery = z\n\t.object({\n\t\tstate: mediaUsageCollectionDeletionStateSchema.optional().default(\"failed\"),\n\t\tcursor: z.string().min(1).max(2048).optional(),\n\t\tlimit: z.coerce.number().int().min(1).max(100).optional().default(50),\n\t})\n\t.meta({ id: \"MediaUsageCollectionDeletionListQuery\" });\nexport const mediaUsageCollectionDeletionItemSchema = z\n\t.object({\n\t\tcollectionId: z.string(),\n\t\tcollectionSlug: z.string(),\n\t\tstate: mediaUsageCollectionDeletionStateSchema,\n\t\tphase: mediaUsageCollectionDeletionPhaseSchema,\n\t\tattemptCount: z.number().int().min(0),\n\t\tnextAttemptAt: z.string(),\n\t\tleaseExpiresAt: z.string().nullable(),\n\t\tlastErrorCode: z.string().nullable(),\n\t\tupdatedAt: z.string(),\n\t})\n\t.meta({ id: \"MediaUsageCollectionDeletionItem\" });\nexport const mediaUsageCollectionDeletionListResponseSchema = z\n\t.object({\n\t\titems: z.array(mediaUsageCollectionDeletionItemSchema),\n\t\tnextCursor: z.string().optional(),\n\t})\n\t.meta({ id: \"MediaUsageCollectionDeletionListResponse\" });\nexport const mediaUsageCollectionDeletionRetryBody = z\n\t.object({ collectionId: boundedOpaqueMediaUsageId })\n\t.strict()\n\t.meta({ id: \"MediaUsageCollectionDeletionRetryBody\" });\nexport const mediaUsageCollectionDeletionRetryResponseSchema = z\n\t.object({\n\t\tchanged: z.boolean(),\n\t\titem: mediaUsageCollectionDeletionItemSchema,\n\t})\n\t.meta({ id: \"MediaUsageCollectionDeletionRetryResponse\" });\n\nexport type MediaUsageRepairRequest = z.infer<typeof mediaUsageRepairBody>;\nexport type MediaUsageRepairResponse = z.infer<typeof mediaUsageRepairResponseSchema>;\nexport type MediaUsageProgress = z.infer<typeof mediaUsageProgressSchema>;\nexport type MediaUsageProgressAdvanceResponse = z.infer<\n\ttypeof mediaUsageProgressAdvanceResponseSchema\n>;\nexport type MediaUsageWorkListQuery = z.infer<typeof mediaUsageWorkListQuery>;\nexport type MediaUsageWorkItem = z.infer<typeof mediaUsageWorkItemSchema>;\nexport type MediaUsageWorkListResponse = z.infer<typeof mediaUsageWorkListResponseSchema>;\nexport type MediaUsageWorkRetryRequest = z.infer<typeof mediaUsageWorkRetryBody>;\nexport type MediaUsageWorkRetryResponse = z.infer<typeof mediaUsageWorkRetryResponseSchema>;\nexport type MediaUsageActivationStatus = z.infer<typeof mediaUsageActivationStatusSchema>;\nexport type MediaUsageActivationAdvanceRequest = z.infer<typeof mediaUsageActivationAdvanceBody>;\nexport type MediaUsageActivationAdvanceResponse = z.infer<\n\ttypeof mediaUsageActivationAdvanceResponseSchema\n>;\nexport type MediaUsageCollectionDeletionListQuery = z.infer<\n\ttypeof mediaUsageCollectionDeletionListQuery\n>;\nexport type MediaUsageCollectionDeletionListResponse = z.infer<\n\ttypeof mediaUsageCollectionDeletionListResponseSchema\n>;\nexport type MediaUsageCollectionDeletionRetryRequest = z.infer<\n\ttypeof mediaUsageCollectionDeletionRetryBody\n>;\nexport type MediaUsageCollectionDeletionRetryResponse = z.infer<\n\ttypeof mediaUsageCollectionDeletionRetryResponseSchema\n>;\nexport type MediaUsageCoverageStatus = z.infer<typeof mediaUsageCoverageStatusSchema>;\nexport type MediaUsageCoverage = z.infer<typeof mediaUsageCoverageSchema>;\nexport type MediaUsageSummary = z.infer<typeof mediaUsageSummarySchema>;\nexport type MediaUsageOccurrenceDetail = z.infer<typeof mediaUsageOccurrenceDetailSchema>;\nexport type MediaUsageSourceDetail = z.infer<typeof mediaUsageSourceDetailSchema>;\nexport type MediaUsageEntryDetail = z.infer<typeof mediaUsageEntryDetailSchema>;\nexport type MediaUsageDetailsResponse = z.infer<typeof mediaUsageDetailsResponseSchema>;\n","import { z } from \"zod\";\n\nimport { isValidFocalPointUpdate } from \"#media/focal-point.js\";\n\nimport { cursorPaginationQuery } from \"./common.js\";\nimport { mediaUsageSummarySchema } from \"./media-usage.js\";\n\n// ---------------------------------------------------------------------------\n// Media: Input schemas\n// ---------------------------------------------------------------------------\n\n/**\n * Accepts a comma-separated string (from URL query params) or an array of\n * strings (from JSON body or programmatic use) and normalises to string[].\n */\nconst mimeTypeFilter = z\n\t.union([z.string(), z.array(z.string())])\n\t.transform((v) => {\n\t\tconst arr = Array.isArray(v) ? v : v.split(\",\");\n\t\treturn arr.map((s) => s.trim()).filter((s) => s.length > 0);\n\t})\n\t.optional();\n\nexport const mediaListQuery = cursorPaginationQuery\n\t.extend({\n\t\tpage: z.coerce.number().int().min(1).max(Number.MAX_SAFE_INTEGER).optional(),\n\t\tmimeType: mimeTypeFilter,\n\t\tfolderId: z\n\t\t\t.union([z.literal(\"unfiled\"), z.string().min(1).max(64)])\n\t\t\t.optional()\n\t\t\t.meta({\n\t\t\t\tdescription:\n\t\t\t\t\t\"Filter by a media folder ID. Use `unfiled` for the Main library; omit for all media.\",\n\t\t\t}),\n\t\t/** Case-insensitive filename substring search (also matches extensions). */\n\t\tq: z.string().trim().min(1).max(200).optional(),\n\t\tincludeUsage: z.literal(\"1\").optional().meta({\n\t\t\tdescription: \"Include a coverage-aware usage summary on each media item\",\n\t\t}),\n\t})\n\t.refine(({ cursor, page }) => cursor === undefined || page === undefined, {\n\t\tmessage: \"cursor and page cannot be used together\",\n\t\tpath: [\"page\"],\n\t})\n\t.meta({ id: \"MediaListQuery\" });\n\nexport const mediaGetQuery = z\n\t.object({\n\t\tincludeUsage: z.literal(\"1\").optional().meta({\n\t\t\tdescription: \"Include a coverage-aware usage summary on the media item\",\n\t\t}),\n\t})\n\t.meta({ id: \"MediaGetQuery\" });\n\nexport const mediaUpdateBody = z\n\t.object({\n\t\talt: z.string().optional(),\n\t\tcaption: z.string().optional(),\n\t\twidth: z.number().int().positive().optional(),\n\t\theight: z.number().int().positive().optional(),\n\t\tfolderId: z\n\t\t\t.union([z.literal(\"unfiled\"), z.string().min(1).max(64)])\n\t\t\t.nullable()\n\t\t\t.optional()\n\t\t\t.transform((value) => (value === \"unfiled\" ? null : value))\n\t\t\t.meta({\n\t\t\t\tdescription:\n\t\t\t\t\t\"Assign a media folder ID, or use null or `unfiled` to return the item to the Main library.\",\n\t\t\t}),\n\t\tfocalX: z.number().min(0).max(1).nullable().optional(),\n\t\tfocalY: z.number().min(0).max(1).nullable().optional(),\n\t})\n\t.superRefine((value, context) => {\n\t\tif (!isValidFocalPointUpdate(value)) {\n\t\t\tcontext.addIssue({\n\t\t\t\tcode: \"custom\",\n\t\t\t\tmessage: \"focalX and focalY must both be numbers or both be null\",\n\t\t\t\tpath: [\"focalX\"],\n\t\t\t});\n\t\t}\n\t})\n\t.meta({ id: \"MediaUpdateBody\" });\n\nexport const mediaFolderIdSchema = z.string().min(1).max(64);\n\nexport const mediaFolderListQuery = cursorPaginationQuery\n\t.extend({ q: z.string().trim().min(1).max(200).optional() })\n\t.meta({ id: \"MediaFolderListQuery\" });\n\nconst mediaFolderNameSchema = z.string().refine(\n\t(value) => {\n\t\tconst length = value.trim().length;\n\t\treturn length >= 1 && length <= 200;\n\t},\n\t{ message: \"Folder name must be between 1 and 200 characters\" },\n);\n\nexport const mediaFolderBody = z\n\t.object({ name: mediaFolderNameSchema })\n\t.meta({ id: \"MediaFolderBody\" });\n\n/** Default maximum allowed file upload size (50 MB). */\nexport const DEFAULT_MAX_UPLOAD_SIZE = 50 * 1024 * 1024;\n\nexport function formatFileSize(bytes: number): string {\n\tif (bytes < 1024) return `${bytes}B`;\n\tif (bytes < 1024 * 1024) return `${Math.floor(bytes / 1024)}KB`;\n\treturn `${Math.floor(bytes / 1024 / 1024)}MB`;\n}\n\n// Matches a full MIME type (type/subtype) with an optional semicolon-delimited\n// parameter section. Forbids CR/LF to prevent header injection.\nexport const CONTENT_TYPE_RE = /^[a-z0-9][a-z0-9!#$&^_+\\-.]*\\/[a-z0-9!#$&^_+\\-.]+(\\s*;[^\\r\\n]*)?$/i;\n\nexport function mediaUploadUrlBody(maxSize: number) {\n\tif (!Number.isFinite(maxSize) || maxSize <= 0) {\n\t\tthrow new Error(`EmDash: maxUploadSize must be a positive finite number, got ${maxSize}`);\n\t}\n\treturn z\n\t\t.object({\n\t\t\tfilename: z.string().min(1, \"filename is required\"),\n\t\t\tcontentType: z\n\t\t\t\t.string()\n\t\t\t\t.min(1, \"contentType is required\")\n\t\t\t\t.regex(CONTENT_TYPE_RE, \"Invalid content type\"),\n\t\t\tsize: z\n\t\t\t\t.number()\n\t\t\t\t.int()\n\t\t\t\t.nonnegative()\n\t\t\t\t.max(maxSize, `File size must not exceed ${formatFileSize(maxSize)}`),\n\t\t\tcontentHash: z.string().optional(),\n\t\t\tfieldId: z.string().optional(),\n\t\t\tdeduplicate: z.boolean().optional(),\n\t\t\tensureUniqueFilename: z.boolean().optional(),\n\t\t\tfolderId: mediaFolderIdSchema.nullable().optional(),\n\t\t})\n\t\t.meta({ id: \"MediaUploadUrlBody\" });\n}\n\nexport const mediaUploadDeduplicateForm = z\n\t.enum([\"true\", \"false\"])\n\t.default(\"true\")\n\t.transform((value) => value === \"true\");\n\nexport const mediaUploadEnsureUniqueFilenameForm = z\n\t.enum([\"true\", \"false\"])\n\t.default(\"false\")\n\t.transform((value) => value === \"true\");\n\nexport const mediaReplaceMetadataForm = z.object({\n\twidth: z.coerce.number().int().positive().max(Number.MAX_SAFE_INTEGER),\n\theight: z.coerce.number().int().positive().max(Number.MAX_SAFE_INTEGER),\n});\n\nconst binaryFileSchema = z.string().meta({ format: \"binary\" });\n\nexport const mediaDirectUploadBody = z\n\t.object({\n\t\tfile: binaryFileSchema,\n\t\twidth: z.string().optional(),\n\t\theight: z.string().optional(),\n\t\tthumbnail: binaryFileSchema.optional(),\n\t\tfieldId: z.string().optional(),\n\t\tdeduplicate: z.enum([\"true\", \"false\"]).optional(),\n\t\tensureUniqueFilename: z.enum([\"true\", \"false\"]).optional(),\n\t\tfolderId: z.union([mediaFolderIdSchema, z.literal(\"unfiled\")]).optional(),\n\t})\n\t.meta({ id: \"MediaDirectUploadBody\" });\n\nexport const mediaReplaceBody = z\n\t.object({\n\t\tfile: binaryFileSchema,\n\t\twidth: z.number().int().positive(),\n\t\theight: z.number().int().positive(),\n\t})\n\t.meta({ id: \"MediaReplaceBody\" });\n\nexport const mediaConfirmBody = z\n\t.object({\n\t\tsize: z.number().int().nonnegative().optional(),\n\t\twidth: z.number().int().positive().optional(),\n\t\theight: z.number().int().positive().optional(),\n\t})\n\t.meta({ id: \"MediaConfirmBody\" });\n\nexport const mediaProviderListQuery = cursorPaginationQuery\n\t.extend({\n\t\tquery: z.string().optional(),\n\t\tmimeType: mimeTypeFilter,\n\t})\n\t.meta({ id: \"MediaProviderListQuery\" });\n\n// ---------------------------------------------------------------------------\n// Media: Response schemas\n// ---------------------------------------------------------------------------\n\nconst mediaStatusSchema = z.enum([\"pending\", \"ready\", \"failed\"]);\n\nexport const mediaItemSchema = z\n\t.object({\n\t\tid: z.string(),\n\t\tfilename: z.string(),\n\t\tmimeType: z.string(),\n\t\tsize: z.number().nullable(),\n\t\twidth: z.number().nullable(),\n\t\theight: z.number().nullable(),\n\t\tfocalX: z.number().nullable(),\n\t\tfocalY: z.number().nullable(),\n\t\talt: z.string().nullable(),\n\t\tcaption: z.string().nullable(),\n\t\tstorageKey: z.string(),\n\t\tstatus: mediaStatusSchema,\n\t\tcontentHash: z.string().nullable(),\n\t\tblurhash: z.string().nullable(),\n\t\tdominantColor: z.string().nullable(),\n\t\tcreatedAt: z.string(),\n\t\tauthorId: z.string().nullable(),\n\t\tfolderId: z.string().nullable(),\n\t})\n\t.meta({ id: \"MediaItem\" });\n\nexport const mediaFolderSchema = z\n\t.object({ id: z.string(), name: z.string() })\n\t.meta({ id: \"MediaFolder\" });\n\nexport const mediaFolderResponseSchema = z\n\t.object({ item: mediaFolderSchema })\n\t.meta({ id: \"MediaFolderResponse\" });\n\nexport const mediaFolderListResponseSchema = z\n\t.object({ items: z.array(mediaFolderSchema), nextCursor: z.string().optional() })\n\t.meta({ id: \"MediaFolderListResponse\" });\n\nexport const mediaResponseSchema = z\n\t.object({ item: mediaItemSchema })\n\t.meta({ id: \"MediaResponse\" });\n\nexport const mediaReadItemSchema = mediaItemSchema\n\t.extend({ usage: mediaUsageSummarySchema.optional() })\n\t.meta({ id: \"MediaReadItem\" });\n\nexport const mediaReadResponseSchema = z\n\t.object({ item: mediaReadItemSchema })\n\t.meta({ id: \"MediaReadResponse\" });\n\nexport const mediaListReadItemSchema = mediaReadItemSchema\n\t.extend({ url: z.string() })\n\t.meta({ id: \"MediaListReadItem\" });\n\nexport const mediaListReadResponseSchema = z\n\t.object({\n\t\titems: z.array(mediaListReadItemSchema),\n\t\tnextCursor: z.string().optional(),\n\t\ttotalCount: z.number().int().nonnegative().optional(),\n\t})\n\t.meta({ id: \"MediaListReadResponse\" });\n\nexport const mediaListResponseSchema = z\n\t.object({\n\t\titems: z.array(mediaItemSchema),\n\t\tnextCursor: z.string().optional(),\n\t\ttotalCount: z.number().int().nonnegative().optional(),\n\t})\n\t.meta({ id: \"MediaListResponse\" });\n\nexport const mediaUploadUrlResponseSchema = z\n\t.object({\n\t\tuploadUrl: z.string(),\n\t\tmethod: z.literal(\"PUT\"),\n\t\theaders: z.record(z.string(), z.string()),\n\t\tmediaId: z.string(),\n\t\tstorageKey: z.string(),\n\t\texpiresAt: z.string(),\n\t})\n\t.meta({ id: \"MediaUploadUrlResponse\" });\n\nexport const mediaExistingResponseSchema = z\n\t.object({\n\t\texisting: z.literal(true),\n\t\tmediaId: z.string(),\n\t\tstorageKey: z.string(),\n\t\turl: z.string(),\n\t})\n\t.meta({ id: \"MediaExistingResponse\" });\n\nexport const mediaConfirmResponseSchema = z\n\t.object({\n\t\titem: mediaItemSchema.extend({ url: z.string() }),\n\t})\n\t.meta({ id: \"MediaConfirmResponse\" });\n\nexport const mediaUploadResponseSchema = z\n\t.object({\n\t\titem: mediaItemSchema.extend({ url: z.string() }),\n\t\tdeduplicated: z.literal(true).optional(),\n\t})\n\t.meta({ id: \"MediaUploadResponse\" });\n\nexport const mediaReplaceResponseSchema = z\n\t.object({ item: mediaItemSchema.extend({ url: z.string() }) })\n\t.meta({ id: \"MediaReplaceResponse\" });\n\nexport const mediaStreamUploadResponseSchema = z\n\t.object({\n\t\tuploaded: z.literal(true),\n\t\tsize: z.number().int().nonnegative(),\n\t})\n\t.meta({ id: \"MediaStreamUploadResponse\" });\n"],"mappings":";;;;;;AASA,MAAa,oBAAoB,IAAI,IAAI;CAAC;CAAI;CAAI;CAAI;CAAI;CAAG,CAAC;;AAG9D,MAAa,YAAY,EAAE,OACzB,QAAQ,CACR,KAAK,CACL,QAAQ,MAAmC,kBAAkB,IAAI,EAAE,EAAE,EACrE,SAAS,qDACT,CAAC;;AAOH,MAAa,wBAAwB,EACnC,OAAO;CACP,QAAQ,EAAE,QAAQ,CAAC,IAAI,KAAK,CAAC,UAAU,CAAC,KAAK,EAAE,aAAa,gCAAgC,CAAC;CAC7F,OAAO,EAAE,OAAO,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,IAAI,IAAI,CAAC,UAAU,CAAC,QAAQ,GAAG,CAAC,KAAK,EAC1E,aAAa,yDACb,CAAC;CACF,CAAC,CACD,KAAK,EAAE,IAAI,yBAAyB,CAAC;;AAGvC,MAAa,wBAAwB,EACnC,OAAO;CACP,OAAO,EAAE,OAAO,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,IAAI,IAAI,CAAC,UAAU,CAAC,QAAQ,GAAG;CACrE,QAAQ,EAAE,OAAO,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,UAAU,CAAC,QAAQ,EAAE;CAC5D,CAAC,CACD,KAAK,EAAE,IAAI,yBAAyB,CAAC;;AAOvC,MAAa,cAAc;;AAG3B,MAAM,iBAAiB;;AAGvB,MAAa,UAAU,EACrB,KAAK,CACL,QAAQ,QAAQ,eAAe,KAAK,IAAI,EAAE,6BAA6B;;;;;;AAOzE,MAAa,aAAa,EAAE,QAAQ,CAAC,MAAM,qBAAqB,sBAAsB;;AAGtF,MAAa,oBAAoB,EAC/B,OAAO,EACP,QAAQ,WAAW,UAAU,EAC7B,CAAC,CACD,KAAK,EAAE,IAAI,qBAAqB,CAAC;;AAOnC,MAAa,iBAAiB,EAC5B,OAAO;CACP,SAAS,EAAE,QAAQ,MAAM,CAAC,KAAK,EAAE,aAAa,yCAAyC,CAAC;CACxF,OAAO,EAAE,OAAO;EACf,MAAM,EACJ,QAAQ,CACR,KAAK;GAAE,aAAa;GAA+B,UAAU,CAAC,YAAY;GAAE,CAAC;EAC/E,SAAS,EAAE,QAAQ,CAAC,KAAK,EAAE,aAAa,gCAAgC,CAAC;EACzE,CAAC;CACF,CAAC,CACD,KAAK,EAAE,IAAI,YAAY,CAAC;;AAG1B,SAAgB,gBAAqC,YAAe;AACnE,QAAO,EAAE,OAAO;EACf,SAAS,EAAE,QAAQ,KAAK,CAAC,KAAK,EAAE,aAAa,yCAAyC,CAAC;EACvF,MAAM;EACN,CAAC;;;AAIH,MAAa,uBAAuB,EAAE,OAAO,EAAE,SAAS,EAAE,QAAQ,KAAK,EAAE,CAAC,CAAC,KAAK,EAC/E,IAAI,kBACJ,CAAC;;AAGF,MAAa,sBAAsB,EACjC,OAAO,EAAE,OAAO,EAAE,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE,EAAE,CAAC,CAC1C,KAAK,EAAE,IAAI,iBAAiB,CAAC;;;;ACnG/B,MAAa,iCAAiC,EAC5C,KAAK;CAAC;CAAY;CAAS;CAAW;CAAW;CAAU;CAAS;CAAU,CAAC,CAC/E,KAAK,EAAE,IAAI,4BAA4B,CAAC;AAE1C,MAAa,2BAA2B,EACtC,OAAO;CACP,OAAO,EAAE,QAAQ,0BAA0B;CAC3C,QAAQ;CACR,CAAC,CACD,KAAK,EAAE,IAAI,sBAAsB,CAAC;AAEpC,MAAa,2BAA2B,EACtC,OAAO;CACP,QAAQ,EAAE,KAAK;EAAC;EAAY;EAAS;EAAkB,CAAC;CACxD,kBAAkB,EAAE,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE;CACzC,kBAAkB,EAAE,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE;CACzC,CAAC,CACD,KAAK,EAAE,IAAI,sBAAsB,CAAC;AAEpC,MAAa,0BAA0B,EACrC,OAAO;CACP,OAAO,EAAE,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,UAAU;CACzC,UAAU;CACV,CAAC,CACD,KAAK,EAAE,IAAI,qBAAqB,CAAC;AAEnC,MAAa,yBAAyB,EAAE,OAAO;CAC9C,QAAQ,EAAE,QAAQ,CAAC,IAAI,EAAE,CAAC,IAAI,KAAK,CAAC,UAAU,CAAC,KAAK,EACnD,aAAa,qCACb,CAAC;CACF,OAAO,EAAE,OAAO,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,IAAI,IAAI,CAAC,UAAU,CAAC,QAAQ,GAAG,CAAC,KAAK,EAC1E,aAAa,wEACb,CAAC;CACF,CAAC;AAEF,MAAa,mCAAmC,EAC9C,OAAO;CACP,WAAW,EAAE,QAAQ;CACrB,WAAW,EAAE,QAAQ;CACrB,iBAAiB,EAAE,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE;CACxC,eAAe,EAAE,KAAK;EAAC;EAAe;EAAc;EAAuB;EAAU,CAAC;CACtF,CAAC,CACD,KAAK,EAAE,IAAI,8BAA8B,CAAC;AAE5C,MAAa,+BAA+B,EAC1C,OAAO;CACP,SAAS,EAAE,KAAK,CAAC,WAAW,gBAAgB,CAAC;CAC7C,aAAa,EAAE,MAAM,iCAAiC;CACtD,CAAC,CACD,KAAK,EAAE,IAAI,0BAA0B,CAAC;AAExC,MAAa,8BAA8B,EACzC,OAAO;CACP,YAAY,EAAE,QAAQ;CACtB,WAAW,EAAE,QAAQ;CACrB,OAAO,EAAE,QAAQ,CAAC,UAAU;CAC5B,MAAM,EAAE,QAAQ,CAAC,UAAU;CAC3B,QAAQ,EAAE,QAAQ,CAAC,UAAU;CAC7B,QAAQ,EAAE,QAAQ,CAAC,UAAU;CAC7B,aAAa,EAAE,QAAQ,CAAC,UAAU;CAClC,WAAW,EAAE,QAAQ,CAAC,UAAU;CAChC,SAAS,EAAE,MAAM,6BAA6B;CAC9C,CAAC,CACD,KAAK,EAAE,IAAI,yBAAyB,CAAC;AAEvC,MAAa,kCAAkC,EAC7C,OAAO;CACP,OAAO,EAAE,MAAM,4BAA4B;CAC3C,YAAY,EAAE,QAAQ,CAAC,UAAU;CACjC,UAAU;CACV,CAAC,CACD,KAAK,EAAE,IAAI,6BAA6B,CAAC;AAE3C,MAAa,+BAA+B,EAC1C,KAAK;CAAC;CAAY;CAAW;CAAU;CAAQ,CAAC,CAChD,KAAK,EAAE,IAAI,0BAA0B,CAAC;AAExC,MAAM,iCAAiC,EACrC,OAAO;CACP,OAAO,EAAE,QAAQ,aAAa;CAC9B,YAAY,EAAE,QAAQ,CAAC,IAAI,EAAE,CAAC,IAAI,GAAG,CAAC,MAAM,aAAa,0BAA0B;CACnF,CAAC,CACD,QAAQ;AAEV,MAAM,0BAA0B,EAAE,OAAO,EAAE,OAAO,EAAE,QAAQ,MAAM,EAAE,CAAC,CAAC,QAAQ;AAE9E,MAAa,uBAAuB,EAClC,mBAAmB,SAAS,CAAC,gCAAgC,wBAAwB,CAAC,CACtF,KAAK,EAAE,IAAI,wBAAwB,CAAC;AAEtC,MAAa,0CAA0C,EACrD,OAAO;CACP,YAAY,EAAE,QAAQ;CACtB,QAAQ;CACR,oBAAoB,EAAE,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE;CAC3C,mBAAmB,EAAE,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE;CAC1C,oBAAoB,EAAE,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE;CAC3C,oBAAoB,EAAE,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE;CAC3C,eAAe,EAAE,QAAQ,CAAC,UAAU;CACpC,WAAW,EAAE,QAAQ;CACrB,aAAa,EAAE,QAAQ,CAAC,UAAU;CAClC,CAAC,CACD,KAAK,EAAE,IAAI,qCAAqC,CAAC;AAEnD,MAAa,iCAAiC,EAC5C,OAAO;CACP,QAAQ;CACR,oBAAoB,EAAE,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE;CAC3C,mBAAmB,EAAE,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE;CAC1C,oBAAoB,EAAE,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE;CAC3C,oBAAoB,EAAE,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE;CAC3C,aAAa,EAAE,MAAM,wCAAwC;CAC7D,CAAC,CACD,KAAK,EAAE,IAAI,4BAA4B,CAAC;AAE1C,MAAa,4BAA4B,EACvC,KAAK;CAAC;CAAW;CAAS;CAAU;CAAS,CAAC,CAC9C,KAAK,EAAE,IAAI,uBAAuB,CAAC;AAErC,MAAa,0BAA0B,EAAE,OAAO;CAC/C,YAAY,EAAE,QAAQ,CAAC,IAAI,EAAE,CAAC,IAAI,GAAG,CAAC,MAAM,aAAa,0BAA0B;CACnF,OAAO,0BAA0B,UAAU;CAC3C,QAAQ,EAAE,QAAQ,CAAC,IAAI,EAAE,CAAC,IAAI,KAAK,CAAC,UAAU,CAAC,KAAK,EACnD,aAAa,2BACb,CAAC;CACF,OAAO,EAAE,OAAO,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,IAAI,IAAI,CAAC,UAAU,CAAC,QAAQ,GAAG,CAAC,KAAK,EAC1E,aAAa,8DACb,CAAC;CACF,CAAC;AAEF,MAAa,2BAA2B,EACtC,OAAO;CACP,cAAc,EAAE,QAAQ;CACxB,gBAAgB,EAAE,QAAQ;CAC1B,WAAW,EAAE,QAAQ;CACrB,OAAO;CACP,cAAc,EAAE,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE;CACrC,eAAe,EAAE,QAAQ;CACzB,gBAAgB,EAAE,QAAQ,CAAC,UAAU;CACrC,iBAAiB,EAAE,QAAQ,CAAC,UAAU;CACtC,eAAe,EAAE,QAAQ,CAAC,UAAU;CACpC,WAAW,EAAE,QAAQ;CACrB,CAAC,CACD,KAAK,EAAE,IAAI,sBAAsB,CAAC;AAEpC,MAAa,mCAAmC,EAC9C,OAAO;CACP,OAAO,EAAE,MAAM,yBAAyB;CACxC,YAAY,EAAE,QAAQ,CAAC,UAAU;CACjC,CAAC,CACD,KAAK,EAAE,IAAI,8BAA8B,CAAC;AAE5C,MAAM,4BAA4B,EAAE,QAAQ,CAAC,IAAI,EAAE,CAAC,IAAI,KAAK;AAE7D,MAAa,0BAA0B,EACrC,OAAO;CACP,cAAc,0BAA0B,KAAK,EAC5C,aAAa,yCACb,CAAC;CACF,WAAW,0BAA0B,KAAK,EACzC,aAAa,qDACb,CAAC;CACF,CAAC,CACD,QAAQ,CACR,KAAK,EAAE,IAAI,2BAA2B,CAAC;AAEzC,MAAa,oCAAoC,EAC/C,OAAO;CACP,SAAS,EAAE,SAAS;CACpB,MAAM;CACN,CAAC,CACD,KAAK,EAAE,IAAI,+BAA+B,CAAC;AAE7C,MAAa,oCAAoC,EAAE,OAAO;CACzD,SAAS,EAAE,QAAQ,MAAM;CACzB,OAAO,EAAE,mBAAmB,QAAQ,CACnC,EAAE,OAAO;EACR,MAAM,EAAE,QAAQ,oBAAoB;EACpC,SAAS,EAAE,QAAQ;EACnB,SAAS,EAAE,OAAO,EAAE,gBAAgB,EAAE,QAAQ,EAAE,CAAC;EACjD,CAAC,EACF,EAAE,OAAO;EACR,MAAM,EAAE,QAAQ,eAAe;EAC/B,SAAS,EAAE,QAAQ;EACnB,CAAC,CACF,CAAC;CACF,CAAC;AAEF,MAAa,kCAAkC,EAC7C,KAAK;CAAC;CAAY;CAAc;CAAS,CAAC,CAC1C,KAAK,EAAE,IAAI,6BAA6B,CAAC;AAE3C,MAAa,mCAAmC,EAC9C,OAAO;CACP,OAAO;CACP,kBAAkB,EAAE,QAAQ,CAAC,UAAU;CACvC,cAAc,EAAE,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE;CACrC,kBAAkB,EAAE,QAAQ,CAAC,UAAU;CACvC,iBAAiB,EAAE,QAAQ,CAAC,UAAU;CACtC,eAAe,EAAE,QAAQ,gCAAgC,CAAC,UAAU;CACpE,gBAAgB,EAAE,QAAQ,CAAC,UAAU;CACrC,aAAa,EAAE,QAAQ,CAAC,UAAU;CAClC,WAAW,EAAE,QAAQ;CACrB,CAAC,CACD,KAAK,EAAE,IAAI,8BAA8B,CAAC;AAE5C,MAAa,kCAAkC,EAC7C,OAAO,EACP,gBAAgB,EAAE,QAAQ,KAAK,EAC/B,CAAC,CACD,QAAQ,CACR,KAAK,EAAE,IAAI,mCAAmC,CAAC;AAEjD,MAAa,4CAA4C,EACvD,OAAO;CACP,SAAS,EAAE,KAAK,CAAC,cAAc,SAAS,CAAC;CACzC,sBAAsB,EAAE,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE;CACpD,YAAY;CACZ,CAAC,CACD,KAAK,EAAE,IAAI,uCAAuC,CAAC;AAErD,MAAa,0CAA0C,EACrD,OAAO;CACP,YAAY;CACZ,UAAU,yBAAyB,UAAU;CAC7C,iBAAiB,EAAE,MAAM;EAAC,EAAE,QAAQ,EAAE;EAAE,EAAE,QAAQ,IAAO;EAAE,EAAE,MAAM;EAAC,CAAC;CACrE,CAAC,CACD,KAAK,EAAE,IAAI,qCAAqC,CAAC;AAEnD,MAAa,qCAAqC,EAAE,OAAO;CAC1D,SAAS,EAAE,QAAQ,MAAM;CACzB,OAAO,EAAE,mBAAmB,QAAQ;EACnC,EAAE,OAAO;GACR,MAAM,EAAE,QAAQ,8BAA8B;GAC9C,SAAS,EAAE,QAAQ;GACnB,SAAS,EAAE,OAAO,EAAE,gBAAgB,EAAE,QAAQ,EAAE,CAAC;GACjD,CAAC;EACF,EAAE,OAAO;GACR,MAAM,EAAE,QAAQ,kCAAkC;GAClD,SAAS,EAAE,QAAQ;GACnB,CAAC;EACF,EAAE,OAAO;GACR,MAAM,EAAE,QAAQ,0CAA0C;GAC1D,SAAS,EAAE,QAAQ;GACnB,CAAC;EACF,CAAC;CACF,CAAC;AAEF,MAAa,0CAA0C,EACrD,KAAK;CAAC;CAAW;CAAS;CAAU;CAAS,CAAC,CAC9C,KAAK,EAAE,IAAI,qCAAqC,CAAC;AACnD,MAAa,0CAA0C,EACrD,KAAK;CAAC;CAAS;CAAY;CAAS;CAAQ;CAAW;CAAU;CAAW,CAAC,CAC7E,KAAK,EAAE,IAAI,qCAAqC,CAAC;AACnD,MAAa,wCAAwC,EACnD,OAAO;CACP,OAAO,wCAAwC,UAAU,CAAC,QAAQ,SAAS;CAC3E,QAAQ,EAAE,QAAQ,CAAC,IAAI,EAAE,CAAC,IAAI,KAAK,CAAC,UAAU;CAC9C,OAAO,EAAE,OAAO,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,IAAI,IAAI,CAAC,UAAU,CAAC,QAAQ,GAAG;CACrE,CAAC,CACD,KAAK,EAAE,IAAI,yCAAyC,CAAC;AACvD,MAAa,yCAAyC,EACpD,OAAO;CACP,cAAc,EAAE,QAAQ;CACxB,gBAAgB,EAAE,QAAQ;CAC1B,OAAO;CACP,OAAO;CACP,cAAc,EAAE,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE;CACrC,eAAe,EAAE,QAAQ;CACzB,gBAAgB,EAAE,QAAQ,CAAC,UAAU;CACrC,eAAe,EAAE,QAAQ,CAAC,UAAU;CACpC,WAAW,EAAE,QAAQ;CACrB,CAAC,CACD,KAAK,EAAE,IAAI,oCAAoC,CAAC;AAClD,MAAa,iDAAiD,EAC5D,OAAO;CACP,OAAO,EAAE,MAAM,uCAAuC;CACtD,YAAY,EAAE,QAAQ,CAAC,UAAU;CACjC,CAAC,CACD,KAAK,EAAE,IAAI,4CAA4C,CAAC;AAC1D,MAAa,wCAAwC,EACnD,OAAO,EAAE,cAAc,2BAA2B,CAAC,CACnD,QAAQ,CACR,KAAK,EAAE,IAAI,yCAAyC,CAAC;AACvD,MAAa,kDAAkD,EAC7D,OAAO;CACP,SAAS,EAAE,SAAS;CACpB,MAAM;CACN,CAAC,CACD,KAAK,EAAE,IAAI,6CAA6C,CAAC;;;;;;;;ACtR3D,MAAM,iBAAiB,EACrB,MAAM,CAAC,EAAE,QAAQ,EAAE,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC,CACxC,WAAW,MAAM;AAEjB,SADY,MAAM,QAAQ,EAAE,GAAG,IAAI,EAAE,MAAM,IAAI,EACpC,KAAK,MAAM,EAAE,MAAM,CAAC,CAAC,QAAQ,MAAM,EAAE,SAAS,EAAE;EAC1D,CACD,UAAU;AAEZ,MAAa,iBAAiB,sBAC5B,OAAO;CACP,MAAM,EAAE,OAAO,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,IAAI,OAAO,iBAAiB,CAAC,UAAU;CAC5E,UAAU;CACV,UAAU,EACR,MAAM,CAAC,EAAE,QAAQ,UAAU,EAAE,EAAE,QAAQ,CAAC,IAAI,EAAE,CAAC,IAAI,GAAG,CAAC,CAAC,CACxD,UAAU,CACV,KAAK,EACL,aACC,wFACD,CAAC;CAEH,GAAG,EAAE,QAAQ,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,IAAI,IAAI,CAAC,UAAU;CAC/C,cAAc,EAAE,QAAQ,IAAI,CAAC,UAAU,CAAC,KAAK,EAC5C,aAAa,6DACb,CAAC;CACF,CAAC,CACD,QAAQ,EAAE,QAAQ,WAAW,WAAW,UAAa,SAAS,QAAW;CACzE,SAAS;CACT,MAAM,CAAC,OAAO;CACd,CAAC,CACD,KAAK,EAAE,IAAI,kBAAkB,CAAC;AAEhC,MAAa,gBAAgB,EAC3B,OAAO,EACP,cAAc,EAAE,QAAQ,IAAI,CAAC,UAAU,CAAC,KAAK,EAC5C,aAAa,4DACb,CAAC,EACF,CAAC,CACD,KAAK,EAAE,IAAI,iBAAiB,CAAC;AAE/B,MAAa,kBAAkB,EAC7B,OAAO;CACP,KAAK,EAAE,QAAQ,CAAC,UAAU;CAC1B,SAAS,EAAE,QAAQ,CAAC,UAAU;CAC9B,OAAO,EAAE,QAAQ,CAAC,KAAK,CAAC,UAAU,CAAC,UAAU;CAC7C,QAAQ,EAAE,QAAQ,CAAC,KAAK,CAAC,UAAU,CAAC,UAAU;CAC9C,UAAU,EACR,MAAM,CAAC,EAAE,QAAQ,UAAU,EAAE,EAAE,QAAQ,CAAC,IAAI,EAAE,CAAC,IAAI,GAAG,CAAC,CAAC,CACxD,UAAU,CACV,UAAU,CACV,WAAW,UAAW,UAAU,YAAY,OAAO,MAAO,CAC1D,KAAK,EACL,aACC,8FACD,CAAC;CACH,QAAQ,EAAE,QAAQ,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC,UAAU,CAAC,UAAU;CACtD,QAAQ,EAAE,QAAQ,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC,UAAU,CAAC,UAAU;CACtD,CAAC,CACD,aAAa,OAAO,YAAY;AAChC,KAAI,CAAC,wBAAwB,MAAM,CAClC,SAAQ,SAAS;EAChB,MAAM;EACN,SAAS;EACT,MAAM,CAAC,SAAS;EAChB,CAAC;EAEF,CACD,KAAK,EAAE,IAAI,mBAAmB,CAAC;AAEjC,MAAa,sBAAsB,EAAE,QAAQ,CAAC,IAAI,EAAE,CAAC,IAAI,GAAG;AAE5D,MAAa,uBAAuB,sBAClC,OAAO,EAAE,GAAG,EAAE,QAAQ,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC,CAC3D,KAAK,EAAE,IAAI,wBAAwB,CAAC;AAEtC,MAAM,wBAAwB,EAAE,QAAQ,CAAC,QACvC,UAAU;CACV,MAAM,SAAS,MAAM,MAAM,CAAC;AAC5B,QAAO,UAAU,KAAK,UAAU;GAEjC,EAAE,SAAS,oDAAoD,CAC/D;AAED,MAAa,kBAAkB,EAC7B,OAAO,EAAE,MAAM,uBAAuB,CAAC,CACvC,KAAK,EAAE,IAAI,mBAAmB,CAAC;;AAGjC,MAAa,0BAA0B,KAAK,OAAO;AAEnD,SAAgB,eAAe,OAAuB;AACrD,KAAI,QAAQ,KAAM,QAAO,GAAG,MAAM;AAClC,KAAI,QAAQ,OAAO,KAAM,QAAO,GAAG,KAAK,MAAM,QAAQ,KAAK,CAAC;AAC5D,QAAO,GAAG,KAAK,MAAM,QAAQ,OAAO,KAAK,CAAC;;AAK3C,MAAa,kBAAkB;AAE/B,SAAgB,mBAAmB,SAAiB;AACnD,KAAI,CAAC,OAAO,SAAS,QAAQ,IAAI,WAAW,EAC3C,OAAM,IAAI,MAAM,+DAA+D,UAAU;AAE1F,QAAO,EACL,OAAO;EACP,UAAU,EAAE,QAAQ,CAAC,IAAI,GAAG,uBAAuB;EACnD,aAAa,EACX,QAAQ,CACR,IAAI,GAAG,0BAA0B,CACjC,MAAM,iBAAiB,uBAAuB;EAChD,MAAM,EACJ,QAAQ,CACR,KAAK,CACL,aAAa,CACb,IAAI,SAAS,6BAA6B,eAAe,QAAQ,GAAG;EACtE,aAAa,EAAE,QAAQ,CAAC,UAAU;EAClC,SAAS,EAAE,QAAQ,CAAC,UAAU;EAC9B,aAAa,EAAE,SAAS,CAAC,UAAU;EACnC,sBAAsB,EAAE,SAAS,CAAC,UAAU;EAC5C,UAAU,oBAAoB,UAAU,CAAC,UAAU;EACnD,CAAC,CACD,KAAK,EAAE,IAAI,sBAAsB,CAAC;;AAGrC,MAAa,6BAA6B,EACxC,KAAK,CAAC,QAAQ,QAAQ,CAAC,CACvB,QAAQ,OAAO,CACf,WAAW,UAAU,UAAU,OAAO;AAExC,MAAa,sCAAsC,EACjD,KAAK,CAAC,QAAQ,QAAQ,CAAC,CACvB,QAAQ,QAAQ,CAChB,WAAW,UAAU,UAAU,OAAO;AAExC,MAAa,2BAA2B,EAAE,OAAO;CAChD,OAAO,EAAE,OAAO,QAAQ,CAAC,KAAK,CAAC,UAAU,CAAC,IAAI,OAAO,iBAAiB;CACtE,QAAQ,EAAE,OAAO,QAAQ,CAAC,KAAK,CAAC,UAAU,CAAC,IAAI,OAAO,iBAAiB;CACvE,CAAC;AAEF,MAAM,mBAAmB,EAAE,QAAQ,CAAC,KAAK,EAAE,QAAQ,UAAU,CAAC;AAE9D,MAAa,wBAAwB,EACnC,OAAO;CACP,MAAM;CACN,OAAO,EAAE,QAAQ,CAAC,UAAU;CAC5B,QAAQ,EAAE,QAAQ,CAAC,UAAU;CAC7B,WAAW,iBAAiB,UAAU;CACtC,SAAS,EAAE,QAAQ,CAAC,UAAU;CAC9B,aAAa,EAAE,KAAK,CAAC,QAAQ,QAAQ,CAAC,CAAC,UAAU;CACjD,sBAAsB,EAAE,KAAK,CAAC,QAAQ,QAAQ,CAAC,CAAC,UAAU;CAC1D,UAAU,EAAE,MAAM,CAAC,qBAAqB,EAAE,QAAQ,UAAU,CAAC,CAAC,CAAC,UAAU;CACzE,CAAC,CACD,KAAK,EAAE,IAAI,yBAAyB,CAAC;AAEvC,MAAa,mBAAmB,EAC9B,OAAO;CACP,MAAM;CACN,OAAO,EAAE,QAAQ,CAAC,KAAK,CAAC,UAAU;CAClC,QAAQ,EAAE,QAAQ,CAAC,KAAK,CAAC,UAAU;CACnC,CAAC,CACD,KAAK,EAAE,IAAI,oBAAoB,CAAC;AAElC,MAAa,mBAAmB,EAC9B,OAAO;CACP,MAAM,EAAE,QAAQ,CAAC,KAAK,CAAC,aAAa,CAAC,UAAU;CAC/C,OAAO,EAAE,QAAQ,CAAC,KAAK,CAAC,UAAU,CAAC,UAAU;CAC7C,QAAQ,EAAE,QAAQ,CAAC,KAAK,CAAC,UAAU,CAAC,UAAU;CAC9C,CAAC,CACD,KAAK,EAAE,IAAI,oBAAoB,CAAC;AAElC,MAAa,yBAAyB,sBACpC,OAAO;CACP,OAAO,EAAE,QAAQ,CAAC,UAAU;CAC5B,UAAU;CACV,CAAC,CACD,KAAK,EAAE,IAAI,0BAA0B,CAAC;AAMxC,MAAM,oBAAoB,EAAE,KAAK;CAAC;CAAW;CAAS;CAAS,CAAC;AAEhE,MAAa,kBAAkB,EAC7B,OAAO;CACP,IAAI,EAAE,QAAQ;CACd,UAAU,EAAE,QAAQ;CACpB,UAAU,EAAE,QAAQ;CACpB,MAAM,EAAE,QAAQ,CAAC,UAAU;CAC3B,OAAO,EAAE,QAAQ,CAAC,UAAU;CAC5B,QAAQ,EAAE,QAAQ,CAAC,UAAU;CAC7B,QAAQ,EAAE,QAAQ,CAAC,UAAU;CAC7B,QAAQ,EAAE,QAAQ,CAAC,UAAU;CAC7B,KAAK,EAAE,QAAQ,CAAC,UAAU;CAC1B,SAAS,EAAE,QAAQ,CAAC,UAAU;CAC9B,YAAY,EAAE,QAAQ;CACtB,QAAQ;CACR,aAAa,EAAE,QAAQ,CAAC,UAAU;CAClC,UAAU,EAAE,QAAQ,CAAC,UAAU;CAC/B,eAAe,EAAE,QAAQ,CAAC,UAAU;CACpC,WAAW,EAAE,QAAQ;CACrB,UAAU,EAAE,QAAQ,CAAC,UAAU;CAC/B,UAAU,EAAE,QAAQ,CAAC,UAAU;CAC/B,CAAC,CACD,KAAK,EAAE,IAAI,aAAa,CAAC;AAE3B,MAAa,oBAAoB,EAC/B,OAAO;CAAE,IAAI,EAAE,QAAQ;CAAE,MAAM,EAAE,QAAQ;CAAE,CAAC,CAC5C,KAAK,EAAE,IAAI,eAAe,CAAC;AAE7B,MAAa,4BAA4B,EACvC,OAAO,EAAE,MAAM,mBAAmB,CAAC,CACnC,KAAK,EAAE,IAAI,uBAAuB,CAAC;AAErC,MAAa,gCAAgC,EAC3C,OAAO;CAAE,OAAO,EAAE,MAAM,kBAAkB;CAAE,YAAY,EAAE,QAAQ,CAAC,UAAU;CAAE,CAAC,CAChF,KAAK,EAAE,IAAI,2BAA2B,CAAC;AAEzC,MAAa,sBAAsB,EACjC,OAAO,EAAE,MAAM,iBAAiB,CAAC,CACjC,KAAK,EAAE,IAAI,iBAAiB,CAAC;AAE/B,MAAa,sBAAsB,gBACjC,OAAO,EAAE,OAAO,wBAAwB,UAAU,EAAE,CAAC,CACrD,KAAK,EAAE,IAAI,iBAAiB,CAAC;AAE/B,MAAa,0BAA0B,EACrC,OAAO,EAAE,MAAM,qBAAqB,CAAC,CACrC,KAAK,EAAE,IAAI,qBAAqB,CAAC;AAEnC,MAAa,0BAA0B,oBACrC,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,CAC3B,KAAK,EAAE,IAAI,qBAAqB,CAAC;AAEnC,MAAa,8BAA8B,EACzC,OAAO;CACP,OAAO,EAAE,MAAM,wBAAwB;CACvC,YAAY,EAAE,QAAQ,CAAC,UAAU;CACjC,YAAY,EAAE,QAAQ,CAAC,KAAK,CAAC,aAAa,CAAC,UAAU;CACrD,CAAC,CACD,KAAK,EAAE,IAAI,yBAAyB,CAAC;AAEvC,MAAa,0BAA0B,EACrC,OAAO;CACP,OAAO,EAAE,MAAM,gBAAgB;CAC/B,YAAY,EAAE,QAAQ,CAAC,UAAU;CACjC,YAAY,EAAE,QAAQ,CAAC,KAAK,CAAC,aAAa,CAAC,UAAU;CACrD,CAAC,CACD,KAAK,EAAE,IAAI,qBAAqB,CAAC;AAEnC,MAAa,+BAA+B,EAC1C,OAAO;CACP,WAAW,EAAE,QAAQ;CACrB,QAAQ,EAAE,QAAQ,MAAM;CACxB,SAAS,EAAE,OAAO,EAAE,QAAQ,EAAE,EAAE,QAAQ,CAAC;CACzC,SAAS,EAAE,QAAQ;CACnB,YAAY,EAAE,QAAQ;CACtB,WAAW,EAAE,QAAQ;CACrB,CAAC,CACD,KAAK,EAAE,IAAI,0BAA0B,CAAC;AAExC,MAAa,8BAA8B,EACzC,OAAO;CACP,UAAU,EAAE,QAAQ,KAAK;CACzB,SAAS,EAAE,QAAQ;CACnB,YAAY,EAAE,QAAQ;CACtB,KAAK,EAAE,QAAQ;CACf,CAAC,CACD,KAAK,EAAE,IAAI,yBAAyB,CAAC;AAEvC,MAAa,6BAA6B,EACxC,OAAO,EACP,MAAM,gBAAgB,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,EACjD,CAAC,CACD,KAAK,EAAE,IAAI,wBAAwB,CAAC;AAEtC,MAAa,4BAA4B,EACvC,OAAO;CACP,MAAM,gBAAgB,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC;CACjD,cAAc,EAAE,QAAQ,KAAK,CAAC,UAAU;CACxC,CAAC,CACD,KAAK,EAAE,IAAI,uBAAuB,CAAC;AAErC,MAAa,6BAA6B,EACxC,OAAO,EAAE,MAAM,gBAAgB,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC,CAC7D,KAAK,EAAE,IAAI,wBAAwB,CAAC;AAEtC,MAAa,kCAAkC,EAC7C,OAAO;CACP,UAAU,EAAE,QAAQ,KAAK;CACzB,MAAM,EAAE,QAAQ,CAAC,KAAK,CAAC,aAAa;CACpC,CAAC,CACD,KAAK,EAAE,IAAI,6BAA6B,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"media-allowlist-
|
|
1
|
+
{"version":3,"file":"media-allowlist-CoTBWoDp.mjs","names":[],"sources":["../src/api/handlers/media-allowlist.ts"],"sourcesContent":["import type { Kysely } from \"kysely\";\n\nimport type { Database } from \"../../database/types.js\";\nimport { parseAllowedMimeTypes } from \"../../media/mime.js\";\n\n/**\n * MIME types allowed for upload by default (when no field-specific list\n * overrides this). Entries ending with \"/\" are prefix-matched (e.g.\n * \"video/\" matches \"video/mp4\", \"video/webm\", etc.).\n *\n * Image types are enumerated explicitly rather than using a bare \"image/\"\n * prefix so that \"image/svg+xml\" is excluded by default: there is no\n * upload-time content validation for SVG, so an unvalidated bare-prefix\n * allowlist would let a Contributor+ upload an SVG with an embedded\n * `<script>`. Fields that genuinely need SVG uploads can still opt in via\n * their own `allowedMimeTypes` (see `resolveFieldAllowlist` below), which is\n * unaffected by this default.\n */\nexport const GLOBAL_UPLOAD_ALLOWLIST: readonly string[] = [\n\t\"image/png\",\n\t\"image/jpeg\",\n\t\"image/gif\",\n\t\"image/webp\",\n\t\"image/avif\",\n\t\"video/\",\n\t\"audio/\",\n\t\"application/pdf\",\n];\n\n/**\n * Resolve the MIME allowlist for a specific field.\n *\n * Returns the field's `allowedMimeTypes` list when the field exists, is of\n * type \"file\" or \"image\", and has a non-empty list configured. Returns null\n * in all other cases — callers should fall back to GLOBAL_UPLOAD_ALLOWLIST.\n *\n * Authentication is the caller's responsibility (the upload routes already\n * gate on `media:upload`).\n */\nexport async function resolveFieldAllowlist(\n\tdb: Kysely<Database>,\n\tfieldId: string,\n): Promise<string[] | null> {\n\tconst row = await db\n\t\t.selectFrom(\"_emdash_fields\")\n\t\t.select([\"type\", \"validation\"])\n\t\t.where(\"id\", \"=\", fieldId)\n\t\t.where(\"type\", \"in\", [\"file\", \"image\"])\n\t\t.executeTakeFirst();\n\n\treturn row ? parseAllowedMimeTypes(row.validation) : null;\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAkBA,MAAa,0BAA6C;CACzD;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;;;;;;;;;;;AAYD,eAAsB,sBACrB,IACA,SAC2B;CAC3B,MAAM,MAAM,MAAM,GAChB,WAAW,iBAAiB,CAC5B,OAAO,CAAC,QAAQ,aAAa,CAAC,CAC9B,MAAM,MAAM,KAAK,QAAQ,CACzB,MAAM,QAAQ,MAAM,CAAC,QAAQ,QAAQ,CAAC,CACtC,kBAAkB;AAEpB,QAAO,MAAM,sBAAsB,IAAI,WAAW,GAAG"}
|
|
@@ -207,4 +207,4 @@ function isUniqueViolation(error) {
|
|
|
207
207
|
|
|
208
208
|
//#endregion
|
|
209
209
|
export { handleMediaFolderUpdate as a, handleMediaFolderList as i, handleMediaFolderDelete as n, handleMediaFolderGet as r, handleMediaFolderCreate as t };
|
|
210
|
-
//# sourceMappingURL=media-folders-
|
|
210
|
+
//# sourceMappingURL=media-folders-BGkATs8n.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"media-folders-D-0CmRZj.mjs","names":[],"sources":["../src/database/repositories/media-folders.ts","../src/api/handlers/media-folders.ts"],"sourcesContent":["import { sql, type Kysely } from \"kysely\";\nimport { ulid } from \"ulidx\";\n\nimport type { Database } from \"../types.js\";\nimport { decodeCursor, EmDashValidationError, encodeCursor, type FindManyResult } from \"./types.js\";\n\nexport interface MediaFolder {\n\tid: string;\n\tname: string;\n}\n\nexport interface FindManyMediaFoldersOptions {\n\tlimit?: number;\n\tcursor?: string;\n\tq?: string;\n}\n\nfunction escapeLike(value: string): string {\n\treturn value.replaceAll(\"\\\\\", \"\\\\\\\\\").replaceAll(\"%\", \"\\\\%\").replaceAll(\"_\", \"\\\\_\");\n}\n\nfunction normalizeFolderSearch(value: string): string {\n\treturn value.trim().normalize(\"NFKC\").toLowerCase();\n}\n\nfunction normalizeFolderName(name: string): { name: string; nameKey: string } {\n\tif (typeof name !== \"string\") {\n\t\tthrow new EmDashValidationError(\"Folder name must be a string\");\n\t}\n\tconst trimmed = name.trim();\n\tif (trimmed.length < 1 || trimmed.length > 200) {\n\t\tthrow new EmDashValidationError(\"Folder name must be between 1 and 200 characters\");\n\t}\n\treturn { name: trimmed, nameKey: trimmed.normalize(\"NFKC\").toLowerCase() };\n}\n\nexport class MediaFolderRepository {\n\tconstructor(private db: Kysely<Database>) {}\n\n\tasync findMany(options: FindManyMediaFoldersOptions = {}): Promise<FindManyResult<MediaFolder>> {\n\t\tconst limit = Math.max(1, Math.min(options.limit ?? 50, 100));\n\t\tlet query = this.db\n\t\t\t.selectFrom(\"media_folders\")\n\t\t\t.select([\"id\", \"name\", \"name_key\"])\n\t\t\t.orderBy(\"name_key\", \"asc\")\n\t\t\t.orderBy(\"id\", \"asc\")\n\t\t\t.limit(limit + 1);\n\n\t\tconst term = normalizeFolderSearch(options.q ?? \"\");\n\t\tif (term) {\n\t\t\tconst pattern = `%${escapeLike(term)}%`;\n\t\t\tquery = query.where(\"name_key\", \"like\", sql<string>`${pattern} escape '\\\\'`);\n\t\t}\n\n\t\tif (options.cursor !== undefined) {\n\t\t\tconst { orderValue: nameKey, id } = decodeCursor(options.cursor);\n\t\t\tquery = query.where((eb) =>\n\t\t\t\teb.or([\n\t\t\t\t\teb(\"name_key\", \">\", nameKey),\n\t\t\t\t\teb.and([eb(\"name_key\", \"=\", nameKey), eb(\"id\", \">\", id)]),\n\t\t\t\t]),\n\t\t\t);\n\t\t}\n\n\t\tconst rows = await query.execute();\n\t\tconst hasMore = rows.length > limit;\n\t\tconst visible = rows.slice(0, limit);\n\t\treturn {\n\t\t\titems: visible.map(({ id, name }) => ({ id, name })),\n\t\t\tnextCursor:\n\t\t\t\thasMore && visible.length > 0\n\t\t\t\t\t? encodeCursor(visible.at(-1)!.name_key, visible.at(-1)!.id)\n\t\t\t\t\t: undefined,\n\t\t};\n\t}\n\n\tasync findById(id: string): Promise<MediaFolder | null> {\n\t\tconst row = await this.db\n\t\t\t.selectFrom(\"media_folders\")\n\t\t\t.select([\"id\", \"name\"])\n\t\t\t.where(\"id\", \"=\", id)\n\t\t\t.executeTakeFirst();\n\t\treturn row ?? null;\n\t}\n\n\tasync create(inputName: string): Promise<MediaFolder> {\n\t\tconst { name, nameKey } = normalizeFolderName(inputName);\n\t\tconst row = await this.db\n\t\t\t.insertInto(\"media_folders\")\n\t\t\t.values({ id: ulid(), name, name_key: nameKey })\n\t\t\t.returning([\"id\", \"name\"])\n\t\t\t.executeTakeFirstOrThrow();\n\t\treturn row;\n\t}\n\n\tasync update(id: string, inputName: string): Promise<MediaFolder | null> {\n\t\tconst { name, nameKey } = normalizeFolderName(inputName);\n\t\tconst row = await this.db\n\t\t\t.updateTable(\"media_folders\")\n\t\t\t.set({ name, name_key: nameKey })\n\t\t\t.where(\"id\", \"=\", id)\n\t\t\t.returning([\"id\", \"name\"])\n\t\t\t.executeTakeFirst();\n\t\treturn row ?? null;\n\t}\n\n\tasync delete(id: string): Promise<boolean> {\n\t\tconst row = await this.db\n\t\t\t.deleteFrom(\"media_folders\")\n\t\t\t.where(\"id\", \"=\", id)\n\t\t\t.returning(\"id\")\n\t\t\t.executeTakeFirst();\n\t\treturn row !== undefined;\n\t}\n}\n","import type { Kysely } from \"kysely\";\n\nimport {\n\tMediaFolderRepository,\n\ttype MediaFolder,\n} from \"../../database/repositories/media-folders.js\";\nimport { EmDashValidationError, InvalidCursorError } from \"../../database/repositories/types.js\";\nimport type { Database } from \"../../database/types.js\";\nimport type { ApiResult } from \"../types.js\";\n\nconst UNIQUE_VIOLATION_RE =\n\t/unique constraint failed|duplicate key value violates unique constraint/i;\n\nexport async function handleMediaFolderList(\n\tdb: Kysely<Database>,\n\toptions: { limit?: number; cursor?: string; q?: string } = {},\n): Promise<ApiResult<{ items: MediaFolder[]; nextCursor?: string }>> {\n\ttry {\n\t\tconst result = await new MediaFolderRepository(db).findMany(options);\n\t\treturn { success: true, data: result };\n\t} catch (error) {\n\t\tif (error instanceof InvalidCursorError) {\n\t\t\treturn { success: false, error: { code: \"INVALID_CURSOR\", message: error.message } };\n\t\t}\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\terror: { code: \"MEDIA_FOLDER_LIST_ERROR\", message: \"Failed to list media folders\" },\n\t\t};\n\t}\n}\n\nexport async function handleMediaFolderGet(\n\tdb: Kysely<Database>,\n\tid: string,\n): Promise<ApiResult<{ item: MediaFolder }>> {\n\ttry {\n\t\tconst item = await new MediaFolderRepository(db).findById(id);\n\t\tif (!item) {\n\t\t\treturn { success: false, error: { code: \"NOT_FOUND\", message: \"Media folder not found\" } };\n\t\t}\n\t\treturn { success: true, data: { item } };\n\t} catch {\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\terror: { code: \"MEDIA_FOLDER_GET_ERROR\", message: \"Failed to get media folder\" },\n\t\t};\n\t}\n}\n\nexport async function handleMediaFolderCreate(\n\tdb: Kysely<Database>,\n\tinput: { name: string },\n): Promise<ApiResult<{ item: MediaFolder }>> {\n\ttry {\n\t\tconst item = await new MediaFolderRepository(db).create(input.name);\n\t\treturn { success: true, data: { item } };\n\t} catch (error) {\n\t\treturn mediaFolderWriteError(\n\t\t\terror,\n\t\t\t\"MEDIA_FOLDER_CREATE_ERROR\",\n\t\t\t\"Failed to create media folder\",\n\t\t);\n\t}\n}\n\nexport async function handleMediaFolderUpdate(\n\tdb: Kysely<Database>,\n\tid: string,\n\tinput: { name: string },\n): Promise<ApiResult<{ item: MediaFolder }>> {\n\ttry {\n\t\tconst item = await new MediaFolderRepository(db).update(id, input.name);\n\t\tif (!item) {\n\t\t\treturn { success: false, error: { code: \"NOT_FOUND\", message: \"Media folder not found\" } };\n\t\t}\n\t\treturn { success: true, data: { item } };\n\t} catch (error) {\n\t\treturn mediaFolderWriteError(\n\t\t\terror,\n\t\t\t\"MEDIA_FOLDER_UPDATE_ERROR\",\n\t\t\t\"Failed to update media folder\",\n\t\t);\n\t}\n}\n\nexport async function handleMediaFolderDelete(\n\tdb: Kysely<Database>,\n\tid: string,\n): Promise<ApiResult<{ deleted: true }>> {\n\ttry {\n\t\tconst deleted = await new MediaFolderRepository(db).delete(id);\n\t\tif (!deleted) {\n\t\t\treturn { success: false, error: { code: \"NOT_FOUND\", message: \"Media folder 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: \"MEDIA_FOLDER_DELETE_ERROR\", message: \"Failed to delete media folder\" },\n\t\t};\n\t}\n}\n\nfunction mediaFolderWriteError(\n\terror: unknown,\n\tcode: \"MEDIA_FOLDER_CREATE_ERROR\" | \"MEDIA_FOLDER_UPDATE_ERROR\",\n\tmessage: string,\n): ApiResult<never> {\n\tif (error instanceof EmDashValidationError) {\n\t\treturn { success: false, error: { code: \"VALIDATION_ERROR\", message: error.message } };\n\t}\n\tif (isUniqueViolation(error)) {\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\terror: { code: \"CONFLICT\", message: \"A media folder with this name already exists\" },\n\t\t};\n\t}\n\treturn { success: false, error: { code, message } };\n}\n\nfunction isUniqueViolation(error: unknown): boolean {\n\tif (error && typeof error === \"object\") {\n\t\tif (\"code\" in error && error.code === \"23505\") return true;\n\t}\n\tconst message = error instanceof Error ? error.message : \"\";\n\tif (UNIQUE_VIOLATION_RE.test(message)) return true;\n\treturn Boolean(\n\t\terror && typeof error === \"object\" && \"cause\" in error && isUniqueViolation(error.cause),\n\t);\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"media-folders-BGkATs8n.mjs","names":[],"sources":["../src/database/repositories/media-folders.ts","../src/api/handlers/media-folders.ts"],"sourcesContent":["import { sql, type Kysely } from \"kysely\";\nimport { ulid } from \"ulidx\";\n\nimport type { Database } from \"../types.js\";\nimport { decodeCursor, EmDashValidationError, encodeCursor, type FindManyResult } from \"./types.js\";\n\nexport interface MediaFolder {\n\tid: string;\n\tname: string;\n}\n\nexport interface FindManyMediaFoldersOptions {\n\tlimit?: number;\n\tcursor?: string;\n\tq?: string;\n}\n\nfunction escapeLike(value: string): string {\n\treturn value.replaceAll(\"\\\\\", \"\\\\\\\\\").replaceAll(\"%\", \"\\\\%\").replaceAll(\"_\", \"\\\\_\");\n}\n\nfunction normalizeFolderSearch(value: string): string {\n\treturn value.trim().normalize(\"NFKC\").toLowerCase();\n}\n\nfunction normalizeFolderName(name: string): { name: string; nameKey: string } {\n\tif (typeof name !== \"string\") {\n\t\tthrow new EmDashValidationError(\"Folder name must be a string\");\n\t}\n\tconst trimmed = name.trim();\n\tif (trimmed.length < 1 || trimmed.length > 200) {\n\t\tthrow new EmDashValidationError(\"Folder name must be between 1 and 200 characters\");\n\t}\n\treturn { name: trimmed, nameKey: trimmed.normalize(\"NFKC\").toLowerCase() };\n}\n\nexport class MediaFolderRepository {\n\tconstructor(private db: Kysely<Database>) {}\n\n\tasync findMany(options: FindManyMediaFoldersOptions = {}): Promise<FindManyResult<MediaFolder>> {\n\t\tconst limit = Math.max(1, Math.min(options.limit ?? 50, 100));\n\t\tlet query = this.db\n\t\t\t.selectFrom(\"media_folders\")\n\t\t\t.select([\"id\", \"name\", \"name_key\"])\n\t\t\t.orderBy(\"name_key\", \"asc\")\n\t\t\t.orderBy(\"id\", \"asc\")\n\t\t\t.limit(limit + 1);\n\n\t\tconst term = normalizeFolderSearch(options.q ?? \"\");\n\t\tif (term) {\n\t\t\tconst pattern = `%${escapeLike(term)}%`;\n\t\t\tquery = query.where(\"name_key\", \"like\", sql<string>`${pattern} escape '\\\\'`);\n\t\t}\n\n\t\tif (options.cursor !== undefined) {\n\t\t\tconst { orderValue: nameKey, id } = decodeCursor(options.cursor);\n\t\t\tquery = query.where((eb) =>\n\t\t\t\teb.or([\n\t\t\t\t\teb(\"name_key\", \">\", nameKey),\n\t\t\t\t\teb.and([eb(\"name_key\", \"=\", nameKey), eb(\"id\", \">\", id)]),\n\t\t\t\t]),\n\t\t\t);\n\t\t}\n\n\t\tconst rows = await query.execute();\n\t\tconst hasMore = rows.length > limit;\n\t\tconst visible = rows.slice(0, limit);\n\t\treturn {\n\t\t\titems: visible.map(({ id, name }) => ({ id, name })),\n\t\t\tnextCursor:\n\t\t\t\thasMore && visible.length > 0\n\t\t\t\t\t? encodeCursor(visible.at(-1)!.name_key, visible.at(-1)!.id)\n\t\t\t\t\t: undefined,\n\t\t};\n\t}\n\n\tasync findById(id: string): Promise<MediaFolder | null> {\n\t\tconst row = await this.db\n\t\t\t.selectFrom(\"media_folders\")\n\t\t\t.select([\"id\", \"name\"])\n\t\t\t.where(\"id\", \"=\", id)\n\t\t\t.executeTakeFirst();\n\t\treturn row ?? null;\n\t}\n\n\tasync create(inputName: string): Promise<MediaFolder> {\n\t\tconst { name, nameKey } = normalizeFolderName(inputName);\n\t\tconst row = await this.db\n\t\t\t.insertInto(\"media_folders\")\n\t\t\t.values({ id: ulid(), name, name_key: nameKey })\n\t\t\t.returning([\"id\", \"name\"])\n\t\t\t.executeTakeFirstOrThrow();\n\t\treturn row;\n\t}\n\n\tasync update(id: string, inputName: string): Promise<MediaFolder | null> {\n\t\tconst { name, nameKey } = normalizeFolderName(inputName);\n\t\tconst row = await this.db\n\t\t\t.updateTable(\"media_folders\")\n\t\t\t.set({ name, name_key: nameKey })\n\t\t\t.where(\"id\", \"=\", id)\n\t\t\t.returning([\"id\", \"name\"])\n\t\t\t.executeTakeFirst();\n\t\treturn row ?? null;\n\t}\n\n\tasync delete(id: string): Promise<boolean> {\n\t\tconst row = await this.db\n\t\t\t.deleteFrom(\"media_folders\")\n\t\t\t.where(\"id\", \"=\", id)\n\t\t\t.returning(\"id\")\n\t\t\t.executeTakeFirst();\n\t\treturn row !== undefined;\n\t}\n}\n","import type { Kysely } from \"kysely\";\n\nimport {\n\tMediaFolderRepository,\n\ttype MediaFolder,\n} from \"../../database/repositories/media-folders.js\";\nimport { EmDashValidationError, InvalidCursorError } from \"../../database/repositories/types.js\";\nimport type { Database } from \"../../database/types.js\";\nimport type { ApiResult } from \"../types.js\";\n\nconst UNIQUE_VIOLATION_RE =\n\t/unique constraint failed|duplicate key value violates unique constraint/i;\n\nexport async function handleMediaFolderList(\n\tdb: Kysely<Database>,\n\toptions: { limit?: number; cursor?: string; q?: string } = {},\n): Promise<ApiResult<{ items: MediaFolder[]; nextCursor?: string }>> {\n\ttry {\n\t\tconst result = await new MediaFolderRepository(db).findMany(options);\n\t\treturn { success: true, data: result };\n\t} catch (error) {\n\t\tif (error instanceof InvalidCursorError) {\n\t\t\treturn { success: false, error: { code: \"INVALID_CURSOR\", message: error.message } };\n\t\t}\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\terror: { code: \"MEDIA_FOLDER_LIST_ERROR\", message: \"Failed to list media folders\" },\n\t\t};\n\t}\n}\n\nexport async function handleMediaFolderGet(\n\tdb: Kysely<Database>,\n\tid: string,\n): Promise<ApiResult<{ item: MediaFolder }>> {\n\ttry {\n\t\tconst item = await new MediaFolderRepository(db).findById(id);\n\t\tif (!item) {\n\t\t\treturn { success: false, error: { code: \"NOT_FOUND\", message: \"Media folder not found\" } };\n\t\t}\n\t\treturn { success: true, data: { item } };\n\t} catch {\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\terror: { code: \"MEDIA_FOLDER_GET_ERROR\", message: \"Failed to get media folder\" },\n\t\t};\n\t}\n}\n\nexport async function handleMediaFolderCreate(\n\tdb: Kysely<Database>,\n\tinput: { name: string },\n): Promise<ApiResult<{ item: MediaFolder }>> {\n\ttry {\n\t\tconst item = await new MediaFolderRepository(db).create(input.name);\n\t\treturn { success: true, data: { item } };\n\t} catch (error) {\n\t\treturn mediaFolderWriteError(\n\t\t\terror,\n\t\t\t\"MEDIA_FOLDER_CREATE_ERROR\",\n\t\t\t\"Failed to create media folder\",\n\t\t);\n\t}\n}\n\nexport async function handleMediaFolderUpdate(\n\tdb: Kysely<Database>,\n\tid: string,\n\tinput: { name: string },\n): Promise<ApiResult<{ item: MediaFolder }>> {\n\ttry {\n\t\tconst item = await new MediaFolderRepository(db).update(id, input.name);\n\t\tif (!item) {\n\t\t\treturn { success: false, error: { code: \"NOT_FOUND\", message: \"Media folder not found\" } };\n\t\t}\n\t\treturn { success: true, data: { item } };\n\t} catch (error) {\n\t\treturn mediaFolderWriteError(\n\t\t\terror,\n\t\t\t\"MEDIA_FOLDER_UPDATE_ERROR\",\n\t\t\t\"Failed to update media folder\",\n\t\t);\n\t}\n}\n\nexport async function handleMediaFolderDelete(\n\tdb: Kysely<Database>,\n\tid: string,\n): Promise<ApiResult<{ deleted: true }>> {\n\ttry {\n\t\tconst deleted = await new MediaFolderRepository(db).delete(id);\n\t\tif (!deleted) {\n\t\t\treturn { success: false, error: { code: \"NOT_FOUND\", message: \"Media folder 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: \"MEDIA_FOLDER_DELETE_ERROR\", message: \"Failed to delete media folder\" },\n\t\t};\n\t}\n}\n\nfunction mediaFolderWriteError(\n\terror: unknown,\n\tcode: \"MEDIA_FOLDER_CREATE_ERROR\" | \"MEDIA_FOLDER_UPDATE_ERROR\",\n\tmessage: string,\n): ApiResult<never> {\n\tif (error instanceof EmDashValidationError) {\n\t\treturn { success: false, error: { code: \"VALIDATION_ERROR\", message: error.message } };\n\t}\n\tif (isUniqueViolation(error)) {\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\terror: { code: \"CONFLICT\", message: \"A media folder with this name already exists\" },\n\t\t};\n\t}\n\treturn { success: false, error: { code, message } };\n}\n\nfunction isUniqueViolation(error: unknown): boolean {\n\tif (error && typeof error === \"object\") {\n\t\tif (\"code\" in error && error.code === \"23505\") return true;\n\t}\n\tconst message = error instanceof Error ? error.message : \"\";\n\tif (UNIQUE_VIOLATION_RE.test(message)) return true;\n\treturn Boolean(\n\t\terror && typeof error === \"object\" && \"cause\" in error && isUniqueViolation(error.cause),\n\t);\n}\n"],"mappings":"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"}
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import "./config-C3EBstHi.mjs";
|
|
2
2
|
import { n as decodeBase64Bytes } from "./base64-CvLhUKQv.mjs";
|
|
3
3
|
import "./types-CQPWhPxE.mjs";
|
|
4
|
-
import { t as MediaRepository } from "./media-
|
|
4
|
+
import { t as MediaRepository } from "./media-BBm8Wg3f.mjs";
|
|
5
5
|
import "./dist-89xCrGqi.mjs";
|
|
6
6
|
import { n as normalizeMime, t as matchesMimeAllowlist } from "./mime-CUIG6x84.mjs";
|
|
7
7
|
import { t as enrichImageMetadata } from "./enrich-BX0IDp4z.mjs";
|
|
8
|
-
import { n as computeContentHash } from "./hash-
|
|
9
|
-
import {
|
|
10
|
-
import { n as DEFAULT_MAX_UPLOAD_SIZE, r as formatFileSize, t as CONTENT_TYPE_RE } from "./media-
|
|
11
|
-
import { t as GLOBAL_UPLOAD_ALLOWLIST } from "./media-allowlist-
|
|
8
|
+
import { n as computeContentHash } from "./hash-3JJPlHF2.mjs";
|
|
9
|
+
import { a as ssrfSafeFetch, t as SsrfError } from "./ssrf-5sIM5jzl.mjs";
|
|
10
|
+
import { n as DEFAULT_MAX_UPLOAD_SIZE, r as formatFileSize, t as CONTENT_TYPE_RE } from "./media-BHjus86Y.mjs";
|
|
11
|
+
import { t as GLOBAL_UPLOAD_ALLOWLIST } from "./media-allowlist-CoTBWoDp.mjs";
|
|
12
12
|
import { ulid } from "ulidx";
|
|
13
13
|
import * as path from "node:path";
|
|
14
14
|
|
|
@@ -144,4 +144,4 @@ async function handleMediaUpload(db, storage, input) {
|
|
|
144
144
|
|
|
145
145
|
//#endregion
|
|
146
146
|
export { handleMediaUpload };
|
|
147
|
-
//# sourceMappingURL=media-upload-
|
|
147
|
+
//# sourceMappingURL=media-upload-BCidR-EY.mjs.map
|