emdash 0.20.0 → 0.21.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{adapters-BzIHV3sw.d.mts → adapters-BxSmgtbF.d.mts} +1 -1
- package/dist/{adapters-BzIHV3sw.d.mts.map → adapters-BxSmgtbF.d.mts.map} +1 -1
- package/dist/{allowed-origins-B1u7Qnvg.mjs → allowed-origins-BqC8cul8.mjs} +2 -2
- package/dist/{allowed-origins-B1u7Qnvg.mjs.map → allowed-origins-BqC8cul8.mjs.map} +1 -1
- package/dist/api/route-utils.d.mts +3 -3
- package/dist/api/route-utils.mjs +13 -12
- package/dist/api/route-utils.mjs.map +1 -1
- package/dist/api/schemas/index.d.mts +1 -1
- package/dist/api/schemas/index.mjs +3 -2
- package/dist/{api-DStv36ik.mjs → api-DxjIV2o8.mjs} +13 -13
- package/dist/{api-DStv36ik.mjs.map → api-DxjIV2o8.mjs.map} +1 -1
- package/dist/{api-tokens-DPfhPu5V.mjs → api-tokens-BFFkB0jB.mjs} +2 -2
- package/dist/{api-tokens-DPfhPu5V.mjs.map → api-tokens-BFFkB0jB.mjs.map} +1 -1
- package/dist/{apply-Dr7snAMT.mjs → apply-CLjxheyb.mjs} +12 -12
- package/dist/{apply-Dr7snAMT.mjs.map → apply-CLjxheyb.mjs.map} +1 -1
- package/dist/astro/index.d.mts +10 -10
- package/dist/astro/index.d.mts.map +1 -1
- package/dist/astro/index.mjs +50 -15
- package/dist/astro/index.mjs.map +1 -1
- package/dist/astro/middleware/auth.d.mts +9 -9
- package/dist/astro/middleware/auth.mjs +5 -5
- package/dist/astro/middleware/redirect.d.mts.map +1 -1
- package/dist/astro/middleware/redirect.mjs +11 -2
- package/dist/astro/middleware/redirect.mjs.map +1 -1
- package/dist/astro/middleware/request-context.mjs +3 -2
- package/dist/astro/middleware/request-context.mjs.map +1 -1
- package/dist/astro/middleware/setup.mjs +1 -1
- package/dist/astro/middleware.d.mts +1 -1
- package/dist/astro/middleware.mjs +63 -60
- package/dist/astro/middleware.mjs.map +1 -1
- package/dist/astro/routes/api/admin/allowed-domains/_domain_.mjs +5 -4
- package/dist/astro/routes/api/admin/allowed-domains/_domain_.mjs.map +1 -1
- package/dist/astro/routes/api/admin/allowed-domains/index.mjs +5 -4
- package/dist/astro/routes/api/admin/allowed-domains/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/api-tokens/_id_.mjs +3 -3
- package/dist/astro/routes/api/admin/api-tokens/index.mjs +4 -4
- package/dist/astro/routes/api/admin/byline-fields/_slug_/usage.mjs +4 -4
- package/dist/astro/routes/api/admin/byline-fields/_slug_.mjs +8 -7
- package/dist/astro/routes/api/admin/byline-fields/_slug_.mjs.map +1 -1
- package/dist/astro/routes/api/admin/byline-fields/index.mjs +8 -7
- package/dist/astro/routes/api/admin/byline-fields/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/byline-fields/reorder.mjs +8 -7
- package/dist/astro/routes/api/admin/byline-fields/reorder.mjs.map +1 -1
- package/dist/astro/routes/api/admin/bylines/_id_/index.mjs +14 -12
- package/dist/astro/routes/api/admin/bylines/_id_/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/bylines/_id_/translations.mjs +14 -12
- package/dist/astro/routes/api/admin/bylines/_id_/translations.mjs.map +1 -1
- package/dist/astro/routes/api/admin/bylines/index.mjs +14 -12
- package/dist/astro/routes/api/admin/bylines/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/comments/_id_/status.mjs +9 -8
- package/dist/astro/routes/api/admin/comments/_id_/status.mjs.map +1 -1
- package/dist/astro/routes/api/admin/comments/_id_.mjs +3 -3
- package/dist/astro/routes/api/admin/comments/bulk.mjs +7 -6
- package/dist/astro/routes/api/admin/comments/bulk.mjs.map +1 -1
- package/dist/astro/routes/api/admin/comments/counts.mjs +3 -3
- package/dist/astro/routes/api/admin/comments/index.mjs +7 -6
- package/dist/astro/routes/api/admin/comments/index.mjs.map +1 -1
- 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/oauth-clients/_id_.mjs +3 -3
- package/dist/astro/routes/api/admin/oauth-clients/index.mjs +3 -3
- package/dist/astro/routes/api/admin/plugins/_id_/disable.mjs +29 -27
- package/dist/astro/routes/api/admin/plugins/_id_/disable.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/_id_/enable.mjs +29 -27
- package/dist/astro/routes/api/admin/plugins/_id_/enable.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/_id_/index.mjs +28 -26
- package/dist/astro/routes/api/admin/plugins/_id_/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/_id_/uninstall.mjs +28 -26
- package/dist/astro/routes/api/admin/plugins/_id_/uninstall.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/_id_/update.mjs +28 -26
- package/dist/astro/routes/api/admin/plugins/_id_/update.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/index.mjs +28 -26
- package/dist/astro/routes/api/admin/plugins/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/marketplace/_id_/icon.mjs +2 -2
- package/dist/astro/routes/api/admin/plugins/marketplace/_id_/index.mjs +28 -26
- package/dist/astro/routes/api/admin/plugins/marketplace/_id_/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/marketplace/_id_/install.mjs +28 -26
- package/dist/astro/routes/api/admin/plugins/marketplace/_id_/install.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/marketplace/index.mjs +28 -26
- package/dist/astro/routes/api/admin/plugins/marketplace/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/registry/_id_/uninstall.mjs +28 -26
- package/dist/astro/routes/api/admin/plugins/registry/_id_/uninstall.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/registry/_id_/update.mjs +29 -27
- package/dist/astro/routes/api/admin/plugins/registry/_id_/update.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/registry/artifact.mjs +28 -26
- package/dist/astro/routes/api/admin/plugins/registry/artifact.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/registry/install.mjs +29 -27
- package/dist/astro/routes/api/admin/plugins/registry/install.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/updates.mjs +28 -26
- package/dist/astro/routes/api/admin/plugins/updates.mjs.map +1 -1
- package/dist/astro/routes/api/admin/themes/marketplace/_id_/index.mjs +28 -26
- package/dist/astro/routes/api/admin/themes/marketplace/_id_/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/themes/marketplace/_id_/thumbnail.mjs +2 -2
- package/dist/astro/routes/api/admin/themes/marketplace/index.mjs +28 -26
- package/dist/astro/routes/api/admin/themes/marketplace/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/users/_id_/disable.mjs +1 -1
- package/dist/astro/routes/api/admin/users/_id_/enable.mjs +1 -1
- package/dist/astro/routes/api/admin/users/_id_/index.mjs +5 -4
- package/dist/astro/routes/api/admin/users/_id_/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/users/_id_/send-recovery.mjs +2 -2
- package/dist/astro/routes/api/admin/users/index.mjs +5 -4
- package/dist/astro/routes/api/admin/users/index.mjs.map +1 -1
- 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 +9 -8
- package/dist/astro/routes/api/auth/invite/complete.mjs.map +1 -1
- package/dist/astro/routes/api/auth/invite/index.mjs +6 -5
- package/dist/astro/routes/api/auth/invite/index.mjs.map +1 -1
- package/dist/astro/routes/api/auth/invite/register-options.mjs +8 -7
- package/dist/astro/routes/api/auth/invite/register-options.mjs.map +1 -1
- package/dist/astro/routes/api/auth/logout.mjs +2 -2
- package/dist/astro/routes/api/auth/magic-link/send.mjs +8 -7
- package/dist/astro/routes/api/auth/magic-link/send.mjs.map +1 -1
- package/dist/astro/routes/api/auth/magic-link/verify.mjs +2 -2
- package/dist/astro/routes/api/auth/me.mjs +5 -4
- package/dist/astro/routes/api/auth/me.mjs.map +1 -1
- package/dist/astro/routes/api/auth/mode.mjs +1 -1
- package/dist/astro/routes/api/auth/oauth/_provider_/callback.mjs +3 -3
- package/dist/astro/routes/api/auth/oauth/_provider_.mjs +2 -2
- package/dist/astro/routes/api/auth/passkey/_id_.mjs +5 -4
- package/dist/astro/routes/api/auth/passkey/_id_.mjs.map +1 -1
- package/dist/astro/routes/api/auth/passkey/index.mjs +1 -1
- package/dist/astro/routes/api/auth/passkey/options.mjs +10 -9
- package/dist/astro/routes/api/auth/passkey/options.mjs.map +1 -1
- package/dist/astro/routes/api/auth/passkey/register/options.mjs +8 -7
- package/dist/astro/routes/api/auth/passkey/register/options.mjs.map +1 -1
- package/dist/astro/routes/api/auth/passkey/register/verify.mjs +9 -8
- package/dist/astro/routes/api/auth/passkey/register/verify.mjs.map +1 -1
- package/dist/astro/routes/api/auth/passkey/verify.mjs +9 -8
- package/dist/astro/routes/api/auth/passkey/verify.mjs.map +1 -1
- package/dist/astro/routes/api/auth/signup/complete.mjs +9 -8
- package/dist/astro/routes/api/auth/signup/complete.mjs.map +1 -1
- package/dist/astro/routes/api/auth/signup/request.mjs +8 -7
- package/dist/astro/routes/api/auth/signup/request.mjs.map +1 -1
- package/dist/astro/routes/api/auth/signup/verify.mjs +1 -1
- package/dist/astro/routes/api/comments/_collection_/_contentId_/index.mjs +11 -9
- package/dist/astro/routes/api/comments/_collection_/_contentId_/index.mjs.map +1 -1
- package/dist/astro/routes/api/content/_collection_/_id_/compare.mjs +2 -2
- package/dist/astro/routes/api/content/_collection_/_id_/discard-draft.mjs +2 -2
- package/dist/astro/routes/api/content/_collection_/_id_/duplicate.mjs +2 -2
- package/dist/astro/routes/api/content/_collection_/_id_/permanent.mjs +2 -2
- package/dist/astro/routes/api/content/_collection_/_id_/preview-url.mjs +10 -8
- package/dist/astro/routes/api/content/_collection_/_id_/preview-url.mjs.map +1 -1
- package/dist/astro/routes/api/content/_collection_/_id_/publish.mjs +6 -5
- package/dist/astro/routes/api/content/_collection_/_id_/publish.mjs.map +1 -1
- package/dist/astro/routes/api/content/_collection_/_id_/restore.mjs +2 -2
- package/dist/astro/routes/api/content/_collection_/_id_/revisions.mjs +2 -2
- package/dist/astro/routes/api/content/_collection_/_id_/schedule.mjs +6 -5
- package/dist/astro/routes/api/content/_collection_/_id_/schedule.mjs.map +1 -1
- package/dist/astro/routes/api/content/_collection_/_id_/terms/_taxonomy_.mjs +10 -9
- package/dist/astro/routes/api/content/_collection_/_id_/terms/_taxonomy_.mjs.map +1 -1
- package/dist/astro/routes/api/content/_collection_/_id_/translations.mjs +2 -2
- package/dist/astro/routes/api/content/_collection_/_id_/unpublish.mjs +2 -2
- package/dist/astro/routes/api/content/_collection_/_id_.mjs +6 -5
- package/dist/astro/routes/api/content/_collection_/_id_.mjs.map +1 -1
- package/dist/astro/routes/api/content/_collection_/authors.mjs +2 -2
- package/dist/astro/routes/api/content/_collection_/index.mjs +6 -5
- package/dist/astro/routes/api/content/_collection_/index.mjs.map +1 -1
- package/dist/astro/routes/api/content/_collection_/trash.mjs +6 -5
- package/dist/astro/routes/api/content/_collection_/trash.mjs.map +1 -1
- package/dist/astro/routes/api/dashboard.mjs +3 -3
- 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 +10 -9
- package/dist/astro/routes/api/import/probe.mjs.map +1 -1
- package/dist/astro/routes/api/import/wordpress/analyze.mjs +3 -3
- package/dist/astro/routes/api/import/wordpress/execute.d.mts +9 -9
- package/dist/astro/routes/api/import/wordpress/execute.mjs +10 -9
- package/dist/astro/routes/api/import/wordpress/execute.mjs.map +1 -1
- package/dist/astro/routes/api/import/wordpress/media.mjs +8 -7
- package/dist/astro/routes/api/import/wordpress/media.mjs.map +1 -1
- package/dist/astro/routes/api/import/wordpress/prepare.mjs +9 -8
- package/dist/astro/routes/api/import/wordpress/prepare.mjs.map +1 -1
- package/dist/astro/routes/api/import/wordpress/rewrite-urls.mjs +8 -7
- package/dist/astro/routes/api/import/wordpress/rewrite-urls.mjs.map +1 -1
- package/dist/astro/routes/api/import/wordpress-plugin/analyze.d.mts +1 -1
- package/dist/astro/routes/api/import/wordpress-plugin/analyze.mjs +10 -9
- package/dist/astro/routes/api/import/wordpress-plugin/analyze.mjs.map +1 -1
- package/dist/astro/routes/api/import/wordpress-plugin/execute.d.mts +1 -1
- package/dist/astro/routes/api/import/wordpress-plugin/execute.mjs +14 -12
- package/dist/astro/routes/api/import/wordpress-plugin/execute.mjs.map +1 -1
- package/dist/astro/routes/api/manifest.mjs +3 -3
- package/dist/astro/routes/api/mcp.mjs +20 -19
- package/dist/astro/routes/api/mcp.mjs.map +1 -1
- package/dist/astro/routes/api/media/_id_/confirm.mjs +6 -5
- package/dist/astro/routes/api/media/_id_/confirm.mjs.map +1 -1
- package/dist/astro/routes/api/media/_id_.mjs +6 -5
- package/dist/astro/routes/api/media/_id_.mjs.map +1 -1
- package/dist/astro/routes/api/media/file/_...key_.mjs +1 -1
- 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 +8 -7
- package/dist/astro/routes/api/media/upload-url.mjs.map +1 -1
- package/dist/astro/routes/api/media.mjs +10 -9
- package/dist/astro/routes/api/media.mjs.map +1 -1
- package/dist/astro/routes/api/menus/_name_/items/_id_.mjs +6 -5
- package/dist/astro/routes/api/menus/_name_/items/_id_.mjs.map +1 -1
- package/dist/astro/routes/api/menus/_name_/items.mjs +6 -5
- package/dist/astro/routes/api/menus/_name_/items.mjs.map +1 -1
- package/dist/astro/routes/api/menus/_name_/reorder.mjs +6 -5
- package/dist/astro/routes/api/menus/_name_/reorder.mjs.map +1 -1
- package/dist/astro/routes/api/menus/_name_/translations.mjs +6 -5
- package/dist/astro/routes/api/menus/_name_/translations.mjs.map +1 -1
- package/dist/astro/routes/api/menus/_name_.mjs +6 -5
- package/dist/astro/routes/api/menus/_name_.mjs.map +1 -1
- package/dist/astro/routes/api/menus/index.mjs +6 -5
- 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 +3 -2
- package/dist/astro/routes/api/openapi.json.mjs.map +1 -1
- package/dist/astro/routes/api/plugins/_pluginId_/_...path_.mjs +3 -3
- package/dist/astro/routes/api/redirects/404s/index.mjs +7 -6
- package/dist/astro/routes/api/redirects/404s/index.mjs.map +1 -1
- package/dist/astro/routes/api/redirects/404s/summary.mjs +7 -6
- package/dist/astro/routes/api/redirects/404s/summary.mjs.map +1 -1
- package/dist/astro/routes/api/redirects/_id_.mjs +8 -7
- package/dist/astro/routes/api/redirects/_id_.mjs.map +1 -1
- package/dist/astro/routes/api/redirects/index.mjs +8 -7
- package/dist/astro/routes/api/redirects/index.mjs.map +1 -1
- package/dist/astro/routes/api/revisions/_revisionId_/index.mjs +2 -2
- package/dist/astro/routes/api/revisions/_revisionId_/restore.mjs +2 -2
- package/dist/astro/routes/api/schema/collections/_slug_/fields/_fieldSlug_.mjs +28 -26
- package/dist/astro/routes/api/schema/collections/_slug_/fields/_fieldSlug_.mjs.map +1 -1
- package/dist/astro/routes/api/schema/collections/_slug_/fields/index.mjs +28 -26
- package/dist/astro/routes/api/schema/collections/_slug_/fields/index.mjs.map +1 -1
- package/dist/astro/routes/api/schema/collections/_slug_/fields/reorder.mjs +28 -26
- package/dist/astro/routes/api/schema/collections/_slug_/fields/reorder.mjs.map +1 -1
- package/dist/astro/routes/api/schema/collections/_slug_/index.mjs +28 -26
- package/dist/astro/routes/api/schema/collections/_slug_/index.mjs.map +1 -1
- package/dist/astro/routes/api/schema/collections/index.mjs +28 -26
- package/dist/astro/routes/api/schema/collections/index.mjs.map +1 -1
- package/dist/astro/routes/api/schema/index.mjs +5 -5
- package/dist/astro/routes/api/schema/orphans/_slug_.mjs +28 -26
- package/dist/astro/routes/api/schema/orphans/_slug_.mjs.map +1 -1
- package/dist/astro/routes/api/schema/orphans/index.mjs +28 -26
- package/dist/astro/routes/api/schema/orphans/index.mjs.map +1 -1
- package/dist/astro/routes/api/search/enable.mjs +9 -8
- package/dist/astro/routes/api/search/enable.mjs.map +1 -1
- package/dist/astro/routes/api/search/index.mjs +8 -7
- package/dist/astro/routes/api/search/index.mjs.map +1 -1
- package/dist/astro/routes/api/search/rebuild.mjs +9 -8
- package/dist/astro/routes/api/search/rebuild.mjs.map +1 -1
- package/dist/astro/routes/api/search/stats.mjs +5 -5
- package/dist/astro/routes/api/search/suggest.mjs +8 -7
- package/dist/astro/routes/api/search/suggest.mjs.map +1 -1
- package/dist/astro/routes/api/sections/_slug_.mjs +8 -7
- package/dist/astro/routes/api/sections/_slug_.mjs.map +1 -1
- package/dist/astro/routes/api/sections/index.mjs +8 -7
- package/dist/astro/routes/api/sections/index.mjs.map +1 -1
- package/dist/astro/routes/api/settings/email.mjs +3 -3
- package/dist/astro/routes/api/settings.mjs +11 -9
- package/dist/astro/routes/api/settings.mjs.map +1 -1
- package/dist/astro/routes/api/setup/admin-verify.mjs +10 -9
- package/dist/astro/routes/api/setup/admin-verify.mjs.map +1 -1
- package/dist/astro/routes/api/setup/admin.mjs +9 -8
- package/dist/astro/routes/api/setup/admin.mjs.map +1 -1
- package/dist/astro/routes/api/setup/dev-bypass.mjs +19 -18
- package/dist/astro/routes/api/setup/dev-bypass.mjs.map +1 -1
- package/dist/astro/routes/api/setup/dev-reset.mjs +1 -1
- package/dist/astro/routes/api/setup/index.mjs +20 -18
- package/dist/astro/routes/api/setup/index.mjs.map +1 -1
- package/dist/astro/routes/api/setup/status.mjs +3 -3
- package/dist/astro/routes/api/snapshot.mjs +5 -4
- package/dist/astro/routes/api/snapshot.mjs.map +1 -1
- package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_/translations.mjs +11 -10
- package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_/translations.mjs.map +1 -1
- package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_.mjs +11 -10
- package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_.mjs.map +1 -1
- package/dist/astro/routes/api/taxonomies/_name_/terms/index.mjs +11 -10
- package/dist/astro/routes/api/taxonomies/_name_/terms/index.mjs.map +1 -1
- package/dist/astro/routes/api/taxonomies/index.mjs +11 -10
- package/dist/astro/routes/api/taxonomies/index.mjs.map +1 -1
- package/dist/astro/routes/api/themes/preview.mjs +5 -4
- package/dist/astro/routes/api/themes/preview.mjs.map +1 -1
- 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.mjs +6 -5
- package/dist/astro/routes/api/widget-areas/_name_/reorder.mjs.map +1 -1
- package/dist/astro/routes/api/widget-areas/_name_/widgets/_id_.mjs +9 -8
- package/dist/astro/routes/api/widget-areas/_name_/widgets/_id_.mjs.map +1 -1
- package/dist/astro/routes/api/widget-areas/_name_/widgets.mjs +9 -8
- package/dist/astro/routes/api/widget-areas/_name_/widgets.mjs.map +1 -1
- package/dist/astro/routes/api/widget-areas/_name_.mjs +5 -5
- package/dist/astro/routes/api/widget-areas/index.mjs +9 -8
- 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 -4
- package/dist/astro/routes/robots.txt.mjs.map +1 -1
- package/dist/astro/routes/sitemap-_collection_.xml.mjs +8 -7
- package/dist/astro/routes/sitemap-_collection_.xml.mjs.map +1 -1
- package/dist/astro/routes/sitemap.xml.mjs +6 -5
- package/dist/astro/routes/sitemap.xml.mjs.map +1 -1
- package/dist/astro/types.d.mts +12 -12
- package/dist/auth/providers/github.d.mts +1 -1
- package/dist/auth/providers/google.d.mts +1 -1
- package/dist/{authorize-DsMSVSaY.mjs → authorize-D5gfBVU5.mjs} +2 -2
- package/dist/{authorize-DsMSVSaY.mjs.map → authorize-D5gfBVU5.mjs.map} +1 -1
- package/dist/{byline-DUx48sJp.mjs → byline-V_Qp1Ziw.mjs} +27 -14
- package/dist/byline-V_Qp1Ziw.mjs.map +1 -0
- package/dist/{byline-fields-8TMtkBnH.mjs → byline-fields-B0NO1yUB.mjs} +3 -3
- package/dist/{byline-fields-8TMtkBnH.mjs.map → byline-fields-B0NO1yUB.mjs.map} +1 -1
- package/dist/{byline-fields-DbibsvTl.d.mts → byline-fields-CQJRIQkn.d.mts} +32 -32
- package/dist/{byline-fields-DbibsvTl.d.mts.map → byline-fields-CQJRIQkn.d.mts.map} +1 -1
- package/dist/{byline-fields--WxSNS79.mjs → byline-fields-nBVqK_Ff.mjs} +2 -2
- package/dist/{byline-fields--WxSNS79.mjs.map → byline-fields-nBVqK_Ff.mjs.map} +1 -1
- package/dist/{byline-registry-CWP7I71B.mjs → byline-registry-DedidtqC.mjs} +2 -2
- package/dist/{byline-registry-CWP7I71B.mjs.map → byline-registry-DedidtqC.mjs.map} +1 -1
- package/dist/{bylines-BdxWCnPL.mjs → bylines-B2NWnIwS.mjs} +2 -2
- package/dist/{bylines-BdxWCnPL.mjs.map → bylines-B2NWnIwS.mjs.map} +1 -1
- package/dist/{bylines-s8c2DXbH.mjs → bylines-DfGDnred.mjs} +7 -7
- package/dist/{bylines-s8c2DXbH.mjs.map → bylines-DfGDnred.mjs.map} +1 -1
- package/dist/{cache-B_HzASVT.mjs → cache-DTTHWD8n.mjs} +1 -1
- package/dist/{cache-B_HzASVT.mjs.map → cache-DTTHWD8n.mjs.map} +1 -1
- package/dist/{challenge-store-DXX3rfdI.mjs → challenge-store-woE0bbCf.mjs} +1 -1
- package/dist/{challenge-store-DXX3rfdI.mjs.map → challenge-store-woE0bbCf.mjs.map} +1 -1
- package/dist/cli/index.mjs +19 -18
- package/dist/cli/index.mjs.map +1 -1
- package/dist/client/cf-access.d.mts +1 -1
- package/dist/client/index.d.mts +1 -1
- package/dist/client/index.mjs +1 -1
- package/dist/{comments-Vkivawyl.mjs → comments-D2hNuxNa.mjs} +1 -1
- package/dist/{comments-Vkivawyl.mjs.map → comments-D2hNuxNa.mjs.map} +1 -1
- package/dist/{components-CK0cuUoH.mjs → components-DYKp2gmo.mjs} +1 -1
- package/dist/{components-CK0cuUoH.mjs.map → components-DYKp2gmo.mjs.map} +1 -1
- package/dist/{context-Y7BRkWes.mjs → context-Cm4pt1Ws.mjs} +5 -5
- package/dist/{context-Y7BRkWes.mjs.map → context-Cm4pt1Ws.mjs.map} +1 -1
- package/dist/{cron-BJ2ClIlj.mjs → cron-DdEVrQ2Y.mjs} +1 -1
- package/dist/{cron-BJ2ClIlj.mjs.map → cron-DdEVrQ2Y.mjs.map} +1 -1
- package/dist/{dashboard-2JgAMWxK.mjs → dashboard-C-UYpps0.mjs} +1 -1
- package/dist/{dashboard-2JgAMWxK.mjs.map → dashboard-C-UYpps0.mjs.map} +1 -1
- package/dist/db/index.d.mts +3 -3
- package/dist/db/libsql.d.mts +1 -1
- package/dist/db/postgres.d.mts +1 -1
- package/dist/db/sqlite.d.mts +1 -1
- package/dist/{db-errors-CtzxKBxe.mjs → db-errors-BluWkwGI.mjs} +1 -1
- package/dist/{db-errors-CtzxKBxe.mjs.map → db-errors-BluWkwGI.mjs.map} +1 -1
- package/dist/{default-IlBaTFxM.mjs → default-NHGuJzQ3.mjs} +1 -1
- package/dist/{default-IlBaTFxM.mjs.map → default-NHGuJzQ3.mjs.map} +1 -1
- package/dist/{device-flow-R23SIbQ2.mjs → device-flow-BQApWgnW.mjs} +4 -4
- package/dist/{device-flow-R23SIbQ2.mjs.map → device-flow-BQApWgnW.mjs.map} +1 -1
- package/dist/{email-console-DHT2Fbpj.mjs → email-console-BbU3RbWv.mjs} +1 -1
- package/dist/{email-console-DHT2Fbpj.mjs.map → email-console-BbU3RbWv.mjs.map} +1 -1
- package/dist/{error-RwM4dD35.mjs → error-CNn_w7jf.mjs} +1 -1
- package/dist/{error-RwM4dD35.mjs.map → error-CNn_w7jf.mjs.map} +1 -1
- package/dist/{escape-Ds07EEyu.mjs → escape-DPgcxcpL.mjs} +1 -1
- package/dist/{escape-Ds07EEyu.mjs.map → escape-DPgcxcpL.mjs.map} +1 -1
- package/dist/{fts-manager-1RgHmopc.mjs → fts-manager-Cx5z8jdA.mjs} +1 -1
- package/dist/{fts-manager-1RgHmopc.mjs.map → fts-manager-Cx5z8jdA.mjs.map} +1 -1
- package/dist/{hash-9w3pd3-m.mjs → hash-DlvIFn0b.mjs} +1 -1
- package/dist/{hash-9w3pd3-m.mjs.map → hash-DlvIFn0b.mjs.map} +1 -1
- package/dist/{import-Dh8bWmyq.mjs → import-KyxT1Mbs.mjs} +3 -3
- package/dist/{import-Dh8bWmyq.mjs.map → import-KyxT1Mbs.mjs.map} +1 -1
- package/dist/{index-B1keaX5Y.d.mts → index-D2VAiumu.d.mts} +15 -15
- package/dist/{index-B1keaX5Y.d.mts.map → index-D2VAiumu.d.mts.map} +1 -1
- package/dist/{index-DR56od45.d.mts → index-uT2yR66F.d.mts} +3 -3
- package/dist/{index-DR56od45.d.mts.map → index-uT2yR66F.d.mts.map} +1 -1
- package/dist/index.d.mts +16 -16
- package/dist/index.mjs +48 -46
- package/dist/init-lock-DlBHjf9-.mjs +83 -0
- package/dist/init-lock-DlBHjf9-.mjs.map +1 -0
- package/dist/{load-BBetCvLC.mjs → load-Dq91b_DK.mjs} +1 -1
- package/dist/{load-BBetCvLC.mjs.map → load-Dq91b_DK.mjs.map} +1 -1
- package/dist/{loader-ZN1ll-d-.mjs → loader-BqWjcH3h.mjs} +2 -2
- package/dist/{loader-ZN1ll-d-.mjs.map → loader-BqWjcH3h.mjs.map} +1 -1
- package/dist/{manifest-schema-BtwbL_vj.mjs → manifest-schema-DFPeqMAn.mjs} +1 -1
- package/dist/{manifest-schema-BtwbL_vj.mjs.map → manifest-schema-DFPeqMAn.mjs.map} +1 -1
- package/dist/media/index.d.mts +1 -1
- package/dist/media/index.mjs +2 -2
- package/dist/media/local-runtime.d.mts +11 -11
- package/dist/media/local-runtime.mjs +4 -3
- package/dist/media/local-runtime.mjs.map +1 -1
- package/dist/{media-allowlist-Dknq-OFY.mjs → media-allowlist-_A0SuDn4.mjs} +2 -2
- package/dist/{media-allowlist-Dknq-OFY.mjs.map → media-allowlist-_A0SuDn4.mjs.map} +1 -1
- package/dist/{media-url-VClf8glU.mjs → media-url-CqLd69IO.mjs} +1 -1
- package/dist/{media-url-VClf8glU.mjs.map → media-url-CqLd69IO.mjs.map} +1 -1
- package/dist/{menus-DrQLusqj.mjs → menus-Ryk9L7fT.mjs} +9 -9
- package/dist/{menus-DrQLusqj.mjs.map → menus-Ryk9L7fT.mjs.map} +1 -1
- package/dist/{mime-CCEzze7W.mjs → mime-YbtlEtvS.mjs} +1 -1
- package/dist/{mime-CCEzze7W.mjs.map → mime-YbtlEtvS.mjs.map} +1 -1
- package/dist/{mode-CO2vQHfq.mjs → mode-CGXzIbD8.mjs} +1 -1
- package/dist/{mode-CO2vQHfq.mjs.map → mode-CGXzIbD8.mjs.map} +1 -1
- package/dist/{normalize-CK5o04zr.mjs → normalize-DKsg36ty.mjs} +1 -1
- package/dist/{normalize-CK5o04zr.mjs.map → normalize-DKsg36ty.mjs.map} +1 -1
- package/dist/{oauth-authorization-Bw4NdF_S.mjs → oauth-authorization-C2kVyjXI.mjs} +4 -4
- package/dist/{oauth-authorization-Bw4NdF_S.mjs.map → oauth-authorization-C2kVyjXI.mjs.map} +1 -1
- package/dist/{oauth-clients-BGGFp57s.mjs → oauth-clients-BC873NCV.mjs} +1 -1
- package/dist/{oauth-clients-BGGFp57s.mjs.map → oauth-clients-BC873NCV.mjs.map} +1 -1
- package/dist/{oauth-state-store-97x0xtN2.mjs → oauth-state-store-Cd--TUaq.mjs} +1 -1
- package/dist/{oauth-state-store-97x0xtN2.mjs.map → oauth-state-store-Cd--TUaq.mjs.map} +1 -1
- package/dist/{oauth-user-lookup-B_vnZHKO.mjs → oauth-user-lookup-e4wOvDud.mjs} +1 -1
- package/dist/{oauth-user-lookup-B_vnZHKO.mjs.map → oauth-user-lookup-e4wOvDud.mjs.map} +1 -1
- package/dist/{options-DyYIYpPd.d.mts → options-9kLgkE8m.d.mts} +3 -3
- package/dist/{options-DyYIYpPd.d.mts.map → options-9kLgkE8m.d.mts.map} +1 -1
- package/dist/page/index.d.mts +2 -2
- package/dist/{parse-CrGndy1A.mjs → parse-DzSrk1t8.mjs} +2 -2
- package/dist/{parse-CrGndy1A.mjs.map → parse-DzSrk1t8.mjs.map} +1 -1
- package/dist/{passkey-config-C3QgnQnU.mjs → passkey-config-BpjbE_Uv.mjs} +1 -1
- package/dist/{passkey-config-C3QgnQnU.mjs.map → passkey-config-BpjbE_Uv.mjs.map} +1 -1
- package/dist/{placeholder-BZxr8W1j.mjs → placeholder-2xumZh4g.mjs} +1 -1
- package/dist/{placeholder-BZxr8W1j.mjs.map → placeholder-2xumZh4g.mjs.map} +1 -1
- package/dist/{placeholder-CVBv5z8k.d.mts → placeholder-BevVKfay.d.mts} +1 -1
- package/dist/{placeholder-CVBv5z8k.d.mts.map → placeholder-BevVKfay.d.mts.map} +1 -1
- package/dist/plugin-types.d.mts +1 -1
- package/dist/plugin-utils.d.mts +9 -9
- package/dist/plugins/adapt-sandbox-entry.d.mts +9 -9
- package/dist/plugins/adapt-sandbox-entry.mjs +2 -2
- package/dist/{preview-BfuRkVKW.mjs → preview-Dqv2hwXr.mjs} +2 -2
- package/dist/{preview-BfuRkVKW.mjs.map → preview-Dqv2hwXr.mjs.map} +1 -1
- package/dist/{public-url-BFVC2OTJ.mjs → public-url-D_zARuvZ.mjs} +1 -1
- package/dist/{public-url-BFVC2OTJ.mjs.map → public-url-D_zARuvZ.mjs.map} +1 -1
- package/dist/{query-CbUcI4Xk.mjs → query-Crm038Mc.mjs} +9 -9
- package/dist/{query-CbUcI4Xk.mjs.map → query-Crm038Mc.mjs.map} +1 -1
- package/dist/{rate-limit-C7hjdkS5.mjs → rate-limit-hRTBqmw1.mjs} +2 -2
- package/dist/{rate-limit-C7hjdkS5.mjs.map → rate-limit-hRTBqmw1.mjs.map} +1 -1
- package/dist/{redirect-B_q19j4v.mjs → redirect-C-OOkyku.mjs} +1 -1
- package/dist/{redirect-B_q19j4v.mjs.map → redirect-C-OOkyku.mjs.map} +1 -1
- package/dist/{redirects-CCbCqCCd.mjs → redirects-6Zg2SoYo.mjs} +8 -9
- package/dist/{redirects-CCbCqCCd.mjs.map → redirects-6Zg2SoYo.mjs.map} +1 -1
- package/dist/{redirects-DxVoR7PI.mjs → redirects-CP3TnTLO.mjs} +20 -14
- package/dist/redirects-CP3TnTLO.mjs.map +1 -0
- package/dist/{registry-brYh-rAT.mjs → registry-diMzD1Wf.mjs} +3 -3
- package/dist/{registry-brYh-rAT.mjs.map → registry-diMzD1Wf.mjs.map} +1 -1
- package/dist/{request-cache-D32LpnmI.mjs → request-cache-UwmBAiUK.mjs} +1 -1
- package/dist/{request-cache-D32LpnmI.mjs.map → request-cache-UwmBAiUK.mjs.map} +1 -1
- package/dist/{request-meta-7ByVLxB-.mjs → request-meta-DPechd0W.mjs} +2 -2
- package/dist/{request-meta-7ByVLxB-.mjs.map → request-meta-DPechd0W.mjs.map} +1 -1
- package/dist/{resolve-BqYMVG0D.mjs → resolve-B3NUUtVY.mjs} +1 -1
- package/dist/{resolve-BqYMVG0D.mjs.map → resolve-B3NUUtVY.mjs.map} +1 -1
- package/dist/{runner-DTdhuI9i.d.mts → runner-C8vcbvCe.d.mts} +2 -2
- package/dist/{runner-DTdhuI9i.d.mts.map → runner-C8vcbvCe.d.mts.map} +1 -1
- package/dist/runtime.d.mts +10 -10
- package/dist/runtime.mjs +1 -1
- package/dist/{schema-C1E70ug_.mjs → schema-BDOkd3OU.mjs} +4 -4
- package/dist/{schema-C1E70ug_.mjs.map → schema-BDOkd3OU.mjs.map} +1 -1
- package/dist/{search-B3SGZw91.mjs → search-Bs_J_EW-.mjs} +3 -3
- package/dist/{search-B3SGZw91.mjs.map → search-Bs_J_EW-.mjs.map} +1 -1
- package/dist/{secrets-ChPTmy9x.mjs → secrets-C8xmE6mR.mjs} +21 -11
- package/dist/secrets-C8xmE6mR.mjs.map +1 -0
- package/dist/{sections-D_lVzwRZ.mjs → sections-P0zuBlyz.mjs} +2 -2
- package/dist/{sections-D_lVzwRZ.mjs.map → sections-P0zuBlyz.mjs.map} +1 -1
- package/dist/seed/index.d.mts +2 -2
- package/dist/seed/index.mjs +14 -13
- package/dist/seo/index.d.mts +1 -1
- package/dist/seo/index.mjs +1 -1
- package/dist/{seo-D_LPkOtu.mjs → seo-CLhm-Fmb.mjs} +1 -1
- package/dist/{seo-D_LPkOtu.mjs.map → seo-CLhm-Fmb.mjs.map} +1 -1
- package/dist/{seo-B5e6y9Wk.mjs → seo-DpNgGQjF.mjs} +1 -1
- package/dist/{seo-B5e6y9Wk.mjs.map → seo-DpNgGQjF.mjs.map} +1 -1
- package/dist/{service-ChDcsTBs.mjs → service-CDQQnT8W.mjs} +2 -2
- package/dist/{service-ChDcsTBs.mjs.map → service-CDQQnT8W.mjs.map} +1 -1
- package/dist/{settings-DfxiWY_s.mjs → settings-BjBsmVAo.mjs} +10 -184
- package/dist/settings-BjBsmVAo.mjs.map +1 -0
- package/dist/{settings-Cv47v9u8.mjs → settings-sO0Fif4p.mjs} +2 -2
- package/dist/{settings-Cv47v9u8.mjs.map → settings-sO0Fif4p.mjs.map} +1 -1
- package/dist/{setup-complete-yvPE4OsP.mjs → setup-complete-CMMr-oZU.mjs} +1 -1
- package/dist/{setup-complete-yvPE4OsP.mjs.map → setup-complete-CMMr-oZU.mjs.map} +1 -1
- package/dist/{setup-nonce-C9aFzb94.mjs → setup-nonce-169xl4fV.mjs} +1 -1
- package/dist/{setup-nonce-C9aFzb94.mjs.map → setup-nonce-169xl4fV.mjs.map} +1 -1
- package/dist/single-flight-cache-C0UV1Npg.mjs +104 -0
- package/dist/single-flight-cache-C0UV1Npg.mjs.map +1 -0
- package/dist/{site-url-CnHlmAs9.mjs → site-url-vtsuOvSD.mjs} +1 -1
- package/dist/{site-url-CnHlmAs9.mjs.map → site-url-vtsuOvSD.mjs.map} +1 -1
- package/dist/{ssrf-BsVGIE0Z.mjs → ssrf-XO05Voq6.mjs} +1 -1
- package/dist/{ssrf-BsVGIE0Z.mjs.map → ssrf-XO05Voq6.mjs.map} +1 -1
- package/dist/status-2gZklYuj.mjs +30 -0
- package/dist/status-2gZklYuj.mjs.map +1 -0
- package/dist/storage/local.d.mts +1 -1
- package/dist/storage/local.mjs +2 -2
- package/dist/storage/s3.d.mts +1 -1
- package/dist/storage/s3.mjs +1 -1
- package/dist/{taxonomies-BdAmbOwx.mjs → taxonomies-BBxYA38v.mjs} +6 -6
- package/dist/{taxonomies-BdAmbOwx.mjs.map → taxonomies-BBxYA38v.mjs.map} +1 -1
- package/dist/{taxonomies-BILwiyGk.mjs → taxonomies-DuESHWKI.mjs} +2 -2
- package/dist/{taxonomies-BILwiyGk.mjs.map → taxonomies-DuESHWKI.mjs.map} +1 -1
- package/dist/{tokens-Bx2afeT-.mjs → tokens-DMkVjxrx.mjs} +1 -1
- package/dist/{tokens-Bx2afeT-.mjs.map → tokens-DMkVjxrx.mjs.map} +1 -1
- package/dist/{transport-CmpLD7W3.mjs → transport-1cIrOb1Y.mjs} +1 -1
- package/dist/{transport-CmpLD7W3.mjs.map → transport-1cIrOb1Y.mjs.map} +1 -1
- package/dist/{transport-B7PPP2CC.d.mts → transport-jdvsZEIt.d.mts} +1 -1
- package/dist/{transport-B7PPP2CC.d.mts.map → transport-jdvsZEIt.d.mts.map} +1 -1
- package/dist/{trusted-proxy-B4AfnoAp.mjs → trusted-proxy-CHp41Fjj.mjs} +1 -1
- package/dist/{trusted-proxy-B4AfnoAp.mjs.map → trusted-proxy-CHp41Fjj.mjs.map} +1 -1
- package/dist/{types-BFgrqwSk.d.mts → types-BFgYtuKd.d.mts} +1 -1
- package/dist/{types-BFgrqwSk.d.mts.map → types-BFgYtuKd.d.mts.map} +1 -1
- package/dist/{types-DZk_y-MU.mjs → types-BIduXPJk.mjs} +1 -1
- package/dist/{types-DZk_y-MU.mjs.map → types-BIduXPJk.mjs.map} +1 -1
- package/dist/{types-DTniiNto.d.mts → types-BTnnBYVX.d.mts} +2 -2
- package/dist/{types-DTniiNto.d.mts.map → types-BTnnBYVX.d.mts.map} +1 -1
- package/dist/{types-BUUVn1zr.d.mts → types-Bzfk2yC8.d.mts} +1 -1
- package/dist/{types-BUUVn1zr.d.mts.map → types-Bzfk2yC8.d.mts.map} +1 -1
- package/dist/{types-BH8-30hc.d.mts → types-CkEuk-Zr.d.mts} +1 -1
- package/dist/{types-BH8-30hc.d.mts.map → types-CkEuk-Zr.d.mts.map} +1 -1
- package/dist/{types-CPAPl93j.d.mts → types-DO7whVYU.d.mts} +2 -2
- package/dist/{types-CPAPl93j.d.mts.map → types-DO7whVYU.d.mts.map} +1 -1
- package/dist/{types-S15DXXNi.d.mts → types-DdkL6fyv.d.mts} +1 -1
- package/dist/{types-S15DXXNi.d.mts.map → types-DdkL6fyv.d.mts.map} +1 -1
- package/dist/{types-DpFmlNyB.mjs → types-DejCHqWT.mjs} +1 -1
- package/dist/{types-DpFmlNyB.mjs.map → types-DejCHqWT.mjs.map} +1 -1
- package/dist/{types-BPzXTV9x.d.mts → types-Del0VMij.d.mts} +1 -1
- package/dist/{types-BPzXTV9x.d.mts.map → types-Del0VMij.d.mts.map} +1 -1
- package/dist/{types-D4kUqbHh.d.mts → types-u_XxjbS8.d.mts} +1 -1
- package/dist/{types-D4kUqbHh.d.mts.map → types-u_XxjbS8.d.mts.map} +1 -1
- package/dist/{utils-C4Ih4DML.mjs → utils-C4M981Br.mjs} +1 -1
- package/dist/{utils-C4Ih4DML.mjs.map → utils-C4M981Br.mjs.map} +1 -1
- package/dist/{validate-Bz4vqcX1.mjs → validate-DGhQPXzI.mjs} +2 -2
- package/dist/{validate-Bz4vqcX1.mjs.map → validate-DGhQPXzI.mjs.map} +1 -1
- package/dist/{validate-CNwkPWzz.d.mts → validate-cJOiOvT2.d.mts} +5 -5
- package/dist/{validate-CNwkPWzz.d.mts.map → validate-cJOiOvT2.d.mts.map} +1 -1
- package/dist/{validation-DgGTJm3u.mjs → validation-DVHjPM1M.mjs} +5 -5
- package/dist/{validation-DgGTJm3u.mjs.map → validation-DVHjPM1M.mjs.map} +1 -1
- package/dist/version-BOjj_cfz.mjs +7 -0
- package/dist/{version-D-5txk2m.mjs.map → version-BOjj_cfz.mjs.map} +1 -1
- package/dist/{widgets-DZfmAbE4.mjs → widgets-Ci6hLwfO.mjs} +4 -4
- package/dist/{widgets-DZfmAbE4.mjs.map → widgets-Ci6hLwfO.mjs.map} +1 -1
- package/dist/{zod-generator-Djo_VHCt.mjs → zod-generator-CarzgPAu.mjs} +2 -2
- package/dist/{zod-generator-Djo_VHCt.mjs.map → zod-generator-CarzgPAu.mjs.map} +1 -1
- package/package.json +5 -5
- package/src/api/handlers/redirects.ts +24 -13
- package/src/api/schemas/redirects.ts +11 -4
- package/src/astro/integration/index.ts +44 -8
- package/src/astro/integration/routes.ts +46 -9
- package/src/astro/middleware/redirect.ts +12 -0
- package/src/bylines/field-defs-cache.ts +70 -20
- package/src/cli/commands/doctor.ts +1 -1
- package/src/config/secrets.ts +28 -14
- package/src/emdash-runtime.ts +5 -5
- package/src/redirects/status.ts +27 -0
- package/src/settings/index.ts +13 -13
- package/src/utils/{isolate-cache.ts → single-flight-cache.ts} +26 -21
- package/dist/byline-DUx48sJp.mjs.map +0 -1
- package/dist/redirects-DxVoR7PI.mjs.map +0 -1
- package/dist/secrets-ChPTmy9x.mjs.map +0 -1
- package/dist/settings-DfxiWY_s.mjs.map +0 -1
- package/dist/version-D-5txk2m.mjs +0 -7
- /package/dist/{api-tokens-Oq39ba-Z.mjs → api-tokens-C7ywRx7l.mjs} +0 -0
- /package/dist/{ssrf-BvgVcfNQ.mjs → ssrf-CRZGzjdL.mjs} +0 -0
- /package/dist/{types-CZI4E3qG.mjs → types-BoRm8-pp.mjs} +0 -0
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import "../../../../../base64-CqR-7kqF.mjs";
|
|
2
2
|
import "../../../../../types-BXSUSAjt.mjs";
|
|
3
|
-
import { n as apiSuccess, r as handleError, t as apiError } from "../../../../../error-
|
|
4
|
-
import { r as parseOptionalBody, t as isParseError } from "../../../../../parse-
|
|
5
|
-
import { Vt as mediaConfirmBody } from "../../../../../redirects-
|
|
6
|
-
import "../../../../../byline-fields-
|
|
3
|
+
import { n as apiSuccess, r as handleError, t as apiError } from "../../../../../error-CNn_w7jf.mjs";
|
|
4
|
+
import { r as parseOptionalBody, t as isParseError } from "../../../../../parse-DzSrk1t8.mjs";
|
|
5
|
+
import { Vt as mediaConfirmBody } from "../../../../../redirects-6Zg2SoYo.mjs";
|
|
6
|
+
import "../../../../../byline-fields-B0NO1yUB.mjs";
|
|
7
|
+
import "../../../../../status-2gZklYuj.mjs";
|
|
7
8
|
import "../../../../../api/schemas/index.mjs";
|
|
8
|
-
import { n as requirePerm, t as requireOwnerPerm } from "../../../../../authorize-
|
|
9
|
+
import { n as requirePerm, t as requireOwnerPerm } from "../../../../../authorize-D5gfBVU5.mjs";
|
|
9
10
|
import { MediaRepository } from "emdash";
|
|
10
11
|
|
|
11
12
|
//#region src/astro/routes/api/media/[id]/confirm.ts
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"confirm.mjs","names":[],"sources":["../../../../../../src/astro/routes/api/media/[id]/confirm.ts"],"sourcesContent":["/**\n * Confirm media upload endpoint\n *\n * POST /_emdash/api/media/{id}/confirm\n *\n * Confirms that the client has successfully uploaded the file to storage.\n * Marks the media record as ready and optionally updates metadata.\n */\n\nimport type { APIRoute } from \"astro\";\nimport { MediaRepository } from \"emdash\";\n\nimport { requireOwnerPerm, requirePerm } from \"#api/authorize.js\";\nimport { apiError, apiSuccess, handleError } from \"#api/error.js\";\nimport { isParseError, parseOptionalBody } from \"#api/parse.js\";\nimport { mediaConfirmBody } from \"#api/schemas.js\";\nimport type { MediaItem } from \"#types\";\n\nexport const prerender = false;\n\n/**\n * Add URL to media item (relative URL for portability)\n */\nfunction addUrlToMedia(item: MediaItem): MediaItem & { url: string } {\n\treturn {\n\t\t...item,\n\t\turl: `/_emdash/api/media/file/${item.storageKey}`,\n\t};\n}\n\n/**\n * Confirm upload completion\n */\nexport const POST: APIRoute = async ({ params, request, locals }) => {\n\tconst { emdash, user } = locals;\n\tconst { id } = params;\n\n\tconst denied = requirePerm(user, \"media:upload\");\n\tif (denied) return denied;\n\n\tif (!id) {\n\t\treturn apiError(\"INVALID_REQUEST\", \"Media ID is required\", 400);\n\t}\n\n\tif (!emdash?.db) {\n\t\treturn apiError(\"NOT_CONFIGURED\", \"EmDash is not initialized\", 500);\n\t}\n\n\ttry {\n\t\tconst body = await parseOptionalBody(request, mediaConfirmBody, {});\n\t\tif (isParseError(body)) return body;\n\n\t\tconst repo = new MediaRepository(emdash.db);\n\n\t\t// Get the media item first to check status\n\t\tconst existing = await repo.findById(id);\n\t\tif (!existing) {\n\t\t\treturn apiError(\"NOT_FOUND\", `Media item not found: ${id}`, 404);\n\t\t}\n\n\t\tif (existing.status !== \"pending\") {\n\t\t\treturn apiError(\"INVALID_STATE\", `Media item is not pending: ${existing.status}`, 400);\n\t\t}\n\n\t\t// Only the uploader or a user with media:edit_any can confirm/fail a pending upload\n\t\tconst ownerDenied = requireOwnerPerm(\n\t\t\tuser,\n\t\t\texisting.authorId ?? \"\",\n\t\t\t\"media:edit_own\",\n\t\t\t\"media:edit_any\",\n\t\t);\n\t\tif (ownerDenied) return ownerDenied;\n\n\t\t// Optionally verify the file exists in storage\n\t\tif (emdash.storage) {\n\t\t\tconst exists = await emdash.storage.exists(existing.storageKey);\n\t\t\tif (!exists) {\n\t\t\t\t// Mark as failed\n\t\t\t\tawait repo.markFailed(id);\n\t\t\t\treturn apiError(\"FILE_NOT_FOUND\", \"File was not uploaded to storage\", 400);\n\t\t\t}\n\t\t}\n\n\t\t// Confirm the upload\n\t\tconst item = await repo.confirmUpload(id, {\n\t\t\tsize: body.size,\n\t\t\twidth: body.width,\n\t\t\theight: body.height,\n\t\t});\n\n\t\tif (!item) {\n\t\t\treturn apiError(\"CONFIRM_FAILED\", \"Failed to confirm upload\", 500);\n\t\t}\n\n\t\t// Add URL to the response (relative URL for portability)\n\t\tconst itemWithUrl = addUrlToMedia(item);\n\n\t\treturn apiSuccess({ item: itemWithUrl });\n\t} catch (error) {\n\t\treturn handleError(error, \"Failed to confirm upload\", \"CONFIRM_ERROR\");\n\t}\n};\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"confirm.mjs","names":[],"sources":["../../../../../../src/astro/routes/api/media/[id]/confirm.ts"],"sourcesContent":["/**\n * Confirm media upload endpoint\n *\n * POST /_emdash/api/media/{id}/confirm\n *\n * Confirms that the client has successfully uploaded the file to storage.\n * Marks the media record as ready and optionally updates metadata.\n */\n\nimport type { APIRoute } from \"astro\";\nimport { MediaRepository } from \"emdash\";\n\nimport { requireOwnerPerm, requirePerm } from \"#api/authorize.js\";\nimport { apiError, apiSuccess, handleError } from \"#api/error.js\";\nimport { isParseError, parseOptionalBody } from \"#api/parse.js\";\nimport { mediaConfirmBody } from \"#api/schemas.js\";\nimport type { MediaItem } from \"#types\";\n\nexport const prerender = false;\n\n/**\n * Add URL to media item (relative URL for portability)\n */\nfunction addUrlToMedia(item: MediaItem): MediaItem & { url: string } {\n\treturn {\n\t\t...item,\n\t\turl: `/_emdash/api/media/file/${item.storageKey}`,\n\t};\n}\n\n/**\n * Confirm upload completion\n */\nexport const POST: APIRoute = async ({ params, request, locals }) => {\n\tconst { emdash, user } = locals;\n\tconst { id } = params;\n\n\tconst denied = requirePerm(user, \"media:upload\");\n\tif (denied) return denied;\n\n\tif (!id) {\n\t\treturn apiError(\"INVALID_REQUEST\", \"Media ID is required\", 400);\n\t}\n\n\tif (!emdash?.db) {\n\t\treturn apiError(\"NOT_CONFIGURED\", \"EmDash is not initialized\", 500);\n\t}\n\n\ttry {\n\t\tconst body = await parseOptionalBody(request, mediaConfirmBody, {});\n\t\tif (isParseError(body)) return body;\n\n\t\tconst repo = new MediaRepository(emdash.db);\n\n\t\t// Get the media item first to check status\n\t\tconst existing = await repo.findById(id);\n\t\tif (!existing) {\n\t\t\treturn apiError(\"NOT_FOUND\", `Media item not found: ${id}`, 404);\n\t\t}\n\n\t\tif (existing.status !== \"pending\") {\n\t\t\treturn apiError(\"INVALID_STATE\", `Media item is not pending: ${existing.status}`, 400);\n\t\t}\n\n\t\t// Only the uploader or a user with media:edit_any can confirm/fail a pending upload\n\t\tconst ownerDenied = requireOwnerPerm(\n\t\t\tuser,\n\t\t\texisting.authorId ?? \"\",\n\t\t\t\"media:edit_own\",\n\t\t\t\"media:edit_any\",\n\t\t);\n\t\tif (ownerDenied) return ownerDenied;\n\n\t\t// Optionally verify the file exists in storage\n\t\tif (emdash.storage) {\n\t\t\tconst exists = await emdash.storage.exists(existing.storageKey);\n\t\t\tif (!exists) {\n\t\t\t\t// Mark as failed\n\t\t\t\tawait repo.markFailed(id);\n\t\t\t\treturn apiError(\"FILE_NOT_FOUND\", \"File was not uploaded to storage\", 400);\n\t\t\t}\n\t\t}\n\n\t\t// Confirm the upload\n\t\tconst item = await repo.confirmUpload(id, {\n\t\t\tsize: body.size,\n\t\t\twidth: body.width,\n\t\t\theight: body.height,\n\t\t});\n\n\t\tif (!item) {\n\t\t\treturn apiError(\"CONFIRM_FAILED\", \"Failed to confirm upload\", 500);\n\t\t}\n\n\t\t// Add URL to the response (relative URL for portability)\n\t\tconst itemWithUrl = addUrlToMedia(item);\n\n\t\treturn apiSuccess({ item: itemWithUrl });\n\t} catch (error) {\n\t\treturn handleError(error, \"Failed to confirm upload\", \"CONFIRM_ERROR\");\n\t}\n};\n"],"mappings":";;;;;;;;;;;;AAkBA,MAAa,YAAY;;;;AAKzB,SAAS,cAAc,MAA8C;AACpE,QAAO;EACN,GAAG;EACH,KAAK,2BAA2B,KAAK;EACrC;;;;;AAMF,MAAa,OAAiB,OAAO,EAAE,QAAQ,SAAS,aAAa;CACpE,MAAM,EAAE,QAAQ,SAAS;CACzB,MAAM,EAAE,OAAO;CAEf,MAAM,SAAS,YAAY,MAAM,eAAe;AAChD,KAAI,OAAQ,QAAO;AAEnB,KAAI,CAAC,GACJ,QAAO,SAAS,mBAAmB,wBAAwB,IAAI;AAGhE,KAAI,CAAC,QAAQ,GACZ,QAAO,SAAS,kBAAkB,6BAA6B,IAAI;AAGpE,KAAI;EACH,MAAM,OAAO,MAAM,kBAAkB,SAAS,kBAAkB,EAAE,CAAC;AACnE,MAAI,aAAa,KAAK,CAAE,QAAO;EAE/B,MAAM,OAAO,IAAI,gBAAgB,OAAO,GAAG;EAG3C,MAAM,WAAW,MAAM,KAAK,SAAS,GAAG;AACxC,MAAI,CAAC,SACJ,QAAO,SAAS,aAAa,yBAAyB,MAAM,IAAI;AAGjE,MAAI,SAAS,WAAW,UACvB,QAAO,SAAS,iBAAiB,8BAA8B,SAAS,UAAU,IAAI;EAIvF,MAAM,cAAc,iBACnB,MACA,SAAS,YAAY,IACrB,kBACA,iBACA;AACD,MAAI,YAAa,QAAO;AAGxB,MAAI,OAAO,SAEV;OAAI,CADW,MAAM,OAAO,QAAQ,OAAO,SAAS,WAAW,EAClD;AAEZ,UAAM,KAAK,WAAW,GAAG;AACzB,WAAO,SAAS,kBAAkB,oCAAoC,IAAI;;;EAK5E,MAAM,OAAO,MAAM,KAAK,cAAc,IAAI;GACzC,MAAM,KAAK;GACX,OAAO,KAAK;GACZ,QAAQ,KAAK;GACb,CAAC;AAEF,MAAI,CAAC,KACJ,QAAO,SAAS,kBAAkB,4BAA4B,IAAI;AAMnE,SAAO,WAAW,EAAE,MAFA,cAAc,KAAK,EAEA,CAAC;UAChC,OAAO;AACf,SAAO,YAAY,OAAO,4BAA4B,gBAAgB"}
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import "../../../../base64-CqR-7kqF.mjs";
|
|
2
2
|
import "../../../../types-BXSUSAjt.mjs";
|
|
3
|
-
import { a as unwrapResult, r as handleError, t as apiError } from "../../../../error-
|
|
4
|
-
import { n as parseBody, t as isParseError } from "../../../../parse-
|
|
5
|
-
import { Yt as mediaUpdateBody } from "../../../../redirects-
|
|
6
|
-
import "../../../../byline-fields-
|
|
3
|
+
import { a as unwrapResult, r as handleError, t as apiError } from "../../../../error-CNn_w7jf.mjs";
|
|
4
|
+
import { n as parseBody, t as isParseError } from "../../../../parse-DzSrk1t8.mjs";
|
|
5
|
+
import { Yt as mediaUpdateBody } from "../../../../redirects-6Zg2SoYo.mjs";
|
|
6
|
+
import "../../../../byline-fields-B0NO1yUB.mjs";
|
|
7
|
+
import "../../../../status-2gZklYuj.mjs";
|
|
7
8
|
import "../../../../api/schemas/index.mjs";
|
|
8
|
-
import { n as requirePerm, t as requireOwnerPerm } from "../../../../authorize-
|
|
9
|
+
import { n as requirePerm, t as requireOwnerPerm } from "../../../../authorize-D5gfBVU5.mjs";
|
|
9
10
|
|
|
10
11
|
//#region src/astro/routes/api/media/[id].ts
|
|
11
12
|
const prerender = false;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"_id_.mjs","names":[],"sources":["../../../../../src/astro/routes/api/media/[id].ts"],"sourcesContent":["/**\n * Single media item endpoint\n *\n * GET /_emdash/api/media/:id - Get media item\n * PUT /_emdash/api/media/:id - Update media metadata\n * DELETE /_emdash/api/media/:id - Delete media item\n */\n\nimport type { APIRoute } from \"astro\";\n\nimport { requireOwnerPerm, requirePerm } from \"#api/authorize.js\";\nimport { apiError, handleError, unwrapResult } from \"#api/error.js\";\nimport { isParseError, parseBody } from \"#api/parse.js\";\nimport { mediaUpdateBody } from \"#api/schemas.js\";\n\nexport const prerender = false;\n\n/**\n * Get media item\n */\nexport const GET: APIRoute = async ({ params, locals }) => {\n\tconst { emdash, user } = locals;\n\tconst { id } = params;\n\n\tconst readDenied = requirePerm(user, \"media:read\");\n\tif (readDenied) return readDenied;\n\n\tif (!id) {\n\t\treturn apiError(\"INVALID_REQUEST\", \"Media ID required\", 400);\n\t}\n\n\tif (!emdash?.handleMediaGet) {\n\t\treturn apiError(\"NOT_CONFIGURED\", \"EmDash is not initialized\", 500);\n\t}\n\n\tconst result = await emdash.handleMediaGet(id);\n\treturn unwrapResult(result);\n};\n\n/**\n * Update media metadata\n *\n * Authors can edit their own media; editors+ can edit any.\n */\nexport const PUT: APIRoute = async ({ params, request, locals }) => {\n\tconst { emdash, user } = locals;\n\tconst { id } = params;\n\n\t// Minimum permission gate — ownership checked below\n\tconst editDenied = requirePerm(user, \"media:edit_own\");\n\tif (editDenied) return editDenied;\n\n\tif (!id) {\n\t\treturn apiError(\"INVALID_REQUEST\", \"Media ID required\", 400);\n\t}\n\n\tif (!emdash?.handleMediaGet || !emdash?.handleMediaUpdate) {\n\t\treturn apiError(\"NOT_CONFIGURED\", \"EmDash is not initialized\", 500);\n\t}\n\n\ttry {\n\t\t// Fetch media item for ownership check\n\t\tconst getResult = await emdash.handleMediaGet(id);\n\t\tif (!getResult.success || !getResult.data?.item) {\n\t\t\treturn apiError(\"NOT_FOUND\", \"Media item not found\", 404);\n\t\t}\n\n\t\tconst media = getResult.data.item;\n\n\t\t// Ownership check: authors can edit own, editors+ can edit any\n\t\tconst ownerDenied = requireOwnerPerm(user, media.authorId, \"media:edit_own\", \"media:edit_any\");\n\t\tif (ownerDenied) return ownerDenied;\n\n\t\tconst body = await parseBody(request, mediaUpdateBody);\n\t\tif (isParseError(body)) return body;\n\n\t\tconst result = await emdash.handleMediaUpdate(id, {\n\t\t\talt: body.alt,\n\t\t\tcaption: body.caption,\n\t\t\twidth: body.width,\n\t\t\theight: body.height,\n\t\t});\n\n\t\treturn unwrapResult(result);\n\t} catch (error) {\n\t\treturn handleError(error, \"Failed to update media\", \"MEDIA_UPDATE_ERROR\");\n\t}\n};\n\n/**\n * Delete media item\n *\n * Authors can delete their own media; editors+ can delete any.\n */\nexport const DELETE: APIRoute = async ({ params, locals }) => {\n\tconst { emdash, user } = locals;\n\tconst { id } = params;\n\n\t// Minimum permission gate — ownership checked below\n\tconst deleteDenied = requirePerm(user, \"media:delete_own\");\n\tif (deleteDenied) return deleteDenied;\n\n\tif (!id) {\n\t\treturn apiError(\"INVALID_REQUEST\", \"Media ID required\", 400);\n\t}\n\n\tif (!emdash?.handleMediaGet || !emdash?.handleMediaDelete) {\n\t\treturn apiError(\"NOT_CONFIGURED\", \"EmDash is not initialized\", 500);\n\t}\n\n\ttry {\n\t\t// Fetch media item for ownership check and storage key\n\t\tconst getResult = await emdash.handleMediaGet(id);\n\t\tif (!getResult.success || !getResult.data?.item) {\n\t\t\treturn apiError(\"NOT_FOUND\", \"Media item not found\", 404);\n\t\t}\n\n\t\tconst media = getResult.data.item;\n\n\t\t// Ownership check: authors can delete own, editors+ can delete any\n\t\tconst ownerDenied = requireOwnerPerm(\n\t\t\tuser,\n\t\t\tmedia.authorId,\n\t\t\t\"media:delete_own\",\n\t\t\t\"media:delete_any\",\n\t\t);\n\t\tif (ownerDenied) return ownerDenied;\n\n\t\t// Delete file from storage via the storage adapter\n\t\tif (emdash.storage) {\n\t\t\ttry {\n\t\t\t\tawait emdash.storage.delete(media.storageKey);\n\t\t\t} catch {\n\t\t\t\t// Best-effort — continue with database deletion\n\t\t\t}\n\t\t}\n\n\t\t// Delete from database — site-settings cache invalidation happens\n\t\t// in `EmDashRuntime.handleMediaDelete` so MCP/plugin paths inherit it.\n\t\tconst result = await emdash.handleMediaDelete(id);\n\n\t\treturn unwrapResult(result);\n\t} catch (error) {\n\t\treturn handleError(error, \"Failed to delete media\", \"MEDIA_DELETE_ERROR\");\n\t}\n};\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"_id_.mjs","names":[],"sources":["../../../../../src/astro/routes/api/media/[id].ts"],"sourcesContent":["/**\n * Single media item endpoint\n *\n * GET /_emdash/api/media/:id - Get media item\n * PUT /_emdash/api/media/:id - Update media metadata\n * DELETE /_emdash/api/media/:id - Delete media item\n */\n\nimport type { APIRoute } from \"astro\";\n\nimport { requireOwnerPerm, requirePerm } from \"#api/authorize.js\";\nimport { apiError, handleError, unwrapResult } from \"#api/error.js\";\nimport { isParseError, parseBody } from \"#api/parse.js\";\nimport { mediaUpdateBody } from \"#api/schemas.js\";\n\nexport const prerender = false;\n\n/**\n * Get media item\n */\nexport const GET: APIRoute = async ({ params, locals }) => {\n\tconst { emdash, user } = locals;\n\tconst { id } = params;\n\n\tconst readDenied = requirePerm(user, \"media:read\");\n\tif (readDenied) return readDenied;\n\n\tif (!id) {\n\t\treturn apiError(\"INVALID_REQUEST\", \"Media ID required\", 400);\n\t}\n\n\tif (!emdash?.handleMediaGet) {\n\t\treturn apiError(\"NOT_CONFIGURED\", \"EmDash is not initialized\", 500);\n\t}\n\n\tconst result = await emdash.handleMediaGet(id);\n\treturn unwrapResult(result);\n};\n\n/**\n * Update media metadata\n *\n * Authors can edit their own media; editors+ can edit any.\n */\nexport const PUT: APIRoute = async ({ params, request, locals }) => {\n\tconst { emdash, user } = locals;\n\tconst { id } = params;\n\n\t// Minimum permission gate — ownership checked below\n\tconst editDenied = requirePerm(user, \"media:edit_own\");\n\tif (editDenied) return editDenied;\n\n\tif (!id) {\n\t\treturn apiError(\"INVALID_REQUEST\", \"Media ID required\", 400);\n\t}\n\n\tif (!emdash?.handleMediaGet || !emdash?.handleMediaUpdate) {\n\t\treturn apiError(\"NOT_CONFIGURED\", \"EmDash is not initialized\", 500);\n\t}\n\n\ttry {\n\t\t// Fetch media item for ownership check\n\t\tconst getResult = await emdash.handleMediaGet(id);\n\t\tif (!getResult.success || !getResult.data?.item) {\n\t\t\treturn apiError(\"NOT_FOUND\", \"Media item not found\", 404);\n\t\t}\n\n\t\tconst media = getResult.data.item;\n\n\t\t// Ownership check: authors can edit own, editors+ can edit any\n\t\tconst ownerDenied = requireOwnerPerm(user, media.authorId, \"media:edit_own\", \"media:edit_any\");\n\t\tif (ownerDenied) return ownerDenied;\n\n\t\tconst body = await parseBody(request, mediaUpdateBody);\n\t\tif (isParseError(body)) return body;\n\n\t\tconst result = await emdash.handleMediaUpdate(id, {\n\t\t\talt: body.alt,\n\t\t\tcaption: body.caption,\n\t\t\twidth: body.width,\n\t\t\theight: body.height,\n\t\t});\n\n\t\treturn unwrapResult(result);\n\t} catch (error) {\n\t\treturn handleError(error, \"Failed to update media\", \"MEDIA_UPDATE_ERROR\");\n\t}\n};\n\n/**\n * Delete media item\n *\n * Authors can delete their own media; editors+ can delete any.\n */\nexport const DELETE: APIRoute = async ({ params, locals }) => {\n\tconst { emdash, user } = locals;\n\tconst { id } = params;\n\n\t// Minimum permission gate — ownership checked below\n\tconst deleteDenied = requirePerm(user, \"media:delete_own\");\n\tif (deleteDenied) return deleteDenied;\n\n\tif (!id) {\n\t\treturn apiError(\"INVALID_REQUEST\", \"Media ID required\", 400);\n\t}\n\n\tif (!emdash?.handleMediaGet || !emdash?.handleMediaDelete) {\n\t\treturn apiError(\"NOT_CONFIGURED\", \"EmDash is not initialized\", 500);\n\t}\n\n\ttry {\n\t\t// Fetch media item for ownership check and storage key\n\t\tconst getResult = await emdash.handleMediaGet(id);\n\t\tif (!getResult.success || !getResult.data?.item) {\n\t\t\treturn apiError(\"NOT_FOUND\", \"Media item not found\", 404);\n\t\t}\n\n\t\tconst media = getResult.data.item;\n\n\t\t// Ownership check: authors can delete own, editors+ can delete any\n\t\tconst ownerDenied = requireOwnerPerm(\n\t\t\tuser,\n\t\t\tmedia.authorId,\n\t\t\t\"media:delete_own\",\n\t\t\t\"media:delete_any\",\n\t\t);\n\t\tif (ownerDenied) return ownerDenied;\n\n\t\t// Delete file from storage via the storage adapter\n\t\tif (emdash.storage) {\n\t\t\ttry {\n\t\t\t\tawait emdash.storage.delete(media.storageKey);\n\t\t\t} catch {\n\t\t\t\t// Best-effort — continue with database deletion\n\t\t\t}\n\t\t}\n\n\t\t// Delete from database — site-settings cache invalidation happens\n\t\t// in `EmDashRuntime.handleMediaDelete` so MCP/plugin paths inherit it.\n\t\tconst result = await emdash.handleMediaDelete(id);\n\n\t\treturn unwrapResult(result);\n\t} catch (error) {\n\t\treturn handleError(error, \"Failed to delete media\", \"MEDIA_DELETE_ERROR\");\n\t}\n};\n"],"mappings":";;;;;;;;;;;AAeA,MAAa,YAAY;;;;AAKzB,MAAa,MAAgB,OAAO,EAAE,QAAQ,aAAa;CAC1D,MAAM,EAAE,QAAQ,SAAS;CACzB,MAAM,EAAE,OAAO;CAEf,MAAM,aAAa,YAAY,MAAM,aAAa;AAClD,KAAI,WAAY,QAAO;AAEvB,KAAI,CAAC,GACJ,QAAO,SAAS,mBAAmB,qBAAqB,IAAI;AAG7D,KAAI,CAAC,QAAQ,eACZ,QAAO,SAAS,kBAAkB,6BAA6B,IAAI;AAIpE,QAAO,aADQ,MAAM,OAAO,eAAe,GAAG,CACnB;;;;;;;AAQ5B,MAAa,MAAgB,OAAO,EAAE,QAAQ,SAAS,aAAa;CACnE,MAAM,EAAE,QAAQ,SAAS;CACzB,MAAM,EAAE,OAAO;CAGf,MAAM,aAAa,YAAY,MAAM,iBAAiB;AACtD,KAAI,WAAY,QAAO;AAEvB,KAAI,CAAC,GACJ,QAAO,SAAS,mBAAmB,qBAAqB,IAAI;AAG7D,KAAI,CAAC,QAAQ,kBAAkB,CAAC,QAAQ,kBACvC,QAAO,SAAS,kBAAkB,6BAA6B,IAAI;AAGpE,KAAI;EAEH,MAAM,YAAY,MAAM,OAAO,eAAe,GAAG;AACjD,MAAI,CAAC,UAAU,WAAW,CAAC,UAAU,MAAM,KAC1C,QAAO,SAAS,aAAa,wBAAwB,IAAI;EAG1D,MAAM,QAAQ,UAAU,KAAK;EAG7B,MAAM,cAAc,iBAAiB,MAAM,MAAM,UAAU,kBAAkB,iBAAiB;AAC9F,MAAI,YAAa,QAAO;EAExB,MAAM,OAAO,MAAM,UAAU,SAAS,gBAAgB;AACtD,MAAI,aAAa,KAAK,CAAE,QAAO;AAS/B,SAAO,aAPQ,MAAM,OAAO,kBAAkB,IAAI;GACjD,KAAK,KAAK;GACV,SAAS,KAAK;GACd,OAAO,KAAK;GACZ,QAAQ,KAAK;GACb,CAAC,CAEyB;UACnB,OAAO;AACf,SAAO,YAAY,OAAO,0BAA0B,qBAAqB;;;;;;;;AAS3E,MAAa,SAAmB,OAAO,EAAE,QAAQ,aAAa;CAC7D,MAAM,EAAE,QAAQ,SAAS;CACzB,MAAM,EAAE,OAAO;CAGf,MAAM,eAAe,YAAY,MAAM,mBAAmB;AAC1D,KAAI,aAAc,QAAO;AAEzB,KAAI,CAAC,GACJ,QAAO,SAAS,mBAAmB,qBAAqB,IAAI;AAG7D,KAAI,CAAC,QAAQ,kBAAkB,CAAC,QAAQ,kBACvC,QAAO,SAAS,kBAAkB,6BAA6B,IAAI;AAGpE,KAAI;EAEH,MAAM,YAAY,MAAM,OAAO,eAAe,GAAG;AACjD,MAAI,CAAC,UAAU,WAAW,CAAC,UAAU,MAAM,KAC1C,QAAO,SAAS,aAAa,wBAAwB,IAAI;EAG1D,MAAM,QAAQ,UAAU,KAAK;EAG7B,MAAM,cAAc,iBACnB,MACA,MAAM,UACN,oBACA,mBACA;AACD,MAAI,YAAa,QAAO;AAGxB,MAAI,OAAO,QACV,KAAI;AACH,SAAM,OAAO,QAAQ,OAAO,MAAM,WAAW;UACtC;AAST,SAAO,aAFQ,MAAM,OAAO,kBAAkB,GAAG,CAEtB;UACnB,OAAO;AACf,SAAO,YAAY,OAAO,0BAA0B,qBAAqB"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import "../../../../../base64-CqR-7kqF.mjs";
|
|
2
2
|
import "../../../../../types-BXSUSAjt.mjs";
|
|
3
|
-
import { r as handleError, t as apiError } from "../../../../../error-
|
|
3
|
+
import { r as handleError, t as apiError } from "../../../../../error-CNn_w7jf.mjs";
|
|
4
4
|
|
|
5
5
|
//#region src/astro/routes/api/media/file/[...key].ts
|
|
6
6
|
const prerender = false;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import "../../../../../../base64-CqR-7kqF.mjs";
|
|
2
2
|
import "../../../../../../types-BXSUSAjt.mjs";
|
|
3
|
-
import { n as apiSuccess, r as handleError, t as apiError } from "../../../../../../error-
|
|
4
|
-
import { n as requirePerm } from "../../../../../../authorize-
|
|
3
|
+
import { n as apiSuccess, r as handleError, t as apiError } from "../../../../../../error-CNn_w7jf.mjs";
|
|
4
|
+
import { n as requirePerm } from "../../../../../../authorize-D5gfBVU5.mjs";
|
|
5
5
|
|
|
6
6
|
//#region src/astro/routes/api/media/providers/[providerId]/[itemId].ts
|
|
7
7
|
const prerender = false;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import "../../../../../../base64-CqR-7kqF.mjs";
|
|
2
2
|
import "../../../../../../types-BXSUSAjt.mjs";
|
|
3
|
-
import { n as apiSuccess, r as handleError, t as apiError } from "../../../../../../error-
|
|
4
|
-
import { n as requirePerm } from "../../../../../../authorize-
|
|
3
|
+
import { n as apiSuccess, r as handleError, t as apiError } from "../../../../../../error-CNn_w7jf.mjs";
|
|
4
|
+
import { n as requirePerm } from "../../../../../../authorize-D5gfBVU5.mjs";
|
|
5
5
|
|
|
6
6
|
//#region src/astro/routes/api/media/providers/[providerId]/index.ts
|
|
7
7
|
const prerender = false;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import "../../../../../base64-CqR-7kqF.mjs";
|
|
2
2
|
import "../../../../../types-BXSUSAjt.mjs";
|
|
3
|
-
import { n as apiSuccess, t as apiError } from "../../../../../error-
|
|
4
|
-
import { n as requirePerm } from "../../../../../authorize-
|
|
3
|
+
import { n as apiSuccess, t as apiError } from "../../../../../error-CNn_w7jf.mjs";
|
|
4
|
+
import { n as requirePerm } from "../../../../../authorize-D5gfBVU5.mjs";
|
|
5
5
|
|
|
6
6
|
//#region src/astro/routes/api/media/providers/index.ts
|
|
7
7
|
const prerender = false;
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import "../../../../base64-CqR-7kqF.mjs";
|
|
2
2
|
import "../../../../types-BXSUSAjt.mjs";
|
|
3
|
-
import { n as normalizeMime, t as matchesMimeAllowlist } from "../../../../mime-
|
|
4
|
-
import { n as apiSuccess, r as handleError, t as apiError } from "../../../../error-
|
|
5
|
-
import { n as parseBody, t as isParseError } from "../../../../parse-
|
|
6
|
-
import { Xt as mediaUploadUrlBody, zt as DEFAULT_MAX_UPLOAD_SIZE } from "../../../../redirects-
|
|
7
|
-
import "../../../../byline-fields-
|
|
3
|
+
import { n as normalizeMime, t as matchesMimeAllowlist } from "../../../../mime-YbtlEtvS.mjs";
|
|
4
|
+
import { n as apiSuccess, r as handleError, t as apiError } from "../../../../error-CNn_w7jf.mjs";
|
|
5
|
+
import { n as parseBody, t as isParseError } from "../../../../parse-DzSrk1t8.mjs";
|
|
6
|
+
import { Xt as mediaUploadUrlBody, zt as DEFAULT_MAX_UPLOAD_SIZE } from "../../../../redirects-6Zg2SoYo.mjs";
|
|
7
|
+
import "../../../../byline-fields-B0NO1yUB.mjs";
|
|
8
|
+
import "../../../../status-2gZklYuj.mjs";
|
|
8
9
|
import "../../../../api/schemas/index.mjs";
|
|
9
|
-
import { n as requirePerm } from "../../../../authorize-
|
|
10
|
-
import { n as resolveFieldAllowlist, t as GLOBAL_UPLOAD_ALLOWLIST } from "../../../../media-allowlist-
|
|
10
|
+
import { n as requirePerm } from "../../../../authorize-D5gfBVU5.mjs";
|
|
11
|
+
import { n as resolveFieldAllowlist, t as GLOBAL_UPLOAD_ALLOWLIST } from "../../../../media-allowlist-_A0SuDn4.mjs";
|
|
11
12
|
import { ulid } from "ulidx";
|
|
12
13
|
import * as path from "node:path";
|
|
13
14
|
import { MediaRepository } from "emdash";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"upload-url.mjs","names":[],"sources":["../../../../../src/astro/routes/api/media/upload-url.ts"],"sourcesContent":["/**\n * Media upload URL endpoint\n *\n * POST /_emdash/api/media/upload-url\n *\n * Returns a signed URL for direct upload to storage.\n * Creates a pending media record that must be confirmed after upload.\n */\n\nimport * as path from \"node:path\";\n\nimport type { APIRoute } from \"astro\";\nimport { MediaRepository } from \"emdash\";\nimport { ulid } from \"ulidx\";\n\nimport { requirePerm } from \"#api/authorize.js\";\nimport { apiError, apiSuccess, handleError } from \"#api/error.js\";\nimport { GLOBAL_UPLOAD_ALLOWLIST, resolveFieldAllowlist } from \"#api/handlers/media-allowlist.js\";\nimport { isParseError, parseBody } from \"#api/parse.js\";\nimport { DEFAULT_MAX_UPLOAD_SIZE, mediaUploadUrlBody } from \"#api/schemas.js\";\nimport { matchesMimeAllowlist, normalizeMime } from \"#media/mime.js\";\n\nexport const prerender = false;\n\ninterface UploadUrlResponse {\n\tuploadUrl: string;\n\tmethod: \"PUT\";\n\theaders: Record<string, string>;\n\tmediaId: string;\n\tstorageKey: string;\n\texpiresAt: string;\n}\n\n/** Response when content already exists (deduplication) */\ninterface ExistingMediaResponse {\n\texisting: true;\n\tmediaId: string;\n\tstorageKey: string;\n\turl: string;\n}\n\n/**\n * Get a signed upload URL for direct-to-storage upload\n */\nexport const POST: APIRoute = async ({ request, locals }) => {\n\tconst { emdash, user } = locals;\n\n\tconst denied = requirePerm(user, \"media:upload\");\n\tif (denied) return denied;\n\n\tif (!emdash?.storage) {\n\t\treturn apiError(\n\t\t\t\"NO_STORAGE\",\n\t\t\t\"Storage not configured. Signed URL uploads require S3-compatible storage.\",\n\t\t\t501,\n\t\t);\n\t}\n\n\tif (!emdash?.db) {\n\t\treturn apiError(\"NOT_CONFIGURED\", \"EmDash is not initialized\", 500);\n\t}\n\n\ttry {\n\t\tconst maxSize = emdash.config.maxUploadSize ?? DEFAULT_MAX_UPLOAD_SIZE;\n\t\tif (!Number.isFinite(maxSize) || maxSize <= 0) {\n\t\t\treturn apiError(\n\t\t\t\t\"CONFIGURATION_ERROR\",\n\t\t\t\t\"Invalid maxUploadSize configuration. Expected a positive finite number.\",\n\t\t\t\t500,\n\t\t\t);\n\t\t}\n\t\tconst body = await parseBody(request, mediaUploadUrlBody(maxSize));\n\t\tif (isParseError(body)) return body;\n\n\t\t// Validate content type (field-aware widening)\n\t\tconst fieldAllowlist = body.fieldId\n\t\t\t? await resolveFieldAllowlist(emdash.db, body.fieldId)\n\t\t\t: null;\n\t\tconst allowlist = fieldAllowlist ?? [...GLOBAL_UPLOAD_ALLOWLIST];\n\n\t\tif (!matchesMimeAllowlist(body.contentType, allowlist)) {\n\t\t\treturn apiError(\"INVALID_TYPE\", \"File type not allowed\", 400);\n\t\t}\n\n\t\tconst repo = new MediaRepository(emdash.db);\n\n\t\t// Check for existing content with same hash (deduplication)\n\t\tif (body.contentHash) {\n\t\t\tconst existing = await repo.findByContentHash(body.contentHash);\n\t\t\tif (existing) {\n\t\t\t\tconst response: ExistingMediaResponse = {\n\t\t\t\t\texisting: true,\n\t\t\t\t\tmediaId: existing.id,\n\t\t\t\t\tstorageKey: existing.storageKey,\n\t\t\t\t\turl: `/_emdash/api/media/file/${existing.storageKey}`,\n\t\t\t\t};\n\t\t\t\treturn apiSuccess(response);\n\t\t\t}\n\t\t}\n\n\t\t// Generate unique storage key\n\t\tconst id = ulid();\n\t\tconst ext = path.extname(body.filename) || \"\";\n\t\tconst storageKey = `${id}${ext}`;\n\n\t\t// Create pending media record with content hash\n\t\tconst mediaItem = await repo.createPending({\n\t\t\tfilename: body.filename,\n\t\t\tmimeType: normalizeMime(body.contentType),\n\t\t\tsize: body.size,\n\t\t\tstorageKey,\n\t\t\tcontentHash: body.contentHash,\n\t\t\tauthorId: user?.id,\n\t\t});\n\n\t\t// Get signed upload URL from storage\n\t\tconst signedUrl = await emdash.storage.getSignedUploadUrl({\n\t\t\tkey: storageKey,\n\t\t\tcontentType: body.contentType,\n\t\t\tsize: body.size,\n\t\t\texpiresIn: 3600, // 1 hour\n\t\t});\n\n\t\tconst response: UploadUrlResponse = {\n\t\t\tuploadUrl: signedUrl.url,\n\t\t\tmethod: signedUrl.method,\n\t\t\theaders: signedUrl.headers,\n\t\t\tmediaId: mediaItem.id,\n\t\t\tstorageKey,\n\t\t\texpiresAt: signedUrl.expiresAt,\n\t\t};\n\n\t\treturn apiSuccess(response);\n\t} catch (error) {\n\t\t// Check if storage doesn't support signed URLs (e.g., local storage)\n\t\tif (\n\t\t\terror instanceof Error &&\n\t\t\t\"code\" in error &&\n\t\t\t// eslint-disable-next-line typescript/no-unsafe-type-assertion -- narrowing error to check custom code property after \"code\" in error guard\n\t\t\t(error as { code: string }).code === \"NOT_SUPPORTED\"\n\t\t) {\n\t\t\treturn apiError(\n\t\t\t\t\"NOT_SUPPORTED\",\n\t\t\t\t\"Storage does not support signed upload URLs. Use direct upload.\",\n\t\t\t\t501,\n\t\t\t);\n\t\t}\n\n\t\treturn handleError(error, \"Failed to generate upload URL\", \"UPLOAD_URL_ERROR\");\n\t}\n};\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"upload-url.mjs","names":[],"sources":["../../../../../src/astro/routes/api/media/upload-url.ts"],"sourcesContent":["/**\n * Media upload URL endpoint\n *\n * POST /_emdash/api/media/upload-url\n *\n * Returns a signed URL for direct upload to storage.\n * Creates a pending media record that must be confirmed after upload.\n */\n\nimport * as path from \"node:path\";\n\nimport type { APIRoute } from \"astro\";\nimport { MediaRepository } from \"emdash\";\nimport { ulid } from \"ulidx\";\n\nimport { requirePerm } from \"#api/authorize.js\";\nimport { apiError, apiSuccess, handleError } from \"#api/error.js\";\nimport { GLOBAL_UPLOAD_ALLOWLIST, resolveFieldAllowlist } from \"#api/handlers/media-allowlist.js\";\nimport { isParseError, parseBody } from \"#api/parse.js\";\nimport { DEFAULT_MAX_UPLOAD_SIZE, mediaUploadUrlBody } from \"#api/schemas.js\";\nimport { matchesMimeAllowlist, normalizeMime } from \"#media/mime.js\";\n\nexport const prerender = false;\n\ninterface UploadUrlResponse {\n\tuploadUrl: string;\n\tmethod: \"PUT\";\n\theaders: Record<string, string>;\n\tmediaId: string;\n\tstorageKey: string;\n\texpiresAt: string;\n}\n\n/** Response when content already exists (deduplication) */\ninterface ExistingMediaResponse {\n\texisting: true;\n\tmediaId: string;\n\tstorageKey: string;\n\turl: string;\n}\n\n/**\n * Get a signed upload URL for direct-to-storage upload\n */\nexport const POST: APIRoute = async ({ request, locals }) => {\n\tconst { emdash, user } = locals;\n\n\tconst denied = requirePerm(user, \"media:upload\");\n\tif (denied) return denied;\n\n\tif (!emdash?.storage) {\n\t\treturn apiError(\n\t\t\t\"NO_STORAGE\",\n\t\t\t\"Storage not configured. Signed URL uploads require S3-compatible storage.\",\n\t\t\t501,\n\t\t);\n\t}\n\n\tif (!emdash?.db) {\n\t\treturn apiError(\"NOT_CONFIGURED\", \"EmDash is not initialized\", 500);\n\t}\n\n\ttry {\n\t\tconst maxSize = emdash.config.maxUploadSize ?? DEFAULT_MAX_UPLOAD_SIZE;\n\t\tif (!Number.isFinite(maxSize) || maxSize <= 0) {\n\t\t\treturn apiError(\n\t\t\t\t\"CONFIGURATION_ERROR\",\n\t\t\t\t\"Invalid maxUploadSize configuration. Expected a positive finite number.\",\n\t\t\t\t500,\n\t\t\t);\n\t\t}\n\t\tconst body = await parseBody(request, mediaUploadUrlBody(maxSize));\n\t\tif (isParseError(body)) return body;\n\n\t\t// Validate content type (field-aware widening)\n\t\tconst fieldAllowlist = body.fieldId\n\t\t\t? await resolveFieldAllowlist(emdash.db, body.fieldId)\n\t\t\t: null;\n\t\tconst allowlist = fieldAllowlist ?? [...GLOBAL_UPLOAD_ALLOWLIST];\n\n\t\tif (!matchesMimeAllowlist(body.contentType, allowlist)) {\n\t\t\treturn apiError(\"INVALID_TYPE\", \"File type not allowed\", 400);\n\t\t}\n\n\t\tconst repo = new MediaRepository(emdash.db);\n\n\t\t// Check for existing content with same hash (deduplication)\n\t\tif (body.contentHash) {\n\t\t\tconst existing = await repo.findByContentHash(body.contentHash);\n\t\t\tif (existing) {\n\t\t\t\tconst response: ExistingMediaResponse = {\n\t\t\t\t\texisting: true,\n\t\t\t\t\tmediaId: existing.id,\n\t\t\t\t\tstorageKey: existing.storageKey,\n\t\t\t\t\turl: `/_emdash/api/media/file/${existing.storageKey}`,\n\t\t\t\t};\n\t\t\t\treturn apiSuccess(response);\n\t\t\t}\n\t\t}\n\n\t\t// Generate unique storage key\n\t\tconst id = ulid();\n\t\tconst ext = path.extname(body.filename) || \"\";\n\t\tconst storageKey = `${id}${ext}`;\n\n\t\t// Create pending media record with content hash\n\t\tconst mediaItem = await repo.createPending({\n\t\t\tfilename: body.filename,\n\t\t\tmimeType: normalizeMime(body.contentType),\n\t\t\tsize: body.size,\n\t\t\tstorageKey,\n\t\t\tcontentHash: body.contentHash,\n\t\t\tauthorId: user?.id,\n\t\t});\n\n\t\t// Get signed upload URL from storage\n\t\tconst signedUrl = await emdash.storage.getSignedUploadUrl({\n\t\t\tkey: storageKey,\n\t\t\tcontentType: body.contentType,\n\t\t\tsize: body.size,\n\t\t\texpiresIn: 3600, // 1 hour\n\t\t});\n\n\t\tconst response: UploadUrlResponse = {\n\t\t\tuploadUrl: signedUrl.url,\n\t\t\tmethod: signedUrl.method,\n\t\t\theaders: signedUrl.headers,\n\t\t\tmediaId: mediaItem.id,\n\t\t\tstorageKey,\n\t\t\texpiresAt: signedUrl.expiresAt,\n\t\t};\n\n\t\treturn apiSuccess(response);\n\t} catch (error) {\n\t\t// Check if storage doesn't support signed URLs (e.g., local storage)\n\t\tif (\n\t\t\terror instanceof Error &&\n\t\t\t\"code\" in error &&\n\t\t\t// eslint-disable-next-line typescript/no-unsafe-type-assertion -- narrowing error to check custom code property after \"code\" in error guard\n\t\t\t(error as { code: string }).code === \"NOT_SUPPORTED\"\n\t\t) {\n\t\t\treturn apiError(\n\t\t\t\t\"NOT_SUPPORTED\",\n\t\t\t\t\"Storage does not support signed upload URLs. Use direct upload.\",\n\t\t\t\t501,\n\t\t\t);\n\t\t}\n\n\t\treturn handleError(error, \"Failed to generate upload URL\", \"UPLOAD_URL_ERROR\");\n\t}\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AAsBA,MAAa,YAAY;;;;AAsBzB,MAAa,OAAiB,OAAO,EAAE,SAAS,aAAa;CAC5D,MAAM,EAAE,QAAQ,SAAS;CAEzB,MAAM,SAAS,YAAY,MAAM,eAAe;AAChD,KAAI,OAAQ,QAAO;AAEnB,KAAI,CAAC,QAAQ,QACZ,QAAO,SACN,cACA,6EACA,IACA;AAGF,KAAI,CAAC,QAAQ,GACZ,QAAO,SAAS,kBAAkB,6BAA6B,IAAI;AAGpE,KAAI;EACH,MAAM,UAAU,OAAO,OAAO,iBAAiB;AAC/C,MAAI,CAAC,OAAO,SAAS,QAAQ,IAAI,WAAW,EAC3C,QAAO,SACN,uBACA,2EACA,IACA;EAEF,MAAM,OAAO,MAAM,UAAU,SAAS,mBAAmB,QAAQ,CAAC;AAClE,MAAI,aAAa,KAAK,CAAE,QAAO;EAM/B,MAAM,aAHiB,KAAK,UACzB,MAAM,sBAAsB,OAAO,IAAI,KAAK,QAAQ,GACpD,SACiC,CAAC,GAAG,wBAAwB;AAEhE,MAAI,CAAC,qBAAqB,KAAK,aAAa,UAAU,CACrD,QAAO,SAAS,gBAAgB,yBAAyB,IAAI;EAG9D,MAAM,OAAO,IAAI,gBAAgB,OAAO,GAAG;AAG3C,MAAI,KAAK,aAAa;GACrB,MAAM,WAAW,MAAM,KAAK,kBAAkB,KAAK,YAAY;AAC/D,OAAI,SAOH,QAAO,WANiC;IACvC,UAAU;IACV,SAAS,SAAS;IAClB,YAAY,SAAS;IACrB,KAAK,2BAA2B,SAAS;IACzC,CAC0B;;EAO7B,MAAM,aAAa,GAFR,MAAM,GACL,KAAK,QAAQ,KAAK,SAAS,IAAI;EAI3C,MAAM,YAAY,MAAM,KAAK,cAAc;GAC1C,UAAU,KAAK;GACf,UAAU,cAAc,KAAK,YAAY;GACzC,MAAM,KAAK;GACX;GACA,aAAa,KAAK;GAClB,UAAU,MAAM;GAChB,CAAC;EAGF,MAAM,YAAY,MAAM,OAAO,QAAQ,mBAAmB;GACzD,KAAK;GACL,aAAa,KAAK;GAClB,MAAM,KAAK;GACX,WAAW;GACX,CAAC;AAWF,SAAO,WAT6B;GACnC,WAAW,UAAU;GACrB,QAAQ,UAAU;GAClB,SAAS,UAAU;GACnB,SAAS,UAAU;GACnB;GACA,WAAW,UAAU;GACrB,CAE0B;UACnB,OAAO;AAEf,MACC,iBAAiB,SACjB,UAAU,SAET,MAA2B,SAAS,gBAErC,QAAO,SACN,iBACA,mEACA,IACA;AAGF,SAAO,YAAY,OAAO,iCAAiC,mBAAmB"}
|
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
import "../../../base64-CqR-7kqF.mjs";
|
|
2
2
|
import "../../../types-BXSUSAjt.mjs";
|
|
3
3
|
import { t as MediaRepository } from "../../../media-JOf3pNkw.mjs";
|
|
4
|
-
import { t as generatePlaceholder } from "../../../placeholder-
|
|
5
|
-
import { n as normalizeMime, t as matchesMimeAllowlist } from "../../../mime-
|
|
6
|
-
import { t as computeContentHash } from "../../../hash-
|
|
7
|
-
import { a as unwrapResult, n as apiSuccess, r as handleError, t as apiError } from "../../../error-
|
|
8
|
-
import { i as parseQuery, t as isParseError } from "../../../parse-
|
|
9
|
-
import { Bt as formatFileSize, Gt as mediaListQuery, zt as DEFAULT_MAX_UPLOAD_SIZE } from "../../../redirects-
|
|
10
|
-
import "../../../byline-fields-
|
|
4
|
+
import { t as generatePlaceholder } from "../../../placeholder-2xumZh4g.mjs";
|
|
5
|
+
import { n as normalizeMime, t as matchesMimeAllowlist } from "../../../mime-YbtlEtvS.mjs";
|
|
6
|
+
import { t as computeContentHash } from "../../../hash-DlvIFn0b.mjs";
|
|
7
|
+
import { a as unwrapResult, n as apiSuccess, r as handleError, t as apiError } from "../../../error-CNn_w7jf.mjs";
|
|
8
|
+
import { i as parseQuery, t as isParseError } from "../../../parse-DzSrk1t8.mjs";
|
|
9
|
+
import { Bt as formatFileSize, Gt as mediaListQuery, zt as DEFAULT_MAX_UPLOAD_SIZE } from "../../../redirects-6Zg2SoYo.mjs";
|
|
10
|
+
import "../../../byline-fields-B0NO1yUB.mjs";
|
|
11
|
+
import "../../../status-2gZklYuj.mjs";
|
|
11
12
|
import "../../../api/schemas/index.mjs";
|
|
12
|
-
import { n as requirePerm } from "../../../authorize-
|
|
13
|
-
import { n as resolveFieldAllowlist, t as GLOBAL_UPLOAD_ALLOWLIST } from "../../../media-allowlist-
|
|
13
|
+
import { n as requirePerm } from "../../../authorize-D5gfBVU5.mjs";
|
|
14
|
+
import { n as resolveFieldAllowlist, t as GLOBAL_UPLOAD_ALLOWLIST } from "../../../media-allowlist-_A0SuDn4.mjs";
|
|
14
15
|
import { ulid } from "ulidx";
|
|
15
16
|
import * as path from "node:path";
|
|
16
17
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"media.mjs","names":[],"sources":["../../../../src/astro/routes/api/media.ts"],"sourcesContent":["/**\n * Media list and upload endpoint\n *\n * GET /_emdash/api/media - List all media\n * POST /_emdash/api/media - Upload new media (via configured storage adapter)\n */\n\nimport * as path from \"node:path\";\n\nimport type { APIRoute } from \"astro\";\nimport { ulid } from \"ulidx\";\n\nimport { requirePerm } from \"#api/authorize.js\";\nimport { apiError, apiSuccess, handleError, unwrapResult } from \"#api/error.js\";\nimport { GLOBAL_UPLOAD_ALLOWLIST, resolveFieldAllowlist } from \"#api/handlers/media-allowlist.js\";\nimport { isParseError, parseQuery } from \"#api/parse.js\";\nimport { DEFAULT_MAX_UPLOAD_SIZE, formatFileSize, mediaListQuery } from \"#api/schemas.js\";\nimport { MediaRepository } from \"#db/repositories/media.js\";\nimport { matchesMimeAllowlist, normalizeMime } from \"#media/mime.js\";\nimport { generatePlaceholder } from \"#media/placeholder.js\";\nimport { computeContentHash } from \"#utils/hash.js\";\n\nimport type { MediaItem } from \"../../types.js\";\n\nexport const prerender = false;\n\n/**\n * Add URL to media items\n * Uses relative URLs to ensure portability across deployments\n */\nfunction addUrlToMedia(item: MediaItem): MediaItem & { url: string } {\n\treturn {\n\t\t...item,\n\t\turl: `/_emdash/api/media/file/${item.storageKey}`,\n\t};\n}\n\n/**\n * List media items\n */\nexport const GET: APIRoute = async ({ request, locals }) => {\n\tconst { emdash, user } = locals;\n\n\tconst denied = requirePerm(user, \"media:read\");\n\tif (denied) return denied;\n\n\tif (!emdash?.handleMediaList) {\n\t\treturn apiError(\"NOT_CONFIGURED\", \"EmDash is not initialized\", 500);\n\t}\n\n\tconst url = new URL(request.url);\n\tconst query = parseQuery(url, mediaListQuery);\n\tif (isParseError(query)) return query;\n\n\tconst result = await emdash.handleMediaList({\n\t\tcursor: query.cursor,\n\t\tlimit: query.limit,\n\t\tmimeType: query.mimeType,\n\t\tq: query.q,\n\t});\n\n\tif (!result.success) {\n\t\treturn unwrapResult(result);\n\t}\n\n\t// Add URL to each media item (relative URLs for portability)\n\tconst itemsWithUrl = result.data.items.map((item) => addUrlToMedia(item));\n\n\treturn apiSuccess({ items: itemsWithUrl, nextCursor: result.data.nextCursor });\n};\n\n/**\n * Upload media file\n *\n * Uses the configured storage adapter to store the file.\n */\nexport const POST: APIRoute = async ({ request, locals }) => {\n\tconst { emdash, user } = locals;\n\n\tconst denied = requirePerm(user, \"media:upload\");\n\tif (denied) return denied;\n\n\tif (!emdash?.handleMediaCreate) {\n\t\treturn apiError(\"NOT_CONFIGURED\", \"EmDash is not initialized\", 500);\n\t}\n\n\tif (!emdash?.storage) {\n\t\treturn apiError(\"NO_STORAGE\", \"Storage not configured\", 500);\n\t}\n\n\ttry {\n\t\tconst rawMax = emdash.config.maxUploadSize ?? DEFAULT_MAX_UPLOAD_SIZE;\n\t\tif (!Number.isFinite(rawMax) || rawMax <= 0) {\n\t\t\treturn apiError(\"CONFIGURATION_ERROR\", \"Invalid maxUploadSize configuration\", 500);\n\t\t}\n\t\tconst maxUploadSize = rawMax;\n\n\t\t// Best-effort size check before buffering the full multipart body\n\t\tconst contentLength = request.headers.get(\"Content-Length\");\n\t\tif (contentLength && parseInt(contentLength, 10) > maxUploadSize) {\n\t\t\treturn apiError(\"PAYLOAD_TOO_LARGE\", \"Upload too large\", 413);\n\t\t}\n\n\t\tconst formData = await request.formData();\n\t\tconst fileEntry = formData.get(\"file\");\n\t\tconst file = fileEntry instanceof File ? fileEntry : null;\n\n\t\tif (!file) {\n\t\t\treturn apiError(\"NO_FILE\", \"No file provided\", 400);\n\t\t}\n\n\t\t// Validate file type — widen the allowlist when a field-specific list is configured\n\t\tconst fieldIdEntry = formData.get(\"fieldId\");\n\t\tconst fieldId =\n\t\t\ttypeof fieldIdEntry === \"string\" && fieldIdEntry.length > 0 ? fieldIdEntry : null;\n\n\t\tconst fieldAllowlist = fieldId ? await resolveFieldAllowlist(emdash.db, fieldId) : null;\n\t\tconst allowlist = fieldAllowlist ?? [...GLOBAL_UPLOAD_ALLOWLIST];\n\n\t\tif (!matchesMimeAllowlist(file.type, allowlist)) {\n\t\t\treturn apiError(\"INVALID_TYPE\", \"File type not allowed\", 400);\n\t\t}\n\n\t\t// Check file size before buffering\n\t\tif (file.size > maxUploadSize) {\n\t\t\treturn apiError(\n\t\t\t\t\"PAYLOAD_TOO_LARGE\",\n\t\t\t\t`File exceeds maximum size of ${formatFileSize(maxUploadSize)}`,\n\t\t\t\t413,\n\t\t\t);\n\t\t}\n\n\t\t// Get file content and compute hash\n\t\tconst buffer = new Uint8Array(await file.arrayBuffer());\n\t\tconst contentHash = await computeContentHash(buffer);\n\n\t\t// Check for existing media with same content hash (deduplication)\n\t\tconst repo = new MediaRepository(emdash.db);\n\t\tconst existing = await repo.findByContentHash(contentHash);\n\t\tif (existing) {\n\t\t\t// Same content already exists - return existing item\n\t\t\tconst itemWithUrl = addUrlToMedia(existing);\n\t\t\treturn apiSuccess({ item: itemWithUrl, deduplicated: true });\n\t\t}\n\n\t\t// Generate unique storage key\n\t\tconst id = ulid();\n\t\tconst ext = path.extname(file.name) || \"\";\n\t\tconst storageKey = `${id}${ext}`;\n\n\t\t// Upload to storage using the configured adapter\n\t\tawait emdash.storage.upload({\n\t\t\tkey: storageKey,\n\t\t\tbody: buffer,\n\t\t\tcontentType: file.type,\n\t\t});\n\n\t\t// Get image dimensions from form data (sent by client)\n\t\tconst widthEntry = formData.get(\"width\");\n\t\tconst widthStr = typeof widthEntry === \"string\" ? widthEntry : null;\n\t\tconst heightEntry = formData.get(\"height\");\n\t\tconst heightStr = typeof heightEntry === \"string\" ? heightEntry : null;\n\t\tconst width = widthStr ? parseInt(widthStr, 10) : undefined;\n\t\tconst height = heightStr ? parseInt(heightStr, 10) : undefined;\n\n\t\t// Generate placeholder data for images.\n\t\t// If the client sent a thumbnail (small pre-resized image), use that\n\t\t// instead of the full buffer to avoid OOM on memory-constrained runtimes.\n\t\tconst thumbnailEntry = formData.get(\"thumbnail\");\n\t\tconst thumbnail = thumbnailEntry instanceof File ? thumbnailEntry : null;\n\n\t\tlet placeholder: Awaited<ReturnType<typeof generatePlaceholder>> = null;\n\t\tif (file.type.startsWith(\"image/\")) {\n\t\t\tif (thumbnail) {\n\t\t\t\tconst thumbBuffer = new Uint8Array(await thumbnail.arrayBuffer());\n\t\t\t\tplaceholder = await generatePlaceholder(thumbBuffer, thumbnail.type);\n\t\t\t} else {\n\t\t\t\tconst clientDims = width && height ? { width, height } : undefined;\n\t\t\t\tplaceholder = await generatePlaceholder(buffer, file.type, clientDims);\n\t\t\t}\n\t\t}\n\n\t\t// Create media record\n\t\tconst result = await emdash.handleMediaCreate({\n\t\t\tfilename: file.name,\n\t\t\tmimeType: normalizeMime(file.type),\n\t\t\tsize: file.size,\n\t\t\twidth,\n\t\t\theight,\n\t\t\tstorageKey,\n\t\t\tcontentHash,\n\t\t\tblurhash: placeholder?.blurhash,\n\t\t\tdominantColor: placeholder?.dominantColor,\n\t\t\tauthorId: user?.id,\n\t\t});\n\n\t\tif (!result.success) {\n\t\t\t// Clean up the uploaded file on failure\n\t\t\ttry {\n\t\t\t\tawait emdash.storage.delete(storageKey);\n\t\t\t} catch {\n\t\t\t\t// Ignore cleanup errors\n\t\t\t}\n\t\t\treturn unwrapResult(result);\n\t\t}\n\n\t\t// Add URL to the response (relative URL for portability)\n\t\tconst itemWithUrl = addUrlToMedia(result.data.item);\n\n\t\treturn apiSuccess({ item: itemWithUrl }, 201);\n\t} catch (error) {\n\t\treturn handleError(error, \"Upload failed\", \"UPLOAD_ERROR\");\n\t}\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AAwBA,MAAa,YAAY;;;;;AAMzB,SAAS,cAAc,MAA8C;AACpE,QAAO;EACN,GAAG;EACH,KAAK,2BAA2B,KAAK;EACrC;;;;;AAMF,MAAa,MAAgB,OAAO,EAAE,SAAS,aAAa;CAC3D,MAAM,EAAE,QAAQ,SAAS;CAEzB,MAAM,SAAS,YAAY,MAAM,aAAa;AAC9C,KAAI,OAAQ,QAAO;AAEnB,KAAI,CAAC,QAAQ,gBACZ,QAAO,SAAS,kBAAkB,6BAA6B,IAAI;CAIpE,MAAM,QAAQ,WADF,IAAI,IAAI,QAAQ,IAAI,EACF,eAAe;AAC7C,KAAI,aAAa,MAAM,CAAE,QAAO;CAEhC,MAAM,SAAS,MAAM,OAAO,gBAAgB;EAC3C,QAAQ,MAAM;EACd,OAAO,MAAM;EACb,UAAU,MAAM;EAChB,GAAG,MAAM;EACT,CAAC;AAEF,KAAI,CAAC,OAAO,QACX,QAAO,aAAa,OAAO;AAM5B,QAAO,WAAW;EAAE,OAFC,OAAO,KAAK,MAAM,KAAK,SAAS,cAAc,KAAK,CAAC;EAEhC,YAAY,OAAO,KAAK;EAAY,CAAC;;;;;;;AAQ/E,MAAa,OAAiB,OAAO,EAAE,SAAS,aAAa;CAC5D,MAAM,EAAE,QAAQ,SAAS;CAEzB,MAAM,SAAS,YAAY,MAAM,eAAe;AAChD,KAAI,OAAQ,QAAO;AAEnB,KAAI,CAAC,QAAQ,kBACZ,QAAO,SAAS,kBAAkB,6BAA6B,IAAI;AAGpE,KAAI,CAAC,QAAQ,QACZ,QAAO,SAAS,cAAc,0BAA0B,IAAI;AAG7D,KAAI;EACH,MAAM,SAAS,OAAO,OAAO,iBAAiB;AAC9C,MAAI,CAAC,OAAO,SAAS,OAAO,IAAI,UAAU,EACzC,QAAO,SAAS,uBAAuB,uCAAuC,IAAI;EAEnF,MAAM,gBAAgB;EAGtB,MAAM,gBAAgB,QAAQ,QAAQ,IAAI,iBAAiB;AAC3D,MAAI,iBAAiB,SAAS,eAAe,GAAG,GAAG,cAClD,QAAO,SAAS,qBAAqB,oBAAoB,IAAI;EAG9D,MAAM,WAAW,MAAM,QAAQ,UAAU;EACzC,MAAM,YAAY,SAAS,IAAI,OAAO;EACtC,MAAM,OAAO,qBAAqB,OAAO,YAAY;AAErD,MAAI,CAAC,KACJ,QAAO,SAAS,WAAW,oBAAoB,IAAI;EAIpD,MAAM,eAAe,SAAS,IAAI,UAAU;EAC5C,MAAM,UACL,OAAO,iBAAiB,YAAY,aAAa,SAAS,IAAI,eAAe;EAG9E,MAAM,aADiB,UAAU,MAAM,sBAAsB,OAAO,IAAI,QAAQ,GAAG,SAC/C,CAAC,GAAG,wBAAwB;AAEhE,MAAI,CAAC,qBAAqB,KAAK,MAAM,UAAU,CAC9C,QAAO,SAAS,gBAAgB,yBAAyB,IAAI;AAI9D,MAAI,KAAK,OAAO,cACf,QAAO,SACN,qBACA,gCAAgC,eAAe,cAAc,IAC7D,IACA;EAIF,MAAM,SAAS,IAAI,WAAW,MAAM,KAAK,aAAa,CAAC;EACvD,MAAM,cAAc,MAAM,mBAAmB,OAAO;EAIpD,MAAM,WAAW,MADJ,IAAI,gBAAgB,OAAO,GAAG,CACf,kBAAkB,YAAY;AAC1D,MAAI,SAGH,QAAO,WAAW;GAAE,MADA,cAAc,SAAS;GACJ,cAAc;GAAM,CAAC;EAM7D,MAAM,aAAa,GAFR,MAAM,GACL,KAAK,QAAQ,KAAK,KAAK,IAAI;AAIvC,QAAM,OAAO,QAAQ,OAAO;GAC3B,KAAK;GACL,MAAM;GACN,aAAa,KAAK;GAClB,CAAC;EAGF,MAAM,aAAa,SAAS,IAAI,QAAQ;EACxC,MAAM,WAAW,OAAO,eAAe,WAAW,aAAa;EAC/D,MAAM,cAAc,SAAS,IAAI,SAAS;EAC1C,MAAM,YAAY,OAAO,gBAAgB,WAAW,cAAc;EAClE,MAAM,QAAQ,WAAW,SAAS,UAAU,GAAG,GAAG;EAClD,MAAM,SAAS,YAAY,SAAS,WAAW,GAAG,GAAG;EAKrD,MAAM,iBAAiB,SAAS,IAAI,YAAY;EAChD,MAAM,YAAY,0BAA0B,OAAO,iBAAiB;EAEpE,IAAI,cAA+D;AACnE,MAAI,KAAK,KAAK,WAAW,SAAS,CACjC,KAAI,UAEH,eAAc,MAAM,oBADA,IAAI,WAAW,MAAM,UAAU,aAAa,CAAC,EACZ,UAAU,KAAK;OAC9D;GACN,MAAM,aAAa,SAAS,SAAS;IAAE;IAAO;IAAQ,GAAG;AACzD,iBAAc,MAAM,oBAAoB,QAAQ,KAAK,MAAM,WAAW;;EAKxE,MAAM,SAAS,MAAM,OAAO,kBAAkB;GAC7C,UAAU,KAAK;GACf,UAAU,cAAc,KAAK,KAAK;GAClC,MAAM,KAAK;GACX;GACA;GACA;GACA;GACA,UAAU,aAAa;GACvB,eAAe,aAAa;GAC5B,UAAU,MAAM;GAChB,CAAC;AAEF,MAAI,CAAC,OAAO,SAAS;AAEpB,OAAI;AACH,UAAM,OAAO,QAAQ,OAAO,WAAW;WAChC;AAGR,UAAO,aAAa,OAAO;;AAM5B,SAAO,WAAW,EAAE,MAFA,cAAc,OAAO,KAAK,KAAK,EAEZ,EAAE,IAAI;UACrC,OAAO;AACf,SAAO,YAAY,OAAO,iBAAiB,eAAe"}
|
|
1
|
+
{"version":3,"file":"media.mjs","names":[],"sources":["../../../../src/astro/routes/api/media.ts"],"sourcesContent":["/**\n * Media list and upload endpoint\n *\n * GET /_emdash/api/media - List all media\n * POST /_emdash/api/media - Upload new media (via configured storage adapter)\n */\n\nimport * as path from \"node:path\";\n\nimport type { APIRoute } from \"astro\";\nimport { ulid } from \"ulidx\";\n\nimport { requirePerm } from \"#api/authorize.js\";\nimport { apiError, apiSuccess, handleError, unwrapResult } from \"#api/error.js\";\nimport { GLOBAL_UPLOAD_ALLOWLIST, resolveFieldAllowlist } from \"#api/handlers/media-allowlist.js\";\nimport { isParseError, parseQuery } from \"#api/parse.js\";\nimport { DEFAULT_MAX_UPLOAD_SIZE, formatFileSize, mediaListQuery } from \"#api/schemas.js\";\nimport { MediaRepository } from \"#db/repositories/media.js\";\nimport { matchesMimeAllowlist, normalizeMime } from \"#media/mime.js\";\nimport { generatePlaceholder } from \"#media/placeholder.js\";\nimport { computeContentHash } from \"#utils/hash.js\";\n\nimport type { MediaItem } from \"../../types.js\";\n\nexport const prerender = false;\n\n/**\n * Add URL to media items\n * Uses relative URLs to ensure portability across deployments\n */\nfunction addUrlToMedia(item: MediaItem): MediaItem & { url: string } {\n\treturn {\n\t\t...item,\n\t\turl: `/_emdash/api/media/file/${item.storageKey}`,\n\t};\n}\n\n/**\n * List media items\n */\nexport const GET: APIRoute = async ({ request, locals }) => {\n\tconst { emdash, user } = locals;\n\n\tconst denied = requirePerm(user, \"media:read\");\n\tif (denied) return denied;\n\n\tif (!emdash?.handleMediaList) {\n\t\treturn apiError(\"NOT_CONFIGURED\", \"EmDash is not initialized\", 500);\n\t}\n\n\tconst url = new URL(request.url);\n\tconst query = parseQuery(url, mediaListQuery);\n\tif (isParseError(query)) return query;\n\n\tconst result = await emdash.handleMediaList({\n\t\tcursor: query.cursor,\n\t\tlimit: query.limit,\n\t\tmimeType: query.mimeType,\n\t\tq: query.q,\n\t});\n\n\tif (!result.success) {\n\t\treturn unwrapResult(result);\n\t}\n\n\t// Add URL to each media item (relative URLs for portability)\n\tconst itemsWithUrl = result.data.items.map((item) => addUrlToMedia(item));\n\n\treturn apiSuccess({ items: itemsWithUrl, nextCursor: result.data.nextCursor });\n};\n\n/**\n * Upload media file\n *\n * Uses the configured storage adapter to store the file.\n */\nexport const POST: APIRoute = async ({ request, locals }) => {\n\tconst { emdash, user } = locals;\n\n\tconst denied = requirePerm(user, \"media:upload\");\n\tif (denied) return denied;\n\n\tif (!emdash?.handleMediaCreate) {\n\t\treturn apiError(\"NOT_CONFIGURED\", \"EmDash is not initialized\", 500);\n\t}\n\n\tif (!emdash?.storage) {\n\t\treturn apiError(\"NO_STORAGE\", \"Storage not configured\", 500);\n\t}\n\n\ttry {\n\t\tconst rawMax = emdash.config.maxUploadSize ?? DEFAULT_MAX_UPLOAD_SIZE;\n\t\tif (!Number.isFinite(rawMax) || rawMax <= 0) {\n\t\t\treturn apiError(\"CONFIGURATION_ERROR\", \"Invalid maxUploadSize configuration\", 500);\n\t\t}\n\t\tconst maxUploadSize = rawMax;\n\n\t\t// Best-effort size check before buffering the full multipart body\n\t\tconst contentLength = request.headers.get(\"Content-Length\");\n\t\tif (contentLength && parseInt(contentLength, 10) > maxUploadSize) {\n\t\t\treturn apiError(\"PAYLOAD_TOO_LARGE\", \"Upload too large\", 413);\n\t\t}\n\n\t\tconst formData = await request.formData();\n\t\tconst fileEntry = formData.get(\"file\");\n\t\tconst file = fileEntry instanceof File ? fileEntry : null;\n\n\t\tif (!file) {\n\t\t\treturn apiError(\"NO_FILE\", \"No file provided\", 400);\n\t\t}\n\n\t\t// Validate file type — widen the allowlist when a field-specific list is configured\n\t\tconst fieldIdEntry = formData.get(\"fieldId\");\n\t\tconst fieldId =\n\t\t\ttypeof fieldIdEntry === \"string\" && fieldIdEntry.length > 0 ? fieldIdEntry : null;\n\n\t\tconst fieldAllowlist = fieldId ? await resolveFieldAllowlist(emdash.db, fieldId) : null;\n\t\tconst allowlist = fieldAllowlist ?? [...GLOBAL_UPLOAD_ALLOWLIST];\n\n\t\tif (!matchesMimeAllowlist(file.type, allowlist)) {\n\t\t\treturn apiError(\"INVALID_TYPE\", \"File type not allowed\", 400);\n\t\t}\n\n\t\t// Check file size before buffering\n\t\tif (file.size > maxUploadSize) {\n\t\t\treturn apiError(\n\t\t\t\t\"PAYLOAD_TOO_LARGE\",\n\t\t\t\t`File exceeds maximum size of ${formatFileSize(maxUploadSize)}`,\n\t\t\t\t413,\n\t\t\t);\n\t\t}\n\n\t\t// Get file content and compute hash\n\t\tconst buffer = new Uint8Array(await file.arrayBuffer());\n\t\tconst contentHash = await computeContentHash(buffer);\n\n\t\t// Check for existing media with same content hash (deduplication)\n\t\tconst repo = new MediaRepository(emdash.db);\n\t\tconst existing = await repo.findByContentHash(contentHash);\n\t\tif (existing) {\n\t\t\t// Same content already exists - return existing item\n\t\t\tconst itemWithUrl = addUrlToMedia(existing);\n\t\t\treturn apiSuccess({ item: itemWithUrl, deduplicated: true });\n\t\t}\n\n\t\t// Generate unique storage key\n\t\tconst id = ulid();\n\t\tconst ext = path.extname(file.name) || \"\";\n\t\tconst storageKey = `${id}${ext}`;\n\n\t\t// Upload to storage using the configured adapter\n\t\tawait emdash.storage.upload({\n\t\t\tkey: storageKey,\n\t\t\tbody: buffer,\n\t\t\tcontentType: file.type,\n\t\t});\n\n\t\t// Get image dimensions from form data (sent by client)\n\t\tconst widthEntry = formData.get(\"width\");\n\t\tconst widthStr = typeof widthEntry === \"string\" ? widthEntry : null;\n\t\tconst heightEntry = formData.get(\"height\");\n\t\tconst heightStr = typeof heightEntry === \"string\" ? heightEntry : null;\n\t\tconst width = widthStr ? parseInt(widthStr, 10) : undefined;\n\t\tconst height = heightStr ? parseInt(heightStr, 10) : undefined;\n\n\t\t// Generate placeholder data for images.\n\t\t// If the client sent a thumbnail (small pre-resized image), use that\n\t\t// instead of the full buffer to avoid OOM on memory-constrained runtimes.\n\t\tconst thumbnailEntry = formData.get(\"thumbnail\");\n\t\tconst thumbnail = thumbnailEntry instanceof File ? thumbnailEntry : null;\n\n\t\tlet placeholder: Awaited<ReturnType<typeof generatePlaceholder>> = null;\n\t\tif (file.type.startsWith(\"image/\")) {\n\t\t\tif (thumbnail) {\n\t\t\t\tconst thumbBuffer = new Uint8Array(await thumbnail.arrayBuffer());\n\t\t\t\tplaceholder = await generatePlaceholder(thumbBuffer, thumbnail.type);\n\t\t\t} else {\n\t\t\t\tconst clientDims = width && height ? { width, height } : undefined;\n\t\t\t\tplaceholder = await generatePlaceholder(buffer, file.type, clientDims);\n\t\t\t}\n\t\t}\n\n\t\t// Create media record\n\t\tconst result = await emdash.handleMediaCreate({\n\t\t\tfilename: file.name,\n\t\t\tmimeType: normalizeMime(file.type),\n\t\t\tsize: file.size,\n\t\t\twidth,\n\t\t\theight,\n\t\t\tstorageKey,\n\t\t\tcontentHash,\n\t\t\tblurhash: placeholder?.blurhash,\n\t\t\tdominantColor: placeholder?.dominantColor,\n\t\t\tauthorId: user?.id,\n\t\t});\n\n\t\tif (!result.success) {\n\t\t\t// Clean up the uploaded file on failure\n\t\t\ttry {\n\t\t\t\tawait emdash.storage.delete(storageKey);\n\t\t\t} catch {\n\t\t\t\t// Ignore cleanup errors\n\t\t\t}\n\t\t\treturn unwrapResult(result);\n\t\t}\n\n\t\t// Add URL to the response (relative URL for portability)\n\t\tconst itemWithUrl = addUrlToMedia(result.data.item);\n\n\t\treturn apiSuccess({ item: itemWithUrl }, 201);\n\t} catch (error) {\n\t\treturn handleError(error, \"Upload failed\", \"UPLOAD_ERROR\");\n\t}\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AAwBA,MAAa,YAAY;;;;;AAMzB,SAAS,cAAc,MAA8C;AACpE,QAAO;EACN,GAAG;EACH,KAAK,2BAA2B,KAAK;EACrC;;;;;AAMF,MAAa,MAAgB,OAAO,EAAE,SAAS,aAAa;CAC3D,MAAM,EAAE,QAAQ,SAAS;CAEzB,MAAM,SAAS,YAAY,MAAM,aAAa;AAC9C,KAAI,OAAQ,QAAO;AAEnB,KAAI,CAAC,QAAQ,gBACZ,QAAO,SAAS,kBAAkB,6BAA6B,IAAI;CAIpE,MAAM,QAAQ,WADF,IAAI,IAAI,QAAQ,IAAI,EACF,eAAe;AAC7C,KAAI,aAAa,MAAM,CAAE,QAAO;CAEhC,MAAM,SAAS,MAAM,OAAO,gBAAgB;EAC3C,QAAQ,MAAM;EACd,OAAO,MAAM;EACb,UAAU,MAAM;EAChB,GAAG,MAAM;EACT,CAAC;AAEF,KAAI,CAAC,OAAO,QACX,QAAO,aAAa,OAAO;AAM5B,QAAO,WAAW;EAAE,OAFC,OAAO,KAAK,MAAM,KAAK,SAAS,cAAc,KAAK,CAAC;EAEhC,YAAY,OAAO,KAAK;EAAY,CAAC;;;;;;;AAQ/E,MAAa,OAAiB,OAAO,EAAE,SAAS,aAAa;CAC5D,MAAM,EAAE,QAAQ,SAAS;CAEzB,MAAM,SAAS,YAAY,MAAM,eAAe;AAChD,KAAI,OAAQ,QAAO;AAEnB,KAAI,CAAC,QAAQ,kBACZ,QAAO,SAAS,kBAAkB,6BAA6B,IAAI;AAGpE,KAAI,CAAC,QAAQ,QACZ,QAAO,SAAS,cAAc,0BAA0B,IAAI;AAG7D,KAAI;EACH,MAAM,SAAS,OAAO,OAAO,iBAAiB;AAC9C,MAAI,CAAC,OAAO,SAAS,OAAO,IAAI,UAAU,EACzC,QAAO,SAAS,uBAAuB,uCAAuC,IAAI;EAEnF,MAAM,gBAAgB;EAGtB,MAAM,gBAAgB,QAAQ,QAAQ,IAAI,iBAAiB;AAC3D,MAAI,iBAAiB,SAAS,eAAe,GAAG,GAAG,cAClD,QAAO,SAAS,qBAAqB,oBAAoB,IAAI;EAG9D,MAAM,WAAW,MAAM,QAAQ,UAAU;EACzC,MAAM,YAAY,SAAS,IAAI,OAAO;EACtC,MAAM,OAAO,qBAAqB,OAAO,YAAY;AAErD,MAAI,CAAC,KACJ,QAAO,SAAS,WAAW,oBAAoB,IAAI;EAIpD,MAAM,eAAe,SAAS,IAAI,UAAU;EAC5C,MAAM,UACL,OAAO,iBAAiB,YAAY,aAAa,SAAS,IAAI,eAAe;EAG9E,MAAM,aADiB,UAAU,MAAM,sBAAsB,OAAO,IAAI,QAAQ,GAAG,SAC/C,CAAC,GAAG,wBAAwB;AAEhE,MAAI,CAAC,qBAAqB,KAAK,MAAM,UAAU,CAC9C,QAAO,SAAS,gBAAgB,yBAAyB,IAAI;AAI9D,MAAI,KAAK,OAAO,cACf,QAAO,SACN,qBACA,gCAAgC,eAAe,cAAc,IAC7D,IACA;EAIF,MAAM,SAAS,IAAI,WAAW,MAAM,KAAK,aAAa,CAAC;EACvD,MAAM,cAAc,MAAM,mBAAmB,OAAO;EAIpD,MAAM,WAAW,MADJ,IAAI,gBAAgB,OAAO,GAAG,CACf,kBAAkB,YAAY;AAC1D,MAAI,SAGH,QAAO,WAAW;GAAE,MADA,cAAc,SAAS;GACJ,cAAc;GAAM,CAAC;EAM7D,MAAM,aAAa,GAFR,MAAM,GACL,KAAK,QAAQ,KAAK,KAAK,IAAI;AAIvC,QAAM,OAAO,QAAQ,OAAO;GAC3B,KAAK;GACL,MAAM;GACN,aAAa,KAAK;GAClB,CAAC;EAGF,MAAM,aAAa,SAAS,IAAI,QAAQ;EACxC,MAAM,WAAW,OAAO,eAAe,WAAW,aAAa;EAC/D,MAAM,cAAc,SAAS,IAAI,SAAS;EAC1C,MAAM,YAAY,OAAO,gBAAgB,WAAW,cAAc;EAClE,MAAM,QAAQ,WAAW,SAAS,UAAU,GAAG,GAAG;EAClD,MAAM,SAAS,YAAY,SAAS,WAAW,GAAG,GAAG;EAKrD,MAAM,iBAAiB,SAAS,IAAI,YAAY;EAChD,MAAM,YAAY,0BAA0B,OAAO,iBAAiB;EAEpE,IAAI,cAA+D;AACnE,MAAI,KAAK,KAAK,WAAW,SAAS,CACjC,KAAI,UAEH,eAAc,MAAM,oBADA,IAAI,WAAW,MAAM,UAAU,aAAa,CAAC,EACZ,UAAU,KAAK;OAC9D;GACN,MAAM,aAAa,SAAS,SAAS;IAAE;IAAO;IAAQ,GAAG;AACzD,iBAAc,MAAM,oBAAoB,QAAQ,KAAK,MAAM,WAAW;;EAKxE,MAAM,SAAS,MAAM,OAAO,kBAAkB;GAC7C,UAAU,KAAK;GACf,UAAU,cAAc,KAAK,KAAK;GAClC,MAAM,KAAK;GACX;GACA;GACA;GACA;GACA,UAAU,aAAa;GACvB,eAAe,aAAa;GAC5B,UAAU,MAAM;GAChB,CAAC;AAEF,MAAI,CAAC,OAAO,SAAS;AAEpB,OAAI;AACH,UAAM,OAAO,QAAQ,OAAO,WAAW;WAChC;AAGR,UAAO,aAAa,OAAO;;AAM5B,SAAO,WAAW,EAAE,MAFA,cAAc,OAAO,KAAK,KAAK,EAEZ,EAAE,IAAI;UACrC,OAAO;AACf,SAAO,YAAY,OAAO,iBAAiB,eAAe"}
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import "../../../../../../base64-CqR-7kqF.mjs";
|
|
2
2
|
import "../../../../../../types-BXSUSAjt.mjs";
|
|
3
3
|
import { a as handleMenuItemDelete, s as handleMenuItemUpdate } from "../../../../../../menus-DX4_E01q.mjs";
|
|
4
|
-
import { a as unwrapResult, r as handleError, t as apiError } from "../../../../../../error-
|
|
5
|
-
import { i as parseQuery, n as parseBody, t as isParseError } from "../../../../../../parse-
|
|
6
|
-
import { Pn as localeFilterQuery, lt as updateMenuItemBody } from "../../../../../../redirects-
|
|
7
|
-
import "../../../../../../byline-fields-
|
|
4
|
+
import { a as unwrapResult, r as handleError, t as apiError } from "../../../../../../error-CNn_w7jf.mjs";
|
|
5
|
+
import { i as parseQuery, n as parseBody, t as isParseError } from "../../../../../../parse-DzSrk1t8.mjs";
|
|
6
|
+
import { Pn as localeFilterQuery, lt as updateMenuItemBody } from "../../../../../../redirects-6Zg2SoYo.mjs";
|
|
7
|
+
import "../../../../../../byline-fields-B0NO1yUB.mjs";
|
|
8
|
+
import "../../../../../../status-2gZklYuj.mjs";
|
|
8
9
|
import "../../../../../../api/schemas/index.mjs";
|
|
9
|
-
import { n as requirePerm } from "../../../../../../authorize-
|
|
10
|
+
import { n as requirePerm } from "../../../../../../authorize-D5gfBVU5.mjs";
|
|
10
11
|
|
|
11
12
|
//#region src/astro/routes/api/menus/[name]/items/[id].ts
|
|
12
13
|
const prerender = false;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"_id_.mjs","names":[],"sources":["../../../../../../../src/astro/routes/api/menus/[name]/items/[id].ts"],"sourcesContent":["/**\n * Single menu item endpoint\n *\n * PUT /_emdash/api/menus/:name/items/:id[?locale=xx]\n * DELETE /_emdash/api/menus/:name/items/:id[?locale=xx]\n */\n\nimport type { APIRoute } from \"astro\";\n\nimport { requirePerm } from \"#api/authorize.js\";\nimport { apiError, handleError, unwrapResult } from \"#api/error.js\";\nimport { handleMenuItemDelete, handleMenuItemUpdate } from \"#api/handlers/menus.js\";\nimport { isParseError, parseBody, parseQuery } from \"#api/parse.js\";\nimport { localeFilterQuery, updateMenuItemBody } from \"#api/schemas.js\";\n\nexport const prerender = false;\n\nexport const PUT: APIRoute = async ({ params, request, locals }) => {\n\tconst { emdash, user } = locals;\n\tconst name = params.name!;\n\tconst itemId = params.id;\n\n\tconst denied = requirePerm(user, \"menus:manage\");\n\tif (denied) return denied;\n\n\tif (!itemId) {\n\t\treturn apiError(\"VALIDATION_ERROR\", \"id is required\", 400);\n\t}\n\n\tconst localeQ = parseQuery(new URL(request.url), localeFilterQuery);\n\tif (isParseError(localeQ)) return localeQ;\n\n\ttry {\n\t\tconst body = await parseBody(request, updateMenuItemBody);\n\t\tif (isParseError(body)) return body;\n\n\t\tconst result = await handleMenuItemUpdate(emdash.db, name, itemId, body, {\n\t\t\tlocale: localeQ.locale,\n\t\t});\n\t\treturn unwrapResult(result);\n\t} catch (error) {\n\t\treturn handleError(error, \"Failed to update menu item\", \"MENU_ITEM_UPDATE_ERROR\");\n\t}\n};\n\nexport const DELETE: APIRoute = async ({ params, request, locals }) => {\n\tconst { emdash, user } = locals;\n\tconst name = params.name!;\n\tconst itemId = params.id;\n\n\tconst denied = requirePerm(user, \"menus:manage\");\n\tif (denied) return denied;\n\n\tif (!itemId) {\n\t\treturn apiError(\"VALIDATION_ERROR\", \"id is required\", 400);\n\t}\n\n\tconst localeQ = parseQuery(new URL(request.url), localeFilterQuery);\n\tif (isParseError(localeQ)) return localeQ;\n\n\ttry {\n\t\tconst result = await handleMenuItemDelete(emdash.db, name, itemId, {\n\t\t\tlocale: localeQ.locale,\n\t\t});\n\t\treturn unwrapResult(result);\n\t} catch (error) {\n\t\treturn handleError(error, \"Failed to delete menu item\", \"MENU_ITEM_DELETE_ERROR\");\n\t}\n};\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"_id_.mjs","names":[],"sources":["../../../../../../../src/astro/routes/api/menus/[name]/items/[id].ts"],"sourcesContent":["/**\n * Single menu item endpoint\n *\n * PUT /_emdash/api/menus/:name/items/:id[?locale=xx]\n * DELETE /_emdash/api/menus/:name/items/:id[?locale=xx]\n */\n\nimport type { APIRoute } from \"astro\";\n\nimport { requirePerm } from \"#api/authorize.js\";\nimport { apiError, handleError, unwrapResult } from \"#api/error.js\";\nimport { handleMenuItemDelete, handleMenuItemUpdate } from \"#api/handlers/menus.js\";\nimport { isParseError, parseBody, parseQuery } from \"#api/parse.js\";\nimport { localeFilterQuery, updateMenuItemBody } from \"#api/schemas.js\";\n\nexport const prerender = false;\n\nexport const PUT: APIRoute = async ({ params, request, locals }) => {\n\tconst { emdash, user } = locals;\n\tconst name = params.name!;\n\tconst itemId = params.id;\n\n\tconst denied = requirePerm(user, \"menus:manage\");\n\tif (denied) return denied;\n\n\tif (!itemId) {\n\t\treturn apiError(\"VALIDATION_ERROR\", \"id is required\", 400);\n\t}\n\n\tconst localeQ = parseQuery(new URL(request.url), localeFilterQuery);\n\tif (isParseError(localeQ)) return localeQ;\n\n\ttry {\n\t\tconst body = await parseBody(request, updateMenuItemBody);\n\t\tif (isParseError(body)) return body;\n\n\t\tconst result = await handleMenuItemUpdate(emdash.db, name, itemId, body, {\n\t\t\tlocale: localeQ.locale,\n\t\t});\n\t\treturn unwrapResult(result);\n\t} catch (error) {\n\t\treturn handleError(error, \"Failed to update menu item\", \"MENU_ITEM_UPDATE_ERROR\");\n\t}\n};\n\nexport const DELETE: APIRoute = async ({ params, request, locals }) => {\n\tconst { emdash, user } = locals;\n\tconst name = params.name!;\n\tconst itemId = params.id;\n\n\tconst denied = requirePerm(user, \"menus:manage\");\n\tif (denied) return denied;\n\n\tif (!itemId) {\n\t\treturn apiError(\"VALIDATION_ERROR\", \"id is required\", 400);\n\t}\n\n\tconst localeQ = parseQuery(new URL(request.url), localeFilterQuery);\n\tif (isParseError(localeQ)) return localeQ;\n\n\ttry {\n\t\tconst result = await handleMenuItemDelete(emdash.db, name, itemId, {\n\t\t\tlocale: localeQ.locale,\n\t\t});\n\t\treturn unwrapResult(result);\n\t} catch (error) {\n\t\treturn handleError(error, \"Failed to delete menu item\", \"MENU_ITEM_DELETE_ERROR\");\n\t}\n};\n"],"mappings":";;;;;;;;;;;;AAeA,MAAa,YAAY;AAEzB,MAAa,MAAgB,OAAO,EAAE,QAAQ,SAAS,aAAa;CACnE,MAAM,EAAE,QAAQ,SAAS;CACzB,MAAM,OAAO,OAAO;CACpB,MAAM,SAAS,OAAO;CAEtB,MAAM,SAAS,YAAY,MAAM,eAAe;AAChD,KAAI,OAAQ,QAAO;AAEnB,KAAI,CAAC,OACJ,QAAO,SAAS,oBAAoB,kBAAkB,IAAI;CAG3D,MAAM,UAAU,WAAW,IAAI,IAAI,QAAQ,IAAI,EAAE,kBAAkB;AACnE,KAAI,aAAa,QAAQ,CAAE,QAAO;AAElC,KAAI;EACH,MAAM,OAAO,MAAM,UAAU,SAAS,mBAAmB;AACzD,MAAI,aAAa,KAAK,CAAE,QAAO;AAK/B,SAAO,aAHQ,MAAM,qBAAqB,OAAO,IAAI,MAAM,QAAQ,MAAM,EACxE,QAAQ,QAAQ,QAChB,CAAC,CACyB;UACnB,OAAO;AACf,SAAO,YAAY,OAAO,8BAA8B,yBAAyB;;;AAInF,MAAa,SAAmB,OAAO,EAAE,QAAQ,SAAS,aAAa;CACtE,MAAM,EAAE,QAAQ,SAAS;CACzB,MAAM,OAAO,OAAO;CACpB,MAAM,SAAS,OAAO;CAEtB,MAAM,SAAS,YAAY,MAAM,eAAe;AAChD,KAAI,OAAQ,QAAO;AAEnB,KAAI,CAAC,OACJ,QAAO,SAAS,oBAAoB,kBAAkB,IAAI;CAG3D,MAAM,UAAU,WAAW,IAAI,IAAI,QAAQ,IAAI,EAAE,kBAAkB;AACnE,KAAI,aAAa,QAAQ,CAAE,QAAO;AAElC,KAAI;AAIH,SAAO,aAHQ,MAAM,qBAAqB,OAAO,IAAI,MAAM,QAAQ,EAClE,QAAQ,QAAQ,QAChB,CAAC,CACyB;UACnB,OAAO;AACf,SAAO,YAAY,OAAO,8BAA8B,yBAAyB"}
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import "../../../../../base64-CqR-7kqF.mjs";
|
|
2
2
|
import "../../../../../types-BXSUSAjt.mjs";
|
|
3
3
|
import { i as handleMenuItemCreate } from "../../../../../menus-DX4_E01q.mjs";
|
|
4
|
-
import { a as unwrapResult, r as handleError } from "../../../../../error-
|
|
5
|
-
import { i as parseQuery, n as parseBody, t as isParseError } from "../../../../../parse-
|
|
6
|
-
import { Pn as localeFilterQuery, et as createMenuItemBody } from "../../../../../redirects-
|
|
7
|
-
import "../../../../../byline-fields-
|
|
4
|
+
import { a as unwrapResult, r as handleError } from "../../../../../error-CNn_w7jf.mjs";
|
|
5
|
+
import { i as parseQuery, n as parseBody, t as isParseError } from "../../../../../parse-DzSrk1t8.mjs";
|
|
6
|
+
import { Pn as localeFilterQuery, et as createMenuItemBody } from "../../../../../redirects-6Zg2SoYo.mjs";
|
|
7
|
+
import "../../../../../byline-fields-B0NO1yUB.mjs";
|
|
8
|
+
import "../../../../../status-2gZklYuj.mjs";
|
|
8
9
|
import "../../../../../api/schemas/index.mjs";
|
|
9
|
-
import { n as requirePerm } from "../../../../../authorize-
|
|
10
|
+
import { n as requirePerm } from "../../../../../authorize-D5gfBVU5.mjs";
|
|
10
11
|
|
|
11
12
|
//#region src/astro/routes/api/menus/[name]/items.ts
|
|
12
13
|
const prerender = false;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"items.mjs","names":[],"sources":["../../../../../../src/astro/routes/api/menus/[name]/items.ts"],"sourcesContent":["/**\n * Menu items create endpoint\n *\n * POST /_emdash/api/menus/:name/items[?locale=xx] - Create a new menu item\n */\n\nimport type { APIRoute } from \"astro\";\n\nimport { requirePerm } from \"#api/authorize.js\";\nimport { handleError, unwrapResult } from \"#api/error.js\";\nimport { handleMenuItemCreate } from \"#api/handlers/menus.js\";\nimport { isParseError, parseBody, parseQuery } from \"#api/parse.js\";\nimport { createMenuItemBody, localeFilterQuery } from \"#api/schemas.js\";\n\nexport const prerender = false;\n\nexport const POST: APIRoute = async ({ params, request, locals }) => {\n\tconst { emdash, user } = locals;\n\tconst name = params.name!;\n\n\tconst denied = requirePerm(user, \"menus:manage\");\n\tif (denied) return denied;\n\n\tconst localeQ = parseQuery(new URL(request.url), localeFilterQuery);\n\tif (isParseError(localeQ)) return localeQ;\n\n\ttry {\n\t\tconst body = await parseBody(request, createMenuItemBody);\n\t\tif (isParseError(body)) return body;\n\n\t\tconst result = await handleMenuItemCreate(emdash.db, name, body, { locale: localeQ.locale });\n\t\treturn unwrapResult(result, 201);\n\t} catch (error) {\n\t\treturn handleError(error, \"Failed to create menu item\", \"MENU_ITEM_CREATE_ERROR\");\n\t}\n};\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"items.mjs","names":[],"sources":["../../../../../../src/astro/routes/api/menus/[name]/items.ts"],"sourcesContent":["/**\n * Menu items create endpoint\n *\n * POST /_emdash/api/menus/:name/items[?locale=xx] - Create a new menu item\n */\n\nimport type { APIRoute } from \"astro\";\n\nimport { requirePerm } from \"#api/authorize.js\";\nimport { handleError, unwrapResult } from \"#api/error.js\";\nimport { handleMenuItemCreate } from \"#api/handlers/menus.js\";\nimport { isParseError, parseBody, parseQuery } from \"#api/parse.js\";\nimport { createMenuItemBody, localeFilterQuery } from \"#api/schemas.js\";\n\nexport const prerender = false;\n\nexport const POST: APIRoute = async ({ params, request, locals }) => {\n\tconst { emdash, user } = locals;\n\tconst name = params.name!;\n\n\tconst denied = requirePerm(user, \"menus:manage\");\n\tif (denied) return denied;\n\n\tconst localeQ = parseQuery(new URL(request.url), localeFilterQuery);\n\tif (isParseError(localeQ)) return localeQ;\n\n\ttry {\n\t\tconst body = await parseBody(request, createMenuItemBody);\n\t\tif (isParseError(body)) return body;\n\n\t\tconst result = await handleMenuItemCreate(emdash.db, name, body, { locale: localeQ.locale });\n\t\treturn unwrapResult(result, 201);\n\t} catch (error) {\n\t\treturn handleError(error, \"Failed to create menu item\", \"MENU_ITEM_CREATE_ERROR\");\n\t}\n};\n"],"mappings":";;;;;;;;;;;;AAcA,MAAa,YAAY;AAEzB,MAAa,OAAiB,OAAO,EAAE,QAAQ,SAAS,aAAa;CACpE,MAAM,EAAE,QAAQ,SAAS;CACzB,MAAM,OAAO,OAAO;CAEpB,MAAM,SAAS,YAAY,MAAM,eAAe;AAChD,KAAI,OAAQ,QAAO;CAEnB,MAAM,UAAU,WAAW,IAAI,IAAI,QAAQ,IAAI,EAAE,kBAAkB;AACnE,KAAI,aAAa,QAAQ,CAAE,QAAO;AAElC,KAAI;EACH,MAAM,OAAO,MAAM,UAAU,SAAS,mBAAmB;AACzD,MAAI,aAAa,KAAK,CAAE,QAAO;AAG/B,SAAO,aADQ,MAAM,qBAAqB,OAAO,IAAI,MAAM,MAAM,EAAE,QAAQ,QAAQ,QAAQ,CAAC,EAChE,IAAI;UACxB,OAAO;AACf,SAAO,YAAY,OAAO,8BAA8B,yBAAyB"}
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import "../../../../../base64-CqR-7kqF.mjs";
|
|
2
2
|
import "../../../../../types-BXSUSAjt.mjs";
|
|
3
3
|
import { o as handleMenuItemReorder } from "../../../../../menus-DX4_E01q.mjs";
|
|
4
|
-
import { a as unwrapResult, r as handleError } from "../../../../../error-
|
|
5
|
-
import { i as parseQuery, n as parseBody, t as isParseError } from "../../../../../parse-
|
|
6
|
-
import { Pn as localeFilterQuery, st as reorderMenuItemsBody } from "../../../../../redirects-
|
|
7
|
-
import "../../../../../byline-fields-
|
|
4
|
+
import { a as unwrapResult, r as handleError } from "../../../../../error-CNn_w7jf.mjs";
|
|
5
|
+
import { i as parseQuery, n as parseBody, t as isParseError } from "../../../../../parse-DzSrk1t8.mjs";
|
|
6
|
+
import { Pn as localeFilterQuery, st as reorderMenuItemsBody } from "../../../../../redirects-6Zg2SoYo.mjs";
|
|
7
|
+
import "../../../../../byline-fields-B0NO1yUB.mjs";
|
|
8
|
+
import "../../../../../status-2gZklYuj.mjs";
|
|
8
9
|
import "../../../../../api/schemas/index.mjs";
|
|
9
|
-
import { n as requirePerm } from "../../../../../authorize-
|
|
10
|
+
import { n as requirePerm } from "../../../../../authorize-D5gfBVU5.mjs";
|
|
10
11
|
|
|
11
12
|
//#region src/astro/routes/api/menus/[name]/reorder.ts
|
|
12
13
|
const prerender = false;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reorder.mjs","names":[],"sources":["../../../../../../src/astro/routes/api/menus/[name]/reorder.ts"],"sourcesContent":["/**\n * Menu items reorder endpoint\n *\n * POST /_emdash/api/menus/:name/reorder - Batch update positions\n */\n\nimport type { APIRoute } from \"astro\";\n\nimport { requirePerm } from \"#api/authorize.js\";\nimport { handleError, unwrapResult } from \"#api/error.js\";\nimport { handleMenuItemReorder } from \"#api/handlers/menus.js\";\nimport { isParseError, parseBody, parseQuery } from \"#api/parse.js\";\nimport { localeFilterQuery, reorderMenuItemsBody } from \"#api/schemas.js\";\n\nexport const prerender = false;\n\nexport const POST: APIRoute = async ({ params, request, locals }) => {\n\tconst { emdash, user } = locals;\n\tconst name = params.name!;\n\n\tconst denied = requirePerm(user, \"menus:manage\");\n\tif (denied) return denied;\n\n\tconst localeQ = parseQuery(new URL(request.url), localeFilterQuery);\n\tif (isParseError(localeQ)) return localeQ;\n\n\ttry {\n\t\tconst body = await parseBody(request, reorderMenuItemsBody);\n\t\tif (isParseError(body)) return body;\n\n\t\tconst result = await handleMenuItemReorder(emdash.db, name, body.items, {\n\t\t\tlocale: localeQ.locale,\n\t\t});\n\t\treturn unwrapResult(result);\n\t} catch (error) {\n\t\treturn handleError(error, \"Failed to reorder menu items\", \"MENU_REORDER_ERROR\");\n\t}\n};\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"reorder.mjs","names":[],"sources":["../../../../../../src/astro/routes/api/menus/[name]/reorder.ts"],"sourcesContent":["/**\n * Menu items reorder endpoint\n *\n * POST /_emdash/api/menus/:name/reorder - Batch update positions\n */\n\nimport type { APIRoute } from \"astro\";\n\nimport { requirePerm } from \"#api/authorize.js\";\nimport { handleError, unwrapResult } from \"#api/error.js\";\nimport { handleMenuItemReorder } from \"#api/handlers/menus.js\";\nimport { isParseError, parseBody, parseQuery } from \"#api/parse.js\";\nimport { localeFilterQuery, reorderMenuItemsBody } from \"#api/schemas.js\";\n\nexport const prerender = false;\n\nexport const POST: APIRoute = async ({ params, request, locals }) => {\n\tconst { emdash, user } = locals;\n\tconst name = params.name!;\n\n\tconst denied = requirePerm(user, \"menus:manage\");\n\tif (denied) return denied;\n\n\tconst localeQ = parseQuery(new URL(request.url), localeFilterQuery);\n\tif (isParseError(localeQ)) return localeQ;\n\n\ttry {\n\t\tconst body = await parseBody(request, reorderMenuItemsBody);\n\t\tif (isParseError(body)) return body;\n\n\t\tconst result = await handleMenuItemReorder(emdash.db, name, body.items, {\n\t\t\tlocale: localeQ.locale,\n\t\t});\n\t\treturn unwrapResult(result);\n\t} catch (error) {\n\t\treturn handleError(error, \"Failed to reorder menu items\", \"MENU_REORDER_ERROR\");\n\t}\n};\n"],"mappings":";;;;;;;;;;;;AAcA,MAAa,YAAY;AAEzB,MAAa,OAAiB,OAAO,EAAE,QAAQ,SAAS,aAAa;CACpE,MAAM,EAAE,QAAQ,SAAS;CACzB,MAAM,OAAO,OAAO;CAEpB,MAAM,SAAS,YAAY,MAAM,eAAe;AAChD,KAAI,OAAQ,QAAO;CAEnB,MAAM,UAAU,WAAW,IAAI,IAAI,QAAQ,IAAI,EAAE,kBAAkB;AACnE,KAAI,aAAa,QAAQ,CAAE,QAAO;AAElC,KAAI;EACH,MAAM,OAAO,MAAM,UAAU,SAAS,qBAAqB;AAC3D,MAAI,aAAa,KAAK,CAAE,QAAO;AAK/B,SAAO,aAHQ,MAAM,sBAAsB,OAAO,IAAI,MAAM,KAAK,OAAO,EACvE,QAAQ,QAAQ,QAChB,CAAC,CACyB;UACnB,OAAO;AACf,SAAO,YAAY,OAAO,gCAAgC,qBAAqB"}
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import "../../../../../base64-CqR-7kqF.mjs";
|
|
2
2
|
import "../../../../../types-BXSUSAjt.mjs";
|
|
3
3
|
import { l as handleMenuTranslations, r as handleMenuGet, t as handleMenuCreate } from "../../../../../menus-DX4_E01q.mjs";
|
|
4
|
-
import { a as unwrapResult, i as requireDb, r as handleError } from "../../../../../error-
|
|
5
|
-
import { i as parseQuery, n as parseBody, t as isParseError } from "../../../../../parse-
|
|
6
|
-
import { Pn as localeFilterQuery } from "../../../../../redirects-
|
|
7
|
-
import "../../../../../byline-fields-
|
|
4
|
+
import { a as unwrapResult, i as requireDb, r as handleError } from "../../../../../error-CNn_w7jf.mjs";
|
|
5
|
+
import { i as parseQuery, n as parseBody, t as isParseError } from "../../../../../parse-DzSrk1t8.mjs";
|
|
6
|
+
import { Pn as localeFilterQuery } from "../../../../../redirects-6Zg2SoYo.mjs";
|
|
7
|
+
import "../../../../../byline-fields-B0NO1yUB.mjs";
|
|
8
|
+
import "../../../../../status-2gZklYuj.mjs";
|
|
8
9
|
import "../../../../../api/schemas/index.mjs";
|
|
9
|
-
import { n as requirePerm } from "../../../../../authorize-
|
|
10
|
+
import { n as requirePerm } from "../../../../../authorize-D5gfBVU5.mjs";
|
|
10
11
|
import { z } from "zod";
|
|
11
12
|
|
|
12
13
|
//#region src/astro/routes/api/menus/[name]/translations.ts
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"translations.mjs","names":[],"sources":["../../../../../../src/astro/routes/api/menus/[name]/translations.ts"],"sourcesContent":["/**\n * Menu translation endpoints\n *\n * GET /_emdash/api/menus/:name/translations — list translations for a menu (uses any locale row)\n * POST /_emdash/api/menus/:name/translations — create a new locale translation (body: { locale, label })\n */\n\nimport type { APIRoute } from \"astro\";\nimport { z } from \"zod\";\n\nimport { requirePerm } from \"#api/authorize.js\";\nimport { handleError, requireDb, unwrapResult } from \"#api/error.js\";\nimport { handleMenuCreate, handleMenuGet, handleMenuTranslations } from \"#api/handlers/menus.js\";\nimport { isParseError, parseBody, parseQuery } from \"#api/parse.js\";\nimport { localeFilterQuery } from \"#api/schemas.js\";\n\nexport const prerender = false;\n\nconst createTranslationBody = z\n\t.object({\n\t\tlocale: z.string().min(1),\n\t\tlabel: z.string().min(1).optional(),\n\t})\n\t.meta({ id: \"CreateMenuTranslationBody\" });\n\nexport const GET: APIRoute = async ({ params, request, locals }) => {\n\tconst { emdash, user } = locals;\n\tconst name = params.name!;\n\n\tconst dbErr = requireDb(emdash?.db);\n\tif (dbErr) return dbErr;\n\n\tconst denied = requirePerm(user, \"menus:read\");\n\tif (denied) return denied;\n\n\tconst localeQ = parseQuery(new URL(request.url), localeFilterQuery);\n\tif (isParseError(localeQ)) return localeQ;\n\n\ttry {\n\t\t// Look up any menu row matching the name so we can get its translation_group.\n\t\tconst anchor = await handleMenuGet(emdash.db, name, { locale: localeQ.locale });\n\t\tif (!anchor.success) return unwrapResult(anchor);\n\t\tconst result = await handleMenuTranslations(emdash.db, anchor.data.id);\n\t\treturn unwrapResult(result);\n\t} catch (error) {\n\t\treturn handleError(error, \"Failed to fetch menu translations\", \"MENU_TRANSLATIONS_ERROR\");\n\t}\n};\n\nexport const POST: APIRoute = async ({ params, request, locals }) => {\n\tconst { emdash, user } = locals;\n\tconst name = params.name!;\n\n\tconst dbErr = requireDb(emdash?.db);\n\tif (dbErr) return dbErr;\n\n\tconst denied = requirePerm(user, \"menus:manage\");\n\tif (denied) return denied;\n\n\tconst localeQ = parseQuery(new URL(request.url), localeFilterQuery);\n\tif (isParseError(localeQ)) return localeQ;\n\n\ttry {\n\t\tconst body = await parseBody(request, createTranslationBody);\n\t\tif (isParseError(body)) return body;\n\n\t\t// Resolve the source menu (either by explicit locale in query, or the\n\t\t// first matching row). Its id becomes the `translationOf` for the new row.\n\t\tconst source = await handleMenuGet(emdash.db, name, { locale: localeQ.locale });\n\t\tif (!source.success) return unwrapResult(source);\n\n\t\tconst result = await handleMenuCreate(emdash.db, {\n\t\t\tname,\n\t\t\tlabel: body.label ?? source.data.label,\n\t\t\tlocale: body.locale,\n\t\t\ttranslationOf: source.data.id,\n\t\t});\n\t\treturn unwrapResult(result, 201);\n\t} catch (error) {\n\t\treturn handleError(error, \"Failed to create menu translation\", \"MENU_TRANSLATION_CREATE_ERROR\");\n\t}\n};\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"translations.mjs","names":[],"sources":["../../../../../../src/astro/routes/api/menus/[name]/translations.ts"],"sourcesContent":["/**\n * Menu translation endpoints\n *\n * GET /_emdash/api/menus/:name/translations — list translations for a menu (uses any locale row)\n * POST /_emdash/api/menus/:name/translations — create a new locale translation (body: { locale, label })\n */\n\nimport type { APIRoute } from \"astro\";\nimport { z } from \"zod\";\n\nimport { requirePerm } from \"#api/authorize.js\";\nimport { handleError, requireDb, unwrapResult } from \"#api/error.js\";\nimport { handleMenuCreate, handleMenuGet, handleMenuTranslations } from \"#api/handlers/menus.js\";\nimport { isParseError, parseBody, parseQuery } from \"#api/parse.js\";\nimport { localeFilterQuery } from \"#api/schemas.js\";\n\nexport const prerender = false;\n\nconst createTranslationBody = z\n\t.object({\n\t\tlocale: z.string().min(1),\n\t\tlabel: z.string().min(1).optional(),\n\t})\n\t.meta({ id: \"CreateMenuTranslationBody\" });\n\nexport const GET: APIRoute = async ({ params, request, locals }) => {\n\tconst { emdash, user } = locals;\n\tconst name = params.name!;\n\n\tconst dbErr = requireDb(emdash?.db);\n\tif (dbErr) return dbErr;\n\n\tconst denied = requirePerm(user, \"menus:read\");\n\tif (denied) return denied;\n\n\tconst localeQ = parseQuery(new URL(request.url), localeFilterQuery);\n\tif (isParseError(localeQ)) return localeQ;\n\n\ttry {\n\t\t// Look up any menu row matching the name so we can get its translation_group.\n\t\tconst anchor = await handleMenuGet(emdash.db, name, { locale: localeQ.locale });\n\t\tif (!anchor.success) return unwrapResult(anchor);\n\t\tconst result = await handleMenuTranslations(emdash.db, anchor.data.id);\n\t\treturn unwrapResult(result);\n\t} catch (error) {\n\t\treturn handleError(error, \"Failed to fetch menu translations\", \"MENU_TRANSLATIONS_ERROR\");\n\t}\n};\n\nexport const POST: APIRoute = async ({ params, request, locals }) => {\n\tconst { emdash, user } = locals;\n\tconst name = params.name!;\n\n\tconst dbErr = requireDb(emdash?.db);\n\tif (dbErr) return dbErr;\n\n\tconst denied = requirePerm(user, \"menus:manage\");\n\tif (denied) return denied;\n\n\tconst localeQ = parseQuery(new URL(request.url), localeFilterQuery);\n\tif (isParseError(localeQ)) return localeQ;\n\n\ttry {\n\t\tconst body = await parseBody(request, createTranslationBody);\n\t\tif (isParseError(body)) return body;\n\n\t\t// Resolve the source menu (either by explicit locale in query, or the\n\t\t// first matching row). Its id becomes the `translationOf` for the new row.\n\t\tconst source = await handleMenuGet(emdash.db, name, { locale: localeQ.locale });\n\t\tif (!source.success) return unwrapResult(source);\n\n\t\tconst result = await handleMenuCreate(emdash.db, {\n\t\t\tname,\n\t\t\tlabel: body.label ?? source.data.label,\n\t\t\tlocale: body.locale,\n\t\t\ttranslationOf: source.data.id,\n\t\t});\n\t\treturn unwrapResult(result, 201);\n\t} catch (error) {\n\t\treturn handleError(error, \"Failed to create menu translation\", \"MENU_TRANSLATION_CREATE_ERROR\");\n\t}\n};\n"],"mappings":";;;;;;;;;;;;;AAgBA,MAAa,YAAY;AAEzB,MAAM,wBAAwB,EAC5B,OAAO;CACP,QAAQ,EAAE,QAAQ,CAAC,IAAI,EAAE;CACzB,OAAO,EAAE,QAAQ,CAAC,IAAI,EAAE,CAAC,UAAU;CACnC,CAAC,CACD,KAAK,EAAE,IAAI,6BAA6B,CAAC;AAE3C,MAAa,MAAgB,OAAO,EAAE,QAAQ,SAAS,aAAa;CACnE,MAAM,EAAE,QAAQ,SAAS;CACzB,MAAM,OAAO,OAAO;CAEpB,MAAM,QAAQ,UAAU,QAAQ,GAAG;AACnC,KAAI,MAAO,QAAO;CAElB,MAAM,SAAS,YAAY,MAAM,aAAa;AAC9C,KAAI,OAAQ,QAAO;CAEnB,MAAM,UAAU,WAAW,IAAI,IAAI,QAAQ,IAAI,EAAE,kBAAkB;AACnE,KAAI,aAAa,QAAQ,CAAE,QAAO;AAElC,KAAI;EAEH,MAAM,SAAS,MAAM,cAAc,OAAO,IAAI,MAAM,EAAE,QAAQ,QAAQ,QAAQ,CAAC;AAC/E,MAAI,CAAC,OAAO,QAAS,QAAO,aAAa,OAAO;AAEhD,SAAO,aADQ,MAAM,uBAAuB,OAAO,IAAI,OAAO,KAAK,GAAG,CAC3C;UACnB,OAAO;AACf,SAAO,YAAY,OAAO,qCAAqC,0BAA0B;;;AAI3F,MAAa,OAAiB,OAAO,EAAE,QAAQ,SAAS,aAAa;CACpE,MAAM,EAAE,QAAQ,SAAS;CACzB,MAAM,OAAO,OAAO;CAEpB,MAAM,QAAQ,UAAU,QAAQ,GAAG;AACnC,KAAI,MAAO,QAAO;CAElB,MAAM,SAAS,YAAY,MAAM,eAAe;AAChD,KAAI,OAAQ,QAAO;CAEnB,MAAM,UAAU,WAAW,IAAI,IAAI,QAAQ,IAAI,EAAE,kBAAkB;AACnE,KAAI,aAAa,QAAQ,CAAE,QAAO;AAElC,KAAI;EACH,MAAM,OAAO,MAAM,UAAU,SAAS,sBAAsB;AAC5D,MAAI,aAAa,KAAK,CAAE,QAAO;EAI/B,MAAM,SAAS,MAAM,cAAc,OAAO,IAAI,MAAM,EAAE,QAAQ,QAAQ,QAAQ,CAAC;AAC/E,MAAI,CAAC,OAAO,QAAS,QAAO,aAAa,OAAO;AAQhD,SAAO,aANQ,MAAM,iBAAiB,OAAO,IAAI;GAChD;GACA,OAAO,KAAK,SAAS,OAAO,KAAK;GACjC,QAAQ,KAAK;GACb,eAAe,OAAO,KAAK;GAC3B,CAAC,EAC0B,IAAI;UACxB,OAAO;AACf,SAAO,YAAY,OAAO,qCAAqC,gCAAgC"}
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import "../../../../base64-CqR-7kqF.mjs";
|
|
2
2
|
import "../../../../types-BXSUSAjt.mjs";
|
|
3
3
|
import { n as handleMenuDelete, r as handleMenuGet, u as handleMenuUpdate } from "../../../../menus-DX4_E01q.mjs";
|
|
4
|
-
import { a as unwrapResult, r as handleError } from "../../../../error-
|
|
5
|
-
import { i as parseQuery, n as parseBody, t as isParseError } from "../../../../parse-
|
|
6
|
-
import { Pn as localeFilterQuery, ct as updateMenuBody } from "../../../../redirects-
|
|
7
|
-
import "../../../../byline-fields-
|
|
4
|
+
import { a as unwrapResult, r as handleError } from "../../../../error-CNn_w7jf.mjs";
|
|
5
|
+
import { i as parseQuery, n as parseBody, t as isParseError } from "../../../../parse-DzSrk1t8.mjs";
|
|
6
|
+
import { Pn as localeFilterQuery, ct as updateMenuBody } from "../../../../redirects-6Zg2SoYo.mjs";
|
|
7
|
+
import "../../../../byline-fields-B0NO1yUB.mjs";
|
|
8
|
+
import "../../../../status-2gZklYuj.mjs";
|
|
8
9
|
import "../../../../api/schemas/index.mjs";
|
|
9
|
-
import { n as requirePerm } from "../../../../authorize-
|
|
10
|
+
import { n as requirePerm } from "../../../../authorize-D5gfBVU5.mjs";
|
|
10
11
|
|
|
11
12
|
//#region src/astro/routes/api/menus/[name].ts
|
|
12
13
|
const prerender = false;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"_name_.mjs","names":[],"sources":["../../../../../src/astro/routes/api/menus/[name].ts"],"sourcesContent":["/**\n * Single menu endpoint\n *\n * GET /_emdash/api/menus/:name[?locale=xx]\n * PUT /_emdash/api/menus/:name[?locale=xx]\n * DELETE /_emdash/api/menus/:name[?locale=xx]\n */\n\nimport type { APIRoute } from \"astro\";\n\nimport { requirePerm } from \"#api/authorize.js\";\nimport { handleError, unwrapResult } from \"#api/error.js\";\nimport { handleMenuDelete, handleMenuGet, handleMenuUpdate } from \"#api/handlers/menus.js\";\nimport { isParseError, parseBody, parseQuery } from \"#api/parse.js\";\nimport { localeFilterQuery, updateMenuBody } from \"#api/schemas.js\";\n\nexport const prerender = false;\n\nexport const GET: APIRoute = async ({ params, request, locals }) => {\n\tconst { emdash, user } = locals;\n\tconst name = params.name!;\n\n\tconst denied = requirePerm(user, \"menus:read\");\n\tif (denied) return denied;\n\n\tconst query = parseQuery(new URL(request.url), localeFilterQuery);\n\tif (isParseError(query)) return query;\n\n\ttry {\n\t\tconst result = await handleMenuGet(emdash.db, name, { locale: query.locale });\n\t\treturn unwrapResult(result);\n\t} catch (error) {\n\t\treturn handleError(error, \"Failed to fetch menu\", \"MENU_GET_ERROR\");\n\t}\n};\n\nexport const PUT: APIRoute = async ({ params, request, locals }) => {\n\tconst { emdash, user } = locals;\n\tconst name = params.name!;\n\n\tconst denied = requirePerm(user, \"menus:manage\");\n\tif (denied) return denied;\n\n\tconst query = parseQuery(new URL(request.url), localeFilterQuery);\n\tif (isParseError(query)) return query;\n\n\ttry {\n\t\tconst body = await parseBody(request, updateMenuBody);\n\t\tif (isParseError(body)) return body;\n\n\t\tconst result = await handleMenuUpdate(emdash.db, name, { ...body, locale: query.locale });\n\t\treturn unwrapResult(result);\n\t} catch (error) {\n\t\treturn handleError(error, \"Failed to update menu\", \"MENU_UPDATE_ERROR\");\n\t}\n};\n\nexport const DELETE: APIRoute = async ({ params, request, locals }) => {\n\tconst { emdash, user } = locals;\n\tconst name = params.name!;\n\n\tconst denied = requirePerm(user, \"menus:manage\");\n\tif (denied) return denied;\n\n\tconst query = parseQuery(new URL(request.url), localeFilterQuery);\n\tif (isParseError(query)) return query;\n\n\ttry {\n\t\tconst result = await handleMenuDelete(emdash.db, name, { locale: query.locale });\n\t\treturn unwrapResult(result);\n\t} catch (error) {\n\t\treturn handleError(error, \"Failed to delete menu\", \"MENU_DELETE_ERROR\");\n\t}\n};\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"_name_.mjs","names":[],"sources":["../../../../../src/astro/routes/api/menus/[name].ts"],"sourcesContent":["/**\n * Single menu endpoint\n *\n * GET /_emdash/api/menus/:name[?locale=xx]\n * PUT /_emdash/api/menus/:name[?locale=xx]\n * DELETE /_emdash/api/menus/:name[?locale=xx]\n */\n\nimport type { APIRoute } from \"astro\";\n\nimport { requirePerm } from \"#api/authorize.js\";\nimport { handleError, unwrapResult } from \"#api/error.js\";\nimport { handleMenuDelete, handleMenuGet, handleMenuUpdate } from \"#api/handlers/menus.js\";\nimport { isParseError, parseBody, parseQuery } from \"#api/parse.js\";\nimport { localeFilterQuery, updateMenuBody } from \"#api/schemas.js\";\n\nexport const prerender = false;\n\nexport const GET: APIRoute = async ({ params, request, locals }) => {\n\tconst { emdash, user } = locals;\n\tconst name = params.name!;\n\n\tconst denied = requirePerm(user, \"menus:read\");\n\tif (denied) return denied;\n\n\tconst query = parseQuery(new URL(request.url), localeFilterQuery);\n\tif (isParseError(query)) return query;\n\n\ttry {\n\t\tconst result = await handleMenuGet(emdash.db, name, { locale: query.locale });\n\t\treturn unwrapResult(result);\n\t} catch (error) {\n\t\treturn handleError(error, \"Failed to fetch menu\", \"MENU_GET_ERROR\");\n\t}\n};\n\nexport const PUT: APIRoute = async ({ params, request, locals }) => {\n\tconst { emdash, user } = locals;\n\tconst name = params.name!;\n\n\tconst denied = requirePerm(user, \"menus:manage\");\n\tif (denied) return denied;\n\n\tconst query = parseQuery(new URL(request.url), localeFilterQuery);\n\tif (isParseError(query)) return query;\n\n\ttry {\n\t\tconst body = await parseBody(request, updateMenuBody);\n\t\tif (isParseError(body)) return body;\n\n\t\tconst result = await handleMenuUpdate(emdash.db, name, { ...body, locale: query.locale });\n\t\treturn unwrapResult(result);\n\t} catch (error) {\n\t\treturn handleError(error, \"Failed to update menu\", \"MENU_UPDATE_ERROR\");\n\t}\n};\n\nexport const DELETE: APIRoute = async ({ params, request, locals }) => {\n\tconst { emdash, user } = locals;\n\tconst name = params.name!;\n\n\tconst denied = requirePerm(user, \"menus:manage\");\n\tif (denied) return denied;\n\n\tconst query = parseQuery(new URL(request.url), localeFilterQuery);\n\tif (isParseError(query)) return query;\n\n\ttry {\n\t\tconst result = await handleMenuDelete(emdash.db, name, { locale: query.locale });\n\t\treturn unwrapResult(result);\n\t} catch (error) {\n\t\treturn handleError(error, \"Failed to delete menu\", \"MENU_DELETE_ERROR\");\n\t}\n};\n"],"mappings":";;;;;;;;;;;;AAgBA,MAAa,YAAY;AAEzB,MAAa,MAAgB,OAAO,EAAE,QAAQ,SAAS,aAAa;CACnE,MAAM,EAAE,QAAQ,SAAS;CACzB,MAAM,OAAO,OAAO;CAEpB,MAAM,SAAS,YAAY,MAAM,aAAa;AAC9C,KAAI,OAAQ,QAAO;CAEnB,MAAM,QAAQ,WAAW,IAAI,IAAI,QAAQ,IAAI,EAAE,kBAAkB;AACjE,KAAI,aAAa,MAAM,CAAE,QAAO;AAEhC,KAAI;AAEH,SAAO,aADQ,MAAM,cAAc,OAAO,IAAI,MAAM,EAAE,QAAQ,MAAM,QAAQ,CAAC,CAClD;UACnB,OAAO;AACf,SAAO,YAAY,OAAO,wBAAwB,iBAAiB;;;AAIrE,MAAa,MAAgB,OAAO,EAAE,QAAQ,SAAS,aAAa;CACnE,MAAM,EAAE,QAAQ,SAAS;CACzB,MAAM,OAAO,OAAO;CAEpB,MAAM,SAAS,YAAY,MAAM,eAAe;AAChD,KAAI,OAAQ,QAAO;CAEnB,MAAM,QAAQ,WAAW,IAAI,IAAI,QAAQ,IAAI,EAAE,kBAAkB;AACjE,KAAI,aAAa,MAAM,CAAE,QAAO;AAEhC,KAAI;EACH,MAAM,OAAO,MAAM,UAAU,SAAS,eAAe;AACrD,MAAI,aAAa,KAAK,CAAE,QAAO;AAG/B,SAAO,aADQ,MAAM,iBAAiB,OAAO,IAAI,MAAM;GAAE,GAAG;GAAM,QAAQ,MAAM;GAAQ,CAAC,CAC9D;UACnB,OAAO;AACf,SAAO,YAAY,OAAO,yBAAyB,oBAAoB;;;AAIzE,MAAa,SAAmB,OAAO,EAAE,QAAQ,SAAS,aAAa;CACtE,MAAM,EAAE,QAAQ,SAAS;CACzB,MAAM,OAAO,OAAO;CAEpB,MAAM,SAAS,YAAY,MAAM,eAAe;AAChD,KAAI,OAAQ,QAAO;CAEnB,MAAM,QAAQ,WAAW,IAAI,IAAI,QAAQ,IAAI,EAAE,kBAAkB;AACjE,KAAI,aAAa,MAAM,CAAE,QAAO;AAEhC,KAAI;AAEH,SAAO,aADQ,MAAM,iBAAiB,OAAO,IAAI,MAAM,EAAE,QAAQ,MAAM,QAAQ,CAAC,CACrD;UACnB,OAAO;AACf,SAAO,YAAY,OAAO,yBAAyB,oBAAoB"}
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import "../../../../base64-CqR-7kqF.mjs";
|
|
2
2
|
import "../../../../types-BXSUSAjt.mjs";
|
|
3
3
|
import { c as handleMenuList, t as handleMenuCreate } from "../../../../menus-DX4_E01q.mjs";
|
|
4
|
-
import { a as unwrapResult, r as handleError } from "../../../../error-
|
|
5
|
-
import { i as parseQuery, n as parseBody, t as isParseError } from "../../../../parse-
|
|
6
|
-
import { $ as createMenuBody, Pn as localeFilterQuery } from "../../../../redirects-
|
|
7
|
-
import "../../../../byline-fields-
|
|
4
|
+
import { a as unwrapResult, r as handleError } from "../../../../error-CNn_w7jf.mjs";
|
|
5
|
+
import { i as parseQuery, n as parseBody, t as isParseError } from "../../../../parse-DzSrk1t8.mjs";
|
|
6
|
+
import { $ as createMenuBody, Pn as localeFilterQuery } from "../../../../redirects-6Zg2SoYo.mjs";
|
|
7
|
+
import "../../../../byline-fields-B0NO1yUB.mjs";
|
|
8
|
+
import "../../../../status-2gZklYuj.mjs";
|
|
8
9
|
import "../../../../api/schemas/index.mjs";
|
|
9
|
-
import { n as requirePerm } from "../../../../authorize-
|
|
10
|
+
import { n as requirePerm } from "../../../../authorize-D5gfBVU5.mjs";
|
|
10
11
|
|
|
11
12
|
//#region src/astro/routes/api/menus/index.ts
|
|
12
13
|
const prerender = false;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":[],"sources":["../../../../../src/astro/routes/api/menus/index.ts"],"sourcesContent":["/**\n * Menus list and create endpoints\n *\n * GET /_emdash/api/menus[?locale=xx] - List menus (optionally filtered by locale)\n * POST /_emdash/api/menus - Create menu (body may include locale & translationOf)\n */\n\nimport type { APIRoute } from \"astro\";\n\nimport { requirePerm } from \"#api/authorize.js\";\nimport { handleError, unwrapResult } from \"#api/error.js\";\nimport { handleMenuCreate, handleMenuList } from \"#api/handlers/menus.js\";\nimport { isParseError, parseBody, parseQuery } from \"#api/parse.js\";\nimport { createMenuBody, localeFilterQuery } from \"#api/schemas.js\";\n\nexport const prerender = false;\n\nexport const GET: APIRoute = async ({ request, locals }) => {\n\tconst { emdash, user } = locals;\n\n\tconst denied = requirePerm(user, \"menus:read\");\n\tif (denied) return denied;\n\n\tconst query = parseQuery(new URL(request.url), localeFilterQuery);\n\tif (isParseError(query)) return query;\n\n\ttry {\n\t\tconst result = await handleMenuList(emdash.db, { locale: query.locale });\n\t\treturn unwrapResult(result);\n\t} catch (error) {\n\t\treturn handleError(error, \"Failed to fetch menus\", \"MENU_LIST_ERROR\");\n\t}\n};\n\nexport const POST: APIRoute = async ({ request, locals }) => {\n\tconst { emdash, user } = locals;\n\n\tconst denied = requirePerm(user, \"menus:manage\");\n\tif (denied) return denied;\n\n\ttry {\n\t\tconst body = await parseBody(request, createMenuBody);\n\t\tif (isParseError(body)) return body;\n\n\t\tconst result = await handleMenuCreate(emdash.db, body);\n\t\treturn unwrapResult(result, 201);\n\t} catch (error) {\n\t\treturn handleError(error, \"Failed to create menu\", \"MENU_CREATE_ERROR\");\n\t}\n};\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../../../../../src/astro/routes/api/menus/index.ts"],"sourcesContent":["/**\n * Menus list and create endpoints\n *\n * GET /_emdash/api/menus[?locale=xx] - List menus (optionally filtered by locale)\n * POST /_emdash/api/menus - Create menu (body may include locale & translationOf)\n */\n\nimport type { APIRoute } from \"astro\";\n\nimport { requirePerm } from \"#api/authorize.js\";\nimport { handleError, unwrapResult } from \"#api/error.js\";\nimport { handleMenuCreate, handleMenuList } from \"#api/handlers/menus.js\";\nimport { isParseError, parseBody, parseQuery } from \"#api/parse.js\";\nimport { createMenuBody, localeFilterQuery } from \"#api/schemas.js\";\n\nexport const prerender = false;\n\nexport const GET: APIRoute = async ({ request, locals }) => {\n\tconst { emdash, user } = locals;\n\n\tconst denied = requirePerm(user, \"menus:read\");\n\tif (denied) return denied;\n\n\tconst query = parseQuery(new URL(request.url), localeFilterQuery);\n\tif (isParseError(query)) return query;\n\n\ttry {\n\t\tconst result = await handleMenuList(emdash.db, { locale: query.locale });\n\t\treturn unwrapResult(result);\n\t} catch (error) {\n\t\treturn handleError(error, \"Failed to fetch menus\", \"MENU_LIST_ERROR\");\n\t}\n};\n\nexport const POST: APIRoute = async ({ request, locals }) => {\n\tconst { emdash, user } = locals;\n\n\tconst denied = requirePerm(user, \"menus:manage\");\n\tif (denied) return denied;\n\n\ttry {\n\t\tconst body = await parseBody(request, createMenuBody);\n\t\tif (isParseError(body)) return body;\n\n\t\tconst result = await handleMenuCreate(emdash.db, body);\n\t\treturn unwrapResult(result, 201);\n\t} catch (error) {\n\t\treturn handleError(error, \"Failed to create menu\", \"MENU_CREATE_ERROR\");\n\t}\n};\n"],"mappings":";;;;;;;;;;;;AAeA,MAAa,YAAY;AAEzB,MAAa,MAAgB,OAAO,EAAE,SAAS,aAAa;CAC3D,MAAM,EAAE,QAAQ,SAAS;CAEzB,MAAM,SAAS,YAAY,MAAM,aAAa;AAC9C,KAAI,OAAQ,QAAO;CAEnB,MAAM,QAAQ,WAAW,IAAI,IAAI,QAAQ,IAAI,EAAE,kBAAkB;AACjE,KAAI,aAAa,MAAM,CAAE,QAAO;AAEhC,KAAI;AAEH,SAAO,aADQ,MAAM,eAAe,OAAO,IAAI,EAAE,QAAQ,MAAM,QAAQ,CAAC,CAC7C;UACnB,OAAO;AACf,SAAO,YAAY,OAAO,yBAAyB,kBAAkB;;;AAIvE,MAAa,OAAiB,OAAO,EAAE,SAAS,aAAa;CAC5D,MAAM,EAAE,QAAQ,SAAS;CAEzB,MAAM,SAAS,YAAY,MAAM,eAAe;AAChD,KAAI,OAAQ,QAAO;AAEnB,KAAI;EACH,MAAM,OAAO,MAAM,UAAU,SAAS,eAAe;AACrD,MAAI,aAAa,KAAK,CAAE,QAAO;AAG/B,SAAO,aADQ,MAAM,iBAAiB,OAAO,IAAI,KAAK,EAC1B,IAAI;UACxB,OAAO;AACf,SAAO,YAAY,OAAO,yBAAyB,oBAAoB"}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { n as getPublicOrigin } from "../../../../public-url-
|
|
2
|
-
import { n as VALID_SCOPES } from "../../../../api-tokens-
|
|
3
|
-
import { t as escapeHtml } from "../../../../escape-
|
|
4
|
-
import { c as validateRedirectUri, o as lookupOAuthClient, s as validateClientRedirectUri } from "../../../../oauth-clients-
|
|
5
|
-
import "../../../../oauth-user-lookup-
|
|
6
|
-
import { n as handleAuthorizationApproval, t as buildDeniedRedirect } from "../../../../oauth-authorization-
|
|
1
|
+
import { n as getPublicOrigin } from "../../../../public-url-D_zARuvZ.mjs";
|
|
2
|
+
import { n as VALID_SCOPES } from "../../../../api-tokens-C7ywRx7l.mjs";
|
|
3
|
+
import { t as escapeHtml } from "../../../../escape-DPgcxcpL.mjs";
|
|
4
|
+
import { c as validateRedirectUri, o as lookupOAuthClient, s as validateClientRedirectUri } from "../../../../oauth-clients-BC873NCV.mjs";
|
|
5
|
+
import "../../../../oauth-user-lookup-e4wOvDud.mjs";
|
|
6
|
+
import { n as handleAuthorizationApproval, t as buildDeniedRedirect } from "../../../../oauth-authorization-C2kVyjXI.mjs";
|
|
7
7
|
|
|
8
8
|
//#region src/astro/routes/api/oauth/authorize.ts
|
|
9
9
|
const prerender = false;
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import "../../../../../base64-CqR-7kqF.mjs";
|
|
2
2
|
import "../../../../../types-BXSUSAjt.mjs";
|
|
3
|
-
import { a as unwrapResult, r as handleError, t as apiError } from "../../../../../error-
|
|
4
|
-
import { n as parseBody, t as isParseError } from "../../../../../parse-
|
|
5
|
-
import "../../../../../api-tokens-
|
|
6
|
-
import "../../../../../oauth-user-lookup-
|
|
7
|
-
import { t as handleDeviceAuthorize } from "../../../../../device-flow-
|
|
3
|
+
import { a as unwrapResult, r as handleError, t as apiError } from "../../../../../error-CNn_w7jf.mjs";
|
|
4
|
+
import { n as parseBody, t as isParseError } from "../../../../../parse-DzSrk1t8.mjs";
|
|
5
|
+
import "../../../../../api-tokens-C7ywRx7l.mjs";
|
|
6
|
+
import "../../../../../oauth-user-lookup-e4wOvDud.mjs";
|
|
7
|
+
import { t as handleDeviceAuthorize } from "../../../../../device-flow-BQApWgnW.mjs";
|
|
8
8
|
import { z } from "zod";
|
|
9
9
|
|
|
10
10
|
//#region src/astro/routes/api/oauth/device/authorize.ts
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import "../../../../../base64-CqR-7kqF.mjs";
|
|
2
2
|
import "../../../../../types-BXSUSAjt.mjs";
|
|
3
|
-
import { a as unwrapResult, r as handleError, t as apiError } from "../../../../../error-
|
|
4
|
-
import { n as parseBody, t as isParseError } from "../../../../../parse-
|
|
5
|
-
import { t as getTrustedProxyHeaders } from "../../../../../trusted-proxy-
|
|
6
|
-
import { n as getPublicOrigin } from "../../../../../public-url-
|
|
7
|
-
import "../../../../../api-tokens-
|
|
8
|
-
import "../../../../../oauth-user-lookup-
|
|
9
|
-
import { n as handleDeviceCodeRequest } from "../../../../../device-flow-
|
|
10
|
-
import { n as getClientIp, r as rateLimitResponse, t as checkRateLimit } from "../../../../../rate-limit-
|
|
3
|
+
import { a as unwrapResult, r as handleError, t as apiError } from "../../../../../error-CNn_w7jf.mjs";
|
|
4
|
+
import { n as parseBody, t as isParseError } from "../../../../../parse-DzSrk1t8.mjs";
|
|
5
|
+
import { t as getTrustedProxyHeaders } from "../../../../../trusted-proxy-CHp41Fjj.mjs";
|
|
6
|
+
import { n as getPublicOrigin } from "../../../../../public-url-D_zARuvZ.mjs";
|
|
7
|
+
import "../../../../../api-tokens-C7ywRx7l.mjs";
|
|
8
|
+
import "../../../../../oauth-user-lookup-e4wOvDud.mjs";
|
|
9
|
+
import { n as handleDeviceCodeRequest } from "../../../../../device-flow-BQApWgnW.mjs";
|
|
10
|
+
import { n as getClientIp, r as rateLimitResponse, t as checkRateLimit } from "../../../../../rate-limit-hRTBqmw1.mjs";
|
|
11
11
|
import { z } from "zod";
|
|
12
12
|
|
|
13
13
|
//#region src/astro/routes/api/oauth/device/code.ts
|