emdash 0.12.0 → 0.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{adapters-BktHA7EO.d.mts → adapters-9DybjTO6.d.mts} +1 -1
- package/dist/{adapters-BktHA7EO.d.mts.map → adapters-9DybjTO6.d.mts.map} +1 -1
- package/dist/allowed-origins-CDdG-4Gd.mjs +116 -0
- package/dist/allowed-origins-CDdG-4Gd.mjs.map +1 -0
- package/dist/api/route-utils.d.mts +68 -0
- package/dist/api/route-utils.d.mts.map +1 -0
- package/dist/api/route-utils.mjs +44 -0
- package/dist/api/route-utils.mjs.map +1 -0
- package/dist/api/schemas/index.d.mts +2 -0
- package/dist/api/schemas/index.mjs +4 -0
- package/dist/api-BMLZuwM4.mjs +3941 -0
- package/dist/api-BMLZuwM4.mjs.map +1 -0
- package/dist/api-tokens-D3C9v02m.mjs +3 -0
- package/dist/api-tokens-eYymBhIT.mjs +153 -0
- package/dist/api-tokens-eYymBhIT.mjs.map +1 -0
- package/dist/{apply-C1ZORgcy.mjs → apply-v4DBgjPw.mjs} +19 -346
- package/dist/apply-v4DBgjPw.mjs.map +1 -0
- package/dist/astro/index.d.mts +10 -6
- package/dist/astro/index.d.mts.map +1 -1
- package/dist/astro/index.mjs +42 -83
- package/dist/astro/index.mjs.map +1 -1
- package/dist/astro/middleware/auth.d.mts +9 -5
- package/dist/astro/middleware/auth.d.mts.map +1 -1
- package/dist/astro/middleware/auth.mjs +25 -65
- package/dist/astro/middleware/auth.mjs.map +1 -1
- package/dist/astro/middleware/redirect.mjs +5 -5
- package/dist/astro/middleware/request-context.mjs +4 -4
- package/dist/astro/middleware/setup.mjs +1 -1
- package/dist/astro/middleware.d.mts.map +1 -1
- package/dist/astro/middleware.mjs +140 -69
- package/dist/astro/middleware.mjs.map +1 -1
- package/dist/astro/routes/PluginRegistry.d.mts +15 -0
- package/dist/astro/routes/PluginRegistry.d.mts.map +1 -0
- package/dist/astro/routes/PluginRegistry.mjs +25 -0
- package/dist/astro/routes/PluginRegistry.mjs.map +1 -0
- package/dist/astro/routes/api/admin/allowed-domains/_domain_.d.mts +15 -0
- package/dist/astro/routes/api/admin/allowed-domains/_domain_.d.mts.map +1 -0
- package/dist/astro/routes/api/admin/allowed-domains/_domain_.mjs +67 -0
- package/dist/astro/routes/api/admin/allowed-domains/_domain_.mjs.map +1 -0
- package/dist/astro/routes/api/admin/allowed-domains/index.d.mts +15 -0
- package/dist/astro/routes/api/admin/allowed-domains/index.d.mts.map +1 -0
- package/dist/astro/routes/api/admin/allowed-domains/index.mjs +67 -0
- package/dist/astro/routes/api/admin/allowed-domains/index.mjs.map +1 -0
- package/dist/astro/routes/api/admin/api-tokens/_id_.d.mts +11 -0
- package/dist/astro/routes/api/admin/api-tokens/_id_.d.mts.map +1 -0
- package/dist/astro/routes/api/admin/api-tokens/_id_.mjs +33 -0
- package/dist/astro/routes/api/admin/api-tokens/_id_.mjs.map +1 -0
- package/dist/astro/routes/api/admin/api-tokens/index.d.mts +17 -0
- package/dist/astro/routes/api/admin/api-tokens/index.d.mts.map +1 -0
- package/dist/astro/routes/api/admin/api-tokens/index.mjs +52 -0
- package/dist/astro/routes/api/admin/api-tokens/index.mjs.map +1 -0
- package/dist/astro/routes/api/admin/bylines/_id_/index.d.mts +10 -0
- package/dist/astro/routes/api/admin/bylines/_id_/index.d.mts.map +1 -0
- package/dist/astro/routes/api/admin/bylines/_id_/index.mjs +74 -0
- package/dist/astro/routes/api/admin/bylines/_id_/index.mjs.map +1 -0
- package/dist/astro/routes/api/admin/bylines/index.d.mts +9 -0
- package/dist/astro/routes/api/admin/bylines/index.d.mts.map +1 -0
- package/dist/astro/routes/api/admin/bylines/index.mjs +61 -0
- package/dist/astro/routes/api/admin/bylines/index.mjs.map +1 -0
- package/dist/astro/routes/api/admin/comments/_id_/status.d.mts +8 -0
- package/dist/astro/routes/api/admin/comments/_id_/status.d.mts.map +1 -0
- package/dist/astro/routes/api/admin/comments/_id_/status.mjs +80 -0
- package/dist/astro/routes/api/admin/comments/_id_/status.mjs.map +1 -0
- package/dist/astro/routes/api/admin/comments/_id_.d.mts +15 -0
- package/dist/astro/routes/api/admin/comments/_id_.d.mts.map +1 -0
- package/dist/astro/routes/api/admin/comments/_id_.mjs +47 -0
- package/dist/astro/routes/api/admin/comments/_id_.mjs.map +1 -0
- package/dist/astro/routes/api/admin/comments/bulk.d.mts +8 -0
- package/dist/astro/routes/api/admin/comments/bulk.d.mts.map +1 -0
- package/dist/astro/routes/api/admin/comments/bulk.mjs +36 -0
- package/dist/astro/routes/api/admin/comments/bulk.mjs.map +1 -0
- package/dist/astro/routes/api/admin/comments/counts.d.mts +8 -0
- package/dist/astro/routes/api/admin/comments/counts.d.mts.map +1 -0
- package/dist/astro/routes/api/admin/comments/counts.mjs +25 -0
- package/dist/astro/routes/api/admin/comments/counts.mjs.map +1 -0
- package/dist/astro/routes/api/admin/comments/index.d.mts +11 -0
- package/dist/astro/routes/api/admin/comments/index.d.mts.map +1 -0
- package/dist/astro/routes/api/admin/comments/index.mjs +40 -0
- package/dist/astro/routes/api/admin/comments/index.mjs.map +1 -0
- package/dist/astro/routes/api/admin/hooks/exclusive/_hookName_.d.mts +8 -0
- package/dist/astro/routes/api/admin/hooks/exclusive/_hookName_.d.mts.map +1 -0
- package/dist/astro/routes/api/admin/hooks/exclusive/_hookName_.mjs +48 -0
- package/dist/astro/routes/api/admin/hooks/exclusive/_hookName_.mjs.map +1 -0
- package/dist/astro/routes/api/admin/hooks/exclusive/index.d.mts +8 -0
- package/dist/astro/routes/api/admin/hooks/exclusive/index.d.mts.map +1 -0
- package/dist/astro/routes/api/admin/hooks/exclusive/index.mjs +36 -0
- package/dist/astro/routes/api/admin/hooks/exclusive/index.mjs.map +1 -0
- package/dist/astro/routes/api/admin/oauth-clients/_id_.d.mts +19 -0
- package/dist/astro/routes/api/admin/oauth-clients/_id_.d.mts.map +1 -0
- package/dist/astro/routes/api/admin/oauth-clients/_id_.mjs +69 -0
- package/dist/astro/routes/api/admin/oauth-clients/_id_.mjs.map +1 -0
- package/dist/astro/routes/api/admin/oauth-clients/index.d.mts +15 -0
- package/dist/astro/routes/api/admin/oauth-clients/index.d.mts.map +1 -0
- package/dist/astro/routes/api/admin/oauth-clients/index.mjs +50 -0
- package/dist/astro/routes/api/admin/oauth-clients/index.mjs.map +1 -0
- package/dist/astro/routes/api/admin/plugins/_id_/disable.d.mts +8 -0
- package/dist/astro/routes/api/admin/plugins/_id_/disable.d.mts.map +1 -0
- package/dist/astro/routes/api/admin/plugins/_id_/disable.mjs +56 -0
- package/dist/astro/routes/api/admin/plugins/_id_/disable.mjs.map +1 -0
- package/dist/astro/routes/api/admin/plugins/_id_/enable.d.mts +8 -0
- package/dist/astro/routes/api/admin/plugins/_id_/enable.d.mts.map +1 -0
- package/dist/astro/routes/api/admin/plugins/_id_/enable.mjs +59 -0
- package/dist/astro/routes/api/admin/plugins/_id_/enable.mjs.map +1 -0
- package/dist/astro/routes/api/admin/plugins/_id_/index.d.mts +8 -0
- package/dist/astro/routes/api/admin/plugins/_id_/index.d.mts.map +1 -0
- package/dist/astro/routes/api/admin/plugins/_id_/index.mjs +51 -0
- package/dist/astro/routes/api/admin/plugins/_id_/index.mjs.map +1 -0
- package/dist/astro/routes/api/admin/plugins/_id_/uninstall.d.mts +8 -0
- package/dist/astro/routes/api/admin/plugins/_id_/uninstall.d.mts.map +1 -0
- package/dist/astro/routes/api/admin/plugins/_id_/uninstall.mjs +58 -0
- package/dist/astro/routes/api/admin/plugins/_id_/uninstall.mjs.map +1 -0
- package/dist/astro/routes/api/admin/plugins/_id_/update.d.mts +8 -0
- package/dist/astro/routes/api/admin/plugins/_id_/update.d.mts.map +1 -0
- package/dist/astro/routes/api/admin/plugins/_id_/update.mjs +66 -0
- package/dist/astro/routes/api/admin/plugins/_id_/update.mjs.map +1 -0
- package/dist/astro/routes/api/admin/plugins/index.d.mts +8 -0
- package/dist/astro/routes/api/admin/plugins/index.d.mts.map +1 -0
- package/dist/astro/routes/api/admin/plugins/index.mjs +49 -0
- package/dist/astro/routes/api/admin/plugins/index.mjs.map +1 -0
- package/dist/astro/routes/api/admin/plugins/marketplace/_id_/icon.d.mts +8 -0
- package/dist/astro/routes/api/admin/plugins/marketplace/_id_/icon.d.mts.map +1 -0
- package/dist/astro/routes/api/admin/plugins/marketplace/_id_/icon.mjs +39 -0
- package/dist/astro/routes/api/admin/plugins/marketplace/_id_/icon.mjs.map +1 -0
- package/dist/astro/routes/api/admin/plugins/marketplace/_id_/index.d.mts +8 -0
- package/dist/astro/routes/api/admin/plugins/marketplace/_id_/index.d.mts.map +1 -0
- package/dist/astro/routes/api/admin/plugins/marketplace/_id_/index.mjs +51 -0
- package/dist/astro/routes/api/admin/plugins/marketplace/_id_/index.mjs.map +1 -0
- package/dist/astro/routes/api/admin/plugins/marketplace/_id_/install.d.mts +8 -0
- package/dist/astro/routes/api/admin/plugins/marketplace/_id_/install.d.mts.map +1 -0
- package/dist/astro/routes/api/admin/plugins/marketplace/_id_/install.mjs +69 -0
- package/dist/astro/routes/api/admin/plugins/marketplace/_id_/install.mjs.map +1 -0
- package/dist/astro/routes/api/admin/plugins/marketplace/index.d.mts +8 -0
- package/dist/astro/routes/api/admin/plugins/marketplace/index.d.mts.map +1 -0
- package/dist/astro/routes/api/admin/plugins/marketplace/index.mjs +58 -0
- package/dist/astro/routes/api/admin/plugins/marketplace/index.mjs.map +1 -0
- package/dist/astro/routes/api/admin/plugins/registry/install.d.mts +8 -0
- package/dist/astro/routes/api/admin/plugins/registry/install.d.mts.map +1 -0
- package/dist/astro/routes/api/admin/plugins/registry/install.mjs +72 -0
- package/dist/astro/routes/api/admin/plugins/registry/install.mjs.map +1 -0
- package/dist/astro/routes/api/admin/plugins/updates.d.mts +8 -0
- package/dist/astro/routes/api/admin/plugins/updates.d.mts.map +1 -0
- package/dist/astro/routes/api/admin/plugins/updates.mjs +49 -0
- package/dist/astro/routes/api/admin/plugins/updates.mjs.map +1 -0
- package/dist/astro/routes/api/admin/themes/marketplace/_id_/index.d.mts +8 -0
- package/dist/astro/routes/api/admin/themes/marketplace/_id_/index.d.mts.map +1 -0
- package/dist/astro/routes/api/admin/themes/marketplace/_id_/index.mjs +51 -0
- package/dist/astro/routes/api/admin/themes/marketplace/_id_/index.mjs.map +1 -0
- package/dist/astro/routes/api/admin/themes/marketplace/_id_/thumbnail.d.mts +8 -0
- package/dist/astro/routes/api/admin/themes/marketplace/_id_/thumbnail.d.mts.map +1 -0
- package/dist/astro/routes/api/admin/themes/marketplace/_id_/thumbnail.mjs +39 -0
- package/dist/astro/routes/api/admin/themes/marketplace/_id_/thumbnail.mjs.map +1 -0
- package/dist/astro/routes/api/admin/themes/marketplace/index.d.mts +8 -0
- package/dist/astro/routes/api/admin/themes/marketplace/index.d.mts.map +1 -0
- package/dist/astro/routes/api/admin/themes/marketplace/index.mjs +67 -0
- package/dist/astro/routes/api/admin/themes/marketplace/index.mjs.map +1 -0
- package/dist/astro/routes/api/admin/users/_id_/disable.d.mts +8 -0
- package/dist/astro/routes/api/admin/users/_id_/disable.d.mts.map +1 -0
- package/dist/astro/routes/api/admin/users/_id_/disable.mjs +43 -0
- package/dist/astro/routes/api/admin/users/_id_/disable.mjs.map +1 -0
- package/dist/astro/routes/api/admin/users/_id_/enable.d.mts +8 -0
- package/dist/astro/routes/api/admin/users/_id_/enable.d.mts.map +1 -0
- package/dist/astro/routes/api/admin/users/_id_/enable.mjs +32 -0
- package/dist/astro/routes/api/admin/users/_id_/enable.mjs.map +1 -0
- package/dist/astro/routes/api/admin/users/_id_/index.d.mts +9 -0
- package/dist/astro/routes/api/admin/users/_id_/index.d.mts.map +1 -0
- package/dist/astro/routes/api/admin/users/_id_/index.mjs +106 -0
- package/dist/astro/routes/api/admin/users/_id_/index.mjs.map +1 -0
- package/dist/astro/routes/api/admin/users/_id_/send-recovery.d.mts +8 -0
- package/dist/astro/routes/api/admin/users/_id_/send-recovery.d.mts.map +1 -0
- package/dist/astro/routes/api/admin/users/_id_/send-recovery.mjs +46 -0
- package/dist/astro/routes/api/admin/users/_id_/send-recovery.mjs.map +1 -0
- package/dist/astro/routes/api/admin/users/index.d.mts +8 -0
- package/dist/astro/routes/api/admin/users/index.d.mts.map +1 -0
- package/dist/astro/routes/api/admin/users/index.mjs +56 -0
- package/dist/astro/routes/api/admin/users/index.mjs.map +1 -0
- package/dist/astro/routes/api/auth/dev-bypass.d.mts +9 -0
- package/dist/astro/routes/api/auth/dev-bypass.d.mts.map +1 -0
- package/dist/astro/routes/api/auth/dev-bypass.mjs +84 -0
- package/dist/astro/routes/api/auth/dev-bypass.mjs.map +1 -0
- package/dist/astro/routes/api/auth/invite/accept.d.mts +8 -0
- package/dist/astro/routes/api/auth/invite/accept.d.mts.map +1 -0
- package/dist/astro/routes/api/auth/invite/accept.mjs +34 -0
- package/dist/astro/routes/api/auth/invite/accept.mjs.map +1 -0
- package/dist/astro/routes/api/auth/invite/complete.d.mts +8 -0
- package/dist/astro/routes/api/auth/invite/complete.d.mts.map +1 -0
- package/dist/astro/routes/api/auth/invite/complete.mjs +56 -0
- package/dist/astro/routes/api/auth/invite/complete.mjs.map +1 -0
- package/dist/astro/routes/api/auth/invite/index.d.mts +8 -0
- package/dist/astro/routes/api/auth/invite/index.d.mts.map +1 -0
- package/dist/astro/routes/api/auth/invite/index.mjs +53 -0
- package/dist/astro/routes/api/auth/invite/index.mjs.map +1 -0
- package/dist/astro/routes/api/auth/invite/register-options.d.mts +8 -0
- package/dist/astro/routes/api/auth/invite/register-options.d.mts.map +1 -0
- package/dist/astro/routes/api/auth/invite/register-options.mjs +46 -0
- package/dist/astro/routes/api/auth/invite/register-options.mjs.map +1 -0
- package/dist/astro/routes/api/auth/logout.d.mts +8 -0
- package/dist/astro/routes/api/auth/logout.d.mts.map +1 -0
- package/dist/astro/routes/api/auth/logout.mjs +27 -0
- package/dist/astro/routes/api/auth/logout.mjs.map +1 -0
- package/dist/astro/routes/api/auth/magic-link/send.d.mts +8 -0
- package/dist/astro/routes/api/auth/magic-link/send.d.mts.map +1 -0
- package/dist/astro/routes/api/auth/magic-link/send.mjs +50 -0
- package/dist/astro/routes/api/auth/magic-link/send.mjs.map +1 -0
- package/dist/astro/routes/api/auth/magic-link/verify.d.mts +8 -0
- package/dist/astro/routes/api/auth/magic-link/verify.d.mts.map +1 -0
- package/dist/astro/routes/api/auth/magic-link/verify.mjs +35 -0
- package/dist/astro/routes/api/auth/magic-link/verify.mjs.map +1 -0
- package/dist/astro/routes/api/auth/me.d.mts +14 -0
- package/dist/astro/routes/api/auth/me.d.mts.map +1 -0
- package/dist/astro/routes/api/auth/me.mjs +43 -0
- package/dist/astro/routes/api/auth/me.mjs.map +1 -0
- package/dist/astro/routes/api/auth/mode.d.mts +8 -0
- package/dist/astro/routes/api/auth/mode.d.mts.map +1 -0
- package/dist/astro/routes/api/auth/mode.mjs +29 -0
- package/dist/astro/routes/api/auth/mode.mjs.map +1 -0
- package/dist/astro/routes/api/auth/oauth/_provider_/callback.d.mts +8 -0
- package/dist/astro/routes/api/auth/oauth/_provider_/callback.d.mts.map +1 -0
- package/dist/astro/routes/api/auth/oauth/_provider_/callback.mjs +130 -0
- package/dist/astro/routes/api/auth/oauth/_provider_/callback.mjs.map +1 -0
- package/dist/astro/routes/api/auth/oauth/_provider_.d.mts +8 -0
- package/dist/astro/routes/api/auth/oauth/_provider_.d.mts.map +1 -0
- package/dist/astro/routes/api/auth/oauth/_provider_.mjs +60 -0
- package/dist/astro/routes/api/auth/oauth/_provider_.mjs.map +1 -0
- package/dist/astro/routes/api/auth/passkey/_id_.d.mts +15 -0
- package/dist/astro/routes/api/auth/passkey/_id_.d.mts.map +1 -0
- package/dist/astro/routes/api/auth/passkey/_id_.mjs +64 -0
- package/dist/astro/routes/api/auth/passkey/_id_.mjs.map +1 -0
- package/dist/astro/routes/api/auth/passkey/index.d.mts +8 -0
- package/dist/astro/routes/api/auth/passkey/index.d.mts.map +1 -0
- package/dist/astro/routes/api/auth/passkey/index.mjs +28 -0
- package/dist/astro/routes/api/auth/passkey/index.mjs.map +1 -0
- package/dist/astro/routes/api/auth/passkey/options.d.mts +8 -0
- package/dist/astro/routes/api/auth/passkey/options.d.mts.map +1 -0
- package/dist/astro/routes/api/auth/passkey/options.mjs +48 -0
- package/dist/astro/routes/api/auth/passkey/options.mjs.map +1 -0
- package/dist/astro/routes/api/auth/passkey/register/options.d.mts +8 -0
- package/dist/astro/routes/api/auth/passkey/register/options.d.mts.map +1 -0
- package/dist/astro/routes/api/auth/passkey/register/options.mjs +46 -0
- package/dist/astro/routes/api/auth/passkey/register/options.mjs.map +1 -0
- package/dist/astro/routes/api/auth/passkey/register/verify.d.mts +8 -0
- package/dist/astro/routes/api/auth/passkey/register/verify.d.mts.map +1 -0
- package/dist/astro/routes/api/auth/passkey/register/verify.mjs +61 -0
- package/dist/astro/routes/api/auth/passkey/register/verify.mjs.map +1 -0
- package/dist/astro/routes/api/auth/passkey/verify.d.mts +8 -0
- package/dist/astro/routes/api/auth/passkey/verify.d.mts.map +1 -0
- package/dist/astro/routes/api/auth/passkey/verify.mjs +49 -0
- package/dist/astro/routes/api/auth/passkey/verify.mjs.map +1 -0
- package/dist/astro/routes/api/auth/signup/complete.d.mts +8 -0
- package/dist/astro/routes/api/auth/signup/complete.d.mts.map +1 -0
- package/dist/astro/routes/api/auth/signup/complete.mjs +57 -0
- package/dist/astro/routes/api/auth/signup/complete.mjs.map +1 -0
- package/dist/astro/routes/api/auth/signup/request.d.mts +8 -0
- package/dist/astro/routes/api/auth/signup/request.d.mts.map +1 -0
- package/dist/astro/routes/api/auth/signup/request.mjs +46 -0
- package/dist/astro/routes/api/auth/signup/request.mjs.map +1 -0
- package/dist/astro/routes/api/auth/signup/verify.d.mts +8 -0
- package/dist/astro/routes/api/auth/signup/verify.d.mts.map +1 -0
- package/dist/astro/routes/api/auth/signup/verify.mjs +35 -0
- package/dist/astro/routes/api/auth/signup/verify.mjs.map +1 -0
- package/dist/astro/routes/api/comments/_collection_/_contentId_/index.d.mts +15 -0
- package/dist/astro/routes/api/comments/_collection_/_contentId_/index.d.mts.map +1 -0
- package/dist/astro/routes/api/comments/_collection_/_contentId_/index.mjs +193 -0
- package/dist/astro/routes/api/comments/_collection_/_contentId_/index.mjs.map +1 -0
- package/dist/astro/routes/api/content/_collection_/_id_/compare.d.mts +8 -0
- package/dist/astro/routes/api/content/_collection_/_id_/compare.d.mts.map +1 -0
- package/dist/astro/routes/api/content/_collection_/_id_/compare.mjs +20 -0
- package/dist/astro/routes/api/content/_collection_/_id_/compare.mjs.map +1 -0
- package/dist/astro/routes/api/content/_collection_/_id_/discard-draft.d.mts +8 -0
- package/dist/astro/routes/api/content/_collection_/_id_/discard-draft.d.mts.map +1 -0
- package/dist/astro/routes/api/content/_collection_/_id_/discard-draft.mjs +28 -0
- package/dist/astro/routes/api/content/_collection_/_id_/discard-draft.mjs.map +1 -0
- package/dist/astro/routes/api/content/_collection_/_id_/duplicate.d.mts +8 -0
- package/dist/astro/routes/api/content/_collection_/_id_/duplicate.d.mts.map +1 -0
- package/dist/astro/routes/api/content/_collection_/_id_/duplicate.mjs +30 -0
- package/dist/astro/routes/api/content/_collection_/_id_/duplicate.mjs.map +1 -0
- package/dist/astro/routes/api/content/_collection_/_id_/permanent.d.mts +8 -0
- package/dist/astro/routes/api/content/_collection_/_id_/permanent.d.mts.map +1 -0
- package/dist/astro/routes/api/content/_collection_/_id_/permanent.mjs +23 -0
- package/dist/astro/routes/api/content/_collection_/_id_/permanent.mjs.map +1 -0
- package/dist/astro/routes/api/content/_collection_/_id_/preview-url.d.mts +8 -0
- package/dist/astro/routes/api/content/_collection_/_id_/preview-url.d.mts.map +1 -0
- package/dist/astro/routes/api/content/_collection_/_id_/preview-url.mjs +78 -0
- package/dist/astro/routes/api/content/_collection_/_id_/preview-url.mjs.map +1 -0
- package/dist/astro/routes/api/content/_collection_/_id_/publish.d.mts +8 -0
- package/dist/astro/routes/api/content/_collection_/_id_/publish.d.mts.map +1 -0
- package/dist/astro/routes/api/content/_collection_/_id_/publish.mjs +48 -0
- package/dist/astro/routes/api/content/_collection_/_id_/publish.mjs.map +1 -0
- package/dist/astro/routes/api/content/_collection_/_id_/restore.d.mts +8 -0
- package/dist/astro/routes/api/content/_collection_/_id_/restore.d.mts.map +1 -0
- package/dist/astro/routes/api/content/_collection_/_id_/restore.mjs +28 -0
- package/dist/astro/routes/api/content/_collection_/_id_/restore.mjs.map +1 -0
- package/dist/astro/routes/api/content/_collection_/_id_/revisions.d.mts +8 -0
- package/dist/astro/routes/api/content/_collection_/_id_/revisions.d.mts.map +1 -0
- package/dist/astro/routes/api/content/_collection_/_id_/revisions.mjs +22 -0
- package/dist/astro/routes/api/content/_collection_/_id_/revisions.mjs.map +1 -0
- package/dist/astro/routes/api/content/_collection_/_id_/schedule.d.mts +9 -0
- package/dist/astro/routes/api/content/_collection_/_id_/schedule.d.mts.map +1 -0
- package/dist/astro/routes/api/content/_collection_/_id_/schedule.mjs +58 -0
- package/dist/astro/routes/api/content/_collection_/_id_/schedule.mjs.map +1 -0
- package/dist/astro/routes/api/content/_collection_/_id_/terms/_taxonomy_.d.mts +15 -0
- package/dist/astro/routes/api/content/_collection_/_id_/terms/_taxonomy_.d.mts.map +1 -0
- package/dist/astro/routes/api/content/_collection_/_id_/terms/_taxonomy_.mjs +85 -0
- package/dist/astro/routes/api/content/_collection_/_id_/terms/_taxonomy_.mjs.map +1 -0
- package/dist/astro/routes/api/content/_collection_/_id_/translations.d.mts +8 -0
- package/dist/astro/routes/api/content/_collection_/_id_/translations.d.mts.map +1 -0
- package/dist/astro/routes/api/content/_collection_/_id_/translations.mjs +43 -0
- package/dist/astro/routes/api/content/_collection_/_id_/translations.mjs.map +1 -0
- package/dist/astro/routes/api/content/_collection_/_id_/unpublish.d.mts +8 -0
- package/dist/astro/routes/api/content/_collection_/_id_/unpublish.d.mts.map +1 -0
- package/dist/astro/routes/api/content/_collection_/_id_/unpublish.mjs +28 -0
- package/dist/astro/routes/api/content/_collection_/_id_/unpublish.mjs.map +1 -0
- package/dist/astro/routes/api/content/_collection_/_id_.d.mts +10 -0
- package/dist/astro/routes/api/content/_collection_/_id_.d.mts.map +1 -0
- package/dist/astro/routes/api/content/_collection_/_id_.mjs +88 -0
- package/dist/astro/routes/api/content/_collection_/_id_.mjs.map +1 -0
- package/dist/astro/routes/api/content/_collection_/index.d.mts +9 -0
- package/dist/astro/routes/api/content/_collection_/index.d.mts.map +1 -0
- package/dist/astro/routes/api/content/_collection_/index.mjs +61 -0
- package/dist/astro/routes/api/content/_collection_/index.mjs.map +1 -0
- package/dist/astro/routes/api/content/_collection_/trash.d.mts +8 -0
- package/dist/astro/routes/api/content/_collection_/trash.d.mts.map +1 -0
- package/dist/astro/routes/api/content/_collection_/trash.mjs +25 -0
- package/dist/astro/routes/api/content/_collection_/trash.mjs.map +1 -0
- package/dist/astro/routes/api/dashboard.d.mts +8 -0
- package/dist/astro/routes/api/dashboard.d.mts.map +1 -0
- package/dist/astro/routes/api/dashboard.mjs +26 -0
- package/dist/astro/routes/api/dashboard.mjs.map +1 -0
- package/dist/astro/routes/api/dev/emails.d.mts +9 -0
- package/dist/astro/routes/api/dev/emails.d.mts.map +1 -0
- package/dist/astro/routes/api/dev/emails.mjs +20 -0
- package/dist/astro/routes/api/dev/emails.mjs.map +1 -0
- package/dist/astro/routes/api/import/probe.d.mts +18 -0
- package/dist/astro/routes/api/import/probe.d.mts.map +1 -0
- package/dist/astro/routes/api/import/probe.mjs +35 -0
- package/dist/astro/routes/api/import/probe.mjs.map +1 -0
- package/dist/astro/routes/api/import/wordpress/analyze.d.mts +88 -0
- package/dist/astro/routes/api/import/wordpress/analyze.d.mts.map +1 -0
- package/dist/astro/routes/api/import/wordpress/analyze.mjs +313 -0
- package/dist/astro/routes/api/import/wordpress/analyze.mjs.map +1 -0
- package/dist/astro/routes/api/import/wordpress/execute.d.mts +93 -0
- package/dist/astro/routes/api/import/wordpress/execute.d.mts.map +1 -0
- package/dist/astro/routes/api/import/wordpress/execute.mjs +593 -0
- package/dist/astro/routes/api/import/wordpress/execute.mjs.map +1 -0
- package/dist/astro/routes/api/import/wordpress/media.d.mts +36 -0
- package/dist/astro/routes/api/import/wordpress/media.d.mts.map +1 -0
- package/dist/astro/routes/api/import/wordpress/media.mjs +225 -0
- package/dist/astro/routes/api/import/wordpress/media.mjs.map +1 -0
- package/dist/astro/routes/api/import/wordpress/prepare.d.mts +20 -0
- package/dist/astro/routes/api/import/wordpress/prepare.d.mts.map +1 -0
- package/dist/astro/routes/api/import/wordpress/prepare.mjs +120 -0
- package/dist/astro/routes/api/import/wordpress/prepare.mjs.map +1 -0
- package/dist/astro/routes/api/import/wordpress/rewrite-url-helpers.d.mts +49 -0
- package/dist/astro/routes/api/import/wordpress/rewrite-url-helpers.d.mts.map +1 -0
- package/dist/astro/routes/api/import/wordpress/rewrite-url-helpers.mjs +131 -0
- package/dist/astro/routes/api/import/wordpress/rewrite-url-helpers.mjs.map +1 -0
- package/dist/astro/routes/api/import/wordpress/rewrite-urls.d.mts +22 -0
- package/dist/astro/routes/api/import/wordpress/rewrite-urls.d.mts.map +1 -0
- package/dist/astro/routes/api/import/wordpress/rewrite-urls.mjs +139 -0
- package/dist/astro/routes/api/import/wordpress/rewrite-urls.mjs.map +1 -0
- package/dist/astro/routes/api/import/wordpress-plugin/analyze.d.mts +16 -0
- package/dist/astro/routes/api/import/wordpress-plugin/analyze.d.mts.map +1 -0
- package/dist/astro/routes/api/import/wordpress-plugin/analyze.mjs +71 -0
- package/dist/astro/routes/api/import/wordpress-plugin/analyze.mjs.map +1 -0
- package/dist/astro/routes/api/import/wordpress-plugin/callback.d.mts +8 -0
- package/dist/astro/routes/api/import/wordpress-plugin/callback.d.mts.map +1 -0
- package/dist/astro/routes/api/import/wordpress-plugin/callback.mjs +29 -0
- package/dist/astro/routes/api/import/wordpress-plugin/callback.mjs.map +1 -0
- package/dist/astro/routes/api/import/wordpress-plugin/execute.d.mts +20 -0
- package/dist/astro/routes/api/import/wordpress-plugin/execute.d.mts.map +1 -0
- package/dist/astro/routes/api/import/wordpress-plugin/execute.mjs +219 -0
- package/dist/astro/routes/api/import/wordpress-plugin/execute.mjs.map +1 -0
- package/dist/astro/routes/api/manifest.d.mts +8 -0
- package/dist/astro/routes/api/manifest.d.mts.map +1 -0
- package/dist/astro/routes/api/manifest.mjs +47 -0
- package/dist/astro/routes/api/manifest.mjs.map +1 -0
- package/dist/astro/routes/api/mcp.d.mts +16 -0
- package/dist/astro/routes/api/mcp.d.mts.map +1 -0
- package/dist/astro/routes/api/mcp.mjs +1414 -0
- package/dist/astro/routes/api/mcp.mjs.map +1 -0
- package/dist/astro/routes/api/media/_id_/confirm.d.mts +11 -0
- package/dist/astro/routes/api/media/_id_/confirm.d.mts.map +1 -0
- package/dist/astro/routes/api/media/_id_/confirm.mjs +61 -0
- package/dist/astro/routes/api/media/_id_/confirm.mjs.map +1 -0
- package/dist/astro/routes/api/media/_id_.d.mts +23 -0
- package/dist/astro/routes/api/media/_id_.d.mts.map +1 -0
- package/dist/astro/routes/api/media/_id_.mjs +83 -0
- package/dist/astro/routes/api/media/_id_.mjs.map +1 -0
- package/dist/astro/routes/api/media/file/_...key_.d.mts +8 -0
- package/dist/astro/routes/api/media/file/_...key_.d.mts.map +1 -0
- package/dist/astro/routes/api/media/file/_...key_.mjs +52 -0
- package/dist/astro/routes/api/media/file/_...key_.mjs.map +1 -0
- package/dist/astro/routes/api/media/providers/_providerId_/_itemId_.d.mts +15 -0
- package/dist/astro/routes/api/media/providers/_providerId_/_itemId_.d.mts.map +1 -0
- package/dist/astro/routes/api/media/providers/_providerId_/_itemId_.mjs +52 -0
- package/dist/astro/routes/api/media/providers/_providerId_/_itemId_.mjs.map +1 -0
- package/dist/astro/routes/api/media/providers/_providerId_/index.d.mts +15 -0
- package/dist/astro/routes/api/media/providers/_providerId_/index.d.mts.map +1 -0
- package/dist/astro/routes/api/media/providers/_providerId_/index.mjs +75 -0
- package/dist/astro/routes/api/media/providers/_providerId_/index.mjs.map +1 -0
- package/dist/astro/routes/api/media/providers/index.d.mts +11 -0
- package/dist/astro/routes/api/media/providers/index.d.mts.map +1 -0
- package/dist/astro/routes/api/media/providers/index.mjs +21 -0
- package/dist/astro/routes/api/media/providers/index.mjs.map +1 -0
- package/dist/astro/routes/api/media/upload-url.d.mts +11 -0
- package/dist/astro/routes/api/media/upload-url.d.mts.map +1 -0
- package/dist/astro/routes/api/media/upload-url.mjs +82 -0
- package/dist/astro/routes/api/media/upload-url.mjs.map +1 -0
- package/dist/astro/routes/api/media.d.mts +17 -0
- package/dist/astro/routes/api/media.d.mts.map +1 -0
- package/dist/astro/routes/api/media.mjs +138 -0
- package/dist/astro/routes/api/media.mjs.map +1 -0
- package/dist/astro/routes/api/menus/_name_/items/_id_.d.mts +9 -0
- package/dist/astro/routes/api/menus/_name_/items/_id_.d.mts.map +1 -0
- package/dist/astro/routes/api/menus/_name_/items/_id_.mjs +48 -0
- package/dist/astro/routes/api/menus/_name_/items/_id_.mjs.map +1 -0
- package/dist/astro/routes/api/menus/_name_/items.d.mts +8 -0
- package/dist/astro/routes/api/menus/_name_/items.d.mts.map +1 -0
- package/dist/astro/routes/api/menus/_name_/items.mjs +31 -0
- package/dist/astro/routes/api/menus/_name_/items.mjs.map +1 -0
- package/dist/astro/routes/api/menus/_name_/reorder.d.mts +8 -0
- package/dist/astro/routes/api/menus/_name_/reorder.d.mts.map +1 -0
- package/dist/astro/routes/api/menus/_name_/reorder.mjs +31 -0
- package/dist/astro/routes/api/menus/_name_/reorder.mjs.map +1 -0
- package/dist/astro/routes/api/menus/_name_/translations.d.mts +9 -0
- package/dist/astro/routes/api/menus/_name_/translations.d.mts.map +1 -0
- package/dist/astro/routes/api/menus/_name_/translations.mjs +62 -0
- package/dist/astro/routes/api/menus/_name_/translations.mjs.map +1 -0
- package/dist/astro/routes/api/menus/_name_.d.mts +10 -0
- package/dist/astro/routes/api/menus/_name_.d.mts.map +1 -0
- package/dist/astro/routes/api/menus/_name_.mjs +60 -0
- package/dist/astro/routes/api/menus/_name_.mjs.map +1 -0
- package/dist/astro/routes/api/menus/index.d.mts +9 -0
- package/dist/astro/routes/api/menus/index.d.mts.map +1 -0
- package/dist/astro/routes/api/menus/index.mjs +40 -0
- package/dist/astro/routes/api/menus/index.mjs.map +1 -0
- package/dist/astro/routes/api/oauth/authorize.d.mts +9 -0
- package/dist/astro/routes/api/oauth/authorize.d.mts.map +1 -0
- package/dist/astro/routes/api/oauth/authorize.mjs +260 -0
- package/dist/astro/routes/api/oauth/authorize.mjs.map +1 -0
- package/dist/astro/routes/api/oauth/device/authorize.d.mts +8 -0
- package/dist/astro/routes/api/oauth/device/authorize.d.mts.map +1 -0
- package/dist/astro/routes/api/oauth/device/authorize.mjs +32 -0
- package/dist/astro/routes/api/oauth/device/authorize.mjs.map +1 -0
- package/dist/astro/routes/api/oauth/device/code.d.mts +8 -0
- package/dist/astro/routes/api/oauth/device/code.d.mts.map +1 -0
- package/dist/astro/routes/api/oauth/device/code.mjs +36 -0
- package/dist/astro/routes/api/oauth/device/code.mjs.map +1 -0
- package/dist/astro/routes/api/oauth/device/token.d.mts +8 -0
- package/dist/astro/routes/api/oauth/device/token.d.mts.map +1 -0
- package/dist/astro/routes/api/oauth/device/token.mjs +47 -0
- package/dist/astro/routes/api/oauth/device/token.mjs.map +1 -0
- package/dist/astro/routes/api/oauth/register.d.mts +9 -0
- package/dist/astro/routes/api/oauth/register.d.mts.map +1 -0
- package/dist/astro/routes/api/oauth/register.mjs +113 -0
- package/dist/astro/routes/api/oauth/register.mjs.map +1 -0
- package/dist/astro/routes/api/oauth/token/refresh.d.mts +8 -0
- package/dist/astro/routes/api/oauth/token/refresh.d.mts.map +1 -0
- package/dist/astro/routes/api/oauth/token/refresh.mjs +30 -0
- package/dist/astro/routes/api/oauth/token/refresh.mjs.map +1 -0
- package/dist/astro/routes/api/oauth/token/revoke.d.mts +8 -0
- package/dist/astro/routes/api/oauth/token/revoke.d.mts.map +1 -0
- package/dist/astro/routes/api/oauth/token/revoke.mjs +27 -0
- package/dist/astro/routes/api/oauth/token/revoke.mjs.map +1 -0
- package/dist/astro/routes/api/oauth/token.d.mts +9 -0
- package/dist/astro/routes/api/oauth/token.d.mts.map +1 -0
- package/dist/astro/routes/api/oauth/token.mjs +141 -0
- package/dist/astro/routes/api/oauth/token.mjs.map +1 -0
- package/dist/astro/routes/api/openapi.json.d.mts +8 -0
- package/dist/astro/routes/api/openapi.json.d.mts.map +1 -0
- package/dist/astro/routes/api/openapi.json.mjs +2642 -0
- package/dist/astro/routes/api/openapi.json.mjs.map +1 -0
- package/dist/astro/routes/api/plugins/_pluginId_/_...path_.d.mts +12 -0
- package/dist/astro/routes/api/plugins/_pluginId_/_...path_.d.mts.map +1 -0
- package/dist/astro/routes/api/plugins/_pluginId_/_...path_.mjs +78 -0
- package/dist/astro/routes/api/plugins/_pluginId_/_...path_.mjs.map +1 -0
- package/dist/astro/routes/api/redirects/404s/index.d.mts +10 -0
- package/dist/astro/routes/api/redirects/404s/index.d.mts.map +1 -0
- package/dist/astro/routes/api/redirects/404s/index.mjs +62 -0
- package/dist/astro/routes/api/redirects/404s/index.mjs.map +1 -0
- package/dist/astro/routes/api/redirects/404s/summary.d.mts +8 -0
- package/dist/astro/routes/api/redirects/404s/summary.d.mts.map +1 -0
- package/dist/astro/routes/api/redirects/404s/summary.mjs +34 -0
- package/dist/astro/routes/api/redirects/404s/summary.mjs.map +1 -0
- package/dist/astro/routes/api/redirects/_id_.d.mts +10 -0
- package/dist/astro/routes/api/redirects/_id_.d.mts.map +1 -0
- package/dist/astro/routes/api/redirects/_id_.mjs +71 -0
- package/dist/astro/routes/api/redirects/_id_.mjs.map +1 -0
- package/dist/astro/routes/api/redirects/index.d.mts +9 -0
- package/dist/astro/routes/api/redirects/index.d.mts.map +1 -0
- package/dist/astro/routes/api/redirects/index.mjs +52 -0
- package/dist/astro/routes/api/redirects/index.mjs.map +1 -0
- package/dist/astro/routes/api/revisions/_revisionId_/index.d.mts +8 -0
- package/dist/astro/routes/api/revisions/_revisionId_/index.d.mts.map +1 -0
- package/dist/astro/routes/api/revisions/_revisionId_/index.mjs +19 -0
- package/dist/astro/routes/api/revisions/_revisionId_/index.mjs.map +1 -0
- package/dist/astro/routes/api/revisions/_revisionId_/restore.d.mts +8 -0
- package/dist/astro/routes/api/revisions/_revisionId_/restore.d.mts.map +1 -0
- package/dist/astro/routes/api/revisions/_revisionId_/restore.mjs +26 -0
- package/dist/astro/routes/api/revisions/_revisionId_/restore.mjs.map +1 -0
- package/dist/astro/routes/api/schema/collections/_slug_/fields/_fieldSlug_.d.mts +10 -0
- package/dist/astro/routes/api/schema/collections/_slug_/fields/_fieldSlug_.d.mts.map +1 -0
- package/dist/astro/routes/api/schema/collections/_slug_/fields/_fieldSlug_.mjs +75 -0
- package/dist/astro/routes/api/schema/collections/_slug_/fields/_fieldSlug_.mjs.map +1 -0
- package/dist/astro/routes/api/schema/collections/_slug_/fields/index.d.mts +9 -0
- package/dist/astro/routes/api/schema/collections/_slug_/fields/index.d.mts.map +1 -0
- package/dist/astro/routes/api/schema/collections/_slug_/fields/index.mjs +63 -0
- package/dist/astro/routes/api/schema/collections/_slug_/fields/index.mjs.map +1 -0
- package/dist/astro/routes/api/schema/collections/_slug_/fields/reorder.d.mts +8 -0
- package/dist/astro/routes/api/schema/collections/_slug_/fields/reorder.d.mts.map +1 -0
- package/dist/astro/routes/api/schema/collections/_slug_/fields/reorder.mjs +54 -0
- package/dist/astro/routes/api/schema/collections/_slug_/fields/reorder.mjs.map +1 -0
- package/dist/astro/routes/api/schema/collections/_slug_/index.d.mts +10 -0
- package/dist/astro/routes/api/schema/collections/_slug_/index.d.mts.map +1 -0
- package/dist/astro/routes/api/schema/collections/_slug_/index.mjs +79 -0
- package/dist/astro/routes/api/schema/collections/_slug_/index.mjs.map +1 -0
- package/dist/astro/routes/api/schema/collections/index.d.mts +9 -0
- package/dist/astro/routes/api/schema/collections/index.d.mts.map +1 -0
- package/dist/astro/routes/api/schema/collections/index.mjs +63 -0
- package/dist/astro/routes/api/schema/collections/index.mjs.map +1 -0
- package/dist/astro/routes/api/schema/index.d.mts +8 -0
- package/dist/astro/routes/api/schema/index.d.mts.map +1 -0
- package/dist/astro/routes/api/schema/index.mjs +82 -0
- package/dist/astro/routes/api/schema/index.mjs.map +1 -0
- package/dist/astro/routes/api/schema/orphans/_slug_.d.mts +8 -0
- package/dist/astro/routes/api/schema/orphans/_slug_.d.mts.map +1 -0
- package/dist/astro/routes/api/schema/orphans/_slug_.mjs +55 -0
- package/dist/astro/routes/api/schema/orphans/_slug_.mjs.map +1 -0
- package/dist/astro/routes/api/schema/orphans/index.d.mts +8 -0
- package/dist/astro/routes/api/schema/orphans/index.d.mts.map +1 -0
- package/dist/astro/routes/api/schema/orphans/index.mjs +50 -0
- package/dist/astro/routes/api/schema/orphans/index.mjs.map +1 -0
- package/dist/astro/routes/api/search/enable.d.mts +16 -0
- package/dist/astro/routes/api/search/enable.d.mts.map +1 -0
- package/dist/astro/routes/api/search/enable.mjs +55 -0
- package/dist/astro/routes/api/search/enable.mjs.map +1 -0
- package/dist/astro/routes/api/search/index.d.mts +17 -0
- package/dist/astro/routes/api/search/index.d.mts.map +1 -0
- package/dist/astro/routes/api/search/index.mjs +52 -0
- package/dist/astro/routes/api/search/index.mjs.map +1 -0
- package/dist/astro/routes/api/search/rebuild.d.mts +14 -0
- package/dist/astro/routes/api/search/rebuild.d.mts.map +1 -0
- package/dist/astro/routes/api/search/rebuild.mjs +48 -0
- package/dist/astro/routes/api/search/rebuild.mjs.map +1 -0
- package/dist/astro/routes/api/search/stats.d.mts +11 -0
- package/dist/astro/routes/api/search/stats.d.mts.map +1 -0
- package/dist/astro/routes/api/search/stats.mjs +29 -0
- package/dist/astro/routes/api/search/stats.mjs.map +1 -0
- package/dist/astro/routes/api/search/suggest.d.mts +16 -0
- package/dist/astro/routes/api/search/suggest.d.mts.map +1 -0
- package/dist/astro/routes/api/search/suggest.mjs +43 -0
- package/dist/astro/routes/api/search/suggest.mjs.map +1 -0
- package/dist/astro/routes/api/sections/_slug_.d.mts +10 -0
- package/dist/astro/routes/api/sections/_slug_.d.mts.map +1 -0
- package/dist/astro/routes/api/sections/_slug_.mjs +65 -0
- package/dist/astro/routes/api/sections/_slug_.mjs.map +1 -0
- package/dist/astro/routes/api/sections/index.d.mts +9 -0
- package/dist/astro/routes/api/sections/index.d.mts.map +1 -0
- package/dist/astro/routes/api/sections/index.mjs +48 -0
- package/dist/astro/routes/api/sections/index.mjs.map +1 -0
- package/dist/astro/routes/api/settings/email.d.mts +18 -0
- package/dist/astro/routes/api/settings/email.d.mts.map +1 -0
- package/dist/astro/routes/api/settings/email.mjs +105 -0
- package/dist/astro/routes/api/settings/email.mjs.map +1 -0
- package/dist/astro/routes/api/settings.d.mts +21 -0
- package/dist/astro/routes/api/settings.d.mts.map +1 -0
- package/dist/astro/routes/api/settings.mjs +58 -0
- package/dist/astro/routes/api/settings.mjs.map +1 -0
- package/dist/astro/routes/api/setup/admin-verify.d.mts +8 -0
- package/dist/astro/routes/api/setup/admin-verify.d.mts.map +1 -0
- package/dist/astro/routes/api/setup/admin-verify.mjs +68 -0
- package/dist/astro/routes/api/setup/admin-verify.mjs.map +1 -0
- package/dist/astro/routes/api/setup/admin.d.mts +8 -0
- package/dist/astro/routes/api/setup/admin.d.mts.map +1 -0
- package/dist/astro/routes/api/setup/admin.mjs +69 -0
- package/dist/astro/routes/api/setup/admin.mjs.map +1 -0
- package/dist/astro/routes/api/setup/dev-bypass.d.mts +9 -0
- package/dist/astro/routes/api/setup/dev-bypass.d.mts.map +1 -0
- package/dist/astro/routes/api/setup/dev-bypass.mjs +139 -0
- package/dist/astro/routes/api/setup/dev-bypass.mjs.map +1 -0
- package/dist/astro/routes/api/setup/dev-reset.d.mts +8 -0
- package/dist/astro/routes/api/setup/dev-reset.d.mts.map +1 -0
- package/dist/astro/routes/api/setup/dev-reset.mjs +25 -0
- package/dist/astro/routes/api/setup/dev-reset.mjs.map +1 -0
- package/dist/astro/routes/api/setup/index.d.mts +8 -0
- package/dist/astro/routes/api/setup/index.d.mts.map +1 -0
- package/dist/astro/routes/api/setup/index.mjs +93 -0
- package/dist/astro/routes/api/setup/index.mjs.map +1 -0
- package/dist/astro/routes/api/setup/status.d.mts +8 -0
- package/dist/astro/routes/api/setup/status.d.mts.map +1 -0
- package/dist/astro/routes/api/setup/status.mjs +60 -0
- package/dist/astro/routes/api/setup/status.mjs.map +1 -0
- package/dist/astro/routes/api/snapshot.d.mts +8 -0
- package/dist/astro/routes/api/snapshot.d.mts.map +1 -0
- package/dist/astro/routes/api/snapshot.mjs +270 -0
- package/dist/astro/routes/api/snapshot.mjs.map +1 -0
- package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_/translations.d.mts +9 -0
- package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_/translations.d.mts.map +1 -0
- package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_/translations.mjs +72 -0
- package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_/translations.mjs.map +1 -0
- package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_.d.mts +19 -0
- package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_.d.mts.map +1 -0
- package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_.mjs +80 -0
- package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_.mjs.map +1 -0
- package/dist/astro/routes/api/taxonomies/_name_/terms/index.d.mts +15 -0
- package/dist/astro/routes/api/taxonomies/_name_/terms/index.d.mts.map +1 -0
- package/dist/astro/routes/api/taxonomies/_name_/terms/index.mjs +59 -0
- package/dist/astro/routes/api/taxonomies/_name_/terms/index.mjs.map +1 -0
- package/dist/astro/routes/api/taxonomies/index.d.mts +15 -0
- package/dist/astro/routes/api/taxonomies/index.d.mts.map +1 -0
- package/dist/astro/routes/api/taxonomies/index.mjs +55 -0
- package/dist/astro/routes/api/taxonomies/index.mjs.map +1 -0
- package/dist/astro/routes/api/themes/preview.d.mts +8 -0
- package/dist/astro/routes/api/themes/preview.d.mts.map +1 -0
- package/dist/astro/routes/api/themes/preview.mjs +49 -0
- package/dist/astro/routes/api/themes/preview.mjs.map +1 -0
- package/dist/astro/routes/api/typegen.d.mts +18 -0
- package/dist/astro/routes/api/typegen.d.mts.map +1 -0
- package/dist/astro/routes/api/typegen.mjs +78 -0
- package/dist/astro/routes/api/typegen.mjs.map +1 -0
- package/dist/astro/routes/api/well-known/auth.d.mts +8 -0
- package/dist/astro/routes/api/well-known/auth.d.mts.map +1 -0
- package/dist/astro/routes/api/well-known/auth.mjs +42 -0
- package/dist/astro/routes/api/well-known/auth.mjs.map +1 -0
- package/dist/astro/routes/api/well-known/oauth-authorization-server.d.mts +8 -0
- package/dist/astro/routes/api/well-known/oauth-authorization-server.d.mts.map +1 -0
- package/dist/astro/routes/api/well-known/oauth-authorization-server.mjs +32 -0
- package/dist/astro/routes/api/well-known/oauth-authorization-server.mjs.map +1 -0
- package/dist/astro/routes/api/well-known/oauth-protected-resource.d.mts +8 -0
- package/dist/astro/routes/api/well-known/oauth-protected-resource.d.mts.map +1 -0
- package/dist/astro/routes/api/well-known/oauth-protected-resource.mjs +21 -0
- package/dist/astro/routes/api/well-known/oauth-protected-resource.mjs.map +1 -0
- package/dist/astro/routes/api/widget-areas/_name_/reorder.d.mts +8 -0
- package/dist/astro/routes/api/widget-areas/_name_/reorder.d.mts.map +1 -0
- package/dist/astro/routes/api/widget-areas/_name_/reorder.mjs +36 -0
- package/dist/astro/routes/api/widget-areas/_name_/reorder.mjs.map +1 -0
- package/dist/astro/routes/api/widget-areas/_name_/widgets/_id_.d.mts +9 -0
- package/dist/astro/routes/api/widget-areas/_name_/widgets/_id_.d.mts.map +1 -0
- package/dist/astro/routes/api/widget-areas/_name_/widgets/_id_.mjs +62 -0
- package/dist/astro/routes/api/widget-areas/_name_/widgets/_id_.mjs.map +1 -0
- package/dist/astro/routes/api/widget-areas/_name_/widgets.d.mts +8 -0
- package/dist/astro/routes/api/widget-areas/_name_/widgets.d.mts.map +1 -0
- package/dist/astro/routes/api/widget-areas/_name_/widgets.mjs +49 -0
- package/dist/astro/routes/api/widget-areas/_name_/widgets.mjs.map +1 -0
- package/dist/astro/routes/api/widget-areas/_name_.d.mts +9 -0
- package/dist/astro/routes/api/widget-areas/_name_.d.mts.map +1 -0
- package/dist/astro/routes/api/widget-areas/_name_.mjs +49 -0
- package/dist/astro/routes/api/widget-areas/_name_.mjs.map +1 -0
- package/dist/astro/routes/api/widget-areas/index.d.mts +9 -0
- package/dist/astro/routes/api/widget-areas/index.d.mts.map +1 -0
- package/dist/astro/routes/api/widget-areas/index.mjs +59 -0
- package/dist/astro/routes/api/widget-areas/index.mjs.map +1 -0
- package/dist/astro/routes/api/widget-components.d.mts +8 -0
- package/dist/astro/routes/api/widget-components.d.mts.map +1 -0
- package/dist/astro/routes/api/widget-components.mjs +18 -0
- package/dist/astro/routes/api/widget-components.mjs.map +1 -0
- package/dist/astro/routes/robots.txt.d.mts +8 -0
- package/dist/astro/routes/robots.txt.d.mts.map +1 -0
- package/dist/astro/routes/robots.txt.mjs +61 -0
- package/dist/astro/routes/robots.txt.mjs.map +1 -0
- package/dist/astro/routes/sitemap-_collection_.xml.d.mts +8 -0
- package/dist/astro/routes/sitemap-_collection_.xml.d.mts.map +1 -0
- package/dist/astro/routes/sitemap-_collection_.xml.mjs +71 -0
- package/dist/astro/routes/sitemap-_collection_.xml.mjs.map +1 -0
- package/dist/astro/routes/sitemap.xml.d.mts +8 -0
- package/dist/astro/routes/sitemap.xml.d.mts.map +1 -0
- package/dist/astro/routes/sitemap.xml.mjs +64 -0
- package/dist/astro/routes/sitemap.xml.mjs.map +1 -0
- package/dist/astro/types.d.mts +48 -8
- package/dist/astro/types.d.mts.map +1 -1
- package/dist/auth/providers/github.d.mts +13 -0
- package/dist/auth/providers/github.d.mts.map +1 -0
- package/dist/auth/providers/github.mjs +18 -0
- package/dist/auth/providers/github.mjs.map +1 -0
- package/dist/auth/providers/google.d.mts +13 -0
- package/dist/auth/providers/google.d.mts.map +1 -0
- package/dist/auth/providers/google.mjs +18 -0
- package/dist/auth/providers/google.mjs.map +1 -0
- package/dist/authorize-BlyCH-96.mjs +37 -0
- package/dist/authorize-BlyCH-96.mjs.map +1 -0
- package/dist/{base64-MBPo9ozB.mjs → base64-CqR-7kqF.mjs} +1 -1
- package/dist/{base64-MBPo9ozB.mjs.map → base64-CqR-7kqF.mjs.map} +1 -1
- package/dist/{byline-gFn1r0vA.mjs → byline-D09BaS4j.mjs} +4 -4
- package/dist/{byline-gFn1r0vA.mjs.map → byline-D09BaS4j.mjs.map} +1 -1
- package/dist/{bylines-DTFI8nDM.mjs → bylines-BTM2xtP8.mjs} +6 -6
- package/dist/{bylines-DTFI8nDM.mjs.map → bylines-BTM2xtP8.mjs.map} +1 -1
- package/dist/bylines-BdUP8NuI.d.mts +1971 -0
- package/dist/bylines-BdUP8NuI.d.mts.map +1 -0
- package/dist/{cache-BAJbeoZ8.mjs → cache-CXCpjWiL.mjs} +3 -3
- package/dist/{cache-BAJbeoZ8.mjs.map → cache-CXCpjWiL.mjs.map} +1 -1
- package/dist/challenge-store-CJ0OOHOr.mjs +49 -0
- package/dist/challenge-store-CJ0OOHOr.mjs.map +1 -0
- package/dist/{chunks-BK1oZS-l.mjs → chunks-DyGtu1Bv.mjs} +2 -2
- package/dist/{chunks-BK1oZS-l.mjs.map → chunks-DyGtu1Bv.mjs.map} +1 -1
- package/dist/cli/index.mjs +23 -18
- package/dist/cli/index.mjs.map +1 -1
- package/dist/client/cf-access.d.mts +1 -1
- package/dist/client/index.d.mts +1 -1
- package/dist/client/index.d.mts.map +1 -1
- package/dist/client/index.mjs +2 -2
- package/dist/client/index.mjs.map +1 -1
- package/dist/comment-Dd9MI82-.mjs +247 -0
- package/dist/comment-Dd9MI82-.mjs.map +1 -0
- package/dist/comments-koGI0FrK.mjs +204 -0
- package/dist/comments-koGI0FrK.mjs.map +1 -0
- package/dist/components-mZem7pbe.mjs +108 -0
- package/dist/components-mZem7pbe.mjs.map +1 -0
- package/dist/{content-CERxPUN0.mjs → content-D6YG26WG.mjs} +10 -34
- package/dist/content-D6YG26WG.mjs.map +1 -0
- package/dist/context-qF8d3IPR.mjs +879 -0
- package/dist/context-qF8d3IPR.mjs.map +1 -0
- package/dist/cron-H8eJ46dv.mjs +264 -0
- package/dist/cron-H8eJ46dv.mjs.map +1 -0
- package/dist/dashboard-BmWSIUwY.mjs +105 -0
- package/dist/dashboard-BmWSIUwY.mjs.map +1 -0
- package/dist/db/index.d.mts +3 -3
- package/dist/db/index.mjs +1 -1
- package/dist/db/libsql.d.mts +1 -1
- package/dist/db/postgres.d.mts +1 -1
- package/dist/db/sqlite.d.mts +1 -1
- package/dist/{db-errors-B7P2pSCn.mjs → db-errors-CGN9kJfo.mjs} +1 -1
- package/dist/{db-errors-B7P2pSCn.mjs.map → db-errors-CGN9kJfo.mjs.map} +1 -1
- package/dist/{default-pHuz9WF6.mjs → default-Dbs22Gg4.mjs} +1 -1
- package/dist/{default-pHuz9WF6.mjs.map → default-Dbs22Gg4.mjs.map} +1 -1
- package/dist/device-flow-BqJRxa0Q.mjs +467 -0
- package/dist/device-flow-BqJRxa0Q.mjs.map +1 -0
- package/dist/email-console-Dmp5Q-P2.mjs +50 -0
- package/dist/email-console-Dmp5Q-P2.mjs.map +1 -0
- package/dist/error-tSQWIl5U.mjs +437 -0
- package/dist/error-tSQWIl5U.mjs.map +1 -0
- package/dist/escape-B8bdIryO.mjs +9 -0
- package/dist/escape-B8bdIryO.mjs.map +1 -0
- package/dist/fts-manager-B633C-kQ.mjs +339 -0
- package/dist/fts-manager-B633C-kQ.mjs.map +1 -0
- package/dist/hash-DlUxGhQS.mjs +33 -0
- package/dist/hash-DlUxGhQS.mjs.map +1 -0
- package/dist/import-CNfLOgDE.mjs +1531 -0
- package/dist/import-CNfLOgDE.mjs.map +1 -0
- package/dist/{index-Dlkzhb4C.d.mts → index-BV8iJ-6s.d.mts} +310 -911
- package/dist/index-BV8iJ-6s.d.mts.map +1 -0
- package/dist/index-D2gvztOP.d.mts +262 -0
- package/dist/index-D2gvztOP.d.mts.map +1 -0
- package/dist/index.d.mts +17 -11
- package/dist/index.mjs +57 -28
- package/dist/{load-DR1VwFXR.mjs → load-QzYRpVN3.mjs} +2 -2
- package/dist/{load-DR1VwFXR.mjs.map → load-QzYRpVN3.mjs.map} +1 -1
- package/dist/{loader-ou_PXAjg.mjs → loader-Cs6-Bqe6.mjs} +4 -4
- package/dist/{loader-ou_PXAjg.mjs.map → loader-Cs6-Bqe6.mjs.map} +1 -1
- package/dist/{manifest-schema-Bp6d4d4n.mjs → manifest-schema-HCtSh4Jq.mjs} +1 -1
- package/dist/{manifest-schema-Bp6d4d4n.mjs.map → manifest-schema-HCtSh4Jq.mjs.map} +1 -1
- package/dist/media/index.d.mts +1 -1
- package/dist/media/index.mjs +2 -1
- package/dist/media/index.mjs.map +1 -1
- package/dist/media/local-runtime.d.mts +11 -7
- package/dist/media/local-runtime.d.mts.map +1 -1
- package/dist/media/local-runtime.mjs +7 -6
- package/dist/media/local-runtime.mjs.map +1 -1
- package/dist/media-Dg7he9uK.mjs +209 -0
- package/dist/media-Dg7he9uK.mjs.map +1 -0
- package/dist/media-allowlist-B8EX01DH.mjs +32 -0
- package/dist/media-allowlist-B8EX01DH.mjs.map +1 -0
- package/dist/menus-DOzIecHi.mjs +723 -0
- package/dist/menus-DOzIecHi.mjs.map +1 -0
- package/dist/menus-X4Z-eBA1.mjs +2788 -0
- package/dist/menus-X4Z-eBA1.mjs.map +1 -0
- package/dist/mime-KV5TqkMN.mjs +36 -0
- package/dist/mime-KV5TqkMN.mjs.map +1 -0
- package/dist/{mode-YhqNVef_.mjs → mode-DPRPvJYm.mjs} +1 -1
- package/dist/{mode-YhqNVef_.mjs.map → mode-DPRPvJYm.mjs.map} +1 -1
- package/dist/normalize-CN5kRSMC.mjs +151 -0
- package/dist/normalize-CN5kRSMC.mjs.map +1 -0
- package/dist/oauth-authorization-62GmpGIH.mjs +275 -0
- package/dist/oauth-authorization-62GmpGIH.mjs.map +1 -0
- package/dist/oauth-clients-D_B0_-Bz.mjs +266 -0
- package/dist/oauth-clients-D_B0_-Bz.mjs.map +1 -0
- package/dist/oauth-state-store-DpsZViTu.mjs +49 -0
- package/dist/oauth-state-store-DpsZViTu.mjs.map +1 -0
- package/dist/oauth-user-lookup-meyS2oB1.mjs +26 -0
- package/dist/oauth-user-lookup-meyS2oB1.mjs.map +1 -0
- package/dist/{options-nPxWnrya.mjs → options-BL4X94qY.mjs} +1 -1
- package/dist/{options-nPxWnrya.mjs.map → options-BL4X94qY.mjs.map} +1 -1
- package/dist/options-Cq64Wx0O.d.mts +207 -0
- package/dist/options-Cq64Wx0O.d.mts.map +1 -0
- package/dist/page/index.d.mts +2 -2
- package/dist/parse-BFTPon-J.mjs +89 -0
- package/dist/parse-BFTPon-J.mjs.map +1 -0
- package/dist/passkey-config-Cg86_ISa.mjs +46 -0
- package/dist/passkey-config-Cg86_ISa.mjs.map +1 -0
- package/dist/{patterns-DsUZ4uxI.mjs → patterns-CqG5Ya3i.mjs} +54 -2
- package/dist/{patterns-DsUZ4uxI.mjs.map → patterns-CqG5Ya3i.mjs.map} +1 -1
- package/dist/{placeholder-CDPtkelt.d.mts → placeholder-D3cFCU9y.d.mts} +2 -1
- package/dist/{placeholder-CDPtkelt.d.mts.map → placeholder-D3cFCU9y.d.mts.map} +1 -1
- package/dist/placeholder-LqmHqvBw.mjs +143 -0
- package/dist/placeholder-LqmHqvBw.mjs.map +1 -0
- package/dist/plugin-types.d.mts +122 -0
- package/dist/plugin-types.d.mts.map +1 -0
- package/dist/plugin-types.mjs +1 -0
- package/dist/plugins/adapt-sandbox-entry.d.mts +20 -12
- package/dist/plugins/adapt-sandbox-entry.d.mts.map +1 -1
- package/dist/plugins/adapt-sandbox-entry.mjs +46 -23
- package/dist/plugins/adapt-sandbox-entry.mjs.map +1 -1
- package/dist/preview-C1LOEbWZ.mjs +107 -0
- package/dist/preview-C1LOEbWZ.mjs.map +1 -0
- package/dist/{public-url-B1AxbbbQ.mjs → public-url-CseXl9Fv.mjs} +39 -2
- package/dist/{public-url-B1AxbbbQ.mjs.map → public-url-CseXl9Fv.mjs.map} +1 -1
- package/dist/{query-yA3-rFji.mjs → query-axZmO6Tn.mjs} +12 -12
- package/dist/{query-yA3-rFji.mjs.map → query-axZmO6Tn.mjs.map} +1 -1
- package/dist/rate-limit-t5CVjCO6.mjs +120 -0
- package/dist/rate-limit-t5CVjCO6.mjs.map +1 -0
- package/dist/redirect-DGRsLO2I.mjs +17 -0
- package/dist/redirect-DGRsLO2I.mjs.map +1 -0
- package/dist/{redirect-C5H7VGIX.mjs → redirect-DkaDxq8e.mjs} +3 -3
- package/dist/{redirect-C5H7VGIX.mjs.map → redirect-DkaDxq8e.mjs.map} +1 -1
- package/dist/redirects-D1fdd68T.mjs +573 -0
- package/dist/redirects-D1fdd68T.mjs.map +1 -0
- package/dist/redirects-Dmj6KRU3.mjs +1141 -0
- package/dist/redirects-Dmj6KRU3.mjs.map +1 -0
- package/dist/{registry-Do34mz_P.mjs → registry-BnCeHYsf.mjs} +8 -300
- package/dist/registry-BnCeHYsf.mjs.map +1 -0
- package/dist/{request-cache-D4I69LeL.mjs → request-cache-dzCt8TZB.mjs} +1 -1
- package/dist/{request-cache-D4I69LeL.mjs.map → request-cache-dzCt8TZB.mjs.map} +1 -1
- package/dist/request-meta-CLCwSQOS.mjs +140 -0
- package/dist/request-meta-CLCwSQOS.mjs.map +1 -0
- package/dist/{runner-Iu3IZSDM.d.mts → runner-DcfZewkO.d.mts} +2 -2
- package/dist/{runner-Iu3IZSDM.d.mts.map → runner-DcfZewkO.d.mts.map} +1 -1
- package/dist/{runner-DIcU2UCC.mjs → runner-DdnQIwz_.mjs} +436 -187
- package/dist/runner-DdnQIwz_.mjs.map +1 -0
- package/dist/runtime.d.mts +10 -6
- package/dist/runtime.d.mts.map +1 -1
- package/dist/runtime.mjs +3 -3
- package/dist/schema-BmqagCwG.mjs +41 -0
- package/dist/schema-BmqagCwG.mjs.map +1 -0
- package/dist/search-CPrvO5u8.mjs +376 -0
- package/dist/search-CPrvO5u8.mjs.map +1 -0
- package/dist/{secrets-CZ8rxLX3.mjs → secrets-6pgZyq0K.mjs} +3 -3
- package/dist/{secrets-CZ8rxLX3.mjs.map → secrets-6pgZyq0K.mjs.map} +1 -1
- package/dist/sections-Cm-zb-gZ.mjs +346 -0
- package/dist/sections-Cm-zb-gZ.mjs.map +1 -0
- package/dist/seed/index.d.mts +2 -2
- package/dist/seed/index.mjs +19 -15
- package/dist/seo/index.d.mts +1 -1
- package/dist/seo-BoR4wCUh.mjs +86 -0
- package/dist/seo-BoR4wCUh.mjs.map +1 -0
- package/dist/seo-DRq9-EPP.mjs +130 -0
- package/dist/seo-DRq9-EPP.mjs.map +1 -0
- package/dist/service-vByySp-2.mjs +195 -0
- package/dist/service-vByySp-2.mjs.map +1 -0
- package/dist/settings-CBBj7HUd.mjs +51 -0
- package/dist/settings-CBBj7HUd.mjs.map +1 -0
- package/dist/settings-xQKsWnzQ.mjs +235 -0
- package/dist/settings-xQKsWnzQ.mjs.map +1 -0
- package/dist/setup-BGAJ2uXs.mjs +137 -0
- package/dist/setup-BGAJ2uXs.mjs.map +1 -0
- package/dist/setup-complete-C6ZCLhKo.mjs +26 -0
- package/dist/setup-complete-C6ZCLhKo.mjs.map +1 -0
- package/dist/setup-nonce-CY1gQiAU.mjs +25 -0
- package/dist/setup-nonce-CY1gQiAU.mjs.map +1 -0
- package/dist/site-url-D-M4Fd8O.mjs +13 -0
- package/dist/site-url-D-M4Fd8O.mjs.map +1 -0
- package/dist/slugify-Cjh1ssOZ.mjs +30 -0
- package/dist/slugify-Cjh1ssOZ.mjs.map +1 -0
- package/dist/ssrf-CTul4uQi.mjs +1 -0
- package/dist/ssrf-DzFN_qV-.mjs +332 -0
- package/dist/ssrf-DzFN_qV-.mjs.map +1 -0
- package/dist/storage/local.d.mts +1 -1
- package/dist/storage/local.mjs +1 -1
- package/dist/storage/s3.d.mts +1 -1
- package/dist/storage/s3.mjs +1 -1
- package/dist/{taxonomies-JmQQZiG1.mjs → taxonomies-Cn9UpaR2.mjs} +7 -7
- package/dist/{taxonomies-JmQQZiG1.mjs.map → taxonomies-Cn9UpaR2.mjs.map} +1 -1
- package/dist/taxonomies-Dc0mzlms.mjs +508 -0
- package/dist/taxonomies-Dc0mzlms.mjs.map +1 -0
- package/dist/{taxonomy-D6NvlKo8.mjs → taxonomy-wPfusMK9.mjs} +3 -3
- package/dist/{taxonomy-D6NvlKo8.mjs.map → taxonomy-wPfusMK9.mjs.map} +1 -1
- package/dist/{tokens-CyRDPVW2.mjs → tokens-DILYNZMi.mjs} +2 -2
- package/dist/{tokens-CyRDPVW2.mjs.map → tokens-DILYNZMi.mjs.map} +1 -1
- package/dist/{transaction-D44LBXvU.mjs → transaction-NQj4VJ7Z.mjs} +1 -1
- package/dist/{transaction-D44LBXvU.mjs.map → transaction-NQj4VJ7Z.mjs.map} +1 -1
- package/dist/{transport-DX_5rpsq.d.mts → transport-GeXlLscf.d.mts} +1 -1
- package/dist/{transport-DX_5rpsq.d.mts.map → transport-GeXlLscf.d.mts.map} +1 -1
- package/dist/{transport-xpzIjCIB.mjs → transport-fw-mKJzT.mjs} +1 -1
- package/dist/{transport-xpzIjCIB.mjs.map → transport-fw-mKJzT.mjs.map} +1 -1
- package/dist/trusted-proxy-CJhQIk65.mjs +51 -0
- package/dist/trusted-proxy-CJhQIk65.mjs.map +1 -0
- package/dist/{types-DgSc9Rpc.d.mts → types-B05e2naf.d.mts} +5 -59
- package/dist/types-B05e2naf.d.mts.map +1 -0
- package/dist/{types-B1gLSAH2.d.mts → types-BWhaSS7U.d.mts} +2 -75
- package/dist/types-BWhaSS7U.d.mts.map +1 -0
- package/dist/{types-BQx6ZXpR.d.mts → types-C1KKK4VP.d.mts} +3 -1
- package/dist/{types-BQx6ZXpR.d.mts.map → types-C1KKK4VP.d.mts.map} +1 -1
- package/dist/types-Cb2UCDJg.d.mts +345 -0
- package/dist/types-Cb2UCDJg.d.mts.map +1 -0
- package/dist/{types-BIgulNsW.mjs → types-CwXMEPRr.mjs} +10 -3
- package/dist/types-CwXMEPRr.mjs.map +1 -0
- package/dist/{types-B_CXXnzh.d.mts → types-CzvJd1ND.d.mts} +7 -1
- package/dist/{types-B_CXXnzh.d.mts.map → types-CzvJd1ND.d.mts.map} +1 -1
- package/dist/types-DFowNO60.d.mts +198 -0
- package/dist/types-DFowNO60.d.mts.map +1 -0
- package/dist/{types-56BKbld_.mjs → types-DSZl1Dsv.mjs} +1 -1
- package/dist/{types-56BKbld_.mjs.map → types-DSZl1Dsv.mjs.map} +1 -1
- package/dist/types-DW1l0gCv.d.mts +75 -0
- package/dist/types-DW1l0gCv.d.mts.map +1 -0
- package/dist/types-Db67HHlU.mjs +3 -0
- package/dist/{types-C-aFbqmA.d.mts → types-DmxPPXGf.d.mts} +1 -1
- package/dist/{types-C-aFbqmA.d.mts.map → types-DmxPPXGf.d.mts.map} +1 -1
- package/dist/{types-PafqtQuM.mjs → types-Dz9CGX_d.mjs} +1 -1
- package/dist/{types-PafqtQuM.mjs.map → types-Dz9CGX_d.mjs.map} +1 -1
- package/dist/user-Dr1bOCqS.mjs +155 -0
- package/dist/user-Dr1bOCqS.mjs.map +1 -0
- package/dist/utils-_F-rWBTN.mjs +286 -0
- package/dist/utils-_F-rWBTN.mjs.map +1 -0
- package/dist/{validate-BcC3m2O7.d.mts → validate-BpQGsmd7.d.mts} +5 -4
- package/dist/validate-BpQGsmd7.d.mts.map +1 -0
- package/dist/{validate-UK4Ja1uo.mjs → validate-DlFxcVVK.mjs} +3 -3
- package/dist/{validate-UK4Ja1uo.mjs.map → validate-DlFxcVVK.mjs.map} +1 -1
- package/dist/{validation-Vc5DQkJa.mjs → validation-BiFJqUp5.mjs} +6 -5
- package/dist/{validation-Vc5DQkJa.mjs.map → validation-BiFJqUp5.mjs.map} +1 -1
- package/dist/version-DNmQakZO.mjs +7 -0
- package/dist/{version-BdP--J1g.mjs.map → version-DNmQakZO.mjs.map} +1 -1
- package/dist/widgets-B9j_yzlk.mjs +106 -0
- package/dist/widgets-B9j_yzlk.mjs.map +1 -0
- package/dist/zod-generator-DSyz01KE.mjs +234 -0
- package/dist/zod-generator-DSyz01KE.mjs.map +1 -0
- package/locals.d.ts +1 -1
- package/package.json +38 -15
- package/src/api/handlers/content.ts +1 -0
- package/src/api/handlers/index.ts +7 -0
- package/src/api/handlers/marketplace.ts +27 -6
- package/src/api/handlers/menus.ts +157 -580
- package/src/api/handlers/plugins.ts +77 -31
- package/src/api/handlers/registry.ts +1083 -0
- package/src/api/openapi/document.ts +10 -4
- package/src/api/schemas/content.ts +1 -0
- package/src/api/schemas/menus.ts +27 -23
- package/src/api/types.ts +6 -0
- package/src/astro/integration/index.ts +1 -0
- package/src/astro/integration/route-naming.ts +19 -0
- package/src/astro/integration/routes.ts +25 -3
- package/src/astro/integration/runtime.ts +35 -8
- package/src/astro/middleware/auth.ts +8 -2
- package/src/astro/middleware/csp.ts +25 -3
- package/src/astro/middleware.ts +3 -0
- package/src/astro/routes/api/admin/plugins/[id]/enable.ts +10 -0
- package/src/astro/routes/api/admin/plugins/registry/install.ts +107 -0
- package/src/astro/routes/api/auth/invite/register-options.ts +8 -1
- package/src/astro/routes/api/import/wordpress/execute.ts +185 -6
- package/src/astro/routes/api/menus/[name]/items/[id].ts +69 -0
- package/src/astro/routes/api/menus/[name]/items.ts +4 -65
- package/src/astro/types.ts +38 -0
- package/src/cli/wxr/parser.ts +263 -0
- package/src/client/index.ts +2 -1
- package/src/database/migrations/036_i18n_menus_and_taxonomies.ts +166 -49
- package/src/database/migrations/038_registry_plugin_state.ts +130 -0
- package/src/database/migrations/039_fix_fts5_triggers.ts +264 -0
- package/src/database/migrations/runner.ts +4 -0
- package/src/database/repositories/content.ts +5 -1
- package/src/database/repositories/index.ts +14 -0
- package/src/database/repositories/menu.ts +644 -0
- package/src/database/repositories/types.ts +6 -0
- package/src/database/types.ts +5 -1
- package/src/emdash-runtime.ts +122 -34
- package/src/import/sources/wordpress-plugin.ts +9 -2
- package/src/import/sources/wxr.ts +16 -2
- package/src/import/ssrf.ts +20 -500
- package/src/import/wxr-taxonomies.ts +730 -0
- package/src/index.ts +3 -10
- package/src/media/normalize.ts +37 -4
- package/src/plugin-types.ts +240 -0
- package/src/plugins/adapt-sandbox-entry.ts +115 -39
- package/src/plugins/define-plugin.ts +34 -56
- package/src/plugins/index.ts +1 -9
- package/src/plugins/marketplace.ts +63 -4
- package/src/plugins/sandbox/index.ts +1 -1
- package/src/plugins/sandbox/noop.ts +2 -2
- package/src/plugins/sandbox/types.ts +7 -4
- package/src/plugins/state.ts +84 -38
- package/src/plugins/types.ts +2 -79
- package/src/registry/config.ts +311 -0
- package/src/registry/plugin-id.ts +116 -0
- package/src/registry/types.ts +206 -0
- package/src/search/fts-manager.ts +77 -15
- package/src/security/ssrf.ts +501 -0
- package/dist/apply-C1ZORgcy.mjs.map +0 -1
- package/dist/content-CERxPUN0.mjs.map +0 -1
- package/dist/error-D6LuHLw9.mjs +0 -27
- package/dist/error-D6LuHLw9.mjs.map +0 -1
- package/dist/index-Dlkzhb4C.d.mts.map +0 -1
- package/dist/placeholder-Ci0RLeCk.mjs +0 -268
- package/dist/placeholder-Ci0RLeCk.mjs.map +0 -1
- package/dist/registry-Do34mz_P.mjs.map +0 -1
- package/dist/runner-DIcU2UCC.mjs.map +0 -1
- package/dist/search-n-ZCMfr3.mjs +0 -9914
- package/dist/search-n-ZCMfr3.mjs.map +0 -1
- package/dist/settings-nTXPRi3D.mjs +0 -440
- package/dist/settings-nTXPRi3D.mjs.map +0 -1
- package/dist/types-B1gLSAH2.d.mts.map +0 -1
- package/dist/types-BIgulNsW.mjs.map +0 -1
- package/dist/types-Cug_RO3W.mjs +0 -16
- package/dist/types-Cug_RO3W.mjs.map +0 -1
- package/dist/types-DgSc9Rpc.d.mts.map +0 -1
- package/dist/validate-BcC3m2O7.d.mts.map +0 -1
- package/dist/version-BdP--J1g.mjs +0 -7
- package/dist/zod-generator-CHnJUP2l.mjs +0 -137
- package/dist/zod-generator-CHnJUP2l.mjs.map +0 -1
|
@@ -0,0 +1,1083 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Registry plugin install handler.
|
|
3
|
+
*
|
|
4
|
+
* Installs a plugin published to the experimental decentralized plugin
|
|
5
|
+
* registry described in RFC 0001. The install flow:
|
|
6
|
+
*
|
|
7
|
+
* 1. Resolve `(handle, slug)` to a publisher DID via the configured
|
|
8
|
+
* aggregator's `resolvePackage` XRPC.
|
|
9
|
+
* 2. Look up the requested release (or the policy-filtered latest one)
|
|
10
|
+
* via `getLatestRelease` / `listReleases`.
|
|
11
|
+
* 3. Reject the install if the aggregator surfaces a `security:yanked`
|
|
12
|
+
* hard-enforcement label or the release is below the configured
|
|
13
|
+
* minimum release age.
|
|
14
|
+
* 4. Fetch the bundle artifact, walking aggregator mirrors first and
|
|
15
|
+
* falling back to the publisher-declared URL.
|
|
16
|
+
* 5. Verify the artifact's multibase checksum against the signed
|
|
17
|
+
* release record's `artifacts.package.checksum`.
|
|
18
|
+
* 6. Extract `manifest.json` + `backend.js` + optional `admin.js` from
|
|
19
|
+
* the gzipped tar bundle.
|
|
20
|
+
* 7. Store the extracted files in site-local R2 under the
|
|
21
|
+
* `registry/<plugin-id>/<version>/` prefix.
|
|
22
|
+
* 8. Write a `plugin_states` row with `source = "registry"` and the
|
|
23
|
+
* `(publisher_did, slug)` pair so updates can be resolved later.
|
|
24
|
+
* 9. Sync the runtime so the plugin becomes active immediately.
|
|
25
|
+
*
|
|
26
|
+
* Known gaps (tracked separately):
|
|
27
|
+
*
|
|
28
|
+
* - The aggregator-supplied records are not yet cryptographically
|
|
29
|
+
* verified against the publisher's MST signature. The signed bytes
|
|
30
|
+
* and CIDs are passed through verbatim per the lexicon, but full
|
|
31
|
+
* PDS-direct verification with proof traversal is follow-up work.
|
|
32
|
+
* The artifact checksum is verified end-to-end against the value
|
|
33
|
+
* in the (aggregator-relayed) release record, which is the actual
|
|
34
|
+
* trust boundary for the bytes that end up in the sandbox.
|
|
35
|
+
* - `acceptLabelers` is forwarded as-is to the aggregator; this
|
|
36
|
+
* handler does not independently re-fetch and verify labels from
|
|
37
|
+
* each labeller's DID. Aggregator label envelope tampering is
|
|
38
|
+
* mitigated by the artifact checksum but not detected.
|
|
39
|
+
*/
|
|
40
|
+
|
|
41
|
+
import type { Did } from "@atcute/lexicons";
|
|
42
|
+
import type { Kysely } from "kysely";
|
|
43
|
+
|
|
44
|
+
import type { Database } from "../../database/types.js";
|
|
45
|
+
import { extractBundle } from "../../plugins/marketplace.js";
|
|
46
|
+
import type { PluginBundle } from "../../plugins/marketplace.js";
|
|
47
|
+
import type { SandboxRunner } from "../../plugins/sandbox/types.js";
|
|
48
|
+
import { PluginStateRepository } from "../../plugins/state.js";
|
|
49
|
+
import {
|
|
50
|
+
canonicalCapabilitiesForDriftCheck,
|
|
51
|
+
coerceRegistryConfig,
|
|
52
|
+
parseDurationSeconds,
|
|
53
|
+
releaseExemptFromMinimumAge,
|
|
54
|
+
validateAggregatorUrl,
|
|
55
|
+
} from "../../registry/config.js";
|
|
56
|
+
import { makeRegistryPluginId } from "../../registry/plugin-id.js";
|
|
57
|
+
import type { RegistryConfigInput } from "../../registry/types.js";
|
|
58
|
+
import { resolveAndValidateExternalUrl, SsrfError } from "../../security/ssrf.js";
|
|
59
|
+
import { EmDashStorageError } from "../../storage/types.js";
|
|
60
|
+
import type { Storage } from "../../storage/types.js";
|
|
61
|
+
import type { ApiResult } from "../types.js";
|
|
62
|
+
import { deleteBundleFromR2, storeBundleInR2 } from "./marketplace.js";
|
|
63
|
+
|
|
64
|
+
// ── Types ──────────────────────────────────────────────────────────
|
|
65
|
+
|
|
66
|
+
export interface RegistryInstallInput {
|
|
67
|
+
/**
|
|
68
|
+
* Publisher DID. Required. The browser is expected to resolve
|
|
69
|
+
* `(handle, slug) → (did, slug)` via the aggregator's
|
|
70
|
+
* `resolvePackage` XRPC before posting -- the server then skips that
|
|
71
|
+
* round-trip and looks up the package directly.
|
|
72
|
+
*
|
|
73
|
+
* Passing DID rather than handle here means installs work for
|
|
74
|
+
* publishers whose handle the aggregator couldn't resolve at view
|
|
75
|
+
* time (handle is "best-effort" per the lexicon -- absent for any
|
|
76
|
+
* publisher whose DID document didn't resolve cleanly at ingest).
|
|
77
|
+
*/
|
|
78
|
+
did: string;
|
|
79
|
+
/** Package slug (rkey of the publisher's profile record). */
|
|
80
|
+
slug: string;
|
|
81
|
+
/** Optional explicit version. When omitted, the aggregator's latest. */
|
|
82
|
+
version?: string;
|
|
83
|
+
/**
|
|
84
|
+
* Capabilities the admin acknowledged in the consent dialog, lifted
|
|
85
|
+
* from the release record's `declaredAccess` block. Compared against
|
|
86
|
+
* the bundle's `manifest.declaredAccess` to detect drift between
|
|
87
|
+
* what the admin agreed to and what the bundle actually requests.
|
|
88
|
+
*
|
|
89
|
+
* When omitted, drift detection is skipped -- callers that don't
|
|
90
|
+
* surface a consent UI before posting (e.g. CI scripts) opt out.
|
|
91
|
+
*/
|
|
92
|
+
acknowledgedDeclaredAccess?: unknown;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export interface RegistryInstallResult {
|
|
96
|
+
/** Hashed, opaque plugin id used everywhere in the runtime. */
|
|
97
|
+
pluginId: string;
|
|
98
|
+
/** Publisher DID resolved from the handle. */
|
|
99
|
+
publisherDid: string;
|
|
100
|
+
/** Publisher slug (== the registry slug). */
|
|
101
|
+
slug: string;
|
|
102
|
+
/** Installed version. */
|
|
103
|
+
version: string;
|
|
104
|
+
/** Capabilities surfaced from the bundle's manifest. */
|
|
105
|
+
capabilities: string[];
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// ── Helpers ────────────────────────────────────────────────────────
|
|
109
|
+
|
|
110
|
+
/** Matches a bare 64-character lowercase/uppercase hex SHA-256 digest. */
|
|
111
|
+
const SHA256_HEX_PATTERN = /^[a-f0-9]{64}$/i;
|
|
112
|
+
|
|
113
|
+
/** Compute the SHA-256 of `bytes` as a lowercase hex string. */
|
|
114
|
+
async function sha256Hex(bytes: Uint8Array): Promise<string> {
|
|
115
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion -- Uint8Array is a valid BufferSource at runtime
|
|
116
|
+
const buf = await crypto.subtle.digest("SHA-256", bytes as unknown as BufferSource);
|
|
117
|
+
const arr = new Uint8Array(buf);
|
|
118
|
+
return Array.from(arr, (b) => b.toString(16).padStart(2, "0")).join("");
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/** multihash code for sha2-256 (single-byte varint). */
|
|
122
|
+
const MULTIHASH_SHA256_CODE = 0x12;
|
|
123
|
+
/** sha2-256 digest length in bytes (single-byte varint). */
|
|
124
|
+
const MULTIHASH_SHA256_LENGTH = 0x20;
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Compute the multibase-multihash sha2-256 checksum of `bytes`, in the
|
|
128
|
+
* same `b<base32>` shape the registry CLI publishes
|
|
129
|
+
* (`packages/plugin-cli/src/multihash.ts`). Returns a 56-character
|
|
130
|
+
* string starting with `b`.
|
|
131
|
+
*
|
|
132
|
+
* The trust contract is: if both sides produce the same string for
|
|
133
|
+
* the same bytes, the bytes are unchanged. We don't decode the
|
|
134
|
+
* publisher-supplied checksum -- we just re-encode our own and compare,
|
|
135
|
+
* which is equivalent and avoids needing a base32 decoder.
|
|
136
|
+
*/
|
|
137
|
+
async function sha256MultibaseMultihash(bytes: Uint8Array): Promise<string> {
|
|
138
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion -- Uint8Array is a valid BufferSource at runtime
|
|
139
|
+
const digestBuf = await crypto.subtle.digest("SHA-256", bytes as unknown as BufferSource);
|
|
140
|
+
const digest = new Uint8Array(digestBuf);
|
|
141
|
+
const multihash = new Uint8Array(2 + digest.length);
|
|
142
|
+
multihash[0] = MULTIHASH_SHA256_CODE;
|
|
143
|
+
multihash[1] = MULTIHASH_SHA256_LENGTH;
|
|
144
|
+
multihash.set(digest, 2);
|
|
145
|
+
const { toBase32 } = await import("@atcute/multibase");
|
|
146
|
+
return `b${toBase32(multihash)}`;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Verify that a checksum string from a release record's
|
|
151
|
+
* `artifact.checksum` field corresponds to the SHA-256 of the given
|
|
152
|
+
* bytes.
|
|
153
|
+
*
|
|
154
|
+
* Accepts two formats:
|
|
155
|
+
*
|
|
156
|
+
* - Bare lowercase/uppercase hex SHA-256 (64 chars). Convenience for
|
|
157
|
+
* publishers / tools that emit hex rather than multibase.
|
|
158
|
+
* - Multibase-multihash with the `b` (base32) prefix and sha2-256.
|
|
159
|
+
* This is the format RFC 0001 mandates and the registry CLI emits
|
|
160
|
+
* (see `packages/plugin-cli/src/multihash.ts`).
|
|
161
|
+
*
|
|
162
|
+
* Hash functions other than sha2-256 are out of scope for this
|
|
163
|
+
* initial release; the install fails closed.
|
|
164
|
+
*/
|
|
165
|
+
async function verifyChecksum(bytes: Uint8Array, checksum: string): Promise<boolean> {
|
|
166
|
+
if (SHA256_HEX_PATTERN.test(checksum)) {
|
|
167
|
+
const actual = await sha256Hex(bytes);
|
|
168
|
+
return checksum.toLowerCase() === actual;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// Multibase-base32 multihash with sha2-256. We re-encode our own
|
|
172
|
+
// digest in the same shape and compare strings -- equivalent to
|
|
173
|
+
// decoding and comparing bytes, but doesn't need a base32 decoder.
|
|
174
|
+
// 56 chars = 'b' + base32(34 bytes) = 'b' + 55 chars.
|
|
175
|
+
if (checksum.length === 56 && checksum.startsWith("b")) {
|
|
176
|
+
const actual = await sha256MultibaseMultihash(bytes);
|
|
177
|
+
// Case-insensitive: multibase 'b' is lowercase by convention but
|
|
178
|
+
// some emitters use uppercase. RFC 4648 base32 alphabets are
|
|
179
|
+
// case-insensitive.
|
|
180
|
+
return actual.toLowerCase() === checksum.toLowerCase();
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
return false;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Bytes-per-artifact cap on the gzipped tarball we'll download before
|
|
188
|
+
* decompression. RFC 0001 caps a sandboxed plugin bundle at 256 KiB
|
|
189
|
+
* decompressed (see `MAX_BUNDLE_SIZE` in cli/commands/bundle-utils.ts);
|
|
190
|
+
* gzip on a mix of JSON manifest + JS code typically gives 0.3-0.6
|
|
191
|
+
* ratio, so compressed bundles are well under 200 KiB in practice.
|
|
192
|
+
* 512 KiB leaves margin for unusual file mixes that compress poorly
|
|
193
|
+
* while still rejecting anything that's obviously not a legitimate
|
|
194
|
+
* plugin bundle.
|
|
195
|
+
*/
|
|
196
|
+
const MAX_ARTIFACT_BYTES = 512 * 1024;
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* Maximum number of HTTP redirects followed during artifact download.
|
|
200
|
+
* Each hop is independently URL-validated, so a malicious server cannot
|
|
201
|
+
* redirect through a series of allowed-looking origins to reach a
|
|
202
|
+
* forbidden one.
|
|
203
|
+
*/
|
|
204
|
+
const MAX_REDIRECTS = 5;
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Wall-clock cap on any single artifact fetch attempt (per URL).
|
|
208
|
+
* Defends against slow-loris mirrors that accept the connection but
|
|
209
|
+
* never finish sending headers or body.
|
|
210
|
+
*/
|
|
211
|
+
const ARTIFACT_FETCH_TIMEOUT_MS = 15_000;
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* Total wall-clock budget for the artifact-download phase across all
|
|
215
|
+
* mirrors and the declared URL. Even with the per-URL timeout, a
|
|
216
|
+
* malicious mirror list could otherwise tie up the install request for
|
|
217
|
+
* minutes; this caps total time at a budget interactive admins can
|
|
218
|
+
* tolerate. Tuned so a fast happy path takes <1s of budget per
|
|
219
|
+
* attempt and a worst case still completes in under a minute.
|
|
220
|
+
*/
|
|
221
|
+
const ARTIFACT_TOTAL_BUDGET_MS = 45_000;
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* Cap on the number of mirror URLs we try before falling back to the
|
|
225
|
+
* publisher-declared URL. Matches the aggregator lexicon's
|
|
226
|
+
* `mirrors` array length cap (16) but enforced here independently so
|
|
227
|
+
* a misbehaving aggregator can't slow-loris us through hundreds of
|
|
228
|
+
* URLs.
|
|
229
|
+
*/
|
|
230
|
+
const MAX_MIRRORS = 16;
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* Per-request timeout applied to every aggregator XRPC call
|
|
234
|
+
* (`resolvePackage`, `getLatestRelease`, `listReleases`). Matches the
|
|
235
|
+
* per-URL artifact-fetch cap. Without this, a slow-loris aggregator
|
|
236
|
+
* can stall the install before the artifact phase even starts.
|
|
237
|
+
*/
|
|
238
|
+
const AGGREGATOR_REQUEST_TIMEOUT_MS = 15_000;
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* Total wall-clock budget for the aggregator-discovery phase
|
|
242
|
+
* (resolve + selected-release lookup). Mirrors the artifact-download
|
|
243
|
+
* budget. Worst case with the pinned-version path's 20-page cap is
|
|
244
|
+
* 20 + 1 calls; capping the total ensures any one stalled call
|
|
245
|
+
* still bounds the whole phase.
|
|
246
|
+
*/
|
|
247
|
+
const AGGREGATOR_TOTAL_BUDGET_MS = 30_000;
|
|
248
|
+
|
|
249
|
+
/** Build a fetch function that enforces a per-request and per-budget timeout. */
|
|
250
|
+
function timedFetch(totalDeadline: number): typeof fetch {
|
|
251
|
+
return (input: Parameters<typeof fetch>[0], init?: Parameters<typeof fetch>[1]) => {
|
|
252
|
+
const now = Date.now();
|
|
253
|
+
const remaining = Math.max(0, totalDeadline - now);
|
|
254
|
+
if (remaining === 0) {
|
|
255
|
+
return Promise.reject(new Error("Aggregator request budget exhausted"));
|
|
256
|
+
}
|
|
257
|
+
const timeout = Math.min(AGGREGATOR_REQUEST_TIMEOUT_MS, remaining);
|
|
258
|
+
const controller = new AbortController();
|
|
259
|
+
const timer = setTimeout(() => controller.abort(), timeout);
|
|
260
|
+
const callerSignal = init?.signal;
|
|
261
|
+
if (callerSignal) {
|
|
262
|
+
if (callerSignal.aborted) controller.abort(callerSignal.reason);
|
|
263
|
+
else callerSignal.addEventListener("abort", () => controller.abort(callerSignal.reason));
|
|
264
|
+
}
|
|
265
|
+
return fetch(input, { ...init, signal: controller.signal }).finally(() => {
|
|
266
|
+
clearTimeout(timer);
|
|
267
|
+
});
|
|
268
|
+
};
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
/**
|
|
272
|
+
* Localhost-equivalent hostnames the artifact fetcher rejects in
|
|
273
|
+
* production. The full literal-IP / DNS-rebinding blocklist lives in
|
|
274
|
+
* `#security/ssrf.js` and is invoked via `resolveAndValidateExternalUrl`
|
|
275
|
+
* below; this small set exists only because the artifact handler has
|
|
276
|
+
* a dev-mode escape hatch that lets `http://localhost` through.
|
|
277
|
+
*/
|
|
278
|
+
const FORBIDDEN_HOSTNAMES = new Set([
|
|
279
|
+
"localhost",
|
|
280
|
+
"localhost.localdomain",
|
|
281
|
+
"ip6-localhost",
|
|
282
|
+
"ip6-loopback",
|
|
283
|
+
]);
|
|
284
|
+
|
|
285
|
+
/** Trailing dot on a hostname, stripped before URL host comparisons. */
|
|
286
|
+
const TRAILING_DOT = /\.$/;
|
|
287
|
+
|
|
288
|
+
/** Hostnames that resolve to the local machine; rejected outright in production. */
|
|
289
|
+
function isLocalhostHostname(hostname: string): boolean {
|
|
290
|
+
// WHATWG URL preserves brackets on IPv6 hostnames; strip them before
|
|
291
|
+
// comparison so `[::1]` is recognised as localhost.
|
|
292
|
+
const stripped = hostname.toLowerCase().replace(TRAILING_DOT, "");
|
|
293
|
+
const h = stripped.startsWith("[") && stripped.endsWith("]") ? stripped.slice(1, -1) : stripped;
|
|
294
|
+
if (FORBIDDEN_HOSTNAMES.has(h)) return true;
|
|
295
|
+
if (h === "localhost") return true;
|
|
296
|
+
if (h.endsWith(".localhost")) return true;
|
|
297
|
+
if (h === "127.0.0.1" || h === "::1") return true;
|
|
298
|
+
if (h.startsWith("::ffff:127.") || h.startsWith("::ffff:7f00:")) return true;
|
|
299
|
+
return false;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
/**
|
|
303
|
+
* Validate that `urlString` is a safe outbound target for artifact
|
|
304
|
+
* downloads. Rejects non-HTTPS (except localhost in dev), embedded
|
|
305
|
+
* credentials, any host that's a loopback / private / link-local
|
|
306
|
+
* literal address, and any hostname whose resolved A or AAAA records
|
|
307
|
+
* point at one of those addresses (closes the DNS-rebinding gap).
|
|
308
|
+
*
|
|
309
|
+
* Wraps `resolveAndValidateExternalUrl` from the import-pipeline SSRF
|
|
310
|
+
* module so both code paths share one DoH cache, one resolver, one
|
|
311
|
+
* blocklist, and one set of regression tests. Layers an
|
|
312
|
+
* artifact-specific protocol/dev-localhost policy on top.
|
|
313
|
+
*
|
|
314
|
+
* `import.meta.env.DEV` is a Vite/Astro compile-time constant, so
|
|
315
|
+
* production bundles cannot enable the dev escape hatch at runtime.
|
|
316
|
+
*/
|
|
317
|
+
async function assertSafeArtifactUrl(urlString: string): Promise<URL> {
|
|
318
|
+
let url: URL;
|
|
319
|
+
try {
|
|
320
|
+
url = new URL(urlString);
|
|
321
|
+
} catch {
|
|
322
|
+
throw new Error(`Invalid artifact URL: ${urlString}`);
|
|
323
|
+
}
|
|
324
|
+
if (url.protocol !== "https:" && url.protocol !== "http:") {
|
|
325
|
+
throw new Error(`Artifact URL protocol not allowed: ${url.protocol}`);
|
|
326
|
+
}
|
|
327
|
+
if (url.username || url.password) {
|
|
328
|
+
throw new Error("Artifact URL must not contain embedded credentials");
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
const rawHostname = url.hostname.toLowerCase().replace(TRAILING_DOT, "");
|
|
332
|
+
// Strip brackets so the IPv4/IPv6 checks see the canonical form.
|
|
333
|
+
const hostname =
|
|
334
|
+
rawHostname.startsWith("[") && rawHostname.endsWith("]")
|
|
335
|
+
? rawHostname.slice(1, -1)
|
|
336
|
+
: rawHostname;
|
|
337
|
+
const localhost = isLocalhostHostname(hostname);
|
|
338
|
+
|
|
339
|
+
// In production: reject HTTP entirely and reject localhost over any
|
|
340
|
+
// protocol -- a publisher pointing at `https://localhost` is still
|
|
341
|
+
// trying to bounce the server through its own loopback interface.
|
|
342
|
+
if (!import.meta.env.DEV) {
|
|
343
|
+
if (url.protocol === "http:") {
|
|
344
|
+
throw new Error("Artifact URL must use https");
|
|
345
|
+
}
|
|
346
|
+
if (localhost) {
|
|
347
|
+
throw new Error(`Artifact URL points to localhost: ${hostname}`);
|
|
348
|
+
}
|
|
349
|
+
} else if (url.protocol === "http:" && !localhost) {
|
|
350
|
+
// Dev mode: http allowed only for localhost.
|
|
351
|
+
throw new Error("Artifact URL must use https (http allowed only for localhost in dev)");
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
if (localhost) {
|
|
355
|
+
// Dev-only path; nothing to resolve.
|
|
356
|
+
return url;
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
// Delegate IP-literal + DNS-rebinding validation to the import
|
|
360
|
+
// pipeline's SSRF helper. Adapts the SsrfError to the existing
|
|
361
|
+
// artifact-URL error vocabulary so callers keep their current
|
|
362
|
+
// catch shape.
|
|
363
|
+
try {
|
|
364
|
+
return await resolveAndValidateExternalUrl(url.href);
|
|
365
|
+
} catch (err) {
|
|
366
|
+
if (err instanceof SsrfError) {
|
|
367
|
+
throw new Error(`Artifact URL rejected: ${err.message}`);
|
|
368
|
+
}
|
|
369
|
+
throw err;
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
/**
|
|
374
|
+
* Fetch one URL with manual redirect handling so every hop is
|
|
375
|
+
* URL-validated, a hard byte cap so a malicious response body cannot
|
|
376
|
+
* exhaust memory before the checksum check rejects it, and a wall-clock
|
|
377
|
+
* timeout that covers connect, headers, and body together. The timeout
|
|
378
|
+
* is the minimum of the per-URL cap and the remaining total budget so
|
|
379
|
+
* a late-arriving mirror still respects the install's global budget.
|
|
380
|
+
*/
|
|
381
|
+
async function fetchWithLimits(initialUrl: string, totalDeadline: number): Promise<Uint8Array> {
|
|
382
|
+
const now = Date.now();
|
|
383
|
+
const remaining = Math.max(0, totalDeadline - now);
|
|
384
|
+
if (remaining === 0) {
|
|
385
|
+
throw new Error("Artifact download budget exhausted");
|
|
386
|
+
}
|
|
387
|
+
const perUrlTimeout = Math.min(ARTIFACT_FETCH_TIMEOUT_MS, remaining);
|
|
388
|
+
const controller = new AbortController();
|
|
389
|
+
const timer = setTimeout(() => controller.abort(), perUrlTimeout);
|
|
390
|
+
try {
|
|
391
|
+
let current = await assertSafeArtifactUrl(initialUrl);
|
|
392
|
+
let response: Response;
|
|
393
|
+
for (let hop = 0; hop <= MAX_REDIRECTS; hop++) {
|
|
394
|
+
response = await fetch(current.href, { redirect: "manual", signal: controller.signal });
|
|
395
|
+
if (response.status < 300 || response.status >= 400) break;
|
|
396
|
+
const location = response.headers.get("location");
|
|
397
|
+
if (!location) break;
|
|
398
|
+
if (hop === MAX_REDIRECTS) {
|
|
399
|
+
throw new Error(`Too many redirects fetching artifact (>${MAX_REDIRECTS})`);
|
|
400
|
+
}
|
|
401
|
+
const next = new URL(location, current);
|
|
402
|
+
current = await assertSafeArtifactUrl(next.href);
|
|
403
|
+
}
|
|
404
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- response is assigned in the first loop iteration
|
|
405
|
+
const finalResponse = response!;
|
|
406
|
+
if (!finalResponse.ok) {
|
|
407
|
+
throw new Error(`HTTP ${finalResponse.status}`);
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
// Check Content-Length up front when present. Untrusted servers can
|
|
411
|
+
// lie or omit it; the streaming cap below is the real defense.
|
|
412
|
+
const lengthHeader = finalResponse.headers.get("content-length");
|
|
413
|
+
if (lengthHeader) {
|
|
414
|
+
const declared = Number(lengthHeader);
|
|
415
|
+
if (Number.isFinite(declared) && declared > MAX_ARTIFACT_BYTES) {
|
|
416
|
+
throw new Error(
|
|
417
|
+
`Artifact too large (declared ${declared} bytes, limit ${MAX_ARTIFACT_BYTES})`,
|
|
418
|
+
);
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
const body = finalResponse.body;
|
|
423
|
+
if (!body) {
|
|
424
|
+
// Workers can't return a null body for a normal GET; defensive fallback.
|
|
425
|
+
const buf = new Uint8Array(await finalResponse.arrayBuffer());
|
|
426
|
+
if (buf.byteLength > MAX_ARTIFACT_BYTES) {
|
|
427
|
+
throw new Error(`Artifact too large (limit ${MAX_ARTIFACT_BYTES} bytes)`);
|
|
428
|
+
}
|
|
429
|
+
return buf;
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
const reader = body.getReader();
|
|
433
|
+
const chunks: Uint8Array[] = [];
|
|
434
|
+
let total = 0;
|
|
435
|
+
while (true) {
|
|
436
|
+
const { done, value } = await reader.read();
|
|
437
|
+
if (done) break;
|
|
438
|
+
if (!value) continue;
|
|
439
|
+
total += value.byteLength;
|
|
440
|
+
if (total > MAX_ARTIFACT_BYTES) {
|
|
441
|
+
try {
|
|
442
|
+
await reader.cancel();
|
|
443
|
+
} catch {
|
|
444
|
+
// nothing to do
|
|
445
|
+
}
|
|
446
|
+
throw new Error(`Artifact too large (limit ${MAX_ARTIFACT_BYTES} bytes)`);
|
|
447
|
+
}
|
|
448
|
+
chunks.push(value);
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
const out = new Uint8Array(total);
|
|
452
|
+
let offset = 0;
|
|
453
|
+
for (const chunk of chunks) {
|
|
454
|
+
out.set(chunk, offset);
|
|
455
|
+
offset += chunk.byteLength;
|
|
456
|
+
}
|
|
457
|
+
return out;
|
|
458
|
+
} finally {
|
|
459
|
+
clearTimeout(timer);
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
/**
|
|
464
|
+
* Strip query string and fragment from a URL for use in
|
|
465
|
+
* client-visible error messages. Registry artifacts are often hosted
|
|
466
|
+
* on storage backends that include presigned tokens in the query
|
|
467
|
+
* string; surfacing the raw URL on a failed install leaks those
|
|
468
|
+
* tokens into the admin's HTTP response and any log drain that
|
|
469
|
+
* captures the error chain. Origin + pathname is enough to identify
|
|
470
|
+
* the host and resource without exposing credentials.
|
|
471
|
+
*
|
|
472
|
+
* Falls back to a generic placeholder when the URL is malformed.
|
|
473
|
+
*/
|
|
474
|
+
function redactUrlForError(raw: string): string {
|
|
475
|
+
try {
|
|
476
|
+
const u = new URL(raw);
|
|
477
|
+
return `${u.origin}${u.pathname}`;
|
|
478
|
+
} catch {
|
|
479
|
+
return "<malformed url>";
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
/** Walk artifact source URLs in priority order and return the first that fetches successfully. */
|
|
484
|
+
async function fetchArtifact(mirrors: string[], declaredUrl: string): Promise<Uint8Array> {
|
|
485
|
+
// Clamp mirrors regardless of what the lexicon type says -- a buggy
|
|
486
|
+
// or malicious aggregator could return more than the spec'd limit
|
|
487
|
+
// and slow-loris each one. The declared URL is always tried last.
|
|
488
|
+
const clampedMirrors = mirrors.slice(0, MAX_MIRRORS);
|
|
489
|
+
const urls = [...clampedMirrors, declaredUrl];
|
|
490
|
+
// Client-visible errors carry redacted URLs (origin + path only).
|
|
491
|
+
// The full URL with any query-string token is logged server-side
|
|
492
|
+
// so operators can still debug delivery failures.
|
|
493
|
+
const clientErrors: string[] = [];
|
|
494
|
+
|
|
495
|
+
const totalDeadline = Date.now() + ARTIFACT_TOTAL_BUDGET_MS;
|
|
496
|
+
|
|
497
|
+
for (const url of urls) {
|
|
498
|
+
if (Date.now() >= totalDeadline) {
|
|
499
|
+
clientErrors.push("(total artifact download budget exhausted)");
|
|
500
|
+
break;
|
|
501
|
+
}
|
|
502
|
+
try {
|
|
503
|
+
return await fetchWithLimits(url, totalDeadline);
|
|
504
|
+
} catch (err) {
|
|
505
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
506
|
+
console.warn(`[registry-install] Artifact fetch failed from ${url}:`, message);
|
|
507
|
+
clientErrors.push(`${redactUrlForError(url)}: ${message}`);
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
throw new Error(
|
|
512
|
+
`Failed to download artifact from any source. Tried:\n ${clientErrors.join("\n ")}`,
|
|
513
|
+
);
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
// ── Install ────────────────────────────────────────────────────────
|
|
517
|
+
|
|
518
|
+
export async function handleRegistryInstall(
|
|
519
|
+
db: Kysely<Database>,
|
|
520
|
+
storage: Storage | null,
|
|
521
|
+
sandboxRunner: SandboxRunner | null,
|
|
522
|
+
registryConfigInput: RegistryConfigInput | undefined,
|
|
523
|
+
input: RegistryInstallInput,
|
|
524
|
+
opts?: { configuredPluginIds?: Set<string> },
|
|
525
|
+
): Promise<ApiResult<RegistryInstallResult>> {
|
|
526
|
+
// Accept either the bare-string shorthand or the full
|
|
527
|
+
// `RegistryConfig` object (see `RegistryConfigInput`).
|
|
528
|
+
const registryConfig = coerceRegistryConfig(registryConfigInput);
|
|
529
|
+
if (!registryConfig) {
|
|
530
|
+
return {
|
|
531
|
+
success: false,
|
|
532
|
+
error: {
|
|
533
|
+
code: "REGISTRY_NOT_CONFIGURED",
|
|
534
|
+
message: "Registry is not configured",
|
|
535
|
+
},
|
|
536
|
+
};
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
if (!storage) {
|
|
540
|
+
return {
|
|
541
|
+
success: false,
|
|
542
|
+
error: {
|
|
543
|
+
code: "STORAGE_NOT_CONFIGURED",
|
|
544
|
+
message: "Storage is required for registry plugin installation",
|
|
545
|
+
},
|
|
546
|
+
};
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
if (!sandboxRunner || !sandboxRunner.isAvailable()) {
|
|
550
|
+
return {
|
|
551
|
+
success: false,
|
|
552
|
+
error: {
|
|
553
|
+
code: "SANDBOX_NOT_AVAILABLE",
|
|
554
|
+
message: "Sandbox runner is required for registry plugins",
|
|
555
|
+
},
|
|
556
|
+
};
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
// Defense in depth: validate the aggregator URL even though the same
|
|
560
|
+
// check runs at config-normalize time. Keeps every entrypoint into
|
|
561
|
+
// `handleRegistryInstall` safe regardless of how the caller obtained
|
|
562
|
+
// the config.
|
|
563
|
+
try {
|
|
564
|
+
validateAggregatorUrl(registryConfig.aggregatorUrl);
|
|
565
|
+
} catch (err) {
|
|
566
|
+
return {
|
|
567
|
+
success: false,
|
|
568
|
+
error: {
|
|
569
|
+
code: "REGISTRY_NOT_CONFIGURED",
|
|
570
|
+
message: err instanceof Error ? err.message : "Invalid aggregator URL",
|
|
571
|
+
},
|
|
572
|
+
};
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
const { did, slug, version: requestedVersion } = input;
|
|
576
|
+
|
|
577
|
+
// Lazy-load the discovery client. Avoids pulling @atcute/client into
|
|
578
|
+
// every code path that imports core/api/handlers.
|
|
579
|
+
const { DiscoveryClient } = await import("@emdash-cms/registry-client/discovery");
|
|
580
|
+
|
|
581
|
+
// Every aggregator XRPC call passes through `timedFetch`, which
|
|
582
|
+
// enforces a per-request timeout and shares a single total-budget
|
|
583
|
+
// deadline. Defends against a slow-loris aggregator stalling the
|
|
584
|
+
// install before the artifact phase begins.
|
|
585
|
+
const aggregatorDeadline = Date.now() + AGGREGATOR_TOTAL_BUDGET_MS;
|
|
586
|
+
const discovery = new DiscoveryClient({
|
|
587
|
+
aggregatorUrl: registryConfig.aggregatorUrl,
|
|
588
|
+
acceptLabelers: registryConfig.acceptLabelers,
|
|
589
|
+
fetch: timedFetch(aggregatorDeadline),
|
|
590
|
+
});
|
|
591
|
+
|
|
592
|
+
// Basic shape check on the DID. The browser is expected to send a
|
|
593
|
+
// DID resolved via the aggregator's `resolvePackage`; reject obvious
|
|
594
|
+
// malformations here rather than letting the XRPC call fail
|
|
595
|
+
// opaquely. The lexicon's `did:${string}:${string}` template is the
|
|
596
|
+
// authoritative check.
|
|
597
|
+
if (!did.startsWith("did:") || did.split(":").length < 3) {
|
|
598
|
+
return {
|
|
599
|
+
success: false,
|
|
600
|
+
error: {
|
|
601
|
+
code: "INVALID_DID",
|
|
602
|
+
message: "DID must be a valid atproto DID (e.g. did:plc:abc123)",
|
|
603
|
+
},
|
|
604
|
+
};
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
try {
|
|
608
|
+
// Step 1: look up the package by DID + slug. The browser already
|
|
609
|
+
// resolved any handle to a DID via `resolvePackage`; we skip that
|
|
610
|
+
// round-trip and go straight to `getPackage`.
|
|
611
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion -- validated above
|
|
612
|
+
const publisherDid = did as Did;
|
|
613
|
+
const packageView = await discovery.getPackage({
|
|
614
|
+
did: publisherDid,
|
|
615
|
+
slug,
|
|
616
|
+
});
|
|
617
|
+
|
|
618
|
+
// Step 2: select the target release.
|
|
619
|
+
// For an explicit version, page through listReleases until we find
|
|
620
|
+
// the matching record; the aggregator returns releases ordered by
|
|
621
|
+
// semver descending. For "latest", use the dedicated convenience
|
|
622
|
+
// endpoint which applies the aggregator's policy filter (yanked
|
|
623
|
+
// exclusion etc.) server-side.
|
|
624
|
+
//
|
|
625
|
+
// Pagination is bounded both by total pages and by repeated-cursor
|
|
626
|
+
// detection: a buggy or compromised aggregator could otherwise
|
|
627
|
+
// return endless distinct cursors that never include the
|
|
628
|
+
// requested version, hanging the install for the platform's
|
|
629
|
+
// request-time budget.
|
|
630
|
+
const MAX_LIST_PAGES = 20; // 20 * 50 limit = 1000 releases worth
|
|
631
|
+
const latestRelease = await (async () => {
|
|
632
|
+
if (!requestedVersion) {
|
|
633
|
+
return discovery.getLatestRelease({
|
|
634
|
+
did: publisherDid,
|
|
635
|
+
package: slug,
|
|
636
|
+
});
|
|
637
|
+
}
|
|
638
|
+
let cursor: string | undefined;
|
|
639
|
+
const seenCursors = new Set<string>();
|
|
640
|
+
for (let page = 0; page < MAX_LIST_PAGES; page++) {
|
|
641
|
+
if (cursor !== undefined) {
|
|
642
|
+
if (seenCursors.has(cursor)) break;
|
|
643
|
+
seenCursors.add(cursor);
|
|
644
|
+
}
|
|
645
|
+
const result = await discovery.listReleases({
|
|
646
|
+
did: publisherDid,
|
|
647
|
+
package: slug,
|
|
648
|
+
cursor,
|
|
649
|
+
limit: 50,
|
|
650
|
+
});
|
|
651
|
+
for (const r of result.releases) {
|
|
652
|
+
if (r.version === requestedVersion) return r;
|
|
653
|
+
}
|
|
654
|
+
if (!result.cursor) break;
|
|
655
|
+
cursor = result.cursor;
|
|
656
|
+
}
|
|
657
|
+
return undefined;
|
|
658
|
+
})();
|
|
659
|
+
const releaseView = latestRelease;
|
|
660
|
+
|
|
661
|
+
if (!releaseView) {
|
|
662
|
+
return {
|
|
663
|
+
success: false,
|
|
664
|
+
error: {
|
|
665
|
+
code: "NO_RELEASE",
|
|
666
|
+
message: requestedVersion
|
|
667
|
+
? `Version ${requestedVersion} not found for ${publisherDid}/${slug}`
|
|
668
|
+
: `No installable release found for ${publisherDid}/${slug}`,
|
|
669
|
+
},
|
|
670
|
+
};
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
// Identity cross-check on every field the aggregator denormalises
|
|
674
|
+
// onto the package and release views. A buggy or compromised
|
|
675
|
+
// aggregator could otherwise return a release view for a
|
|
676
|
+
// different `(did, slug, version)` than we asked for; the
|
|
677
|
+
// handler would then fetch + checksum-verify + install bytes
|
|
678
|
+
// under the requested package's pluginId but for a different
|
|
679
|
+
// publisher's record. Checksum verification only proves the bytes
|
|
680
|
+
// match the *returned* record, not that the record belongs to
|
|
681
|
+
// the package we requested.
|
|
682
|
+
// `releaseView.release` is validated against the release lexicon by
|
|
683
|
+
// DiscoveryClient (or `null` if it didn't conform). A `null` here makes
|
|
684
|
+
// the identity checks below fail closed, which is the desired outcome.
|
|
685
|
+
const signedRelease = releaseView.release;
|
|
686
|
+
if (packageView.did !== publisherDid || packageView.slug !== slug) {
|
|
687
|
+
return {
|
|
688
|
+
success: false,
|
|
689
|
+
error: {
|
|
690
|
+
code: "AGGREGATOR_IDENTITY_MISMATCH",
|
|
691
|
+
message: "Aggregator returned a package view for a different publisher or slug.",
|
|
692
|
+
},
|
|
693
|
+
};
|
|
694
|
+
}
|
|
695
|
+
if (
|
|
696
|
+
releaseView.did !== publisherDid ||
|
|
697
|
+
releaseView.package !== slug ||
|
|
698
|
+
signedRelease?.package !== slug ||
|
|
699
|
+
(requestedVersion !== undefined && releaseView.version !== requestedVersion) ||
|
|
700
|
+
signedRelease?.version !== releaseView.version
|
|
701
|
+
) {
|
|
702
|
+
return {
|
|
703
|
+
success: false,
|
|
704
|
+
error: {
|
|
705
|
+
code: "AGGREGATOR_IDENTITY_MISMATCH",
|
|
706
|
+
message:
|
|
707
|
+
"Aggregator returned a release view that does not match the requested package or version.",
|
|
708
|
+
},
|
|
709
|
+
};
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
const version = releaseView.version;
|
|
713
|
+
|
|
714
|
+
// Step 3: takedown label check (hard-enforced via aggregator's
|
|
715
|
+
// `atproto-accept-labelers` filtering, but we belt-and-suspenders
|
|
716
|
+
// the package-level labels too).
|
|
717
|
+
const yanked = (packageView.labels ?? []).some(
|
|
718
|
+
(l: { val?: string }) => l.val === "security:yanked",
|
|
719
|
+
);
|
|
720
|
+
const releaseYanked = (releaseView.labels ?? []).some(
|
|
721
|
+
(l: { val?: string }) => l.val === "security:yanked",
|
|
722
|
+
);
|
|
723
|
+
if (yanked || releaseYanked) {
|
|
724
|
+
return {
|
|
725
|
+
success: false,
|
|
726
|
+
error: {
|
|
727
|
+
code: "RELEASE_YANKED",
|
|
728
|
+
message: "This release has been withdrawn (security:yanked label).",
|
|
729
|
+
},
|
|
730
|
+
};
|
|
731
|
+
}
|
|
732
|
+
|
|
733
|
+
// Step 3a: enforce the configured minimum release age. The browser
|
|
734
|
+
// applies the same check up front for UX, but the gate lives here
|
|
735
|
+
// -- a stale browser tab, a deep link, or a non-admin-UI caller
|
|
736
|
+
// must still hit the holdback. The `minimumReleaseAgeExclude`
|
|
737
|
+
// allowlist short-circuits the check for trusted publisher DIDs.
|
|
738
|
+
//
|
|
739
|
+
// Caveat: `releaseView.indexedAt` is aggregator-supplied envelope
|
|
740
|
+
// data, not a signed timestamp. A compromised aggregator can
|
|
741
|
+
// claim an arbitrary indexed-at date and bypass the holdback;
|
|
742
|
+
// closing this gap requires fetching the release record's
|
|
743
|
+
// signed createdAt from the publisher's PDS (deferred to the
|
|
744
|
+
// follow-up that adds full MST verification). If the timestamp
|
|
745
|
+
// is missing or malformed, we fail closed and reject the install.
|
|
746
|
+
// `registryConfig` is the user-supplied integration option, not
|
|
747
|
+
// the normalized manifest shape, so the duration parse runs once
|
|
748
|
+
// per install. Catch a malformed value here -- normally caught at
|
|
749
|
+
// `normalizeRegistryConfig` time, but a future config-mutation
|
|
750
|
+
// path could re-enter with a bad value -- and surface it as a
|
|
751
|
+
// structured error rather than letting it bubble out as a generic
|
|
752
|
+
// 500.
|
|
753
|
+
const minimumReleaseAge = registryConfig.policy?.minimumReleaseAge;
|
|
754
|
+
let minimumReleaseAgeSeconds = 0;
|
|
755
|
+
if (minimumReleaseAge !== undefined) {
|
|
756
|
+
try {
|
|
757
|
+
minimumReleaseAgeSeconds = parseDurationSeconds(minimumReleaseAge);
|
|
758
|
+
} catch (err) {
|
|
759
|
+
return {
|
|
760
|
+
success: false,
|
|
761
|
+
error: {
|
|
762
|
+
code: "REGISTRY_POLICY_INVALID",
|
|
763
|
+
message:
|
|
764
|
+
err instanceof Error
|
|
765
|
+
? err.message
|
|
766
|
+
: "Invalid minimumReleaseAge value in registry config",
|
|
767
|
+
},
|
|
768
|
+
};
|
|
769
|
+
}
|
|
770
|
+
}
|
|
771
|
+
if (minimumReleaseAgeSeconds > 0) {
|
|
772
|
+
const exclude = registryConfig.policy?.minimumReleaseAgeExclude?.map((e) =>
|
|
773
|
+
e.trim().toLowerCase(),
|
|
774
|
+
);
|
|
775
|
+
const exempt = releaseExemptFromMinimumAge(exclude, publisherDid, slug);
|
|
776
|
+
if (!exempt) {
|
|
777
|
+
const indexedAt = Date.parse(releaseView.indexedAt);
|
|
778
|
+
if (!Number.isFinite(indexedAt)) {
|
|
779
|
+
return {
|
|
780
|
+
success: false,
|
|
781
|
+
error: {
|
|
782
|
+
code: "RELEASE_TIMESTAMP_INVALID",
|
|
783
|
+
message:
|
|
784
|
+
"Release record is missing a valid indexed-at timestamp; cannot evaluate minimum release age policy.",
|
|
785
|
+
},
|
|
786
|
+
};
|
|
787
|
+
}
|
|
788
|
+
const ageSeconds = (Date.now() - indexedAt) / 1000;
|
|
789
|
+
if (ageSeconds < minimumReleaseAgeSeconds) {
|
|
790
|
+
const remaining = Math.ceil(minimumReleaseAgeSeconds - ageSeconds);
|
|
791
|
+
return {
|
|
792
|
+
success: false,
|
|
793
|
+
error: {
|
|
794
|
+
code: "RELEASE_TOO_NEW",
|
|
795
|
+
message:
|
|
796
|
+
`This release does not meet the configured minimum release age of ` +
|
|
797
|
+
`${minimumReleaseAgeSeconds}s. It will be installable in ~${remaining}s.`,
|
|
798
|
+
},
|
|
799
|
+
};
|
|
800
|
+
}
|
|
801
|
+
}
|
|
802
|
+
}
|
|
803
|
+
|
|
804
|
+
// Derive the normalized opaque plugin id we'll use as the
|
|
805
|
+
// runtime-wide identifier from here on. The publisher_did + slug
|
|
806
|
+
// stay in the state row for update resolution and admin display.
|
|
807
|
+
const pluginId = await makeRegistryPluginId(publisherDid, slug);
|
|
808
|
+
|
|
809
|
+
// Block installation if a configured (trusted) plugin shares this
|
|
810
|
+
// id. Mirrors the marketplace install's PLUGIN_ID_CONFLICT check.
|
|
811
|
+
if (opts?.configuredPluginIds?.has(pluginId)) {
|
|
812
|
+
return {
|
|
813
|
+
success: false,
|
|
814
|
+
error: {
|
|
815
|
+
code: "PLUGIN_ID_CONFLICT",
|
|
816
|
+
message: "A configured plugin with the same derived id already exists",
|
|
817
|
+
},
|
|
818
|
+
};
|
|
819
|
+
}
|
|
820
|
+
|
|
821
|
+
// Check for an existing install (any source) under the derived id.
|
|
822
|
+
// We reject all pre-existing rows -- if the row is from a registry
|
|
823
|
+
// install of this same package, the caller should go through the
|
|
824
|
+
// (future) update flow; if it's from any other source, the
|
|
825
|
+
// pluginId collision means installing would silently mutate an
|
|
826
|
+
// unrelated plugin's lifecycle row.
|
|
827
|
+
const stateRepo = new PluginStateRepository(db);
|
|
828
|
+
const existing = await stateRepo.get(pluginId);
|
|
829
|
+
if (existing) {
|
|
830
|
+
if (existing.source === "registry") {
|
|
831
|
+
return {
|
|
832
|
+
success: false,
|
|
833
|
+
error: {
|
|
834
|
+
code: "ALREADY_INSTALLED",
|
|
835
|
+
message: `Plugin ${publisherDid}/${slug} is already installed`,
|
|
836
|
+
},
|
|
837
|
+
};
|
|
838
|
+
}
|
|
839
|
+
return {
|
|
840
|
+
success: false,
|
|
841
|
+
error: {
|
|
842
|
+
code: "PLUGIN_ID_COLLISION",
|
|
843
|
+
message:
|
|
844
|
+
`A non-registry plugin already exists at the derived id ${pluginId}. ` +
|
|
845
|
+
"Uninstall it before installing this registry plugin.",
|
|
846
|
+
},
|
|
847
|
+
};
|
|
848
|
+
}
|
|
849
|
+
|
|
850
|
+
// Step 4: fetch the artifact bytes.
|
|
851
|
+
// `releaseView.release` is lexicon-validated by DiscoveryClient (or
|
|
852
|
+
// `null`); a missing url/checksum (incl. the `null` case) fails closed
|
|
853
|
+
// below. Mirrors come from the envelope (aggregator operational data,
|
|
854
|
+
// not part of the signed record).
|
|
855
|
+
const release = releaseView.release;
|
|
856
|
+
const declaredUrl = release?.artifacts?.package?.url;
|
|
857
|
+
const declaredChecksum = release?.artifacts?.package?.checksum;
|
|
858
|
+
|
|
859
|
+
if (!declaredUrl || !declaredChecksum) {
|
|
860
|
+
return {
|
|
861
|
+
success: false,
|
|
862
|
+
error: {
|
|
863
|
+
code: "INVALID_RELEASE",
|
|
864
|
+
message: "Release record is missing artifact url or checksum",
|
|
865
|
+
},
|
|
866
|
+
};
|
|
867
|
+
}
|
|
868
|
+
|
|
869
|
+
const mirrors = releaseView.mirrors ?? [];
|
|
870
|
+
const artifactBytes = await fetchArtifact(mirrors, declaredUrl);
|
|
871
|
+
|
|
872
|
+
// Step 5: verify the bytes against the signed record's checksum.
|
|
873
|
+
const checksumOk = await verifyChecksum(artifactBytes, declaredChecksum);
|
|
874
|
+
if (!checksumOk) {
|
|
875
|
+
return {
|
|
876
|
+
success: false,
|
|
877
|
+
error: {
|
|
878
|
+
code: "CHECKSUM_MISMATCH",
|
|
879
|
+
message:
|
|
880
|
+
"Artifact bytes do not match the release record's checksum, or the checksum encoding is unsupported.",
|
|
881
|
+
},
|
|
882
|
+
};
|
|
883
|
+
}
|
|
884
|
+
|
|
885
|
+
// Step 6: extract the bundle.
|
|
886
|
+
let bundle: PluginBundle;
|
|
887
|
+
try {
|
|
888
|
+
bundle = await extractBundle(artifactBytes);
|
|
889
|
+
} catch (err) {
|
|
890
|
+
return {
|
|
891
|
+
success: false,
|
|
892
|
+
error: {
|
|
893
|
+
code: "INVALID_BUNDLE",
|
|
894
|
+
message: err instanceof Error ? err.message : "Failed to extract plugin bundle",
|
|
895
|
+
},
|
|
896
|
+
};
|
|
897
|
+
}
|
|
898
|
+
|
|
899
|
+
// Manifest sanity: declared version must match the release's version.
|
|
900
|
+
if (bundle.manifest.version !== version) {
|
|
901
|
+
return {
|
|
902
|
+
success: false,
|
|
903
|
+
error: {
|
|
904
|
+
code: "MANIFEST_VERSION_MISMATCH",
|
|
905
|
+
message: `Bundle manifest version (${bundle.manifest.version}) does not match release version (${version})`,
|
|
906
|
+
},
|
|
907
|
+
};
|
|
908
|
+
}
|
|
909
|
+
|
|
910
|
+
// Manifest identity: the bundle's `manifest.id` is the publisher's
|
|
911
|
+
// natural plugin id (their slug). It MUST equal the slug the
|
|
912
|
+
// install was requested for; otherwise a malicious registry bundle
|
|
913
|
+
// could declare `manifest.id: "audit-log"` and confuse the sandbox
|
|
914
|
+
// bridge, which uses `manifest.id` as the trust key for
|
|
915
|
+
// per-plugin storage, cron schedules, and bridge-scoped
|
|
916
|
+
// operations.
|
|
917
|
+
if (bundle.manifest.id !== slug) {
|
|
918
|
+
return {
|
|
919
|
+
success: false,
|
|
920
|
+
error: {
|
|
921
|
+
code: "MANIFEST_ID_MISMATCH",
|
|
922
|
+
message: `Bundle manifest id (${bundle.manifest.id}) does not match registry slug (${slug})`,
|
|
923
|
+
},
|
|
924
|
+
};
|
|
925
|
+
}
|
|
926
|
+
|
|
927
|
+
// Rewrite the manifest's id to the derived opaque pluginId before
|
|
928
|
+
// it reaches R2 storage or the sandbox loader. The sandbox uses
|
|
929
|
+
// `manifest.id` as its identity for per-plugin storage and bridge
|
|
930
|
+
// calls; addressing it by the same pluginId we use in the runtime
|
|
931
|
+
// cache, R2 prefix, and `_plugin_state` row keeps every layer
|
|
932
|
+
// in sync and prevents registry installs from colliding with
|
|
933
|
+
// marketplace plugins that happen to share the publisher's slug.
|
|
934
|
+
bundle.manifest = { ...bundle.manifest, id: pluginId };
|
|
935
|
+
|
|
936
|
+
// Capability consent gate: the admin MUST acknowledge the
|
|
937
|
+
// capabilities the bundle's manifest actually declares before we
|
|
938
|
+
// install it. The bundle manifest is the only source of truth
|
|
939
|
+
// the runtime sandbox enforces -- the release record's
|
|
940
|
+
// `declaredAccess` extension is an aggregator-supplied
|
|
941
|
+
// assertion that the publisher may or may not have included,
|
|
942
|
+
// and trusting it would let a malicious publisher (or a
|
|
943
|
+
// compromised aggregator) ship a bundle whose manifest
|
|
944
|
+
// requests `content:*` etc. behind an empty consent dialog.
|
|
945
|
+
//
|
|
946
|
+
// Two outcomes after normalization (filter to strings, dedupe,
|
|
947
|
+
// sort):
|
|
948
|
+
//
|
|
949
|
+
// 1. The bundle declares no capabilities: install is allowed
|
|
950
|
+
// without any acknowledgement (nothing to consent to).
|
|
951
|
+
// 2. The bundle declares capabilities: install requires the
|
|
952
|
+
// caller to send `acknowledgedDeclaredAccess`, and the
|
|
953
|
+
// sorted lists must match exactly.
|
|
954
|
+
//
|
|
955
|
+
// We compare against the bundle's *capabilities* (the legacy
|
|
956
|
+
// shape) for v1 because EmDash's existing sandbox enforces
|
|
957
|
+
// capabilities, not the RFC's structured `declaredAccess`. Once
|
|
958
|
+
// the runtime starts enforcing `declaredAccess` natively, this
|
|
959
|
+
// comparison switches to that shape.
|
|
960
|
+
const actualCapabilities = canonicalCapabilitiesForDriftCheck(bundle.manifest.capabilities);
|
|
961
|
+
if (actualCapabilities.length > 0) {
|
|
962
|
+
if (input.acknowledgedDeclaredAccess === undefined) {
|
|
963
|
+
return {
|
|
964
|
+
success: false,
|
|
965
|
+
error: {
|
|
966
|
+
code: "DECLARED_ACCESS_REQUIRED",
|
|
967
|
+
message:
|
|
968
|
+
"This plugin declares capabilities that require consent. Re-open the install dialog to review and acknowledge them.",
|
|
969
|
+
},
|
|
970
|
+
};
|
|
971
|
+
}
|
|
972
|
+
const acknowledged = canonicalCapabilitiesForDriftCheck(input.acknowledgedDeclaredAccess);
|
|
973
|
+
if (
|
|
974
|
+
acknowledged.length !== actualCapabilities.length ||
|
|
975
|
+
acknowledged.some((cap, i) => cap !== actualCapabilities[i])
|
|
976
|
+
) {
|
|
977
|
+
return {
|
|
978
|
+
success: false,
|
|
979
|
+
error: {
|
|
980
|
+
code: "DECLARED_ACCESS_DRIFT",
|
|
981
|
+
message:
|
|
982
|
+
"Plugin manifest has changed since you consented. Re-open the install dialog to review the new permissions.",
|
|
983
|
+
},
|
|
984
|
+
};
|
|
985
|
+
}
|
|
986
|
+
}
|
|
987
|
+
|
|
988
|
+
// Step 7: store in R2 under the registry prefix.
|
|
989
|
+
await storeBundleInR2(storage, pluginId, version, bundle, "registry");
|
|
990
|
+
|
|
991
|
+
// Step 8: write plugin state.
|
|
992
|
+
// Display name and description come from the *package profile*
|
|
993
|
+
// (the signed record from the publisher's repo), not from the
|
|
994
|
+
// bundle manifest -- the manifest carries the trust contract,
|
|
995
|
+
// the profile carries the marketing copy.
|
|
996
|
+
//
|
|
997
|
+
// On failure, we may need to clean up the R2 bundle we just
|
|
998
|
+
// wrote. But two parallel installs of the same (did, slug,
|
|
999
|
+
// version) both pass the earlier `existing` check at line 822
|
|
1000
|
+
// (the read is not transactional with the insert), both upload
|
|
1001
|
+
// to the same deterministic R2 prefix (overwrites are
|
|
1002
|
+
// content-identical because R2 keys include the version and
|
|
1003
|
+
// the bundle is checksum-verified upstream), and then one wins
|
|
1004
|
+
// the insert while the other fails with a PK constraint
|
|
1005
|
+
// violation.
|
|
1006
|
+
//
|
|
1007
|
+
// If we blindly clean up R2 on every state-write failure, the
|
|
1008
|
+
// loser of that race would delete the winner's bundle and the
|
|
1009
|
+
// runtime would fail to load the plugin on the next sync.
|
|
1010
|
+
//
|
|
1011
|
+
// Instead: on state-write failure, re-query the state row. If
|
|
1012
|
+
// a row now exists for this pluginId, we lost the race -- the
|
|
1013
|
+
// winner owns the R2 bundle and we must not touch it. If the
|
|
1014
|
+
// row doesn't exist, the failure was a real DB error and the
|
|
1015
|
+
// R2 bytes are orphans; clean them up.
|
|
1016
|
+
//
|
|
1017
|
+
// Cleanup is best-effort; if it also fails, the row failure
|
|
1018
|
+
// still surfaces to the caller and the orphan R2 bundle costs
|
|
1019
|
+
// only the storage of a single checksum-verified zip.
|
|
1020
|
+
// `packageView.profile` is lexicon-validated by DiscoveryClient (or null).
|
|
1021
|
+
const profile = packageView.profile;
|
|
1022
|
+
try {
|
|
1023
|
+
await stateRepo.upsert(pluginId, version, "active", {
|
|
1024
|
+
source: "registry",
|
|
1025
|
+
displayName: profile?.name ?? slug,
|
|
1026
|
+
description: profile?.description ?? undefined,
|
|
1027
|
+
registryPublisherDid: publisherDid,
|
|
1028
|
+
registrySlug: slug,
|
|
1029
|
+
});
|
|
1030
|
+
} catch (stateErr) {
|
|
1031
|
+
let lostRace = false;
|
|
1032
|
+
try {
|
|
1033
|
+
const winner = await stateRepo.get(pluginId);
|
|
1034
|
+
lostRace = winner !== undefined && winner !== null;
|
|
1035
|
+
} catch (probeErr) {
|
|
1036
|
+
console.warn(
|
|
1037
|
+
`[registry-install] Failed to probe state row for ${pluginId} after state-write failure; treating as orphan:`,
|
|
1038
|
+
probeErr,
|
|
1039
|
+
);
|
|
1040
|
+
}
|
|
1041
|
+
if (!lostRace) {
|
|
1042
|
+
try {
|
|
1043
|
+
await deleteBundleFromR2(storage, pluginId, version, "registry");
|
|
1044
|
+
} catch (cleanupErr) {
|
|
1045
|
+
console.warn(
|
|
1046
|
+
`[registry-install] Failed to clean up R2 bundle for ${pluginId}@${version} after state-row write failure:`,
|
|
1047
|
+
cleanupErr,
|
|
1048
|
+
);
|
|
1049
|
+
}
|
|
1050
|
+
}
|
|
1051
|
+
throw stateErr;
|
|
1052
|
+
}
|
|
1053
|
+
|
|
1054
|
+
return {
|
|
1055
|
+
success: true,
|
|
1056
|
+
data: {
|
|
1057
|
+
pluginId,
|
|
1058
|
+
publisherDid,
|
|
1059
|
+
slug,
|
|
1060
|
+
version,
|
|
1061
|
+
capabilities: bundle.manifest.capabilities,
|
|
1062
|
+
},
|
|
1063
|
+
};
|
|
1064
|
+
} catch (err) {
|
|
1065
|
+
if (err instanceof EmDashStorageError) {
|
|
1066
|
+
return {
|
|
1067
|
+
success: false,
|
|
1068
|
+
error: {
|
|
1069
|
+
code: err.code ?? "STORAGE_ERROR",
|
|
1070
|
+
message: "Storage error while installing plugin",
|
|
1071
|
+
},
|
|
1072
|
+
};
|
|
1073
|
+
}
|
|
1074
|
+
console.error("[registry-install] Failed:", err);
|
|
1075
|
+
return {
|
|
1076
|
+
success: false,
|
|
1077
|
+
error: {
|
|
1078
|
+
code: "INSTALL_FAILED",
|
|
1079
|
+
message: err instanceof Error ? err.message : "Failed to install plugin from registry",
|
|
1080
|
+
},
|
|
1081
|
+
};
|
|
1082
|
+
}
|
|
1083
|
+
}
|