emdash 0.36.0 → 0.38.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{activation-K0kGBWuJ.mjs → activation-DyNTe_Tl.mjs} +3 -3
- package/dist/{activation-K0kGBWuJ.mjs.map → activation-DyNTe_Tl.mjs.map} +1 -1
- package/dist/{adapters-CzL3H752.d.mts → adapters-DCEgOBXi.d.mts} +4 -2
- package/dist/{adapters-CzL3H752.d.mts.map → adapters-DCEgOBXi.d.mts.map} +1 -1
- package/dist/{allowed-origins-maylGaHv.mjs → allowed-origins-GFUVavRj.mjs} +2 -2
- package/dist/{allowed-origins-maylGaHv.mjs.map → allowed-origins-GFUVavRj.mjs.map} +1 -1
- package/dist/api/route-utils.d.mts +3 -3
- package/dist/api/route-utils.mjs +25 -24
- package/dist/api/route-utils.mjs.map +1 -1
- package/dist/api/schemas/index.d.mts +2 -2
- package/dist/api/schemas/index.mjs +5 -5
- package/dist/api-BvxJmnFY.mjs +10094 -0
- package/dist/api-BvxJmnFY.mjs.map +1 -0
- package/dist/{api-tokens-9YrrCoE6.mjs → api-tokens-xpGqMHrC.mjs} +2 -2
- package/dist/{api-tokens-9YrrCoE6.mjs.map → api-tokens-xpGqMHrC.mjs.map} +1 -1
- package/dist/{apply-B_VMpJ2P.mjs → apply-DLmM3R7f.mjs} +26 -22
- package/dist/apply-DLmM3R7f.mjs.map +1 -0
- package/dist/artifact-fetch-P2JXVwOq.mjs +972 -0
- package/dist/artifact-fetch-P2JXVwOq.mjs.map +1 -0
- package/dist/astro/image-endpoint.mjs +2 -2
- package/dist/astro/image-endpoint.mjs.map +1 -1
- package/dist/astro/index.d.mts +12 -12
- package/dist/astro/index.d.mts.map +1 -1
- package/dist/astro/index.mjs +138 -39
- package/dist/astro/index.mjs.map +1 -1
- package/dist/astro/middleware/auth.d.mts +10 -10
- package/dist/astro/middleware/auth.mjs +6 -6
- package/dist/astro/middleware/media-usage-write-fence.mjs +3 -3
- package/dist/astro/middleware/redirect.mjs +7 -5
- package/dist/astro/middleware/redirect.mjs.map +1 -1
- package/dist/astro/middleware/request-context.mjs +3 -3
- package/dist/astro/middleware/setup.mjs +1 -1
- package/dist/astro/middleware.d.mts +10 -10
- package/dist/astro/middleware.d.mts.map +1 -1
- package/dist/astro/middleware.mjs +223 -232
- package/dist/astro/middleware.mjs.map +1 -1
- package/dist/astro/routes/api/admin/allowed-domains/_domain_.mjs +6 -6
- package/dist/astro/routes/api/admin/allowed-domains/index.mjs +6 -6
- package/dist/astro/routes/api/admin/api-tokens/_id_.mjs +3 -3
- package/dist/astro/routes/api/admin/api-tokens/index.d.mts.map +1 -1
- package/dist/astro/routes/api/admin/api-tokens/index.mjs +5 -5
- package/dist/astro/routes/api/admin/api-tokens/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/byline-fields/_slug_/usage.mjs +4 -4
- package/dist/astro/routes/api/admin/byline-fields/_slug_.mjs +9 -9
- package/dist/astro/routes/api/admin/byline-fields/index.mjs +9 -9
- package/dist/astro/routes/api/admin/byline-fields/reorder.mjs +9 -9
- package/dist/astro/routes/api/admin/bylines/_id_/index.mjs +17 -17
- package/dist/astro/routes/api/admin/bylines/_id_/translations.mjs +17 -17
- package/dist/astro/routes/api/admin/bylines/index.mjs +17 -17
- package/dist/astro/routes/api/admin/comments/_id_/status.mjs +13 -13
- package/dist/astro/routes/api/admin/comments/_id_.mjs +5 -5
- package/dist/astro/routes/api/admin/comments/bulk.mjs +10 -10
- package/dist/astro/routes/api/admin/comments/counts.mjs +5 -5
- package/dist/astro/routes/api/admin/comments/index.mjs +10 -10
- package/dist/astro/routes/api/admin/hooks/exclusive/_hookName_.mjs +4 -4
- package/dist/astro/routes/api/admin/hooks/exclusive/index.mjs +3 -3
- package/dist/astro/routes/api/admin/media-usage/activation.mjs +13 -13
- package/dist/astro/routes/api/admin/media-usage/collection-deletions/index.mjs +15 -15
- package/dist/astro/routes/api/admin/media-usage/collection-deletions/retry.mjs +15 -15
- package/dist/astro/routes/api/admin/media-usage/progress.mjs +14 -14
- package/dist/astro/routes/api/admin/media-usage/repair.mjs +17 -17
- package/dist/astro/routes/api/admin/media-usage/work/index.mjs +15 -15
- package/dist/astro/routes/api/admin/media-usage/work/retry.mjs +15 -15
- package/dist/astro/routes/api/admin/oauth-clients/_id_.mjs +4 -4
- package/dist/astro/routes/api/admin/oauth-clients/_id_.mjs.map +1 -1
- package/dist/astro/routes/api/admin/oauth-clients/index.mjs +4 -4
- package/dist/astro/routes/api/admin/oauth-clients/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/_id_/disable.mjs +59 -56
- package/dist/astro/routes/api/admin/plugins/_id_/disable.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/_id_/enable.mjs +59 -56
- package/dist/astro/routes/api/admin/plugins/_id_/enable.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/_id_/index.mjs +57 -54
- package/dist/astro/routes/api/admin/plugins/_id_/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/_id_/mcp.mjs +4 -4
- package/dist/astro/routes/api/admin/plugins/_id_/settings.mjs +57 -54
- package/dist/astro/routes/api/admin/plugins/_id_/settings.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/_id_/uninstall.mjs +58 -55
- package/dist/astro/routes/api/admin/plugins/_id_/uninstall.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/_id_/update.mjs +58 -55
- package/dist/astro/routes/api/admin/plugins/_id_/update.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/index.mjs +57 -54
- package/dist/astro/routes/api/admin/plugins/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/marketplace/_id_/icon.mjs +2 -2
- package/dist/astro/routes/api/admin/plugins/marketplace/_id_/index.mjs +57 -54
- package/dist/astro/routes/api/admin/plugins/marketplace/_id_/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/marketplace/_id_/install.mjs +58 -55
- package/dist/astro/routes/api/admin/plugins/marketplace/_id_/install.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/marketplace/index.mjs +57 -54
- package/dist/astro/routes/api/admin/plugins/marketplace/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/registry/_id_/uninstall.mjs +58 -55
- package/dist/astro/routes/api/admin/plugins/registry/_id_/uninstall.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/registry/_id_/update.d.mts.map +1 -1
- package/dist/astro/routes/api/admin/plugins/registry/_id_/update.mjs +64 -57
- package/dist/astro/routes/api/admin/plugins/registry/_id_/update.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/registry/artifact.mjs +18 -16
- package/dist/astro/routes/api/admin/plugins/registry/artifact.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/registry/install.d.mts.map +1 -1
- package/dist/astro/routes/api/admin/plugins/registry/install.mjs +65 -58
- package/dist/astro/routes/api/admin/plugins/registry/install.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/registry/verify.d.mts +8 -0
- package/dist/astro/routes/api/admin/plugins/registry/verify.d.mts.map +1 -0
- package/dist/astro/routes/api/admin/plugins/registry/verify.mjs +96 -0
- package/dist/astro/routes/api/admin/plugins/registry/verify.mjs.map +1 -0
- package/dist/astro/routes/api/admin/plugins/updates.mjs +57 -54
- package/dist/astro/routes/api/admin/plugins/updates.mjs.map +1 -1
- package/dist/astro/routes/api/admin/themes/marketplace/_id_/index.mjs +57 -54
- package/dist/astro/routes/api/admin/themes/marketplace/_id_/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/themes/marketplace/_id_/thumbnail.mjs +2 -2
- package/dist/astro/routes/api/admin/themes/marketplace/index.mjs +57 -54
- package/dist/astro/routes/api/admin/themes/marketplace/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/users/_id_/disable.mjs +1 -1
- package/dist/astro/routes/api/admin/users/_id_/enable.mjs +1 -1
- package/dist/astro/routes/api/admin/users/_id_/index.mjs +6 -6
- package/dist/astro/routes/api/admin/users/_id_/send-recovery.mjs +3 -3
- package/dist/astro/routes/api/admin/users/index.mjs +6 -6
- package/dist/astro/routes/api/auth/dev-bypass.mjs +3 -3
- package/dist/astro/routes/api/auth/invite/accept.mjs +1 -1
- package/dist/astro/routes/api/auth/invite/complete.mjs +11 -11
- package/dist/astro/routes/api/auth/invite/index.mjs +8 -8
- package/dist/astro/routes/api/auth/invite/register-options.mjs +10 -10
- package/dist/astro/routes/api/auth/logout.mjs +2 -2
- package/dist/astro/routes/api/auth/magic-link/send.mjs +10 -10
- package/dist/astro/routes/api/auth/magic-link/verify.mjs +2 -2
- package/dist/astro/routes/api/auth/me.mjs +7 -7
- package/dist/astro/routes/api/auth/mode.mjs +2 -2
- package/dist/astro/routes/api/auth/oauth/_provider_/callback.mjs +4 -4
- package/dist/astro/routes/api/auth/oauth/_provider_.mjs +2 -2
- package/dist/astro/routes/api/auth/passkey/_id_.mjs +6 -6
- package/dist/astro/routes/api/auth/passkey/index.mjs +1 -1
- package/dist/astro/routes/api/auth/passkey/options.mjs +12 -12
- package/dist/astro/routes/api/auth/passkey/register/options.mjs +10 -10
- package/dist/astro/routes/api/auth/passkey/register/verify.mjs +11 -11
- package/dist/astro/routes/api/auth/passkey/verify.mjs +11 -11
- package/dist/astro/routes/api/auth/signup/complete.mjs +11 -11
- package/dist/astro/routes/api/auth/signup/request.mjs +10 -10
- package/dist/astro/routes/api/auth/signup/verify.mjs +1 -1
- package/dist/astro/routes/api/comments/_collection_/_contentId_/index.mjs +14 -14
- package/dist/astro/routes/api/comments/_collection_/_contentId_/reactions.mjs +13 -13
- package/dist/astro/routes/api/content/_collection_/_id_/compare.mjs +2 -2
- package/dist/astro/routes/api/content/_collection_/_id_/discard-draft.d.mts.map +1 -1
- package/dist/astro/routes/api/content/_collection_/_id_/discard-draft.mjs +19 -5
- package/dist/astro/routes/api/content/_collection_/_id_/discard-draft.mjs.map +1 -1
- package/dist/astro/routes/api/content/_collection_/_id_/duplicate.mjs +3 -3
- package/dist/astro/routes/api/content/_collection_/_id_/lock.d.mts +10 -0
- package/dist/astro/routes/api/content/_collection_/_id_/lock.d.mts.map +1 -0
- package/dist/astro/routes/api/content/_collection_/_id_/lock.mjs +66 -0
- package/dist/astro/routes/api/content/_collection_/_id_/lock.mjs.map +1 -0
- package/dist/astro/routes/api/content/_collection_/_id_/permanent.mjs +2 -2
- package/dist/astro/routes/api/content/_collection_/_id_/preview-url.mjs +11 -11
- package/dist/astro/routes/api/content/_collection_/_id_/publish.d.mts.map +1 -1
- package/dist/astro/routes/api/content/_collection_/_id_/publish.mjs +18 -10
- package/dist/astro/routes/api/content/_collection_/_id_/publish.mjs.map +1 -1
- package/dist/astro/routes/api/content/_collection_/_id_/references/_relation_/children.mjs +20 -18
- package/dist/astro/routes/api/content/_collection_/_id_/references/_relation_/children.mjs.map +1 -1
- package/dist/astro/routes/api/content/_collection_/_id_/references/_relation_/parents.mjs +20 -18
- package/dist/astro/routes/api/content/_collection_/_id_/references/_relation_/parents.mjs.map +1 -1
- package/dist/astro/routes/api/content/_collection_/_id_/restore.mjs +3 -3
- package/dist/astro/routes/api/content/_collection_/_id_/revisions.mjs +2 -2
- package/dist/astro/routes/api/content/_collection_/_id_/schedule.d.mts.map +1 -1
- package/dist/astro/routes/api/content/_collection_/_id_/schedule.mjs +15 -8
- package/dist/astro/routes/api/content/_collection_/_id_/schedule.mjs.map +1 -1
- package/dist/astro/routes/api/content/_collection_/_id_/terms/_taxonomy_.mjs +16 -15
- package/dist/astro/routes/api/content/_collection_/_id_/terms/_taxonomy_.mjs.map +1 -1
- package/dist/astro/routes/api/content/_collection_/_id_/translations.mjs +2 -2
- package/dist/astro/routes/api/content/_collection_/_id_/unpublish.d.mts.map +1 -1
- package/dist/astro/routes/api/content/_collection_/_id_/unpublish.mjs +19 -5
- package/dist/astro/routes/api/content/_collection_/_id_/unpublish.mjs.map +1 -1
- package/dist/astro/routes/api/content/_collection_/_id_.d.mts.map +1 -1
- package/dist/astro/routes/api/content/_collection_/_id_.mjs +23 -11
- package/dist/astro/routes/api/content/_collection_/_id_.mjs.map +1 -1
- package/dist/astro/routes/api/content/_collection_/authors.mjs +2 -2
- package/dist/astro/routes/api/content/_collection_/index.mjs +14 -9
- package/dist/astro/routes/api/content/_collection_/index.mjs.map +1 -1
- package/dist/astro/routes/api/content/_collection_/trash.mjs +7 -7
- package/dist/astro/routes/api/dashboard.mjs +8 -8
- package/dist/astro/routes/api/dev/emails.mjs +2 -2
- package/dist/astro/routes/api/import/probe.d.mts +3 -3
- package/dist/astro/routes/api/import/probe.mjs +18 -18
- package/dist/astro/routes/api/import/wordpress/analyze.mjs +3 -3
- package/dist/astro/routes/api/import/wordpress/execute.d.mts +11 -11
- package/dist/astro/routes/api/import/wordpress/execute.mjs +15 -14
- package/dist/astro/routes/api/import/wordpress/execute.mjs.map +1 -1
- package/dist/astro/routes/api/import/wordpress/media.d.mts +10 -10
- package/dist/astro/routes/api/import/wordpress/media.mjs +11 -11
- package/dist/astro/routes/api/import/wordpress/prepare.mjs +10 -10
- package/dist/astro/routes/api/import/wordpress/rewrite-urls.d.mts +11 -11
- package/dist/astro/routes/api/import/wordpress/rewrite-urls.mjs +13 -13
- package/dist/astro/routes/api/import/wordpress-plugin/analyze.d.mts +1 -1
- package/dist/astro/routes/api/import/wordpress-plugin/analyze.mjs +18 -18
- package/dist/astro/routes/api/import/wordpress-plugin/execute.d.mts +11 -11
- package/dist/astro/routes/api/import/wordpress-plugin/execute.mjs +29 -28
- package/dist/astro/routes/api/import/wordpress-plugin/execute.mjs.map +1 -1
- package/dist/astro/routes/api/manifest.mjs +4 -4
- package/dist/astro/routes/api/manifest.mjs.map +1 -1
- package/dist/astro/routes/api/mcp.mjs +213 -74
- package/dist/astro/routes/api/mcp.mjs.map +1 -1
- package/dist/astro/routes/api/media/_id_/confirm.mjs +11 -11
- package/dist/astro/routes/api/media/_id_/replace.d.mts +8 -0
- package/dist/astro/routes/api/media/_id_/replace.d.mts.map +1 -0
- package/dist/astro/routes/api/media/_id_/replace.mjs +91 -0
- package/dist/astro/routes/api/media/_id_/replace.mjs.map +1 -0
- package/dist/astro/routes/api/media/_id_/upload.mjs +6 -6
- package/dist/astro/routes/api/media/_id_/usage.mjs +19 -19
- package/dist/astro/routes/api/media/_id_.mjs +18 -18
- package/dist/astro/routes/api/media/file/_...key_.d.mts.map +1 -1
- package/dist/astro/routes/api/media/file/_...key_.mjs +3 -2
- package/dist/astro/routes/api/media/file/_...key_.mjs.map +1 -1
- package/dist/astro/routes/api/media/folders/_id_.mjs +8 -8
- package/dist/astro/routes/api/media/folders/index.mjs +8 -8
- package/dist/astro/routes/api/media/providers/_providerId_/_itemId_.mjs +2 -2
- package/dist/astro/routes/api/media/providers/_providerId_/index.mjs +2 -2
- package/dist/astro/routes/api/media/providers/index.mjs +2 -2
- package/dist/astro/routes/api/media/upload-url.mjs +16 -14
- 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 +53 -30
- package/dist/astro/routes/api/media.mjs.map +1 -1
- package/dist/astro/routes/api/menus/_name_/items/_id_.d.mts.map +1 -1
- package/dist/astro/routes/api/menus/_name_/items/_id_.mjs +20 -13
- package/dist/astro/routes/api/menus/_name_/items/_id_.mjs.map +1 -1
- package/dist/astro/routes/api/menus/_name_/items.d.mts.map +1 -1
- package/dist/astro/routes/api/menus/_name_/items.mjs +15 -11
- package/dist/astro/routes/api/menus/_name_/items.mjs.map +1 -1
- package/dist/astro/routes/api/menus/_name_/reorder.d.mts.map +1 -1
- package/dist/astro/routes/api/menus/_name_/reorder.mjs +15 -11
- package/dist/astro/routes/api/menus/_name_/reorder.mjs.map +1 -1
- package/dist/astro/routes/api/menus/_name_/translations.d.mts.map +1 -1
- package/dist/astro/routes/api/menus/_name_/translations.mjs +16 -12
- package/dist/astro/routes/api/menus/_name_/translations.mjs.map +1 -1
- package/dist/astro/routes/api/menus/_name_.d.mts.map +1 -1
- package/dist/astro/routes/api/menus/_name_.mjs +21 -14
- package/dist/astro/routes/api/menus/_name_.mjs.map +1 -1
- package/dist/astro/routes/api/menus/index.d.mts.map +1 -1
- package/dist/astro/routes/api/menus/index.mjs +15 -11
- package/dist/astro/routes/api/menus/index.mjs.map +1 -1
- package/dist/astro/routes/api/oauth/authorize.mjs +6 -6
- package/dist/astro/routes/api/oauth/device/authorize.mjs +5 -5
- package/dist/astro/routes/api/oauth/device/code.mjs +8 -8
- package/dist/astro/routes/api/oauth/device/token.mjs +7 -7
- package/dist/astro/routes/api/oauth/register.mjs +2 -2
- package/dist/astro/routes/api/oauth/token/refresh.mjs +5 -5
- package/dist/astro/routes/api/oauth/token/revoke.mjs +5 -5
- package/dist/astro/routes/api/oauth/token.mjs +5 -5
- package/dist/astro/routes/api/openapi.json.mjs +184 -52
- package/dist/astro/routes/api/openapi.json.mjs.map +1 -1
- package/dist/astro/routes/api/plugins/_pluginId_/_...path_.mjs +4 -4
- package/dist/astro/routes/api/redirects/404s/index.mjs +12 -11
- package/dist/astro/routes/api/redirects/404s/index.mjs.map +1 -1
- package/dist/astro/routes/api/redirects/404s/summary.mjs +12 -11
- package/dist/astro/routes/api/redirects/404s/summary.mjs.map +1 -1
- package/dist/astro/routes/api/redirects/_id_.mjs +13 -12
- package/dist/astro/routes/api/redirects/_id_.mjs.map +1 -1
- package/dist/astro/routes/api/redirects/index.mjs +13 -12
- package/dist/astro/routes/api/redirects/index.mjs.map +1 -1
- package/dist/astro/routes/api/relations/_id_/index.mjs +20 -18
- package/dist/astro/routes/api/relations/_id_/index.mjs.map +1 -1
- package/dist/astro/routes/api/relations/_id_/translations.mjs +15 -13
- package/dist/astro/routes/api/relations/_id_/translations.mjs.map +1 -1
- package/dist/astro/routes/api/relations/index.mjs +20 -18
- package/dist/astro/routes/api/relations/index.mjs.map +1 -1
- package/dist/astro/routes/api/revisions/_revisionId_/index.mjs +2 -2
- package/dist/astro/routes/api/revisions/_revisionId_/restore.mjs +3 -3
- package/dist/astro/routes/api/schema/collections/_slug_/fields/_fieldSlug_.mjs +57 -54
- package/dist/astro/routes/api/schema/collections/_slug_/fields/_fieldSlug_.mjs.map +1 -1
- package/dist/astro/routes/api/schema/collections/_slug_/fields/index.mjs +57 -54
- package/dist/astro/routes/api/schema/collections/_slug_/fields/index.mjs.map +1 -1
- package/dist/astro/routes/api/schema/collections/_slug_/fields/reorder.mjs +57 -54
- package/dist/astro/routes/api/schema/collections/_slug_/fields/reorder.mjs.map +1 -1
- package/dist/astro/routes/api/schema/collections/_slug_/index.mjs +57 -54
- package/dist/astro/routes/api/schema/collections/_slug_/index.mjs.map +1 -1
- package/dist/astro/routes/api/schema/collections/index.mjs +57 -54
- package/dist/astro/routes/api/schema/collections/index.mjs.map +1 -1
- package/dist/astro/routes/api/schema/collections/reorder.mjs +57 -54
- package/dist/astro/routes/api/schema/collections/reorder.mjs.map +1 -1
- package/dist/astro/routes/api/schema/index.mjs +13 -11
- package/dist/astro/routes/api/schema/index.mjs.map +1 -1
- package/dist/astro/routes/api/schema/orphans/_slug_.mjs +57 -54
- package/dist/astro/routes/api/schema/orphans/_slug_.mjs.map +1 -1
- package/dist/astro/routes/api/schema/orphans/index.mjs +57 -54
- package/dist/astro/routes/api/schema/orphans/index.mjs.map +1 -1
- package/dist/astro/routes/api/search/enable.mjs +12 -11
- package/dist/astro/routes/api/search/enable.mjs.map +1 -1
- package/dist/astro/routes/api/search/index.mjs +11 -10
- package/dist/astro/routes/api/search/index.mjs.map +1 -1
- package/dist/astro/routes/api/search/rebuild.mjs +12 -11
- package/dist/astro/routes/api/search/rebuild.mjs.map +1 -1
- package/dist/astro/routes/api/search/stats.mjs +7 -6
- package/dist/astro/routes/api/search/stats.mjs.map +1 -1
- package/dist/astro/routes/api/search/suggest.mjs +11 -10
- package/dist/astro/routes/api/search/suggest.mjs.map +1 -1
- package/dist/astro/routes/api/sections/_slug_.mjs +11 -10
- package/dist/astro/routes/api/sections/_slug_.mjs.map +1 -1
- package/dist/astro/routes/api/sections/index.mjs +11 -10
- package/dist/astro/routes/api/sections/index.mjs.map +1 -1
- package/dist/astro/routes/api/settings/backups/archives/_name_.mjs +7 -6
- package/dist/astro/routes/api/settings/backups/archives/_name_.mjs.map +1 -1
- package/dist/astro/routes/api/settings/backups/archives/index.mjs +6 -5
- package/dist/astro/routes/api/settings/backups/archives/index.mjs.map +1 -1
- package/dist/astro/routes/api/settings/backups/export.mjs +7 -6
- package/dist/astro/routes/api/settings/backups/export.mjs.map +1 -1
- package/dist/astro/routes/api/settings/backups/index.mjs +8 -7
- package/dist/astro/routes/api/settings/backups/index.mjs.map +1 -1
- package/dist/astro/routes/api/settings/email.mjs +5 -5
- package/dist/astro/routes/api/settings/email.mjs.map +1 -1
- package/dist/astro/routes/api/settings.d.mts.map +1 -1
- package/dist/astro/routes/api/settings.mjs +21 -17
- package/dist/astro/routes/api/settings.mjs.map +1 -1
- package/dist/astro/routes/api/setup/admin-verify.mjs +12 -12
- package/dist/astro/routes/api/setup/admin.mjs +11 -11
- package/dist/astro/routes/api/setup/dev-bypass.mjs +35 -33
- package/dist/astro/routes/api/setup/dev-bypass.mjs.map +1 -1
- package/dist/astro/routes/api/setup/dev-reset.mjs +2 -2
- package/dist/astro/routes/api/setup/index.mjs +35 -33
- package/dist/astro/routes/api/setup/index.mjs.map +1 -1
- package/dist/astro/routes/api/setup/status.mjs +3 -3
- package/dist/astro/routes/api/snapshot.mjs +8 -7
- package/dist/astro/routes/api/snapshot.mjs.map +1 -1
- package/dist/astro/routes/api/taxonomies/_name_/reorder.d.mts.map +1 -1
- package/dist/astro/routes/api/taxonomies/_name_/reorder.mjs +22 -17
- package/dist/astro/routes/api/taxonomies/_name_/reorder.mjs.map +1 -1
- package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_/translations.d.mts.map +1 -1
- package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_/translations.mjs +23 -18
- package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_/translations.mjs.map +1 -1
- package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_.d.mts.map +1 -1
- package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_.mjs +27 -19
- package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_.mjs.map +1 -1
- package/dist/astro/routes/api/taxonomies/_name_/terms/index.d.mts.map +1 -1
- package/dist/astro/routes/api/taxonomies/_name_/terms/index.mjs +22 -17
- package/dist/astro/routes/api/taxonomies/_name_/terms/index.mjs.map +1 -1
- package/dist/astro/routes/api/taxonomies/_name_/translations.mjs +16 -15
- package/dist/astro/routes/api/taxonomies/_name_/translations.mjs.map +1 -1
- package/dist/astro/routes/api/taxonomies/_name_.d.mts.map +1 -1
- package/dist/astro/routes/api/taxonomies/_name_.mjs +28 -20
- package/dist/astro/routes/api/taxonomies/_name_.mjs.map +1 -1
- package/dist/astro/routes/api/taxonomies/index.d.mts.map +1 -1
- package/dist/astro/routes/api/taxonomies/index.mjs +22 -17
- package/dist/astro/routes/api/taxonomies/index.mjs.map +1 -1
- package/dist/astro/routes/api/themes/preview.mjs +5 -5
- package/dist/astro/routes/api/typegen.mjs +4 -4
- package/dist/astro/routes/api/well-known/auth.mjs +2 -2
- package/dist/astro/routes/api/well-known/oauth-authorization-server.mjs +2 -2
- package/dist/astro/routes/api/well-known/oauth-protected-resource.mjs +2 -2
- package/dist/astro/routes/api/widget-areas/_name_/reorder.d.mts.map +1 -1
- package/dist/astro/routes/api/widget-areas/_name_/reorder.mjs +10 -8
- package/dist/astro/routes/api/widget-areas/_name_/reorder.mjs.map +1 -1
- package/dist/astro/routes/api/widget-areas/_name_/widgets/_id_.d.mts.map +1 -1
- package/dist/astro/routes/api/widget-areas/_name_/widgets/_id_.mjs +18 -14
- package/dist/astro/routes/api/widget-areas/_name_/widgets/_id_.mjs.map +1 -1
- package/dist/astro/routes/api/widget-areas/_name_/widgets.d.mts.map +1 -1
- package/dist/astro/routes/api/widget-areas/_name_/widgets.mjs +16 -13
- package/dist/astro/routes/api/widget-areas/_name_/widgets.mjs.map +1 -1
- package/dist/astro/routes/api/widget-areas/_name_.d.mts.map +1 -1
- package/dist/astro/routes/api/widget-areas/_name_.mjs +9 -7
- package/dist/astro/routes/api/widget-areas/_name_.mjs.map +1 -1
- package/dist/astro/routes/api/widget-areas/index.d.mts.map +1 -1
- package/dist/astro/routes/api/widget-areas/index.mjs +16 -13
- package/dist/astro/routes/api/widget-areas/index.mjs.map +1 -1
- package/dist/astro/routes/api/widget-components.mjs +2 -2
- package/dist/astro/routes/robots.txt.mjs +8 -8
- package/dist/astro/routes/sitemap-_collection_.xml.mjs +13 -12
- package/dist/astro/routes/sitemap-_collection_.xml.mjs.map +1 -1
- package/dist/astro/routes/sitemap.xml.mjs +9 -9
- package/dist/astro/types.d.mts +50 -20
- package/dist/astro/types.d.mts.map +1 -1
- package/dist/auth/providers/github.d.mts +1 -1
- package/dist/auth/providers/google.d.mts +1 -1
- package/dist/{authorize-ByYs-Uxs.mjs → authorize-C2QHlWSS.mjs} +2 -2
- package/dist/{authorize-ByYs-Uxs.mjs.map → authorize-C2QHlWSS.mjs.map} +1 -1
- package/dist/{backup-ChyHfIoX.mjs → backup-oS8ft5Cm.mjs} +5 -5
- package/dist/{backup-ChyHfIoX.mjs.map → backup-oS8ft5Cm.mjs.map} +1 -1
- package/dist/{bundle-DZFhFurR.mjs → bundle-CL0JjIPx.mjs} +4 -4
- package/dist/{bundle-DZFhFurR.mjs.map → bundle-CL0JjIPx.mjs.map} +1 -1
- package/dist/{byline-Cpnwrje1.mjs → byline-Vdi85CsZ.mjs} +27 -14
- package/dist/byline-Vdi85CsZ.mjs.map +1 -0
- package/dist/{byline-fields-CAyA_Umd.mjs → byline-fields-DPVRFMz2.mjs} +2 -2
- package/dist/{byline-fields-CAyA_Umd.mjs.map → byline-fields-DPVRFMz2.mjs.map} +1 -1
- package/dist/{byline-registry-Bpu9-MVs.mjs → byline-registry-BxDGIO0I.mjs} +2 -2
- package/dist/{byline-registry-Bpu9-MVs.mjs.map → byline-registry-BxDGIO0I.mjs.map} +1 -1
- package/dist/{bylines-BSo9B9RX.mjs → bylines-BX8QhcTk.mjs} +7 -7
- package/dist/{bylines-BSo9B9RX.mjs.map → bylines-BX8QhcTk.mjs.map} +1 -1
- package/dist/{bylines-CHjvehVX.mjs → bylines-w-E1IEQd.mjs} +3 -3
- package/dist/{bylines-CHjvehVX.mjs.map → bylines-w-E1IEQd.mjs.map} +1 -1
- package/dist/{cache-5VirJ2Cn.mjs → cache--7HKu5Xm.mjs} +4 -4
- package/dist/{cache-5VirJ2Cn.mjs.map → cache--7HKu5Xm.mjs.map} +1 -1
- package/dist/{capture-triggers-CNW1q3HK.mjs → capture-triggers-CeAsC76Z.mjs} +2 -2
- package/dist/{capture-triggers-CNW1q3HK.mjs.map → capture-triggers-CeAsC76Z.mjs.map} +1 -1
- package/dist/{challenge-store-D5pSY2S1.mjs → challenge-store-BIOak-tp.mjs} +5 -3
- package/dist/challenge-store-BIOak-tp.mjs.map +1 -0
- package/dist/chrome-tags-DzDQBCjX.mjs +24 -0
- package/dist/chrome-tags-DzDQBCjX.mjs.map +1 -0
- package/dist/{chunks-bNiX6_DR.mjs → chunks-VG_tyqnP.mjs} +2 -2
- package/dist/{chunks-bNiX6_DR.mjs.map → chunks-VG_tyqnP.mjs.map} +1 -1
- package/dist/cli/index.mjs +68 -40
- package/dist/cli/index.mjs.map +1 -1
- package/dist/client/cf-access.d.mts +1 -1
- package/dist/client/index.d.mts +17 -7
- package/dist/client/index.d.mts.map +1 -1
- package/dist/client/index.mjs +17 -12
- package/dist/client/index.mjs.map +1 -1
- package/dist/{collection-deletion-m_oi2c0N.mjs → collection-deletion-BCwaWTDw.mjs} +4 -4
- package/dist/{collection-deletion-m_oi2c0N.mjs.map → collection-deletion-BCwaWTDw.mjs.map} +1 -1
- package/dist/collection-slugs-cache-7lTmNzeA.mjs +85 -0
- package/dist/collection-slugs-cache-7lTmNzeA.mjs.map +1 -0
- package/dist/{comment-reaction-CRuItEjt.mjs → comment-reaction-CDyvPQRj.mjs} +2 -2
- package/dist/{comment-reaction-CRuItEjt.mjs.map → comment-reaction-CDyvPQRj.mjs.map} +1 -1
- package/dist/{comment-DhvLEdhQ.mjs → comment-vxOzWbZN.mjs} +2 -2
- package/dist/{comment-DhvLEdhQ.mjs.map → comment-vxOzWbZN.mjs.map} +1 -1
- package/dist/{comments-CLj4bi8I.mjs → comments-VzmVLyaC.mjs} +2 -2
- package/dist/{comments-CLj4bi8I.mjs.map → comments-VzmVLyaC.mjs.map} +1 -1
- package/dist/{components-v4U4DT2y.mjs → components-CL6Wkdk-.mjs} +1 -1
- package/dist/{components-v4U4DT2y.mjs.map → components-CL6Wkdk-.mjs.map} +1 -1
- package/dist/config--eWjQJE5.mjs +217 -0
- package/dist/config--eWjQJE5.mjs.map +1 -0
- package/dist/{index-DWbJrsAg.d.mts → config-CGAhyOjP.d.mts} +276 -76
- package/dist/config-CGAhyOjP.d.mts.map +1 -0
- package/dist/{config-DrfghTPe.d.mts → config-ChFzshGd.d.mts} +1 -1
- package/dist/{config-DrfghTPe.d.mts.map → config-ChFzshGd.d.mts.map} +1 -1
- package/dist/{content-CP-SeXNa.mjs → content-CNfMWuhY.mjs} +202 -46
- package/dist/content-CNfMWuhY.mjs.map +1 -0
- package/dist/{content-list-query-BhejKVqb.d.mts → content-list-query-B8d4UQp9.d.mts} +1 -1
- package/dist/{content-list-query-BhejKVqb.d.mts.map → content-list-query-B8d4UQp9.d.mts.map} +1 -1
- package/dist/{content-refresh-DLOfIhYc.mjs → content-refresh-GTMyi2Xy.mjs} +53 -26
- package/dist/content-refresh-GTMyi2Xy.mjs.map +1 -0
- package/dist/{content-repair-BCxzy0r4.mjs → content-repair-CIMt5C0U.mjs} +4 -4
- package/dist/{content-repair-BCxzy0r4.mjs.map → content-repair-CIMt5C0U.mjs.map} +1 -1
- package/dist/{context-BR5hRWiK.mjs → context-C9PB8vGd.mjs} +308 -33
- package/dist/context-C9PB8vGd.mjs.map +1 -0
- package/dist/{cron-CWfWrWKG.mjs → cron-DHAy9oyq.mjs} +1 -1
- package/dist/{cron-CWfWrWKG.mjs.map → cron-DHAy9oyq.mjs.map} +1 -1
- package/dist/{dashboard-CkIV2rnQ.mjs → dashboard-BNSvAN8A.mjs} +5 -5
- package/dist/{dashboard-CkIV2rnQ.mjs.map → dashboard-BNSvAN8A.mjs.map} +1 -1
- package/dist/db/index.d.mts +3 -3
- package/dist/db/index.mjs +2 -2
- package/dist/db/index.mjs.map +1 -1
- package/dist/db/libsql-migrations.d.mts +1 -1
- package/dist/db/libsql-migrations.mjs +5 -5
- package/dist/db/libsql.d.mts +1 -1
- package/dist/db/postgres-migrations.d.mts +1 -1
- package/dist/db/postgres-migrations.mjs +5 -5
- package/dist/db/postgres.d.mts +1 -1
- package/dist/db/postgres.d.mts.map +1 -1
- package/dist/db/postgres.mjs +19 -3
- package/dist/db/postgres.mjs.map +1 -1
- package/dist/db/sqlite-migrations.d.mts +1 -1
- package/dist/db/sqlite-migrations.mjs +5 -5
- package/dist/db/sqlite.d.mts +1 -1
- package/dist/db/sqlite.mjs +1 -1
- package/dist/{default-YMEfcQUx.mjs → default-ByZ0JqZo.mjs} +1 -1
- package/dist/{default-YMEfcQUx.mjs.map → default-ByZ0JqZo.mjs.map} +1 -1
- package/dist/{deferred-tasks-DfqxH5Xf.d.mts → deferred-tasks-Cu4NSJpa.d.mts} +1 -1
- package/dist/{deferred-tasks-DfqxH5Xf.d.mts.map → deferred-tasks-Cu4NSJpa.d.mts.map} +1 -1
- package/dist/dev-typegen-DHT7lcMU.mjs +29 -0
- package/dist/dev-typegen-DHT7lcMU.mjs.map +1 -0
- package/dist/{device-flow-CojjSBwb.mjs → device-flow-Cf6bhCCT.mjs} +4 -4
- package/dist/{device-flow-CojjSBwb.mjs.map → device-flow-Cf6bhCCT.mjs.map} +1 -1
- package/dist/{dialect-helpers-BSbfaO3F.mjs → dialect-helpers-BcQvkHgn.mjs} +83 -2
- package/dist/dialect-helpers-BcQvkHgn.mjs.map +1 -0
- package/dist/{direct-executor-BWeWiRYB.mjs → direct-executor-yAyUGSqB.mjs} +3 -3
- package/dist/{direct-executor-BWeWiRYB.mjs.map → direct-executor-yAyUGSqB.mjs.map} +1 -1
- package/dist/{dist-89xCrGqi.mjs → dist-BAsh8dbf.mjs} +1 -1
- package/dist/{dist-89xCrGqi.mjs.map → dist-BAsh8dbf.mjs.map} +1 -1
- package/dist/{email-console-CEJgR_LB.mjs → email-console-DNup1Fku.mjs} +1 -1
- package/dist/{email-console-CEJgR_LB.mjs.map → email-console-DNup1Fku.mjs.map} +1 -1
- package/dist/{enrich-BX0IDp4z.mjs → enrich-t2Xvjdqa.mjs} +3 -3
- package/dist/{enrich-BX0IDp4z.mjs.map → enrich-t2Xvjdqa.mjs.map} +1 -1
- package/dist/entry-lock-BEr8gDkG.mjs +163 -0
- package/dist/entry-lock-BEr8gDkG.mjs.map +1 -0
- package/dist/{relations-C7B46bcU.d.mts → entry-lock-CGAtrwAR.d.mts} +265 -76
- package/dist/entry-lock-CGAtrwAR.d.mts.map +1 -0
- package/dist/{redirects-CRIM55KH.mjs → entry-lock-DIYHAaSw.mjs} +112 -34
- package/dist/entry-lock-DIYHAaSw.mjs.map +1 -0
- package/dist/entry-locks-BEcX7ET0.mjs +167 -0
- package/dist/entry-locks-BEcX7ET0.mjs.map +1 -0
- package/dist/{error-D9w94fjV.mjs → error-BDcFyoRt.mjs} +2 -2
- package/dist/{error-D9w94fjV.mjs.map → error-BDcFyoRt.mjs.map} +1 -1
- package/dist/{errors-n2j49uNf.mjs → errors-DvMdNrgf.mjs} +10 -1
- package/dist/errors-DvMdNrgf.mjs.map +1 -0
- package/dist/{escape-DN4Qmjsl.mjs → escape-B3asJC6W.mjs} +1 -1
- package/dist/{escape-DN4Qmjsl.mjs.map → escape-B3asJC6W.mjs.map} +1 -1
- package/dist/{field-defs-cache-Bh4q6oar.mjs → field-defs-cache-Cf5FHK0M.mjs} +5 -5
- package/dist/{field-defs-cache-Bh4q6oar.mjs.map → field-defs-cache-Cf5FHK0M.mjs.map} +1 -1
- package/dist/{fts-manager-BhOdW0bi.mjs → fts-manager-iddym8cd.mjs} +4 -4
- package/dist/{fts-manager-BhOdW0bi.mjs.map → fts-manager-iddym8cd.mjs.map} +1 -1
- package/dist/{hash-CTcngWvj.mjs → hash-BRweX6jz.mjs} +1 -1
- package/dist/{hash-CTcngWvj.mjs.map → hash-BRweX6jz.mjs.map} +1 -1
- package/dist/hook-result-BrshYHLx.d.mts +31 -0
- package/dist/hook-result-BrshYHLx.d.mts.map +1 -0
- package/dist/{hreflang-7pTHsLZJ.d.mts → hreflang-CQpu5bMy.d.mts} +2 -2
- package/dist/{hreflang-7pTHsLZJ.d.mts.map → hreflang-CQpu5bMy.d.mts.map} +1 -1
- package/dist/{hreflang-Huc6O5wa.mjs → hreflang-DshnweTC.mjs} +9 -8
- package/dist/{hreflang-Huc6O5wa.mjs.map → hreflang-DshnweTC.mjs.map} +1 -1
- package/dist/{identity-DXmb4aVp.mjs → identity-CjGKDq8J.mjs} +3 -3
- package/dist/{identity-DXmb4aVp.mjs.map → identity-CjGKDq8J.mjs.map} +1 -1
- package/dist/{import-C4_O3KXU.mjs → import-D96g2otw.mjs} +6 -6
- package/dist/{import-C4_O3KXU.mjs.map → import-D96g2otw.mjs.map} +1 -1
- package/dist/{index-6bRee8zb.d.mts → index-1ECYpfiF.d.mts} +3 -3
- package/dist/{index-6bRee8zb.d.mts.map → index-1ECYpfiF.d.mts.map} +1 -1
- package/dist/index.d.mts +22 -21
- package/dist/index.mjs +84 -81
- package/dist/{init-lock-DJkX6Hto.mjs → init-lock-CFNBe_iH.mjs} +1 -1
- package/dist/{init-lock-DJkX6Hto.mjs.map → init-lock-CFNBe_iH.mjs.map} +1 -1
- package/dist/{load-Bo7fZAbg.mjs → load-DPtY9cZo.mjs} +2 -2
- package/dist/{load-Bo7fZAbg.mjs.map → load-DPtY9cZo.mjs.map} +1 -1
- package/dist/{loader-ZsjE4paL.mjs → loader-WJi6GFRn.mjs} +90 -17
- package/dist/loader-WJi6GFRn.mjs.map +1 -0
- package/dist/{manifest-builder-QXuqvVMP.mjs → manifest-builder-BfNlGQIA.mjs} +2 -2
- package/dist/{manifest-builder-QXuqvVMP.mjs.map → manifest-builder-BfNlGQIA.mjs.map} +1 -1
- package/dist/{manifest-schema-CUYPfCEH.mjs → manifest-schema-CILooI5J.mjs} +5 -5
- package/dist/manifest-schema-CILooI5J.mjs.map +1 -0
- package/dist/media/image-endpoint.d.mts +4 -2
- package/dist/media/image-endpoint.d.mts.map +1 -1
- package/dist/media/image-endpoint.mjs +6 -4
- package/dist/media/image-endpoint.mjs.map +1 -1
- package/dist/media/index.d.mts +1 -1
- package/dist/media/index.mjs +3 -3
- package/dist/media/local-runtime.d.mts +12 -12
- package/dist/media/local-runtime.mjs +7 -7
- package/dist/{media-D6SeAfBl.mjs → media-BBm8Wg3f.mjs} +30 -2
- package/dist/media-BBm8Wg3f.mjs.map +1 -0
- package/dist/{media-BjwNuLEu.mjs → media-C1EIZKh1.mjs} +35 -5
- package/dist/media-C1EIZKh1.mjs.map +1 -0
- package/dist/{media-allowlist-D35v7bmL.mjs → media-allowlist-elXJgb_K.mjs} +2 -2
- package/dist/{media-allowlist-D35v7bmL.mjs.map → media-allowlist-elXJgb_K.mjs.map} +1 -1
- package/dist/{media-folders-D-0CmRZj.mjs → media-folders-DASfX_DH.mjs} +1 -1
- package/dist/{media-folders-D-0CmRZj.mjs.map → media-folders-DASfX_DH.mjs.map} +1 -1
- package/dist/{media-upload-C7bLXGcI.mjs → media-upload-C7_AQJ5v.mjs} +9 -9
- package/dist/{media-upload-C7bLXGcI.mjs.map → media-upload-C7_AQJ5v.mjs.map} +1 -1
- package/dist/{media-url-DH7giMx_.mjs → media-url-8dVl1loq.mjs} +19 -2
- package/dist/media-url-8dVl1loq.mjs.map +1 -0
- package/dist/{media-usage-BTRJvS6V.mjs → media-usage-C1EswMTq.mjs} +10 -10
- package/dist/{media-usage-BTRJvS6V.mjs.map → media-usage-C1EswMTq.mjs.map} +1 -1
- package/dist/{media-usage-activation-Dx0kPV6b.mjs → media-usage-activation-CrHNltlL.mjs} +3 -3
- package/dist/{media-usage-activation-Dx0kPV6b.mjs.map → media-usage-activation-CrHNltlL.mjs.map} +1 -1
- package/dist/{media-usage-work-C-fhM30c.mjs → media-usage-work-C5B1zT1c.mjs} +2 -2
- package/dist/{media-usage-work-C-fhM30c.mjs.map → media-usage-work-C5B1zT1c.mjs.map} +1 -1
- package/dist/{media-usage-work-DWb2XPMI.mjs → media-usage-work-IkQx_Yz6.mjs} +4 -4
- package/dist/{media-usage-work-DWb2XPMI.mjs.map → media-usage-work-IkQx_Yz6.mjs.map} +1 -1
- package/dist/{media-usage-write-fence-BwoJVRDC.mjs → media-usage-write-fence-B9anjOSg.mjs} +3 -3
- package/dist/{media-usage-write-fence-BwoJVRDC.mjs.map → media-usage-write-fence-B9anjOSg.mjs.map} +1 -1
- package/dist/{menus-CNg0QlDt.mjs → menus-D8mC4eaN.mjs} +406 -175
- package/dist/menus-D8mC4eaN.mjs.map +1 -0
- package/dist/{menus-CD7EFLwz.mjs → menus-UdwjHZJC.mjs} +12 -4
- package/dist/{menus-CD7EFLwz.mjs.map → menus-UdwjHZJC.mjs.map} +1 -1
- package/dist/migrations/index.d.mts +1 -1
- package/dist/migrations/index.mjs +4 -4
- package/dist/{mime-CUIG6x84.mjs → mime-DYpsOAny.mjs} +1 -1
- package/dist/{mime-CUIG6x84.mjs.map → mime-DYpsOAny.mjs.map} +1 -1
- package/dist/{mode-DaUM_MB2.mjs → mode-Dm4BHhRH.mjs} +1 -1
- package/dist/{mode-DaUM_MB2.mjs.map → mode-Dm4BHhRH.mjs.map} +1 -1
- package/dist/{node-sqlite-compat-Udb4Y-rs.mjs → node-sqlite-compat-2sezm-Zd.mjs} +1 -1
- package/dist/{node-sqlite-compat-Udb4Y-rs.mjs.map → node-sqlite-compat-2sezm-Zd.mjs.map} +1 -1
- package/dist/{normalize-CSxdKBVa.mjs → normalize-4nkKGsuW.mjs} +15 -5
- package/dist/normalize-4nkKGsuW.mjs.map +1 -0
- package/dist/{oauth-authorization-Dpsb-fMJ.mjs → oauth-authorization-BxE_lURD.mjs} +4 -4
- package/dist/{oauth-authorization-Dpsb-fMJ.mjs.map → oauth-authorization-BxE_lURD.mjs.map} +1 -1
- package/dist/{oauth-clients-Bxnoe_67.mjs → oauth-clients-DJIdOdq0.mjs} +1 -1
- package/dist/{oauth-clients-Bxnoe_67.mjs.map → oauth-clients-DJIdOdq0.mjs.map} +1 -1
- package/dist/{oauth-state-store-0C4s0K6w.mjs → oauth-state-store-CsdxP57n.mjs} +1 -1
- package/dist/{oauth-state-store-0C4s0K6w.mjs.map → oauth-state-store-CsdxP57n.mjs.map} +1 -1
- package/dist/{oauth-user-lookup-wlGYSeqX.mjs → oauth-user-lookup-HzzW-dkF.mjs} +1 -1
- package/dist/{oauth-user-lookup-wlGYSeqX.mjs.map → oauth-user-lookup-HzzW-dkF.mjs.map} +1 -1
- package/dist/object-cache/memory.d.mts +1 -1
- package/dist/{object-cache-71tPfV4A.mjs → object-cache-DVKnyOfy.mjs} +19 -3
- package/dist/object-cache-DVKnyOfy.mjs.map +1 -0
- package/dist/{options-BHPeIbBd.mjs → options-D1FBiAv1.mjs} +60 -5
- package/dist/options-D1FBiAv1.mjs.map +1 -0
- package/dist/{options-BhZIeFY1.d.mts → options-D8Y0VHc7.d.mts} +30 -11
- package/dist/options-D8Y0VHc7.d.mts.map +1 -0
- package/dist/page/index.d.mts +2 -2
- package/dist/page/index.d.mts.map +1 -1
- package/dist/page/index.mjs +12 -0
- package/dist/page/index.mjs.map +1 -1
- package/dist/{parse-BRJg1kz8.mjs → parse-WRg5C3NX.mjs} +2 -2
- package/dist/{parse-BRJg1kz8.mjs.map → parse-WRg5C3NX.mjs.map} +1 -1
- package/dist/{passkey-config-B3P0nHRR.mjs → passkey-config-qIdO-wF6.mjs} +1 -1
- package/dist/{passkey-config-B3P0nHRR.mjs.map → passkey-config-qIdO-wF6.mjs.map} +1 -1
- package/dist/{patterns-D9iDO3j8.mjs → patterns-DC8CLptu.mjs} +1 -1
- package/dist/{patterns-D9iDO3j8.mjs.map → patterns-DC8CLptu.mjs.map} +1 -1
- package/dist/{placeholder-BR4ZhVJl.d.mts → placeholder-COrvARyD.d.mts} +1 -1
- package/dist/{placeholder-BR4ZhVJl.d.mts.map → placeholder-COrvARyD.d.mts.map} +1 -1
- package/dist/plugin-types.d.mts +8 -3
- package/dist/plugin-types.d.mts.map +1 -1
- package/dist/plugin-utils.d.mts +10 -10
- package/dist/plugins/adapt-sandbox-entry.d.mts +10 -10
- package/dist/plugins/adapt-sandbox-entry.mjs +2 -2
- package/dist/{policy-BVRganJQ.mjs → policy-XCfb-IE9.mjs} +2 -2
- package/dist/{policy-BVRganJQ.mjs.map → policy-XCfb-IE9.mjs.map} +1 -1
- package/dist/{portable-text-C8Tvp4_g.mjs → portable-text-BS3d5n-0.mjs} +1 -1
- package/dist/{portable-text-C8Tvp4_g.mjs.map → portable-text-BS3d5n-0.mjs.map} +1 -1
- package/dist/{preview-dn2dUyM0.mjs → preview-BxwsGgGp.mjs} +2 -2
- package/dist/{preview-dn2dUyM0.mjs.map → preview-BxwsGgGp.mjs.map} +1 -1
- package/dist/{protocol-CuBEsqgE.d.mts → protocol-CLn58-nw.d.mts} +2 -2
- package/dist/{protocol-CuBEsqgE.d.mts.map → protocol-CLn58-nw.d.mts.map} +1 -1
- package/dist/{public-url-DRz_AinV.mjs → public-url-FWWAvnre.mjs} +1 -1
- package/dist/{public-url-DRz_AinV.mjs.map → public-url-FWWAvnre.mjs.map} +1 -1
- package/dist/{query-D18vTdha.mjs → query-DygOte9M.mjs} +26 -17
- package/dist/query-DygOte9M.mjs.map +1 -0
- package/dist/{query-tZDEdtCN.mjs → query-gtXT03Wc.mjs} +5 -5
- package/dist/{query-tZDEdtCN.mjs.map → query-gtXT03Wc.mjs.map} +1 -1
- package/dist/{rate-limit-on7KPo-v.mjs → rate-limit-CQUPm0dh.mjs} +2 -2
- package/dist/{rate-limit-on7KPo-v.mjs.map → rate-limit-CQUPm0dh.mjs.map} +1 -1
- package/dist/{redirect-DrbEmU9a.mjs → redirect-D1cWafi6.mjs} +1 -1
- package/dist/{redirect-DrbEmU9a.mjs.map → redirect-D1cWafi6.mjs.map} +1 -1
- package/dist/{redirect-CZkbozu9.mjs → redirect-DId44BS1.mjs} +19 -6
- package/dist/redirect-DId44BS1.mjs.map +1 -0
- package/dist/{redirects-BahWiu8Z.mjs → redirects-DN-ZE33W.mjs} +5 -5
- package/dist/{redirects-BahWiu8Z.mjs.map → redirects-DN-ZE33W.mjs.map} +1 -1
- package/dist/{registry-Cx-jEJOS.mjs → registry-DTqaqxed.mjs} +46 -12
- package/dist/registry-DTqaqxed.mjs.map +1 -0
- package/dist/{relation-A6wLF_DS.mjs → relation-DxgCHOBw.mjs} +2 -2
- package/dist/{relation-A6wLF_DS.mjs.map → relation-DxgCHOBw.mjs.map} +1 -1
- package/dist/{relations-Cj5hZ6Zg.mjs → relations-KKDSLUwS.mjs} +4 -4
- package/dist/{relations-Cj5hZ6Zg.mjs.map → relations-KKDSLUwS.mjs.map} +1 -1
- package/dist/{relations-BTPM2saV.mjs → relations-rOmbndUJ.mjs} +8 -8
- package/dist/relations-rOmbndUJ.mjs.map +1 -0
- package/dist/{request-cache-DH9zdCOD.mjs → request-cache-DAZZmesc.mjs} +1 -1
- package/dist/{request-cache-DH9zdCOD.mjs.map → request-cache-DAZZmesc.mjs.map} +1 -1
- package/dist/request-context.d.mts +1 -1
- package/dist/{request-meta-DRp5ENd_.mjs → request-meta-BgjUQLQ-.mjs} +2 -2
- package/dist/{request-meta-DRp5ENd_.mjs.map → request-meta-BgjUQLQ-.mjs.map} +1 -1
- package/dist/{resolve-DxUpTMmE.mjs → resolve-Cy0aWSRj.mjs} +37 -4
- package/dist/resolve-Cy0aWSRj.mjs.map +1 -0
- package/dist/{runner-zgqA_CqP.d.mts → runner-CfwysRM0.d.mts} +3 -2
- package/dist/runner-CfwysRM0.d.mts.map +1 -0
- package/dist/{runner-77GOZCnH.mjs → runner-nEzvnogG.mjs} +476 -295
- package/dist/runner-nEzvnogG.mjs.map +1 -0
- package/dist/runtime.d.mts +11 -11
- package/dist/runtime.mjs +3 -2
- package/dist/runtime.mjs.map +1 -1
- package/dist/{schema-BY-oVntF.mjs → schema-CRu38Pr5.mjs} +3 -3
- package/dist/{schema-BY-oVntF.mjs.map → schema-CRu38Pr5.mjs.map} +1 -1
- package/dist/{schema-Cw9kVK0I.mjs → schema-DifxndJx.mjs} +5 -5
- package/dist/{schema-Cw9kVK0I.mjs.map → schema-DifxndJx.mjs.map} +1 -1
- package/dist/{scopes-vMR1uIbt.mjs → scopes-D5A1OZbq.mjs} +3 -3
- package/dist/{scopes-vMR1uIbt.mjs.map → scopes-D5A1OZbq.mjs.map} +1 -1
- package/dist/{search-CfT3KxO5.mjs → search-DEPFSBFq.mjs} +4 -4
- package/dist/{search-CfT3KxO5.mjs.map → search-DEPFSBFq.mjs.map} +1 -1
- package/dist/{secrets-BH2Qow1-.mjs → secrets-CdfzLdoO.mjs} +3 -3
- package/dist/{secrets-BH2Qow1-.mjs.map → secrets-CdfzLdoO.mjs.map} +1 -1
- package/dist/{sections-DTfjyf1z.mjs → sections-3X52kmIR.mjs} +2 -2
- package/dist/{sections-DTfjyf1z.mjs.map → sections-3X52kmIR.mjs.map} +1 -1
- package/dist/seed/index.d.mts +2 -2
- package/dist/seed/index.mjs +28 -26
- package/dist/seo/index.d.mts +3 -3
- package/dist/seo/index.d.mts.map +1 -1
- package/dist/seo/index.mjs +20 -21
- package/dist/seo/index.mjs.map +1 -1
- package/dist/{seo-Cm-dtvgk.mjs → seo-Bw68KxRc.mjs} +3 -3
- package/dist/{seo-Cm-dtvgk.mjs.map → seo-Bw68KxRc.mjs.map} +1 -1
- package/dist/{seo-BSiTIXzd.mjs → seo-C4AmbsMU.mjs} +3 -2
- package/dist/seo-C4AmbsMU.mjs.map +1 -0
- package/dist/{service-DYsDHEKe.mjs → service-J_-Vgo7R.mjs} +3 -3
- package/dist/{service-DYsDHEKe.mjs.map → service-J_-Vgo7R.mjs.map} +1 -1
- package/dist/{session-user-CNAfvsdw.mjs → session-user-CbnMMwk6.mjs} +1 -1
- package/dist/{session-user-CNAfvsdw.mjs.map → session-user-CbnMMwk6.mjs.map} +1 -1
- package/dist/{settings-DjtkUo__.mjs → settings-AnEFYICn.mjs} +3 -3
- package/dist/{settings-DjtkUo__.mjs.map → settings-AnEFYICn.mjs.map} +1 -1
- package/dist/{settings-BgN-0DT-.mjs → settings-DcMjREe5.mjs} +21 -8
- package/dist/settings-DcMjREe5.mjs.map +1 -0
- package/dist/{setup-complete-CcpXaPU7.mjs → setup-complete-BClXXTvr.mjs} +2 -2
- package/dist/{setup-complete-CcpXaPU7.mjs.map → setup-complete-BClXXTvr.mjs.map} +1 -1
- package/dist/{setup-nonce-Reyw30jg.mjs → setup-nonce-BheRa4RG.mjs} +1 -1
- package/dist/{setup-nonce-Reyw30jg.mjs.map → setup-nonce-BheRa4RG.mjs.map} +1 -1
- package/dist/{single-flight-cache-BPuGPdcN.mjs → single-flight-cache-jaswDzmQ.mjs} +2 -2
- package/dist/{single-flight-cache-BPuGPdcN.mjs.map → single-flight-cache-jaswDzmQ.mjs.map} +1 -1
- package/dist/{site-url-Cs_V9n3V.mjs → site-url-Bqf-ea3N.mjs} +3 -3
- package/dist/{site-url-Cs_V9n3V.mjs.map → site-url-Bqf-ea3N.mjs.map} +1 -1
- package/dist/{snapshot-DSB8P7Lm.mjs → snapshot-C4CtXntb.mjs} +51 -35
- package/dist/snapshot-C4CtXntb.mjs.map +1 -0
- package/dist/{ssrf-DqebVE34.mjs → ssrf-gl4gFNhw.mjs} +151 -93
- package/dist/ssrf-gl4gFNhw.mjs.map +1 -0
- package/dist/{state-BJfU9Uzw.mjs → state-1F6IOhdQ.mjs} +1 -1
- package/dist/{state-BJfU9Uzw.mjs.map → state-1F6IOhdQ.mjs.map} +1 -1
- package/dist/{status-DDu8HIQl.mjs → status-Cenfk_r5.mjs} +1 -1
- package/dist/{status-DDu8HIQl.mjs.map → status-Cenfk_r5.mjs.map} +1 -1
- package/dist/storage/local.d.mts +2 -1
- package/dist/storage/local.d.mts.map +1 -1
- package/dist/storage/local.mjs +1 -1
- package/dist/storage/local.mjs.map +1 -1
- package/dist/storage/s3.d.mts +2 -1
- package/dist/storage/s3.d.mts.map +1 -1
- package/dist/storage/s3.mjs +3 -2
- package/dist/storage/s3.mjs.map +1 -1
- package/dist/{target-D0o26Azo.mjs → target-CRzeTs8G.mjs} +1 -1
- package/dist/{target-D0o26Azo.mjs.map → target-CRzeTs8G.mjs.map} +1 -1
- package/dist/{taxonomies-CPGxo-bn.mjs → taxonomies-BOdxuZpV.mjs} +23 -13
- package/dist/taxonomies-BOdxuZpV.mjs.map +1 -0
- package/dist/{taxonomies-kmyudNGP.mjs → taxonomies-NcFDq5Gg.mjs} +58 -23
- package/dist/taxonomies-NcFDq5Gg.mjs.map +1 -0
- package/dist/{taxonomy-8X09dLN5.mjs → taxonomy-DP1vny4K.mjs} +12 -4
- package/dist/{taxonomy-8X09dLN5.mjs.map → taxonomy-DP1vny4K.mjs.map} +1 -1
- package/dist/{tokens-gTS-IVUp.mjs → tokens-CDk8ox9p.mjs} +1 -1
- package/dist/{tokens-gTS-IVUp.mjs.map → tokens-CDk8ox9p.mjs.map} +1 -1
- package/dist/{transport-_6R1ub7t.d.mts → transport-BVn4tVb9.d.mts} +1 -1
- package/dist/{transport-_6R1ub7t.d.mts.map → transport-BVn4tVb9.d.mts.map} +1 -1
- package/dist/{transport-fX59xaJz.mjs → transport-DP0JI-8i.mjs} +1 -1
- package/dist/{transport-fX59xaJz.mjs.map → transport-DP0JI-8i.mjs.map} +1 -1
- package/dist/{trusted-proxy-fe6nEgR4.mjs → trusted-proxy-BTM6UxqD.mjs} +1 -1
- package/dist/{trusted-proxy-fe6nEgR4.mjs.map → trusted-proxy-BTM6UxqD.mjs.map} +1 -1
- package/dist/{types-D_DWe7k9.d.mts → types-2n848aVW.d.mts} +3 -2
- package/dist/types-2n848aVW.d.mts.map +1 -0
- package/dist/types-A2cN6a4a.mjs +3 -0
- package/dist/{types-75KIqzL9.mjs → types-BMXnRIrX.mjs} +4 -2
- package/dist/types-BMXnRIrX.mjs.map +1 -0
- package/dist/{types-Vg6f5i3s.d.mts → types-BouXpOsa.d.mts} +121 -4
- package/dist/types-BouXpOsa.d.mts.map +1 -0
- package/dist/{types-BXUmsINL.mjs → types-ByG2coLw.mjs} +1 -1
- package/dist/{types-BXUmsINL.mjs.map → types-ByG2coLw.mjs.map} +1 -1
- package/dist/types-CQPWhPxE.mjs.map +1 -1
- package/dist/{types-Blb-MRC3.d.mts → types-DEfNJ__A.d.mts} +1 -1
- package/dist/{types-Blb-MRC3.d.mts.map → types-DEfNJ__A.d.mts.map} +1 -1
- package/dist/{types-Br-ERaxh.d.mts → types-DKcKSbtB.d.mts} +23 -7
- package/dist/types-DKcKSbtB.d.mts.map +1 -0
- package/dist/{types-BzBd3PeX.d.mts → types-DRYs7uTL.d.mts} +1 -1
- package/dist/{types-BzBd3PeX.d.mts.map → types-DRYs7uTL.d.mts.map} +1 -1
- package/dist/{types-CLqvnd05.d.mts → types-DaEg7KX2.d.mts} +1 -1
- package/dist/{types-CLqvnd05.d.mts.map → types-DaEg7KX2.d.mts.map} +1 -1
- package/dist/{types-DJQxln7q.d.mts → types-LU8utpP_.d.mts} +14 -10
- package/dist/types-LU8utpP_.d.mts.map +1 -0
- package/dist/{types-D5VVLr7J.d.mts → types-VpYfPUxN.d.mts} +1 -1
- package/dist/{types-D5VVLr7J.d.mts.map → types-VpYfPUxN.d.mts.map} +1 -1
- package/dist/{types-DM3vioBY.mjs → types-c9GP7Dj5.mjs} +1 -1
- package/dist/{types-DM3vioBY.mjs.map → types-c9GP7Dj5.mjs.map} +1 -1
- package/dist/{types-DHxzBjbD.d.mts → types-tJWDK__M.d.mts} +14 -1
- package/dist/types-tJWDK__M.d.mts.map +1 -0
- package/dist/{upload-attempts-CNyGSepg.mjs → upload-attempts-C6S2y-lp.mjs} +1 -1
- package/dist/{upload-attempts-CNyGSepg.mjs.map → upload-attempts-C6S2y-lp.mjs.map} +1 -1
- package/dist/{url-pattern-K-KdXcSe.mjs → url-pattern-UYtxVTuj.mjs} +1 -1
- package/dist/{url-pattern-K-KdXcSe.mjs.map → url-pattern-UYtxVTuj.mjs.map} +1 -1
- package/dist/{user-CtYY0tp2.mjs → user-DIsIXogT.mjs} +2 -2
- package/dist/{user-CtYY0tp2.mjs.map → user-DIsIXogT.mjs.map} +1 -1
- package/dist/{utils-HztC73hq.mjs → utils-BicP5Qbg.mjs} +2 -2
- package/dist/{utils-HztC73hq.mjs.map → utils-BicP5Qbg.mjs.map} +1 -1
- package/dist/{validate-Dd-IUjnZ.mjs → validate-D8VPn4Hv.mjs} +8 -3
- package/dist/validate-D8VPn4Hv.mjs.map +1 -0
- package/dist/{validate-DlqdOZXB.d.mts → validate-Df6Dvwbw.d.mts} +12 -7
- package/dist/validate-Df6Dvwbw.d.mts.map +1 -0
- package/dist/{validation-D83n7Npi.mjs → validation-CzMJn9Ku.mjs} +13 -11
- package/dist/{validation-D83n7Npi.mjs.map → validation-CzMJn9Ku.mjs.map} +1 -1
- package/dist/version-CK67_SXX.mjs +7 -0
- package/dist/{version-ri-sCyAp.mjs.map → version-CK67_SXX.mjs.map} +1 -1
- package/dist/{widgets-CpmZd9Q-.mjs → widgets-RFVAxQl3.mjs} +18 -5
- package/dist/widgets-RFVAxQl3.mjs.map +1 -0
- package/dist/{wxr-taxonomies-BFd0y72_.d.mts → wxr-taxonomies-BX4yQL9s.d.mts} +1 -1
- package/dist/{wxr-taxonomies-BFd0y72_.d.mts.map → wxr-taxonomies-BX4yQL9s.d.mts.map} +1 -1
- package/dist/{wxr-taxonomies-Df4vxWcU.mjs → wxr-taxonomies-Csdp7yde.mjs} +4 -4
- package/dist/{wxr-taxonomies-Df4vxWcU.mjs.map → wxr-taxonomies-Csdp7yde.mjs.map} +1 -1
- package/dist/{zod-generator-DylzusHh.mjs → zod-generator-CNRGdnBY.mjs} +11 -7
- package/dist/zod-generator-CNRGdnBY.mjs.map +1 -0
- package/package.json +16 -11
- package/src/api/errors.ts +9 -0
- package/src/api/handlers/content.ts +115 -90
- package/src/api/handlers/entry-lock.ts +206 -0
- package/src/api/handlers/index.ts +1 -0
- package/src/api/handlers/manifest.ts +162 -12
- package/src/api/handlers/marketplace.ts +28 -20
- package/src/api/handlers/media.ts +30 -0
- package/src/api/handlers/menus.ts +9 -0
- package/src/api/handlers/registry.ts +406 -297
- package/src/api/handlers/revision.ts +2 -1
- package/src/api/handlers/seo.ts +10 -1
- package/src/api/handlers/snapshot.ts +84 -72
- package/src/api/handlers/taxonomies.ts +25 -9
- package/src/api/openapi/document.ts +196 -11
- package/src/api/parse.ts +1 -1
- package/src/api/schemas/auth.ts +4 -4
- package/src/api/schemas/bylines.ts +3 -3
- package/src/api/schemas/comments.ts +1 -1
- package/src/api/schemas/common.ts +3 -2
- package/src/api/schemas/content.ts +86 -22
- package/src/api/schemas/entry-lock.ts +48 -0
- package/src/api/schemas/index.ts +1 -0
- package/src/api/schemas/media.ts +52 -0
- package/src/api/schemas/redirects.ts +6 -1
- package/src/api/schemas/schema.ts +14 -1
- package/src/api/schemas/setup.ts +1 -1
- package/src/api/schemas/taxonomies.ts +2 -2
- package/src/api/schemas/users.ts +1 -1
- package/src/api/types.ts +25 -10
- package/src/astro/dev-typegen.ts +35 -0
- package/src/astro/image-endpoint.ts +2 -2
- package/src/astro/integration/dev-typegen.ts +91 -0
- package/src/astro/integration/index.ts +18 -50
- package/src/astro/integration/routes.ts +10 -0
- package/src/astro/integration/runtime.ts +13 -5
- package/src/astro/integration/vite-config.ts +51 -2
- package/src/astro/middleware.ts +21 -0
- package/src/astro/routes/api/admin/api-tokens/index.ts +4 -1
- package/src/astro/routes/api/admin/oauth-clients/[id].ts +1 -1
- package/src/astro/routes/api/admin/oauth-clients/index.ts +1 -1
- package/src/astro/routes/api/admin/plugins/registry/[id]/update.ts +4 -0
- package/src/astro/routes/api/admin/plugins/registry/artifact.ts +3 -7
- package/src/astro/routes/api/admin/plugins/registry/install.ts +4 -0
- package/src/astro/routes/api/admin/plugins/registry/verify.ts +60 -0
- package/src/astro/routes/api/content/[collection]/[id]/discard-draft.ts +18 -2
- package/src/astro/routes/api/content/[collection]/[id]/lock.ts +133 -0
- package/src/astro/routes/api/content/[collection]/[id]/publish.ts +12 -1
- package/src/astro/routes/api/content/[collection]/[id]/schedule.ts +20 -0
- package/src/astro/routes/api/content/[collection]/[id]/unpublish.ts +16 -2
- package/src/astro/routes/api/content/[collection]/[id].ts +27 -2
- package/src/astro/routes/api/content/[collection]/index.ts +3 -0
- package/src/astro/routes/api/manifest.ts +1 -1
- package/src/astro/routes/api/media/[id]/replace.ts +114 -0
- package/src/astro/routes/api/media/file/[...key].ts +4 -1
- package/src/astro/routes/api/media/upload-url.ts +8 -4
- package/src/astro/routes/api/media.ts +54 -8
- package/src/astro/routes/api/menus/[name]/items/[id].ts +7 -2
- package/src/astro/routes/api/menus/[name]/items.ts +4 -1
- package/src/astro/routes/api/menus/[name]/reorder.ts +4 -1
- package/src/astro/routes/api/menus/[name]/translations.ts +4 -1
- package/src/astro/routes/api/menus/[name].ts +7 -2
- package/src/astro/routes/api/menus/index.ts +4 -1
- package/src/astro/routes/api/settings/email.ts +1 -1
- package/src/astro/routes/api/settings.ts +4 -1
- package/src/astro/routes/api/taxonomies/[name]/reorder.ts +4 -1
- package/src/astro/routes/api/taxonomies/[name]/terms/[slug]/translations.ts +4 -1
- package/src/astro/routes/api/taxonomies/[name]/terms/[slug].ts +7 -2
- package/src/astro/routes/api/taxonomies/[name]/terms/index.ts +4 -1
- package/src/astro/routes/api/taxonomies/[name].ts +7 -2
- package/src/astro/routes/api/taxonomies/index.ts +4 -1
- package/src/astro/routes/api/widget-areas/[name]/reorder.ts +3 -1
- package/src/astro/routes/api/widget-areas/[name]/widgets/[id].ts +5 -2
- package/src/astro/routes/api/widget-areas/[name]/widgets.ts +3 -1
- package/src/astro/routes/api/widget-areas/[name].ts +3 -1
- package/src/astro/routes/api/widget-areas/index.ts +3 -1
- package/src/astro/routes/sitemap-[collection].xml.ts +4 -0
- package/src/astro/types.ts +36 -8
- package/src/auth/challenge-store.ts +3 -1
- package/src/aws-sdk.d.ts +1 -0
- package/src/cache/chrome-tags.ts +24 -0
- package/src/cli/commands/content.ts +31 -5
- package/src/cli/commands/export-seed.ts +2 -0
- package/src/client/index.ts +34 -7
- package/src/components/EmDashBodyEnd.astro +4 -1
- package/src/components/EmDashBodyStart.astro +4 -1
- package/src/components/EmDashHead.astro +35 -16
- package/src/components/EmDashImage.astro +2 -1
- package/src/components/EmDashMedia.astro +2 -1
- package/src/components/Gallery.astro +18 -4
- package/src/components/InlineEditor.astro +3 -1
- package/src/components/InlinePortableTextEditor.tsx +112 -12
- package/src/components/PortableText.astro +4 -0
- package/src/components/Table.astro +147 -62
- package/src/components/widgets/Archives.astro +2 -37
- package/src/config/errors.ts +13 -0
- package/src/content/converters/index.ts +2 -0
- package/src/content/converters/mark-safety.ts +1 -0
- package/src/content/converters/portable-text-identity.ts +139 -0
- package/src/content/converters/portable-text-to-prosemirror.ts +226 -69
- package/src/content/converters/prosemirror-to-portable-text.ts +128 -28
- package/src/content/converters/types.ts +11 -0
- package/src/database/dialect-helpers.ts +125 -0
- package/src/database/migrations/017_authorization_codes.ts +14 -4
- package/src/database/migrations/074_content_deleted_scheduled_index.ts +55 -0
- package/src/database/migrations/075_entry_edit_locks.ts +44 -0
- package/src/database/migrations/076_collection_nav_group.ts +22 -0
- package/src/database/migrations/077_plugin_storage_revisions.ts +89 -0
- package/src/database/migrations/runner.ts +9 -1
- package/src/database/repositories/byline.ts +32 -16
- package/src/database/repositories/content.ts +284 -48
- package/src/database/repositories/entry-locks.ts +257 -0
- package/src/database/repositories/media-usage.ts +66 -37
- package/src/database/repositories/media.ts +60 -1
- package/src/database/repositories/options.ts +69 -5
- package/src/database/repositories/plugin-storage.ts +233 -9
- package/src/database/repositories/redirect.ts +17 -6
- package/src/database/repositories/taxonomy.ts +8 -0
- package/src/database/repositories/types.ts +11 -7
- package/src/database/types.ts +15 -1
- package/src/db/adapters.ts +8 -1
- package/src/db/postgres.ts +23 -0
- package/src/emdash-runtime.ts +196 -199
- package/src/fields/boolean.ts +1 -1
- package/src/fields/datetime.ts +1 -1
- package/src/fields/file.ts +1 -1
- package/src/fields/integer.ts +1 -1
- package/src/fields/json.ts +1 -1
- package/src/fields/multiselect.ts +1 -1
- package/src/fields/number.ts +1 -1
- package/src/fields/portable-text.ts +1 -1
- package/src/fields/richtext.ts +1 -1
- package/src/fields/select.ts +1 -1
- package/src/fields/slug.ts +1 -1
- package/src/fields/text.ts +1 -1
- package/src/fields/textarea.ts +1 -1
- package/src/fields/types.ts +2 -2
- package/src/i18n/resolve.ts +44 -4
- package/src/index.ts +39 -3
- package/src/loader.ts +96 -12
- package/src/mcp/server.ts +251 -29
- package/src/media/image-endpoint.ts +5 -2
- package/src/media/normalize.ts +15 -4
- package/src/media/responsive.ts +23 -0
- package/src/media/usage/cleanup.ts +9 -8
- package/src/media/usage/content-refresh.ts +2 -1
- package/src/menus/index.ts +33 -21
- package/src/object-cache/index.ts +44 -2
- package/src/page/seo-contributions.ts +78 -1
- package/src/page/seo-panel.ts +47 -0
- package/src/plugin-types.ts +27 -1
- package/src/plugins/conditional-storage.ts +30 -0
- package/src/plugins/context.ts +49 -17
- package/src/plugins/hooks.ts +10 -1
- package/src/plugins/index.ts +15 -0
- package/src/plugins/manager.ts +6 -2
- package/src/plugins/manifest-schema.ts +1 -1
- package/src/plugins/routes.ts +3 -1
- package/src/plugins/sandbox/hook-result.ts +52 -0
- package/src/plugins/sandbox/index.ts +10 -0
- package/src/plugins/sandbox/types.ts +16 -2
- package/src/plugins/storage-query.ts +45 -0
- package/src/plugins/storage-update.ts +96 -0
- package/src/plugins/types.ts +120 -0
- package/src/query.ts +29 -3
- package/src/registry/artifact-checksum.ts +15 -0
- package/src/registry/artifact-verification.ts +85 -0
- package/src/registry/authoritative-records.ts +180 -0
- package/src/registry/config.ts +130 -27
- package/src/registry/record-labels.ts +28 -0
- package/src/registry/types.ts +5 -6
- package/src/schema/collection-slugs-cache.ts +157 -0
- package/src/schema/registry.ts +45 -3
- package/src/schema/types.ts +25 -6
- package/src/schema/zod-generator.ts +16 -13
- package/src/security/ssrf.ts +172 -143
- package/src/seed/apply.ts +4 -0
- package/src/seed/types.ts +7 -2
- package/src/seed/validate.ts +18 -1
- package/src/seo/hreflang.ts +1 -0
- package/src/seo/index.ts +5 -10
- package/src/seo/media-url.ts +26 -0
- package/src/settings/index.ts +16 -0
- package/src/storage/local.ts +1 -0
- package/src/storage/s3.ts +2 -0
- package/src/storage/types.ts +2 -0
- package/src/taxonomies/index.ts +40 -20
- package/src/taxonomies/term-counts.ts +22 -5
- package/src/widgets/archives.ts +67 -0
- package/src/widgets/index.ts +16 -0
- package/dist/api-B0w3uBiG.mjs +0 -2269
- package/dist/api-B0w3uBiG.mjs.map +0 -1
- package/dist/apply-B_VMpJ2P.mjs.map +0 -1
- package/dist/byline-Cpnwrje1.mjs.map +0 -1
- package/dist/challenge-store-D5pSY2S1.mjs.map +0 -1
- package/dist/content-CP-SeXNa.mjs.map +0 -1
- package/dist/content-refresh-DLOfIhYc.mjs.map +0 -1
- package/dist/context-BR5hRWiK.mjs.map +0 -1
- package/dist/dialect-helpers-BSbfaO3F.mjs.map +0 -1
- package/dist/errors-n2j49uNf.mjs.map +0 -1
- package/dist/index-DWbJrsAg.d.mts.map +0 -1
- package/dist/loader-ZsjE4paL.mjs.map +0 -1
- package/dist/manifest-schema-CUYPfCEH.mjs.map +0 -1
- package/dist/media-BjwNuLEu.mjs.map +0 -1
- package/dist/media-D6SeAfBl.mjs.map +0 -1
- package/dist/media-url-DH7giMx_.mjs.map +0 -1
- package/dist/menus-CNg0QlDt.mjs.map +0 -1
- package/dist/normalize-CSxdKBVa.mjs.map +0 -1
- package/dist/object-cache-71tPfV4A.mjs.map +0 -1
- package/dist/options-BHPeIbBd.mjs.map +0 -1
- package/dist/options-BhZIeFY1.d.mts.map +0 -1
- package/dist/query-D18vTdha.mjs.map +0 -1
- package/dist/redirect-CZkbozu9.mjs.map +0 -1
- package/dist/redirects-CRIM55KH.mjs.map +0 -1
- package/dist/registry-BiO5WwPq.mjs +0 -2716
- package/dist/registry-BiO5WwPq.mjs.map +0 -1
- package/dist/registry-Cx-jEJOS.mjs.map +0 -1
- package/dist/relations-BTPM2saV.mjs.map +0 -1
- package/dist/relations-C7B46bcU.d.mts.map +0 -1
- package/dist/resolve-DxUpTMmE.mjs.map +0 -1
- package/dist/runner-77GOZCnH.mjs.map +0 -1
- package/dist/runner-zgqA_CqP.d.mts.map +0 -1
- package/dist/seo-BSiTIXzd.mjs.map +0 -1
- package/dist/settings-BgN-0DT-.mjs.map +0 -1
- package/dist/snapshot-DSB8P7Lm.mjs.map +0 -1
- package/dist/ssrf-DqebVE34.mjs.map +0 -1
- package/dist/taxonomies-CPGxo-bn.mjs.map +0 -1
- package/dist/taxonomies-kmyudNGP.mjs.map +0 -1
- package/dist/types-75KIqzL9.mjs.map +0 -1
- package/dist/types-Br-ERaxh.d.mts.map +0 -1
- package/dist/types-D6OcIp2P.mjs +0 -3
- package/dist/types-DHxzBjbD.d.mts.map +0 -1
- package/dist/types-DJQxln7q.d.mts.map +0 -1
- package/dist/types-D_DWe7k9.d.mts.map +0 -1
- package/dist/types-Vg6f5i3s.d.mts.map +0 -1
- package/dist/validate-Dd-IUjnZ.mjs.map +0 -1
- package/dist/validate-DlqdOZXB.d.mts.map +0 -1
- package/dist/version-ri-sCyAp.mjs +0 -7
- package/dist/widgets-CpmZd9Q-.mjs.map +0 -1
- package/dist/zod-generator-DylzusHh.mjs.map +0 -1
- /package/dist/{api-tokens-B5NHLNUN.mjs → api-tokens-B_lfpmH3.mjs} +0 -0
- /package/dist/{ssrf-BPKzkm6O.mjs → ssrf-TQhaljuI.mjs} +0 -0
|
@@ -1,70 +1,110 @@
|
|
|
1
1
|
//#region src/security/ssrf.ts
|
|
2
2
|
/**
|
|
3
|
-
* SSRF protection for
|
|
3
|
+
* SSRF protection for outbound HTTP requests.
|
|
4
4
|
*
|
|
5
|
-
* Validates that URLs
|
|
6
|
-
* Applied before any fetch() call in the import pipeline.
|
|
5
|
+
* Validates that URLs do not target non-public network addresses.
|
|
7
6
|
*/
|
|
8
|
-
const IPV4_MAPPED_IPV6_DOTTED_PATTERN = /^::ffff:(\d+\.\d+\.\d+\.\d+)$/i;
|
|
9
|
-
const IPV4_MAPPED_IPV6_HEX_PATTERN = /^::ffff:([0-9a-f]{1,4}):([0-9a-f]{1,4})$/i;
|
|
10
|
-
const IPV4_TRANSLATED_HEX_PATTERN = /^::ffff:0:([0-9a-f]{1,4}):([0-9a-f]{1,4})$/i;
|
|
11
|
-
const IPV6_EXPANDED_MAPPED_PATTERN = /^0{0,4}:0{0,4}:0{0,4}:0{0,4}:0{0,4}:ffff:([0-9a-f]{1,4}):([0-9a-f]{1,4})$/i;
|
|
12
|
-
/**
|
|
13
|
-
* IPv4-compatible (deprecated) addresses: ::XXXX:XXXX
|
|
14
|
-
*
|
|
15
|
-
* The WHATWG URL parser normalizes [::127.0.0.1] to [::7f00:1] (no ffff prefix).
|
|
16
|
-
* These are deprecated but still parsed, and bypass the ffff-based checks.
|
|
17
|
-
*/
|
|
18
|
-
const IPV4_COMPATIBLE_HEX_PATTERN = /^::([0-9a-f]{1,4}):([0-9a-f]{1,4})$/i;
|
|
19
|
-
/**
|
|
20
|
-
* NAT64 prefix (RFC 6052): 64:ff9b::XXXX:XXXX
|
|
21
|
-
*
|
|
22
|
-
* Used by NAT64 gateways to embed IPv4 addresses in IPv6.
|
|
23
|
-
* [64:ff9b::127.0.0.1] normalizes to [64:ff9b::7f00:1].
|
|
24
|
-
*/
|
|
25
|
-
const NAT64_HEX_PATTERN = /^64:ff9b::([0-9a-f]{1,4}):([0-9a-f]{1,4})$/i;
|
|
26
7
|
const IPV6_BRACKET_PATTERN = /^\[|\]$/g;
|
|
27
|
-
|
|
28
|
-
const
|
|
29
|
-
const IPV6_ULA_FD_PATTERN = /^fd[0-9a-f]{2}:/;
|
|
8
|
+
const IPV4_PART_PATTERN = /^(?:0|[1-9]\d{0,2})$/;
|
|
9
|
+
const IPV6_PART_PATTERN = /^[0-9a-f]{1,4}$/i;
|
|
30
10
|
/** Strip trailing dots from an FQDN-form hostname ("localhost." -> "localhost"). */
|
|
31
11
|
const TRAILING_DOT_PATTERN = /\.+$/;
|
|
32
12
|
/**
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
* Includes:
|
|
36
|
-
* - Loopback (127.0.0.0/8)
|
|
37
|
-
* - Private (10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16)
|
|
38
|
-
* - Link-local (169.254.0.0/16)
|
|
39
|
-
* - Cloud metadata (169.254.169.254 — AWS/GCP/Azure)
|
|
40
|
-
* - IPv6 loopback and link-local
|
|
13
|
+
* IPv4 ranges that are not globally reachable unicast destinations.
|
|
41
14
|
*/
|
|
42
15
|
const BLOCKED_PATTERNS = [
|
|
43
16
|
{
|
|
44
|
-
start: ip4ToNum(
|
|
45
|
-
end: ip4ToNum(
|
|
17
|
+
start: ip4ToNum(0, 0, 0, 0),
|
|
18
|
+
end: ip4ToNum(0, 255, 255, 255)
|
|
46
19
|
},
|
|
47
20
|
{
|
|
48
21
|
start: ip4ToNum(10, 0, 0, 0),
|
|
49
22
|
end: ip4ToNum(10, 255, 255, 255)
|
|
50
23
|
},
|
|
24
|
+
{
|
|
25
|
+
start: ip4ToNum(100, 64, 0, 0),
|
|
26
|
+
end: ip4ToNum(100, 127, 255, 255)
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
start: ip4ToNum(127, 0, 0, 0),
|
|
30
|
+
end: ip4ToNum(127, 255, 255, 255)
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
start: ip4ToNum(169, 254, 0, 0),
|
|
34
|
+
end: ip4ToNum(169, 254, 255, 255)
|
|
35
|
+
},
|
|
51
36
|
{
|
|
52
37
|
start: ip4ToNum(172, 16, 0, 0),
|
|
53
38
|
end: ip4ToNum(172, 31, 255, 255)
|
|
54
39
|
},
|
|
40
|
+
{
|
|
41
|
+
start: ip4ToNum(192, 0, 0, 0),
|
|
42
|
+
end: ip4ToNum(192, 0, 0, 255)
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
start: ip4ToNum(192, 0, 2, 0),
|
|
46
|
+
end: ip4ToNum(192, 0, 2, 255)
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
start: ip4ToNum(192, 88, 99, 0),
|
|
50
|
+
end: ip4ToNum(192, 88, 99, 255)
|
|
51
|
+
},
|
|
55
52
|
{
|
|
56
53
|
start: ip4ToNum(192, 168, 0, 0),
|
|
57
54
|
end: ip4ToNum(192, 168, 255, 255)
|
|
58
55
|
},
|
|
59
56
|
{
|
|
60
|
-
start: ip4ToNum(
|
|
61
|
-
end: ip4ToNum(
|
|
57
|
+
start: ip4ToNum(198, 18, 0, 0),
|
|
58
|
+
end: ip4ToNum(198, 19, 255, 255)
|
|
62
59
|
},
|
|
63
60
|
{
|
|
64
|
-
start: ip4ToNum(
|
|
65
|
-
end: ip4ToNum(
|
|
61
|
+
start: ip4ToNum(198, 51, 100, 0),
|
|
62
|
+
end: ip4ToNum(198, 51, 100, 255)
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
start: ip4ToNum(203, 0, 113, 0),
|
|
66
|
+
end: ip4ToNum(203, 0, 113, 255)
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
start: ip4ToNum(224, 0, 0, 0),
|
|
70
|
+
end: ip4ToNum(255, 255, 255, 255)
|
|
66
71
|
}
|
|
67
72
|
];
|
|
73
|
+
const ALLOWED_IPV4_EXCEPTIONS = new Set([ip4ToNum(192, 0, 0, 9), ip4ToNum(192, 0, 0, 10)]);
|
|
74
|
+
function ipv6Range(address, prefixLength) {
|
|
75
|
+
const parsed = parseIpv6(address);
|
|
76
|
+
if (parsed === null) throw new Error(`Invalid IPv6 range: ${address}/${prefixLength}`);
|
|
77
|
+
return {
|
|
78
|
+
address: parsed,
|
|
79
|
+
prefixLength
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
const IPV6_GLOBAL_UNICAST_RANGE = ipv6Range("2000::", 3);
|
|
83
|
+
const IPV4_COMPATIBLE_IPV6_RANGE = ipv6Range("::", 96);
|
|
84
|
+
const IPV4_EMBEDDED_IPV6_RANGES = [
|
|
85
|
+
IPV4_COMPATIBLE_IPV6_RANGE,
|
|
86
|
+
ipv6Range("::ffff:0:0", 96),
|
|
87
|
+
ipv6Range("::ffff:0:0:0", 96),
|
|
88
|
+
ipv6Range("64:ff9b::", 96)
|
|
89
|
+
];
|
|
90
|
+
/** Globally reachable allocations inside the otherwise reserved 2001::/23 block. */
|
|
91
|
+
const ALLOWED_IPV6_SPECIAL_RANGES = [
|
|
92
|
+
ipv6Range("2001:1::1", 128),
|
|
93
|
+
ipv6Range("2001:1::2", 128),
|
|
94
|
+
ipv6Range("2001:1::3", 128),
|
|
95
|
+
ipv6Range("2001:3::", 32),
|
|
96
|
+
ipv6Range("2001:4:112::", 48),
|
|
97
|
+
ipv6Range("2001:20::", 28),
|
|
98
|
+
ipv6Range("2001:30::", 28)
|
|
99
|
+
];
|
|
100
|
+
/** Non-global allocations inside the ordinary IPv6 global-unicast range. */
|
|
101
|
+
const BLOCKED_IPV6_GLOBAL_UNICAST_RANGES = [
|
|
102
|
+
ipv6Range("2001::", 23),
|
|
103
|
+
ipv6Range("2001:db8::", 32),
|
|
104
|
+
ipv6Range("2002::", 16),
|
|
105
|
+
ipv6Range("3ffe::", 16),
|
|
106
|
+
ipv6Range("3fff::", 20)
|
|
107
|
+
];
|
|
68
108
|
const BLOCKED_HOSTNAMES = new Set([
|
|
69
109
|
"localhost",
|
|
70
110
|
"metadata.google.internal",
|
|
@@ -95,41 +135,59 @@ function ip4ToNum(a, b, c, d) {
|
|
|
95
135
|
function parseIpv4(ip) {
|
|
96
136
|
const parts = ip.split(".");
|
|
97
137
|
if (parts.length !== 4) return null;
|
|
98
|
-
const nums = parts.map(Number);
|
|
99
|
-
if (nums.some((n) =>
|
|
138
|
+
const nums = parts.map((part) => IPV4_PART_PATTERN.test(part) ? Number(part) : NaN);
|
|
139
|
+
if (nums.some((n) => !Number.isInteger(n) || n < 0 || n > 255)) return null;
|
|
100
140
|
return ip4ToNum(nums[0], nums[1], nums[2], nums[3]);
|
|
101
141
|
}
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
*/
|
|
111
|
-
function normalizeIPv6MappedToIPv4(ip) {
|
|
112
|
-
let match = ip.match(IPV4_MAPPED_IPV6_HEX_PATTERN);
|
|
113
|
-
if (!match) match = ip.match(IPV4_TRANSLATED_HEX_PATTERN);
|
|
114
|
-
if (!match) match = ip.match(IPV6_EXPANDED_MAPPED_PATTERN);
|
|
115
|
-
if (!match) match = ip.match(IPV4_COMPATIBLE_HEX_PATTERN);
|
|
116
|
-
if (!match) match = ip.match(NAT64_HEX_PATTERN);
|
|
117
|
-
if (match) {
|
|
118
|
-
const high = parseInt(match[1] ?? "", 16);
|
|
119
|
-
const low = parseInt(match[2] ?? "", 16);
|
|
120
|
-
return `${high >> 8 & 255}.${high & 255}.${low >> 8 & 255}.${low & 255}`;
|
|
142
|
+
function parseIpv6(ip) {
|
|
143
|
+
let address = ip;
|
|
144
|
+
if (address.includes(".")) {
|
|
145
|
+
const separator = address.lastIndexOf(":");
|
|
146
|
+
if (separator === -1) return null;
|
|
147
|
+
const ipv4 = parseIpv4(address.slice(separator + 1));
|
|
148
|
+
if (ipv4 === null) return null;
|
|
149
|
+
address = `${address.slice(0, separator + 1)}${(ipv4 >>> 16).toString(16)}:${(ipv4 & 65535).toString(16)}`;
|
|
121
150
|
}
|
|
122
|
-
return null;
|
|
151
|
+
if (address.includes(":::") || address.split("::").length > 2) return null;
|
|
152
|
+
const [before = "", after = ""] = address.split("::");
|
|
153
|
+
const head = before === "" ? [] : before.split(":");
|
|
154
|
+
const tail = after === "" ? [] : after.split(":");
|
|
155
|
+
const parts = [...head, ...tail];
|
|
156
|
+
if (parts.some((part) => !IPV6_PART_PATTERN.test(part)) || parts.length > 8) return null;
|
|
157
|
+
if (address.includes("::") ? parts.length >= 8 : parts.length !== 8) return null;
|
|
158
|
+
const zeroCount = address.includes("::") ? 8 - parts.length : 0;
|
|
159
|
+
return [
|
|
160
|
+
...head,
|
|
161
|
+
...Array.from({ length: zeroCount }).fill("0"),
|
|
162
|
+
...tail
|
|
163
|
+
].map((part) => Number.parseInt(part, 16));
|
|
164
|
+
}
|
|
165
|
+
function isIpv6InRange(address, range) {
|
|
166
|
+
const completeParts = Math.floor(range.prefixLength / 16);
|
|
167
|
+
for (let i = 0; i < completeParts; i++) if (address[i] !== range.address[i]) return false;
|
|
168
|
+
const remainingBits = range.prefixLength % 16;
|
|
169
|
+
if (remainingBits === 0) return true;
|
|
170
|
+
const mask = 65535 << 16 - remainingBits & 65535;
|
|
171
|
+
return (address[completeParts] & mask) === (range.address[completeParts] & mask);
|
|
123
172
|
}
|
|
124
|
-
function
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
173
|
+
function extractEmbeddedIpv4(address) {
|
|
174
|
+
if (!IPV4_EMBEDDED_IPV6_RANGES.some((range) => isIpv6InRange(address, range))) return null;
|
|
175
|
+
const ipv4 = (address[6] << 16 | address[7]) >>> 0;
|
|
176
|
+
if (ipv4 <= 1 && isIpv6InRange(address, IPV4_COMPATIBLE_IPV6_RANGE)) return null;
|
|
177
|
+
return ipv4;
|
|
178
|
+
}
|
|
179
|
+
function isNonPublicIp(ip) {
|
|
180
|
+
const parsedIpv4 = parseIpv4(ip);
|
|
181
|
+
const ipv6 = parsedIpv4 === null ? parseIpv6(ip) : null;
|
|
182
|
+
const ipv4 = ipv6 === null ? parsedIpv4 : extractEmbeddedIpv4(ipv6);
|
|
183
|
+
if (ipv4 !== null) {
|
|
184
|
+
if (ALLOWED_IPV4_EXCEPTIONS.has(ipv4)) return false;
|
|
185
|
+
return BLOCKED_PATTERNS.some((range) => ipv4 >= range.start && ipv4 <= range.end);
|
|
186
|
+
}
|
|
187
|
+
if (ipv6 === null) return true;
|
|
188
|
+
if (ALLOWED_IPV6_SPECIAL_RANGES.some((range) => isIpv6InRange(ipv6, range))) return false;
|
|
189
|
+
if (!isIpv6InRange(ipv6, IPV6_GLOBAL_UNICAST_RANGE)) return true;
|
|
190
|
+
return BLOCKED_IPV6_GLOBAL_UNICAST_RANGES.some((range) => isIpv6InRange(ipv6, range));
|
|
133
191
|
}
|
|
134
192
|
/**
|
|
135
193
|
* Error thrown when SSRF protection blocks a URL.
|
|
@@ -142,17 +200,15 @@ var SsrfError = class extends Error {
|
|
|
142
200
|
}
|
|
143
201
|
};
|
|
144
202
|
/**
|
|
145
|
-
* Validate
|
|
203
|
+
* Validate a URL's scheme, hostname, and literal address.
|
|
146
204
|
*
|
|
147
205
|
* Checks:
|
|
148
206
|
* 1. URL is well-formed with http/https scheme
|
|
149
207
|
* 2. Hostname is not a known internal name (localhost, metadata endpoints)
|
|
150
|
-
* 3. If hostname is an IP literal, it
|
|
208
|
+
* 3. If hostname is an IP literal, it is a public address
|
|
151
209
|
*
|
|
152
|
-
*
|
|
153
|
-
*
|
|
154
|
-
* before connecting, which needs a custom fetch implementation. This covers
|
|
155
|
-
* the most common SSRF vectors.
|
|
210
|
+
* Hostnames also need DNS validation before dispatch. Resolving and checking
|
|
211
|
+
* addresses does not bind an ordinary fetch() connection to those addresses.
|
|
156
212
|
*
|
|
157
213
|
* @throws SsrfError if the URL targets an internal address
|
|
158
214
|
*/
|
|
@@ -169,7 +225,7 @@ function validateExternalUrl(url) {
|
|
|
169
225
|
const normalizedHost = parsed.hostname.replace(IPV6_BRACKET_PATTERN, "").toLowerCase().replace(TRAILING_DOT_PATTERN, "");
|
|
170
226
|
if (BLOCKED_HOSTNAMES.has(normalizedHost)) throw new SsrfError("URLs targeting internal hosts are not allowed");
|
|
171
227
|
for (const suffix of BLOCKED_HOSTNAME_SUFFIXES) if (normalizedHost === suffix || normalizedHost.endsWith(`.${suffix}`)) throw new SsrfError("URLs targeting wildcard DNS services are not allowed");
|
|
172
|
-
if (
|
|
228
|
+
if (isIpLiteral(normalizedHost) && isNonPublicIp(normalizedHost)) throw new SsrfError("URLs targeting non-public IP addresses are not allowed");
|
|
173
229
|
return parsed;
|
|
174
230
|
}
|
|
175
231
|
/**
|
|
@@ -194,7 +250,10 @@ function parseDohResponse(raw) {
|
|
|
194
250
|
if (!hasProperty(raw, "Status") || typeof raw.Status !== "number") throw new Error("DoH response missing Status field");
|
|
195
251
|
const answers = [];
|
|
196
252
|
if (hasProperty(raw, "Answer") && Array.isArray(raw.Answer)) {
|
|
197
|
-
for (const entry of raw.Answer) if (hasProperty(entry, "
|
|
253
|
+
for (const entry of raw.Answer) if (hasProperty(entry, "type") && typeof entry.type === "number" && Number.isInteger(entry.type) && hasProperty(entry, "data") && typeof entry.data === "string") answers.push({
|
|
254
|
+
type: entry.type,
|
|
255
|
+
data: entry.data
|
|
256
|
+
});
|
|
198
257
|
}
|
|
199
258
|
return {
|
|
200
259
|
Status: raw.Status,
|
|
@@ -210,6 +269,7 @@ function parseDohResponse(raw) {
|
|
|
210
269
|
*/
|
|
211
270
|
const cloudflareDohResolver = async (hostname) => {
|
|
212
271
|
async function query(type) {
|
|
272
|
+
const expectedAnswerType = type === "A" ? 1 : 28;
|
|
213
273
|
const params = new URLSearchParams({
|
|
214
274
|
name: hostname,
|
|
215
275
|
type
|
|
@@ -225,7 +285,7 @@ const cloudflareDohResolver = async (hostname) => {
|
|
|
225
285
|
const body = parseDohResponse(await response.json());
|
|
226
286
|
if (body.Status === 3) return [];
|
|
227
287
|
if (body.Status !== 0) throw new Error(`DoH ${type} lookup failed: rcode=${body.Status}`);
|
|
228
|
-
return body.Answer.map((
|
|
288
|
+
return body.Answer.filter((answer) => answer.type === expectedAnswerType).map((answer) => answer.data).filter(isIpLiteral);
|
|
229
289
|
} finally {
|
|
230
290
|
clearTimeout(timeout);
|
|
231
291
|
}
|
|
@@ -234,14 +294,12 @@ const cloudflareDohResolver = async (hostname) => {
|
|
|
234
294
|
return [...a, ...aaaa];
|
|
235
295
|
};
|
|
236
296
|
/**
|
|
237
|
-
* Validate a URL and
|
|
238
|
-
*
|
|
239
|
-
* attacker-controlled domains that publicly resolve to private addresses,
|
|
240
|
-
* and wildcard DNS services like nip.io used by exploit tooling.
|
|
297
|
+
* Validate a URL and reject hostnames that resolve to non-public addresses,
|
|
298
|
+
* including wildcard DNS services like nip.io used by exploit tooling.
|
|
241
299
|
*
|
|
242
300
|
* Runs `validateExternalUrl` first for cheap pre-flight checks (scheme,
|
|
243
301
|
* literal IP, known-bad hostnames). Then resolves the hostname and rejects
|
|
244
|
-
* if ANY returned address is
|
|
302
|
+
* if ANY returned address is non-public.
|
|
245
303
|
*
|
|
246
304
|
* Fails closed: if resolution fails or returns no records, throws SsrfError.
|
|
247
305
|
*
|
|
@@ -256,9 +314,9 @@ const cloudflareDohResolver = async (hostname) => {
|
|
|
256
314
|
* - Host-file overrides or split-horizon corporate DNS on self-hosted Node.
|
|
257
315
|
* - Attacker-controlled rebinding services the caller has allowlisted.
|
|
258
316
|
*
|
|
259
|
-
*
|
|
260
|
-
*
|
|
261
|
-
*
|
|
317
|
+
* Connections must use the addresses from resolveAndValidateExternalUrlTarget
|
|
318
|
+
* to avoid a second lookup. Callers using ordinary fetch() need network-level
|
|
319
|
+
* egress controls to prevent these attacks.
|
|
262
320
|
*/
|
|
263
321
|
async function resolveAndValidateExternalUrl(url, options) {
|
|
264
322
|
return (await resolveAndValidateExternalUrlTarget(url, options)).url;
|
|
@@ -284,17 +342,16 @@ async function resolveAndValidateExternalUrlTarget(url, options) {
|
|
|
284
342
|
if (addresses.length === 0) throw new SsrfError("Hostname resolved to no addresses");
|
|
285
343
|
for (const ip of addresses) {
|
|
286
344
|
if (!isIpLiteral(ip)) throw new SsrfError("Hostname resolver returned a non-IP address");
|
|
287
|
-
if (
|
|
345
|
+
if (isNonPublicIp(ip)) throw new SsrfError("Hostname resolves to a non-public IP address");
|
|
288
346
|
}
|
|
289
347
|
return {
|
|
290
348
|
url: parsed,
|
|
291
349
|
addresses
|
|
292
350
|
};
|
|
293
351
|
}
|
|
294
|
-
/** True when a string
|
|
352
|
+
/** True when a string is a valid IPv4 or IPv6 literal. */
|
|
295
353
|
function isIpLiteral(host) {
|
|
296
|
-
|
|
297
|
-
return host.includes(":");
|
|
354
|
+
return parseIpv4(host) !== null || parseIpv6(host) !== null;
|
|
298
355
|
}
|
|
299
356
|
/**
|
|
300
357
|
* Fetch a URL with SSRF protection on redirects.
|
|
@@ -316,7 +373,8 @@ async function ssrfSafeFetch(url, init, options) {
|
|
|
316
373
|
let currentUrl = url;
|
|
317
374
|
let currentInit = init;
|
|
318
375
|
for (let i = 0; i <= MAX_REDIRECTS; i++) {
|
|
319
|
-
await resolveAndValidateExternalUrl(currentUrl, options);
|
|
376
|
+
const validated = await resolveAndValidateExternalUrl(currentUrl, options);
|
|
377
|
+
if (options?.httpsOnly === true && validated.protocol !== "https:") throw new SsrfError("Only HTTPS URLs are allowed");
|
|
320
378
|
const response = await globalThis.fetch(currentUrl, {
|
|
321
379
|
...currentInit,
|
|
322
380
|
redirect: "manual"
|
|
@@ -344,5 +402,5 @@ function stripCredentialHeaders(init) {
|
|
|
344
402
|
}
|
|
345
403
|
|
|
346
404
|
//#endregion
|
|
347
|
-
export {
|
|
348
|
-
//# sourceMappingURL=ssrf-
|
|
405
|
+
export { ssrfSafeFetch as a, resolveAndValidateExternalUrlTarget as i, cloudflareDohResolver as n, stripCredentialHeaders as o, resolveAndValidateExternalUrl as r, validateExternalUrl as s, SsrfError as t };
|
|
406
|
+
//# sourceMappingURL=ssrf-gl4gFNhw.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ssrf-gl4gFNhw.mjs","names":[],"sources":["../src/security/ssrf.ts"],"sourcesContent":["/**\n * SSRF protection for outbound HTTP requests.\n *\n * Validates that URLs do not target non-public network addresses.\n */\n\nconst IPV6_BRACKET_PATTERN = /^\\[|\\]$/g;\nconst IPV4_PART_PATTERN = /^(?:0|[1-9]\\d{0,2})$/;\nconst IPV6_PART_PATTERN = /^[0-9a-f]{1,4}$/i;\n\n/** Strip trailing dots from an FQDN-form hostname (\"localhost.\" -> \"localhost\"). */\nconst TRAILING_DOT_PATTERN = /\\.+$/;\n\n/**\n * IPv4 ranges that are not globally reachable unicast destinations.\n */\nconst BLOCKED_PATTERNS: Array<{ start: number; end: number }> = [\n\t// Current network\n\t{ start: ip4ToNum(0, 0, 0, 0), end: ip4ToNum(0, 255, 255, 255) },\n\t// Private use\n\t{ start: ip4ToNum(10, 0, 0, 0), end: ip4ToNum(10, 255, 255, 255) },\n\t// Shared address space\n\t{ start: ip4ToNum(100, 64, 0, 0), end: ip4ToNum(100, 127, 255, 255) },\n\t// Loopback\n\t{ start: ip4ToNum(127, 0, 0, 0), end: ip4ToNum(127, 255, 255, 255) },\n\t// Link-local, including common cloud metadata endpoints\n\t{ start: ip4ToNum(169, 254, 0, 0), end: ip4ToNum(169, 254, 255, 255) },\n\t// Private use\n\t{ start: ip4ToNum(172, 16, 0, 0), end: ip4ToNum(172, 31, 255, 255) },\n\t// IETF protocol assignments. Globally reachable exceptions are handled below.\n\t{ start: ip4ToNum(192, 0, 0, 0), end: ip4ToNum(192, 0, 0, 255) },\n\t// Documentation\n\t{ start: ip4ToNum(192, 0, 2, 0), end: ip4ToNum(192, 0, 2, 255) },\n\t// Deprecated 6to4 relay anycast\n\t{ start: ip4ToNum(192, 88, 99, 0), end: ip4ToNum(192, 88, 99, 255) },\n\t// Private use\n\t{ start: ip4ToNum(192, 168, 0, 0), end: ip4ToNum(192, 168, 255, 255) },\n\t// Benchmarking\n\t{ start: ip4ToNum(198, 18, 0, 0), end: ip4ToNum(198, 19, 255, 255) },\n\t// Documentation\n\t{ start: ip4ToNum(198, 51, 100, 0), end: ip4ToNum(198, 51, 100, 255) },\n\t{ start: ip4ToNum(203, 0, 113, 0), end: ip4ToNum(203, 0, 113, 255) },\n\t// Multicast, reserved, and limited broadcast\n\t{ start: ip4ToNum(224, 0, 0, 0), end: ip4ToNum(255, 255, 255, 255) },\n];\n\nconst ALLOWED_IPV4_EXCEPTIONS = new Set([ip4ToNum(192, 0, 0, 9), ip4ToNum(192, 0, 0, 10)]);\n\ninterface Ipv6Range {\n\taddress: number[];\n\tprefixLength: number;\n}\n\nfunction ipv6Range(address: string, prefixLength: number): Ipv6Range {\n\tconst parsed = parseIpv6(address);\n\tif (parsed === null) throw new Error(`Invalid IPv6 range: ${address}/${prefixLength}`);\n\treturn { address: parsed, prefixLength };\n}\n\nconst IPV6_GLOBAL_UNICAST_RANGE = ipv6Range(\"2000::\", 3);\nconst IPV4_COMPATIBLE_IPV6_RANGE = ipv6Range(\"::\", 96);\nconst IPV4_EMBEDDED_IPV6_RANGES: Ipv6Range[] = [\n\tIPV4_COMPATIBLE_IPV6_RANGE,\n\tipv6Range(\"::ffff:0:0\", 96),\n\tipv6Range(\"::ffff:0:0:0\", 96),\n\tipv6Range(\"64:ff9b::\", 96),\n];\n\n/** Globally reachable allocations inside the otherwise reserved 2001::/23 block. */\nconst ALLOWED_IPV6_SPECIAL_RANGES: Ipv6Range[] = [\n\tipv6Range(\"2001:1::1\", 128),\n\tipv6Range(\"2001:1::2\", 128),\n\tipv6Range(\"2001:1::3\", 128),\n\tipv6Range(\"2001:3::\", 32),\n\tipv6Range(\"2001:4:112::\", 48),\n\tipv6Range(\"2001:20::\", 28),\n\tipv6Range(\"2001:30::\", 28),\n];\n\n/** Non-global allocations inside the ordinary IPv6 global-unicast range. */\nconst BLOCKED_IPV6_GLOBAL_UNICAST_RANGES: Ipv6Range[] = [\n\tipv6Range(\"2001::\", 23),\n\tipv6Range(\"2001:db8::\", 32),\n\tipv6Range(\"2002::\", 16),\n\tipv6Range(\"3ffe::\", 16),\n\tipv6Range(\"3fff::\", 20),\n];\n\n// Bracket-stripped form is used for lookups (validateExternalUrl strips\n// brackets from parsed.hostname before checking), so \"::1\" appears here\n// without brackets. The \"::1\" case is already covered by isNonPublicIp, but\n// keeping it here makes the intent explicit and gives a clearer error\n// message for the common `http://[::1]/` form.\nconst BLOCKED_HOSTNAMES = new Set([\n\t\"localhost\",\n\t\"metadata.google.internal\",\n\t\"metadata.google\",\n\t\"::1\",\n]);\n\n/**\n * Wildcard DNS services that publicly resolve arbitrary IPs embedded in the\n * hostname. Commonly used in local dev and by SSRF exploit tooling to bypass\n * hostname-only blocklists (e.g. 127.0.0.1.nip.io -> 127.0.0.1).\n *\n * Matched case-insensitively as a suffix, so both the apex and any subdomain\n * are blocked.\n */\nconst BLOCKED_HOSTNAME_SUFFIXES = [\n\t\"nip.io\",\n\t\"sslip.io\",\n\t\"xip.io\",\n\t\"traefik.me\",\n\t\"lvh.me\",\n\t\"localtest.me\",\n];\n\n/** Blocked URL schemes */\nconst ALLOWED_SCHEMES = new Set([\"http:\", \"https:\"]);\n\nfunction ip4ToNum(a: number, b: number, c: number, d: number): number {\n\treturn ((a << 24) | (b << 16) | (c << 8) | d) >>> 0;\n}\n\nfunction parseIpv4(ip: string): number | null {\n\tconst parts = ip.split(\".\");\n\tif (parts.length !== 4) return null;\n\n\tconst nums = parts.map((part) => (IPV4_PART_PATTERN.test(part) ? Number(part) : Number.NaN));\n\tif (nums.some((n) => !Number.isInteger(n) || n < 0 || n > 255)) return null;\n\n\treturn ip4ToNum(nums[0], nums[1], nums[2], nums[3]);\n}\n\nfunction parseIpv6(ip: string): number[] | null {\n\tlet address = ip;\n\tif (address.includes(\".\")) {\n\t\tconst separator = address.lastIndexOf(\":\");\n\t\tif (separator === -1) return null;\n\t\tconst ipv4 = parseIpv4(address.slice(separator + 1));\n\t\tif (ipv4 === null) return null;\n\t\taddress = `${address.slice(0, separator + 1)}${(ipv4 >>> 16).toString(16)}:${(ipv4 & 0xffff).toString(16)}`;\n\t}\n\tif (address.includes(\":::\") || address.split(\"::\").length > 2) return null;\n\n\tconst [before = \"\", after = \"\"] = address.split(\"::\");\n\tconst head = before === \"\" ? [] : before.split(\":\");\n\tconst tail = after === \"\" ? [] : after.split(\":\");\n\tconst parts = [...head, ...tail];\n\tif (parts.some((part) => !IPV6_PART_PATTERN.test(part)) || parts.length > 8) return null;\n\tif (address.includes(\"::\") ? parts.length >= 8 : parts.length !== 8) return null;\n\n\tconst zeroCount = address.includes(\"::\") ? 8 - parts.length : 0;\n\treturn [...head, ...Array.from<string>({ length: zeroCount }).fill(\"0\"), ...tail].map((part) =>\n\t\tNumber.parseInt(part, 16),\n\t);\n}\n\nfunction isIpv6InRange(address: number[], range: Ipv6Range): boolean {\n\tconst completeParts = Math.floor(range.prefixLength / 16);\n\tfor (let i = 0; i < completeParts; i++) {\n\t\tif (address[i] !== range.address[i]) return false;\n\t}\n\n\tconst remainingBits = range.prefixLength % 16;\n\tif (remainingBits === 0) return true;\n\tconst mask = (0xffff << (16 - remainingBits)) & 0xffff;\n\treturn (address[completeParts] & mask) === (range.address[completeParts] & mask);\n}\n\nfunction extractEmbeddedIpv4(address: number[]): number | null {\n\tif (!IPV4_EMBEDDED_IPV6_RANGES.some((range) => isIpv6InRange(address, range))) return null;\n\tconst ipv4 = ((address[6] << 16) | address[7]) >>> 0;\n\t// The unspecified and loopback addresses retain their native IPv6 meaning.\n\tif (ipv4 <= 1 && isIpv6InRange(address, IPV4_COMPATIBLE_IPV6_RANGE)) return null;\n\treturn ipv4;\n}\n\n/** Convert a hex-form IPv6 address with an embedded IPv4 destination to dotted decimal. */\nexport function normalizeIPv6MappedToIPv4(ip: string): string | null {\n\tif (ip.includes(\".\")) return null;\n\tconst address = parseIpv6(ip);\n\tif (address === null) return null;\n\tconst ipv4 = extractEmbeddedIpv4(address);\n\tif (ipv4 === null) return null;\n\treturn `${ipv4 >>> 24}.${(ipv4 >>> 16) & 0xff}.${(ipv4 >>> 8) & 0xff}.${ipv4 & 0xff}`;\n}\n\nfunction isNonPublicIp(ip: string): boolean {\n\tconst parsedIpv4 = parseIpv4(ip);\n\tconst ipv6 = parsedIpv4 === null ? parseIpv6(ip) : null;\n\tconst ipv4 = ipv6 === null ? parsedIpv4 : extractEmbeddedIpv4(ipv6);\n\tif (ipv4 !== null) {\n\t\tif (ALLOWED_IPV4_EXCEPTIONS.has(ipv4)) return false;\n\t\treturn BLOCKED_PATTERNS.some((range) => ipv4 >= range.start && ipv4 <= range.end);\n\t}\n\tif (ipv6 === null) return true;\n\tif (ALLOWED_IPV6_SPECIAL_RANGES.some((range) => isIpv6InRange(ipv6, range))) return false;\n\tif (!isIpv6InRange(ipv6, IPV6_GLOBAL_UNICAST_RANGE)) return true;\n\treturn BLOCKED_IPV6_GLOBAL_UNICAST_RANGES.some((range) => isIpv6InRange(ipv6, range));\n}\n\n/**\n * Error thrown when SSRF protection blocks a URL.\n */\nexport class SsrfError extends Error {\n\tcode = \"SSRF_BLOCKED\" as const;\n\n\tconstructor(message: string) {\n\t\tsuper(message);\n\t\tthis.name = \"SsrfError\";\n\t}\n}\n\n/**\n * Validate a URL's scheme, hostname, and literal address.\n *\n * Checks:\n * 1. URL is well-formed with http/https scheme\n * 2. Hostname is not a known internal name (localhost, metadata endpoints)\n * 3. If hostname is an IP literal, it is a public address\n *\n * Hostnames also need DNS validation before dispatch. Resolving and checking\n * addresses does not bind an ordinary fetch() connection to those addresses.\n *\n * @throws SsrfError if the URL targets an internal address\n */\n/** Maximum number of redirects to follow in ssrfSafeFetch */\nconst MAX_REDIRECTS = 5;\n\nexport function validateExternalUrl(url: string): URL {\n\tlet parsed: URL;\n\ttry {\n\t\tparsed = new URL(url);\n\t} catch {\n\t\tthrow new SsrfError(\"Invalid URL\");\n\t}\n\n\t// Only allow http/https\n\tif (!ALLOWED_SCHEMES.has(parsed.protocol)) {\n\t\tthrow new SsrfError(`Scheme '${parsed.protocol}' is not allowed`);\n\t}\n\n\t// Strip brackets from IPv6 hostname\n\tconst hostname = parsed.hostname.replace(IPV6_BRACKET_PATTERN, \"\");\n\n\t// Normalize the hostname for blocklist matching: lowercase + strip any\n\t// trailing dots. WHATWG preserves trailing dots on .hostname, so without\n\t// this normalization \"localhost.\" and \"nip.io.\" bypass the checks.\n\tconst normalizedHost = hostname.toLowerCase().replace(TRAILING_DOT_PATTERN, \"\");\n\n\t// Check against known internal hostnames\n\tif (BLOCKED_HOSTNAMES.has(normalizedHost)) {\n\t\tthrow new SsrfError(\"URLs targeting internal hosts are not allowed\");\n\t}\n\n\t// Check against wildcard DNS services used by SSRF tooling to bypass\n\t// hostname-only checks. Match the apex and any subdomain.\n\tfor (const suffix of BLOCKED_HOSTNAME_SUFFIXES) {\n\t\tif (normalizedHost === suffix || normalizedHost.endsWith(`.${suffix}`)) {\n\t\t\tthrow new SsrfError(\"URLs targeting wildcard DNS services are not allowed\");\n\t\t}\n\t}\n\n\t// Check if hostname is a non-public IP address. Use the\n\t// normalized form so \"127.0.0.1..\" and friends don't bypass parseIpv4\n\t// (which rejects extra trailing dots).\n\tif (isIpLiteral(normalizedHost) && isNonPublicIp(normalizedHost)) {\n\t\tthrow new SsrfError(\"URLs targeting non-public IP addresses are not allowed\");\n\t}\n\n\treturn parsed;\n}\n\n// ---------------------------------------------------------------------------\n// DNS-aware validation\n// ---------------------------------------------------------------------------\n\n/**\n * A resolver that maps a hostname to a list of IPv4/IPv6 addresses.\n * Injectable so callers can swap in OS-level DNS on Node, stub it in tests,\n * or point to a different DoH endpoint.\n */\nexport type DnsResolver = (hostname: string) => Promise<string[]>;\n\n/**\n * Module-level default resolver. Tests can swap this with a stub so fetch\n * mocks don't see unexpected DoH round-trips. Production code should leave\n * it alone.\n */\nlet defaultResolver: DnsResolver | null = null;\n\n/** Override the default DNS resolver. Returns the previous value. */\nexport function setDefaultDnsResolver(resolver: DnsResolver | null): DnsResolver | null {\n\tconst previous = defaultResolver;\n\tdefaultResolver = resolver;\n\treturn previous;\n}\n\n/** Timeout for a single DoH request, in milliseconds. */\nconst DOH_TIMEOUT_MS = 3000;\n\n/** Default DoH endpoint — Cloudflare's public resolver. */\nconst DEFAULT_DOH_URL = \"https://cloudflare-dns.com/dns-query\";\n\ninterface DohAnswer {\n\ttype: number;\n\tdata: string;\n}\n\ninterface DohResponse {\n\tStatus: number;\n\tAnswer: DohAnswer[];\n}\n\nfunction hasProperty<K extends string>(obj: unknown, key: K): obj is Record<K, unknown> {\n\treturn typeof obj === \"object\" && obj !== null && key in obj;\n}\n\n/**\n * Narrow an unknown JSON body to a DohResponse shape we can read safely.\n * Throws if the body doesn't look like a DoH response — a malformed body is\n * indistinguishable from a failure and must not be silently treated as empty.\n */\nfunction parseDohResponse(raw: unknown): DohResponse {\n\tif (!hasProperty(raw, \"Status\") || typeof raw.Status !== \"number\") {\n\t\tthrow new Error(\"DoH response missing Status field\");\n\t}\n\tconst answers: DohAnswer[] = [];\n\tif (hasProperty(raw, \"Answer\") && Array.isArray(raw.Answer)) {\n\t\tfor (const entry of raw.Answer) {\n\t\t\tif (\n\t\t\t\thasProperty(entry, \"type\") &&\n\t\t\t\ttypeof entry.type === \"number\" &&\n\t\t\t\tNumber.isInteger(entry.type) &&\n\t\t\t\thasProperty(entry, \"data\") &&\n\t\t\t\ttypeof entry.data === \"string\"\n\t\t\t) {\n\t\t\t\tanswers.push({ type: entry.type, data: entry.data });\n\t\t\t}\n\t\t}\n\t}\n\treturn { Status: raw.Status, Answer: answers };\n}\n\n/**\n * Resolve a hostname via DNS over HTTPS (Cloudflare). Returns all A and AAAA\n * records. Works in both Workers and Node without requiring node:dns.\n *\n * Fails closed: any network error, non-2xx response, or DNS rcode != 0\n * causes a rejected promise so the calling validator treats it as a block.\n */\nexport const cloudflareDohResolver: DnsResolver = async (hostname) => {\n\tasync function query(type: \"A\" | \"AAAA\"): Promise<string[]> {\n\t\tconst expectedAnswerType = type === \"A\" ? 1 : 28;\n\t\tconst params = new URLSearchParams({ name: hostname, type });\n\t\tconst controller = new AbortController();\n\t\tconst timeout = setTimeout(() => controller.abort(), DOH_TIMEOUT_MS);\n\t\ttry {\n\t\t\tconst response = await globalThis.fetch(`${DEFAULT_DOH_URL}?${params.toString()}`, {\n\t\t\t\theaders: { Accept: \"application/dns-json\" },\n\t\t\t\tsignal: controller.signal,\n\t\t\t});\n\t\t\tif (!response.ok) {\n\t\t\t\tthrow new Error(`DoH lookup failed: ${response.status}`);\n\t\t\t}\n\t\t\tconst raw = await response.json();\n\t\t\tconst body = parseDohResponse(raw);\n\t\t\t// NXDOMAIN (3) is a legitimate \"does not exist\" — treat as empty.\n\t\t\t// Any other non-zero status (SERVFAIL=2, REFUSED=5, etc.) is\n\t\t\t// ambiguous and could be a split-view attacker hiding records\n\t\t\t// from our resolver. Fail closed.\n\t\t\tif (body.Status === 3) return [];\n\t\t\tif (body.Status !== 0) {\n\t\t\t\tthrow new Error(`DoH ${type} lookup failed: rcode=${body.Status}`);\n\t\t\t}\n\t\t\t// DoH Answer arrays often include CNAME records alongside A/AAAA\n\t\t\t// records. Their `data` is a hostname, not an IP. Filter to just\n\t\t\t// IP literals of the requested record type.\n\t\t\treturn body.Answer.filter((answer) => answer.type === expectedAnswerType)\n\t\t\t\t.map((answer) => answer.data)\n\t\t\t\t.filter(isIpLiteral);\n\t\t} finally {\n\t\t\tclearTimeout(timeout);\n\t\t}\n\t}\n\n\tconst [a, aaaa] = await Promise.all([query(\"A\"), query(\"AAAA\")]);\n\treturn [...a, ...aaaa];\n};\n\n/**\n * Validate a URL and reject hostnames that resolve to non-public addresses,\n * including wildcard DNS services like nip.io used by exploit tooling.\n *\n * Runs `validateExternalUrl` first for cheap pre-flight checks (scheme,\n * literal IP, known-bad hostnames). Then resolves the hostname and rejects\n * if ANY returned address is non-public.\n *\n * Fails closed: if resolution fails or returns no records, throws SsrfError.\n *\n * **Caveats.** This does NOT fully close the TOCTOU between check and\n * connect. Attacks that still work against this layer include:\n *\n * - TTL=0 rebind: authoritative server returns public IP to the check, then\n * private IP to the subsequent fetch() a few milliseconds later.\n * - Split-view via EDNS Client Subnet or source-IP inspection: the\n * authoritative server returns public IP to Cloudflare's DoH resolver and\n * private IP to the victim's own resolver (used by fetch()).\n * - Host-file overrides or split-horizon corporate DNS on self-hosted Node.\n * - Attacker-controlled rebinding services the caller has allowlisted.\n *\n * Connections must use the addresses from resolveAndValidateExternalUrlTarget\n * to avoid a second lookup. Callers using ordinary fetch() need network-level\n * egress controls to prevent these attacks.\n */\nexport async function resolveAndValidateExternalUrl(\n\turl: string,\n\toptions?: { resolver?: DnsResolver },\n): Promise<URL> {\n\treturn (await resolveAndValidateExternalUrlTarget(url, options)).url;\n}\n\nexport interface ResolvedExternalUrlTarget {\n\turl: URL;\n\taddresses: readonly string[];\n}\n\n/**\n * Validate a URL and return the exact public addresses approved for the\n * subsequent connection.\n */\nexport async function resolveAndValidateExternalUrlTarget(\n\turl: string,\n\toptions?: { resolver?: DnsResolver },\n): Promise<ResolvedExternalUrlTarget> {\n\tconst parsed = validateExternalUrl(url);\n\n\t// Strip brackets from IPv6 hostnames\n\tconst hostname = parsed.hostname.replace(IPV6_BRACKET_PATTERN, \"\");\n\n\t// If the hostname is already an IP literal, validateExternalUrl has\n\t// already checked it against the non-public ranges. Skip DNS.\n\tif (isIpLiteral(hostname)) {\n\t\treturn { url: parsed, addresses: [hostname] };\n\t}\n\n\tconst resolver = options?.resolver ?? defaultResolver ?? cloudflareDohResolver;\n\n\tlet addresses: string[];\n\ttry {\n\t\taddresses = await resolver(hostname);\n\t} catch (error) {\n\t\tthrow new SsrfError(\n\t\t\t`Could not resolve hostname: ${error instanceof Error ? error.message : String(error)}`,\n\t\t);\n\t}\n\n\tif (addresses.length === 0) {\n\t\tthrow new SsrfError(\"Hostname resolved to no addresses\");\n\t}\n\n\tfor (const ip of addresses) {\n\t\tif (!isIpLiteral(ip)) {\n\t\t\tthrow new SsrfError(\"Hostname resolver returned a non-IP address\");\n\t\t}\n\t\tif (isNonPublicIp(ip)) {\n\t\t\tthrow new SsrfError(\"Hostname resolves to a non-public IP address\");\n\t\t}\n\t}\n\n\treturn { url: parsed, addresses };\n}\n\n/** True when a string is a valid IPv4 or IPv6 literal. */\nfunction isIpLiteral(host: string): boolean {\n\treturn parseIpv4(host) !== null || parseIpv6(host) !== null;\n}\n\n/**\n * Fetch a URL with SSRF protection on redirects.\n *\n * Uses `redirect: \"manual\"` to intercept redirects and re-validate each\n * redirect target against SSRF rules before following it. This prevents\n * an attacker from setting up an allowed external URL that redirects to\n * an internal IP (e.g. 169.254.169.254 for cloud metadata).\n *\n * @throws SsrfError if the initial URL or any redirect target is internal\n */\n/** Headers that must be stripped when a redirect crosses origins */\nconst CREDENTIAL_HEADERS = [\"authorization\", \"cookie\", \"proxy-authorization\"];\n\nexport async function ssrfSafeFetch(\n\turl: string,\n\tinit?: RequestInit,\n\toptions?: { resolver?: DnsResolver; httpsOnly?: boolean },\n): Promise<Response> {\n\tlet currentUrl = url;\n\tlet currentInit = init;\n\n\tfor (let i = 0; i <= MAX_REDIRECTS; i++) {\n\t\tconst validated = await resolveAndValidateExternalUrl(currentUrl, options);\n\t\tif (options?.httpsOnly === true && validated.protocol !== \"https:\") {\n\t\t\tthrow new SsrfError(\"Only HTTPS URLs are allowed\");\n\t\t}\n\n\t\tconst response = await globalThis.fetch(currentUrl, {\n\t\t\t...currentInit,\n\t\t\tredirect: \"manual\",\n\t\t});\n\n\t\t// Not a redirect -- return directly\n\t\tif (response.status < 300 || response.status >= 400) {\n\t\t\treturn response;\n\t\t}\n\n\t\t// Extract redirect target\n\t\tconst location = response.headers.get(\"Location\");\n\t\tif (!location) {\n\t\t\treturn response;\n\t\t}\n\n\t\t// Resolve relative redirects against the current URL\n\t\tconst previousOrigin = new URL(currentUrl).origin;\n\t\tcurrentUrl = new URL(location, currentUrl).href;\n\t\tconst nextOrigin = new URL(currentUrl).origin;\n\n\t\t// Strip credential headers on cross-origin redirects\n\t\tif (previousOrigin !== nextOrigin && currentInit) {\n\t\t\tcurrentInit = stripCredentialHeaders(currentInit);\n\t\t}\n\t}\n\n\tthrow new SsrfError(`Too many redirects (max ${MAX_REDIRECTS})`);\n}\n\n/**\n * Return a copy of init with credential headers removed.\n */\nexport function stripCredentialHeaders(init: RequestInit): RequestInit {\n\tif (!init.headers) return init;\n\n\tconst headers = new Headers(init.headers);\n\tfor (const name of CREDENTIAL_HEADERS) {\n\t\theaders.delete(name);\n\t}\n\n\treturn { ...init, headers };\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"state-BJfU9Uzw.mjs","names":[],"sources":["../src/plugins/state.ts"],"sourcesContent":["/**\n * Plugin State Repository\n *\n * Database-backed storage for plugin activation state.\n * Used by the admin API to persist plugin enable/disable across restarts.\n */\n\nimport type { Kysely } from \"kysely\";\n\nimport type { Database } from \"../database/types.js\";\n\nexport type PluginStatus = \"active\" | \"inactive\";\nexport type PluginSource = \"config\" | \"marketplace\" | \"registry\";\n\nconst TIMEZONE_SUFFIX = /(?:z|[+-]\\d{2}(?::?\\d{2})?)$/i;\nconst HOUR_OFFSET_SUFFIX = /\\d{2}:\\d{2}(?::\\d{2}(?:\\.\\d+)?)?[+-]\\d{2}$/i;\n\nfunction parseDatabaseTimestamp(value: string): Date {\n\tlet normalized = value.trim().replace(\" \", \"T\");\n\tif (HOUR_OFFSET_SUFFIX.test(normalized)) normalized += \":00\";\n\telse if (!TIMEZONE_SUFFIX.test(normalized)) normalized += \"Z\";\n\treturn new Date(normalized);\n}\n\nfunction toPluginStatus(value: string): PluginStatus {\n\tif (value === \"active\") return \"active\";\n\treturn \"inactive\";\n}\n\nfunction toPluginSource(value: string | undefined | null): PluginSource {\n\tif (value === \"marketplace\") return \"marketplace\";\n\tif (value === \"registry\") return \"registry\";\n\treturn \"config\";\n}\n\nexport interface PluginState {\n\tpluginId: string;\n\tstatus: PluginStatus;\n\tversion: string;\n\tinstalledAt: Date;\n\tactivatedAt: Date | null;\n\tdeactivatedAt: Date | null;\n\tsource: PluginSource;\n\tmarketplaceVersion: string | null;\n\tdisplayName: string | null;\n\tdescription: string | null;\n\t/**\n\t * Publisher DID this plugin was published under. Populated only when\n\t * `source === \"registry\"`; null otherwise.\n\t */\n\tregistryPublisherDid: string | null;\n\t/**\n\t * Slug under which the plugin was published in the publisher's repo\n\t * (the rkey of the `pm.fair.package.profile` record). Populated only\n\t * when `source === \"registry\"`; null otherwise.\n\t *\n\t * The opaque `pluginId` for registry installs is derived from\n\t * `(registryPublisherDid, registrySlug)` -- see\n\t * `packages/core/src/registry/plugin-id.ts`.\n\t */\n\tregistrySlug: string | null;\n\tmcpToolsEnabled: boolean;\n\tmcpToolsConsent: string | null;\n}\n\n/**\n * Repository for plugin state in the database\n */\nexport class PluginStateRepository {\n\tconstructor(private db: Kysely<Database>) {}\n\n\t/**\n\t * Get state for a specific plugin\n\t */\n\tasync get(pluginId: string): Promise<PluginState | null> {\n\t\tconst row = await this.db\n\t\t\t.selectFrom(\"_plugin_state\")\n\t\t\t.selectAll()\n\t\t\t.where(\"plugin_id\", \"=\", pluginId)\n\t\t\t.executeTakeFirst();\n\n\t\tif (!row) return null;\n\n\t\treturn rowToPluginState(row);\n\t}\n\n\t/**\n\t * Get all plugin states\n\t */\n\tasync getAll(): Promise<PluginState[]> {\n\t\tconst rows = await this.db.selectFrom(\"_plugin_state\").selectAll().execute();\n\t\treturn rows.map(rowToPluginState);\n\t}\n\n\t/**\n\t * Get all marketplace-installed plugin states\n\t */\n\tasync getMarketplacePlugins(): Promise<PluginState[]> {\n\t\tconst rows = await this.db\n\t\t\t.selectFrom(\"_plugin_state\")\n\t\t\t.selectAll()\n\t\t\t.where(\"source\", \"=\", \"marketplace\")\n\t\t\t.execute();\n\t\treturn rows.map(rowToPluginState);\n\t}\n\n\t/**\n\t * Get all registry-installed plugin states.\n\t *\n\t * The runtime's registry sync path uses this to discover which\n\t * registry plugins should be loaded into the sandbox on this worker.\n\t */\n\tasync getRegistryPlugins(): Promise<PluginState[]> {\n\t\tconst rows = await this.db\n\t\t\t.selectFrom(\"_plugin_state\")\n\t\t\t.selectAll()\n\t\t\t.where(\"source\", \"=\", \"registry\")\n\t\t\t.execute();\n\t\treturn rows.map(rowToPluginState);\n\t}\n\n\t/**\n\t * Create or update plugin state\n\t */\n\tasync upsert(\n\t\tpluginId: string,\n\t\tversion: string,\n\t\tstatus: PluginStatus,\n\t\topts?: {\n\t\t\tsource?: PluginSource;\n\t\t\tmarketplaceVersion?: string;\n\t\t\tdisplayName?: string;\n\t\t\tdescription?: string;\n\t\t\tregistryPublisherDid?: string;\n\t\t\tregistrySlug?: string;\n\t\t\tmcpToolsEnabled?: boolean;\n\t\t\tmcpToolsConsent?: string | null;\n\t\t},\n\t): Promise<PluginState> {\n\t\tconst now = new Date().toISOString();\n\t\tconst existing = await this.get(pluginId);\n\n\t\tif (existing) {\n\t\t\t// Update existing state\n\t\t\tconst updates: Record<string, string | number | null> = {\n\t\t\t\tstatus,\n\t\t\t\tversion,\n\t\t\t};\n\n\t\t\tif (status === \"active\" && existing.status !== \"active\") {\n\t\t\t\tupdates.activated_at = now;\n\t\t\t} else if (status === \"inactive\" && existing.status !== \"inactive\") {\n\t\t\t\tupdates.deactivated_at = now;\n\t\t\t}\n\n\t\t\tif (opts?.source) updates.source = opts.source;\n\t\t\tif (opts?.marketplaceVersion !== undefined) {\n\t\t\t\tupdates.marketplace_version = opts.marketplaceVersion;\n\t\t\t}\n\t\t\tif (opts?.displayName !== undefined) {\n\t\t\t\tupdates.display_name = opts.displayName;\n\t\t\t}\n\t\t\tif (opts?.description !== undefined) {\n\t\t\t\tupdates.description = opts.description;\n\t\t\t}\n\t\t\tif (opts?.registryPublisherDid !== undefined) {\n\t\t\t\tupdates.registry_publisher_did = opts.registryPublisherDid;\n\t\t\t}\n\t\t\tif (opts?.registrySlug !== undefined) {\n\t\t\t\tupdates.registry_slug = opts.registrySlug;\n\t\t\t}\n\t\t\tif (opts?.mcpToolsEnabled !== undefined) {\n\t\t\t\tupdates.mcp_tools_enabled = opts.mcpToolsEnabled ? 1 : 0;\n\t\t\t}\n\t\t\tif (opts?.mcpToolsConsent !== undefined) {\n\t\t\t\tupdates.mcp_tools_consent = opts.mcpToolsConsent;\n\t\t\t}\n\n\t\t\tawait this.db\n\t\t\t\t.updateTable(\"_plugin_state\")\n\t\t\t\t.set(updates)\n\t\t\t\t.where(\"plugin_id\", \"=\", pluginId)\n\t\t\t\t.execute();\n\t\t} else {\n\t\t\t// Create new state\n\t\t\tawait this.db\n\t\t\t\t.insertInto(\"_plugin_state\")\n\t\t\t\t.values({\n\t\t\t\t\tplugin_id: pluginId,\n\t\t\t\t\tstatus,\n\t\t\t\t\tversion,\n\t\t\t\t\tinstalled_at: now,\n\t\t\t\t\tactivated_at: status === \"active\" ? now : null,\n\t\t\t\t\tdeactivated_at: null,\n\t\t\t\t\tdata: null,\n\t\t\t\t\tsource: opts?.source ?? \"config\",\n\t\t\t\t\tmarketplace_version: opts?.marketplaceVersion ?? null,\n\t\t\t\t\tdisplay_name: opts?.displayName ?? null,\n\t\t\t\t\tdescription: opts?.description ?? null,\n\t\t\t\t\tregistry_publisher_did: opts?.registryPublisherDid ?? null,\n\t\t\t\t\tregistry_slug: opts?.registrySlug ?? null,\n\t\t\t\t\tmcp_tools_enabled: opts?.mcpToolsEnabled ? 1 : 0,\n\t\t\t\t\tmcp_tools_consent: opts?.mcpToolsConsent ?? null,\n\t\t\t\t})\n\t\t\t\t.execute();\n\t\t}\n\n\t\treturn (await this.get(pluginId))!;\n\t}\n\n\t/**\n\t * Enable a plugin\n\t */\n\tasync enable(pluginId: string, version: string): Promise<PluginState> {\n\t\treturn this.upsert(pluginId, version, \"active\");\n\t}\n\n\t/**\n\t * Disable a plugin\n\t */\n\tasync disable(pluginId: string, version: string): Promise<PluginState> {\n\t\treturn this.upsert(pluginId, version, \"inactive\");\n\t}\n\n\t/**\n\t * Delete plugin state\n\t */\n\tasync delete(pluginId: string): Promise<boolean> {\n\t\tconst result = await this.db\n\t\t\t.deleteFrom(\"_plugin_state\")\n\t\t\t.where(\"plugin_id\", \"=\", pluginId)\n\t\t\t.executeTakeFirst();\n\n\t\treturn (result.numDeletedRows ?? 0) > 0;\n\t}\n}\n\n/**\n * Internal: map a `_plugin_state` row to the public `PluginState` shape.\n *\n * Kept at module scope so the three select paths (`get`, `getAll`,\n * `getMarketplacePlugins`, `getRegistryPlugins`) stay byte-identical in\n * their handling of nullable columns -- adding a new column to the table\n * means changing this function and nothing else.\n */\ninterface PluginStateRow {\n\tplugin_id: string;\n\tstatus: string;\n\tversion: string;\n\tinstalled_at: string;\n\tactivated_at: string | null;\n\tdeactivated_at: string | null;\n\tsource: string;\n\tmarketplace_version: string | null;\n\tdisplay_name: string | null;\n\tdescription: string | null;\n\tregistry_publisher_did: string | null;\n\tregistry_slug: string | null;\n\tmcp_tools_enabled: number;\n\tmcp_tools_consent: string | null;\n}\n\nfunction rowToPluginState(row: PluginStateRow): PluginState {\n\treturn {\n\t\tpluginId: row.plugin_id,\n\t\tstatus: toPluginStatus(row.status),\n\t\tversion: row.version,\n\t\tinstalledAt: parseDatabaseTimestamp(row.installed_at),\n\t\tactivatedAt: row.activated_at ? parseDatabaseTimestamp(row.activated_at) : null,\n\t\tdeactivatedAt: row.deactivated_at ? parseDatabaseTimestamp(row.deactivated_at) : null,\n\t\tsource: toPluginSource(row.source),\n\t\tmarketplaceVersion: row.marketplace_version ?? null,\n\t\tdisplayName: row.display_name ?? null,\n\t\tdescription: row.description ?? null,\n\t\tregistryPublisherDid: row.registry_publisher_did ?? null,\n\t\tregistrySlug: row.registry_slug ?? null,\n\t\tmcpToolsEnabled: row.mcp_tools_enabled === 1,\n\t\tmcpToolsConsent: row.mcp_tools_consent ?? null,\n\t};\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"state-1F6IOhdQ.mjs","names":[],"sources":["../src/plugins/state.ts"],"sourcesContent":["/**\n * Plugin State Repository\n *\n * Database-backed storage for plugin activation state.\n * Used by the admin API to persist plugin enable/disable across restarts.\n */\n\nimport type { Kysely } from \"kysely\";\n\nimport type { Database } from \"../database/types.js\";\n\nexport type PluginStatus = \"active\" | \"inactive\";\nexport type PluginSource = \"config\" | \"marketplace\" | \"registry\";\n\nconst TIMEZONE_SUFFIX = /(?:z|[+-]\\d{2}(?::?\\d{2})?)$/i;\nconst HOUR_OFFSET_SUFFIX = /\\d{2}:\\d{2}(?::\\d{2}(?:\\.\\d+)?)?[+-]\\d{2}$/i;\n\nfunction parseDatabaseTimestamp(value: string): Date {\n\tlet normalized = value.trim().replace(\" \", \"T\");\n\tif (HOUR_OFFSET_SUFFIX.test(normalized)) normalized += \":00\";\n\telse if (!TIMEZONE_SUFFIX.test(normalized)) normalized += \"Z\";\n\treturn new Date(normalized);\n}\n\nfunction toPluginStatus(value: string): PluginStatus {\n\tif (value === \"active\") return \"active\";\n\treturn \"inactive\";\n}\n\nfunction toPluginSource(value: string | undefined | null): PluginSource {\n\tif (value === \"marketplace\") return \"marketplace\";\n\tif (value === \"registry\") return \"registry\";\n\treturn \"config\";\n}\n\nexport interface PluginState {\n\tpluginId: string;\n\tstatus: PluginStatus;\n\tversion: string;\n\tinstalledAt: Date;\n\tactivatedAt: Date | null;\n\tdeactivatedAt: Date | null;\n\tsource: PluginSource;\n\tmarketplaceVersion: string | null;\n\tdisplayName: string | null;\n\tdescription: string | null;\n\t/**\n\t * Publisher DID this plugin was published under. Populated only when\n\t * `source === \"registry\"`; null otherwise.\n\t */\n\tregistryPublisherDid: string | null;\n\t/**\n\t * Slug under which the plugin was published in the publisher's repo\n\t * (the rkey of the `pm.fair.package.profile` record). Populated only\n\t * when `source === \"registry\"`; null otherwise.\n\t *\n\t * The opaque `pluginId` for registry installs is derived from\n\t * `(registryPublisherDid, registrySlug)` -- see\n\t * `packages/core/src/registry/plugin-id.ts`.\n\t */\n\tregistrySlug: string | null;\n\tmcpToolsEnabled: boolean;\n\tmcpToolsConsent: string | null;\n}\n\n/**\n * Repository for plugin state in the database\n */\nexport class PluginStateRepository {\n\tconstructor(private db: Kysely<Database>) {}\n\n\t/**\n\t * Get state for a specific plugin\n\t */\n\tasync get(pluginId: string): Promise<PluginState | null> {\n\t\tconst row = await this.db\n\t\t\t.selectFrom(\"_plugin_state\")\n\t\t\t.selectAll()\n\t\t\t.where(\"plugin_id\", \"=\", pluginId)\n\t\t\t.executeTakeFirst();\n\n\t\tif (!row) return null;\n\n\t\treturn rowToPluginState(row);\n\t}\n\n\t/**\n\t * Get all plugin states\n\t */\n\tasync getAll(): Promise<PluginState[]> {\n\t\tconst rows = await this.db.selectFrom(\"_plugin_state\").selectAll().execute();\n\t\treturn rows.map(rowToPluginState);\n\t}\n\n\t/**\n\t * Get all marketplace-installed plugin states\n\t */\n\tasync getMarketplacePlugins(): Promise<PluginState[]> {\n\t\tconst rows = await this.db\n\t\t\t.selectFrom(\"_plugin_state\")\n\t\t\t.selectAll()\n\t\t\t.where(\"source\", \"=\", \"marketplace\")\n\t\t\t.execute();\n\t\treturn rows.map(rowToPluginState);\n\t}\n\n\t/**\n\t * Get all registry-installed plugin states.\n\t *\n\t * The runtime's registry sync path uses this to discover which\n\t * registry plugins should be loaded into the sandbox on this worker.\n\t */\n\tasync getRegistryPlugins(): Promise<PluginState[]> {\n\t\tconst rows = await this.db\n\t\t\t.selectFrom(\"_plugin_state\")\n\t\t\t.selectAll()\n\t\t\t.where(\"source\", \"=\", \"registry\")\n\t\t\t.execute();\n\t\treturn rows.map(rowToPluginState);\n\t}\n\n\t/**\n\t * Create or update plugin state\n\t */\n\tasync upsert(\n\t\tpluginId: string,\n\t\tversion: string,\n\t\tstatus: PluginStatus,\n\t\topts?: {\n\t\t\tsource?: PluginSource;\n\t\t\tmarketplaceVersion?: string;\n\t\t\tdisplayName?: string;\n\t\t\tdescription?: string;\n\t\t\tregistryPublisherDid?: string;\n\t\t\tregistrySlug?: string;\n\t\t\tmcpToolsEnabled?: boolean;\n\t\t\tmcpToolsConsent?: string | null;\n\t\t},\n\t): Promise<PluginState> {\n\t\tconst now = new Date().toISOString();\n\t\tconst existing = await this.get(pluginId);\n\n\t\tif (existing) {\n\t\t\t// Update existing state\n\t\t\tconst updates: Record<string, string | number | null> = {\n\t\t\t\tstatus,\n\t\t\t\tversion,\n\t\t\t};\n\n\t\t\tif (status === \"active\" && existing.status !== \"active\") {\n\t\t\t\tupdates.activated_at = now;\n\t\t\t} else if (status === \"inactive\" && existing.status !== \"inactive\") {\n\t\t\t\tupdates.deactivated_at = now;\n\t\t\t}\n\n\t\t\tif (opts?.source) updates.source = opts.source;\n\t\t\tif (opts?.marketplaceVersion !== undefined) {\n\t\t\t\tupdates.marketplace_version = opts.marketplaceVersion;\n\t\t\t}\n\t\t\tif (opts?.displayName !== undefined) {\n\t\t\t\tupdates.display_name = opts.displayName;\n\t\t\t}\n\t\t\tif (opts?.description !== undefined) {\n\t\t\t\tupdates.description = opts.description;\n\t\t\t}\n\t\t\tif (opts?.registryPublisherDid !== undefined) {\n\t\t\t\tupdates.registry_publisher_did = opts.registryPublisherDid;\n\t\t\t}\n\t\t\tif (opts?.registrySlug !== undefined) {\n\t\t\t\tupdates.registry_slug = opts.registrySlug;\n\t\t\t}\n\t\t\tif (opts?.mcpToolsEnabled !== undefined) {\n\t\t\t\tupdates.mcp_tools_enabled = opts.mcpToolsEnabled ? 1 : 0;\n\t\t\t}\n\t\t\tif (opts?.mcpToolsConsent !== undefined) {\n\t\t\t\tupdates.mcp_tools_consent = opts.mcpToolsConsent;\n\t\t\t}\n\n\t\t\tawait this.db\n\t\t\t\t.updateTable(\"_plugin_state\")\n\t\t\t\t.set(updates)\n\t\t\t\t.where(\"plugin_id\", \"=\", pluginId)\n\t\t\t\t.execute();\n\t\t} else {\n\t\t\t// Create new state\n\t\t\tawait this.db\n\t\t\t\t.insertInto(\"_plugin_state\")\n\t\t\t\t.values({\n\t\t\t\t\tplugin_id: pluginId,\n\t\t\t\t\tstatus,\n\t\t\t\t\tversion,\n\t\t\t\t\tinstalled_at: now,\n\t\t\t\t\tactivated_at: status === \"active\" ? now : null,\n\t\t\t\t\tdeactivated_at: null,\n\t\t\t\t\tdata: null,\n\t\t\t\t\tsource: opts?.source ?? \"config\",\n\t\t\t\t\tmarketplace_version: opts?.marketplaceVersion ?? null,\n\t\t\t\t\tdisplay_name: opts?.displayName ?? null,\n\t\t\t\t\tdescription: opts?.description ?? null,\n\t\t\t\t\tregistry_publisher_did: opts?.registryPublisherDid ?? null,\n\t\t\t\t\tregistry_slug: opts?.registrySlug ?? null,\n\t\t\t\t\tmcp_tools_enabled: opts?.mcpToolsEnabled ? 1 : 0,\n\t\t\t\t\tmcp_tools_consent: opts?.mcpToolsConsent ?? null,\n\t\t\t\t})\n\t\t\t\t.execute();\n\t\t}\n\n\t\treturn (await this.get(pluginId))!;\n\t}\n\n\t/**\n\t * Enable a plugin\n\t */\n\tasync enable(pluginId: string, version: string): Promise<PluginState> {\n\t\treturn this.upsert(pluginId, version, \"active\");\n\t}\n\n\t/**\n\t * Disable a plugin\n\t */\n\tasync disable(pluginId: string, version: string): Promise<PluginState> {\n\t\treturn this.upsert(pluginId, version, \"inactive\");\n\t}\n\n\t/**\n\t * Delete plugin state\n\t */\n\tasync delete(pluginId: string): Promise<boolean> {\n\t\tconst result = await this.db\n\t\t\t.deleteFrom(\"_plugin_state\")\n\t\t\t.where(\"plugin_id\", \"=\", pluginId)\n\t\t\t.executeTakeFirst();\n\n\t\treturn (result.numDeletedRows ?? 0) > 0;\n\t}\n}\n\n/**\n * Internal: map a `_plugin_state` row to the public `PluginState` shape.\n *\n * Kept at module scope so the three select paths (`get`, `getAll`,\n * `getMarketplacePlugins`, `getRegistryPlugins`) stay byte-identical in\n * their handling of nullable columns -- adding a new column to the table\n * means changing this function and nothing else.\n */\ninterface PluginStateRow {\n\tplugin_id: string;\n\tstatus: string;\n\tversion: string;\n\tinstalled_at: string;\n\tactivated_at: string | null;\n\tdeactivated_at: string | null;\n\tsource: string;\n\tmarketplace_version: string | null;\n\tdisplay_name: string | null;\n\tdescription: string | null;\n\tregistry_publisher_did: string | null;\n\tregistry_slug: string | null;\n\tmcp_tools_enabled: number;\n\tmcp_tools_consent: string | null;\n}\n\nfunction rowToPluginState(row: PluginStateRow): PluginState {\n\treturn {\n\t\tpluginId: row.plugin_id,\n\t\tstatus: toPluginStatus(row.status),\n\t\tversion: row.version,\n\t\tinstalledAt: parseDatabaseTimestamp(row.installed_at),\n\t\tactivatedAt: row.activated_at ? parseDatabaseTimestamp(row.activated_at) : null,\n\t\tdeactivatedAt: row.deactivated_at ? parseDatabaseTimestamp(row.deactivated_at) : null,\n\t\tsource: toPluginSource(row.source),\n\t\tmarketplaceVersion: row.marketplace_version ?? null,\n\t\tdisplayName: row.display_name ?? null,\n\t\tdescription: row.description ?? null,\n\t\tregistryPublisherDid: row.registry_publisher_did ?? null,\n\t\tregistrySlug: row.registry_slug ?? null,\n\t\tmcpToolsEnabled: row.mcp_tools_enabled === 1,\n\t\tmcpToolsConsent: row.mcp_tools_consent ?? null,\n\t};\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"status-
|
|
1
|
+
{"version":3,"file":"status-Cenfk_r5.mjs","names":[],"sources":["../src/redirects/status.ts"],"sourcesContent":["/**\n * Redirect rule status codes.\n *\n * A redirect rule's `type` is either a *redirect* status (issues a `Location`\n * header) or a *terminal* status (serves the status with no target). Terminal\n * statuses let editors mark a URL as intentionally gone:\n * - `410 Gone` — permanently and intentionally deleted (Google deindexes it\n * faster than a 404).\n * - `451 Unavailable For Legal Reasons`.\n */\n\n/** Statuses that issue an HTTP redirect (require a destination). */\nexport const REDIRECT_STATUSES = [301, 302, 307, 308] as const;\n\n/** Terminal statuses that serve a status with no `Location` / no destination. */\nexport const TERMINAL_STATUSES = [410, 451] as const;\n\n/** All values accepted as a redirect rule `type`. */\nexport const REDIRECT_RULE_STATUSES: readonly number[] = [\n\t...REDIRECT_STATUSES,\n\t...TERMINAL_STATUSES,\n];\n\n/** True for terminal statuses (410/451) — served directly, with no target. */\nexport function isTerminalStatus(type: number): boolean {\n\treturn (TERMINAL_STATUSES as readonly number[]).includes(type);\n}\n"],"mappings":";;;;;;;;;;;;AAYA,MAAa,oBAAoB;CAAC;CAAK;CAAK;CAAK;CAAI;;AAGrD,MAAa,oBAAoB,CAAC,KAAK,IAAI;;AAG3C,MAAa,yBAA4C,CACxD,GAAG,mBACH,GAAG,kBACH;;AAGD,SAAgB,iBAAiB,MAAuB;AACvD,QAAQ,kBAAwC,SAAS,KAAK"}
|
package/dist/storage/local.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as ListOptions, d as Storage, l as SignedUploadOptions, n as DownloadResult, o as ListResult, p as UploadResult, s as LocalStorageConfig, u as SignedUploadUrl } from "../types-
|
|
1
|
+
import { a as ListOptions, d as Storage, l as SignedUploadOptions, n as DownloadResult, o as ListResult, p as UploadResult, s as LocalStorageConfig, u as SignedUploadUrl } from "../types-2n848aVW.mjs";
|
|
2
2
|
|
|
3
3
|
//#region src/storage/local.d.ts
|
|
4
4
|
/**
|
|
@@ -21,6 +21,7 @@ declare class LocalStorage implements Storage {
|
|
|
21
21
|
key: string;
|
|
22
22
|
body: Buffer | Uint8Array | ReadableStream<Uint8Array>;
|
|
23
23
|
contentType: string;
|
|
24
|
+
cacheControl?: string;
|
|
24
25
|
}): Promise<UploadResult>;
|
|
25
26
|
download(key: string): Promise<DownloadResult>;
|
|
26
27
|
delete(key: string): Promise<void>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"local.d.mts","names":[],"sources":["../../src/storage/local.ts"],"mappings":";;;;;;cAuCa,YAAA,YAAwB,OAAA;EA+BP;EAAA,QA7BrB,SAAA;EAAA,QACA,OAAA;cAEI,MAAA,EAAQ,kBAAA;
|
|
1
|
+
{"version":3,"file":"local.d.mts","names":[],"sources":["../../src/storage/local.ts"],"mappings":";;;;;;cAuCa,YAAA,YAAwB,OAAA;EA+BP;EAAA,QA7BrB,SAAA;EAAA,QACA,OAAA;cAEI,MAAA,EAAQ,kBAAA;EAkES;;;;;;;EAAA,QAtDrB,WAAA;EAYF,MAAA,CAAO,OAAA;IACZ,GAAA;IACA,IAAA,EAAM,MAAA,GAAS,UAAA,GAAa,cAAA,CAAe,UAAA;IAC3C,WAAA;IACA,YAAA;EAAA,IACG,OAAA,CAAQ,YAAA;EAqCN,QAAA,CAAS,GAAA,WAAc,OAAA,CAAQ,cAAA;EAkC/B,MAAA,CAAO,GAAA,WAAc,OAAA;EAYrB,MAAA,CAAO,GAAA,WAAc,OAAA;EAUrB,IAAA,CAAK,OAAA,GAAS,WAAA,GAAmB,OAAA,CAAQ,UAAA;EAsDzC,kBAAA,CAAmB,QAAA,EAAU,mBAAA,GAAsB,OAAA,CAAQ,eAAA;EASjE,YAAA,CAAa,GAAA;AAAA;;;;;iBAgBE,aAAA,CAAc,MAAA,EAAQ,MAAA,oBAA0B,OAAA"}
|
package/dist/storage/local.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"local.mjs","names":[],"sources":["../../src/storage/local.ts"],"sourcesContent":["/**\n * Local Filesystem Storage Implementation\n *\n * For development and testing. Stores files in a local directory.\n */\n\nimport { createReadStream, existsSync } from \"node:fs\";\nimport * as fs from \"node:fs/promises\";\nimport * as path from \"node:path\";\nimport { Readable } from \"node:stream\";\n\nimport mime from \"mime/lite\";\n\n/** Type guard for Node.js ErrnoException */\nfunction isNodeError(error: unknown): error is NodeJS.ErrnoException {\n\treturn error instanceof Error && \"code\" in error;\n}\n\nimport type {\n\tStorage,\n\tLocalStorageConfig,\n\tUploadResult,\n\tDownloadResult,\n\tListResult,\n\tListOptions,\n\tSignedUploadUrl,\n\tSignedUploadOptions,\n} from \"./types.js\";\nimport { EmDashStorageError } from \"./types.js\";\n\n/** Pattern to remove leading slashes */\nconst LEADING_SLASH_PATTERN = /^\\//;\n\n/** Pattern to remove trailing slashes */\nconst TRAILING_SLASH_PATTERN = /\\/$/;\n\n/**\n * Local filesystem storage implementation\n */\nexport class LocalStorage implements Storage {\n\t/** Resolved absolute base directory for all stored files */\n\tprivate directory: string;\n\tprivate baseUrl: string;\n\n\tconstructor(config: LocalStorageConfig) {\n\t\tthis.directory = path.resolve(config.directory);\n\t\tthis.baseUrl = config.baseUrl.replace(TRAILING_SLASH_PATTERN, \"\");\n\t}\n\n\t/**\n\t * Resolve a storage key to an absolute file path, ensuring it stays\n\t * within the configured storage directory. Uses path.resolve() for\n\t * canonical resolution rather than regex stripping.\n\t *\n\t * @throws EmDashStorageError if the resolved path escapes the base directory\n\t */\n\tprivate getFilePath(key: string): string {\n\t\tconst normalizedKey = key.replace(LEADING_SLASH_PATTERN, \"\");\n\t\tconst resolved = path.resolve(this.directory, normalizedKey);\n\n\t\t// Verify the resolved path is within the base directory\n\t\tif (!resolved.startsWith(this.directory + path.sep) && resolved !== this.directory) {\n\t\t\tthrow new EmDashStorageError(\"Invalid file path\", \"INVALID_PATH\");\n\t\t}\n\n\t\treturn resolved;\n\t}\n\n\tasync upload(options: {\n\t\tkey: string;\n\t\tbody: Buffer | Uint8Array | ReadableStream<Uint8Array>;\n\t\tcontentType: string;\n\t}): Promise<UploadResult> {\n\t\ttry {\n\t\t\tconst filePath = this.getFilePath(options.key);\n\t\t\tconst dir = path.dirname(filePath);\n\n\t\t\t// Ensure directory exists\n\t\t\tawait fs.mkdir(dir, { recursive: true });\n\n\t\t\t// Convert body to buffer\n\t\t\tlet buffer: Buffer;\n\t\t\tif (options.body instanceof ReadableStream) {\n\t\t\t\tconst chunks: Uint8Array[] = [];\n\t\t\t\tconst reader = options.body.getReader();\n\t\t\t\twhile (true) {\n\t\t\t\t\tconst { done, value } = await reader.read();\n\t\t\t\t\tif (done) break;\n\t\t\t\t\tchunks.push(value);\n\t\t\t\t}\n\t\t\t\tbuffer = Buffer.concat(chunks);\n\t\t\t} else if (options.body instanceof Uint8Array) {\n\t\t\t\tbuffer = Buffer.from(options.body);\n\t\t\t} else {\n\t\t\t\tbuffer = options.body;\n\t\t\t}\n\n\t\t\tawait fs.writeFile(filePath, buffer);\n\n\t\t\treturn {\n\t\t\t\tkey: options.key,\n\t\t\t\turl: this.getPublicUrl(options.key),\n\t\t\t\tsize: buffer.length,\n\t\t\t};\n\t\t} catch (error) {\n\t\t\tthrow new EmDashStorageError(`Failed to upload file: ${options.key}`, \"UPLOAD_FAILED\", error);\n\t\t}\n\t}\n\n\tasync download(key: string): Promise<DownloadResult> {\n\t\ttry {\n\t\t\tconst filePath = this.getFilePath(key);\n\n\t\t\tif (!existsSync(filePath)) {\n\t\t\t\tthrow new EmDashStorageError(`File not found: ${key}`, \"NOT_FOUND\");\n\t\t\t}\n\n\t\t\tconst stat = await fs.stat(filePath);\n\t\t\tconst nodeStream = createReadStream(filePath);\n\n\t\t\t// Convert Node.js stream to web ReadableStream\n\t\t\t// Readable.toWeb returns ReadableStream (which is ReadableStream<unknown>),\n\t\t\t// but Node ReadStreams produce Buffer/Uint8Array chunks\n\t\t\t// eslint-disable-next-line typescript/no-unsafe-type-assertion -- Readable.toWeb returns ReadableStream<unknown>; Node ReadStreams produce Uint8Array chunks\n\t\t\tconst webStream: ReadableStream<Uint8Array> = Readable.toWeb(\n\t\t\t\tnodeStream,\n\t\t\t) as ReadableStream<Uint8Array>;\n\n\t\t\t// Infer content type from extension\n\t\t\tconst ext = path.extname(key).toLowerCase();\n\t\t\tconst contentType = getContentType(ext);\n\n\t\t\treturn {\n\t\t\t\tbody: webStream,\n\t\t\t\tcontentType,\n\t\t\t\tsize: stat.size,\n\t\t\t};\n\t\t} catch (error) {\n\t\t\tif (error instanceof EmDashStorageError) throw error;\n\t\t\tthrow new EmDashStorageError(`Failed to download file: ${key}`, \"DOWNLOAD_FAILED\", error);\n\t\t}\n\t}\n\n\tasync delete(key: string): Promise<void> {\n\t\ttry {\n\t\t\tconst filePath = this.getFilePath(key);\n\t\t\tawait fs.unlink(filePath);\n\t\t} catch (error) {\n\t\t\t// Ignore \"file not found\" errors (idempotent delete)\n\t\t\tif (!isNodeError(error) || error.code !== \"ENOENT\") {\n\t\t\t\tthrow new EmDashStorageError(`Failed to delete file: ${key}`, \"DELETE_FAILED\", error);\n\t\t\t}\n\t\t}\n\t}\n\n\tasync exists(key: string): Promise<boolean> {\n\t\ttry {\n\t\t\tconst filePath = this.getFilePath(key);\n\t\t\tawait fs.access(filePath);\n\t\t\treturn true;\n\t\t} catch {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\tasync list(options: ListOptions = {}): Promise<ListResult> {\n\t\ttry {\n\t\t\tconst prefix = options.prefix || \"\";\n\t\t\tconst searchDir = path.resolve(this.directory, path.dirname(prefix));\n\n\t\t\t// Validate the search directory stays within the base directory\n\t\t\tif (!searchDir.startsWith(this.directory + path.sep) && searchDir !== this.directory) {\n\t\t\t\tthrow new EmDashStorageError(\"Invalid list prefix\", \"INVALID_PATH\");\n\t\t\t}\n\n\t\t\tconst prefixBase = path.basename(prefix);\n\n\t\t\t// Ensure directory exists\n\t\t\ttry {\n\t\t\t\tawait fs.access(searchDir);\n\t\t\t} catch {\n\t\t\t\treturn { files: [] };\n\t\t\t}\n\n\t\t\tconst entries = await fs.readdir(searchDir, { withFileTypes: true });\n\t\t\tconst files: ListResult[\"files\"] = [];\n\n\t\t\tfor (const entry of entries) {\n\t\t\t\tif (entry.isFile() && entry.name.startsWith(prefixBase)) {\n\t\t\t\t\tconst key = path.join(path.dirname(prefix), entry.name);\n\t\t\t\t\tconst filePath = path.join(searchDir, entry.name);\n\t\t\t\t\tconst stat = await fs.stat(filePath);\n\n\t\t\t\t\tfiles.push({\n\t\t\t\t\t\tkey,\n\t\t\t\t\t\tsize: stat.size,\n\t\t\t\t\t\tlastModified: stat.mtime,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Sort by last modified (newest first)\n\t\t\tfiles.sort((a, b) => b.lastModified.getTime() - a.lastModified.getTime());\n\n\t\t\t// Apply limit and cursor (simple implementation)\n\t\t\tconst startIndex = options.cursor ? parseInt(options.cursor, 10) : 0;\n\t\t\tconst limit = options.limit || 1000;\n\t\t\tconst paginatedFiles = files.slice(startIndex, startIndex + limit);\n\t\t\tconst hasMore = startIndex + limit < files.length;\n\n\t\t\treturn {\n\t\t\t\tfiles: paginatedFiles,\n\t\t\t\tnextCursor: hasMore ? String(startIndex + limit) : undefined,\n\t\t\t};\n\t\t} catch (error) {\n\t\t\tthrow new EmDashStorageError(\"Failed to list files\", \"LIST_FAILED\", error);\n\t\t}\n\t}\n\n\tasync getSignedUploadUrl(_options: SignedUploadOptions): Promise<SignedUploadUrl> {\n\t\t// Local storage doesn't support signed URLs\n\t\tthrow new EmDashStorageError(\n\t\t\t\"Local storage does not support signed upload URLs. \" +\n\t\t\t\t\"Upload files directly through the API.\",\n\t\t\t\"NOT_SUPPORTED\",\n\t\t);\n\t}\n\n\tgetPublicUrl(key: string): string {\n\t\treturn `${this.baseUrl}/${key}`;\n\t}\n}\n\n/**\n * Get content type from file extension\n */\nfunction getContentType(ext: string): string {\n\treturn mime.getType(ext) ?? \"application/octet-stream\";\n}\n\n/**\n * Create local storage adapter\n * This is the factory function called at runtime\n */\nexport function createStorage(config: Record<string, unknown>): Storage {\n\tconst directory = typeof config.directory === \"string\" ? config.directory : \"\";\n\tconst baseUrl = typeof config.baseUrl === \"string\" ? config.baseUrl : \"\";\n\treturn new LocalStorage({ directory, baseUrl });\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"local.mjs","names":[],"sources":["../../src/storage/local.ts"],"sourcesContent":["/**\n * Local Filesystem Storage Implementation\n *\n * For development and testing. Stores files in a local directory.\n */\n\nimport { createReadStream, existsSync } from \"node:fs\";\nimport * as fs from \"node:fs/promises\";\nimport * as path from \"node:path\";\nimport { Readable } from \"node:stream\";\n\nimport mime from \"mime/lite\";\n\n/** Type guard for Node.js ErrnoException */\nfunction isNodeError(error: unknown): error is NodeJS.ErrnoException {\n\treturn error instanceof Error && \"code\" in error;\n}\n\nimport type {\n\tStorage,\n\tLocalStorageConfig,\n\tUploadResult,\n\tDownloadResult,\n\tListResult,\n\tListOptions,\n\tSignedUploadUrl,\n\tSignedUploadOptions,\n} from \"./types.js\";\nimport { EmDashStorageError } from \"./types.js\";\n\n/** Pattern to remove leading slashes */\nconst LEADING_SLASH_PATTERN = /^\\//;\n\n/** Pattern to remove trailing slashes */\nconst TRAILING_SLASH_PATTERN = /\\/$/;\n\n/**\n * Local filesystem storage implementation\n */\nexport class LocalStorage implements Storage {\n\t/** Resolved absolute base directory for all stored files */\n\tprivate directory: string;\n\tprivate baseUrl: string;\n\n\tconstructor(config: LocalStorageConfig) {\n\t\tthis.directory = path.resolve(config.directory);\n\t\tthis.baseUrl = config.baseUrl.replace(TRAILING_SLASH_PATTERN, \"\");\n\t}\n\n\t/**\n\t * Resolve a storage key to an absolute file path, ensuring it stays\n\t * within the configured storage directory. Uses path.resolve() for\n\t * canonical resolution rather than regex stripping.\n\t *\n\t * @throws EmDashStorageError if the resolved path escapes the base directory\n\t */\n\tprivate getFilePath(key: string): string {\n\t\tconst normalizedKey = key.replace(LEADING_SLASH_PATTERN, \"\");\n\t\tconst resolved = path.resolve(this.directory, normalizedKey);\n\n\t\t// Verify the resolved path is within the base directory\n\t\tif (!resolved.startsWith(this.directory + path.sep) && resolved !== this.directory) {\n\t\t\tthrow new EmDashStorageError(\"Invalid file path\", \"INVALID_PATH\");\n\t\t}\n\n\t\treturn resolved;\n\t}\n\n\tasync upload(options: {\n\t\tkey: string;\n\t\tbody: Buffer | Uint8Array | ReadableStream<Uint8Array>;\n\t\tcontentType: string;\n\t\tcacheControl?: string;\n\t}): Promise<UploadResult> {\n\t\ttry {\n\t\t\tconst filePath = this.getFilePath(options.key);\n\t\t\tconst dir = path.dirname(filePath);\n\n\t\t\t// Ensure directory exists\n\t\t\tawait fs.mkdir(dir, { recursive: true });\n\n\t\t\t// Convert body to buffer\n\t\t\tlet buffer: Buffer;\n\t\t\tif (options.body instanceof ReadableStream) {\n\t\t\t\tconst chunks: Uint8Array[] = [];\n\t\t\t\tconst reader = options.body.getReader();\n\t\t\t\twhile (true) {\n\t\t\t\t\tconst { done, value } = await reader.read();\n\t\t\t\t\tif (done) break;\n\t\t\t\t\tchunks.push(value);\n\t\t\t\t}\n\t\t\t\tbuffer = Buffer.concat(chunks);\n\t\t\t} else if (options.body instanceof Uint8Array) {\n\t\t\t\tbuffer = Buffer.from(options.body);\n\t\t\t} else {\n\t\t\t\tbuffer = options.body;\n\t\t\t}\n\n\t\t\tawait fs.writeFile(filePath, buffer);\n\n\t\t\treturn {\n\t\t\t\tkey: options.key,\n\t\t\t\turl: this.getPublicUrl(options.key),\n\t\t\t\tsize: buffer.length,\n\t\t\t};\n\t\t} catch (error) {\n\t\t\tthrow new EmDashStorageError(`Failed to upload file: ${options.key}`, \"UPLOAD_FAILED\", error);\n\t\t}\n\t}\n\n\tasync download(key: string): Promise<DownloadResult> {\n\t\ttry {\n\t\t\tconst filePath = this.getFilePath(key);\n\n\t\t\tif (!existsSync(filePath)) {\n\t\t\t\tthrow new EmDashStorageError(`File not found: ${key}`, \"NOT_FOUND\");\n\t\t\t}\n\n\t\t\tconst stat = await fs.stat(filePath);\n\t\t\tconst nodeStream = createReadStream(filePath);\n\n\t\t\t// Convert Node.js stream to web ReadableStream\n\t\t\t// Readable.toWeb returns ReadableStream (which is ReadableStream<unknown>),\n\t\t\t// but Node ReadStreams produce Buffer/Uint8Array chunks\n\t\t\t// eslint-disable-next-line typescript/no-unsafe-type-assertion -- Readable.toWeb returns ReadableStream<unknown>; Node ReadStreams produce Uint8Array chunks\n\t\t\tconst webStream: ReadableStream<Uint8Array> = Readable.toWeb(\n\t\t\t\tnodeStream,\n\t\t\t) as ReadableStream<Uint8Array>;\n\n\t\t\t// Infer content type from extension\n\t\t\tconst ext = path.extname(key).toLowerCase();\n\t\t\tconst contentType = getContentType(ext);\n\n\t\t\treturn {\n\t\t\t\tbody: webStream,\n\t\t\t\tcontentType,\n\t\t\t\tsize: stat.size,\n\t\t\t};\n\t\t} catch (error) {\n\t\t\tif (error instanceof EmDashStorageError) throw error;\n\t\t\tthrow new EmDashStorageError(`Failed to download file: ${key}`, \"DOWNLOAD_FAILED\", error);\n\t\t}\n\t}\n\n\tasync delete(key: string): Promise<void> {\n\t\ttry {\n\t\t\tconst filePath = this.getFilePath(key);\n\t\t\tawait fs.unlink(filePath);\n\t\t} catch (error) {\n\t\t\t// Ignore \"file not found\" errors (idempotent delete)\n\t\t\tif (!isNodeError(error) || error.code !== \"ENOENT\") {\n\t\t\t\tthrow new EmDashStorageError(`Failed to delete file: ${key}`, \"DELETE_FAILED\", error);\n\t\t\t}\n\t\t}\n\t}\n\n\tasync exists(key: string): Promise<boolean> {\n\t\ttry {\n\t\t\tconst filePath = this.getFilePath(key);\n\t\t\tawait fs.access(filePath);\n\t\t\treturn true;\n\t\t} catch {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\tasync list(options: ListOptions = {}): Promise<ListResult> {\n\t\ttry {\n\t\t\tconst prefix = options.prefix || \"\";\n\t\t\tconst searchDir = path.resolve(this.directory, path.dirname(prefix));\n\n\t\t\t// Validate the search directory stays within the base directory\n\t\t\tif (!searchDir.startsWith(this.directory + path.sep) && searchDir !== this.directory) {\n\t\t\t\tthrow new EmDashStorageError(\"Invalid list prefix\", \"INVALID_PATH\");\n\t\t\t}\n\n\t\t\tconst prefixBase = path.basename(prefix);\n\n\t\t\t// Ensure directory exists\n\t\t\ttry {\n\t\t\t\tawait fs.access(searchDir);\n\t\t\t} catch {\n\t\t\t\treturn { files: [] };\n\t\t\t}\n\n\t\t\tconst entries = await fs.readdir(searchDir, { withFileTypes: true });\n\t\t\tconst files: ListResult[\"files\"] = [];\n\n\t\t\tfor (const entry of entries) {\n\t\t\t\tif (entry.isFile() && entry.name.startsWith(prefixBase)) {\n\t\t\t\t\tconst key = path.join(path.dirname(prefix), entry.name);\n\t\t\t\t\tconst filePath = path.join(searchDir, entry.name);\n\t\t\t\t\tconst stat = await fs.stat(filePath);\n\n\t\t\t\t\tfiles.push({\n\t\t\t\t\t\tkey,\n\t\t\t\t\t\tsize: stat.size,\n\t\t\t\t\t\tlastModified: stat.mtime,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Sort by last modified (newest first)\n\t\t\tfiles.sort((a, b) => b.lastModified.getTime() - a.lastModified.getTime());\n\n\t\t\t// Apply limit and cursor (simple implementation)\n\t\t\tconst startIndex = options.cursor ? parseInt(options.cursor, 10) : 0;\n\t\t\tconst limit = options.limit || 1000;\n\t\t\tconst paginatedFiles = files.slice(startIndex, startIndex + limit);\n\t\t\tconst hasMore = startIndex + limit < files.length;\n\n\t\t\treturn {\n\t\t\t\tfiles: paginatedFiles,\n\t\t\t\tnextCursor: hasMore ? String(startIndex + limit) : undefined,\n\t\t\t};\n\t\t} catch (error) {\n\t\t\tthrow new EmDashStorageError(\"Failed to list files\", \"LIST_FAILED\", error);\n\t\t}\n\t}\n\n\tasync getSignedUploadUrl(_options: SignedUploadOptions): Promise<SignedUploadUrl> {\n\t\t// Local storage doesn't support signed URLs\n\t\tthrow new EmDashStorageError(\n\t\t\t\"Local storage does not support signed upload URLs. \" +\n\t\t\t\t\"Upload files directly through the API.\",\n\t\t\t\"NOT_SUPPORTED\",\n\t\t);\n\t}\n\n\tgetPublicUrl(key: string): string {\n\t\treturn `${this.baseUrl}/${key}`;\n\t}\n}\n\n/**\n * Get content type from file extension\n */\nfunction getContentType(ext: string): string {\n\treturn mime.getType(ext) ?? \"application/octet-stream\";\n}\n\n/**\n * Create local storage adapter\n * This is the factory function called at runtime\n */\nexport function createStorage(config: Record<string, unknown>): Storage {\n\tconst directory = typeof config.directory === \"string\" ? config.directory : \"\";\n\tconst baseUrl = typeof config.baseUrl === \"string\" ? config.baseUrl : \"\";\n\treturn new LocalStorage({ directory, baseUrl });\n}\n"],"mappings":"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"}
|
package/dist/storage/s3.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as ListOptions, c as S3StorageConfig, d as Storage, l as SignedUploadOptions, n as DownloadResult, o as ListResult, p as UploadResult, u as SignedUploadUrl } from "../types-
|
|
1
|
+
import { a as ListOptions, c as S3StorageConfig, d as Storage, l as SignedUploadOptions, n as DownloadResult, o as ListResult, p as UploadResult, u as SignedUploadUrl } from "../types-2n848aVW.mjs";
|
|
2
2
|
|
|
3
3
|
//#region src/storage/s3.d.ts
|
|
4
4
|
/**
|
|
@@ -21,6 +21,7 @@ declare class S3Storage implements Storage {
|
|
|
21
21
|
key: string;
|
|
22
22
|
body: Buffer | Uint8Array | ReadableStream<Uint8Array>;
|
|
23
23
|
contentType: string;
|
|
24
|
+
cacheControl?: string;
|
|
24
25
|
}): Promise<UploadResult>;
|
|
25
26
|
download(key: string): Promise<DownloadResult>;
|
|
26
27
|
delete(key: string): Promise<void>;
|