emdash 0.13.0 → 0.15.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-9DybjTO6.d.mts → adapters-C4yd_UJR.d.mts} +1 -1
- package/dist/{adapters-9DybjTO6.d.mts.map → adapters-C4yd_UJR.d.mts.map} +1 -1
- package/dist/{allowed-origins-CDdG-4Gd.mjs → allowed-origins-D0fFk9a6.mjs} +2 -2
- package/dist/{allowed-origins-CDdG-4Gd.mjs.map → allowed-origins-D0fFk9a6.mjs.map} +1 -1
- package/dist/api/route-utils.d.mts +3 -3
- package/dist/api/route-utils.mjs +15 -15
- package/dist/api/schemas/index.d.mts +2 -2
- package/dist/api/schemas/index.mjs +3 -3
- package/dist/{api-ayIQ7rIe.mjs → api-CLwG_3dh.mjs} +523 -59
- package/dist/api-CLwG_3dh.mjs.map +1 -0
- package/dist/{api-tokens-eYymBhIT.mjs → api-tokens-ucpcNXDt.mjs} +2 -2
- package/dist/{api-tokens-eYymBhIT.mjs.map → api-tokens-ucpcNXDt.mjs.map} +1 -1
- package/dist/{apply-v4DBgjPw.mjs → apply-wJhM_bwU.mjs} +17 -17
- package/dist/{apply-v4DBgjPw.mjs.map → apply-wJhM_bwU.mjs.map} +1 -1
- package/dist/astro/index.d.mts +10 -10
- package/dist/astro/index.mjs +21 -5
- package/dist/astro/index.mjs.map +1 -1
- package/dist/astro/middleware/auth.d.mts +9 -9
- package/dist/astro/middleware/auth.mjs +6 -6
- package/dist/astro/middleware/auth.mjs.map +1 -1
- package/dist/astro/middleware/redirect.mjs +4 -4
- package/dist/astro/middleware/request-context.mjs +2 -2
- package/dist/astro/middleware/request-context.mjs.map +1 -1
- package/dist/astro/middleware/setup.mjs +1 -1
- package/dist/astro/middleware.d.mts.map +1 -1
- package/dist/astro/middleware.mjs +353 -71
- package/dist/astro/middleware.mjs.map +1 -1
- package/dist/astro/routes/api/admin/allowed-domains/_domain_.mjs +5 -5
- package/dist/astro/routes/api/admin/allowed-domains/index.mjs +5 -5
- package/dist/astro/routes/api/admin/api-tokens/_id_.mjs +4 -4
- package/dist/astro/routes/api/admin/api-tokens/index.mjs +5 -5
- package/dist/astro/routes/api/admin/bylines/_id_/index.d.mts.map +1 -1
- package/dist/astro/routes/api/admin/bylines/_id_/index.mjs +14 -17
- package/dist/astro/routes/api/admin/bylines/_id_/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/bylines/_id_/translations.d.mts +9 -0
- package/dist/astro/routes/api/admin/bylines/_id_/translations.d.mts.map +1 -0
- package/dist/astro/routes/api/admin/bylines/_id_/translations.mjs +70 -0
- package/dist/astro/routes/api/admin/bylines/_id_/translations.mjs.map +1 -0
- package/dist/astro/routes/api/admin/bylines/index.d.mts.map +1 -1
- package/dist/astro/routes/api/admin/bylines/index.mjs +25 -16
- package/dist/astro/routes/api/admin/bylines/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/comments/_id_/status.mjs +10 -10
- package/dist/astro/routes/api/admin/comments/_id_.mjs +5 -5
- package/dist/astro/routes/api/admin/comments/bulk.mjs +8 -8
- package/dist/astro/routes/api/admin/comments/counts.mjs +5 -5
- package/dist/astro/routes/api/admin/comments/index.mjs +8 -8
- package/dist/astro/routes/api/admin/hooks/exclusive/_hookName_.mjs +4 -4
- package/dist/astro/routes/api/admin/hooks/exclusive/index.mjs +3 -3
- package/dist/astro/routes/api/admin/oauth-clients/_id_.mjs +4 -4
- package/dist/astro/routes/api/admin/oauth-clients/index.mjs +4 -4
- package/dist/astro/routes/api/admin/plugins/_id_/disable.mjs +32 -31
- package/dist/astro/routes/api/admin/plugins/_id_/disable.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/_id_/enable.mjs +32 -31
- package/dist/astro/routes/api/admin/plugins/_id_/enable.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/_id_/index.mjs +31 -30
- package/dist/astro/routes/api/admin/plugins/_id_/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/_id_/uninstall.mjs +31 -30
- package/dist/astro/routes/api/admin/plugins/_id_/uninstall.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/_id_/update.mjs +33 -31
- package/dist/astro/routes/api/admin/plugins/_id_/update.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/index.mjs +31 -30
- package/dist/astro/routes/api/admin/plugins/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/marketplace/_id_/icon.mjs +3 -3
- package/dist/astro/routes/api/admin/plugins/marketplace/_id_/index.mjs +31 -30
- package/dist/astro/routes/api/admin/plugins/marketplace/_id_/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/marketplace/_id_/install.mjs +33 -31
- package/dist/astro/routes/api/admin/plugins/marketplace/_id_/install.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/marketplace/index.mjs +31 -30
- package/dist/astro/routes/api/admin/plugins/marketplace/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/registry/_id_/uninstall.d.mts +8 -0
- package/dist/astro/routes/api/admin/plugins/registry/_id_/uninstall.d.mts.map +1 -0
- package/dist/astro/routes/api/admin/plugins/registry/_id_/uninstall.mjs +59 -0
- package/dist/astro/routes/api/admin/plugins/registry/_id_/uninstall.mjs.map +1 -0
- package/dist/astro/routes/api/admin/plugins/registry/_id_/update.d.mts +8 -0
- package/dist/astro/routes/api/admin/plugins/registry/_id_/update.d.mts.map +1 -0
- package/dist/astro/routes/api/admin/plugins/registry/_id_/update.mjs +72 -0
- package/dist/astro/routes/api/admin/plugins/registry/_id_/update.mjs.map +1 -0
- package/dist/astro/routes/api/admin/plugins/registry/install.mjs +31 -30
- package/dist/astro/routes/api/admin/plugins/registry/install.mjs.map +1 -1
- package/dist/astro/routes/api/admin/plugins/updates.d.mts.map +1 -1
- package/dist/astro/routes/api/admin/plugins/updates.mjs +44 -31
- package/dist/astro/routes/api/admin/plugins/updates.mjs.map +1 -1
- package/dist/astro/routes/api/admin/themes/marketplace/_id_/index.mjs +31 -30
- package/dist/astro/routes/api/admin/themes/marketplace/_id_/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/themes/marketplace/_id_/thumbnail.mjs +3 -3
- package/dist/astro/routes/api/admin/themes/marketplace/index.mjs +31 -30
- package/dist/astro/routes/api/admin/themes/marketplace/index.mjs.map +1 -1
- package/dist/astro/routes/api/admin/users/_id_/disable.mjs +2 -2
- package/dist/astro/routes/api/admin/users/_id_/enable.mjs +2 -2
- package/dist/astro/routes/api/admin/users/_id_/index.mjs +5 -5
- package/dist/astro/routes/api/admin/users/_id_/send-recovery.mjs +3 -3
- package/dist/astro/routes/api/admin/users/index.mjs +5 -5
- package/dist/astro/routes/api/auth/dev-bypass.mjs +5 -5
- package/dist/astro/routes/api/auth/invite/accept.mjs +2 -2
- package/dist/astro/routes/api/auth/invite/complete.mjs +9 -9
- package/dist/astro/routes/api/auth/invite/index.mjs +6 -6
- package/dist/astro/routes/api/auth/invite/register-options.mjs +8 -8
- package/dist/astro/routes/api/auth/logout.mjs +3 -3
- package/dist/astro/routes/api/auth/magic-link/send.mjs +8 -8
- package/dist/astro/routes/api/auth/magic-link/verify.mjs +3 -3
- package/dist/astro/routes/api/auth/me.mjs +5 -5
- package/dist/astro/routes/api/auth/mode.mjs +1 -1
- package/dist/astro/routes/api/auth/oauth/_provider_/callback.mjs +3 -3
- package/dist/astro/routes/api/auth/oauth/_provider_/callback.mjs.map +1 -1
- package/dist/astro/routes/api/auth/oauth/_provider_.mjs +2 -2
- package/dist/astro/routes/api/auth/oauth/_provider_.mjs.map +1 -1
- package/dist/astro/routes/api/auth/passkey/_id_.mjs +5 -5
- package/dist/astro/routes/api/auth/passkey/index.mjs +2 -2
- package/dist/astro/routes/api/auth/passkey/options.mjs +10 -10
- package/dist/astro/routes/api/auth/passkey/register/options.mjs +8 -8
- package/dist/astro/routes/api/auth/passkey/register/verify.mjs +9 -9
- package/dist/astro/routes/api/auth/passkey/verify.mjs +9 -9
- package/dist/astro/routes/api/auth/signup/complete.mjs +9 -9
- package/dist/astro/routes/api/auth/signup/request.mjs +8 -8
- package/dist/astro/routes/api/auth/signup/verify.mjs +2 -2
- package/dist/astro/routes/api/comments/_collection_/_contentId_/index.mjs +11 -11
- package/dist/astro/routes/api/content/_collection_/_id_/compare.mjs +3 -3
- package/dist/astro/routes/api/content/_collection_/_id_/discard-draft.mjs +3 -3
- package/dist/astro/routes/api/content/_collection_/_id_/discard-draft.mjs.map +1 -1
- package/dist/astro/routes/api/content/_collection_/_id_/duplicate.mjs +3 -3
- package/dist/astro/routes/api/content/_collection_/_id_/duplicate.mjs.map +1 -1
- package/dist/astro/routes/api/content/_collection_/_id_/permanent.mjs +3 -3
- package/dist/astro/routes/api/content/_collection_/_id_/preview-url.mjs +9 -9
- package/dist/astro/routes/api/content/_collection_/_id_/publish.mjs +6 -6
- package/dist/astro/routes/api/content/_collection_/_id_/publish.mjs.map +1 -1
- package/dist/astro/routes/api/content/_collection_/_id_/restore.mjs +3 -3
- package/dist/astro/routes/api/content/_collection_/_id_/restore.mjs.map +1 -1
- package/dist/astro/routes/api/content/_collection_/_id_/revisions.mjs +3 -3
- package/dist/astro/routes/api/content/_collection_/_id_/schedule.mjs +6 -6
- package/dist/astro/routes/api/content/_collection_/_id_/schedule.mjs.map +1 -1
- package/dist/astro/routes/api/content/_collection_/_id_/terms/_taxonomy_.mjs +10 -9
- package/dist/astro/routes/api/content/_collection_/_id_/terms/_taxonomy_.mjs.map +1 -1
- package/dist/astro/routes/api/content/_collection_/_id_/translations.mjs +3 -3
- package/dist/astro/routes/api/content/_collection_/_id_/translations.mjs.map +1 -1
- package/dist/astro/routes/api/content/_collection_/_id_/unpublish.mjs +3 -3
- package/dist/astro/routes/api/content/_collection_/_id_/unpublish.mjs.map +1 -1
- package/dist/astro/routes/api/content/_collection_/_id_.mjs +6 -6
- package/dist/astro/routes/api/content/_collection_/_id_.mjs.map +1 -1
- package/dist/astro/routes/api/content/_collection_/index.mjs +6 -6
- package/dist/astro/routes/api/content/_collection_/trash.mjs +6 -6
- package/dist/astro/routes/api/dashboard.mjs +7 -7
- package/dist/astro/routes/api/dev/emails.mjs +3 -3
- package/dist/astro/routes/api/import/probe.d.mts +3 -3
- package/dist/astro/routes/api/import/probe.mjs +10 -10
- package/dist/astro/routes/api/import/wordpress/analyze.mjs +3 -3
- package/dist/astro/routes/api/import/wordpress/execute.d.mts +9 -9
- package/dist/astro/routes/api/import/wordpress/execute.mjs +9 -8
- package/dist/astro/routes/api/import/wordpress/execute.mjs.map +1 -1
- package/dist/astro/routes/api/import/wordpress/media.mjs +8 -8
- package/dist/astro/routes/api/import/wordpress/prepare.mjs +8 -8
- package/dist/astro/routes/api/import/wordpress/prepare.mjs.map +1 -1
- package/dist/astro/routes/api/import/wordpress/rewrite-urls.mjs +7 -7
- package/dist/astro/routes/api/import/wordpress/rewrite-urls.mjs.map +1 -1
- package/dist/astro/routes/api/import/wordpress-plugin/analyze.d.mts +1 -1
- package/dist/astro/routes/api/import/wordpress-plugin/analyze.mjs +10 -10
- package/dist/astro/routes/api/import/wordpress-plugin/execute.d.mts +1 -1
- package/dist/astro/routes/api/import/wordpress-plugin/execute.mjs +11 -11
- package/dist/astro/routes/api/import/wordpress-plugin/execute.mjs.map +1 -1
- package/dist/astro/routes/api/manifest.mjs +4 -4
- package/dist/astro/routes/api/mcp.mjs +29 -29
- package/dist/astro/routes/api/mcp.mjs.map +1 -1
- package/dist/astro/routes/api/media/_id_/confirm.mjs +6 -6
- package/dist/astro/routes/api/media/_id_.mjs +6 -6
- package/dist/astro/routes/api/media/file/_...key_.mjs +2 -2
- package/dist/astro/routes/api/media/providers/_providerId_/_itemId_.mjs +3 -3
- package/dist/astro/routes/api/media/providers/_providerId_/index.mjs +3 -3
- package/dist/astro/routes/api/media/providers/index.mjs +3 -3
- package/dist/astro/routes/api/media/upload-url.mjs +7 -7
- package/dist/astro/routes/api/media/upload-url.mjs.map +1 -1
- package/dist/astro/routes/api/media.mjs +8 -8
- package/dist/astro/routes/api/menus/_name_/items/_id_.mjs +7 -7
- package/dist/astro/routes/api/menus/_name_/items.mjs +7 -7
- package/dist/astro/routes/api/menus/_name_/reorder.mjs +7 -7
- package/dist/astro/routes/api/menus/_name_/translations.mjs +7 -7
- package/dist/astro/routes/api/menus/_name_.mjs +7 -7
- package/dist/astro/routes/api/menus/index.mjs +7 -7
- package/dist/astro/routes/api/oauth/authorize.mjs +6 -6
- package/dist/astro/routes/api/oauth/device/authorize.mjs +6 -6
- package/dist/astro/routes/api/oauth/device/code.mjs +9 -9
- package/dist/astro/routes/api/oauth/device/token.mjs +8 -8
- package/dist/astro/routes/api/oauth/register.mjs +3 -3
- package/dist/astro/routes/api/oauth/token/refresh.mjs +6 -6
- package/dist/astro/routes/api/oauth/token/revoke.mjs +6 -6
- package/dist/astro/routes/api/oauth/token.mjs +6 -6
- package/dist/astro/routes/api/openapi.json.mjs +3 -3
- package/dist/astro/routes/api/openapi.json.mjs.map +1 -1
- package/dist/astro/routes/api/plugins/_pluginId_/_...path_.mjs +4 -4
- package/dist/astro/routes/api/redirects/404s/index.mjs +8 -8
- package/dist/astro/routes/api/redirects/404s/index.mjs.map +1 -1
- package/dist/astro/routes/api/redirects/404s/summary.mjs +8 -8
- package/dist/astro/routes/api/redirects/404s/summary.mjs.map +1 -1
- package/dist/astro/routes/api/redirects/_id_.mjs +9 -9
- package/dist/astro/routes/api/redirects/_id_.mjs.map +1 -1
- package/dist/astro/routes/api/redirects/index.mjs +9 -9
- package/dist/astro/routes/api/redirects/index.mjs.map +1 -1
- package/dist/astro/routes/api/revisions/_revisionId_/index.mjs +3 -3
- package/dist/astro/routes/api/revisions/_revisionId_/restore.mjs +3 -3
- package/dist/astro/routes/api/schema/collections/_slug_/fields/_fieldSlug_.mjs +31 -30
- package/dist/astro/routes/api/schema/collections/_slug_/fields/_fieldSlug_.mjs.map +1 -1
- package/dist/astro/routes/api/schema/collections/_slug_/fields/index.mjs +31 -30
- package/dist/astro/routes/api/schema/collections/_slug_/fields/index.mjs.map +1 -1
- package/dist/astro/routes/api/schema/collections/_slug_/fields/reorder.mjs +31 -30
- package/dist/astro/routes/api/schema/collections/_slug_/fields/reorder.mjs.map +1 -1
- package/dist/astro/routes/api/schema/collections/_slug_/index.mjs +31 -30
- package/dist/astro/routes/api/schema/collections/_slug_/index.mjs.map +1 -1
- package/dist/astro/routes/api/schema/collections/index.mjs +31 -30
- package/dist/astro/routes/api/schema/collections/index.mjs.map +1 -1
- package/dist/astro/routes/api/schema/index.mjs +6 -6
- package/dist/astro/routes/api/schema/index.mjs.map +1 -1
- package/dist/astro/routes/api/schema/orphans/_slug_.mjs +31 -30
- package/dist/astro/routes/api/schema/orphans/_slug_.mjs.map +1 -1
- package/dist/astro/routes/api/schema/orphans/index.mjs +31 -30
- package/dist/astro/routes/api/schema/orphans/index.mjs.map +1 -1
- package/dist/astro/routes/api/search/enable.mjs +9 -9
- package/dist/astro/routes/api/search/index.mjs +8 -8
- package/dist/astro/routes/api/search/rebuild.mjs +9 -9
- package/dist/astro/routes/api/search/stats.mjs +6 -6
- package/dist/astro/routes/api/search/suggest.mjs +8 -8
- package/dist/astro/routes/api/sections/_slug_.mjs +8 -8
- package/dist/astro/routes/api/sections/_slug_.mjs.map +1 -1
- package/dist/astro/routes/api/sections/index.mjs +8 -8
- package/dist/astro/routes/api/sections/index.mjs.map +1 -1
- package/dist/astro/routes/api/settings/email.mjs +4 -4
- package/dist/astro/routes/api/settings.mjs +10 -10
- package/dist/astro/routes/api/setup/admin-verify.mjs +10 -10
- package/dist/astro/routes/api/setup/admin.mjs +9 -9
- package/dist/astro/routes/api/setup/dev-bypass.mjs +22 -22
- package/dist/astro/routes/api/setup/dev-reset.mjs +2 -2
- package/dist/astro/routes/api/setup/index.mjs +22 -22
- package/dist/astro/routes/api/setup/status.mjs +4 -4
- package/dist/astro/routes/api/snapshot.mjs +5 -5
- package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_/translations.mjs +11 -10
- package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_/translations.mjs.map +1 -1
- package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_.mjs +11 -10
- package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_.mjs.map +1 -1
- package/dist/astro/routes/api/taxonomies/_name_/terms/index.mjs +11 -10
- package/dist/astro/routes/api/taxonomies/_name_/terms/index.mjs.map +1 -1
- package/dist/astro/routes/api/taxonomies/index.mjs +11 -10
- package/dist/astro/routes/api/taxonomies/index.mjs.map +1 -1
- package/dist/astro/routes/api/themes/preview.mjs +5 -5
- package/dist/astro/routes/api/typegen.mjs +5 -5
- package/dist/astro/routes/api/well-known/auth.mjs +1 -1
- package/dist/astro/routes/api/well-known/oauth-authorization-server.mjs +2 -2
- package/dist/astro/routes/api/well-known/oauth-protected-resource.mjs +2 -2
- package/dist/astro/routes/api/widget-areas/_name_/reorder.mjs +6 -6
- package/dist/astro/routes/api/widget-areas/_name_/widgets/_id_.mjs +8 -8
- package/dist/astro/routes/api/widget-areas/_name_/widgets.mjs +8 -8
- package/dist/astro/routes/api/widget-areas/_name_.mjs +5 -5
- package/dist/astro/routes/api/widget-areas/index.mjs +8 -8
- package/dist/astro/routes/api/widget-components.mjs +3 -3
- package/dist/astro/routes/robots.txt.mjs +5 -5
- package/dist/astro/routes/sitemap-_collection_.xml.mjs +4 -4
- package/dist/astro/routes/sitemap.xml.mjs +5 -5
- package/dist/astro/types.d.mts +13 -12
- package/dist/astro/types.d.mts.map +1 -1
- package/dist/auth/providers/github.d.mts +1 -1
- package/dist/auth/providers/google.d.mts +1 -1
- package/dist/{authorize-BlyCH-96.mjs → authorize-Bkwe8kuL.mjs} +2 -2
- package/dist/{authorize-BlyCH-96.mjs.map → authorize-Bkwe8kuL.mjs.map} +1 -1
- package/dist/byline-CTaWkMh5.mjs +404 -0
- package/dist/byline-CTaWkMh5.mjs.map +1 -0
- package/dist/bylines-BYHWU3T7.mjs +174 -0
- package/dist/bylines-BYHWU3T7.mjs.map +1 -0
- package/dist/{bylines-C6eYUWlZ.d.mts → bylines-DtDRNF1n.d.mts} +63 -18
- package/dist/bylines-DtDRNF1n.d.mts.map +1 -0
- package/dist/bylines-H0Xh5TMy.mjs +118 -0
- package/dist/bylines-H0Xh5TMy.mjs.map +1 -0
- package/dist/{cache-CXCpjWiL.mjs → cache-CNk1jIxp.mjs} +2 -2
- package/dist/{cache-CXCpjWiL.mjs.map → cache-CNk1jIxp.mjs.map} +1 -1
- package/dist/{challenge-store-CJ0OOHOr.mjs → challenge-store-Dng1SxKT.mjs} +1 -1
- package/dist/{challenge-store-CJ0OOHOr.mjs.map → challenge-store-Dng1SxKT.mjs.map} +1 -1
- package/dist/{chunks-DyGtu1Bv.mjs → chunks-BkfVdD-3.mjs} +2 -2
- package/dist/{chunks-DyGtu1Bv.mjs.map → chunks-BkfVdD-3.mjs.map} +1 -1
- package/dist/cli/index.mjs +21 -29
- package/dist/cli/index.mjs.map +1 -1
- package/dist/client/cf-access.d.mts +1 -1
- package/dist/client/index.d.mts +1 -1
- package/dist/client/index.mjs +1 -1
- package/dist/client/index.mjs.map +1 -1
- package/dist/{comment-Dd9MI82-.mjs → comment-_yzlBYPx.mjs} +2 -2
- package/dist/{comment-Dd9MI82-.mjs.map → comment-_yzlBYPx.mjs.map} +1 -1
- package/dist/{comments-koGI0FrK.mjs → comments-DxID-rsd.mjs} +3 -3
- package/dist/{comments-koGI0FrK.mjs.map → comments-DxID-rsd.mjs.map} +1 -1
- package/dist/{components-mZem7pbe.mjs → components-Dx3DM0gg.mjs} +1 -1
- package/dist/{components-mZem7pbe.mjs.map → components-Dx3DM0gg.mjs.map} +1 -1
- package/dist/config-CVssduLe.mjs.map +1 -1
- package/dist/{content-D6YG26WG.mjs → content-C0ooIs-f.mjs} +3 -3
- package/dist/{content-D6YG26WG.mjs.map → content-C0ooIs-f.mjs.map} +1 -1
- package/dist/{context-qF8d3IPR.mjs → context-sAnCaUIR.mjs} +10 -10
- package/dist/context-sAnCaUIR.mjs.map +1 -0
- package/dist/{cron-H8eJ46dv.mjs → cron-Bd3b3iuj.mjs} +1 -1
- package/dist/{cron-H8eJ46dv.mjs.map → cron-Bd3b3iuj.mjs.map} +1 -1
- package/dist/{dashboard-BmWSIUwY.mjs → dashboard-Cqw3ay2X.mjs} +4 -4
- package/dist/{dashboard-BmWSIUwY.mjs.map → dashboard-Cqw3ay2X.mjs.map} +1 -1
- 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/{default-Dbs22Gg4.mjs → default-BvTAYCzx.mjs} +1 -1
- package/dist/{default-Dbs22Gg4.mjs.map → default-BvTAYCzx.mjs.map} +1 -1
- package/dist/{device-flow-BqJRxa0Q.mjs → device-flow-B9oG8PwP.mjs} +4 -4
- package/dist/{device-flow-BqJRxa0Q.mjs.map → device-flow-B9oG8PwP.mjs.map} +1 -1
- package/dist/{email-console-Dmp5Q-P2.mjs → email-console-CubRll9q.mjs} +1 -1
- package/dist/email-console-CubRll9q.mjs.map +1 -0
- package/dist/{error-tSQWIl5U.mjs → error-CPh_8eLq.mjs} +16 -8
- package/dist/error-CPh_8eLq.mjs.map +1 -0
- package/dist/{escape-B8bdIryO.mjs → escape-Cg6kMELH.mjs} +1 -1
- package/dist/{escape-B8bdIryO.mjs.map → escape-Cg6kMELH.mjs.map} +1 -1
- package/dist/{fts-manager-B633C-kQ.mjs → fts-manager-Mnrtn-r2.mjs} +2 -2
- package/dist/{fts-manager-B633C-kQ.mjs.map → fts-manager-Mnrtn-r2.mjs.map} +1 -1
- package/dist/{import-CNfLOgDE.mjs → import-DG80rC_I.mjs} +3 -3
- package/dist/{import-CNfLOgDE.mjs.map → import-DG80rC_I.mjs.map} +1 -1
- package/dist/{index-UmOMt9T-.d.mts → index-Bv1Wf1zB.d.mts} +235 -18
- package/dist/index-Bv1Wf1zB.d.mts.map +1 -0
- package/dist/{index-D2gvztOP.d.mts → index-CC42STEm.d.mts} +3 -3
- package/dist/{index-D2gvztOP.d.mts.map → index-CC42STEm.d.mts.map} +1 -1
- package/dist/index.d.mts +17 -17
- package/dist/index.mjs +50 -49
- package/dist/{load-QzYRpVN3.mjs → load-DmXNVhst.mjs} +2 -2
- package/dist/{load-QzYRpVN3.mjs.map → load-DmXNVhst.mjs.map} +1 -1
- package/dist/{loader-Cs6-Bqe6.mjs → loader-Chm5h7Gr.mjs} +3 -3
- package/dist/loader-Chm5h7Gr.mjs.map +1 -0
- package/dist/{manifest-schema-HCtSh4Jq.mjs → manifest-schema-Czqf0TLu.mjs} +1 -1
- package/dist/{manifest-schema-HCtSh4Jq.mjs.map → manifest-schema-Czqf0TLu.mjs.map} +1 -1
- package/dist/media/index.d.mts +1 -1
- package/dist/media/local-runtime.d.mts +11 -11
- package/dist/media/local-runtime.mjs +4 -4
- package/dist/{media-allowlist-B8EX01DH.mjs → media-allowlist-BNloC69x.mjs} +1 -1
- package/dist/{media-allowlist-B8EX01DH.mjs.map → media-allowlist-BNloC69x.mjs.map} +1 -1
- package/dist/{media-Dg7he9uK.mjs → media-oqRcNiQf.mjs} +2 -2
- package/dist/media-oqRcNiQf.mjs.map +1 -0
- package/dist/{menus-DOzIecHi.mjs → menus-Bjf5R1Qq.mjs} +2 -2
- package/dist/menus-Bjf5R1Qq.mjs.map +1 -0
- package/dist/{menus-X4Z-eBA1.mjs → menus-C75SSmRy.mjs} +30 -11
- package/dist/menus-C75SSmRy.mjs.map +1 -0
- package/dist/mime-KV5TqkMN.mjs.map +1 -1
- package/dist/{mode-DPRPvJYm.mjs → mode-CaaiebZI.mjs} +1 -1
- package/dist/{mode-DPRPvJYm.mjs.map → mode-CaaiebZI.mjs.map} +1 -1
- package/dist/{oauth-authorization-62GmpGIH.mjs → oauth-authorization-CTMeVfvj.mjs} +4 -4
- package/dist/{oauth-authorization-62GmpGIH.mjs.map → oauth-authorization-CTMeVfvj.mjs.map} +1 -1
- package/dist/{oauth-clients-D_B0_-Bz.mjs → oauth-clients-eJCbkVSG.mjs} +1 -1
- package/dist/oauth-clients-eJCbkVSG.mjs.map +1 -0
- package/dist/{oauth-state-store-DpsZViTu.mjs → oauth-state-store-vOSdOeGe.mjs} +1 -1
- package/dist/{oauth-state-store-DpsZViTu.mjs.map → oauth-state-store-vOSdOeGe.mjs.map} +1 -1
- package/dist/{oauth-user-lookup-meyS2oB1.mjs → oauth-user-lookup-3JwsVw6N.mjs} +1 -1
- package/dist/{oauth-user-lookup-meyS2oB1.mjs.map → oauth-user-lookup-3JwsVw6N.mjs.map} +1 -1
- package/dist/options-BL4X94qY.mjs.map +1 -1
- package/dist/{options-Cq64Wx0O.d.mts → options-DhV-gwJb.d.mts} +4 -4
- package/dist/options-DhV-gwJb.d.mts.map +1 -0
- package/dist/page/index.d.mts +2 -2
- package/dist/{parse-BFTPon-J.mjs → parse-3-caTKgt.mjs} +2 -2
- package/dist/{parse-BFTPon-J.mjs.map → parse-3-caTKgt.mjs.map} +1 -1
- package/dist/{passkey-config-Cg86_ISa.mjs → passkey-config-BloQOT3y.mjs} +1 -1
- package/dist/{passkey-config-Cg86_ISa.mjs.map → passkey-config-BloQOT3y.mjs.map} +1 -1
- package/dist/{placeholder-D3cFCU9y.d.mts → placeholder-KCkkCtgQ.d.mts} +1 -1
- package/dist/{placeholder-D3cFCU9y.d.mts.map → placeholder-KCkkCtgQ.d.mts.map} +1 -1
- package/dist/plugin-types.d.mts +1 -1
- package/dist/plugins/adapt-sandbox-entry.d.mts +9 -9
- package/dist/plugins/adapt-sandbox-entry.d.mts.map +1 -1
- package/dist/plugins/adapt-sandbox-entry.mjs +26 -15
- package/dist/plugins/adapt-sandbox-entry.mjs.map +1 -1
- package/dist/{preview-C1LOEbWZ.mjs → preview-D4z0WONU.mjs} +2 -2
- package/dist/{preview-C1LOEbWZ.mjs.map → preview-D4z0WONU.mjs.map} +1 -1
- package/dist/{public-url-CseXl9Fv.mjs → public-url-CUWWFME2.mjs} +1 -1
- package/dist/{public-url-CseXl9Fv.mjs.map → public-url-CUWWFME2.mjs.map} +1 -1
- package/dist/{query-axZmO6Tn.mjs → query-BJn8TOPk.mjs} +16 -13
- package/dist/{query-axZmO6Tn.mjs.map → query-BJn8TOPk.mjs.map} +1 -1
- package/dist/{rate-limit-t5CVjCO6.mjs → rate-limit-D_-gAeJ0.mjs} +2 -2
- package/dist/{rate-limit-t5CVjCO6.mjs.map → rate-limit-D_-gAeJ0.mjs.map} +1 -1
- package/dist/{redirect-DGRsLO2I.mjs → redirect-BINiRYq4.mjs} +1 -1
- package/dist/{redirect-DGRsLO2I.mjs.map → redirect-BINiRYq4.mjs.map} +1 -1
- package/dist/{redirect-DkaDxq8e.mjs → redirect-CNv4mHX2.mjs} +2 -2
- package/dist/{redirect-DkaDxq8e.mjs.map → redirect-CNv4mHX2.mjs.map} +1 -1
- package/dist/{redirects-D1fdd68T.mjs → redirects-B-CUZ1Xh.mjs} +3 -3
- package/dist/{redirects-D1fdd68T.mjs.map → redirects-B-CUZ1Xh.mjs.map} +1 -1
- package/dist/{redirects-Dmj6KRU3.mjs → redirects-COMLwsV5.mjs} +19 -5
- package/dist/redirects-COMLwsV5.mjs.map +1 -0
- package/dist/{registry-BnCeHYsf.mjs → registry-DqrAQDXH.mjs} +4 -4
- package/dist/{registry-BnCeHYsf.mjs.map → registry-DqrAQDXH.mjs.map} +1 -1
- package/dist/request-cache-dzCt8TZB.mjs.map +1 -1
- package/dist/request-context.mjs.map +1 -1
- package/dist/{request-meta-CLCwSQOS.mjs → request-meta-C_Cjii-T.mjs} +2 -2
- package/dist/{request-meta-CLCwSQOS.mjs.map → request-meta-C_Cjii-T.mjs.map} +1 -1
- package/dist/resolve-Cj98DuqN.mjs +39 -0
- package/dist/resolve-Cj98DuqN.mjs.map +1 -0
- package/dist/{runner-DdnQIwz_.mjs → runner-CGlojznK.mjs} +472 -165
- package/dist/runner-CGlojznK.mjs.map +1 -0
- package/dist/{runner-DcfZewkO.d.mts → runner-CNHRo1mT.d.mts} +2 -2
- package/dist/{runner-DcfZewkO.d.mts.map → runner-CNHRo1mT.d.mts.map} +1 -1
- package/dist/runtime.d.mts +10 -10
- package/dist/runtime.mjs +2 -2
- package/dist/{schema-BmqagCwG.mjs → schema-Djdlfi5G.mjs} +4 -4
- package/dist/{schema-BmqagCwG.mjs.map → schema-Djdlfi5G.mjs.map} +1 -1
- package/dist/{search-CPrvO5u8.mjs → search-By-NN3da.mjs} +4 -4
- package/dist/{search-CPrvO5u8.mjs.map → search-By-NN3da.mjs.map} +1 -1
- package/dist/{secrets-6pgZyq0K.mjs → secrets-rPdhEBkD.mjs} +1 -1
- package/dist/{secrets-6pgZyq0K.mjs.map → secrets-rPdhEBkD.mjs.map} +1 -1
- package/dist/{sections-Cm-zb-gZ.mjs → sections-DcBIlOq1.mjs} +3 -3
- package/dist/{sections-Cm-zb-gZ.mjs.map → sections-DcBIlOq1.mjs.map} +1 -1
- package/dist/seed/index.d.mts +2 -2
- package/dist/seed/index.mjs +16 -16
- package/dist/seo/index.d.mts +1 -1
- package/dist/{seo-DRq9-EPP.mjs → seo-bjDoq9Eg.mjs} +2 -2
- package/dist/{seo-DRq9-EPP.mjs.map → seo-bjDoq9Eg.mjs.map} +1 -1
- package/dist/{service-vByySp-2.mjs → service-BuuTdGAT.mjs} +3 -3
- package/dist/{service-vByySp-2.mjs.map → service-BuuTdGAT.mjs.map} +1 -1
- package/dist/{settings-CBBj7HUd.mjs → settings-CJnKiWuR.mjs} +3 -3
- package/dist/{settings-CBBj7HUd.mjs.map → settings-CJnKiWuR.mjs.map} +1 -1
- package/dist/{settings-xQKsWnzQ.mjs → settings-hcubRfkr.mjs} +3 -3
- package/dist/settings-hcubRfkr.mjs.map +1 -0
- package/dist/{setup-BGAJ2uXs.mjs → setup-Cf_TyOv5.mjs} +2 -2
- package/dist/{setup-BGAJ2uXs.mjs.map → setup-Cf_TyOv5.mjs.map} +1 -1
- package/dist/{setup-complete-C6ZCLhKo.mjs → setup-complete-MzzN9u0b.mjs} +1 -1
- package/dist/{setup-complete-C6ZCLhKo.mjs.map → setup-complete-MzzN9u0b.mjs.map} +1 -1
- package/dist/{setup-nonce-CY1gQiAU.mjs → setup-nonce-DXuriHsg.mjs} +1 -1
- package/dist/{setup-nonce-CY1gQiAU.mjs.map → setup-nonce-DXuriHsg.mjs.map} +1 -1
- package/dist/{site-url-D-M4Fd8O.mjs → site-url-xkhw1tcz.mjs} +1 -1
- package/dist/{site-url-D-M4Fd8O.mjs.map → site-url-xkhw1tcz.mjs.map} +1 -1
- package/dist/{ssrf-DzFN_qV-.mjs → ssrf-MZ-zrG6-.mjs} +1 -1
- package/dist/{ssrf-DzFN_qV-.mjs.map → ssrf-MZ-zrG6-.mjs.map} +1 -1
- package/dist/storage/local.d.mts +1 -1
- package/dist/storage/local.mjs +1 -1
- package/dist/storage/local.mjs.map +1 -1
- package/dist/storage/s3.d.mts +1 -1
- package/dist/storage/s3.mjs +1 -1
- package/dist/storage/s3.mjs.map +1 -1
- package/dist/{taxonomies-Dc0mzlms.mjs → taxonomies-CLs9HPE2.mjs} +4 -4
- package/dist/{taxonomies-Dc0mzlms.mjs.map → taxonomies-CLs9HPE2.mjs.map} +1 -1
- package/dist/{taxonomies-Cn9UpaR2.mjs → taxonomies-WamPVA2x.mjs} +7 -42
- package/dist/taxonomies-WamPVA2x.mjs.map +1 -0
- package/dist/{taxonomy-wPfusMK9.mjs → taxonomy-D4Uc2LsZ.mjs} +3 -3
- package/dist/{taxonomy-wPfusMK9.mjs.map → taxonomy-D4Uc2LsZ.mjs.map} +1 -1
- package/dist/{tokens-DILYNZMi.mjs → tokens-N8otWMmj.mjs} +1 -1
- package/dist/{tokens-DILYNZMi.mjs.map → tokens-N8otWMmj.mjs.map} +1 -1
- package/dist/{transport-fw-mKJzT.mjs → transport-B6CHddbu.mjs} +1 -1
- package/dist/{transport-fw-mKJzT.mjs.map → transport-B6CHddbu.mjs.map} +1 -1
- package/dist/{transport-GeXlLscf.d.mts → transport-DOxLfUir.d.mts} +1 -1
- package/dist/{transport-GeXlLscf.d.mts.map → transport-DOxLfUir.d.mts.map} +1 -1
- package/dist/{trusted-proxy-CJhQIk65.mjs → trusted-proxy-97pajC2f.mjs} +1 -1
- package/dist/{trusted-proxy-CJhQIk65.mjs.map → trusted-proxy-97pajC2f.mjs.map} +1 -1
- package/dist/{types-CwXMEPRr.mjs → types-ByV5sgsv.mjs} +2 -2
- package/dist/types-ByV5sgsv.mjs.map +1 -0
- package/dist/{types-Dz9CGX_d.mjs → types-Cd9UCu3t.mjs} +1 -1
- package/dist/{types-Dz9CGX_d.mjs.map → types-Cd9UCu3t.mjs.map} +1 -1
- package/dist/{types-DmxPPXGf.d.mts → types-CkDSF81F.d.mts} +1 -1
- package/dist/{types-DmxPPXGf.d.mts.map → types-CkDSF81F.d.mts.map} +1 -1
- package/dist/{types-BWhaSS7U.d.mts → types-CpUuGcd5.d.mts} +1 -1
- package/dist/{types-BWhaSS7U.d.mts.map → types-CpUuGcd5.d.mts.map} +1 -1
- package/dist/{types-DFowNO60.d.mts → types-D599-ruj.d.mts} +1 -1
- package/dist/{types-DFowNO60.d.mts.map → types-D599-ruj.d.mts.map} +1 -1
- package/dist/{types-B05e2naf.d.mts → types-DGHWRQgr.d.mts} +3 -3
- package/dist/{types-B05e2naf.d.mts.map → types-DGHWRQgr.d.mts.map} +1 -1
- package/dist/{types-CzvJd1ND.d.mts → types-DaYDYW6g.d.mts} +14 -1
- package/dist/types-DaYDYW6g.d.mts.map +1 -0
- package/dist/{types-C1KKK4VP.d.mts → types-DaqNzqVt.d.mts} +16 -1
- package/dist/{types-C1KKK4VP.d.mts.map → types-DaqNzqVt.d.mts.map} +1 -1
- package/dist/{types-DW1l0gCv.d.mts → types-Dgo6y-Ut.d.mts} +1 -1
- package/dist/{types-DW1l0gCv.d.mts.map → types-Dgo6y-Ut.d.mts.map} +1 -1
- package/dist/{types-Cb2UCDJg.d.mts → types-bYmRn_Uy.d.mts} +1 -1
- package/dist/{types-Cb2UCDJg.d.mts.map → types-bYmRn_Uy.d.mts.map} +1 -1
- package/dist/{user-Dr1bOCqS.mjs → user-D3BD5zdT.mjs} +2 -2
- package/dist/{user-Dr1bOCqS.mjs.map → user-D3BD5zdT.mjs.map} +1 -1
- package/dist/{utils-_F-rWBTN.mjs → utils-C3wTAP-P.mjs} +1 -1
- package/dist/{utils-_F-rWBTN.mjs.map → utils-C3wTAP-P.mjs.map} +1 -1
- package/dist/{validate-BpQGsmd7.d.mts → validate-DQtHw9NT.d.mts} +5 -5
- package/dist/{validate-BpQGsmd7.d.mts.map → validate-DQtHw9NT.d.mts.map} +1 -1
- package/dist/{validate-DlFxcVVK.mjs → validate-mz87i8_1.mjs} +2 -2
- package/dist/{validate-DlFxcVVK.mjs.map → validate-mz87i8_1.mjs.map} +1 -1
- package/dist/{validation-BiFJqUp5.mjs → validation-DKHhXjPr.mjs} +5 -5
- package/dist/{validation-BiFJqUp5.mjs.map → validation-DKHhXjPr.mjs.map} +1 -1
- package/dist/version-Ct7C6RSo.mjs +7 -0
- package/dist/{version-Dw7Z5PVU.mjs.map → version-Ct7C6RSo.mjs.map} +1 -1
- package/dist/{widgets-B9j_yzlk.mjs → widgets-lShIQXU5.mjs} +3 -3
- package/dist/widgets-lShIQXU5.mjs.map +1 -0
- package/dist/{zod-generator-DSyz01KE.mjs → zod-generator-dvxgmd1M.mjs} +2 -2
- package/dist/{zod-generator-DSyz01KE.mjs.map → zod-generator-dvxgmd1M.mjs.map} +1 -1
- package/package.json +10 -8
- package/src/api/error.ts +18 -3
- package/src/api/errors.ts +6 -0
- package/src/api/handlers/bylines.ts +161 -0
- package/src/api/handlers/content.ts +125 -43
- package/src/api/handlers/index.ts +6 -0
- package/src/api/handlers/marketplace.ts +27 -5
- package/src/api/handlers/oauth-clients.ts +1 -1
- package/src/api/handlers/registry.ts +568 -22
- package/src/api/openapi/document.ts +1 -1
- package/src/api/schemas/bylines.ts +46 -0
- package/src/astro/integration/index.ts +1 -1
- package/src/astro/integration/routes.ts +5 -0
- package/src/astro/integration/runtime.ts +12 -1
- package/src/astro/integration/virtual-modules.ts +19 -2
- package/src/astro/integration/vite-config.ts +2 -2
- package/src/astro/middleware/auth.ts +7 -7
- package/src/astro/middleware/request-context.ts +1 -1
- package/src/astro/middleware.ts +31 -20
- package/src/astro/routes/api/admin/bylines/[id]/index.ts +3 -12
- package/src/astro/routes/api/admin/bylines/[id]/translations.ts +99 -0
- package/src/astro/routes/api/admin/bylines/index.ts +22 -11
- package/src/astro/routes/api/admin/plugins/[id]/update.ts +1 -0
- package/src/astro/routes/api/admin/plugins/marketplace/[id]/install.ts +6 -1
- package/src/astro/routes/api/admin/plugins/registry/[id]/uninstall.ts +51 -0
- package/src/astro/routes/api/admin/plugins/registry/[id]/update.ts +79 -0
- package/src/astro/routes/api/admin/plugins/updates.ts +43 -6
- package/src/astro/routes/api/admin/themes/marketplace/index.ts +1 -1
- package/src/astro/routes/api/auth/oauth/[provider]/callback.ts +2 -2
- package/src/astro/routes/api/auth/oauth/[provider].ts +2 -2
- package/src/astro/routes/api/content/[collection]/[id]/discard-draft.ts +2 -2
- package/src/astro/routes/api/content/[collection]/[id]/duplicate.ts +2 -2
- package/src/astro/routes/api/content/[collection]/[id]/publish.ts +2 -2
- package/src/astro/routes/api/content/[collection]/[id]/restore.ts +2 -2
- package/src/astro/routes/api/content/[collection]/[id]/schedule.ts +2 -2
- package/src/astro/routes/api/content/[collection]/[id]/terms/[taxonomy].ts +6 -6
- package/src/astro/routes/api/content/[collection]/[id]/translations.ts +1 -1
- package/src/astro/routes/api/content/[collection]/[id]/unpublish.ts +2 -2
- package/src/astro/routes/api/content/[collection]/[id].ts +6 -6
- package/src/astro/routes/api/import/wordpress/execute.ts +1 -1
- package/src/astro/routes/api/import/wordpress/prepare.ts +2 -2
- package/src/astro/routes/api/import/wordpress/rewrite-urls.ts +3 -3
- package/src/astro/routes/api/import/wordpress-plugin/execute.ts +2 -2
- package/src/astro/routes/api/media/upload-url.ts +1 -1
- package/src/astro/routes/api/redirects/404s/index.ts +3 -3
- package/src/astro/routes/api/redirects/404s/summary.ts +1 -1
- package/src/astro/routes/api/redirects/[id].ts +3 -3
- package/src/astro/routes/api/redirects/index.ts +2 -2
- package/src/astro/routes/api/schema/collections/[slug]/fields/[fieldSlug].ts +4 -4
- package/src/astro/routes/api/schema/collections/[slug]/fields/index.ts +2 -6
- package/src/astro/routes/api/schema/collections/[slug]/fields/reorder.ts +1 -1
- package/src/astro/routes/api/schema/collections/[slug]/index.ts +6 -6
- package/src/astro/routes/api/schema/collections/index.ts +4 -4
- package/src/astro/routes/api/schema/index.ts +1 -1
- package/src/astro/routes/api/schema/orphans/[slug].ts +1 -1
- package/src/astro/routes/api/schema/orphans/index.ts +1 -1
- package/src/astro/routes/api/sections/[slug].ts +3 -3
- package/src/astro/routes/api/sections/index.ts +2 -2
- package/src/astro/types.ts +4 -0
- package/src/auth/rate-limit.ts +1 -1
- package/src/auth/trusted-proxy.ts +1 -1
- package/src/bylines/index.ts +154 -55
- package/src/cli/commands/init.ts +4 -8
- package/src/client/index.ts +1 -1
- package/src/components/InlinePortableTextEditor.tsx +5 -1
- package/src/components/inline-code-block.tsx +343 -0
- package/src/config/secrets.ts +3 -3
- package/src/database/migrations/006_taxonomy_defs.ts +1 -1
- package/src/database/migrations/014_draft_revisions.ts +6 -6
- package/src/database/migrations/040_byline_i18n.ts +497 -0
- package/src/database/migrations/runner.ts +4 -1
- package/src/database/repositories/audit.ts +2 -2
- package/src/database/repositories/byline.ts +320 -50
- package/src/database/repositories/media.ts +2 -2
- package/src/database/repositories/menu.ts +1 -1
- package/src/database/repositories/options.ts +3 -3
- package/src/database/repositories/plugin-storage.ts +3 -3
- package/src/database/repositories/types.ts +13 -0
- package/src/database/types.ts +15 -0
- package/src/emdash-runtime.ts +492 -20
- package/src/i18n/config.ts +1 -1
- package/src/index.ts +7 -0
- package/src/loader.ts +1 -1
- package/src/mcp/server.ts +3 -3
- package/src/media/mime.ts +1 -1
- package/src/page/absolute-url.ts +1 -1
- package/src/plugins/adapt-sandbox-entry.ts +45 -40
- package/src/plugins/email-console.ts +1 -1
- package/src/plugins/index.ts +1 -0
- package/src/plugins/marketplace.ts +1 -1
- package/src/plugins/sandbox/index.ts +1 -0
- package/src/plugins/sandbox/noop.ts +11 -3
- package/src/plugins/sandbox/types.ts +28 -0
- package/src/query.ts +17 -2
- package/src/registry/config.ts +1 -1
- package/src/request-cache.ts +3 -3
- package/src/request-context.ts +1 -1
- package/src/settings/index.ts +4 -4
- package/src/storage/local.ts +1 -1
- package/src/storage/s3.ts +3 -3
- package/src/widgets/index.ts +1 -1
- package/dist/api-ayIQ7rIe.mjs.map +0 -1
- package/dist/byline-D09BaS4j.mjs +0 -220
- package/dist/byline-D09BaS4j.mjs.map +0 -1
- package/dist/bylines-BTM2xtP8.mjs +0 -113
- package/dist/bylines-BTM2xtP8.mjs.map +0 -1
- package/dist/bylines-C6eYUWlZ.d.mts.map +0 -1
- package/dist/context-qF8d3IPR.mjs.map +0 -1
- package/dist/email-console-Dmp5Q-P2.mjs.map +0 -1
- package/dist/error-tSQWIl5U.mjs.map +0 -1
- package/dist/index-UmOMt9T-.d.mts.map +0 -1
- package/dist/loader-Cs6-Bqe6.mjs.map +0 -1
- package/dist/media-Dg7he9uK.mjs.map +0 -1
- package/dist/menus-DOzIecHi.mjs.map +0 -1
- package/dist/menus-X4Z-eBA1.mjs.map +0 -1
- package/dist/oauth-clients-D_B0_-Bz.mjs.map +0 -1
- package/dist/options-Cq64Wx0O.d.mts.map +0 -1
- package/dist/redirects-Dmj6KRU3.mjs.map +0 -1
- package/dist/runner-DdnQIwz_.mjs.map +0 -1
- package/dist/settings-xQKsWnzQ.mjs.map +0 -1
- package/dist/taxonomies-Cn9UpaR2.mjs.map +0 -1
- package/dist/types-CwXMEPRr.mjs.map +0 -1
- package/dist/types-CzvJd1ND.d.mts.map +0 -1
- package/dist/version-Dw7Z5PVU.mjs +0 -7
- package/dist/widgets-B9j_yzlk.mjs.map +0 -1
- /package/dist/{api-tokens-D3C9v02m.mjs → api-tokens-iPIHAY8N.mjs} +0 -0
- /package/dist/{ssrf-CTul4uQi.mjs → ssrf-BIcd-aXW.mjs} +0 -0
- /package/dist/{types-Db67HHlU.mjs → types-1NNkmTIn.mjs} +0 -0
package/src/emdash-runtime.ts
CHANGED
|
@@ -247,11 +247,21 @@ export interface RuntimeDependencies {
|
|
|
247
247
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
248
248
|
createStorage: ((config: any) => Storage) | null;
|
|
249
249
|
sandboxEnabled: boolean;
|
|
250
|
+
/** sandbox: false escape hatch - load sandboxed plugins in-process */
|
|
251
|
+
sandboxBypassed?: boolean;
|
|
250
252
|
/** Media provider entries from virtual module */
|
|
251
253
|
mediaProviderEntries?: MediaProviderEntry[];
|
|
252
254
|
sandboxedPluginEntries: SandboxedPluginEntry[];
|
|
253
255
|
/** Factory function matching SandboxRunnerFactory signature */
|
|
254
|
-
createSandboxRunner:
|
|
256
|
+
createSandboxRunner:
|
|
257
|
+
| ((opts: {
|
|
258
|
+
db: Kysely<Database>;
|
|
259
|
+
mediaStorage?: {
|
|
260
|
+
upload(options: { key: string; body: Uint8Array; contentType: string }): Promise<unknown>;
|
|
261
|
+
delete(key: string): Promise<unknown>;
|
|
262
|
+
};
|
|
263
|
+
}) => SandboxRunner)
|
|
264
|
+
| null;
|
|
255
265
|
}
|
|
256
266
|
|
|
257
267
|
/**
|
|
@@ -393,7 +403,7 @@ export class EmDashRuntime {
|
|
|
393
403
|
get db(): Kysely<Database> {
|
|
394
404
|
const ctx = getRequestContext();
|
|
395
405
|
if (ctx?.db) {
|
|
396
|
-
// eslint-disable-next-line typescript
|
|
406
|
+
// eslint-disable-next-line typescript/no-unsafe-type-assertion -- db in context is set by middleware with correct type
|
|
397
407
|
return ctx.db as Kysely<Database>;
|
|
398
408
|
}
|
|
399
409
|
return this._db;
|
|
@@ -428,6 +438,16 @@ export class EmDashRuntime {
|
|
|
428
438
|
return sandboxRunner;
|
|
429
439
|
}
|
|
430
440
|
|
|
441
|
+
/**
|
|
442
|
+
* Whether the sandbox bypass mode (sandbox: false) is active.
|
|
443
|
+
* Marketplace install/update handlers use this to skip the
|
|
444
|
+
* SANDBOX_NOT_AVAILABLE gate, since the bypass path loads
|
|
445
|
+
* marketplace plugins in-process via syncMarketplacePlugins().
|
|
446
|
+
*/
|
|
447
|
+
isSandboxBypassed(): boolean {
|
|
448
|
+
return this.runtimeDeps.sandboxBypassed === true;
|
|
449
|
+
}
|
|
450
|
+
|
|
431
451
|
/**
|
|
432
452
|
* Tick the cron system from request context (piggyback mode).
|
|
433
453
|
* Call this from middleware on each request to ensure cron tasks
|
|
@@ -519,6 +539,17 @@ export class EmDashRuntime {
|
|
|
519
539
|
*/
|
|
520
540
|
async syncMarketplacePlugins(): Promise<void> {
|
|
521
541
|
if (!this.config.marketplace) return;
|
|
542
|
+
|
|
543
|
+
// In sandbox bypass mode (sandbox: false), the noop runner reports
|
|
544
|
+
// unavailable but we still want admin metadata for newly installed
|
|
545
|
+
// marketplace plugins to refresh in-process. Hooks/routes still won't
|
|
546
|
+
// execute (matches the cold-start bypass behavior), but Configure
|
|
547
|
+
// links and admin pages appear immediately.
|
|
548
|
+
if (this.runtimeDeps.sandboxBypassed) {
|
|
549
|
+
await this.syncMarketplacePluginsBypassed();
|
|
550
|
+
return;
|
|
551
|
+
}
|
|
552
|
+
|
|
522
553
|
await this.syncSandboxedSourcePlugins("marketplace");
|
|
523
554
|
}
|
|
524
555
|
|
|
@@ -537,8 +568,8 @@ export class EmDashRuntime {
|
|
|
537
568
|
/**
|
|
538
569
|
* Internal: reconcile in-memory sandboxed-plugin state with the
|
|
539
570
|
* `_plugin_state` table for the given source tier. Shared
|
|
540
|
-
* implementation behind
|
|
541
|
-
*
|
|
571
|
+
* implementation behind {@link syncMarketplacePlugins} and
|
|
572
|
+
* {@link syncRegistryPlugins}.
|
|
542
573
|
*
|
|
543
574
|
* Each source tier has its own key set in `${source}PluginKeys` so a
|
|
544
575
|
* sync for one tier doesn't invalidate the other.
|
|
@@ -652,6 +683,173 @@ export class EmDashRuntime {
|
|
|
652
683
|
}
|
|
653
684
|
}
|
|
654
685
|
|
|
686
|
+
/**
|
|
687
|
+
* Remove a plugin from the in-memory pipeline lists by ID.
|
|
688
|
+
* Mutates allPipelinePlugins and configuredPlugins in place.
|
|
689
|
+
*/
|
|
690
|
+
private removePluginFromLists(pluginId: string): void {
|
|
691
|
+
const allIdx = this.allPipelinePlugins.findIndex((p) => p.id === pluginId);
|
|
692
|
+
if (allIdx !== -1) this.allPipelinePlugins.splice(allIdx, 1);
|
|
693
|
+
const configIdx = this.configuredPlugins.findIndex((p) => p.id === pluginId);
|
|
694
|
+
if (configIdx !== -1) this.configuredPlugins.splice(configIdx, 1);
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
/**
|
|
698
|
+
* Sync marketplace plugin metadata in sandbox: false bypass mode.
|
|
699
|
+
*
|
|
700
|
+
* In bypass mode the noop runner can't load plugins, but admin pages,
|
|
701
|
+
* widgets, and route metadata still need to refresh in-process when an
|
|
702
|
+
* admin installs/updates/uninstalls a marketplace plugin. Otherwise the
|
|
703
|
+
* admin UI shows stale data until the server restarts.
|
|
704
|
+
*
|
|
705
|
+
* Hooks and routes still won't execute under bypass (matches the
|
|
706
|
+
* cold-start bypass behavior in loadMarketplacePluginsBypassed).
|
|
707
|
+
*
|
|
708
|
+
* Known limitation: bypass plugins are loaded via `import(dataUrl)`,
|
|
709
|
+
* which Node's ESM cache keys on the full URL. Updates create fresh
|
|
710
|
+
* module objects, but old ones remain cached for the worker's lifetime.
|
|
711
|
+
* In practice this is a few KB per update — only matters for sites with
|
|
712
|
+
* very frequent marketplace updates running long-lived processes. The
|
|
713
|
+
* fix would be vm.SourceTextModule for explicit lifecycle management.
|
|
714
|
+
*/
|
|
715
|
+
private async syncMarketplacePluginsBypassed(): Promise<void> {
|
|
716
|
+
if (!this.storage) return;
|
|
717
|
+
try {
|
|
718
|
+
const stateRepo = new PluginStateRepository(this.db);
|
|
719
|
+
const marketplaceStates = await stateRepo.getMarketplacePlugins();
|
|
720
|
+
|
|
721
|
+
const desired = new Map<string, string>();
|
|
722
|
+
for (const state of marketplaceStates) {
|
|
723
|
+
this.pluginStates.set(state.pluginId, state.status);
|
|
724
|
+
if (state.status === "active") {
|
|
725
|
+
this.enabledPlugins.add(state.pluginId);
|
|
726
|
+
} else {
|
|
727
|
+
this.enabledPlugins.delete(state.pluginId);
|
|
728
|
+
}
|
|
729
|
+
if (state.status !== "active") continue;
|
|
730
|
+
desired.set(state.pluginId, state.marketplaceVersion ?? state.version);
|
|
731
|
+
}
|
|
732
|
+
|
|
733
|
+
// Drop metadata for plugins no longer active.
|
|
734
|
+
const toRemove: string[] = [];
|
|
735
|
+
for (const pluginId of marketplaceManifestCache.keys()) {
|
|
736
|
+
if (!desired.has(pluginId)) toRemove.push(pluginId);
|
|
737
|
+
}
|
|
738
|
+
for (const pluginId of toRemove) {
|
|
739
|
+
// Fire plugin:deactivate hook before removal
|
|
740
|
+
const resolved = this.allPipelinePlugins.find((p) => p.id === pluginId);
|
|
741
|
+
if (resolved) {
|
|
742
|
+
try {
|
|
743
|
+
const deactivateHook = resolved.hooks?.["plugin:deactivate"];
|
|
744
|
+
if (deactivateHook) {
|
|
745
|
+
const handler =
|
|
746
|
+
typeof deactivateHook === "function" ? deactivateHook : deactivateHook.handler;
|
|
747
|
+
if (typeof handler === "function") {
|
|
748
|
+
// Sandbox-bypass cleanup: the plugin context isn't constructable
|
|
749
|
+
// here (no DB binding, no media, etc.), but well-behaved
|
|
750
|
+
// deactivate hooks should be no-op safe. If a hook does require
|
|
751
|
+
// ctx, it throws and the surrounding catch logs it.
|
|
752
|
+
// eslint-disable-next-line typescript-eslint/no-unsafe-type-assertion -- best-effort cleanup; see comment above
|
|
753
|
+
await handler({ pluginId }, {} as never);
|
|
754
|
+
}
|
|
755
|
+
}
|
|
756
|
+
} catch (err) {
|
|
757
|
+
console.warn(`[emdash] plugin:deactivate hook failed for ${pluginId}:`, err);
|
|
758
|
+
}
|
|
759
|
+
}
|
|
760
|
+
marketplaceManifestCache.delete(pluginId);
|
|
761
|
+
sandboxedRouteMetaCache.delete(pluginId);
|
|
762
|
+
// Remove from pipeline lists too (mutate in place since the
|
|
763
|
+
// arrays are readonly references but mutable contents)
|
|
764
|
+
this.removePluginFromLists(pluginId);
|
|
765
|
+
this.enabledPlugins.delete(pluginId);
|
|
766
|
+
}
|
|
767
|
+
|
|
768
|
+
// Load plugin code, adapt as trusted plugins, and add to pipeline lists
|
|
769
|
+
const { adaptSandboxEntry } = await import("./plugins/adapt-sandbox-entry.js");
|
|
770
|
+
const newPlugins: ResolvedPlugin[] = [];
|
|
771
|
+
for (const [pluginId, version] of desired) {
|
|
772
|
+
const bundle = await loadBundleFromR2(this.storage, pluginId, version);
|
|
773
|
+
if (!bundle) {
|
|
774
|
+
console.warn(`EmDash: Marketplace plugin ${pluginId}@${version} not found in R2`);
|
|
775
|
+
continue;
|
|
776
|
+
}
|
|
777
|
+
marketplaceManifestCache.set(pluginId, {
|
|
778
|
+
id: bundle.manifest.id,
|
|
779
|
+
version: bundle.manifest.version,
|
|
780
|
+
admin: bundle.manifest.admin,
|
|
781
|
+
});
|
|
782
|
+
if (bundle.manifest.routes.length > 0) {
|
|
783
|
+
const routeMetaMap = new Map<string, RouteMeta>();
|
|
784
|
+
for (const entry of bundle.manifest.routes) {
|
|
785
|
+
const normalized = normalizeManifestRoute(entry);
|
|
786
|
+
routeMetaMap.set(normalized.name, { public: normalized.public === true });
|
|
787
|
+
}
|
|
788
|
+
sandboxedRouteMetaCache.set(pluginId, routeMetaMap);
|
|
789
|
+
} else {
|
|
790
|
+
sandboxedRouteMetaCache.delete(pluginId);
|
|
791
|
+
}
|
|
792
|
+
|
|
793
|
+
// Skip if already in the pipeline at this version
|
|
794
|
+
const existing = this.allPipelinePlugins.find((p) => p.id === pluginId);
|
|
795
|
+
if (existing && existing.version === bundle.manifest.version) continue;
|
|
796
|
+
|
|
797
|
+
// Remove any older version
|
|
798
|
+
if (existing) {
|
|
799
|
+
this.removePluginFromLists(pluginId);
|
|
800
|
+
}
|
|
801
|
+
|
|
802
|
+
try {
|
|
803
|
+
const dataUrl = `data:text/javascript;base64,${Buffer.from(bundle.backendCode).toString("base64")}`;
|
|
804
|
+
// Dynamic data: import returns `any` from a base64-encoded module.
|
|
805
|
+
// We trust the bundle to be shaped like a plugin (built by plugin-cli);
|
|
806
|
+
// adaptSandboxEntry then validates fields it cares about.
|
|
807
|
+
// eslint-disable-next-line typescript-eslint/no-unsafe-type-assertion -- dynamic module from trusted bundle
|
|
808
|
+
const pluginModule = (await import(/* @vite-ignore */ dataUrl)) as Record<
|
|
809
|
+
string,
|
|
810
|
+
unknown
|
|
811
|
+
>;
|
|
812
|
+
const pluginDef = (pluginModule.default ?? pluginModule) as Parameters<
|
|
813
|
+
typeof adaptSandboxEntry
|
|
814
|
+
>[0];
|
|
815
|
+
const adapted = adaptSandboxEntry(pluginDef, {
|
|
816
|
+
id: bundle.manifest.id,
|
|
817
|
+
version: bundle.manifest.version,
|
|
818
|
+
entrypoint: "",
|
|
819
|
+
capabilities: bundle.manifest.capabilities ?? [],
|
|
820
|
+
allowedHosts: bundle.manifest.allowedHosts ?? [],
|
|
821
|
+
// eslint-disable-next-line typescript-eslint/no-unsafe-type-assertion -- adaptSandboxEntry copies storage through
|
|
822
|
+
storage: (bundle.manifest.storage ?? {}) as never,
|
|
823
|
+
adminPages: bundle.manifest.admin?.pages,
|
|
824
|
+
adminWidgets: bundle.manifest.admin?.widgets?.map((w) => ({
|
|
825
|
+
id: w.id,
|
|
826
|
+
title: w.title,
|
|
827
|
+
size:
|
|
828
|
+
w.size === "full" || w.size === "half" || w.size === "third" ? w.size : undefined,
|
|
829
|
+
})),
|
|
830
|
+
});
|
|
831
|
+
newPlugins.push(adapted);
|
|
832
|
+
this.allPipelinePlugins.push(adapted);
|
|
833
|
+
this.configuredPlugins.push(adapted);
|
|
834
|
+
this.enabledPlugins.add(adapted.id);
|
|
835
|
+
} catch (error) {
|
|
836
|
+
console.error(
|
|
837
|
+
`EmDash: Failed to load marketplace plugin ${pluginId}@${version} in-process:`,
|
|
838
|
+
error,
|
|
839
|
+
);
|
|
840
|
+
}
|
|
841
|
+
}
|
|
842
|
+
|
|
843
|
+
// If anything changed, rebuild the hook pipeline so new/removed
|
|
844
|
+
// plugins take effect immediately without a server restart.
|
|
845
|
+
if (toRemove.length > 0 || newPlugins.length > 0) {
|
|
846
|
+
await this.rebuildHookPipeline();
|
|
847
|
+
}
|
|
848
|
+
} catch (error) {
|
|
849
|
+
console.error("EmDash: Failed to sync marketplace plugins (bypass):", error);
|
|
850
|
+
}
|
|
851
|
+
}
|
|
852
|
+
|
|
655
853
|
/**
|
|
656
854
|
* Create and initialize the runtime
|
|
657
855
|
*/
|
|
@@ -737,6 +935,11 @@ export class EmDashRuntime {
|
|
|
737
935
|
// rebuildHookPipeline() filters this to only enabled plugins.
|
|
738
936
|
const allPipelinePlugins: ResolvedPlugin[] = [...deps.plugins];
|
|
739
937
|
|
|
938
|
+
// Collected bypassed plugins (sandbox: false escape hatch).
|
|
939
|
+
// These need to be added to BOTH the pipeline (for hooks) AND the
|
|
940
|
+
// configuredPlugins list (for route dispatch).
|
|
941
|
+
const bypassedPluginsList: ResolvedPlugin[] = [];
|
|
942
|
+
|
|
740
943
|
// In dev mode, register a built-in console email provider.
|
|
741
944
|
// It participates in exclusive hook resolution like any other plugin —
|
|
742
945
|
// auto-selected when it's the sole provider, overridden when a real one is configured.
|
|
@@ -784,6 +987,53 @@ export class EmDashRuntime {
|
|
|
784
987
|
console.warn("[comments] Failed to register default moderator:", error);
|
|
785
988
|
}
|
|
786
989
|
|
|
990
|
+
// sandbox: false escape hatch - load sandboxed plugin entries in-process
|
|
991
|
+
// as trusted plugins (no isolation) so they participate in the hook pipeline.
|
|
992
|
+
// Block this on Cloudflare Workers where dynamic import(dataUrl) is not
|
|
993
|
+
// available and running untrusted code in-process is a security risk.
|
|
994
|
+
if (deps.sandboxBypassed && deps.sandboxedPluginEntries.length > 0) {
|
|
995
|
+
const isCfWorkers =
|
|
996
|
+
typeof navigator !== "undefined" &&
|
|
997
|
+
typeof navigator.userAgent === "string" &&
|
|
998
|
+
navigator.userAgent.includes("Cloudflare-Workers");
|
|
999
|
+
if (isCfWorkers) {
|
|
1000
|
+
throw new Error(
|
|
1001
|
+
"sandbox: false is not supported in Cloudflare Workers. " +
|
|
1002
|
+
"Remove the sandbox: false option or use the Cloudflare sandbox runner.",
|
|
1003
|
+
);
|
|
1004
|
+
}
|
|
1005
|
+
console.info(
|
|
1006
|
+
"EmDash: Sandbox disabled (sandbox: false). " +
|
|
1007
|
+
"Sandboxed plugins will run in-process without isolation.",
|
|
1008
|
+
);
|
|
1009
|
+
const bypassedPlugins = await EmDashRuntime.loadBypassedPlugins(deps.sandboxedPluginEntries);
|
|
1010
|
+
for (const plugin of bypassedPlugins) {
|
|
1011
|
+
allPipelinePlugins.push(plugin);
|
|
1012
|
+
bypassedPluginsList.push(plugin);
|
|
1013
|
+
// Respect plugin state: only enable if active or no record exists.
|
|
1014
|
+
// Plugins an admin previously disabled should stay disabled.
|
|
1015
|
+
const status = pluginStates.get(plugin.id);
|
|
1016
|
+
if (status === undefined || status === "active") {
|
|
1017
|
+
enabledPlugins.add(plugin.id);
|
|
1018
|
+
}
|
|
1019
|
+
}
|
|
1020
|
+
}
|
|
1021
|
+
|
|
1022
|
+
// In bypass mode, also load marketplace plugins from R2 as trusted
|
|
1023
|
+
// in-process plugins BEFORE pipeline creation. They need to be in the
|
|
1024
|
+
// pipeline to participate in hook dispatch.
|
|
1025
|
+
if (deps.sandboxBypassed && deps.config.marketplace && storage) {
|
|
1026
|
+
const marketplaceBypassed = await EmDashRuntime.loadMarketplacePluginsBypassed(db, storage);
|
|
1027
|
+
for (const plugin of marketplaceBypassed) {
|
|
1028
|
+
allPipelinePlugins.push(plugin);
|
|
1029
|
+
bypassedPluginsList.push(plugin);
|
|
1030
|
+
const status = pluginStates.get(plugin.id);
|
|
1031
|
+
if (status === undefined || status === "active") {
|
|
1032
|
+
enabledPlugins.add(plugin.id);
|
|
1033
|
+
}
|
|
1034
|
+
}
|
|
1035
|
+
}
|
|
1036
|
+
|
|
787
1037
|
// Filter to currently enabled plugins for the initial pipeline
|
|
788
1038
|
const enabledPluginList = allPipelinePlugins.filter((p) => enabledPlugins.has(p.id));
|
|
789
1039
|
|
|
@@ -795,13 +1045,14 @@ export class EmDashRuntime {
|
|
|
795
1045
|
};
|
|
796
1046
|
const pipeline = createHookPipeline(enabledPluginList, pipelineFactoryOptions);
|
|
797
1047
|
|
|
798
|
-
// Load sandboxed plugins (build-time)
|
|
1048
|
+
// Load sandboxed plugins (build-time, sandbox runner path)
|
|
799
1049
|
const sandboxedPlugins = await phase("rt.sandbox", "Sandboxed plugins", () =>
|
|
800
|
-
EmDashRuntime.loadSandboxedPlugins(deps, db),
|
|
1050
|
+
EmDashRuntime.loadSandboxedPlugins(deps, db, storage),
|
|
801
1051
|
);
|
|
802
1052
|
|
|
803
|
-
// Cold-start: load marketplace-installed plugins from site R2
|
|
804
|
-
|
|
1053
|
+
// Cold-start: load marketplace-installed plugins from site R2 via
|
|
1054
|
+
// the sandbox runner. In bypass mode this was already handled above.
|
|
1055
|
+
if (deps.config.marketplace && storage && !deps.sandboxBypassed) {
|
|
805
1056
|
await phase("rt.market", "Marketplace plugins", () =>
|
|
806
1057
|
EmDashRuntime.loadInstalledSandboxedPlugins(
|
|
807
1058
|
"marketplace",
|
|
@@ -942,7 +1193,10 @@ export class EmDashRuntime {
|
|
|
942
1193
|
return new EmDashRuntime({
|
|
943
1194
|
db,
|
|
944
1195
|
storage,
|
|
945
|
-
configuredPlugins
|
|
1196
|
+
// Include bypassed sandboxed plugins in configuredPlugins so route
|
|
1197
|
+
// dispatch can find them under sandbox: false (they're treated as
|
|
1198
|
+
// trusted plugins for the duration of the bypass).
|
|
1199
|
+
configuredPlugins: [...deps.plugins, ...bypassedPluginsList],
|
|
946
1200
|
sandboxedPlugins,
|
|
947
1201
|
sandboxedPluginEntries: deps.sandboxedPluginEntries,
|
|
948
1202
|
hooks: pipeline,
|
|
@@ -997,7 +1251,7 @@ export class EmDashRuntime {
|
|
|
997
1251
|
// path gives us a fresh singleton instead.
|
|
998
1252
|
const ctx = getRequestContext();
|
|
999
1253
|
if (ctx?.dbIsIsolated && ctx.db) {
|
|
1000
|
-
// eslint-disable-next-line typescript
|
|
1254
|
+
// eslint-disable-next-line typescript/no-unsafe-type-assertion -- db in context is typed as unknown to avoid circular deps
|
|
1001
1255
|
return ctx.db as Kysely<Database>;
|
|
1002
1256
|
}
|
|
1003
1257
|
|
|
@@ -1115,12 +1369,84 @@ export class EmDashRuntime {
|
|
|
1115
1369
|
return storage;
|
|
1116
1370
|
}
|
|
1117
1371
|
|
|
1372
|
+
/**
|
|
1373
|
+
* Load sandboxed plugin entries as trusted in-process plugins.
|
|
1374
|
+
* Used by the sandbox: false debugging escape hatch.
|
|
1375
|
+
*
|
|
1376
|
+
* Imports each plugin's bundled ESM code via a data URL, adapts it
|
|
1377
|
+
* with adaptSandboxEntry, and returns ResolvedPlugin objects ready
|
|
1378
|
+
* to be merged into the pipeline plugin list.
|
|
1379
|
+
*/
|
|
1380
|
+
private static async loadBypassedPlugins(
|
|
1381
|
+
entries: SandboxedPluginEntry[],
|
|
1382
|
+
): Promise<ResolvedPlugin[]> {
|
|
1383
|
+
const { adaptSandboxEntry } = await import("./plugins/adapt-sandbox-entry.js");
|
|
1384
|
+
const plugins: ResolvedPlugin[] = [];
|
|
1385
|
+
for (const entry of entries) {
|
|
1386
|
+
try {
|
|
1387
|
+
const dataUrl = `data:text/javascript;base64,${Buffer.from(entry.code).toString("base64")}`;
|
|
1388
|
+
// eslint-disable-next-line typescript-eslint/no-unsafe-type-assertion -- dynamic module from trusted bundle (built by plugin-cli); adaptSandboxEntry validates required fields.
|
|
1389
|
+
const pluginModule = (await import(/* @vite-ignore */ dataUrl)) as Record<string, unknown>;
|
|
1390
|
+
const pluginDef = (pluginModule.default ?? pluginModule) as Parameters<
|
|
1391
|
+
typeof adaptSandboxEntry
|
|
1392
|
+
>[0];
|
|
1393
|
+
// PluginDescriptor.storage's TypeScript type is narrower than what
|
|
1394
|
+
// adaptSandboxEntry actually accepts at runtime — it copies indexes
|
|
1395
|
+
// through to PluginStorageConfig which supports composite indexes
|
|
1396
|
+
// (string[][]). Pass the raw entry.storage with a structural cast
|
|
1397
|
+
// to preserve composite index declarations.
|
|
1398
|
+
// eslint-disable-next-line typescript-eslint/no-unsafe-type-assertion -- adaptSandboxEntry copies storage through to PluginStorageConfig which supports composite indexes
|
|
1399
|
+
// Preserve admin metadata so plugin-management APIs can derive
|
|
1400
|
+
// hasAdminPages / hasDashboardWidgets correctly. Without this,
|
|
1401
|
+
// the admin UI hides Configure links and dashboard widgets for
|
|
1402
|
+
// bypassed plugins even though they declared them.
|
|
1403
|
+
// SandboxedPluginEntry uses looser types than PluginDescriptor
|
|
1404
|
+
// (label?, size: string), so coerce to the descriptor shape.
|
|
1405
|
+
const adminPages = entry.adminPages?.map((p) => ({
|
|
1406
|
+
path: p.path,
|
|
1407
|
+
label: p.label ?? p.path,
|
|
1408
|
+
icon: p.icon,
|
|
1409
|
+
}));
|
|
1410
|
+
const adminWidgets:
|
|
1411
|
+
| Array<{
|
|
1412
|
+
id: string;
|
|
1413
|
+
title?: string;
|
|
1414
|
+
size?: "full" | "half" | "third";
|
|
1415
|
+
}>
|
|
1416
|
+
| undefined = entry.adminWidgets?.map((w) => {
|
|
1417
|
+
const size: "full" | "half" | "third" | undefined =
|
|
1418
|
+
w.size === "full" || w.size === "half" || w.size === "third" ? w.size : undefined;
|
|
1419
|
+
return { id: w.id, title: w.title, size };
|
|
1420
|
+
});
|
|
1421
|
+
const resolved = adaptSandboxEntry(pluginDef, {
|
|
1422
|
+
id: entry.id,
|
|
1423
|
+
version: entry.version,
|
|
1424
|
+
entrypoint: "",
|
|
1425
|
+
capabilities: entry.capabilities,
|
|
1426
|
+
allowedHosts: entry.allowedHosts,
|
|
1427
|
+
// eslint-disable-next-line typescript-eslint/no-unsafe-type-assertion -- adaptSandboxEntry copies storage through
|
|
1428
|
+
storage: entry.storage as never,
|
|
1429
|
+
adminPages,
|
|
1430
|
+
adminWidgets,
|
|
1431
|
+
});
|
|
1432
|
+
plugins.push(resolved);
|
|
1433
|
+
console.log(
|
|
1434
|
+
`EmDash: Loaded plugin ${entry.id}:${entry.version} in-process (sandbox bypassed)`,
|
|
1435
|
+
);
|
|
1436
|
+
} catch (error) {
|
|
1437
|
+
console.error(`EmDash: Failed to load sandboxed plugin ${entry.id} in-process:`, error);
|
|
1438
|
+
}
|
|
1439
|
+
}
|
|
1440
|
+
return plugins;
|
|
1441
|
+
}
|
|
1442
|
+
|
|
1118
1443
|
/**
|
|
1119
1444
|
* Load sandboxed plugins using SandboxRunner
|
|
1120
1445
|
*/
|
|
1121
1446
|
private static async loadSandboxedPlugins(
|
|
1122
1447
|
deps: RuntimeDependencies,
|
|
1123
1448
|
db: Kysely<Database>,
|
|
1449
|
+
mediaStorage?: Storage | null,
|
|
1124
1450
|
): Promise<Map<string, SandboxedPluginInstance>> {
|
|
1125
1451
|
// Return cached plugins if already loaded
|
|
1126
1452
|
if (sandboxedPluginCache.size > 0) {
|
|
@@ -1128,26 +1454,56 @@ export class EmDashRuntime {
|
|
|
1128
1454
|
}
|
|
1129
1455
|
|
|
1130
1456
|
// Check if sandboxing is enabled
|
|
1131
|
-
if (!deps.sandboxEnabled
|
|
1457
|
+
if (!deps.sandboxEnabled) {
|
|
1132
1458
|
return sandboxedPluginCache;
|
|
1133
1459
|
}
|
|
1134
1460
|
|
|
1135
1461
|
// Create sandbox runner if not exists
|
|
1136
1462
|
if (!sandboxRunner && deps.createSandboxRunner) {
|
|
1137
|
-
sandboxRunner = deps.createSandboxRunner({
|
|
1463
|
+
sandboxRunner = deps.createSandboxRunner({
|
|
1464
|
+
db,
|
|
1465
|
+
mediaStorage: mediaStorage
|
|
1466
|
+
? {
|
|
1467
|
+
upload: (opts) =>
|
|
1468
|
+
mediaStorage.upload({
|
|
1469
|
+
key: opts.key,
|
|
1470
|
+
body: opts.body,
|
|
1471
|
+
contentType: opts.contentType,
|
|
1472
|
+
}),
|
|
1473
|
+
delete: (key) => mediaStorage.delete(key),
|
|
1474
|
+
}
|
|
1475
|
+
: undefined,
|
|
1476
|
+
});
|
|
1138
1477
|
}
|
|
1139
1478
|
|
|
1140
1479
|
if (!sandboxRunner) {
|
|
1141
1480
|
return sandboxedPluginCache;
|
|
1142
1481
|
}
|
|
1143
1482
|
|
|
1144
|
-
// Check if the runner is actually available (has required bindings)
|
|
1483
|
+
// Check if the runner is actually available (has required bindings).
|
|
1484
|
+
// Warn regardless of whether there are plugins to load, so operators
|
|
1485
|
+
// see the issue even if no marketplace plugins are installed yet.
|
|
1145
1486
|
if (!sandboxRunner.isAvailable()) {
|
|
1146
|
-
console.
|
|
1487
|
+
console.warn(
|
|
1488
|
+
"EmDash: Plugin sandbox is configured but not available on this platform. " +
|
|
1489
|
+
"Sandboxed plugins will not be loaded. " +
|
|
1490
|
+
"If using @emdash-cms/sandbox-workerd/sandbox, ensure workerd is installed.",
|
|
1491
|
+
);
|
|
1492
|
+
return sandboxedPluginCache;
|
|
1493
|
+
}
|
|
1494
|
+
|
|
1495
|
+
if (deps.sandboxedPluginEntries.length === 0) {
|
|
1496
|
+
return sandboxedPluginCache;
|
|
1497
|
+
}
|
|
1498
|
+
|
|
1499
|
+
// sandbox: false escape hatch is handled separately (before pipeline
|
|
1500
|
+
// creation) via loadBypassedPlugins. If we somehow reach here with the
|
|
1501
|
+
// flag set, just return — the plugins are already in the trusted pipeline.
|
|
1502
|
+
if (deps.sandboxBypassed) {
|
|
1147
1503
|
return sandboxedPluginCache;
|
|
1148
1504
|
}
|
|
1149
1505
|
|
|
1150
|
-
// Load each sandboxed plugin
|
|
1506
|
+
// Load each sandboxed plugin via sandbox runner
|
|
1151
1507
|
for (const entry of deps.sandboxedPluginEntries) {
|
|
1152
1508
|
const pluginKey = `${entry.id}:${entry.version}`;
|
|
1153
1509
|
if (sandboxedPluginCache.has(pluginKey)) {
|
|
@@ -1201,10 +1557,26 @@ export class EmDashRuntime {
|
|
|
1201
1557
|
deps: RuntimeDependencies,
|
|
1202
1558
|
cache: Map<string, SandboxedPluginInstance>,
|
|
1203
1559
|
): Promise<void> {
|
|
1204
|
-
// Ensure sandbox runner exists
|
|
1560
|
+
// Ensure sandbox runner exists with media storage wired up.
|
|
1561
|
+
// (storage here is the media Storage adapter from the runtime.)
|
|
1205
1562
|
if (!sandboxRunner && deps.createSandboxRunner) {
|
|
1206
|
-
sandboxRunner = deps.createSandboxRunner({
|
|
1563
|
+
sandboxRunner = deps.createSandboxRunner({
|
|
1564
|
+
db,
|
|
1565
|
+
mediaStorage: {
|
|
1566
|
+
upload: (opts) =>
|
|
1567
|
+
storage.upload({
|
|
1568
|
+
key: opts.key,
|
|
1569
|
+
body: opts.body,
|
|
1570
|
+
contentType: opts.contentType,
|
|
1571
|
+
}),
|
|
1572
|
+
delete: (key) => storage.delete(key),
|
|
1573
|
+
},
|
|
1574
|
+
});
|
|
1207
1575
|
}
|
|
1576
|
+
// In sandbox bypass mode, marketplace plugins are loaded in-process
|
|
1577
|
+
// BEFORE pipeline creation by EmDashRuntime.create(). Skip here.
|
|
1578
|
+
if (deps.sandboxBypassed) return;
|
|
1579
|
+
|
|
1208
1580
|
if (!sandboxRunner || !sandboxRunner.isAvailable()) {
|
|
1209
1581
|
return;
|
|
1210
1582
|
}
|
|
@@ -1270,6 +1642,106 @@ export class EmDashRuntime {
|
|
|
1270
1642
|
}
|
|
1271
1643
|
}
|
|
1272
1644
|
|
|
1645
|
+
/**
|
|
1646
|
+
* Cold-start: load marketplace plugins in bypass mode (sandbox: false).
|
|
1647
|
+
*
|
|
1648
|
+
* Each active marketplace bundle is read, evaluated via data URL, adapted
|
|
1649
|
+
* with adaptSandboxEntry, and returned as a ResolvedPlugin. The caller is
|
|
1650
|
+
* responsible for merging these into allPipelinePlugins / configuredPlugins
|
|
1651
|
+
* BEFORE the hook pipeline is created, so hooks and routes register in
|
|
1652
|
+
* the trusted pipeline.
|
|
1653
|
+
*
|
|
1654
|
+
* Also caches manifest and route metadata so admin UI / getManifest() work.
|
|
1655
|
+
*
|
|
1656
|
+
* Returns ResolvedPlugins to be merged into the pipeline.
|
|
1657
|
+
*/
|
|
1658
|
+
private static async loadMarketplacePluginsBypassed(
|
|
1659
|
+
db: Kysely<Database>,
|
|
1660
|
+
storage: Storage,
|
|
1661
|
+
): Promise<ResolvedPlugin[]> {
|
|
1662
|
+
const resolved: ResolvedPlugin[] = [];
|
|
1663
|
+
try {
|
|
1664
|
+
const stateRepo = new PluginStateRepository(db);
|
|
1665
|
+
const marketplacePlugins = await stateRepo.getMarketplacePlugins();
|
|
1666
|
+
if (marketplacePlugins.length === 0) return resolved;
|
|
1667
|
+
|
|
1668
|
+
console.info(
|
|
1669
|
+
"EmDash: Sandbox disabled (sandbox: false). " +
|
|
1670
|
+
"Marketplace plugins will run in-process without isolation.",
|
|
1671
|
+
);
|
|
1672
|
+
|
|
1673
|
+
const { adaptSandboxEntry } = await import("./plugins/adapt-sandbox-entry.js");
|
|
1674
|
+
|
|
1675
|
+
for (const plugin of marketplacePlugins) {
|
|
1676
|
+
if (plugin.status !== "active") continue;
|
|
1677
|
+
const version = plugin.marketplaceVersion ?? plugin.version;
|
|
1678
|
+
try {
|
|
1679
|
+
const bundle = await loadBundleFromR2(storage, plugin.pluginId, version);
|
|
1680
|
+
if (!bundle) {
|
|
1681
|
+
console.warn(
|
|
1682
|
+
`EmDash: Marketplace plugin ${plugin.pluginId}@${version} not found in R2`,
|
|
1683
|
+
);
|
|
1684
|
+
continue;
|
|
1685
|
+
}
|
|
1686
|
+
|
|
1687
|
+
// Cache manifest and route metadata for admin UI and route auth
|
|
1688
|
+
marketplaceManifestCache.set(plugin.pluginId, {
|
|
1689
|
+
id: bundle.manifest.id,
|
|
1690
|
+
version: bundle.manifest.version,
|
|
1691
|
+
admin: bundle.manifest.admin,
|
|
1692
|
+
});
|
|
1693
|
+
if (bundle.manifest.routes.length > 0) {
|
|
1694
|
+
const routeMeta = new Map<string, RouteMeta>();
|
|
1695
|
+
for (const entry of bundle.manifest.routes) {
|
|
1696
|
+
const normalized = normalizeManifestRoute(entry);
|
|
1697
|
+
routeMeta.set(normalized.name, { public: normalized.public === true });
|
|
1698
|
+
}
|
|
1699
|
+
sandboxedRouteMetaCache.set(plugin.pluginId, routeMeta);
|
|
1700
|
+
}
|
|
1701
|
+
|
|
1702
|
+
// Evaluate the bundled ESM and adapt it as a trusted plugin
|
|
1703
|
+
const dataUrl = `data:text/javascript;base64,${Buffer.from(bundle.backendCode).toString("base64")}`;
|
|
1704
|
+
// eslint-disable-next-line typescript-eslint/no-unsafe-type-assertion -- dynamic module from trusted bundle (built by plugin-cli); adaptSandboxEntry validates required fields.
|
|
1705
|
+
const pluginModule = (await import(/* @vite-ignore */ dataUrl)) as Record<
|
|
1706
|
+
string,
|
|
1707
|
+
unknown
|
|
1708
|
+
>;
|
|
1709
|
+
const pluginDef = (pluginModule.default ?? pluginModule) as Parameters<
|
|
1710
|
+
typeof adaptSandboxEntry
|
|
1711
|
+
>[0];
|
|
1712
|
+
const adapted = adaptSandboxEntry(pluginDef, {
|
|
1713
|
+
id: bundle.manifest.id,
|
|
1714
|
+
version: bundle.manifest.version,
|
|
1715
|
+
entrypoint: "",
|
|
1716
|
+
capabilities: bundle.manifest.capabilities ?? [],
|
|
1717
|
+
allowedHosts: bundle.manifest.allowedHosts ?? [],
|
|
1718
|
+
// eslint-disable-next-line typescript-eslint/no-unsafe-type-assertion -- adaptSandboxEntry copies storage through
|
|
1719
|
+
storage: (bundle.manifest.storage ?? {}) as never,
|
|
1720
|
+
adminPages: bundle.manifest.admin?.pages,
|
|
1721
|
+
adminWidgets: bundle.manifest.admin?.widgets?.map((w) => ({
|
|
1722
|
+
id: w.id,
|
|
1723
|
+
title: w.title,
|
|
1724
|
+
size:
|
|
1725
|
+
w.size === "full" || w.size === "half" || w.size === "third" ? w.size : undefined,
|
|
1726
|
+
})),
|
|
1727
|
+
});
|
|
1728
|
+
resolved.push(adapted);
|
|
1729
|
+
console.log(
|
|
1730
|
+
`EmDash: Loaded marketplace plugin ${plugin.pluginId}@${version} in-process (sandbox bypassed)`,
|
|
1731
|
+
);
|
|
1732
|
+
} catch (error) {
|
|
1733
|
+
console.error(
|
|
1734
|
+
`EmDash: Failed to load marketplace plugin ${plugin.pluginId} in-process:`,
|
|
1735
|
+
error,
|
|
1736
|
+
);
|
|
1737
|
+
}
|
|
1738
|
+
}
|
|
1739
|
+
} catch {
|
|
1740
|
+
// _plugin_state table may not exist yet
|
|
1741
|
+
}
|
|
1742
|
+
return resolved;
|
|
1743
|
+
}
|
|
1744
|
+
|
|
1273
1745
|
/**
|
|
1274
1746
|
* Resolve exclusive hook selections on startup.
|
|
1275
1747
|
*
|
|
@@ -1676,7 +2148,7 @@ export class EmDashRuntime {
|
|
|
1676
2148
|
*/
|
|
1677
2149
|
private async hydrateDraftData<T>(result: T): Promise<T> {
|
|
1678
2150
|
if (!result || typeof result !== "object") return result;
|
|
1679
|
-
// eslint-disable-next-line typescript
|
|
2151
|
+
// eslint-disable-next-line typescript/no-unsafe-type-assertion -- shape probed below
|
|
1680
2152
|
const r = result as {
|
|
1681
2153
|
success?: boolean;
|
|
1682
2154
|
data?: { item?: Record<string, unknown> };
|
|
@@ -1690,7 +2162,7 @@ export class EmDashRuntime {
|
|
|
1690
2162
|
if (!revision) return result;
|
|
1691
2163
|
const liveData =
|
|
1692
2164
|
item.data && typeof item.data === "object"
|
|
1693
|
-
? // eslint-disable-next-line typescript
|
|
2165
|
+
? // eslint-disable-next-line typescript/no-unsafe-type-assertion -- narrowed to object above
|
|
1694
2166
|
(item.data as Record<string, unknown>)
|
|
1695
2167
|
: {};
|
|
1696
2168
|
// Strip leading-underscore keys (`_slug`, `_rev`, etc.) from the
|
|
@@ -1711,7 +2183,7 @@ export class EmDashRuntime {
|
|
|
1711
2183
|
// hydrated item without going back through `unknown`.
|
|
1712
2184
|
return {
|
|
1713
2185
|
...result,
|
|
1714
|
-
// eslint-disable-next-line typescript
|
|
2186
|
+
// eslint-disable-next-line typescript/no-unsafe-type-assertion -- shape preserved; result has been narrowed to the {success,data:{item}} envelope
|
|
1715
2187
|
data: {
|
|
1716
2188
|
...r.data,
|
|
1717
2189
|
item: { ...item, data: mergedData, liveData },
|
package/src/i18n/config.ts
CHANGED
|
@@ -51,7 +51,7 @@ export function getFallbackChain(locale: string): string[] {
|
|
|
51
51
|
const visited = new Set<string>([locale]);
|
|
52
52
|
|
|
53
53
|
while (_config.fallback?.[current]) {
|
|
54
|
-
// eslint-disable-next-line typescript
|
|
54
|
+
// eslint-disable-next-line typescript/no-unnecessary-type-assertion -- noUncheckedIndexedAccess
|
|
55
55
|
const next = _config.fallback[current]!;
|
|
56
56
|
if (visited.has(next)) break; // prevent cycles
|
|
57
57
|
chain.push(next);
|
package/src/index.ts
CHANGED
|
@@ -12,6 +12,9 @@ export type {
|
|
|
12
12
|
export {
|
|
13
13
|
ContentRepository,
|
|
14
14
|
MediaRepository,
|
|
15
|
+
PluginStorageRepository,
|
|
16
|
+
UserRepository,
|
|
17
|
+
OptionsRepository,
|
|
15
18
|
EmDashValidationError,
|
|
16
19
|
InvalidCursorError,
|
|
17
20
|
} from "./database/repositories/index.js";
|
|
@@ -198,7 +201,11 @@ export {
|
|
|
198
201
|
// Sandbox
|
|
199
202
|
NoopSandboxRunner,
|
|
200
203
|
SandboxNotAvailableError,
|
|
204
|
+
SandboxUnavailableError,
|
|
201
205
|
createNoopSandboxRunner,
|
|
206
|
+
// HTTP access for plugins (shared between in-process, Cloudflare, and workerd runners)
|
|
207
|
+
createHttpAccess,
|
|
208
|
+
createUnrestrictedHttpAccess,
|
|
202
209
|
} from "./plugins/index.js";
|
|
203
210
|
export type {
|
|
204
211
|
PluginDefinition,
|