emdash 1.1.0 → 1.2.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/action-token-BdWad2YG.mjs +26 -0
- package/dist/action-token-BdWad2YG.mjs.map +1 -0
- package/dist/adapters-B4-nbElt.d.mts +173 -0
- package/dist/adapters-B4-nbElt.d.mts.map +1 -0
- package/dist/allowed-origins-CLpHGGlc.mjs +116 -0
- package/dist/allowed-origins-CLpHGGlc.mjs.map +1 -0
- package/dist/api/route-utils.d.mts +4 -4
- package/dist/api/route-utils.d.mts.map +1 -1
- package/dist/api/route-utils.mjs +39 -39
- package/dist/api/schemas/index.d.mts +2 -2
- package/dist/api/schemas/index.mjs +10 -10
- package/dist/api-DBw_IWoi.mjs +5024 -0
- package/dist/api-DBw_IWoi.mjs.map +1 -0
- package/dist/api-tokens-B0ZipcZ-.mjs +173 -0
- package/dist/api-tokens-B0ZipcZ-.mjs.map +1 -0
- package/dist/apply-Cx48saFC.mjs +1680 -0
- package/dist/apply-Cx48saFC.mjs.map +1 -0
- package/dist/approvals-BXgtXA2s.mjs +460 -0
- package/dist/approvals-BXgtXA2s.mjs.map +1 -0
- package/dist/artifact-fetch-DsRczRGG.mjs +659 -0
- package/dist/artifact-fetch-DsRczRGG.mjs.map +1 -0
- package/dist/artifacts-D-O-qj9C.mjs +307 -0
- package/dist/artifacts-D-O-qj9C.mjs.map +1 -0
- package/dist/astro/image-endpoint.d.mts.map +1 -1
- package/dist/astro/image-endpoint.mjs +26 -6
- package/dist/astro/image-endpoint.mjs.map +1 -1
- package/dist/astro/index.d.mts +14 -14
- package/dist/astro/index.d.mts.map +1 -1
- package/dist/astro/index.mjs +225 -15
- package/dist/astro/index.mjs.map +1 -1
- package/dist/astro/middleware/auth.d.mts +12 -12
- package/dist/astro/middleware/auth.d.mts.map +1 -1
- package/dist/astro/middleware/auth.mjs +15 -11
- package/dist/astro/middleware/auth.mjs.map +1 -1
- package/dist/astro/middleware/media-usage-write-fence.mjs +4 -4
- package/dist/astro/middleware/redirect.d.mts.map +1 -1
- package/dist/astro/middleware/redirect.mjs +30 -15
- package/dist/astro/middleware/redirect.mjs.map +1 -1
- package/dist/astro/middleware/request-context.d.mts.map +1 -1
- package/dist/astro/middleware/request-context.mjs +71 -44
- package/dist/astro/middleware/request-context.mjs.map +1 -1
- package/dist/astro/middleware/setup.mjs +1 -1
- package/dist/astro/middleware.d.mts +12 -12
- package/dist/astro/middleware.d.mts.map +1 -1
- package/dist/astro/middleware.mjs +129 -107
- package/dist/astro/middleware.mjs.map +1 -1
- package/dist/astro/routes/api/admin/allowed-domains/_domain_.mjs +13 -13
- package/dist/astro/routes/api/admin/allowed-domains/index.mjs +13 -13
- package/dist/astro/routes/api/admin/api-tokens/_id_.mjs +6 -5
- package/dist/astro/routes/api/admin/api-tokens/_id_.mjs.map +1 -1
- package/dist/astro/routes/api/admin/api-tokens/index.mjs +7 -6
- package/dist/astro/routes/api/admin/api-tokens/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/byline-fields/_slug_/usage.mjs +5 -5
- package/dist/astro/routes/api/admin/byline-fields/_slug_.mjs +15 -15
- package/dist/astro/routes/api/admin/byline-fields/index.mjs +15 -15
- package/dist/astro/routes/api/admin/byline-fields/reorder.mjs +15 -15
- package/dist/astro/routes/api/admin/bylines/_id_/index.mjs +20 -20
- package/dist/astro/routes/api/admin/bylines/_id_/translations.mjs +20 -20
- package/dist/astro/routes/api/admin/bylines/index.mjs +20 -20
- package/dist/astro/routes/api/admin/comments/_id_/status.mjs +17 -17
- package/dist/astro/routes/api/admin/comments/_id_.mjs +6 -6
- package/dist/astro/routes/api/admin/comments/bulk.mjs +16 -16
- package/dist/astro/routes/api/admin/comments/counts.mjs +6 -6
- package/dist/astro/routes/api/admin/comments/index.mjs +16 -16
- package/dist/astro/routes/api/admin/core-update.mjs +6 -6
- package/dist/astro/routes/api/admin/hooks/exclusive/_hookName_.mjs +5 -5
- package/dist/astro/routes/api/admin/hooks/exclusive/index.mjs +4 -4
- package/dist/astro/routes/api/admin/media-usage/activation.mjs +17 -17
- package/dist/astro/routes/api/admin/media-usage/collection-deletions/index.mjs +19 -19
- package/dist/astro/routes/api/admin/media-usage/collection-deletions/retry.mjs +19 -19
- package/dist/astro/routes/api/admin/media-usage/progress.mjs +16 -16
- package/dist/astro/routes/api/admin/media-usage/repair.mjs +22 -22
- package/dist/astro/routes/api/admin/media-usage/work/index.mjs +19 -19
- package/dist/astro/routes/api/admin/media-usage/work/retry.mjs +19 -19
- package/dist/astro/routes/api/admin/oauth-clients/_id_.mjs +5 -5
- package/dist/astro/routes/api/admin/oauth-clients/index.mjs +5 -5
- package/dist/astro/routes/api/admin/plugins/_id_/disable.mjs +7 -7
- package/dist/astro/routes/api/admin/plugins/_id_/enable.mjs +7 -7
- package/dist/astro/routes/api/admin/plugins/_id_/index.mjs +63 -63
- package/dist/astro/routes/api/admin/plugins/_id_/mcp.mjs +6 -6
- package/dist/astro/routes/api/admin/plugins/_id_/settings.mjs +62 -62
- package/dist/astro/routes/api/admin/plugins/_id_/uninstall.mjs +63 -63
- package/dist/astro/routes/api/admin/plugins/_id_/update.mjs +72 -72
- package/dist/astro/routes/api/admin/plugins/index.mjs +63 -63
- package/dist/astro/routes/api/admin/plugins/marketplace/_id_/icon.mjs +6 -6
- package/dist/astro/routes/api/admin/plugins/marketplace/_id_/index.mjs +62 -62
- package/dist/astro/routes/api/admin/plugins/marketplace/_id_/install.mjs +71 -71
- package/dist/astro/routes/api/admin/plugins/marketplace/index.mjs +62 -62
- package/dist/astro/routes/api/admin/plugins/registry/_id_/uninstall.mjs +63 -63
- package/dist/astro/routes/api/admin/plugins/registry/_id_/update.mjs +73 -73
- package/dist/astro/routes/api/admin/plugins/registry/artifact.mjs +8 -8
- package/dist/astro/routes/api/admin/plugins/registry/install.mjs +65 -65
- package/dist/astro/routes/api/admin/plugins/registry/publisher-handle.mjs +6 -6
- package/dist/astro/routes/api/admin/plugins/registry/verify.mjs +63 -63
- package/dist/astro/routes/api/admin/plugins/updates.mjs +62 -62
- package/dist/astro/routes/api/admin/scheduled-policy-rejections/_collection_/_id_.mjs +4 -4
- package/dist/astro/routes/api/admin/themes/marketplace/_id_/index.mjs +62 -62
- package/dist/astro/routes/api/admin/themes/marketplace/_id_/thumbnail.mjs +6 -6
- package/dist/astro/routes/api/admin/themes/marketplace/index.mjs +62 -62
- package/dist/astro/routes/api/admin/transfer/_...path_.mjs +3 -3
- package/dist/astro/routes/api/admin/transfer/approvals/_id_/approve.mjs +30 -30
- package/dist/astro/routes/api/admin/transfer/approvals/_id_/deny.mjs +30 -30
- package/dist/astro/routes/api/admin/transfer/approvals/index.mjs +32 -32
- package/dist/astro/routes/api/admin/transfer/capabilities.mjs +32 -32
- package/dist/astro/routes/api/admin/transfer/exports/_id_/advance.mjs +32 -32
- package/dist/astro/routes/api/admin/transfer/exports/_id_/archive.mjs +33 -33
- package/dist/astro/routes/api/admin/transfer/exports/_id_/files/_...path_.mjs +33 -33
- package/dist/astro/routes/api/admin/transfer/exports/_id_/index.mjs +32 -32
- package/dist/astro/routes/api/admin/transfer/exports/_id_/manifest.mjs +33 -33
- package/dist/astro/routes/api/admin/transfer/exports/index.mjs +34 -34
- package/dist/astro/routes/api/admin/transfer/imports/_id_/abandon.mjs +32 -32
- package/dist/astro/routes/api/admin/transfer/imports/_id_/advance.mjs +32 -32
- package/dist/astro/routes/api/admin/transfer/imports/_id_/analyze.mjs +34 -34
- package/dist/astro/routes/api/admin/transfer/imports/_id_/cancel.mjs +32 -32
- package/dist/astro/routes/api/admin/transfer/imports/_id_/execute.mjs +34 -34
- package/dist/astro/routes/api/admin/transfer/imports/_id_/files/_...path_.mjs +32 -32
- package/dist/astro/routes/api/admin/transfer/imports/_id_/index.mjs +32 -32
- package/dist/astro/routes/api/admin/transfer/imports/_id_/missing.mjs +34 -34
- package/dist/astro/routes/api/admin/transfer/imports/_id_/plan.mjs +32 -32
- package/dist/astro/routes/api/admin/transfer/imports/_id_/receipt.mjs +32 -32
- package/dist/astro/routes/api/admin/transfer/imports/index.mjs +34 -34
- package/dist/astro/routes/api/admin/users/_id_/disable.mjs +3 -3
- package/dist/astro/routes/api/admin/users/_id_/enable.mjs +3 -3
- package/dist/astro/routes/api/admin/users/_id_/index.mjs +13 -13
- package/dist/astro/routes/api/admin/users/_id_/send-recovery.mjs +5 -5
- package/dist/astro/routes/api/admin/users/index.mjs +13 -13
- package/dist/astro/routes/api/auth/dev-bypass.mjs +5 -5
- package/dist/astro/routes/api/auth/handover.d.mts +8 -0
- package/dist/astro/routes/api/auth/handover.d.mts.map +1 -0
- package/dist/astro/routes/api/auth/handover.mjs +49 -0
- package/dist/astro/routes/api/auth/handover.mjs.map +1 -0
- package/dist/astro/routes/api/auth/invite/accept.mjs +3 -3
- package/dist/astro/routes/api/auth/invite/complete.mjs +18 -18
- package/dist/astro/routes/api/auth/invite/index.mjs +15 -15
- package/dist/astro/routes/api/auth/invite/register-options.mjs +16 -16
- package/dist/astro/routes/api/auth/logout.mjs +4 -4
- package/dist/astro/routes/api/auth/magic-link/send.mjs +18 -17
- package/dist/astro/routes/api/auth/magic-link/send.mjs.map +1 -1
- package/dist/astro/routes/api/auth/magic-link/verify.d.mts.map +1 -1
- package/dist/astro/routes/api/auth/magic-link/verify.mjs +22 -16
- package/dist/astro/routes/api/auth/magic-link/verify.mjs.map +1 -1
- package/dist/astro/routes/api/auth/me.mjs +14 -14
- package/dist/astro/routes/api/auth/mode.mjs +4 -4
- package/dist/astro/routes/api/auth/oauth/_provider_/callback.mjs +7 -7
- package/dist/astro/routes/api/auth/oauth/_provider_.mjs +2 -2
- package/dist/astro/routes/api/auth/passkey/_id_.mjs +13 -13
- package/dist/astro/routes/api/auth/passkey/index.mjs +3 -3
- package/dist/astro/routes/api/auth/passkey/options.d.mts.map +1 -1
- package/dist/astro/routes/api/auth/passkey/options.mjs +26 -19
- package/dist/astro/routes/api/auth/passkey/options.mjs.map +1 -1
- package/dist/astro/routes/api/auth/passkey/register/options.mjs +16 -16
- package/dist/astro/routes/api/auth/passkey/register/verify.mjs +17 -17
- package/dist/astro/routes/api/auth/passkey/verify.mjs +18 -18
- package/dist/astro/routes/api/auth/signup/complete.mjs +18 -18
- package/dist/astro/routes/api/auth/signup/request.mjs +17 -16
- package/dist/astro/routes/api/auth/signup/request.mjs.map +1 -1
- package/dist/astro/routes/api/auth/signup/verify.mjs +3 -3
- package/dist/astro/routes/api/calendar.mjs +14 -14
- package/dist/astro/routes/api/comments/_collection_/_contentId_/index.mjs +11 -11
- package/dist/astro/routes/api/comments/_collection_/_contentId_/reactions.mjs +17 -17
- package/dist/astro/routes/api/content/_collection_/_id_/compare.mjs +4 -4
- package/dist/astro/routes/api/content/_collection_/_id_/discard-draft.mjs +15 -15
- package/dist/astro/routes/api/content/_collection_/_id_/duplicate.mjs +4 -4
- package/dist/astro/routes/api/content/_collection_/_id_/lock.mjs +15 -15
- package/dist/astro/routes/api/content/_collection_/_id_/permanent.mjs +4 -4
- package/dist/astro/routes/api/content/_collection_/_id_/plugin-extensions/_pluginId_/_kind_/_extensionId_.mjs +8 -8
- package/dist/astro/routes/api/content/_collection_/_id_/preview-url.mjs +23 -23
- package/dist/astro/routes/api/content/_collection_/_id_/publish.mjs +15 -15
- package/dist/astro/routes/api/content/_collection_/_id_/references/_relation_/children.mjs +27 -27
- package/dist/astro/routes/api/content/_collection_/_id_/references/_relation_/parents.mjs +27 -27
- package/dist/astro/routes/api/content/_collection_/_id_/restore.mjs +4 -4
- package/dist/astro/routes/api/content/_collection_/_id_/revisions.mjs +4 -4
- package/dist/astro/routes/api/content/_collection_/_id_/schedule.mjs +15 -15
- package/dist/astro/routes/api/content/_collection_/_id_/terms/_taxonomy_.mjs +20 -20
- package/dist/astro/routes/api/content/_collection_/_id_/translations.mjs +4 -4
- package/dist/astro/routes/api/content/_collection_/_id_/unpublish.mjs +15 -15
- package/dist/astro/routes/api/content/_collection_/_id_.mjs +15 -15
- package/dist/astro/routes/api/content/_collection_/authors.mjs +4 -4
- package/dist/astro/routes/api/content/_collection_/index.mjs +14 -14
- package/dist/astro/routes/api/content/_collection_/trash.mjs +14 -14
- package/dist/astro/routes/api/dashboard.mjs +9 -9
- package/dist/astro/routes/api/dev/emails.mjs +4 -4
- package/dist/astro/routes/api/health.mjs +5 -5
- package/dist/astro/routes/api/import/probe.d.mts +3 -3
- package/dist/astro/routes/api/import/probe.mjs +22 -22
- package/dist/astro/routes/api/import/wordpress/analyze.mjs +4 -4
- package/dist/astro/routes/api/import/wordpress/execute.d.mts +13 -13
- package/dist/astro/routes/api/import/wordpress/execute.mjs +28 -21
- package/dist/astro/routes/api/import/wordpress/execute.mjs.map +1 -1
- package/dist/astro/routes/api/import/wordpress/media.d.mts +12 -12
- package/dist/astro/routes/api/import/wordpress/media.mjs +16 -16
- package/dist/astro/routes/api/import/wordpress/prepare.mjs +16 -16
- package/dist/astro/routes/api/import/wordpress/rewrite-url-helpers.d.mts +8 -0
- package/dist/astro/routes/api/import/wordpress/rewrite-url-helpers.d.mts.map +1 -1
- package/dist/astro/routes/api/import/wordpress/rewrite-url-helpers.mjs +67 -31
- package/dist/astro/routes/api/import/wordpress/rewrite-url-helpers.mjs.map +1 -1
- package/dist/astro/routes/api/import/wordpress/rewrite-urls.d.mts +13 -13
- package/dist/astro/routes/api/import/wordpress/rewrite-urls.mjs +20 -20
- package/dist/astro/routes/api/import/wordpress-plugin/analyze.d.mts +1 -1
- package/dist/astro/routes/api/import/wordpress-plugin/analyze.mjs +22 -22
- package/dist/astro/routes/api/import/wordpress-plugin/execute.d.mts +13 -13
- package/dist/astro/routes/api/import/wordpress-plugin/execute.mjs +35 -28
- package/dist/astro/routes/api/import/wordpress-plugin/execute.mjs.map +1 -1
- package/dist/astro/routes/api/manifest.mjs +8 -5
- package/dist/astro/routes/api/manifest.mjs.map +1 -1
- package/dist/astro/routes/api/mcp.mjs +81 -81
- package/dist/astro/routes/api/media/_id_/confirm.d.mts.map +1 -1
- package/dist/astro/routes/api/media/_id_/confirm.mjs +32 -16
- package/dist/astro/routes/api/media/_id_/confirm.mjs.map +1 -1
- package/dist/astro/routes/api/media/_id_/replace.mjs +13 -13
- package/dist/astro/routes/api/media/_id_/upload.mjs +6 -6
- package/dist/astro/routes/api/media/_id_/usage.mjs +24 -24
- package/dist/astro/routes/api/media/_id_.mjs +22 -22
- package/dist/astro/routes/api/media/asset/_id_/_filename_.mjs +5 -5
- package/dist/astro/routes/api/media/file/_...key_.d.mts.map +1 -1
- package/dist/astro/routes/api/media/file/_...key_.mjs +44 -14
- package/dist/astro/routes/api/media/file/_...key_.mjs.map +1 -1
- package/dist/astro/routes/api/media/folders/_id_.mjs +15 -15
- package/dist/astro/routes/api/media/folders/index.mjs +15 -15
- package/dist/astro/routes/api/media/providers/_providerId_/_itemId_.mjs +4 -4
- package/dist/astro/routes/api/media/providers/_providerId_/index.mjs +4 -4
- package/dist/astro/routes/api/media/providers/index.mjs +4 -4
- package/dist/astro/routes/api/media/upload-url.mjs +39 -19
- package/dist/astro/routes/api/media/upload-url.mjs.map +1 -1
- package/dist/astro/routes/api/media.d.mts.map +1 -1
- package/dist/astro/routes/api/media.mjs +33 -23
- package/dist/astro/routes/api/media.mjs.map +1 -1
- package/dist/astro/routes/api/menus/_name_/items/_id_.mjs +15 -15
- package/dist/astro/routes/api/menus/_name_/items.mjs +15 -15
- package/dist/astro/routes/api/menus/_name_/reorder.mjs +15 -15
- package/dist/astro/routes/api/menus/_name_/translations.mjs +15 -15
- package/dist/astro/routes/api/menus/_name_.mjs +15 -15
- package/dist/astro/routes/api/menus/index.mjs +15 -15
- package/dist/astro/routes/api/oauth/authorize.mjs +6 -6
- package/dist/astro/routes/api/oauth/device/authorize.mjs +7 -7
- package/dist/astro/routes/api/oauth/device/code.mjs +11 -10
- package/dist/astro/routes/api/oauth/device/code.mjs.map +1 -1
- package/dist/astro/routes/api/oauth/device/token.mjs +10 -9
- package/dist/astro/routes/api/oauth/device/token.mjs.map +1 -1
- package/dist/astro/routes/api/oauth/register.mjs +7 -6
- package/dist/astro/routes/api/oauth/register.mjs.map +1 -1
- package/dist/astro/routes/api/oauth/token/refresh.mjs +7 -7
- package/dist/astro/routes/api/oauth/token/revoke.mjs +7 -7
- package/dist/astro/routes/api/oauth/token.mjs +7 -7
- package/dist/astro/routes/api/openapi.json.mjs +21 -21
- package/dist/astro/routes/api/openapi.json.mjs.map +1 -1
- package/dist/astro/routes/api/plugins/_pluginId_/_...path_.mjs +8 -8
- package/dist/astro/routes/api/redirects/404s/index.mjs +18 -18
- package/dist/astro/routes/api/redirects/404s/summary.mjs +18 -18
- package/dist/astro/routes/api/redirects/_id_.mjs +18 -18
- package/dist/astro/routes/api/redirects/index.mjs +18 -18
- package/dist/astro/routes/api/relations/_id_/index.mjs +27 -27
- package/dist/astro/routes/api/relations/index.mjs +27 -27
- package/dist/astro/routes/api/revisions/_revisionId_/index.mjs +4 -4
- package/dist/astro/routes/api/revisions/_revisionId_/restore.mjs +15 -15
- package/dist/astro/routes/api/schema/block-types/_slug_/index.mjs +62 -62
- package/dist/astro/routes/api/schema/block-types/_slug_/versions/_version_/activate.mjs +62 -62
- package/dist/astro/routes/api/schema/block-types/index.mjs +62 -62
- package/dist/astro/routes/api/schema/collections/_slug_/fields/_fieldSlug_.mjs +62 -62
- package/dist/astro/routes/api/schema/collections/_slug_/fields/index.mjs +62 -62
- package/dist/astro/routes/api/schema/collections/_slug_/fields/reorder.mjs +62 -62
- package/dist/astro/routes/api/schema/collections/_slug_/index.mjs +62 -62
- package/dist/astro/routes/api/schema/collections/index.mjs +62 -62
- package/dist/astro/routes/api/schema/collections/reorder.mjs +62 -62
- package/dist/astro/routes/api/schema/index.mjs +10 -10
- package/dist/astro/routes/api/schema/index.mjs.map +1 -1
- package/dist/astro/routes/api/schema/orphans/_slug_.mjs +62 -62
- package/dist/astro/routes/api/schema/orphans/index.mjs +62 -62
- package/dist/astro/routes/api/search/enable.mjs +17 -17
- package/dist/astro/routes/api/search/index.mjs +16 -16
- package/dist/astro/routes/api/search/rebuild.mjs +17 -17
- package/dist/astro/routes/api/search/stats.mjs +7 -7
- package/dist/astro/routes/api/search/suggest.mjs +16 -16
- package/dist/astro/routes/api/sections/_slug_.mjs +16 -16
- package/dist/astro/routes/api/sections/index.mjs +16 -16
- package/dist/astro/routes/api/settings/backups/archives/_name_.mjs +6 -6
- package/dist/astro/routes/api/settings/backups/archives/index.mjs +6 -6
- package/dist/astro/routes/api/settings/backups/export.mjs +6 -6
- package/dist/astro/routes/api/settings/backups/index.mjs +7 -7
- package/dist/astro/routes/api/settings/domain-notify.d.mts +8 -0
- package/dist/astro/routes/api/settings/domain-notify.d.mts.map +1 -0
- package/dist/astro/routes/api/settings/domain-notify.mjs +125 -0
- package/dist/astro/routes/api/settings/domain-notify.mjs.map +1 -0
- package/dist/astro/routes/api/settings/domain.d.mts +9 -0
- package/dist/astro/routes/api/settings/domain.d.mts.map +1 -0
- package/dist/astro/routes/api/settings/domain.mjs +61 -0
- package/dist/astro/routes/api/settings/domain.mjs.map +1 -0
- package/dist/astro/routes/api/settings/email.mjs +5 -5
- package/dist/astro/routes/api/settings.mjs +18 -18
- package/dist/astro/routes/api/setup/admin-verify.mjs +19 -19
- package/dist/astro/routes/api/setup/admin.mjs +17 -17
- package/dist/astro/routes/api/setup/dev-bypass.mjs +34 -34
- package/dist/astro/routes/api/setup/dev-reset.mjs +3 -3
- package/dist/astro/routes/api/setup/index.d.mts.map +1 -1
- package/dist/astro/routes/api/setup/index.mjs +44 -40
- package/dist/astro/routes/api/setup/index.mjs.map +1 -1
- package/dist/astro/routes/api/setup/status.mjs +5 -5
- package/dist/astro/routes/api/site/domain-proof.d.mts +8 -0
- package/dist/astro/routes/api/site/domain-proof.d.mts.map +1 -0
- package/dist/astro/routes/api/site/domain-proof.mjs +33 -0
- package/dist/astro/routes/api/site/domain-proof.mjs.map +1 -0
- package/dist/astro/routes/api/snapshot.mjs +7 -7
- package/dist/astro/routes/api/taxonomies/_name_/reorder.mjs +19 -19
- package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_/translations.mjs +19 -19
- package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_.mjs +19 -19
- package/dist/astro/routes/api/taxonomies/_name_/terms/index.mjs +19 -19
- package/dist/astro/routes/api/taxonomies/_name_/translations.mjs +19 -19
- package/dist/astro/routes/api/taxonomies/_name_.mjs +19 -19
- package/dist/astro/routes/api/taxonomies/bulk-tag.mjs +27 -27
- package/dist/astro/routes/api/taxonomies/index.mjs +19 -19
- package/dist/astro/routes/api/themes/preview.mjs +5 -5
- package/dist/astro/routes/api/typegen.mjs +5 -5
- package/dist/astro/routes/api/visual-editing/action-token.mjs +5 -5
- package/dist/astro/routes/api/visual-editing/content/_collection_/_id_/publish.mjs +17 -17
- package/dist/astro/routes/api/visual-editing/toolbar-labels.mjs +3 -3
- 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 +14 -14
- package/dist/astro/routes/api/widget-areas/_name_/widgets/_id_.mjs +16 -16
- package/dist/astro/routes/api/widget-areas/_name_/widgets.mjs +16 -16
- package/dist/astro/routes/api/widget-areas/_name_.mjs +6 -6
- package/dist/astro/routes/api/widget-areas/index.mjs +16 -16
- package/dist/astro/routes/api/widget-components.mjs +4 -4
- package/dist/astro/routes/robots.txt.mjs +4 -4
- package/dist/astro/routes/sitemap-_collection_.xml.d.mts.map +1 -1
- package/dist/astro/routes/sitemap-_collection_.xml.mjs +27 -10
- package/dist/astro/routes/sitemap-_collection_.xml.mjs.map +1 -1
- package/dist/astro/routes/sitemap.xml.d.mts.map +1 -1
- package/dist/astro/routes/sitemap.xml.mjs +11 -10
- package/dist/astro/routes/sitemap.xml.mjs.map +1 -1
- package/dist/astro/types.d.mts +30 -18
- package/dist/astro/types.d.mts.map +1 -1
- package/dist/auth/providers/github.d.mts +1 -1
- package/dist/auth/providers/google.d.mts +1 -1
- package/dist/auth/providers/microsoft.d.mts +1 -1
- package/dist/authoritative-records-Dcs7l2H5.mjs +5183 -0
- package/dist/authoritative-records-Dcs7l2H5.mjs.map +1 -0
- package/dist/authorize-TdIGpRSE.mjs +49 -0
- package/dist/authorize-TdIGpRSE.mjs.map +1 -0
- package/dist/backup-CZt5Mzwx.mjs +246 -0
- package/dist/backup-CZt5Mzwx.mjs.map +1 -0
- package/dist/block-types-DHnkzE6u.mjs +132 -0
- package/dist/block-types-DHnkzE6u.mjs.map +1 -0
- package/dist/block-values-C4N_F2-G.mjs +175 -0
- package/dist/block-values-C4N_F2-G.mjs.map +1 -0
- package/dist/byline-BmVKOQ8l.mjs +909 -0
- package/dist/byline-BmVKOQ8l.mjs.map +1 -0
- package/dist/byline-fields-B8SDs3M_.mjs +123 -0
- package/dist/byline-fields-B8SDs3M_.mjs.map +1 -0
- package/dist/byline-fields-Bze3ZdAw.mjs +280 -0
- package/dist/byline-fields-Bze3ZdAw.mjs.map +1 -0
- package/dist/bylines-CHhR28r9.mjs +150 -0
- package/dist/bylines-CHhR28r9.mjs.map +1 -0
- package/dist/bylines-DZS4OflA.mjs +234 -0
- package/dist/bylines-DZS4OflA.mjs.map +1 -0
- package/dist/cache-x0z8t_m9.mjs +133 -0
- package/dist/cache-x0z8t_m9.mjs.map +1 -0
- package/dist/canonical-BUcKRYpG.mjs +174 -0
- package/dist/canonical-BUcKRYpG.mjs.map +1 -0
- package/dist/challenge-store-BHgdPVze.mjs +51 -0
- package/dist/challenge-store-BHgdPVze.mjs.map +1 -0
- package/dist/checksum-BYR5i7qe.mjs +162 -0
- package/dist/checksum-BYR5i7qe.mjs.map +1 -0
- package/dist/chunks-Dr5Vr0zA.mjs +25 -0
- package/dist/chunks-Dr5Vr0zA.mjs.map +1 -0
- package/dist/cli/index.mjs +44 -42
- package/dist/cli/index.mjs.map +1 -1
- package/dist/client/cf-access.d.mts +1 -1
- package/dist/client/index.d.mts +107 -107
- package/dist/client/index.d.mts.map +1 -1
- package/dist/client/index.mjs +2 -2
- package/dist/client/index.mjs.map +1 -1
- package/dist/comment-CWla6OHV.mjs +325 -0
- package/dist/comment-CWla6OHV.mjs.map +1 -0
- package/dist/comment-reaction-RZrcs5cW.mjs +85 -0
- package/dist/comment-reaction-RZrcs5cW.mjs.map +1 -0
- package/dist/comments-BzmIKVb2.mjs +99 -0
- package/dist/comments-BzmIKVb2.mjs.map +1 -0
- package/dist/comments-Da_dI2O1.mjs +195 -0
- package/dist/comments-Da_dI2O1.mjs.map +1 -0
- package/dist/components-oFXumpf5.mjs +112 -0
- package/dist/components-oFXumpf5.mjs.map +1 -0
- package/dist/config--wamYxBW.d.mts +39 -0
- package/dist/config--wamYxBW.d.mts.map +1 -0
- package/dist/config-Bo4eOOdV.mjs +228 -0
- package/dist/config-Bo4eOOdV.mjs.map +1 -0
- package/dist/config-C4-UxIk7.d.mts +6790 -0
- package/dist/config-C4-UxIk7.d.mts.map +1 -0
- package/dist/connection-UpzYxtE2.mjs +36 -0
- package/dist/connection-UpzYxtE2.mjs.map +1 -0
- package/dist/content-CcHrqkgp.mjs +2072 -0
- package/dist/content-CcHrqkgp.mjs.map +1 -0
- package/dist/content-list-query-Bxxdd9fv.d.mts +26 -0
- package/dist/content-list-query-Bxxdd9fv.d.mts.map +1 -0
- package/dist/content-repair-havk1F0-.mjs +442 -0
- package/dist/content-repair-havk1F0-.mjs.map +1 -0
- package/dist/context-CvhgHgSH.mjs +2043 -0
- package/dist/context-CvhgHgSH.mjs.map +1 -0
- package/dist/credits-CygUrPOi.mjs +110 -0
- package/dist/credits-CygUrPOi.mjs.map +1 -0
- package/dist/cron-C6ytTOLw.mjs +306 -0
- package/dist/cron-C6ytTOLw.mjs.map +1 -0
- package/dist/dashboard-7_FYfafc.mjs +151 -0
- package/dist/dashboard-7_FYfafc.mjs.map +1 -0
- package/dist/db/index.d.mts +3 -3
- package/dist/db/index.mjs +1 -1
- package/dist/db/libsql-migrations.d.mts +1 -1
- package/dist/db/libsql-migrations.mjs +4 -4
- package/dist/db/libsql.d.mts +1 -1
- package/dist/db/postgres-migrations.d.mts +1 -1
- package/dist/db/postgres-migrations.mjs +4 -4
- package/dist/db/postgres.d.mts +1 -1
- package/dist/db/sqlite-migrations.d.mts +1 -1
- package/dist/db/sqlite-migrations.mjs +4 -4
- package/dist/db/sqlite.d.mts +1 -1
- package/dist/db/sqlite.mjs +1 -1
- package/dist/default-CHCUkV4Z.mjs +81 -0
- package/dist/default-CHCUkV4Z.mjs.map +1 -0
- package/dist/deferred-tasks-G0xhcJTl.d.mts +9 -0
- package/dist/deferred-tasks-G0xhcJTl.d.mts.map +1 -0
- package/dist/device-flow-CzDJmQ1q.mjs +521 -0
- package/dist/device-flow-CzDJmQ1q.mjs.map +1 -0
- package/dist/digest-xJmyPv2r.mjs +194 -0
- package/dist/digest-xJmyPv2r.mjs.map +1 -0
- package/dist/direct-executor-BXiYIVJ9.mjs +104 -0
- package/dist/direct-executor-BXiYIVJ9.mjs.map +1 -0
- package/dist/email-console-7ZPApLlm.mjs +50 -0
- package/dist/email-console-7ZPApLlm.mjs.map +1 -0
- package/dist/email-locale-DFdUA6UF.mjs +25 -0
- package/dist/email-locale-DFdUA6UF.mjs.map +1 -0
- package/dist/emdash-runtime-C4oFeVpN.mjs +4363 -0
- package/dist/emdash-runtime-C4oFeVpN.mjs.map +1 -0
- package/dist/entry-lock-B4n0HdQ_.mjs +163 -0
- package/dist/entry-lock-B4n0HdQ_.mjs.map +1 -0
- package/dist/entry-lock-BAAlKYrz.d.mts +4566 -0
- package/dist/entry-lock-BAAlKYrz.d.mts.map +1 -0
- package/dist/entry-lock-Cjz0h45X.mjs +1209 -0
- package/dist/entry-lock-Cjz0h45X.mjs.map +1 -0
- package/dist/env-types-4bkF6Bqg.mjs +38 -0
- package/dist/env-types-4bkF6Bqg.mjs.map +1 -0
- package/dist/error-DxgQdaZ_.mjs +90 -0
- package/dist/error-DxgQdaZ_.mjs.map +1 -0
- package/dist/errors-CjtE5aWF.mjs +120 -0
- package/dist/errors-CjtE5aWF.mjs.map +1 -0
- package/dist/errors-hskQ0C8G.mjs +479 -0
- package/dist/errors-hskQ0C8G.mjs.map +1 -0
- package/dist/escape-ESFhYzwG.mjs +9 -0
- package/dist/escape-ESFhYzwG.mjs.map +1 -0
- package/dist/fence-vc3aHgRA.mjs +162 -0
- package/dist/fence-vc3aHgRA.mjs.map +1 -0
- package/dist/field-defs-cache-zoow36nz.mjs +77 -0
- package/dist/field-defs-cache-zoow36nz.mjs.map +1 -0
- package/dist/field-map-JD1wG0Tq.mjs +83 -0
- package/dist/field-map-JD1wG0Tq.mjs.map +1 -0
- package/dist/fts-manager-WJCN8uU6.mjs +443 -0
- package/dist/fts-manager-WJCN8uU6.mjs.map +1 -0
- package/dist/gc-CsGZiKdH.mjs +75 -0
- package/dist/gc-CsGZiKdH.mjs.map +1 -0
- package/dist/hook-result-CXjtMk7Q.d.mts +31 -0
- package/dist/hook-result-CXjtMk7Q.d.mts.map +1 -0
- package/dist/hreflang-BAma7iRr.mjs +105 -0
- package/dist/hreflang-BAma7iRr.mjs.map +1 -0
- package/dist/hreflang-BsYo4x_M.d.mts +50 -0
- package/dist/hreflang-BsYo4x_M.d.mts.map +1 -0
- package/dist/http-route-dispatch-C8G7hAK6.mjs +342 -0
- package/dist/http-route-dispatch-C8G7hAK6.mjs.map +1 -0
- package/dist/identity-BwBKM1fH.mjs +35 -0
- package/dist/identity-BwBKM1fH.mjs.map +1 -0
- package/dist/import-DJ3Z2wxE.mjs +2021 -0
- package/dist/import-DJ3Z2wxE.mjs.map +1 -0
- package/dist/index-DYsn97dY.d.mts +623 -0
- package/dist/index-DYsn97dY.d.mts.map +1 -0
- package/dist/index.d.mts +24 -24
- package/dist/index.mjs +87 -87
- package/dist/install-finalization-DCFnFSHv.mjs +58 -0
- package/dist/install-finalization-DCFnFSHv.mjs.map +1 -0
- package/dist/keys-CGvAndSp.mjs +61 -0
- package/dist/keys-CGvAndSp.mjs.map +1 -0
- package/dist/kinds-DT1W4T4Y.mjs +974 -0
- package/dist/kinds-DT1W4T4Y.mjs.map +1 -0
- package/dist/lifecycle-BzglCSY0.mjs +25 -0
- package/dist/lifecycle-BzglCSY0.mjs.map +1 -0
- package/dist/load-DjUqmf3s.mjs +28 -0
- package/dist/load-DjUqmf3s.mjs.map +1 -0
- package/dist/loader-CetY659y.mjs +1355 -0
- package/dist/loader-CetY659y.mjs.map +1 -0
- package/dist/loops-DkT1zkPH.mjs +205 -0
- package/dist/loops-DkT1zkPH.mjs.map +1 -0
- package/dist/manifest-builder-BOFCd9rX.mjs +189 -0
- package/dist/manifest-builder-BOFCd9rX.mjs.map +1 -0
- package/dist/manifest-schema-BiFBPEsp.mjs +497 -0
- package/dist/manifest-schema-BiFBPEsp.mjs.map +1 -0
- package/dist/marketplace-CUlenvZm.mjs +257 -0
- package/dist/marketplace-CUlenvZm.mjs.map +1 -0
- package/dist/media/image-endpoint.d.mts +26 -2
- package/dist/media/image-endpoint.d.mts.map +1 -1
- package/dist/media/image-endpoint.mjs +73 -3
- package/dist/media/image-endpoint.mjs.map +1 -1
- package/dist/media/index.d.mts +1 -1
- package/dist/media/local-runtime.d.mts +14 -14
- package/dist/media/local-runtime.mjs +4 -4
- package/dist/media-CRKsKlfK.mjs +416 -0
- package/dist/media-CRKsKlfK.mjs.map +1 -0
- package/dist/media-C_z7sRuC.mjs +294 -0
- package/dist/media-C_z7sRuC.mjs.map +1 -0
- package/dist/media-IT8hQleU.mjs +373 -0
- package/dist/media-IT8hQleU.mjs.map +1 -0
- package/dist/media-allowlist-Ct6wvnT2.mjs +45 -0
- package/dist/media-allowlist-Ct6wvnT2.mjs.map +1 -0
- package/dist/media-folders-DtMt-vAA.mjs +210 -0
- package/dist/media-folders-DtMt-vAA.mjs.map +1 -0
- package/dist/media-url-BpXLqCmf.mjs +43 -0
- package/dist/media-url-BpXLqCmf.mjs.map +1 -0
- package/dist/media-usage-DEPHZZ9X.mjs +282 -0
- package/dist/media-usage-DEPHZZ9X.mjs.map +1 -0
- package/dist/media-usage-activation-V2Siabtw.mjs +78 -0
- package/dist/media-usage-activation-V2Siabtw.mjs.map +1 -0
- package/dist/media-usage-work-Cv1OE59F.mjs +151 -0
- package/dist/media-usage-work-Cv1OE59F.mjs.map +1 -0
- package/dist/media-usage-work-cgDYGvrt.mjs +1015 -0
- package/dist/media-usage-work-cgDYGvrt.mjs.map +1 -0
- package/dist/menus-CvVYfsuk.mjs +753 -0
- package/dist/menus-CvVYfsuk.mjs.map +1 -0
- package/dist/menus-D1HC8npj.mjs +92 -0
- package/dist/menus-D1HC8npj.mjs.map +1 -0
- package/dist/menus-DL8IPIcm.mjs +3721 -0
- package/dist/menus-DL8IPIcm.mjs.map +1 -0
- package/dist/migrations/index.d.mts +1 -1
- package/dist/migrations/index.mjs +3 -3
- package/dist/mode-eieqAWLe.mjs +23 -0
- package/dist/mode-eieqAWLe.mjs.map +1 -0
- package/dist/node-sqlite-compat-VuyzJw1b.mjs +63 -0
- package/dist/node-sqlite-compat-VuyzJw1b.mjs.map +1 -0
- package/dist/oauth-authorization-B6ZJbMd2.mjs +274 -0
- package/dist/oauth-authorization-B6ZJbMd2.mjs.map +1 -0
- package/dist/oauth-clients-DVjRc9v3.mjs +266 -0
- package/dist/oauth-clients-DVjRc9v3.mjs.map +1 -0
- package/dist/oauth-state-store-CnmYYsVQ.mjs +50 -0
- package/dist/oauth-state-store-CnmYYsVQ.mjs.map +1 -0
- package/dist/oauth-user-lookup-Dz1_R5vT.mjs +26 -0
- package/dist/oauth-user-lookup-Dz1_R5vT.mjs.map +1 -0
- package/dist/object-cache/memory.d.mts +1 -1
- package/dist/options-BR9XZl7h.d.mts +81 -0
- package/dist/options-BR9XZl7h.d.mts.map +1 -0
- package/dist/ownership-COPyVysP.mjs +12 -0
- package/dist/ownership-COPyVysP.mjs.map +1 -0
- package/dist/page/index.d.mts +2 -2
- package/dist/page/index.mjs +3 -3
- package/dist/parse-BOGhrwSq.d.mts +174 -0
- package/dist/parse-BOGhrwSq.d.mts.map +1 -0
- package/dist/parse-Cn5aSk1N.mjs +81 -0
- package/dist/parse-Cn5aSk1N.mjs.map +1 -0
- package/dist/passkey-config-mMFRQUCj.mjs +46 -0
- package/dist/passkey-config-mMFRQUCj.mjs.map +1 -0
- package/dist/paths-BmcAdBo9.mjs +77 -0
- package/dist/paths-BmcAdBo9.mjs.map +1 -0
- package/dist/patterns-CMNnYCgf.mjs +159 -0
- package/dist/patterns-CMNnYCgf.mjs.map +1 -0
- package/dist/placeholder-nOep3_Gn.d.mts +306 -0
- package/dist/placeholder-nOep3_Gn.d.mts.map +1 -0
- package/dist/plan-CDY4K8CH.mjs +135 -0
- package/dist/plan-CDY4K8CH.mjs.map +1 -0
- package/dist/plugin-test-runtime.d.mts +14 -14
- package/dist/plugin-test-runtime.d.mts.map +1 -1
- package/dist/plugin-test-runtime.mjs +100 -100
- package/dist/plugin-types.d.mts +2 -2
- package/dist/plugin-utils.d.mts +12 -12
- package/dist/plugin-utils.mjs +1 -1
- package/dist/plugin-utils.mjs.map +1 -1
- package/dist/plugins/adapt-sandbox-entry.d.mts +12 -12
- package/dist/plugins/adapt-sandbox-entry.mjs +3 -3
- package/dist/plugins/host.d.mts +5 -5
- package/dist/plugins/host.mjs +35 -35
- package/dist/plugins-DFBpfbO3.mjs +261 -0
- package/dist/plugins-DFBpfbO3.mjs.map +1 -0
- package/dist/policy-B_2qnHSy.mjs +45 -0
- package/dist/policy-B_2qnHSy.mjs.map +1 -0
- package/dist/portable-text-Dc2YAusw.mjs +307 -0
- package/dist/portable-text-Dc2YAusw.mjs.map +1 -0
- package/dist/preview-BtzikJ9O.mjs +107 -0
- package/dist/preview-BtzikJ9O.mjs.map +1 -0
- package/dist/protocol-M268ox8L.d.mts +61 -0
- package/dist/protocol-M268ox8L.d.mts.map +1 -0
- package/dist/public-submission-BQZavgZU.mjs +251 -0
- package/dist/public-submission-BQZavgZU.mjs.map +1 -0
- package/dist/public-url-uT1Ok2Tu.mjs +101 -0
- package/dist/public-url-uT1Ok2Tu.mjs.map +1 -0
- package/dist/query-BGG3sDEd.mjs +1127 -0
- package/dist/query-BGG3sDEd.mjs.map +1 -0
- package/dist/query-C_CWlifp.mjs +41 -0
- package/dist/query-C_CWlifp.mjs.map +1 -0
- package/dist/range-CXK_kDbI.mjs +51 -0
- package/dist/range-CXK_kDbI.mjs.map +1 -0
- package/dist/rate-limit-Dvamvay-.mjs +127 -0
- package/dist/rate-limit-Dvamvay-.mjs.map +1 -0
- package/dist/receipt-BmQGzquP.mjs +43 -0
- package/dist/receipt-BmQGzquP.mjs.map +1 -0
- package/dist/redirect-B39kTQ_0.mjs +423 -0
- package/dist/redirect-B39kTQ_0.mjs.map +1 -0
- package/dist/redirect-BguJ00Pv.mjs +19 -0
- package/dist/redirect-BguJ00Pv.mjs.map +1 -0
- package/dist/redirects-C8G4BsfP.mjs +446 -0
- package/dist/redirects-C8G4BsfP.mjs.map +1 -0
- package/dist/redirects-DFT7Wr-e.mjs +148 -0
- package/dist/redirects-DFT7Wr-e.mjs.map +1 -0
- package/dist/registry/testing.mjs +3 -3
- package/dist/registry-DeZ27gVi.mjs +8374 -0
- package/dist/registry-DeZ27gVi.mjs.map +1 -0
- package/dist/relations-DBB1bRJW.mjs +776 -0
- package/dist/relations-DBB1bRJW.mjs.map +1 -0
- package/dist/request-context.d.mts +1 -1
- package/dist/request-meta-BSvkhIBX.mjs +141 -0
- package/dist/request-meta-BSvkhIBX.mjs.map +1 -0
- package/dist/resolve-BxH64HN9.mjs +100 -0
- package/dist/resolve-BxH64HN9.mjs.map +1 -0
- package/dist/route-wire-CwbWB_6O.mjs +197 -0
- package/dist/route-wire-CwbWB_6O.mjs.map +1 -0
- package/dist/routes-BfIxc7ft.mjs +272 -0
- package/dist/routes-BfIxc7ft.mjs.map +1 -0
- package/dist/runner-DkeafPBA.d.mts +68 -0
- package/dist/runner-DkeafPBA.d.mts.map +1 -0
- package/dist/runner-wqt4BrIW.mjs +6383 -0
- package/dist/runner-wqt4BrIW.mjs.map +1 -0
- package/dist/runtime.d.mts +13 -13
- package/dist/runtime.mjs +1 -1
- package/dist/schema/project-env-types.mjs +29 -29
- package/dist/schema-BXIW-JHi.mjs +815 -0
- package/dist/schema-BXIW-JHi.mjs.map +1 -0
- package/dist/schema-I74JwYte.mjs +13 -0
- package/dist/schema-I74JwYte.mjs.map +1 -0
- package/dist/scopes-RWZ5ft_Z.mjs +34 -0
- package/dist/scopes-RWZ5ft_Z.mjs.map +1 -0
- package/dist/search-DxwagyWS.mjs +450 -0
- package/dist/search-DxwagyWS.mjs.map +1 -0
- package/dist/sections-Ccq9ZgyD.mjs +346 -0
- package/dist/sections-Ccq9ZgyD.mjs.map +1 -0
- package/dist/seed/index.d.mts +2 -2
- package/dist/seed/index.mjs +27 -27
- package/dist/seo/index.d.mts +3 -3
- package/dist/seo/index.mjs +14 -14
- package/dist/seo-CCnfPWAQ.mjs +133 -0
- package/dist/seo-CCnfPWAQ.mjs.map +1 -0
- package/dist/seo-QCtJ1jjV.mjs +188 -0
- package/dist/seo-QCtJ1jjV.mjs.map +1 -0
- package/dist/service-DX84s2rw.mjs +150 -0
- package/dist/service-DX84s2rw.mjs.map +1 -0
- package/dist/session-user-1dtJc2zv.mjs +61 -0
- package/dist/session-user-1dtJc2zv.mjs.map +1 -0
- package/dist/settings-B1jOxAIl.mjs +443 -0
- package/dist/settings-B1jOxAIl.mjs.map +1 -0
- package/dist/settings-Bc1IBl1t.mjs +66 -0
- package/dist/settings-Bc1IBl1t.mjs.map +1 -0
- package/dist/settings-GaZ5sVgg.mjs +73 -0
- package/dist/settings-GaZ5sVgg.mjs.map +1 -0
- package/dist/setup-complete-DidMAWJS.mjs +65 -0
- package/dist/setup-complete-DidMAWJS.mjs.map +1 -0
- package/dist/setup-nonce-DKl4S4c6.mjs +25 -0
- package/dist/setup-nonce-DKl4S4c6.mjs.map +1 -0
- package/dist/site-domain-CbI51Pc2.mjs +113 -0
- package/dist/site-domain-CbI51Pc2.mjs.map +1 -0
- package/dist/site-settings-CDdT4mVm.mjs +50 -0
- package/dist/site-settings-CDdT4mVm.mjs.map +1 -0
- package/dist/site-url-CrDZaAvo.mjs +45 -0
- package/dist/site-url-CrDZaAvo.mjs.map +1 -0
- package/dist/sitemap-name-W3BTor6X.mjs +26 -0
- package/dist/sitemap-name-W3BTor6X.mjs.map +1 -0
- package/dist/slug-BJhHKoOH.mjs +16 -0
- package/dist/slug-BJhHKoOH.mjs.map +1 -0
- package/dist/slugify-bu2-jKia.mjs +22 -0
- package/dist/slugify-bu2-jKia.mjs.map +1 -0
- package/dist/snapshot-BuI_2uDe.mjs +414 -0
- package/dist/snapshot-BuI_2uDe.mjs.map +1 -0
- package/dist/ssrf-LM_0wpGA.mjs +406 -0
- package/dist/ssrf-LM_0wpGA.mjs.map +1 -0
- package/dist/stage-DhzZuYaT.mjs +662 -0
- package/dist/stage-DhzZuYaT.mjs.map +1 -0
- package/dist/staged-DboEaWsV.mjs +686 -0
- package/dist/staged-DboEaWsV.mjs.map +1 -0
- package/dist/state-DCXDzjHq.mjs +178 -0
- package/dist/state-DCXDzjHq.mjs.map +1 -0
- package/dist/status-Dl85BK39.mjs +30 -0
- package/dist/status-Dl85BK39.mjs.map +1 -0
- package/dist/storage/local.d.mts +2 -2
- package/dist/storage/local.d.mts.map +1 -1
- package/dist/storage/local.mjs +11 -4
- package/dist/storage/local.mjs.map +1 -1
- package/dist/storage/s3.d.mts +4 -2
- package/dist/storage/s3.d.mts.map +1 -1
- package/dist/storage/s3.mjs +56 -9
- package/dist/storage/s3.mjs.map +1 -1
- package/dist/storage-query-BOBmeDMD.d.mts +1615 -0
- package/dist/storage-query-BOBmeDMD.d.mts.map +1 -0
- package/dist/tar-K40edFMt.mjs +449 -0
- package/dist/tar-K40edFMt.mjs.map +1 -0
- package/dist/target-BOighEY1.mjs +27 -0
- package/dist/target-BOighEY1.mjs.map +1 -0
- package/dist/taxonomies-DQSywBvX.mjs +697 -0
- package/dist/taxonomies-DQSywBvX.mjs.map +1 -0
- package/dist/taxonomies-Dj5eaobC.mjs +939 -0
- package/dist/taxonomies-Dj5eaobC.mjs.map +1 -0
- package/dist/taxonomy-QrNmTfIZ.mjs +550 -0
- package/dist/taxonomy-QrNmTfIZ.mjs.map +1 -0
- package/dist/tokens-j5L0as2H.mjs +171 -0
- package/dist/tokens-j5L0as2H.mjs.map +1 -0
- package/dist/transfer-CYEw8Tu4.mjs +8873 -0
- package/dist/transfer-CYEw8Tu4.mjs.map +1 -0
- package/dist/transfer-DDX10hkD.mjs +166 -0
- package/dist/transfer-DDX10hkD.mjs.map +1 -0
- package/dist/transfer-download-BAqq6GJv.mjs +33 -0
- package/dist/transfer-download-BAqq6GJv.mjs.map +1 -0
- package/dist/transformations-De44wqV_.mjs +196 -0
- package/dist/transformations-De44wqV_.mjs.map +1 -0
- package/dist/transport-1QjUhCRO.d.mts +42 -0
- package/dist/transport-1QjUhCRO.d.mts.map +1 -0
- package/dist/transport-Ds5pVX7p.mjs +136 -0
- package/dist/transport-Ds5pVX7p.mjs.map +1 -0
- package/dist/trusted-proxy-d4Tk6biT.mjs +51 -0
- package/dist/trusted-proxy-d4Tk6biT.mjs.map +1 -0
- package/dist/turnstile-DaFLtyrs.mjs +58 -0
- package/dist/turnstile-DaFLtyrs.mjs.map +1 -0
- package/dist/types-B4-1P2DK.d.mts +227 -0
- package/dist/types-B4-1P2DK.d.mts.map +1 -0
- package/dist/types-BKXA0f-c.mjs +16 -0
- package/dist/types-BKXA0f-c.mjs.map +1 -0
- package/dist/types-BiHcpUoO.d.mts +374 -0
- package/dist/types-BiHcpUoO.d.mts.map +1 -0
- package/dist/types-BihhvkyN.d.mts +85 -0
- package/dist/types-BihhvkyN.d.mts.map +1 -0
- package/dist/types-Bq9Wohd7.d.mts +363 -0
- package/dist/types-Bq9Wohd7.d.mts.map +1 -0
- package/dist/types-C-Xp0CcN.mjs.map +1 -1
- package/dist/types-C4P7F1Vq.d.mts +1741 -0
- package/dist/types-C4P7F1Vq.d.mts.map +1 -0
- package/dist/types-CGaqwHw4.mjs +37 -0
- package/dist/types-CGaqwHw4.mjs.map +1 -0
- package/dist/types-D4ECCE4X.mjs +77 -0
- package/dist/types-D4ECCE4X.mjs.map +1 -0
- package/dist/types-DcRJp0vS.d.mts +125 -0
- package/dist/types-DcRJp0vS.d.mts.map +1 -0
- package/dist/types-Ff85fTzU.d.mts +289 -0
- package/dist/types-Ff85fTzU.d.mts.map +1 -0
- package/dist/types-UKr5Sf4y.d.mts +916 -0
- package/dist/types-UKr5Sf4y.d.mts.map +1 -0
- package/dist/types-YpN8hZW7.d.mts +204 -0
- package/dist/types-YpN8hZW7.d.mts.map +1 -0
- package/dist/update-check-DrlsK-tt.mjs +161 -0
- package/dist/update-check-DrlsK-tt.mjs.map +1 -0
- package/dist/upload-attempts-D8CPPvRU.mjs +32 -0
- package/dist/upload-attempts-D8CPPvRU.mjs.map +1 -0
- package/dist/url-pattern-Di4Nn3vP.mjs +41 -0
- package/dist/url-pattern-Di4Nn3vP.mjs.map +1 -0
- package/dist/user-B-ZdGjhI.mjs +171 -0
- package/dist/user-B-ZdGjhI.mjs.map +1 -0
- package/dist/utils-D7wL3r6-.mjs +437 -0
- package/dist/utils-D7wL3r6-.mjs.map +1 -0
- package/dist/validate-BSZbSUDk.mjs +524 -0
- package/dist/validate-BSZbSUDk.mjs.map +1 -0
- package/dist/validate-Dfv0DpZi.d.mts +468 -0
- package/dist/validate-Dfv0DpZi.d.mts.map +1 -0
- package/dist/validation-DRyC_Vm5.mjs +219 -0
- package/dist/validation-DRyC_Vm5.mjs.map +1 -0
- package/dist/version-C4kz0PcO.mjs +7 -0
- package/dist/version-C4kz0PcO.mjs.map +1 -0
- package/dist/version-jhs2BRtl.mjs +9 -0
- package/dist/version-jhs2BRtl.mjs.map +1 -0
- package/dist/video-DReZ48Un.mjs +54 -0
- package/dist/video-DReZ48Un.mjs.map +1 -0
- package/dist/virtual-modules-D0e6VbEv.mjs +516 -0
- package/dist/virtual-modules-D0e6VbEv.mjs.map +1 -0
- package/dist/widgets-BkcMzKct.mjs +121 -0
- package/dist/widgets-BkcMzKct.mjs.map +1 -0
- package/dist/wxr-taxonomies-BxI0CbTg.mjs +453 -0
- package/dist/wxr-taxonomies-BxI0CbTg.mjs.map +1 -0
- package/dist/wxr-taxonomies-Dad33GJi.d.mts +34 -0
- package/dist/wxr-taxonomies-Dad33GJi.d.mts.map +1 -0
- package/package.json +13 -10
- package/src/api/errors.ts +9 -0
- package/src/api/handlers/api-tokens.ts +12 -6
- package/src/api/handlers/content.ts +57 -8
- package/src/api/handlers/domain-move-notice.ts +94 -0
- package/src/api/handlers/index.ts +2 -0
- package/src/api/handlers/manifest.ts +5 -0
- package/src/api/handlers/media-usage.ts +2 -1
- package/src/api/handlers/media.ts +1 -0
- package/src/api/handlers/seo.ts +155 -59
- package/src/api/handlers/settings.ts +31 -1
- package/src/api/handlers/site-domain.ts +143 -0
- package/src/api/openapi/document.ts +2 -2
- package/src/api/public-url.ts +1 -1
- package/src/api/schemas/content.ts +20 -0
- package/src/api/schemas/media-usage.ts +7 -1
- package/src/api/schemas/media.ts +12 -0
- package/src/api/site-url.ts +53 -5
- package/src/api/types.ts +2 -0
- package/src/astro/image-endpoint.ts +46 -4
- package/src/astro/integration/admin-locales.ts +168 -0
- package/src/astro/integration/dev-env.ts +84 -0
- package/src/astro/integration/index.ts +49 -9
- package/src/astro/integration/routes.ts +20 -0
- package/src/astro/integration/runtime.ts +15 -0
- package/src/astro/integration/vite-config.ts +18 -1
- package/src/astro/middleware/auth.ts +16 -3
- package/src/astro/middleware/csp.ts +1 -0
- package/src/astro/middleware/redirect.ts +27 -12
- package/src/astro/middleware/request-context.ts +12 -6
- package/src/astro/middleware.ts +53 -14
- package/src/astro/routes/api/auth/handover.ts +58 -0
- package/src/astro/routes/api/auth/magic-link/verify.ts +11 -3
- package/src/astro/routes/api/auth/passkey/options.ts +10 -2
- package/src/astro/routes/api/import/wordpress/execute.ts +19 -0
- package/src/astro/routes/api/import/wordpress/rewrite-url-helpers.ts +80 -42
- package/src/astro/routes/api/import/wordpress-plugin/execute.ts +15 -0
- package/src/astro/routes/api/manifest.ts +10 -0
- package/src/astro/routes/api/media/[id]/confirm.ts +19 -0
- package/src/astro/routes/api/media/file/[...key].ts +60 -12
- package/src/astro/routes/api/media/upload-url.ts +28 -4
- package/src/astro/routes/api/media.ts +15 -0
- package/src/astro/routes/api/schema/index.ts +1 -1
- package/src/astro/routes/api/settings/domain-notify.ts +76 -0
- package/src/astro/routes/api/settings/domain.ts +63 -0
- package/src/astro/routes/api/setup/index.ts +7 -0
- package/src/astro/routes/api/site/domain-proof.ts +28 -0
- package/src/astro/routes/sitemap-[collection].xml.ts +31 -8
- package/src/astro/routes/sitemap.xml.ts +12 -10
- package/src/astro/types.ts +13 -1
- package/src/auth/rate-limit.ts +18 -13
- package/src/auth/types.ts +7 -0
- package/src/aws-sdk.d.ts +2 -1
- package/src/cleanup.ts +26 -0
- package/src/cli/commands/export-seed.ts +2 -0
- package/src/cli/commands/seed.ts +5 -4
- package/src/client/index.ts +6 -1
- package/src/comments/public-submission.ts +15 -8
- package/src/components/CommentForm.astro +48 -8
- package/src/components/Comments.astro +50 -28
- package/src/components/EmDashImage.astro +6 -4
- package/src/components/Gallery.astro +4 -3
- package/src/components/Image.astro +4 -3
- package/src/components/InlinePortableTextEditor.tsx +148 -26
- package/src/components/Video.astro +100 -0
- package/src/components/index.ts +4 -1
- package/src/components/inline-code-block.tsx +8 -0
- package/src/components/webmcp-search.ts +15 -19
- package/src/components/widgets/RecentPosts.astro +57 -17
- package/src/content/converters/mark-safety.ts +3 -3
- package/src/content/converters/portable-text-identity.ts +1 -0
- package/src/content/converters/portable-text-to-prosemirror.ts +7 -0
- package/src/content/converters/prosemirror-to-portable-text.ts +16 -0
- package/src/content/converters/types.ts +22 -0
- package/src/content/converters/video.ts +77 -0
- package/src/database/datetime-storage.ts +1 -1
- package/src/database/migrations/runner.ts +13 -1
- package/src/database/repositories/comment.ts +17 -3
- package/src/database/repositories/content.ts +22 -3
- package/src/database/repositories/plugin-storage.ts +28 -19
- package/src/database/repositories/redirect.ts +24 -2
- package/src/database/repositories/taxonomy.ts +61 -46
- package/src/database/repositories/types.ts +2 -0
- package/src/emdash-runtime.ts +217 -68
- package/src/import/sources/wordpress-plugin.ts +3 -2
- package/src/import/utils.ts +2 -3
- package/src/index.ts +3 -0
- package/src/loader.ts +134 -43
- package/src/media/image-endpoint.ts +101 -1
- package/src/media/responsive.ts +14 -7
- package/src/media/usage/extractor.ts +19 -2
- package/src/media/usage/types.ts +5 -1
- package/src/plugin-utils.ts +1 -1
- package/src/plugins/context.ts +3 -7
- package/src/plugins/hooks.ts +1 -1
- package/src/plugins/http-route-dispatch.ts +5 -1
- package/src/plugins/manifest-schema.ts +1 -0
- package/src/plugins/route-error.ts +14 -0
- package/src/plugins/routes.ts +2 -2
- package/src/plugins/state.ts +36 -0
- package/src/plugins/types.ts +6 -0
- package/src/query.ts +8 -0
- package/src/redirects/patterns.ts +26 -2
- package/src/schema/registry.ts +7 -4
- package/src/schema/slug.ts +19 -0
- package/src/search/text-extraction.ts +6 -1
- package/src/seed/validate.ts +31 -0
- package/src/seo/sitemap-name.ts +22 -0
- package/src/storage/index.ts +2 -0
- package/src/storage/local.ts +10 -2
- package/src/storage/range.ts +54 -0
- package/src/storage/s3.ts +52 -8
- package/src/storage/types.ts +30 -3
- package/src/ui.ts +1 -0
- package/src/utils/slugify.ts +6 -1
- package/src/visual-editing/toolbar.ts +80 -35
- package/src/widgets/components.ts +4 -0
- package/src/widgets/index.ts +74 -82
- package/src/widgets/recent-posts.ts +62 -0
- package/dist/action-token-AgOs1UWD.mjs +0 -26
- package/dist/action-token-AgOs1UWD.mjs.map +0 -1
- package/dist/adapters-DM1oyHIN.d.mts +0 -173
- package/dist/adapters-DM1oyHIN.d.mts.map +0 -1
- package/dist/allowed-origins-CFtudhyw.mjs +0 -116
- package/dist/allowed-origins-CFtudhyw.mjs.map +0 -1
- package/dist/api-CltsXhiX.mjs +0 -4980
- package/dist/api-CltsXhiX.mjs.map +0 -1
- package/dist/api-tokens-P3mAaQgr.mjs +0 -166
- package/dist/api-tokens-P3mAaQgr.mjs.map +0 -1
- package/dist/apply-Q7uvzBWW.mjs +0 -1680
- package/dist/apply-Q7uvzBWW.mjs.map +0 -1
- package/dist/approvals-DycwI6lZ.mjs +0 -460
- package/dist/approvals-DycwI6lZ.mjs.map +0 -1
- package/dist/artifact-fetch-CWxyELVI.mjs +0 -659
- package/dist/artifact-fetch-CWxyELVI.mjs.map +0 -1
- package/dist/artifacts-UzWbysb8.mjs +0 -307
- package/dist/artifacts-UzWbysb8.mjs.map +0 -1
- package/dist/authoritative-records-dSvXCfzb.mjs +0 -5172
- package/dist/authoritative-records-dSvXCfzb.mjs.map +0 -1
- package/dist/authorize-DeWfk--K.mjs +0 -49
- package/dist/authorize-DeWfk--K.mjs.map +0 -1
- package/dist/backup-CFnbdTSJ.mjs +0 -246
- package/dist/backup-CFnbdTSJ.mjs.map +0 -1
- package/dist/block-types-C0YFSfR7.mjs +0 -132
- package/dist/block-types-C0YFSfR7.mjs.map +0 -1
- package/dist/block-values-H4E0XwE8.mjs +0 -175
- package/dist/block-values-H4E0XwE8.mjs.map +0 -1
- package/dist/byline-BhVslYLz.mjs +0 -909
- package/dist/byline-BhVslYLz.mjs.map +0 -1
- package/dist/byline-fields-DHJs0Mja.mjs +0 -280
- package/dist/byline-fields-DHJs0Mja.mjs.map +0 -1
- package/dist/byline-fields-xdxE9kxZ.mjs +0 -123
- package/dist/byline-fields-xdxE9kxZ.mjs.map +0 -1
- package/dist/bylines-B_nN9liM.mjs +0 -234
- package/dist/bylines-B_nN9liM.mjs.map +0 -1
- package/dist/bylines-C71YACkL.mjs +0 -150
- package/dist/bylines-C71YACkL.mjs.map +0 -1
- package/dist/cache-aTYCL9nK.mjs +0 -133
- package/dist/cache-aTYCL9nK.mjs.map +0 -1
- package/dist/canonical-Y1dpjCnp.mjs +0 -174
- package/dist/canonical-Y1dpjCnp.mjs.map +0 -1
- package/dist/challenge-store-CxZxPqaw.mjs +0 -51
- package/dist/challenge-store-CxZxPqaw.mjs.map +0 -1
- package/dist/checksum-DtH6m5uk.mjs +0 -162
- package/dist/checksum-DtH6m5uk.mjs.map +0 -1
- package/dist/chunks-zlGB5IQP.mjs +0 -25
- package/dist/chunks-zlGB5IQP.mjs.map +0 -1
- package/dist/comment-Bu08Wvr3.mjs +0 -313
- package/dist/comment-Bu08Wvr3.mjs.map +0 -1
- package/dist/comment-reaction-B8SfT-yM.mjs +0 -85
- package/dist/comment-reaction-B8SfT-yM.mjs.map +0 -1
- package/dist/comments-BRtp992B.mjs +0 -99
- package/dist/comments-BRtp992B.mjs.map +0 -1
- package/dist/comments-DVUYqdyC.mjs +0 -195
- package/dist/comments-DVUYqdyC.mjs.map +0 -1
- package/dist/components-CQY-Sgm-.mjs +0 -108
- package/dist/components-CQY-Sgm-.mjs.map +0 -1
- package/dist/config-B-uePMLj.d.mts +0 -39
- package/dist/config-B-uePMLj.d.mts.map +0 -1
- package/dist/config-B6BDSsz2.d.mts +0 -6712
- package/dist/config-B6BDSsz2.d.mts.map +0 -1
- package/dist/config-BsJHiQxC.mjs +0 -228
- package/dist/config-BsJHiQxC.mjs.map +0 -1
- package/dist/connection-B9pIasFd.mjs +0 -36
- package/dist/connection-B9pIasFd.mjs.map +0 -1
- package/dist/content-Dji9vEiW.mjs +0 -2063
- package/dist/content-Dji9vEiW.mjs.map +0 -1
- package/dist/content-list-query-DiNwyKtd.d.mts +0 -26
- package/dist/content-list-query-DiNwyKtd.d.mts.map +0 -1
- package/dist/content-repair-B7wnbzhN.mjs +0 -442
- package/dist/content-repair-B7wnbzhN.mjs.map +0 -1
- package/dist/context-Ctcxc8Ia.mjs +0 -2026
- package/dist/context-Ctcxc8Ia.mjs.map +0 -1
- package/dist/credits-Bu7dlobo.mjs +0 -110
- package/dist/credits-Bu7dlobo.mjs.map +0 -1
- package/dist/cron-xe5XKqA-.mjs +0 -306
- package/dist/cron-xe5XKqA-.mjs.map +0 -1
- package/dist/dashboard-B5hVHOtf.mjs +0 -151
- package/dist/dashboard-B5hVHOtf.mjs.map +0 -1
- package/dist/default-DaoYyFRS.mjs +0 -81
- package/dist/default-DaoYyFRS.mjs.map +0 -1
- package/dist/deferred-tasks-BYcDx2o_.d.mts +0 -9
- package/dist/deferred-tasks-BYcDx2o_.d.mts.map +0 -1
- package/dist/device-flow-Ma5P5d2e.mjs +0 -521
- package/dist/device-flow-Ma5P5d2e.mjs.map +0 -1
- package/dist/digest-xIpR3o64.mjs +0 -194
- package/dist/digest-xIpR3o64.mjs.map +0 -1
- package/dist/direct-executor-DMWwCey3.mjs +0 -104
- package/dist/direct-executor-DMWwCey3.mjs.map +0 -1
- package/dist/email-console-DmqVF5J_.mjs +0 -50
- package/dist/email-console-DmqVF5J_.mjs.map +0 -1
- package/dist/email-locale-Cc5YSXfJ.mjs +0 -25
- package/dist/email-locale-Cc5YSXfJ.mjs.map +0 -1
- package/dist/emdash-runtime-BlybX9Ui.mjs +0 -4249
- package/dist/emdash-runtime-BlybX9Ui.mjs.map +0 -1
- package/dist/entry-lock-De1L8qUQ.mjs +0 -163
- package/dist/entry-lock-De1L8qUQ.mjs.map +0 -1
- package/dist/entry-lock-esmMbgI9.d.mts +0 -4551
- package/dist/entry-lock-esmMbgI9.d.mts.map +0 -1
- package/dist/entry-lock-sxz2PGAT.mjs +0 -1197
- package/dist/entry-lock-sxz2PGAT.mjs.map +0 -1
- package/dist/env-types-BkjCtN13.mjs +0 -38
- package/dist/env-types-BkjCtN13.mjs.map +0 -1
- package/dist/error-B0rgPgsQ.mjs +0 -90
- package/dist/error-B0rgPgsQ.mjs.map +0 -1
- package/dist/errors-CuHQRiBW.mjs +0 -120
- package/dist/errors-CuHQRiBW.mjs.map +0 -1
- package/dist/errors-DTE6C3K_.mjs +0 -470
- package/dist/errors-DTE6C3K_.mjs.map +0 -1
- package/dist/escape-nJW7dR0s.mjs +0 -9
- package/dist/escape-nJW7dR0s.mjs.map +0 -1
- package/dist/fence-CGw57S4v.mjs +0 -162
- package/dist/fence-CGw57S4v.mjs.map +0 -1
- package/dist/field-defs-cache-Bw8w499w.mjs +0 -77
- package/dist/field-defs-cache-Bw8w499w.mjs.map +0 -1
- package/dist/field-map-hn-D-SyH.mjs +0 -83
- package/dist/field-map-hn-D-SyH.mjs.map +0 -1
- package/dist/fts-manager-DacCYIe4.mjs +0 -443
- package/dist/fts-manager-DacCYIe4.mjs.map +0 -1
- package/dist/gc-BBplHrv6.mjs +0 -75
- package/dist/gc-BBplHrv6.mjs.map +0 -1
- package/dist/hook-result-DSRRxu_-.d.mts +0 -31
- package/dist/hook-result-DSRRxu_-.d.mts.map +0 -1
- package/dist/hreflang-CKPunvU0.mjs +0 -105
- package/dist/hreflang-CKPunvU0.mjs.map +0 -1
- package/dist/hreflang-egumj6WF.d.mts +0 -50
- package/dist/hreflang-egumj6WF.d.mts.map +0 -1
- package/dist/http-route-dispatch-DjNFZcJ2.mjs +0 -339
- package/dist/http-route-dispatch-DjNFZcJ2.mjs.map +0 -1
- package/dist/identity-Dfrx2_Bc.mjs +0 -35
- package/dist/identity-Dfrx2_Bc.mjs.map +0 -1
- package/dist/import-ROBvhbNc.mjs +0 -2021
- package/dist/import-ROBvhbNc.mjs.map +0 -1
- package/dist/index-B4sIdCAT.d.mts +0 -623
- package/dist/index-B4sIdCAT.d.mts.map +0 -1
- package/dist/install-finalization-CPM7Gged.mjs +0 -58
- package/dist/install-finalization-CPM7Gged.mjs.map +0 -1
- package/dist/keys-DxqxcAD4.mjs +0 -61
- package/dist/keys-DxqxcAD4.mjs.map +0 -1
- package/dist/kinds-BQl5gN6e.mjs +0 -974
- package/dist/kinds-BQl5gN6e.mjs.map +0 -1
- package/dist/lifecycle-DGQI7itS.mjs +0 -25
- package/dist/lifecycle-DGQI7itS.mjs.map +0 -1
- package/dist/load-DMxRl4VK.mjs +0 -28
- package/dist/load-DMxRl4VK.mjs.map +0 -1
- package/dist/loader-1DMiOq5s.mjs +0 -1303
- package/dist/loader-1DMiOq5s.mjs.map +0 -1
- package/dist/loops-Dn1i16FP.mjs +0 -205
- package/dist/loops-Dn1i16FP.mjs.map +0 -1
- package/dist/manifest-builder-CTw4FmZk.mjs +0 -189
- package/dist/manifest-builder-CTw4FmZk.mjs.map +0 -1
- package/dist/manifest-schema-gy37bD_D.mjs +0 -496
- package/dist/manifest-schema-gy37bD_D.mjs.map +0 -1
- package/dist/marketplace-tHWSsCUo.mjs +0 -257
- package/dist/marketplace-tHWSsCUo.mjs.map +0 -1
- package/dist/media-Bw-Q65ve.mjs +0 -294
- package/dist/media-Bw-Q65ve.mjs.map +0 -1
- package/dist/media-BzUDu7nl.mjs +0 -373
- package/dist/media-BzUDu7nl.mjs.map +0 -1
- package/dist/media-aahnKHze.mjs +0 -408
- package/dist/media-aahnKHze.mjs.map +0 -1
- package/dist/media-allowlist-RMrjo8TU.mjs +0 -45
- package/dist/media-allowlist-RMrjo8TU.mjs.map +0 -1
- package/dist/media-folders-kabR1oJf.mjs +0 -210
- package/dist/media-folders-kabR1oJf.mjs.map +0 -1
- package/dist/media-url-DloW2xrP.mjs +0 -43
- package/dist/media-url-DloW2xrP.mjs.map +0 -1
- package/dist/media-usage-CHHpV7ee.mjs +0 -282
- package/dist/media-usage-CHHpV7ee.mjs.map +0 -1
- package/dist/media-usage-activation-BinYqC_r.mjs +0 -78
- package/dist/media-usage-activation-BinYqC_r.mjs.map +0 -1
- package/dist/media-usage-work-C734aq6s.mjs +0 -1015
- package/dist/media-usage-work-C734aq6s.mjs.map +0 -1
- package/dist/media-usage-work-lxvV0-UO.mjs +0 -151
- package/dist/media-usage-work-lxvV0-UO.mjs.map +0 -1
- package/dist/menus-6RHNq4ZK.mjs +0 -753
- package/dist/menus-6RHNq4ZK.mjs.map +0 -1
- package/dist/menus-AuCTaO9W.mjs +0 -3704
- package/dist/menus-AuCTaO9W.mjs.map +0 -1
- package/dist/menus-BQKqf0Up.mjs +0 -92
- package/dist/menus-BQKqf0Up.mjs.map +0 -1
- package/dist/mode-nh0ppSX5.mjs +0 -23
- package/dist/mode-nh0ppSX5.mjs.map +0 -1
- package/dist/node-sqlite-compat-CDOEcc97.mjs +0 -63
- package/dist/node-sqlite-compat-CDOEcc97.mjs.map +0 -1
- package/dist/oauth-authorization-BtYQ80uU.mjs +0 -274
- package/dist/oauth-authorization-BtYQ80uU.mjs.map +0 -1
- package/dist/oauth-clients-C1S4NQHh.mjs +0 -266
- package/dist/oauth-clients-C1S4NQHh.mjs.map +0 -1
- package/dist/oauth-state-store-CpGi2FZH.mjs +0 -50
- package/dist/oauth-state-store-CpGi2FZH.mjs.map +0 -1
- package/dist/oauth-user-lookup-BNp1aFAr.mjs +0 -26
- package/dist/oauth-user-lookup-BNp1aFAr.mjs.map +0 -1
- package/dist/options-B41aLm1I.d.mts +0 -81
- package/dist/options-B41aLm1I.d.mts.map +0 -1
- package/dist/ownership-DoeAIuTg.mjs +0 -12
- package/dist/ownership-DoeAIuTg.mjs.map +0 -1
- package/dist/parse-CmFDTGzp.mjs +0 -81
- package/dist/parse-CmFDTGzp.mjs.map +0 -1
- package/dist/parse-QVS0t5oR.d.mts +0 -172
- package/dist/parse-QVS0t5oR.d.mts.map +0 -1
- package/dist/passkey-config-C-MxsV22.mjs +0 -46
- package/dist/passkey-config-C-MxsV22.mjs.map +0 -1
- package/dist/paths-kr8hAMMI.mjs +0 -77
- package/dist/paths-kr8hAMMI.mjs.map +0 -1
- package/dist/patterns-DyZJ67I7.mjs +0 -140
- package/dist/patterns-DyZJ67I7.mjs.map +0 -1
- package/dist/placeholder-Dn7MMdWr.d.mts +0 -306
- package/dist/placeholder-Dn7MMdWr.d.mts.map +0 -1
- package/dist/plan-CuQOeU9g.mjs +0 -135
- package/dist/plan-CuQOeU9g.mjs.map +0 -1
- package/dist/plugins-CGb-G98c.mjs +0 -261
- package/dist/plugins-CGb-G98c.mjs.map +0 -1
- package/dist/policy-C5wrDXYV.mjs +0 -45
- package/dist/policy-C5wrDXYV.mjs.map +0 -1
- package/dist/portable-text-BnRuiR1-.mjs +0 -307
- package/dist/portable-text-BnRuiR1-.mjs.map +0 -1
- package/dist/preview-xWNSR1Li.mjs +0 -107
- package/dist/preview-xWNSR1Li.mjs.map +0 -1
- package/dist/protocol-ClxN-m1e.d.mts +0 -61
- package/dist/protocol-ClxN-m1e.d.mts.map +0 -1
- package/dist/public-submission-CkmT2SKv.mjs +0 -250
- package/dist/public-submission-CkmT2SKv.mjs.map +0 -1
- package/dist/public-url-B5a0QAh6.mjs +0 -101
- package/dist/public-url-B5a0QAh6.mjs.map +0 -1
- package/dist/query-DHqFiqqH.mjs +0 -41
- package/dist/query-DHqFiqqH.mjs.map +0 -1
- package/dist/query-DT85BehD.mjs +0 -1125
- package/dist/query-DT85BehD.mjs.map +0 -1
- package/dist/rate-limit-iMvcu3eu.mjs +0 -120
- package/dist/rate-limit-iMvcu3eu.mjs.map +0 -1
- package/dist/receipt-Dpp1uaX9.mjs +0 -43
- package/dist/receipt-Dpp1uaX9.mjs.map +0 -1
- package/dist/redirect-BRoLiWQE.mjs +0 -19
- package/dist/redirect-BRoLiWQE.mjs.map +0 -1
- package/dist/redirect-xZNpBoGp.mjs +0 -417
- package/dist/redirect-xZNpBoGp.mjs.map +0 -1
- package/dist/redirects-D4EWeXAo.mjs +0 -148
- package/dist/redirects-D4EWeXAo.mjs.map +0 -1
- package/dist/redirects-DCKqwiWp.mjs +0 -446
- package/dist/redirects-DCKqwiWp.mjs.map +0 -1
- package/dist/registry-DaXmUsD4.mjs +0 -8369
- package/dist/registry-DaXmUsD4.mjs.map +0 -1
- package/dist/relations-JvBP8nGP.mjs +0 -776
- package/dist/relations-JvBP8nGP.mjs.map +0 -1
- package/dist/request-meta-B6blULFY.mjs +0 -141
- package/dist/request-meta-B6blULFY.mjs.map +0 -1
- package/dist/resolve-DAhHi5tn.mjs +0 -100
- package/dist/resolve-DAhHi5tn.mjs.map +0 -1
- package/dist/route-wire-DK600v4u.mjs +0 -197
- package/dist/route-wire-DK600v4u.mjs.map +0 -1
- package/dist/routes-BeZyaCzv.mjs +0 -272
- package/dist/routes-BeZyaCzv.mjs.map +0 -1
- package/dist/runner-CskI4Hmq.mjs +0 -6372
- package/dist/runner-CskI4Hmq.mjs.map +0 -1
- package/dist/runner-J3Cj6DGk.d.mts +0 -68
- package/dist/runner-J3Cj6DGk.d.mts.map +0 -1
- package/dist/schema-CK0ihqMR.mjs +0 -815
- package/dist/schema-CK0ihqMR.mjs.map +0 -1
- package/dist/schema-VtaZSrC-.mjs +0 -13
- package/dist/schema-VtaZSrC-.mjs.map +0 -1
- package/dist/scopes-BRnGlL9t.mjs +0 -34
- package/dist/scopes-BRnGlL9t.mjs.map +0 -1
- package/dist/search-D6-XK1Sn.mjs +0 -448
- package/dist/search-D6-XK1Sn.mjs.map +0 -1
- package/dist/sections-CBDCf7qR.mjs +0 -346
- package/dist/sections-CBDCf7qR.mjs.map +0 -1
- package/dist/seo-BdeEPDNW.mjs +0 -133
- package/dist/seo-BdeEPDNW.mjs.map +0 -1
- package/dist/seo-C61bnPuV.mjs +0 -114
- package/dist/seo-C61bnPuV.mjs.map +0 -1
- package/dist/service-BuRKLMxa.mjs +0 -150
- package/dist/service-BuRKLMxa.mjs.map +0 -1
- package/dist/session-user-CqkPtrPL.mjs +0 -61
- package/dist/session-user-CqkPtrPL.mjs.map +0 -1
- package/dist/settings-0u0lTthS.mjs +0 -51
- package/dist/settings-0u0lTthS.mjs.map +0 -1
- package/dist/settings-WHr45II1.mjs +0 -61
- package/dist/settings-WHr45II1.mjs.map +0 -1
- package/dist/settings-m5tIYnF0.mjs +0 -443
- package/dist/settings-m5tIYnF0.mjs.map +0 -1
- package/dist/setup-complete-B2_dhZZz.mjs +0 -65
- package/dist/setup-complete-B2_dhZZz.mjs.map +0 -1
- package/dist/setup-nonce-CJV9ftSK.mjs +0 -25
- package/dist/setup-nonce-CJV9ftSK.mjs.map +0 -1
- package/dist/site-settings-KJOqJW6W.mjs +0 -50
- package/dist/site-settings-KJOqJW6W.mjs.map +0 -1
- package/dist/site-url-Ceq_AUK0.mjs +0 -16
- package/dist/site-url-Ceq_AUK0.mjs.map +0 -1
- package/dist/slugify-T5GHH42D.mjs +0 -17
- package/dist/slugify-T5GHH42D.mjs.map +0 -1
- package/dist/snapshot-Dzsn3NZa.mjs +0 -414
- package/dist/snapshot-Dzsn3NZa.mjs.map +0 -1
- package/dist/ssrf-DsmvZB80.mjs +0 -406
- package/dist/ssrf-DsmvZB80.mjs.map +0 -1
- package/dist/stage-Csnh_yEd.mjs +0 -662
- package/dist/stage-Csnh_yEd.mjs.map +0 -1
- package/dist/staged-Q7pnEVvI.mjs +0 -686
- package/dist/staged-Q7pnEVvI.mjs.map +0 -1
- package/dist/state-kGdOMQRY.mjs +0 -153
- package/dist/state-kGdOMQRY.mjs.map +0 -1
- package/dist/status-D39Fpy8R.mjs +0 -30
- package/dist/status-D39Fpy8R.mjs.map +0 -1
- package/dist/storage-query-C7iy6eUb.d.mts +0 -1615
- package/dist/storage-query-C7iy6eUb.d.mts.map +0 -1
- package/dist/tar-BWiraSUY.mjs +0 -449
- package/dist/tar-BWiraSUY.mjs.map +0 -1
- package/dist/target-DOFs5oUC.mjs +0 -27
- package/dist/target-DOFs5oUC.mjs.map +0 -1
- package/dist/taxonomies-BS40Wxvi.mjs +0 -939
- package/dist/taxonomies-BS40Wxvi.mjs.map +0 -1
- package/dist/taxonomies-DAZU9VDd.mjs +0 -697
- package/dist/taxonomies-DAZU9VDd.mjs.map +0 -1
- package/dist/taxonomy-XzLE95Vx.mjs +0 -525
- package/dist/taxonomy-XzLE95Vx.mjs.map +0 -1
- package/dist/tokens-DSQan4p7.mjs +0 -171
- package/dist/tokens-DSQan4p7.mjs.map +0 -1
- package/dist/transfer-BcCVxDgf.mjs +0 -166
- package/dist/transfer-BcCVxDgf.mjs.map +0 -1
- package/dist/transfer-OMrancOt.mjs +0 -8873
- package/dist/transfer-OMrancOt.mjs.map +0 -1
- package/dist/transfer-download-Dc-ltjZY.mjs +0 -33
- package/dist/transfer-download-Dc-ltjZY.mjs.map +0 -1
- package/dist/transformations-Ddx7UtrY.mjs +0 -196
- package/dist/transformations-Ddx7UtrY.mjs.map +0 -1
- package/dist/transport-flR-Zmds.d.mts +0 -42
- package/dist/transport-flR-Zmds.d.mts.map +0 -1
- package/dist/transport-umzEbgYO.mjs +0 -136
- package/dist/transport-umzEbgYO.mjs.map +0 -1
- package/dist/trusted-proxy-BqfQFs6a.mjs +0 -51
- package/dist/trusted-proxy-BqfQFs6a.mjs.map +0 -1
- package/dist/turnstile-Do60baId.mjs +0 -58
- package/dist/turnstile-Do60baId.mjs.map +0 -1
- package/dist/types-BT1p3uyb.d.mts +0 -1735
- package/dist/types-BT1p3uyb.d.mts.map +0 -1
- package/dist/types-BYaPWs_F.d.mts +0 -198
- package/dist/types-BYaPWs_F.d.mts.map +0 -1
- package/dist/types-CLTQ9b_r.d.mts +0 -374
- package/dist/types-CLTQ9b_r.d.mts.map +0 -1
- package/dist/types-CPkQw2T2.d.mts +0 -85
- package/dist/types-CPkQw2T2.d.mts.map +0 -1
- package/dist/types-CQLvuXoZ.d.mts +0 -198
- package/dist/types-CQLvuXoZ.d.mts.map +0 -1
- package/dist/types-CV5xszpF.d.mts +0 -363
- package/dist/types-CV5xszpF.d.mts.map +0 -1
- package/dist/types-CdEMurNh.mjs +0 -77
- package/dist/types-CdEMurNh.mjs.map +0 -1
- package/dist/types-CxwtnuSS.mjs +0 -37
- package/dist/types-CxwtnuSS.mjs.map +0 -1
- package/dist/types-DGw8KMX_.mjs +0 -16
- package/dist/types-DGw8KMX_.mjs.map +0 -1
- package/dist/types-DOfVMPoo.d.mts +0 -125
- package/dist/types-DOfVMPoo.d.mts.map +0 -1
- package/dist/types-LtS0SM4F.d.mts +0 -287
- package/dist/types-LtS0SM4F.d.mts.map +0 -1
- package/dist/types-ifgOkcBa.d.mts +0 -916
- package/dist/types-ifgOkcBa.d.mts.map +0 -1
- package/dist/update-check-DOc2aBIU.mjs +0 -161
- package/dist/update-check-DOc2aBIU.mjs.map +0 -1
- package/dist/upload-attempts-nzdc3cay.mjs +0 -32
- package/dist/upload-attempts-nzdc3cay.mjs.map +0 -1
- package/dist/url-pattern-hVbqpXs6.mjs +0 -41
- package/dist/url-pattern-hVbqpXs6.mjs.map +0 -1
- package/dist/user-Dnp53zTq.mjs +0 -171
- package/dist/user-Dnp53zTq.mjs.map +0 -1
- package/dist/utils-CoV-PYhg.mjs +0 -439
- package/dist/utils-CoV-PYhg.mjs.map +0 -1
- package/dist/validate-CfQ9_YlD.d.mts +0 -468
- package/dist/validate-CfQ9_YlD.d.mts.map +0 -1
- package/dist/validate-DBX3DKtL.mjs +0 -516
- package/dist/validate-DBX3DKtL.mjs.map +0 -1
- package/dist/validation-BJMiDhB1.mjs +0 -219
- package/dist/validation-BJMiDhB1.mjs.map +0 -1
- package/dist/version-BaT8yKIT.mjs +0 -7
- package/dist/version-BaT8yKIT.mjs.map +0 -1
- package/dist/version-BwEGkqkx.mjs +0 -9
- package/dist/version-BwEGkqkx.mjs.map +0 -1
- package/dist/virtual-modules-B6vJW15k.mjs +0 -516
- package/dist/virtual-modules-B6vJW15k.mjs.map +0 -1
- package/dist/widgets-BkxBAgZ_.mjs +0 -126
- package/dist/widgets-BkxBAgZ_.mjs.map +0 -1
- package/dist/wxr-taxonomies-D7gAJyOF.mjs +0 -453
- package/dist/wxr-taxonomies-D7gAJyOF.mjs.map +0 -1
- package/dist/wxr-taxonomies-DM5J9AsT.d.mts +0 -34
- package/dist/wxr-taxonomies-DM5J9AsT.d.mts.map +0 -1
- /package/dist/{api-tokens-BLz2MtQs.mjs → api-tokens-D2zgAIEt.mjs} +0 -0
- /package/dist/{ssrf-tA45vIPX.mjs → ssrf-BvNItdxk.mjs} +0 -0
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
import { a as pluginManifestSchema, o as reconcileManifestAccess } from "./manifest-schema-BiFBPEsp.mjs";
|
|
2
|
+
import { createGzipDecoder, unpackTar } from "modern-tar";
|
|
3
|
+
|
|
4
|
+
//#region src/plugins/marketplace.ts
|
|
5
|
+
/**
|
|
6
|
+
* MarketplaceClient — HTTP client for the EmDash Plugin Marketplace
|
|
7
|
+
*
|
|
8
|
+
* Used by the install/update/proxy endpoints in EmDash core to communicate
|
|
9
|
+
* with the marketplace Worker. The marketplace is a distribution channel,
|
|
10
|
+
* not a runtime dependency — bundles are copied to site-local R2 at install time.
|
|
11
|
+
*/
|
|
12
|
+
const TRAILING_SLASHES = /\/+$/;
|
|
13
|
+
const LEADING_DOT_SLASH = /^\.\//;
|
|
14
|
+
var MarketplaceError = class extends Error {
|
|
15
|
+
constructor(message, status, code) {
|
|
16
|
+
super(message);
|
|
17
|
+
this.status = status;
|
|
18
|
+
this.code = code;
|
|
19
|
+
this.name = "MarketplaceError";
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
var MarketplaceUnavailableError = class extends MarketplaceError {
|
|
23
|
+
constructor(cause) {
|
|
24
|
+
super("Plugin marketplace is unavailable", void 0, "MARKETPLACE_UNAVAILABLE");
|
|
25
|
+
if (cause) this.cause = cause;
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
const MAX_REDIRECTS = 5;
|
|
29
|
+
/**
|
|
30
|
+
* Fetches a marketplace URL, following redirects only while they stay on
|
|
31
|
+
* that URL's origin. Throws a `MarketplaceError` coded
|
|
32
|
+
* `${codePrefix}_REDIRECT_UNTRUSTED` or `${codePrefix}_TOO_MANY_REDIRECTS`.
|
|
33
|
+
*/
|
|
34
|
+
async function fetchWithinOrigin(url, label, codePrefix) {
|
|
35
|
+
const origin = new URL(url).origin;
|
|
36
|
+
let currentUrl = url;
|
|
37
|
+
let response = await fetch(currentUrl, { redirect: "manual" });
|
|
38
|
+
for (let i = 0; i < MAX_REDIRECTS; i++) {
|
|
39
|
+
if (response.status < 300 || response.status >= 400) break;
|
|
40
|
+
const location = response.headers.get("location");
|
|
41
|
+
if (!location) break;
|
|
42
|
+
const target = new URL(location, currentUrl);
|
|
43
|
+
if (target.origin !== origin) throw new MarketplaceError(`${label} redirected to untrusted host: ${target.origin}`, response.status, `${codePrefix}_REDIRECT_UNTRUSTED`);
|
|
44
|
+
currentUrl = target.href;
|
|
45
|
+
response = await fetch(currentUrl, { redirect: "manual" });
|
|
46
|
+
}
|
|
47
|
+
if (response.status >= 300 && response.status < 400) throw new MarketplaceError(`${label} exceeded maximum redirects (${MAX_REDIRECTS})`, response.status, `${codePrefix}_TOO_MANY_REDIRECTS`);
|
|
48
|
+
return response;
|
|
49
|
+
}
|
|
50
|
+
var MarketplaceClientImpl = class {
|
|
51
|
+
baseUrl;
|
|
52
|
+
siteOrigin;
|
|
53
|
+
constructor(baseUrl, siteOrigin) {
|
|
54
|
+
this.baseUrl = baseUrl.replace(TRAILING_SLASHES, "");
|
|
55
|
+
this.siteOrigin = siteOrigin;
|
|
56
|
+
}
|
|
57
|
+
async search(query, opts) {
|
|
58
|
+
const params = new URLSearchParams();
|
|
59
|
+
if (query) params.set("q", query);
|
|
60
|
+
if (opts?.category) params.set("category", opts.category);
|
|
61
|
+
if (opts?.capability) params.set("capability", opts.capability);
|
|
62
|
+
if (opts?.sort) params.set("sort", opts.sort);
|
|
63
|
+
if (opts?.cursor) params.set("cursor", opts.cursor);
|
|
64
|
+
if (opts?.limit) params.set("limit", String(opts.limit));
|
|
65
|
+
const qs = params.toString();
|
|
66
|
+
const url = `${this.baseUrl}/api/v1/plugins${qs ? `?${qs}` : ""}`;
|
|
67
|
+
return await this.fetchJson(url);
|
|
68
|
+
}
|
|
69
|
+
async getPlugin(id) {
|
|
70
|
+
const url = `${this.baseUrl}/api/v1/plugins/${encodeURIComponent(id)}`;
|
|
71
|
+
return this.fetchJson(url);
|
|
72
|
+
}
|
|
73
|
+
async getVersions(id) {
|
|
74
|
+
const url = `${this.baseUrl}/api/v1/plugins/${encodeURIComponent(id)}/versions`;
|
|
75
|
+
return (await this.fetchJson(url)).items;
|
|
76
|
+
}
|
|
77
|
+
async downloadBundle(id, version) {
|
|
78
|
+
const bundleUrl = `${this.baseUrl}/api/v1/plugins/${encodeURIComponent(id)}/versions/${encodeURIComponent(version)}/bundle`;
|
|
79
|
+
let response;
|
|
80
|
+
try {
|
|
81
|
+
response = await fetchWithinOrigin(bundleUrl, "Bundle download", "BUNDLE");
|
|
82
|
+
} catch (err) {
|
|
83
|
+
if (err instanceof MarketplaceError) throw err;
|
|
84
|
+
throw new MarketplaceUnavailableError(err);
|
|
85
|
+
}
|
|
86
|
+
if (!response.ok) throw new MarketplaceError(`Failed to download bundle: ${response.status} ${response.statusText}`, response.status, "BUNDLE_DOWNLOAD_FAILED");
|
|
87
|
+
const tarballBytes = new Uint8Array(await response.arrayBuffer());
|
|
88
|
+
try {
|
|
89
|
+
return await extractBundle(tarballBytes);
|
|
90
|
+
} catch (err) {
|
|
91
|
+
if (err instanceof MarketplaceError) throw err;
|
|
92
|
+
throw new MarketplaceError("Failed to extract plugin bundle", void 0, "BUNDLE_EXTRACT_FAILED");
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
async reportInstall(id, version) {
|
|
96
|
+
const siteHash = await generateSiteHash(this.siteOrigin);
|
|
97
|
+
const url = `${this.baseUrl}/api/v1/plugins/${encodeURIComponent(id)}/installs`;
|
|
98
|
+
try {
|
|
99
|
+
await fetch(url, {
|
|
100
|
+
method: "POST",
|
|
101
|
+
headers: { "Content-Type": "application/json" },
|
|
102
|
+
body: JSON.stringify({
|
|
103
|
+
siteHash,
|
|
104
|
+
version
|
|
105
|
+
})
|
|
106
|
+
});
|
|
107
|
+
} catch {}
|
|
108
|
+
}
|
|
109
|
+
async searchThemes(query, opts) {
|
|
110
|
+
const params = new URLSearchParams();
|
|
111
|
+
if (query) params.set("q", query);
|
|
112
|
+
if (opts?.keyword) params.set("keyword", opts.keyword);
|
|
113
|
+
if (opts?.sort) params.set("sort", opts.sort);
|
|
114
|
+
if (opts?.cursor) params.set("cursor", opts.cursor);
|
|
115
|
+
if (opts?.limit) params.set("limit", String(opts.limit));
|
|
116
|
+
const qs = params.toString();
|
|
117
|
+
const url = `${this.baseUrl}/api/v1/themes${qs ? `?${qs}` : ""}`;
|
|
118
|
+
return this.fetchJson(url);
|
|
119
|
+
}
|
|
120
|
+
async getTheme(id) {
|
|
121
|
+
const url = `${this.baseUrl}/api/v1/themes/${encodeURIComponent(id)}`;
|
|
122
|
+
return this.fetchJson(url);
|
|
123
|
+
}
|
|
124
|
+
async fetchJson(url) {
|
|
125
|
+
let response;
|
|
126
|
+
try {
|
|
127
|
+
response = await fetch(url, { headers: { Accept: "application/json" } });
|
|
128
|
+
} catch (err) {
|
|
129
|
+
throw new MarketplaceUnavailableError(err);
|
|
130
|
+
}
|
|
131
|
+
if (!response.ok) {
|
|
132
|
+
let errorMessage = `Marketplace request failed: ${response.status}`;
|
|
133
|
+
try {
|
|
134
|
+
const body = await response.json();
|
|
135
|
+
if (body.error) errorMessage = body.error;
|
|
136
|
+
} catch {}
|
|
137
|
+
throw new MarketplaceError(errorMessage, response.status);
|
|
138
|
+
}
|
|
139
|
+
return await response.json();
|
|
140
|
+
}
|
|
141
|
+
};
|
|
142
|
+
/**
|
|
143
|
+
* Extract manifest + code files from a tarball.
|
|
144
|
+
*
|
|
145
|
+
* The tarball is a gzipped tar archive containing:
|
|
146
|
+
* - manifest.json
|
|
147
|
+
* - backend.js
|
|
148
|
+
* - admin.js (optional)
|
|
149
|
+
*
|
|
150
|
+
* We use a minimal tar parser since we only need to read a few small files.
|
|
151
|
+
*/
|
|
152
|
+
/**
|
|
153
|
+
* Exported so the experimental registry install handler can reuse the
|
|
154
|
+
* same parse / validate / hash primitive. Despite the file name, this
|
|
155
|
+
* function predates the marketplace-vs-registry split and is generic
|
|
156
|
+
* over plugin bundle tarballs regardless of distribution channel.
|
|
157
|
+
*/
|
|
158
|
+
const MAX_DECOMPRESSED_BUNDLE_BYTES = 256 * 1024;
|
|
159
|
+
const MAX_BUNDLE_TAR_ENTRIES = 32;
|
|
160
|
+
async function extractBundle(tarballBytes) {
|
|
161
|
+
const reader = new ReadableStream({ start(controller) {
|
|
162
|
+
controller.enqueue(tarballBytes);
|
|
163
|
+
controller.close();
|
|
164
|
+
} }).pipeThrough(createGzipDecoder()).getReader();
|
|
165
|
+
const chunks = [];
|
|
166
|
+
let total = 0;
|
|
167
|
+
while (true) {
|
|
168
|
+
const { done, value } = await reader.read();
|
|
169
|
+
if (done) break;
|
|
170
|
+
if (!value) continue;
|
|
171
|
+
total += value.byteLength;
|
|
172
|
+
if (total > MAX_DECOMPRESSED_BUNDLE_BYTES) {
|
|
173
|
+
try {
|
|
174
|
+
await reader.cancel();
|
|
175
|
+
} catch {}
|
|
176
|
+
throw new MarketplaceError(`Bundle decompressed size exceeds limit (${MAX_DECOMPRESSED_BUNDLE_BYTES} bytes)`, void 0, "INVALID_BUNDLE");
|
|
177
|
+
}
|
|
178
|
+
chunks.push(value);
|
|
179
|
+
}
|
|
180
|
+
const decompressedBytes = new Uint8Array(total);
|
|
181
|
+
{
|
|
182
|
+
let offset = 0;
|
|
183
|
+
for (const chunk of chunks) {
|
|
184
|
+
decompressedBytes.set(chunk, offset);
|
|
185
|
+
offset += chunk.byteLength;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
const entries = await unpackTar(new ReadableStream({ start(controller) {
|
|
189
|
+
controller.enqueue(decompressedBytes);
|
|
190
|
+
controller.close();
|
|
191
|
+
} }));
|
|
192
|
+
if (entries.length > MAX_BUNDLE_TAR_ENTRIES) throw new MarketplaceError(`Bundle has too many tar entries (${entries.length} > ${MAX_BUNDLE_TAR_ENTRIES})`, void 0, "INVALID_BUNDLE");
|
|
193
|
+
const decoder = new TextDecoder();
|
|
194
|
+
const files = /* @__PURE__ */ new Map();
|
|
195
|
+
for (const entry of entries) if (entry.data && entry.header.type === "file") {
|
|
196
|
+
const name = entry.header.name.replace(LEADING_DOT_SLASH, "");
|
|
197
|
+
files.set(name, decoder.decode(entry.data));
|
|
198
|
+
}
|
|
199
|
+
const manifestJson = files.get("manifest.json");
|
|
200
|
+
const backendCode = files.get("backend.js");
|
|
201
|
+
if (!manifestJson) throw new MarketplaceError("Invalid bundle: missing manifest.json", void 0, "INVALID_BUNDLE");
|
|
202
|
+
if (!backendCode) throw new MarketplaceError("Invalid bundle: missing backend.js", void 0, "INVALID_BUNDLE");
|
|
203
|
+
let manifest;
|
|
204
|
+
try {
|
|
205
|
+
const parsed = JSON.parse(manifestJson);
|
|
206
|
+
const result = pluginManifestSchema.safeParse(parsed);
|
|
207
|
+
if (!result.success) throw new MarketplaceError("Invalid bundle: manifest.json failed validation", void 0, "INVALID_BUNDLE");
|
|
208
|
+
manifest = reconcileManifestAccess(result.data);
|
|
209
|
+
} catch (err) {
|
|
210
|
+
if (err instanceof MarketplaceError) throw err;
|
|
211
|
+
throw new MarketplaceError("Invalid bundle: malformed manifest.json", void 0, "INVALID_BUNDLE");
|
|
212
|
+
}
|
|
213
|
+
const hashBuffer = await crypto.subtle.digest("SHA-256", tarballBytes);
|
|
214
|
+
const hashArray = new Uint8Array(hashBuffer);
|
|
215
|
+
const checksum = Array.from(hashArray, (b) => b.toString(16).padStart(2, "0")).join("");
|
|
216
|
+
return {
|
|
217
|
+
manifest,
|
|
218
|
+
backendCode,
|
|
219
|
+
adminCode: files.get("admin.js"),
|
|
220
|
+
checksum
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
224
|
+
* Generate a stable non-identifying site hash from the site origin.
|
|
225
|
+
* The same origin always produces the same hash, so the marketplace
|
|
226
|
+
* installs table deduplicates correctly per (plugin_id, site_hash).
|
|
227
|
+
*/
|
|
228
|
+
async function generateSiteHash(siteOrigin) {
|
|
229
|
+
const seed = siteOrigin ? `emdash-site:${siteOrigin}` : `emdash-anonymous`;
|
|
230
|
+
try {
|
|
231
|
+
const hash = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(seed));
|
|
232
|
+
const arr = new Uint8Array(hash);
|
|
233
|
+
return Array.from(arr.slice(0, 8), (b) => b.toString(16).padStart(2, "0")).join("");
|
|
234
|
+
} catch {
|
|
235
|
+
let h = 2166136261;
|
|
236
|
+
for (let i = 0; i < seed.length; i++) {
|
|
237
|
+
h ^= seed.charCodeAt(i);
|
|
238
|
+
h = Math.imul(h, 16777619);
|
|
239
|
+
}
|
|
240
|
+
const h2 = h ^ h >>> 16;
|
|
241
|
+
return (h >>> 0).toString(16).padStart(8, "0") + (h2 >>> 0).toString(16).padStart(8, "0");
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
/**
|
|
245
|
+
* Create a MarketplaceClient for the given marketplace URL.
|
|
246
|
+
*
|
|
247
|
+
* @param baseUrl - The marketplace API base URL (e.g. "https://marketplace.emdashcms.com")
|
|
248
|
+
* @param siteOrigin - The origin of the EmDash site (e.g. "https://myblog.example.com").
|
|
249
|
+
* Used to generate a stable, non-identifying site hash for install deduplication.
|
|
250
|
+
*/
|
|
251
|
+
function createMarketplaceClient(baseUrl, siteOrigin) {
|
|
252
|
+
return new MarketplaceClientImpl(baseUrl, siteOrigin);
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
//#endregion
|
|
256
|
+
export { fetchWithinOrigin as i, MarketplaceUnavailableError as n, createMarketplaceClient as r, MarketplaceError as t };
|
|
257
|
+
//# sourceMappingURL=marketplace-CUlenvZm.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"marketplace-CUlenvZm.mjs","names":[],"sources":["../src/plugins/marketplace.ts"],"sourcesContent":["/**\n * MarketplaceClient — HTTP client for the EmDash Plugin Marketplace\n *\n * Used by the install/update/proxy endpoints in EmDash core to communicate\n * with the marketplace Worker. The marketplace is a distribution channel,\n * not a runtime dependency — bundles are copied to site-local R2 at install time.\n */\n\nimport { createGzipDecoder, unpackTar } from \"modern-tar\";\n\nimport { pluginManifestSchema, reconcileManifestAccess } from \"./manifest-schema.js\";\nimport type { PluginManifest } from \"./types.js\";\n\n// ── Module-level regex patterns ───────────────────────────────────\n\nconst TRAILING_SLASHES = /\\/+$/;\nconst LEADING_DOT_SLASH = /^\\.\\//;\n\n// ── Types ──────────────────────────────────────────────────────────\n\nexport interface MarketplacePluginSummary {\n\tid: string;\n\tname: string;\n\tdescription: string | null;\n\tauthor: {\n\t\tname: string;\n\t\tverified: boolean;\n\t\tavatarUrl: string | null;\n\t};\n\tcapabilities: string[];\n\tkeywords: string[];\n\tinstallCount: number;\n\thasIcon: boolean;\n\ticonUrl: string;\n\tlatestVersion?: {\n\t\tversion: string;\n\t\taudit?: {\n\t\t\tverdict: string;\n\t\t\triskScore: number;\n\t\t};\n\t\timageAudit?: {\n\t\t\tverdict: string;\n\t\t};\n\t};\n\tcreatedAt: string;\n\tupdatedAt: string;\n}\n\nexport interface MarketplaceVersionSummary {\n\tversion: string;\n\tminEmDashVersion: string | null;\n\tbundleSize: number;\n\tchecksum: string;\n\tchangelog: string | null;\n\tcapabilities: string[];\n\tstatus: string;\n\tauditVerdict: string | null;\n\timageAuditVerdict: string | null;\n\tpublishedAt: string;\n}\n\nexport interface MarketplacePluginDetail extends MarketplacePluginSummary {\n\trepositoryUrl: string | null;\n\thomepageUrl: string | null;\n\tlicense: string | null;\n\tlatestVersion?: {\n\t\tversion: string;\n\t\tminEmDashVersion: string | null;\n\t\tbundleSize: number;\n\t\tchecksum: string;\n\t\tchangelog: string | null;\n\t\treadme: string | null;\n\t\thasIcon: boolean;\n\t\tscreenshotCount: number;\n\t\tscreenshotUrls: string[];\n\t\tcapabilities: string[];\n\t\tstatus: string;\n\t\taudit?: {\n\t\t\tverdict: string;\n\t\t\triskScore: number;\n\t\t};\n\t\timageAudit?: {\n\t\t\tverdict: string;\n\t\t};\n\t\tpublishedAt: string;\n\t};\n}\n\nexport interface MarketplaceSearchOpts {\n\tcategory?: string;\n\tcapability?: string;\n\tsort?: \"installs\" | \"updated\" | \"created\" | \"name\";\n\tcursor?: string;\n\tlimit?: number;\n}\n\nexport interface MarketplaceSearchResult {\n\titems: MarketplacePluginSummary[];\n\tnextCursor?: string;\n}\n\n// ── Theme types ───────────────────────────────────────────────────\n\nexport interface MarketplaceThemeSummary {\n\tid: string;\n\tname: string;\n\tdescription: string | null;\n\tauthor: {\n\t\tname: string;\n\t\tverified: boolean;\n\t\tavatarUrl: string | null;\n\t};\n\tkeywords: string[];\n\tpreviewUrl: string;\n\tdemoUrl: string | null;\n\thasThumbnail: boolean;\n\tthumbnailUrl: string | null;\n\tcreatedAt: string;\n\tupdatedAt: string;\n}\n\nexport interface MarketplaceThemeDetail extends MarketplaceThemeSummary {\n\tauthor: {\n\t\tid: string;\n\t\tname: string;\n\t\tverified: boolean;\n\t\tavatarUrl: string | null;\n\t};\n\trepositoryUrl: string | null;\n\thomepageUrl: string | null;\n\tlicense: string | null;\n\tscreenshotCount: number;\n\tscreenshotUrls: string[];\n}\n\nexport interface MarketplaceThemeSearchOpts {\n\tkeyword?: string;\n\tsort?: \"name\" | \"created\" | \"updated\";\n\tcursor?: string;\n\tlimit?: number;\n}\n\nexport interface MarketplaceThemeSearchResult {\n\titems: MarketplaceThemeSummary[];\n\tnextCursor?: string;\n}\n\nexport interface PluginBundle {\n\tmanifest: PluginManifest;\n\tbackendCode: string;\n\tadminCode?: string;\n\tchecksum: string;\n}\n\n// ── Interface ──────────────────────────────────────────────────────\n\nexport interface MarketplaceClient {\n\t/** Search the marketplace catalog */\n\tsearch(query?: string, opts?: MarketplaceSearchOpts): Promise<MarketplaceSearchResult>;\n\n\t/** Get full plugin detail */\n\tgetPlugin(id: string): Promise<MarketplacePluginDetail>;\n\n\t/** Get version history for a plugin */\n\tgetVersions(id: string): Promise<MarketplaceVersionSummary[]>;\n\n\t/** Download and extract a plugin bundle */\n\tdownloadBundle(id: string, version: string): Promise<PluginBundle>;\n\n\t/** Fire-and-forget install stat (never throws) */\n\treportInstall(id: string, version: string): Promise<void>;\n\n\t/** Search theme listings */\n\tsearchThemes(\n\t\tquery?: string,\n\t\topts?: MarketplaceThemeSearchOpts,\n\t): Promise<MarketplaceThemeSearchResult>;\n\n\t/** Get full theme detail */\n\tgetTheme(id: string): Promise<MarketplaceThemeDetail>;\n}\n\n// ── Errors ─────────────────────────────────────────────────────────\n\nexport class MarketplaceError extends Error {\n\tconstructor(\n\t\tmessage: string,\n\t\tpublic readonly status?: number,\n\t\tpublic readonly code?: string,\n\t) {\n\t\tsuper(message);\n\t\tthis.name = \"MarketplaceError\";\n\t}\n}\n\nexport class MarketplaceUnavailableError extends MarketplaceError {\n\tconstructor(cause?: unknown) {\n\t\tsuper(\"Plugin marketplace is unavailable\", undefined, \"MARKETPLACE_UNAVAILABLE\");\n\t\tif (cause) this.cause = cause;\n\t}\n}\n\nconst MAX_REDIRECTS = 5;\n\n/**\n * Fetches a marketplace URL, following redirects only while they stay on\n * that URL's origin. Throws a `MarketplaceError` coded\n * `${codePrefix}_REDIRECT_UNTRUSTED` or `${codePrefix}_TOO_MANY_REDIRECTS`.\n */\nexport async function fetchWithinOrigin(\n\turl: string,\n\tlabel: string,\n\tcodePrefix: string,\n): Promise<Response> {\n\tconst origin = new URL(url).origin;\n\tlet currentUrl = url;\n\tlet response = await fetch(currentUrl, { redirect: \"manual\" });\n\n\tfor (let i = 0; i < MAX_REDIRECTS; i++) {\n\t\tif (response.status < 300 || response.status >= 400) break;\n\n\t\tconst location = response.headers.get(\"location\");\n\t\tif (!location) break;\n\n\t\tconst target = new URL(location, currentUrl);\n\t\tif (target.origin !== origin) {\n\t\t\tthrow new MarketplaceError(\n\t\t\t\t`${label} redirected to untrusted host: ${target.origin}`,\n\t\t\t\tresponse.status,\n\t\t\t\t`${codePrefix}_REDIRECT_UNTRUSTED`,\n\t\t\t);\n\t\t}\n\t\tcurrentUrl = target.href;\n\t\tresponse = await fetch(currentUrl, { redirect: \"manual\" });\n\t}\n\n\tif (response.status >= 300 && response.status < 400) {\n\t\tthrow new MarketplaceError(\n\t\t\t`${label} exceeded maximum redirects (${MAX_REDIRECTS})`,\n\t\t\tresponse.status,\n\t\t\t`${codePrefix}_TOO_MANY_REDIRECTS`,\n\t\t);\n\t}\n\treturn response;\n}\n\n// ── Implementation ─────────────────────────────────────────────────\n\nclass MarketplaceClientImpl implements MarketplaceClient {\n\tprivate readonly baseUrl: string;\n\tprivate readonly siteOrigin: string | undefined;\n\n\tconstructor(baseUrl: string, siteOrigin?: string) {\n\t\t// Strip trailing slash\n\t\tthis.baseUrl = baseUrl.replace(TRAILING_SLASHES, \"\");\n\t\tthis.siteOrigin = siteOrigin;\n\t}\n\n\tasync search(query?: string, opts?: MarketplaceSearchOpts): Promise<MarketplaceSearchResult> {\n\t\tconst params = new URLSearchParams();\n\t\tif (query) params.set(\"q\", query);\n\t\tif (opts?.category) params.set(\"category\", opts.category);\n\t\tif (opts?.capability) params.set(\"capability\", opts.capability);\n\t\tif (opts?.sort) params.set(\"sort\", opts.sort);\n\t\tif (opts?.cursor) params.set(\"cursor\", opts.cursor);\n\t\tif (opts?.limit) params.set(\"limit\", String(opts.limit));\n\n\t\tconst qs = params.toString();\n\t\tconst url = `${this.baseUrl}/api/v1/plugins${qs ? `?${qs}` : \"\"}`;\n\t\tconst data = await this.fetchJson<MarketplaceSearchResult>(url);\n\t\treturn data;\n\t}\n\n\tasync getPlugin(id: string): Promise<MarketplacePluginDetail> {\n\t\tconst url = `${this.baseUrl}/api/v1/plugins/${encodeURIComponent(id)}`;\n\t\treturn this.fetchJson<MarketplacePluginDetail>(url);\n\t}\n\n\tasync getVersions(id: string): Promise<MarketplaceVersionSummary[]> {\n\t\tconst url = `${this.baseUrl}/api/v1/plugins/${encodeURIComponent(id)}/versions`;\n\t\tconst data = await this.fetchJson<{ items: MarketplaceVersionSummary[] }>(url);\n\t\treturn data.items;\n\t}\n\n\tasync downloadBundle(id: string, version: string): Promise<PluginBundle> {\n\t\tconst bundleUrl = `${this.baseUrl}/api/v1/plugins/${encodeURIComponent(id)}/versions/${encodeURIComponent(version)}/bundle`;\n\n\t\tlet response: Response;\n\t\ttry {\n\t\t\tresponse = await fetchWithinOrigin(bundleUrl, \"Bundle download\", \"BUNDLE\");\n\t\t} catch (err) {\n\t\t\tif (err instanceof MarketplaceError) throw err;\n\t\t\tthrow new MarketplaceUnavailableError(err);\n\t\t}\n\n\t\tif (!response.ok) {\n\t\t\tthrow new MarketplaceError(\n\t\t\t\t`Failed to download bundle: ${response.status} ${response.statusText}`,\n\t\t\t\tresponse.status,\n\t\t\t\t\"BUNDLE_DOWNLOAD_FAILED\",\n\t\t\t);\n\t\t}\n\n\t\tconst tarballBytes = new Uint8Array(await response.arrayBuffer());\n\t\ttry {\n\t\t\treturn await extractBundle(tarballBytes);\n\t\t} catch (err) {\n\t\t\tif (err instanceof MarketplaceError) throw err;\n\t\t\tthrow new MarketplaceError(\n\t\t\t\t\"Failed to extract plugin bundle\",\n\t\t\t\tundefined,\n\t\t\t\t\"BUNDLE_EXTRACT_FAILED\",\n\t\t\t);\n\t\t}\n\t}\n\n\tasync reportInstall(id: string, version: string): Promise<void> {\n\t\t// Generate a stable site hash from the site origin (best-effort, non-identifying)\n\t\tconst siteHash = await generateSiteHash(this.siteOrigin);\n\t\tconst url = `${this.baseUrl}/api/v1/plugins/${encodeURIComponent(id)}/installs`;\n\n\t\ttry {\n\t\t\tawait fetch(url, {\n\t\t\t\tmethod: \"POST\",\n\t\t\t\theaders: { \"Content-Type\": \"application/json\" },\n\t\t\t\tbody: JSON.stringify({ siteHash, version }),\n\t\t\t});\n\t\t} catch {\n\t\t\t// Fire-and-forget — never throw\n\t\t}\n\t}\n\n\tasync searchThemes(\n\t\tquery?: string,\n\t\topts?: MarketplaceThemeSearchOpts,\n\t): Promise<MarketplaceThemeSearchResult> {\n\t\tconst params = new URLSearchParams();\n\t\tif (query) params.set(\"q\", query);\n\t\tif (opts?.keyword) params.set(\"keyword\", opts.keyword);\n\t\tif (opts?.sort) params.set(\"sort\", opts.sort);\n\t\tif (opts?.cursor) params.set(\"cursor\", opts.cursor);\n\t\tif (opts?.limit) params.set(\"limit\", String(opts.limit));\n\n\t\tconst qs = params.toString();\n\t\tconst url = `${this.baseUrl}/api/v1/themes${qs ? `?${qs}` : \"\"}`;\n\t\treturn this.fetchJson<MarketplaceThemeSearchResult>(url);\n\t}\n\n\tasync getTheme(id: string): Promise<MarketplaceThemeDetail> {\n\t\tconst url = `${this.baseUrl}/api/v1/themes/${encodeURIComponent(id)}`;\n\t\treturn this.fetchJson<MarketplaceThemeDetail>(url);\n\t}\n\n\tprivate async fetchJson<T>(url: string): Promise<T> {\n\t\tlet response: Response;\n\t\ttry {\n\t\t\tresponse = await fetch(url, {\n\t\t\t\theaders: { Accept: \"application/json\" },\n\t\t\t});\n\t\t} catch (err) {\n\t\t\tthrow new MarketplaceUnavailableError(err);\n\t\t}\n\n\t\tif (!response.ok) {\n\t\t\tlet errorMessage = `Marketplace request failed: ${response.status}`;\n\t\t\ttry {\n\t\t\t\tconst body: { error?: string } = await response.json();\n\t\t\t\tif (body.error) errorMessage = body.error;\n\t\t\t} catch {\n\t\t\t\t// use default message\n\t\t\t}\n\t\t\tthrow new MarketplaceError(errorMessage, response.status);\n\t\t}\n\n\t\tconst data: T = await response.json();\n\t\treturn data;\n\t}\n}\n\n// ── Bundle extraction ──────────────────────────────────────────────\n\n/**\n * Extract manifest + code files from a tarball.\n *\n * The tarball is a gzipped tar archive containing:\n * - manifest.json\n * - backend.js\n * - admin.js (optional)\n *\n * We use a minimal tar parser since we only need to read a few small files.\n */\n/**\n * Exported so the experimental registry install handler can reuse the\n * same parse / validate / hash primitive. Despite the file name, this\n * function predates the marketplace-vs-registry split and is generic\n * over plugin bundle tarballs regardless of distribution channel.\n */\n// Aligns with RFC 0001 §\"Bundle size limits\" (256 KiB decompressed,\n// 20 files). Matches `MAX_BUNDLE_SIZE` in @emdash-cms/plugin-cli. We\n// don't import that constant to keep this runtime module independent\n// of the authoring CLI; the two values must stay in sync.\n//\n// Tar adds per-file headers (~512 bytes each) plus directory entries,\n// so the entry count cap is set comfortably above RFC's 20-file limit.\n// Going over either is a strong signal the bundle isn't a legitimate\n// sandboxed plugin.\nconst MAX_DECOMPRESSED_BUNDLE_BYTES = 256 * 1024;\nconst MAX_BUNDLE_TAR_ENTRIES = 32;\n\nexport async function extractBundle(tarballBytes: Uint8Array): Promise<PluginBundle> {\n\t// Decompress fully into memory first, then parse the tar.\n\t// Passing a pipeThrough() stream directly to unpackTar causes a backpressure\n\t// deadlock in workerd: the tar decoder's body-stream pull() needs more\n\t// decompressed data, but the upstream pipe is stalled waiting for the\n\t// decoder's writable side to drain — a circular dependency.\n\tconst decompressedStream = new ReadableStream<Uint8Array>({\n\t\tstart(controller) {\n\t\t\tcontroller.enqueue(tarballBytes);\n\t\t\tcontroller.close();\n\t\t},\n\t}).pipeThrough(createGzipDecoder());\n\n\t// Collect decompressed bytes with a hard cap. A gzip-bomb -- a small\n\t// tarball that decompresses to gigabytes -- otherwise exhausts\n\t// worker / Node memory before we know to reject it. The cap matches\n\t// RFC 0001's publish-time bundle size limit (MAX_DECOMPRESSED_BUNDLE_BYTES);\n\t// anything past that isn't a legitimate sandboxed plugin.\n\tconst reader = decompressedStream.getReader();\n\tconst chunks: Uint8Array[] = [];\n\tlet total = 0;\n\twhile (true) {\n\t\tconst { done, value } = await reader.read();\n\t\tif (done) break;\n\t\tif (!value) continue;\n\t\ttotal += value.byteLength;\n\t\tif (total > MAX_DECOMPRESSED_BUNDLE_BYTES) {\n\t\t\ttry {\n\t\t\t\tawait reader.cancel();\n\t\t\t} catch {\n\t\t\t\t// nothing to do\n\t\t\t}\n\t\t\tthrow new MarketplaceError(\n\t\t\t\t`Bundle decompressed size exceeds limit (${MAX_DECOMPRESSED_BUNDLE_BYTES} bytes)`,\n\t\t\t\tundefined,\n\t\t\t\t\"INVALID_BUNDLE\",\n\t\t\t);\n\t\t}\n\t\tchunks.push(value);\n\t}\n\tconst decompressedBytes = new Uint8Array(total);\n\t{\n\t\tlet offset = 0;\n\t\tfor (const chunk of chunks) {\n\t\t\tdecompressedBytes.set(chunk, offset);\n\t\t\toffset += chunk.byteLength;\n\t\t}\n\t}\n\n\tconst decompressed = new ReadableStream<Uint8Array>({\n\t\tstart(controller) {\n\t\t\tcontroller.enqueue(decompressedBytes);\n\t\t\tcontroller.close();\n\t\t},\n\t});\n\n\tconst entries = await unpackTar(decompressed);\n\tif (entries.length > MAX_BUNDLE_TAR_ENTRIES) {\n\t\tthrow new MarketplaceError(\n\t\t\t`Bundle has too many tar entries (${entries.length} > ${MAX_BUNDLE_TAR_ENTRIES})`,\n\t\t\tundefined,\n\t\t\t\"INVALID_BUNDLE\",\n\t\t);\n\t}\n\n\tconst decoder = new TextDecoder();\n\tconst files = new Map<string, string>();\n\tfor (const entry of entries) {\n\t\tif (entry.data && entry.header.type === \"file\") {\n\t\t\t// Strip leading ./ prefix that tar tools commonly add\n\t\t\tconst name = entry.header.name.replace(LEADING_DOT_SLASH, \"\");\n\t\t\tfiles.set(name, decoder.decode(entry.data));\n\t\t}\n\t}\n\n\tconst manifestJson = files.get(\"manifest.json\");\n\tconst backendCode = files.get(\"backend.js\");\n\n\tif (!manifestJson) {\n\t\tthrow new MarketplaceError(\n\t\t\t\"Invalid bundle: missing manifest.json\",\n\t\t\tundefined,\n\t\t\t\"INVALID_BUNDLE\",\n\t\t);\n\t}\n\tif (!backendCode) {\n\t\tthrow new MarketplaceError(\"Invalid bundle: missing backend.js\", undefined, \"INVALID_BUNDLE\");\n\t}\n\n\tlet manifest: PluginManifest;\n\ttry {\n\t\tconst parsed: unknown = JSON.parse(manifestJson);\n\t\tconst result = pluginManifestSchema.safeParse(parsed);\n\t\tif (!result.success) {\n\t\t\tthrow new MarketplaceError(\n\t\t\t\t\"Invalid bundle: manifest.json failed validation\",\n\t\t\t\tundefined,\n\t\t\t\t\"INVALID_BUNDLE\",\n\t\t\t);\n\t\t}\n\t\tmanifest = reconcileManifestAccess(result.data);\n\t} catch (err) {\n\t\tif (err instanceof MarketplaceError) throw err;\n\t\tthrow new MarketplaceError(\n\t\t\t\"Invalid bundle: malformed manifest.json\",\n\t\t\tundefined,\n\t\t\t\"INVALID_BUNDLE\",\n\t\t);\n\t}\n\n\t// Compute SHA-256 checksum of the tarball for verification\n\t// eslint-disable-next-line typescript/no-unsafe-type-assertion -- Uint8Array is a valid BufferSource at runtime; TS lib mismatch\n\tconst hashBuffer = await crypto.subtle.digest(\"SHA-256\", tarballBytes as unknown as BufferSource);\n\tconst hashArray = new Uint8Array(hashBuffer);\n\tconst checksum = Array.from(hashArray, (b) => b.toString(16).padStart(2, \"0\")).join(\"\");\n\n\treturn {\n\t\tmanifest,\n\t\tbackendCode,\n\t\tadminCode: files.get(\"admin.js\"),\n\t\tchecksum,\n\t};\n}\n\n// ── Helpers ────────────────────────────────────────────────────────\n\n/**\n * Generate a stable non-identifying site hash from the site origin.\n * The same origin always produces the same hash, so the marketplace\n * installs table deduplicates correctly per (plugin_id, site_hash).\n */\nasync function generateSiteHash(siteOrigin?: string): Promise<string> {\n\tconst seed = siteOrigin ? `emdash-site:${siteOrigin}` : `emdash-anonymous`;\n\ttry {\n\t\tconst hash = await crypto.subtle.digest(\"SHA-256\", new TextEncoder().encode(seed));\n\t\tconst arr = new Uint8Array(hash);\n\t\treturn Array.from(arr.slice(0, 8), (b) => b.toString(16).padStart(2, \"0\")).join(\"\");\n\t} catch {\n\t\t// Fallback for environments without crypto.subtle: FNV-1a hash encoded as hex.\n\t\t// Deterministic, uniform distribution, no origin leakage.\n\t\tlet h = 0x811c9dc5;\n\t\tfor (let i = 0; i < seed.length; i++) {\n\t\t\th ^= seed.charCodeAt(i);\n\t\t\th = Math.imul(h, 0x01000193);\n\t\t}\n\t\tconst h2 = h ^ (h >>> 16);\n\t\treturn (h >>> 0).toString(16).padStart(8, \"0\") + (h2 >>> 0).toString(16).padStart(8, \"0\");\n\t}\n}\n\n// ── Factory ────────────────────────────────────────────────────────\n\n/**\n * Create a MarketplaceClient for the given marketplace URL.\n *\n * @param baseUrl - The marketplace API base URL (e.g. \"https://marketplace.emdashcms.com\")\n * @param siteOrigin - The origin of the EmDash site (e.g. \"https://myblog.example.com\").\n * Used to generate a stable, non-identifying site hash for install deduplication.\n */\nexport function createMarketplaceClient(baseUrl: string, siteOrigin?: string): MarketplaceClient {\n\treturn new MarketplaceClientImpl(baseUrl, siteOrigin);\n}\n"],"mappings":"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"}
|
|
@@ -46,6 +46,30 @@ interface ImageTransformOptions {
|
|
|
46
46
|
declare const IMMUTABLE_IMAGE_CACHE = "public, max-age=31536000, immutable";
|
|
47
47
|
/** Cache policy for media keys that Replace original may overwrite. */
|
|
48
48
|
declare const MUTABLE_MEDIA_CACHE_CONTROL = "public, max-age=0, must-revalidate";
|
|
49
|
+
/**
|
|
50
|
+
* Format a Date as an HTTP-date (RFC 7231).
|
|
51
|
+
*/
|
|
52
|
+
declare function formatHttpDate(date: Date): string;
|
|
53
|
+
/**
|
|
54
|
+
* Build a weak validator from representation metadata. Weak because it is based
|
|
55
|
+
* on size and modification time rather than a content hash. Keeps the same
|
|
56
|
+
* shape for stored files and derived transforms so replacements change the tag.
|
|
57
|
+
*/
|
|
58
|
+
declare function makeWeakEtag(size: number, lastModified?: Date, suffix?: string): string;
|
|
59
|
+
/**
|
|
60
|
+
* Build a canonical fingerprint of the transform query params that affect the
|
|
61
|
+
* derived /_image bytes. Used as the suffix of a transform's weak ETag.
|
|
62
|
+
*/
|
|
63
|
+
declare function getTransformFingerprint(params: URLSearchParams): string;
|
|
64
|
+
/**
|
|
65
|
+
* Check whether a request's preconditions are satisfied for the given
|
|
66
|
+
* representation. Returns true when the client already has the current version.
|
|
67
|
+
*/
|
|
68
|
+
declare function isNotModified(request: Request, size: number, lastModified?: Date, suffix?: string): boolean;
|
|
69
|
+
/**
|
|
70
|
+
* Headers that make a mutable representation conditionally cacheable.
|
|
71
|
+
*/
|
|
72
|
+
declare function validatorHeaders(size: number, lastModified?: Date, suffix?: string): Record<string, string>;
|
|
49
73
|
/**
|
|
50
74
|
* Headers for streaming **original** stored bytes (the no-transform fallback).
|
|
51
75
|
* Carries the same stored-XSS protections as the media file route: a sandbox
|
|
@@ -53,7 +77,7 @@ declare const MUTABLE_MEDIA_CACHE_CONTROL = "public, max-age=0, must-revalidate"
|
|
|
53
77
|
* inline raster allowlist (so a stored SVG can't run scripts in the site
|
|
54
78
|
* origin). Transformed output is always generated raster and doesn't need this.
|
|
55
79
|
*/
|
|
56
|
-
declare function originalMediaHeaders(contentType: string): Record<string, string>;
|
|
80
|
+
declare function originalMediaHeaders(contentType: string, size?: number, lastModified?: Date): Record<string, string>;
|
|
57
81
|
/** Whether a storage key is safe to resolve against the storage backend. */
|
|
58
82
|
declare function isSafeTransformKey(key: string): boolean;
|
|
59
83
|
/**
|
|
@@ -100,5 +124,5 @@ declare function resolveTransformQuality(format: ImageTransformFormat, requested
|
|
|
100
124
|
*/
|
|
101
125
|
declare function parseTransformParams(params: URLSearchParams): ParsedTransformParams;
|
|
102
126
|
//#endregion
|
|
103
|
-
export { ALLOWED_TRANSFORM_FORMATS, DEFAULT_TRANSFORM_FORMAT, DEFAULT_TRANSFORM_QUALITY, IMMUTABLE_IMAGE_CACHE, ImageTransformFormat, ImageTransformOptions, MAX_TRANSFORM_DIMENSION, MUTABLE_MEDIA_CACHE_CONTROL, ParsedTransformParams, isSafeTransformKey, isTransformFormat, matchInternalMediaKey, originalMediaHeaders, parseTransformParams, resolveTransformQuality };
|
|
127
|
+
export { ALLOWED_TRANSFORM_FORMATS, DEFAULT_TRANSFORM_FORMAT, DEFAULT_TRANSFORM_QUALITY, IMMUTABLE_IMAGE_CACHE, ImageTransformFormat, ImageTransformOptions, MAX_TRANSFORM_DIMENSION, MUTABLE_MEDIA_CACHE_CONTROL, ParsedTransformParams, formatHttpDate, getTransformFingerprint, isNotModified, isSafeTransformKey, isTransformFormat, makeWeakEtag, matchInternalMediaKey, originalMediaHeaders, parseTransformParams, resolveTransformQuality, validatorHeaders };
|
|
104
128
|
//# sourceMappingURL=image-endpoint.d.mts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"image-endpoint.d.mts","names":[],"sources":["../../src/media/image-endpoint.ts"],"mappings":";;AAiBA;;;;;AAGA;;;;;AAWA;;;cAda,yBAAA;;cAGA,wBAAA,EAA0B,oBAAA;;;;;
|
|
1
|
+
{"version":3,"file":"image-endpoint.d.mts","names":[],"sources":["../../src/media/image-endpoint.ts"],"mappings":";;AAiBA;;;;;AAGA;;;;;AAWA;;;cAda,yBAAA;;cAGA,wBAAA,EAA0B,oBAAA;;;;;AA4BvC;;;;;cAjBa,yBAAA;;cAGA,uBAAA;;KAcD,oBAAA,WAA+B,yBAAA;;UAG1B,qBAAA;EAChB,KAAA;EACA,MAAA;EACA,MAAA,EAAQ,oBAAA;EAMD;AAIR;;;;EAJC,OAAA;AAAA;;cAIY,qBAAA;;cAGA,2BAAA;AAKb;;;AAAA,iBAAgB,cAAA,CAAe,IAAA,EAAM,IAAA;;AASrC;;;;iBAAgB,YAAA,CAAa,IAAA,UAAc,YAAA,GAAe,IAAA,EAAM,MAAA;;;;;iBAWhD,uBAAA,CAAwB,MAAA,EAAQ,eAAA;AAAhD;;;;AAAA,iBAkBgB,aAAA,CACf,OAAA,EAAS,OAAA,EACT,IAAA,UACA,YAAA,GAAe,IAAA,EACf,MAAA;AAJD;;;AAAA,iBA6BgB,gBAAA,CACf,IAAA,UACA,YAAA,GAAe,IAAA,EACf,MAAA,YACE,MAAA;;;;;;;;iBA+Ba,oBAAA,CACf,WAAA,UACA,IAAA,WACA,YAAA,GAAe,IAAA,GACb,MAAA;AAvCH;AAAA,iBA0DgB,kBAAA,CAAmB,GAAA;;;;;;;;;;AAvBnC;;;;iBAwCgB,qBAAA,CAAsB,IAAA;;iBAetB,iBAAA,CAAkB,KAAA,WAAgB,KAAA,IAAS,oBAAA;;KAK/C,qBAAA;EACP,EAAA;EAAU,OAAA,EAAS,qBAAA;AAAA;EACnB,EAAA;EAAW,OAAA;AAAA;;AAtBhB;;;;;AAeA;;iBAiBgB,uBAAA,CACf,MAAA,EAAQ,oBAAA,EACR,SAAA;;;;;;;AAdD;;;iBA6BgB,oBAAA,CAAqB,MAAA,EAAQ,eAAA,GAAkB,qBAAA"}
|
|
@@ -35,11 +35,80 @@ const DEFAULT_TRANSFORM_FORMAT = "webp";
|
|
|
35
35
|
const DEFAULT_TRANSFORM_QUALITY = 85;
|
|
36
36
|
/** Upper bound for a requested dimension; caps the work a single request asks for. */
|
|
37
37
|
const MAX_TRANSFORM_DIMENSION = 4e3;
|
|
38
|
+
/** Weak prefix on an ETag, stripped for weak comparison per RFC 7232. */
|
|
39
|
+
const WEAK_ETAG_PREFIX = /^W\//;
|
|
40
|
+
/**
|
|
41
|
+
* Strip surrounding whitespace and the weak prefix from an ETag value for
|
|
42
|
+
* weak comparison. Defined at module scope so it is not recreated per request.
|
|
43
|
+
*/
|
|
44
|
+
function stripWeakEtagPrefix(value) {
|
|
45
|
+
return value.trim().replace(WEAK_ETAG_PREFIX, "");
|
|
46
|
+
}
|
|
38
47
|
/** Long-lived cache for content-addressed image URLs. */
|
|
39
48
|
const IMMUTABLE_IMAGE_CACHE = "public, max-age=31536000, immutable";
|
|
40
49
|
/** Cache policy for media keys that Replace original may overwrite. */
|
|
41
50
|
const MUTABLE_MEDIA_CACHE_CONTROL = "public, max-age=0, must-revalidate";
|
|
42
51
|
/**
|
|
52
|
+
* Format a Date as an HTTP-date (RFC 7231).
|
|
53
|
+
*/
|
|
54
|
+
function formatHttpDate(date) {
|
|
55
|
+
return date.toUTCString();
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Build a weak validator from representation metadata. Weak because it is based
|
|
59
|
+
* on size and modification time rather than a content hash. Keeps the same
|
|
60
|
+
* shape for stored files and derived transforms so replacements change the tag.
|
|
61
|
+
*/
|
|
62
|
+
function makeWeakEtag(size, lastModified, suffix) {
|
|
63
|
+
let value = String(size);
|
|
64
|
+
if (lastModified) value += `-${lastModified.getTime()}`;
|
|
65
|
+
if (suffix) value += `-${suffix}`;
|
|
66
|
+
return `W/"${value}"`;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Build a canonical fingerprint of the transform query params that affect the
|
|
70
|
+
* derived /_image bytes. Used as the suffix of a transform's weak ETag.
|
|
71
|
+
*/
|
|
72
|
+
function getTransformFingerprint(params) {
|
|
73
|
+
const parts = [];
|
|
74
|
+
const append = (name) => {
|
|
75
|
+
const value = params.get(name);
|
|
76
|
+
if (value !== null) parts.push(`${name}=${value}`);
|
|
77
|
+
};
|
|
78
|
+
append("w");
|
|
79
|
+
append("h");
|
|
80
|
+
append("f");
|
|
81
|
+
append("q");
|
|
82
|
+
append("fit");
|
|
83
|
+
return parts.join("&");
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Check whether a request's preconditions are satisfied for the given
|
|
87
|
+
* representation. Returns true when the client already has the current version.
|
|
88
|
+
*/
|
|
89
|
+
function isNotModified(request, size, lastModified, suffix) {
|
|
90
|
+
const etag = makeWeakEtag(size, lastModified, suffix);
|
|
91
|
+
const ifNoneMatch = request.headers.get("If-None-Match");
|
|
92
|
+
if (ifNoneMatch !== null) {
|
|
93
|
+
if (ifNoneMatch.trim() === "*") return true;
|
|
94
|
+
return ifNoneMatch.split(",").map(stripWeakEtagPrefix).includes(stripWeakEtagPrefix(etag));
|
|
95
|
+
}
|
|
96
|
+
const ifModifiedSince = request.headers.get("If-Modified-Since");
|
|
97
|
+
if (ifModifiedSince !== null && lastModified) {
|
|
98
|
+
const since = Date.parse(ifModifiedSince);
|
|
99
|
+
if (!Number.isNaN(since)) return Math.floor(lastModified.getTime() / 1e3) * 1e3 <= since;
|
|
100
|
+
}
|
|
101
|
+
return false;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Headers that make a mutable representation conditionally cacheable.
|
|
105
|
+
*/
|
|
106
|
+
function validatorHeaders(size, lastModified, suffix) {
|
|
107
|
+
const headers = { ETag: makeWeakEtag(size, lastModified, suffix) };
|
|
108
|
+
if (lastModified) headers["Last-Modified"] = formatHttpDate(lastModified);
|
|
109
|
+
return headers;
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
43
112
|
* Raster types safe to render inline. Anything else (SVG, PDF, ...) is served
|
|
44
113
|
* as an attachment so it can't execute as an active document. Mirrors the
|
|
45
114
|
* `/_emdash/api/media/file/{key}` route's allowlist.
|
|
@@ -59,13 +128,14 @@ const SAFE_INLINE_IMAGE_TYPES = new Set([
|
|
|
59
128
|
* inline raster allowlist (so a stored SVG can't run scripts in the site
|
|
60
129
|
* origin). Transformed output is always generated raster and doesn't need this.
|
|
61
130
|
*/
|
|
62
|
-
function originalMediaHeaders(contentType) {
|
|
131
|
+
function originalMediaHeaders(contentType, size, lastModified) {
|
|
63
132
|
return {
|
|
64
133
|
"Content-Type": contentType,
|
|
65
134
|
"Cache-Control": MUTABLE_MEDIA_CACHE_CONTROL,
|
|
66
135
|
"X-Content-Type-Options": "nosniff",
|
|
67
136
|
"Content-Security-Policy": "sandbox; default-src 'none'; img-src 'self'; style-src 'unsafe-inline'",
|
|
68
|
-
"Content-Disposition": SAFE_INLINE_IMAGE_TYPES.has(contentType) ? "inline" : "attachment"
|
|
137
|
+
"Content-Disposition": SAFE_INLINE_IMAGE_TYPES.has(contentType) ? "inline" : "attachment",
|
|
138
|
+
...size !== void 0 ? validatorHeaders(size, lastModified) : {}
|
|
69
139
|
};
|
|
70
140
|
}
|
|
71
141
|
/** Storage keys safe to serve: the flat `{ulid}{ext}` shape, no slashes/traversal. */
|
|
@@ -186,5 +256,5 @@ function parseDimension(raw) {
|
|
|
186
256
|
}
|
|
187
257
|
|
|
188
258
|
//#endregion
|
|
189
|
-
export { ALLOWED_TRANSFORM_FORMATS, DEFAULT_TRANSFORM_FORMAT, DEFAULT_TRANSFORM_QUALITY, IMMUTABLE_IMAGE_CACHE, MAX_TRANSFORM_DIMENSION, MUTABLE_MEDIA_CACHE_CONTROL, isSafeTransformKey, isTransformFormat, matchInternalMediaKey, originalMediaHeaders, parseTransformParams, resolveTransformQuality };
|
|
259
|
+
export { ALLOWED_TRANSFORM_FORMATS, DEFAULT_TRANSFORM_FORMAT, DEFAULT_TRANSFORM_QUALITY, IMMUTABLE_IMAGE_CACHE, MAX_TRANSFORM_DIMENSION, MUTABLE_MEDIA_CACHE_CONTROL, formatHttpDate, getTransformFingerprint, isNotModified, isSafeTransformKey, isTransformFormat, makeWeakEtag, matchInternalMediaKey, originalMediaHeaders, parseTransformParams, resolveTransformQuality, validatorHeaders };
|
|
190
260
|
//# sourceMappingURL=image-endpoint.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"image-endpoint.mjs","names":[],"sources":["../../src/media/image-endpoint.ts"],"sourcesContent":["/**\n * Portable helpers shared by the platform image-endpoint modules.\n *\n * EmDash wraps Astro's image endpoint (`image.endpoint`) so that source bytes\n * for EmDash media are read straight from the storage adapter instead of being\n * fetched over HTTP. The platform endpoint modules (Node: sharp via\n * `astro:assets`; Cloudflare: the `IMAGES` binding) do the actual transform;\n * this module holds the platform-agnostic bits they share: recognizing an\n * EmDash media URL and validating transform query params.\n *\n * Kept free of `astro:*` / `virtual:emdash/*` imports so it stays in the\n * precompiled package and can be unit-tested directly.\n */\n\nimport { INTERNAL_MEDIA_PREFIX } from \"./normalize.js\";\n\n/** Output formats the wrapped endpoint can produce on Cloudflare. */\nexport const ALLOWED_TRANSFORM_FORMATS = [\"webp\", \"avif\", \"jpeg\", \"png\"] as const;\n\n/** Default output format -- broad support, strong compression. */\nexport const DEFAULT_TRANSFORM_FORMAT: ImageTransformFormat = \"webp\";\n\n/**\n * Default output quality for lossy formats (WebP/AVIF/JPEG) when the request\n * doesn't specify one. Matches the default Cloudflare applies to URL-based\n * image transformations. The Images *binding* applies no default of its own\n * and encodes near-losslessly when quality is omitted (a 2048px WebP comes\n * out ~900 KB instead of ~100 KB), so the endpoint sends an explicit quality\n * for lossy output. PNG is exempt: an explicit PNG quality switches the\n * binding to lossy PNG8, which is not a safe default for a lossless format.\n */\nexport const DEFAULT_TRANSFORM_QUALITY = 85;\n\n/** Upper bound for a requested dimension; caps the work a single request asks for. */\nexport const MAX_TRANSFORM_DIMENSION = 4000;\n\n/** A format string accepted by {@link ImageTransformOptions.format}. */\nexport type ImageTransformFormat = (typeof ALLOWED_TRANSFORM_FORMATS)[number];\n\n/** Validated options for a single transform. */\nexport interface ImageTransformOptions {\n\twidth?: number;\n\theight?: number;\n\tformat: ImageTransformFormat;\n\t/**\n\t * Explicitly-requested quality (1-100), or `undefined` when the request\n\t * carried no `q`. Callers apply their own default per format (see\n\t * {@link DEFAULT_TRANSFORM_QUALITY}); lossless PNG deliberately gets none.\n\t */\n\tquality?: number;\n}\n\n/** Long-lived cache for content-addressed image URLs. */\nexport const IMMUTABLE_IMAGE_CACHE = \"public, max-age=31536000, immutable\";\n\n/** Cache policy for media keys that Replace original may overwrite. */\nexport const MUTABLE_MEDIA_CACHE_CONTROL = \"public, max-age=0, must-revalidate\";\n\n/**\n * Raster types safe to render inline. Anything else (SVG, PDF, ...) is served\n * as an attachment so it can't execute as an active document. Mirrors the\n * `/_emdash/api/media/file/{key}` route's allowlist.\n */\nconst SAFE_INLINE_IMAGE_TYPES = new Set([\n\t\"image/jpeg\",\n\t\"image/png\",\n\t\"image/gif\",\n\t\"image/webp\",\n\t\"image/avif\",\n\t\"image/x-icon\",\n]);\n\n/**\n * Headers for streaming **original** stored bytes (the no-transform fallback).\n * Carries the same stored-XSS protections as the media file route: a sandbox\n * CSP, `nosniff`, and `Content-Disposition: attachment` for anything not on the\n * inline raster allowlist (so a stored SVG can't run scripts in the site\n * origin). Transformed output is always generated raster and doesn't need this.\n */\nexport function originalMediaHeaders(contentType: string): Record<string, string> {\n\treturn {\n\t\t\"Content-Type\": contentType,\n\t\t\"Cache-Control\": MUTABLE_MEDIA_CACHE_CONTROL,\n\t\t\"X-Content-Type-Options\": \"nosniff\",\n\t\t\"Content-Security-Policy\":\n\t\t\t\"sandbox; default-src 'none'; img-src 'self'; style-src 'unsafe-inline'\",\n\t\t\"Content-Disposition\": SAFE_INLINE_IMAGE_TYPES.has(contentType) ? \"inline\" : \"attachment\",\n\t};\n}\n\n/** Storage keys safe to serve: the flat `{ulid}{ext}` shape, no slashes/traversal. */\nconst SAFE_STORAGE_KEY = /^[A-Za-z0-9._-]+$/;\n\n/** Plain decimal digits only -- rejects \"1e3\", \"0x10\", \"+5\", whitespace. */\nconst DECIMAL_DIGITS = /^\\d+$/;\n\n/** Whether a storage key is safe to resolve against the storage backend. */\nexport function isSafeTransformKey(key: string): boolean {\n\treturn SAFE_STORAGE_KEY.test(key);\n}\n\n/**\n * If `href` points at the internal EmDash media route\n * (`/_emdash/api/media/file/{key}`) with a safe key, return the key; otherwise\n * `null` (the endpoint then delegates to the stock image endpoint for bundled\n * assets, allowed remote, and `publicUrl` media).\n *\n * The component absolutizes same-origin media (Astro only optimizes absolute,\n * remote-allowed URLs), so `href` is typically `https://site/_emdash/...` but\n * may be relative. We match on the **pathname** only and never fetch `href` —\n * the key is read from our own storage — so the host is irrelevant and can't be\n * an SSRF vector. A dummy base resolves both absolute and relative forms and\n * strips any query/fragment.\n */\nexport function matchInternalMediaKey(href: string | null | undefined): string | null {\n\tif (!href) return null;\n\tlet pathname: string;\n\ttry {\n\t\tpathname = new URL(href, \"http://localhost\").pathname;\n\t} catch {\n\t\treturn null;\n\t}\n\tif (!pathname.startsWith(INTERNAL_MEDIA_PREFIX)) return null;\n\tconst key = pathname.slice(INTERNAL_MEDIA_PREFIX.length);\n\tif (!key || !isSafeTransformKey(key)) return null;\n\treturn key;\n}\n\n/** Type guard for {@link ImageTransformFormat}. */\nexport function isTransformFormat(value: string): value is ImageTransformFormat {\n\treturn (ALLOWED_TRANSFORM_FORMATS as readonly string[]).includes(value);\n}\n\n/** Outcome of parsing transform query params: validated options or an error. */\nexport type ParsedTransformParams =\n\t| { ok: true; options: ImageTransformOptions }\n\t| { ok: false; message: string };\n\n/**\n * Resolve the quality to send to the image binding for a transform. An\n * explicitly-requested quality always wins. Otherwise lossy formats\n * (WebP/AVIF/JPEG) get {@link DEFAULT_TRANSFORM_QUALITY} because the Images\n * binding encodes near-losslessly when quality is omitted; lossless PNG gets\n * `undefined` because an explicit PNG quality switches the binding to lossy\n * PNG8, which is not a safe default for a lossless format.\n */\nexport function resolveTransformQuality(\n\tformat: ImageTransformFormat,\n\trequested: number | undefined,\n): number | undefined {\n\tif (requested !== undefined) return requested;\n\treturn format === \"png\" ? undefined : DEFAULT_TRANSFORM_QUALITY;\n}\n\n/**\n * Parse and validate `?w=&h=&f=&q=` query params. Width is required (it sizes\n * the rendition); dimensions are bounded so a request can't ask for an\n * unbounded or nonsensical transform. Format falls back to\n * {@link DEFAULT_TRANSFORM_FORMAT} when not requested. `q` is validated when\n * present but otherwise left `undefined` so the caller can apply a per-format\n * default (lossy formats get one, lossless PNG does not — see\n * {@link DEFAULT_TRANSFORM_QUALITY}).\n */\nexport function parseTransformParams(params: URLSearchParams): ParsedTransformParams {\n\tconst width = parseDimension(params.get(\"w\"));\n\tif (width === null) return { ok: false, message: \"Invalid 'w' (width)\" };\n\tif (width === undefined) return { ok: false, message: \"Missing 'w' (width)\" };\n\n\tconst height = parseDimension(params.get(\"h\"));\n\tif (height === null) return { ok: false, message: \"Invalid 'h' (height)\" };\n\n\tconst formatRaw = params.get(\"f\");\n\tlet format: ImageTransformFormat = DEFAULT_TRANSFORM_FORMAT;\n\tif (formatRaw !== null) {\n\t\tif (!isTransformFormat(formatRaw)) {\n\t\t\treturn { ok: false, message: `Unsupported 'f' (format): ${formatRaw}` };\n\t\t}\n\t\tformat = formatRaw;\n\t}\n\n\tlet quality: number | undefined;\n\tconst qualityRaw = params.get(\"q\");\n\tif (qualityRaw !== null) {\n\t\tconst q = Number(qualityRaw);\n\t\tif (!Number.isInteger(q) || q < 1 || q > 100) {\n\t\t\treturn { ok: false, message: \"Invalid 'q' (quality), expected 1-100\" };\n\t\t}\n\t\tquality = q;\n\t}\n\n\treturn { ok: true, options: { width, height, format, quality } };\n}\n\n/**\n * Parse a dimension query value.\n * - `undefined`: param absent\n * - `null`: present but invalid (non-integer, out of range)\n * - `number`: valid, within [1, MAX_TRANSFORM_DIMENSION]\n */\nfunction parseDimension(raw: string | null): number | undefined | null {\n\tif (raw === null) return undefined;\n\tif (!DECIMAL_DIGITS.test(raw)) return null;\n\tconst n = Number(raw);\n\tif (n < 1 || n > MAX_TRANSFORM_DIMENSION) return null;\n\treturn n;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;AAiBA,MAAa,4BAA4B;CAAC;CAAQ;CAAQ;CAAQ;CAAM;;AAGxE,MAAa,2BAAiD;;;;;;;;;;AAW9D,MAAa,4BAA4B;;AAGzC,MAAa,0BAA0B;;AAmBvC,MAAa,wBAAwB;;AAGrC,MAAa,8BAA8B;;;;;;AAO3C,MAAM,0BAA0B,IAAI,IAAI;CACvC;CACA;CACA;CACA;CACA;CACA;CACA,CAAC;;;;;;;;AASF,SAAgB,qBAAqB,aAA6C;AACjF,QAAO;EACN,gBAAgB;EAChB,iBAAiB;EACjB,0BAA0B;EAC1B,2BACC;EACD,uBAAuB,wBAAwB,IAAI,YAAY,GAAG,WAAW;EAC7E;;;AAIF,MAAM,mBAAmB;;AAGzB,MAAM,iBAAiB;;AAGvB,SAAgB,mBAAmB,KAAsB;AACxD,QAAO,iBAAiB,KAAK,IAAI;;;;;;;;;;;;;;;AAgBlC,SAAgB,sBAAsB,MAAgD;AACrF,KAAI,CAAC,KAAM,QAAO;CAClB,IAAI;AACJ,KAAI;AACH,aAAW,IAAI,IAAI,MAAM,mBAAmB,CAAC;SACtC;AACP,SAAO;;AAER,KAAI,CAAC,SAAS,WAAW,sBAAsB,CAAE,QAAO;CACxD,MAAM,MAAM,SAAS,MAAM,sBAAsB,OAAO;AACxD,KAAI,CAAC,OAAO,CAAC,mBAAmB,IAAI,CAAE,QAAO;AAC7C,QAAO;;;AAIR,SAAgB,kBAAkB,OAA8C;AAC/E,QAAQ,0BAAgD,SAAS,MAAM;;;;;;;;;;AAgBxE,SAAgB,wBACf,QACA,WACqB;AACrB,KAAI,cAAc,OAAW,QAAO;AACpC,QAAO,WAAW,QAAQ,SAAY;;;;;;;;;;;AAYvC,SAAgB,qBAAqB,QAAgD;CACpF,MAAM,QAAQ,eAAe,OAAO,IAAI,IAAI,CAAC;AAC7C,KAAI,UAAU,KAAM,QAAO;EAAE,IAAI;EAAO,SAAS;EAAuB;AACxE,KAAI,UAAU,OAAW,QAAO;EAAE,IAAI;EAAO,SAAS;EAAuB;CAE7E,MAAM,SAAS,eAAe,OAAO,IAAI,IAAI,CAAC;AAC9C,KAAI,WAAW,KAAM,QAAO;EAAE,IAAI;EAAO,SAAS;EAAwB;CAE1E,MAAM,YAAY,OAAO,IAAI,IAAI;CACjC,IAAI,SAA+B;AACnC,KAAI,cAAc,MAAM;AACvB,MAAI,CAAC,kBAAkB,UAAU,CAChC,QAAO;GAAE,IAAI;GAAO,SAAS,6BAA6B;GAAa;AAExE,WAAS;;CAGV,IAAI;CACJ,MAAM,aAAa,OAAO,IAAI,IAAI;AAClC,KAAI,eAAe,MAAM;EACxB,MAAM,IAAI,OAAO,WAAW;AAC5B,MAAI,CAAC,OAAO,UAAU,EAAE,IAAI,IAAI,KAAK,IAAI,IACxC,QAAO;GAAE,IAAI;GAAO,SAAS;GAAyC;AAEvE,YAAU;;AAGX,QAAO;EAAE,IAAI;EAAM,SAAS;GAAE;GAAO;GAAQ;GAAQ;GAAS;EAAE;;;;;;;;AASjE,SAAS,eAAe,KAA+C;AACtE,KAAI,QAAQ,KAAM,QAAO;AACzB,KAAI,CAAC,eAAe,KAAK,IAAI,CAAE,QAAO;CACtC,MAAM,IAAI,OAAO,IAAI;AACrB,KAAI,IAAI,KAAK,IAAI,wBAAyB,QAAO;AACjD,QAAO"}
|
|
1
|
+
{"version":3,"file":"image-endpoint.mjs","names":[],"sources":["../../src/media/image-endpoint.ts"],"sourcesContent":["/**\n * Portable helpers shared by the platform image-endpoint modules.\n *\n * EmDash wraps Astro's image endpoint (`image.endpoint`) so that source bytes\n * for EmDash media are read straight from the storage adapter instead of being\n * fetched over HTTP. The platform endpoint modules (Node: sharp via\n * `astro:assets`; Cloudflare: the `IMAGES` binding) do the actual transform;\n * this module holds the platform-agnostic bits they share: recognizing an\n * EmDash media URL and validating transform query params.\n *\n * Kept free of `astro:*` / `virtual:emdash/*` imports so it stays in the\n * precompiled package and can be unit-tested directly.\n */\n\nimport { INTERNAL_MEDIA_PREFIX } from \"./normalize.js\";\n\n/** Output formats the wrapped endpoint can produce on Cloudflare. */\nexport const ALLOWED_TRANSFORM_FORMATS = [\"webp\", \"avif\", \"jpeg\", \"png\"] as const;\n\n/** Default output format -- broad support, strong compression. */\nexport const DEFAULT_TRANSFORM_FORMAT: ImageTransformFormat = \"webp\";\n\n/**\n * Default output quality for lossy formats (WebP/AVIF/JPEG) when the request\n * doesn't specify one. Matches the default Cloudflare applies to URL-based\n * image transformations. The Images *binding* applies no default of its own\n * and encodes near-losslessly when quality is omitted (a 2048px WebP comes\n * out ~900 KB instead of ~100 KB), so the endpoint sends an explicit quality\n * for lossy output. PNG is exempt: an explicit PNG quality switches the\n * binding to lossy PNG8, which is not a safe default for a lossless format.\n */\nexport const DEFAULT_TRANSFORM_QUALITY = 85;\n\n/** Upper bound for a requested dimension; caps the work a single request asks for. */\nexport const MAX_TRANSFORM_DIMENSION = 4000;\n\n/** Weak prefix on an ETag, stripped for weak comparison per RFC 7232. */\nconst WEAK_ETAG_PREFIX = /^W\\//;\n\n/**\n * Strip surrounding whitespace and the weak prefix from an ETag value for\n * weak comparison. Defined at module scope so it is not recreated per request.\n */\nfunction stripWeakEtagPrefix(value: string): string {\n\treturn value.trim().replace(WEAK_ETAG_PREFIX, \"\");\n}\n\n/** A format string accepted by {@link ImageTransformOptions.format}. */\nexport type ImageTransformFormat = (typeof ALLOWED_TRANSFORM_FORMATS)[number];\n\n/** Validated options for a single transform. */\nexport interface ImageTransformOptions {\n\twidth?: number;\n\theight?: number;\n\tformat: ImageTransformFormat;\n\t/**\n\t * Explicitly-requested quality (1-100), or `undefined` when the request\n\t * carried no `q`. Callers apply their own default per format (see\n\t * {@link DEFAULT_TRANSFORM_QUALITY}); lossless PNG deliberately gets none.\n\t */\n\tquality?: number;\n}\n\n/** Long-lived cache for content-addressed image URLs. */\nexport const IMMUTABLE_IMAGE_CACHE = \"public, max-age=31536000, immutable\";\n\n/** Cache policy for media keys that Replace original may overwrite. */\nexport const MUTABLE_MEDIA_CACHE_CONTROL = \"public, max-age=0, must-revalidate\";\n\n/**\n * Format a Date as an HTTP-date (RFC 7231).\n */\nexport function formatHttpDate(date: Date): string {\n\treturn date.toUTCString();\n}\n\n/**\n * Build a weak validator from representation metadata. Weak because it is based\n * on size and modification time rather than a content hash. Keeps the same\n * shape for stored files and derived transforms so replacements change the tag.\n */\nexport function makeWeakEtag(size: number, lastModified?: Date, suffix?: string): string {\n\tlet value = String(size);\n\tif (lastModified) value += `-${lastModified.getTime()}`;\n\tif (suffix) value += `-${suffix}`;\n\treturn `W/\"${value}\"`;\n}\n\n/**\n * Build a canonical fingerprint of the transform query params that affect the\n * derived /_image bytes. Used as the suffix of a transform's weak ETag.\n */\nexport function getTransformFingerprint(params: URLSearchParams): string {\n\tconst parts: string[] = [];\n\tconst append = (name: string) => {\n\t\tconst value = params.get(name);\n\t\tif (value !== null) parts.push(`${name}=${value}`);\n\t};\n\tappend(\"w\");\n\tappend(\"h\");\n\tappend(\"f\");\n\tappend(\"q\");\n\tappend(\"fit\");\n\treturn parts.join(\"&\");\n}\n\n/**\n * Check whether a request's preconditions are satisfied for the given\n * representation. Returns true when the client already has the current version.\n */\nexport function isNotModified(\n\trequest: Request,\n\tsize: number,\n\tlastModified?: Date,\n\tsuffix?: string,\n): boolean {\n\tconst etag = makeWeakEtag(size, lastModified, suffix);\n\tconst ifNoneMatch = request.headers.get(\"If-None-Match\");\n\tif (ifNoneMatch !== null) {\n\t\tif (ifNoneMatch.trim() === \"*\") return true;\n\t\t// If-None-Match uses weak comparison: \"W/\" prefixes are ignored.\n\t\tconst requestedTags = ifNoneMatch.split(\",\").map(stripWeakEtagPrefix);\n\t\treturn requestedTags.includes(stripWeakEtagPrefix(etag));\n\t}\n\tconst ifModifiedSince = request.headers.get(\"If-Modified-Since\");\n\tif (ifModifiedSince !== null && lastModified) {\n\t\tconst since = Date.parse(ifModifiedSince);\n\t\tif (!Number.isNaN(since)) {\n\t\t\t// HTTP-date has one-second precision; round the stored time down so\n\t\t\t// a Last-Modified header replayed as If-Modified-Since always matches.\n\t\t\treturn Math.floor(lastModified.getTime() / 1000) * 1000 <= since;\n\t\t}\n\t}\n\treturn false;\n}\n\n/**\n * Headers that make a mutable representation conditionally cacheable.\n */\nexport function validatorHeaders(\n\tsize: number,\n\tlastModified?: Date,\n\tsuffix?: string,\n): Record<string, string> {\n\tconst headers: Record<string, string> = {\n\t\tETag: makeWeakEtag(size, lastModified, suffix),\n\t};\n\tif (lastModified) {\n\t\theaders[\"Last-Modified\"] = formatHttpDate(lastModified);\n\t}\n\treturn headers;\n}\n\n/**\n * Raster types safe to render inline. Anything else (SVG, PDF, ...) is served\n * as an attachment so it can't execute as an active document. Mirrors the\n * `/_emdash/api/media/file/{key}` route's allowlist.\n */\nconst SAFE_INLINE_IMAGE_TYPES = new Set([\n\t\"image/jpeg\",\n\t\"image/png\",\n\t\"image/gif\",\n\t\"image/webp\",\n\t\"image/avif\",\n\t\"image/x-icon\",\n]);\n\n/**\n * Headers for streaming **original** stored bytes (the no-transform fallback).\n * Carries the same stored-XSS protections as the media file route: a sandbox\n * CSP, `nosniff`, and `Content-Disposition: attachment` for anything not on the\n * inline raster allowlist (so a stored SVG can't run scripts in the site\n * origin). Transformed output is always generated raster and doesn't need this.\n */\nexport function originalMediaHeaders(\n\tcontentType: string,\n\tsize?: number,\n\tlastModified?: Date,\n): Record<string, string> {\n\treturn {\n\t\t\"Content-Type\": contentType,\n\t\t\"Cache-Control\": MUTABLE_MEDIA_CACHE_CONTROL,\n\t\t\"X-Content-Type-Options\": \"nosniff\",\n\t\t\"Content-Security-Policy\":\n\t\t\t\"sandbox; default-src 'none'; img-src 'self'; style-src 'unsafe-inline'\",\n\t\t\"Content-Disposition\": SAFE_INLINE_IMAGE_TYPES.has(contentType) ? \"inline\" : \"attachment\",\n\t\t...(size !== undefined ? validatorHeaders(size, lastModified) : {}),\n\t};\n}\n\n/** Storage keys safe to serve: the flat `{ulid}{ext}` shape, no slashes/traversal. */\nconst SAFE_STORAGE_KEY = /^[A-Za-z0-9._-]+$/;\n\n/** Plain decimal digits only -- rejects \"1e3\", \"0x10\", \"+5\", whitespace. */\nconst DECIMAL_DIGITS = /^\\d+$/;\n\n/** Whether a storage key is safe to resolve against the storage backend. */\nexport function isSafeTransformKey(key: string): boolean {\n\treturn SAFE_STORAGE_KEY.test(key);\n}\n\n/**\n * If `href` points at the internal EmDash media route\n * (`/_emdash/api/media/file/{key}`) with a safe key, return the key; otherwise\n * `null` (the endpoint then delegates to the stock image endpoint for bundled\n * assets, allowed remote, and `publicUrl` media).\n *\n * The component absolutizes same-origin media (Astro only optimizes absolute,\n * remote-allowed URLs), so `href` is typically `https://site/_emdash/...` but\n * may be relative. We match on the **pathname** only and never fetch `href` —\n * the key is read from our own storage — so the host is irrelevant and can't be\n * an SSRF vector. A dummy base resolves both absolute and relative forms and\n * strips any query/fragment.\n */\nexport function matchInternalMediaKey(href: string | null | undefined): string | null {\n\tif (!href) return null;\n\tlet pathname: string;\n\ttry {\n\t\tpathname = new URL(href, \"http://localhost\").pathname;\n\t} catch {\n\t\treturn null;\n\t}\n\tif (!pathname.startsWith(INTERNAL_MEDIA_PREFIX)) return null;\n\tconst key = pathname.slice(INTERNAL_MEDIA_PREFIX.length);\n\tif (!key || !isSafeTransformKey(key)) return null;\n\treturn key;\n}\n\n/** Type guard for {@link ImageTransformFormat}. */\nexport function isTransformFormat(value: string): value is ImageTransformFormat {\n\treturn (ALLOWED_TRANSFORM_FORMATS as readonly string[]).includes(value);\n}\n\n/** Outcome of parsing transform query params: validated options or an error. */\nexport type ParsedTransformParams =\n\t| { ok: true; options: ImageTransformOptions }\n\t| { ok: false; message: string };\n\n/**\n * Resolve the quality to send to the image binding for a transform. An\n * explicitly-requested quality always wins. Otherwise lossy formats\n * (WebP/AVIF/JPEG) get {@link DEFAULT_TRANSFORM_QUALITY} because the Images\n * binding encodes near-losslessly when quality is omitted; lossless PNG gets\n * `undefined` because an explicit PNG quality switches the binding to lossy\n * PNG8, which is not a safe default for a lossless format.\n */\nexport function resolveTransformQuality(\n\tformat: ImageTransformFormat,\n\trequested: number | undefined,\n): number | undefined {\n\tif (requested !== undefined) return requested;\n\treturn format === \"png\" ? undefined : DEFAULT_TRANSFORM_QUALITY;\n}\n\n/**\n * Parse and validate `?w=&h=&f=&q=` query params. Width is required (it sizes\n * the rendition); dimensions are bounded so a request can't ask for an\n * unbounded or nonsensical transform. Format falls back to\n * {@link DEFAULT_TRANSFORM_FORMAT} when not requested. `q` is validated when\n * present but otherwise left `undefined` so the caller can apply a per-format\n * default (lossy formats get one, lossless PNG does not — see\n * {@link DEFAULT_TRANSFORM_QUALITY}).\n */\nexport function parseTransformParams(params: URLSearchParams): ParsedTransformParams {\n\tconst width = parseDimension(params.get(\"w\"));\n\tif (width === null) return { ok: false, message: \"Invalid 'w' (width)\" };\n\tif (width === undefined) return { ok: false, message: \"Missing 'w' (width)\" };\n\n\tconst height = parseDimension(params.get(\"h\"));\n\tif (height === null) return { ok: false, message: \"Invalid 'h' (height)\" };\n\n\tconst formatRaw = params.get(\"f\");\n\tlet format: ImageTransformFormat = DEFAULT_TRANSFORM_FORMAT;\n\tif (formatRaw !== null) {\n\t\tif (!isTransformFormat(formatRaw)) {\n\t\t\treturn { ok: false, message: `Unsupported 'f' (format): ${formatRaw}` };\n\t\t}\n\t\tformat = formatRaw;\n\t}\n\n\tlet quality: number | undefined;\n\tconst qualityRaw = params.get(\"q\");\n\tif (qualityRaw !== null) {\n\t\tconst q = Number(qualityRaw);\n\t\tif (!Number.isInteger(q) || q < 1 || q > 100) {\n\t\t\treturn { ok: false, message: \"Invalid 'q' (quality), expected 1-100\" };\n\t\t}\n\t\tquality = q;\n\t}\n\n\treturn { ok: true, options: { width, height, format, quality } };\n}\n\n/**\n * Parse a dimension query value.\n * - `undefined`: param absent\n * - `null`: present but invalid (non-integer, out of range)\n * - `number`: valid, within [1, MAX_TRANSFORM_DIMENSION]\n */\nfunction parseDimension(raw: string | null): number | undefined | null {\n\tif (raw === null) return undefined;\n\tif (!DECIMAL_DIGITS.test(raw)) return null;\n\tconst n = Number(raw);\n\tif (n < 1 || n > MAX_TRANSFORM_DIMENSION) return null;\n\treturn n;\n}\n"],"mappings":"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"}
|
package/dist/media/index.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { _ as MediaValue, a as ComponentEmbed, b as mediaItemToValue, c as EmbedResult, d as MediaListResult, f as MediaProvider, g as MediaUploadInput, h as MediaProviderItem, i as AudioEmbed, l as ImageEmbed, m as MediaProviderDescriptor, n as generatePlaceholder, o as CreateMediaProviderFn, p as MediaProviderCapabilities, r as normalizeMediaValue, s as EmbedOptions, t as PlaceholderData, u as MediaListOptions, v as ThumbnailOptions, y as VideoEmbed } from "../placeholder-
|
|
1
|
+
import { _ as MediaValue, a as ComponentEmbed, b as mediaItemToValue, c as EmbedResult, d as MediaListResult, f as MediaProvider, g as MediaUploadInput, h as MediaProviderItem, i as AudioEmbed, l as ImageEmbed, m as MediaProviderDescriptor, n as generatePlaceholder, o as CreateMediaProviderFn, p as MediaProviderCapabilities, r as normalizeMediaValue, s as EmbedOptions, t as PlaceholderData, u as MediaListOptions, v as ThumbnailOptions, y as VideoEmbed } from "../placeholder-nOep3_Gn.mjs";
|
|
2
2
|
|
|
3
3
|
//#region src/media/enrich.d.ts
|
|
4
4
|
/**
|
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
import "../parse-
|
|
2
|
-
import { t as Database } from "../types-
|
|
3
|
-
import "../types-
|
|
4
|
-
import "../options-
|
|
5
|
-
import "../entry-lock-
|
|
6
|
-
import { h as MediaProviderItem, o as CreateMediaProviderFn } from "../placeholder-
|
|
7
|
-
import "../config-
|
|
8
|
-
import "../runner-
|
|
9
|
-
import "../storage-query-
|
|
10
|
-
import "../index-
|
|
11
|
-
import {
|
|
12
|
-
import "../types-
|
|
13
|
-
import "../hreflang-
|
|
14
|
-
import "../validate-
|
|
1
|
+
import "../parse-BOGhrwSq.mjs";
|
|
2
|
+
import { t as Database } from "../types-UKr5Sf4y.mjs";
|
|
3
|
+
import "../types-C4P7F1Vq.mjs";
|
|
4
|
+
import "../options-BR9XZl7h.mjs";
|
|
5
|
+
import "../entry-lock-BAAlKYrz.mjs";
|
|
6
|
+
import { h as MediaProviderItem, o as CreateMediaProviderFn } from "../placeholder-nOep3_Gn.mjs";
|
|
7
|
+
import "../config-C4-UxIk7.mjs";
|
|
8
|
+
import "../runner-DkeafPBA.mjs";
|
|
9
|
+
import "../storage-query-BOBmeDMD.mjs";
|
|
10
|
+
import "../index-DYsn97dY.mjs";
|
|
11
|
+
import { p as Storage } from "../types-B4-1P2DK.mjs";
|
|
12
|
+
import "../types-Bq9Wohd7.mjs";
|
|
13
|
+
import "../hreflang-BsYo4x_M.mjs";
|
|
14
|
+
import "../validate-Dfv0DpZi.mjs";
|
|
15
15
|
import "../index.mjs";
|
|
16
16
|
import { Kysely } from "kysely";
|
|
17
17
|
|
|
@@ -7,10 +7,10 @@ import "../base64-BQBZwXCx.mjs";
|
|
|
7
7
|
import "../object-cache-Bo6DGaC9.mjs";
|
|
8
8
|
import "../request-cache-C4CIo5ad.mjs";
|
|
9
9
|
import "../types-C-Xp0CcN.mjs";
|
|
10
|
-
import { t as MediaRepository } from "../media-
|
|
11
|
-
import "../loader-
|
|
12
|
-
import { n as handleMediaDelete } from "../media-
|
|
13
|
-
import {
|
|
10
|
+
import { t as MediaRepository } from "../media-IT8hQleU.mjs";
|
|
11
|
+
import "../loader-CetY659y.mjs";
|
|
12
|
+
import { n as handleMediaDelete } from "../media-C_z7sRuC.mjs";
|
|
13
|
+
import { c as invalidateSiteSettingsCache } from "../settings-B1jOxAIl.mjs";
|
|
14
14
|
|
|
15
15
|
//#region src/media/local-runtime.ts
|
|
16
16
|
/**
|