emdash 0.0.0-b → 0.0.2
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/README.md +87 -43
- package/dist/adapters-BLMa4JGD.d.mts +106 -0
- package/dist/adapters-BLMa4JGD.d.mts.map +1 -0
- package/dist/apply-Bjfq_b4-.mjs +1293 -0
- package/dist/apply-Bjfq_b4-.mjs.map +1 -0
- package/dist/astro/index.d.mts +51 -0
- package/dist/astro/index.d.mts.map +1 -0
- package/dist/astro/index.mjs +1336 -0
- package/dist/astro/index.mjs.map +1 -0
- package/dist/astro/middleware/auth.d.mts +31 -0
- package/dist/astro/middleware/auth.d.mts.map +1 -0
- package/dist/astro/middleware/auth.mjs +654 -0
- package/dist/astro/middleware/auth.mjs.map +1 -0
- package/dist/astro/middleware/redirect.d.mts +22 -0
- package/dist/astro/middleware/redirect.d.mts.map +1 -0
- package/dist/astro/middleware/redirect.mjs +63 -0
- package/dist/astro/middleware/redirect.mjs.map +1 -0
- package/dist/astro/middleware/request-context.d.mts +18 -0
- package/dist/astro/middleware/request-context.d.mts.map +1 -0
- package/dist/astro/middleware/request-context.mjs +1310 -0
- package/dist/astro/middleware/request-context.mjs.map +1 -0
- package/dist/astro/middleware/setup.d.mts +20 -0
- package/dist/astro/middleware/setup.d.mts.map +1 -0
- package/dist/astro/middleware/setup.mjs +47 -0
- package/dist/astro/middleware/setup.mjs.map +1 -0
- package/dist/astro/middleware.d.mts +13 -0
- package/dist/astro/middleware.d.mts.map +1 -0
- package/dist/astro/middleware.mjs +1613 -0
- package/dist/astro/middleware.mjs.map +1 -0
- package/dist/astro/types.d.mts +250 -0
- package/dist/astro/types.d.mts.map +1 -0
- package/dist/astro/types.mjs +1 -0
- package/dist/base64-MBPo9ozB.mjs +59 -0
- package/dist/base64-MBPo9ozB.mjs.map +1 -0
- package/dist/byline-CL847F26.mjs +213 -0
- package/dist/byline-CL847F26.mjs.map +1 -0
- package/dist/bylines-C2a-2TGt.mjs +136 -0
- package/dist/bylines-C2a-2TGt.mjs.map +1 -0
- package/dist/chunk-ClPoSABd.mjs +21 -0
- package/dist/cli/index.d.mts +1 -0
- package/dist/cli/index.mjs +3909 -0
- package/dist/cli/index.mjs.map +1 -0
- package/dist/client/cf-access.d.mts +60 -0
- package/dist/client/cf-access.d.mts.map +1 -0
- package/dist/client/cf-access.mjs +179 -0
- package/dist/client/cf-access.mjs.map +1 -0
- package/dist/client/index.d.mts +398 -0
- package/dist/client/index.d.mts.map +1 -0
- package/dist/client/index.mjs +346 -0
- package/dist/client/index.mjs.map +1 -0
- package/dist/config-CKE8p9xM.mjs +55 -0
- package/dist/config-CKE8p9xM.mjs.map +1 -0
- package/dist/connection-B4zVnQIa.mjs +40 -0
- package/dist/connection-B4zVnQIa.mjs.map +1 -0
- package/dist/content-D6C2WsZC.mjs +824 -0
- package/dist/content-D6C2WsZC.mjs.map +1 -0
- package/dist/db/index.d.mts +4 -0
- package/dist/db/index.mjs +62 -0
- package/dist/db/index.mjs.map +1 -0
- package/dist/db/libsql.d.mts +11 -0
- package/dist/db/libsql.d.mts.map +1 -0
- package/dist/db/libsql.mjs +17 -0
- package/dist/db/libsql.mjs.map +1 -0
- package/dist/db/postgres.d.mts +11 -0
- package/dist/db/postgres.d.mts.map +1 -0
- package/dist/db/postgres.mjs +30 -0
- package/dist/db/postgres.mjs.map +1 -0
- package/dist/db/sqlite.d.mts +11 -0
- package/dist/db/sqlite.d.mts.map +1 -0
- package/dist/db/sqlite.mjs +16 -0
- package/dist/db/sqlite.mjs.map +1 -0
- package/dist/default-Cyi4aAxu.mjs +81 -0
- package/dist/default-Cyi4aAxu.mjs.map +1 -0
- package/dist/dialect-helpers-B9uSp2GJ.mjs +90 -0
- package/dist/dialect-helpers-B9uSp2GJ.mjs.map +1 -0
- package/dist/error-Cxz0tQeO.mjs +27 -0
- package/dist/error-Cxz0tQeO.mjs.map +1 -0
- package/dist/index-C1xF3OGh.d.mts +4527 -0
- package/dist/index-C1xF3OGh.d.mts.map +1 -0
- package/dist/index.d.mts +16 -0
- package/dist/index.mjs +30 -0
- package/dist/load-yOOlckBj.mjs +28 -0
- package/dist/load-yOOlckBj.mjs.map +1 -0
- package/dist/loader-fz8Q_3EO.mjs +447 -0
- package/dist/loader-fz8Q_3EO.mjs.map +1 -0
- package/dist/manifest-schema-Dcl0R6nM.mjs +184 -0
- package/dist/manifest-schema-Dcl0R6nM.mjs.map +1 -0
- package/dist/media/index.d.mts +26 -0
- package/dist/media/index.d.mts.map +1 -0
- package/dist/media/index.mjs +55 -0
- package/dist/media/index.mjs.map +1 -0
- package/dist/media/local-runtime.d.mts +39 -0
- package/dist/media/local-runtime.d.mts.map +1 -0
- package/dist/media/local-runtime.mjs +133 -0
- package/dist/media/local-runtime.mjs.map +1 -0
- package/dist/media-DqHVh136.mjs +200 -0
- package/dist/media-DqHVh136.mjs.map +1 -0
- package/dist/mode-C2EzN1uE.mjs +23 -0
- package/dist/mode-C2EzN1uE.mjs.map +1 -0
- package/dist/page/index.d.mts +140 -0
- package/dist/page/index.d.mts.map +1 -0
- package/dist/page/index.mjs +416 -0
- package/dist/page/index.mjs.map +1 -0
- package/dist/placeholder-CmGAmqeO.d.mts +276 -0
- package/dist/placeholder-CmGAmqeO.d.mts.map +1 -0
- package/dist/placeholder-SmpOx-_v.mjs +243 -0
- package/dist/placeholder-SmpOx-_v.mjs.map +1 -0
- package/dist/plugin-utils.d.mts +58 -0
- package/dist/plugin-utils.d.mts.map +1 -0
- package/dist/plugin-utils.mjs +78 -0
- package/dist/plugin-utils.mjs.map +1 -0
- package/dist/plugins/adapt-sandbox-entry.d.mts +22 -0
- package/dist/plugins/adapt-sandbox-entry.d.mts.map +1 -0
- package/dist/plugins/adapt-sandbox-entry.mjs +113 -0
- package/dist/plugins/adapt-sandbox-entry.mjs.map +1 -0
- package/dist/query-CS_iSj34.mjs +460 -0
- package/dist/query-CS_iSj34.mjs.map +1 -0
- package/dist/redirect-DIfIni3r.mjs +329 -0
- package/dist/redirect-DIfIni3r.mjs.map +1 -0
- package/dist/registry-D_w5HW4G.mjs +863 -0
- package/dist/registry-D_w5HW4G.mjs.map +1 -0
- package/dist/request-context.d.mts +49 -0
- package/dist/request-context.d.mts.map +1 -0
- package/dist/request-context.mjs +43 -0
- package/dist/request-context.mjs.map +1 -0
- package/dist/runner-C0hCbYnD.mjs +1412 -0
- package/dist/runner-C0hCbYnD.mjs.map +1 -0
- package/dist/runner-EAtf0ZIe.d.mts +27 -0
- package/dist/runner-EAtf0ZIe.d.mts.map +1 -0
- package/dist/runtime.d.mts +26 -0
- package/dist/runtime.d.mts.map +1 -0
- package/dist/runtime.mjs +42 -0
- package/dist/runtime.mjs.map +1 -0
- package/dist/search-DG603UrT.mjs +9211 -0
- package/dist/search-DG603UrT.mjs.map +1 -0
- package/dist/seed/index.d.mts +3 -0
- package/dist/seed/index.mjs +15 -0
- package/dist/seo/index.d.mts +70 -0
- package/dist/seo/index.d.mts.map +1 -0
- package/dist/seo/index.mjs +70 -0
- package/dist/seo/index.mjs.map +1 -0
- package/dist/storage/local.d.mts +39 -0
- package/dist/storage/local.d.mts.map +1 -0
- package/dist/storage/local.mjs +166 -0
- package/dist/storage/local.mjs.map +1 -0
- package/dist/storage/s3.d.mts +32 -0
- package/dist/storage/s3.d.mts.map +1 -0
- package/dist/storage/s3.mjs +175 -0
- package/dist/storage/s3.mjs.map +1 -0
- package/dist/tokens-DpgrkrXK.mjs +171 -0
- package/dist/tokens-DpgrkrXK.mjs.map +1 -0
- package/dist/transport-BFGblqwG.d.mts +42 -0
- package/dist/transport-BFGblqwG.d.mts.map +1 -0
- package/dist/transport-yxiQsi8I.mjs +418 -0
- package/dist/transport-yxiQsi8I.mjs.map +1 -0
- package/dist/types-BRuPJGdV.d.mts +102 -0
- package/dist/types-BRuPJGdV.d.mts.map +1 -0
- package/dist/types-C4-fAxN3.d.mts +182 -0
- package/dist/types-C4-fAxN3.d.mts.map +1 -0
- package/dist/types-CMMN0pNg.mjs +31 -0
- package/dist/types-CMMN0pNg.mjs.map +1 -0
- package/dist/types-CUBbjgmP.mjs +16 -0
- package/dist/types-CUBbjgmP.mjs.map +1 -0
- package/dist/types-DRjfYOEv.d.mts +426 -0
- package/dist/types-DRjfYOEv.d.mts.map +1 -0
- package/dist/types-DY5zk5HN.mjs +73 -0
- package/dist/types-DY5zk5HN.mjs.map +1 -0
- package/dist/types-DaNLHo_T.d.mts +184 -0
- package/dist/types-DaNLHo_T.d.mts.map +1 -0
- package/dist/types-DvhsUmSJ.d.mts +1111 -0
- package/dist/types-DvhsUmSJ.d.mts.map +1 -0
- package/dist/validate-CpBtVMsD.d.mts +378 -0
- package/dist/validate-CpBtVMsD.d.mts.map +1 -0
- package/dist/validate-CqRJb_xU.mjs +97 -0
- package/dist/validate-CqRJb_xU.mjs.map +1 -0
- package/dist/validate-O7PWmlnq.mjs +328 -0
- package/dist/validate-O7PWmlnq.mjs.map +1 -0
- package/locals.d.ts +46 -0
- package/package.json +233 -19
- package/src/api/authorize.ts +63 -0
- package/src/api/csrf.ts +48 -0
- package/src/api/error.ts +99 -0
- package/src/api/errors.ts +445 -0
- package/src/api/escape.ts +9 -0
- package/src/api/handlers/api-tokens.ts +240 -0
- package/src/api/handlers/comments.ts +314 -0
- package/src/api/handlers/content.ts +1315 -0
- package/src/api/handlers/dashboard.ts +205 -0
- package/src/api/handlers/device-flow.ts +684 -0
- package/src/api/handlers/index.ts +163 -0
- package/src/api/handlers/manifest.ts +158 -0
- package/src/api/handlers/marketplace.ts +930 -0
- package/src/api/handlers/media.ts +207 -0
- package/src/api/handlers/menus.ts +493 -0
- package/src/api/handlers/oauth-authorization.ts +429 -0
- package/src/api/handlers/oauth-clients.ts +349 -0
- package/src/api/handlers/oauth-user-lookup.ts +39 -0
- package/src/api/handlers/plugins.ts +254 -0
- package/src/api/handlers/redirects.ts +360 -0
- package/src/api/handlers/revision.ts +145 -0
- package/src/api/handlers/schema.ts +534 -0
- package/src/api/handlers/sections.ts +289 -0
- package/src/api/handlers/seo.ts +115 -0
- package/src/api/handlers/settings.ts +49 -0
- package/src/api/handlers/snapshot.ts +350 -0
- package/src/api/handlers/taxonomies.ts +523 -0
- package/src/api/index.ts +6 -0
- package/src/api/openapi/document.ts +2368 -0
- package/src/api/openapi/index.ts +1 -0
- package/src/api/parse.ts +139 -0
- package/src/api/redirect.ts +14 -0
- package/src/api/rev.ts +67 -0
- package/src/api/schemas/auth.ts +112 -0
- package/src/api/schemas/bylines.ts +85 -0
- package/src/api/schemas/comments.ts +117 -0
- package/src/api/schemas/common.ts +89 -0
- package/src/api/schemas/content.ts +191 -0
- package/src/api/schemas/import.ts +52 -0
- package/src/api/schemas/index.ts +17 -0
- package/src/api/schemas/media.ts +116 -0
- package/src/api/schemas/menus.ts +111 -0
- package/src/api/schemas/redirects.ts +155 -0
- package/src/api/schemas/schema.ts +203 -0
- package/src/api/schemas/search.ts +63 -0
- package/src/api/schemas/sections.ts +67 -0
- package/src/api/schemas/settings.ts +63 -0
- package/src/api/schemas/setup.ts +37 -0
- package/src/api/schemas/taxonomies.ts +113 -0
- package/src/api/schemas/users.ts +96 -0
- package/src/api/schemas/widgets.ts +80 -0
- package/src/api/site-url.ts +25 -0
- package/src/api/types.ts +82 -0
- package/src/astro/index.ts +27 -0
- package/src/astro/integration/index.ts +303 -0
- package/src/astro/integration/routes.ts +834 -0
- package/src/astro/integration/runtime.ts +338 -0
- package/src/astro/integration/virtual-modules.ts +469 -0
- package/src/astro/integration/vite-config.ts +335 -0
- package/src/astro/middleware/auth.ts +743 -0
- package/src/astro/middleware/redirect.ts +89 -0
- package/src/astro/middleware/request-context.ts +129 -0
- package/src/astro/middleware/setup.ts +89 -0
- package/src/astro/middleware.ts +398 -0
- package/src/astro/routes/PluginRegistry.tsx +15 -0
- package/src/astro/routes/admin.astro +81 -0
- package/src/astro/routes/api/admin/allowed-domains/[domain].ts +112 -0
- package/src/astro/routes/api/admin/allowed-domains/index.ts +108 -0
- package/src/astro/routes/api/admin/api-tokens/[id].ts +40 -0
- package/src/astro/routes/api/admin/api-tokens/index.ts +68 -0
- package/src/astro/routes/api/admin/bylines/[id]/index.ts +87 -0
- package/src/astro/routes/api/admin/bylines/index.ts +72 -0
- package/src/astro/routes/api/admin/comments/[id]/status.ts +116 -0
- package/src/astro/routes/api/admin/comments/[id].ts +64 -0
- package/src/astro/routes/api/admin/comments/bulk.ts +42 -0
- package/src/astro/routes/api/admin/comments/counts.ts +30 -0
- package/src/astro/routes/api/admin/comments/index.ts +46 -0
- package/src/astro/routes/api/admin/hooks/exclusive/[hookName].ts +91 -0
- package/src/astro/routes/api/admin/hooks/exclusive/index.ts +51 -0
- package/src/astro/routes/api/admin/oauth-clients/[id].ts +110 -0
- package/src/astro/routes/api/admin/oauth-clients/index.ts +71 -0
- package/src/astro/routes/api/admin/plugins/[id]/disable.ts +39 -0
- package/src/astro/routes/api/admin/plugins/[id]/enable.ts +39 -0
- package/src/astro/routes/api/admin/plugins/[id]/index.ts +38 -0
- package/src/astro/routes/api/admin/plugins/[id]/uninstall.ts +48 -0
- package/src/astro/routes/api/admin/plugins/[id]/update.ts +59 -0
- package/src/astro/routes/api/admin/plugins/index.ts +32 -0
- package/src/astro/routes/api/admin/plugins/marketplace/[id]/icon.ts +61 -0
- package/src/astro/routes/api/admin/plugins/marketplace/[id]/index.ts +33 -0
- package/src/astro/routes/api/admin/plugins/marketplace/[id]/install.ts +62 -0
- package/src/astro/routes/api/admin/plugins/marketplace/index.ts +38 -0
- package/src/astro/routes/api/admin/plugins/updates.ts +28 -0
- package/src/astro/routes/api/admin/themes/marketplace/[id]/index.ts +33 -0
- package/src/astro/routes/api/admin/themes/marketplace/[id]/thumbnail.ts +61 -0
- package/src/astro/routes/api/admin/themes/marketplace/index.ts +45 -0
- package/src/astro/routes/api/admin/users/[id]/disable.ts +69 -0
- package/src/astro/routes/api/admin/users/[id]/enable.ts +48 -0
- package/src/astro/routes/api/admin/users/[id]/index.ts +146 -0
- package/src/astro/routes/api/admin/users/[id]/send-recovery.ts +72 -0
- package/src/astro/routes/api/admin/users/index.ts +66 -0
- package/src/astro/routes/api/auth/dev-bypass.ts +139 -0
- package/src/astro/routes/api/auth/invite/accept.ts +52 -0
- package/src/astro/routes/api/auth/invite/complete.ts +84 -0
- package/src/astro/routes/api/auth/invite/index.ts +99 -0
- package/src/astro/routes/api/auth/logout.ts +40 -0
- package/src/astro/routes/api/auth/magic-link/send.ts +89 -0
- package/src/astro/routes/api/auth/magic-link/verify.ts +71 -0
- package/src/astro/routes/api/auth/me.ts +60 -0
- package/src/astro/routes/api/auth/oauth/[provider]/callback.ts +219 -0
- package/src/astro/routes/api/auth/oauth/[provider].ts +119 -0
- package/src/astro/routes/api/auth/passkey/[id].ts +124 -0
- package/src/astro/routes/api/auth/passkey/index.ts +54 -0
- package/src/astro/routes/api/auth/passkey/options.ts +82 -0
- package/src/astro/routes/api/auth/passkey/register/options.ts +86 -0
- package/src/astro/routes/api/auth/passkey/register/verify.ts +115 -0
- package/src/astro/routes/api/auth/passkey/verify.ts +66 -0
- package/src/astro/routes/api/auth/signup/complete.ts +85 -0
- package/src/astro/routes/api/auth/signup/request.ts +77 -0
- package/src/astro/routes/api/auth/signup/verify.ts +53 -0
- package/src/astro/routes/api/comments/[collection]/[contentId]/index.ts +312 -0
- package/src/astro/routes/api/content/[collection]/[id]/compare.ts +28 -0
- package/src/astro/routes/api/content/[collection]/[id]/discard-draft.ts +54 -0
- package/src/astro/routes/api/content/[collection]/[id]/duplicate.ts +61 -0
- package/src/astro/routes/api/content/[collection]/[id]/permanent.ts +33 -0
- package/src/astro/routes/api/content/[collection]/[id]/preview-url.ts +107 -0
- package/src/astro/routes/api/content/[collection]/[id]/publish.ts +56 -0
- package/src/astro/routes/api/content/[collection]/[id]/restore.ts +54 -0
- package/src/astro/routes/api/content/[collection]/[id]/revisions.ts +31 -0
- package/src/astro/routes/api/content/[collection]/[id]/schedule.ts +101 -0
- package/src/astro/routes/api/content/[collection]/[id]/terms/[taxonomy].ts +140 -0
- package/src/astro/routes/api/content/[collection]/[id]/translations.ts +30 -0
- package/src/astro/routes/api/content/[collection]/[id]/unpublish.ts +56 -0
- package/src/astro/routes/api/content/[collection]/[id].ts +137 -0
- package/src/astro/routes/api/content/[collection]/index.ts +59 -0
- package/src/astro/routes/api/content/[collection]/trash.ts +33 -0
- package/src/astro/routes/api/dashboard.ts +32 -0
- package/src/astro/routes/api/dev/emails.ts +36 -0
- package/src/astro/routes/api/import/probe.ts +47 -0
- package/src/astro/routes/api/import/wordpress/analyze.ts +510 -0
- package/src/astro/routes/api/import/wordpress/execute.ts +283 -0
- package/src/astro/routes/api/import/wordpress/media.ts +338 -0
- package/src/astro/routes/api/import/wordpress/prepare.ts +181 -0
- package/src/astro/routes/api/import/wordpress/rewrite-urls.ts +393 -0
- package/src/astro/routes/api/import/wordpress-plugin/analyze.ts +111 -0
- package/src/astro/routes/api/import/wordpress-plugin/callback.ts +58 -0
- package/src/astro/routes/api/import/wordpress-plugin/execute.ts +347 -0
- package/src/astro/routes/api/manifest.ts +62 -0
- package/src/astro/routes/api/mcp.ts +124 -0
- package/src/astro/routes/api/media/[id]/confirm.ts +93 -0
- package/src/astro/routes/api/media/[id].ts +145 -0
- package/src/astro/routes/api/media/file/[key].ts +79 -0
- package/src/astro/routes/api/media/providers/[providerId]/[itemId].ts +86 -0
- package/src/astro/routes/api/media/providers/[providerId]/index.ts +111 -0
- package/src/astro/routes/api/media/providers/index.ts +30 -0
- package/src/astro/routes/api/media/upload-url.ts +137 -0
- package/src/astro/routes/api/media.ts +190 -0
- package/src/astro/routes/api/menus/[name]/items.ts +87 -0
- package/src/astro/routes/api/menus/[name]/reorder.ts +33 -0
- package/src/astro/routes/api/menus/[name].ts +65 -0
- package/src/astro/routes/api/menus/index.ts +47 -0
- package/src/astro/routes/api/oauth/authorize.ts +412 -0
- package/src/astro/routes/api/oauth/device/authorize.ts +45 -0
- package/src/astro/routes/api/oauth/device/code.ts +51 -0
- package/src/astro/routes/api/oauth/device/token.ts +69 -0
- package/src/astro/routes/api/oauth/token/refresh.ts +38 -0
- package/src/astro/routes/api/oauth/token/revoke.ts +38 -0
- package/src/astro/routes/api/oauth/token.ts +184 -0
- package/src/astro/routes/api/openapi.json.ts +32 -0
- package/src/astro/routes/api/plugins/[pluginId]/[...path].ts +92 -0
- package/src/astro/routes/api/redirects/404s/index.ts +72 -0
- package/src/astro/routes/api/redirects/404s/summary.ts +33 -0
- package/src/astro/routes/api/redirects/[id].ts +84 -0
- package/src/astro/routes/api/redirects/index.ts +52 -0
- package/src/astro/routes/api/revisions/[revisionId]/index.ts +29 -0
- package/src/astro/routes/api/revisions/[revisionId]/restore.ts +58 -0
- package/src/astro/routes/api/schema/collections/[slug]/fields/[fieldSlug].ts +76 -0
- package/src/astro/routes/api/schema/collections/[slug]/fields/index.ts +52 -0
- package/src/astro/routes/api/schema/collections/[slug]/fields/reorder.ts +32 -0
- package/src/astro/routes/api/schema/collections/[slug]/index.ts +80 -0
- package/src/astro/routes/api/schema/collections/index.ts +47 -0
- package/src/astro/routes/api/schema/index.ts +109 -0
- package/src/astro/routes/api/schema/orphans/[slug].ts +36 -0
- package/src/astro/routes/api/schema/orphans/index.ts +26 -0
- package/src/astro/routes/api/search/enable.ts +64 -0
- package/src/astro/routes/api/search/index.ts +55 -0
- package/src/astro/routes/api/search/rebuild.ts +72 -0
- package/src/astro/routes/api/search/stats.ts +35 -0
- package/src/astro/routes/api/search/suggest.ts +53 -0
- package/src/astro/routes/api/sections/[slug].ts +84 -0
- package/src/astro/routes/api/sections/index.ts +52 -0
- package/src/astro/routes/api/settings/email.ts +150 -0
- package/src/astro/routes/api/settings.ts +67 -0
- package/src/astro/routes/api/setup/admin-verify.ts +100 -0
- package/src/astro/routes/api/setup/admin.ts +94 -0
- package/src/astro/routes/api/setup/dev-bypass.ts +199 -0
- package/src/astro/routes/api/setup/dev-reset.ts +40 -0
- package/src/astro/routes/api/setup/index.ts +126 -0
- package/src/astro/routes/api/setup/status.ts +122 -0
- package/src/astro/routes/api/snapshot.ts +75 -0
- package/src/astro/routes/api/taxonomies/[name]/terms/[slug].ts +95 -0
- package/src/astro/routes/api/taxonomies/[name]/terms/index.ts +69 -0
- package/src/astro/routes/api/taxonomies/index.ts +59 -0
- package/src/astro/routes/api/themes/preview.ts +77 -0
- package/src/astro/routes/api/typegen.ts +114 -0
- package/src/astro/routes/api/well-known/auth.ts +68 -0
- package/src/astro/routes/api/well-known/oauth-authorization-server.ts +44 -0
- package/src/astro/routes/api/well-known/oauth-protected-resource.ts +37 -0
- package/src/astro/routes/api/widget-areas/[name]/reorder.ts +68 -0
- package/src/astro/routes/api/widget-areas/[name]/widgets/[id].ts +127 -0
- package/src/astro/routes/api/widget-areas/[name]/widgets.ts +80 -0
- package/src/astro/routes/api/widget-areas/[name].ts +87 -0
- package/src/astro/routes/api/widget-areas/index.ts +99 -0
- package/src/astro/routes/api/widget-components.ts +22 -0
- package/src/astro/routes/robots.txt.ts +77 -0
- package/src/astro/routes/sitemap.xml.ts +97 -0
- package/src/astro/storage/adapters.ts +74 -0
- package/src/astro/storage/index.ts +19 -0
- package/src/astro/storage/types.ts +60 -0
- package/src/astro/types.ts +346 -0
- package/src/auth/api-tokens.ts +25 -0
- package/src/auth/challenge-store.ts +80 -0
- package/src/auth/mode.ts +96 -0
- package/src/auth/oauth-state-store.ts +96 -0
- package/src/auth/passkey-config.ts +27 -0
- package/src/auth/rate-limit.ts +158 -0
- package/src/auth/scopes.ts +33 -0
- package/src/auth/types.ts +104 -0
- package/src/aws-sdk.d.ts +100 -0
- package/src/bylines/index.ts +237 -0
- package/src/cleanup.ts +153 -0
- package/src/cli/client-factory.ts +100 -0
- package/src/cli/commands/auth.ts +46 -0
- package/src/cli/commands/bundle-utils.ts +247 -0
- package/src/cli/commands/bundle.ts +609 -0
- package/src/cli/commands/content.ts +442 -0
- package/src/cli/commands/dev.ts +191 -0
- package/src/cli/commands/doctor.ts +211 -0
- package/src/cli/commands/export-seed.ts +630 -0
- package/src/cli/commands/import/wordpress.ts +1056 -0
- package/src/cli/commands/init.ts +192 -0
- package/src/cli/commands/login.ts +547 -0
- package/src/cli/commands/media.ts +165 -0
- package/src/cli/commands/menu.ts +67 -0
- package/src/cli/commands/plugin-init.ts +291 -0
- package/src/cli/commands/plugin-validate.ts +31 -0
- package/src/cli/commands/plugin.ts +33 -0
- package/src/cli/commands/publish.ts +697 -0
- package/src/cli/commands/schema.ts +233 -0
- package/src/cli/commands/search-cmd.ts +54 -0
- package/src/cli/commands/seed.ts +286 -0
- package/src/cli/commands/taxonomy.ts +128 -0
- package/src/cli/commands/types.ts +68 -0
- package/src/cli/credentials.ts +236 -0
- package/src/cli/index.ts +70 -0
- package/src/cli/output.ts +75 -0
- package/src/cli/wxr/parser.ts +969 -0
- package/src/client/cf-access.ts +193 -0
- package/src/client/index.ts +854 -0
- package/src/client/portable-text.ts +413 -0
- package/src/client/transport.ts +200 -0
- package/src/comments/moderator.ts +46 -0
- package/src/comments/notifications.ts +144 -0
- package/src/comments/query.ts +105 -0
- package/src/comments/service.ts +213 -0
- package/src/components/Break.astro +45 -0
- package/src/components/Button.astro +71 -0
- package/src/components/Buttons.astro +49 -0
- package/src/components/Code.astro +59 -0
- package/src/components/Columns.astro +59 -0
- package/src/components/CommentForm.astro +315 -0
- package/src/components/Comments.astro +232 -0
- package/src/components/Cover.astro +128 -0
- package/src/components/EmDashBodyEnd.astro +32 -0
- package/src/components/EmDashBodyStart.astro +32 -0
- package/src/components/EmDashHead.astro +53 -0
- package/src/components/EmDashImage.astro +178 -0
- package/src/components/EmDashMedia.astro +167 -0
- package/src/components/Embed.astro +128 -0
- package/src/components/File.astro +122 -0
- package/src/components/Gallery.astro +93 -0
- package/src/components/HtmlBlock.astro +33 -0
- package/src/components/Image.astro +178 -0
- package/src/components/InlineEditor.astro +27 -0
- package/src/components/InlinePortableTextEditor.tsx +1905 -0
- package/src/components/LiveSearch.astro +614 -0
- package/src/components/PortableText.astro +51 -0
- package/src/components/Pullquote.astro +51 -0
- package/src/components/Table.astro +108 -0
- package/src/components/WidgetArea.astro +22 -0
- package/src/components/WidgetRenderer.astro +72 -0
- package/src/components/index.ts +116 -0
- package/src/components/marks/Link.astro +31 -0
- package/src/components/marks/StrikeThrough.astro +7 -0
- package/src/components/marks/Subscript.astro +7 -0
- package/src/components/marks/Superscript.astro +7 -0
- package/src/components/marks/Underline.astro +7 -0
- package/src/components/widgets/Archives.astro +65 -0
- package/src/components/widgets/Categories.astro +35 -0
- package/src/components/widgets/RecentPosts.astro +51 -0
- package/src/components/widgets/Search.astro +18 -0
- package/src/components/widgets/Tags.astro +38 -0
- package/src/content/converters/index.ts +9 -0
- package/src/content/converters/portable-text-to-prosemirror.ts +385 -0
- package/src/content/converters/prosemirror-to-portable-text.ts +413 -0
- package/src/content/converters/types.ts +120 -0
- package/src/content/index.ts +5 -0
- package/src/database/connection.ts +67 -0
- package/src/database/dialect-helpers.ts +138 -0
- package/src/database/index.ts +5 -0
- package/src/database/migrations/001_initial.ts +170 -0
- package/src/database/migrations/002_media_status.ts +26 -0
- package/src/database/migrations/003_schema_registry.ts +79 -0
- package/src/database/migrations/004_plugins.ts +62 -0
- package/src/database/migrations/005_menus.ts +67 -0
- package/src/database/migrations/006_taxonomy_defs.ts +51 -0
- package/src/database/migrations/007_widgets.ts +42 -0
- package/src/database/migrations/008_auth.ts +194 -0
- package/src/database/migrations/009_user_disabled.ts +27 -0
- package/src/database/migrations/011_sections.ts +65 -0
- package/src/database/migrations/012_search.ts +25 -0
- package/src/database/migrations/013_scheduled_publishing.ts +51 -0
- package/src/database/migrations/014_draft_revisions.ts +72 -0
- package/src/database/migrations/015_indexes.ts +82 -0
- package/src/database/migrations/016_api_tokens.ts +89 -0
- package/src/database/migrations/017_authorization_codes.ts +45 -0
- package/src/database/migrations/018_seo.ts +56 -0
- package/src/database/migrations/019_i18n.ts +618 -0
- package/src/database/migrations/020_collection_url_pattern.ts +23 -0
- package/src/database/migrations/021_remove_section_categories.ts +43 -0
- package/src/database/migrations/022_marketplace_plugin_state.ts +46 -0
- package/src/database/migrations/023_plugin_metadata.ts +33 -0
- package/src/database/migrations/024_media_placeholders.ts +32 -0
- package/src/database/migrations/025_oauth_clients.ts +28 -0
- package/src/database/migrations/026_cron_tasks.ts +49 -0
- package/src/database/migrations/027_comments.ts +87 -0
- package/src/database/migrations/028_drop_author_url.ts +9 -0
- package/src/database/migrations/029_redirects.ts +67 -0
- package/src/database/migrations/030_widen_scheduled_index.ts +48 -0
- package/src/database/migrations/031_bylines.ts +90 -0
- package/src/database/migrations/032_rate_limits.ts +39 -0
- package/src/database/migrations/runner.ts +170 -0
- package/src/database/repositories/audit.ts +294 -0
- package/src/database/repositories/byline.ts +387 -0
- package/src/database/repositories/comment.ts +458 -0
- package/src/database/repositories/content.ts +1144 -0
- package/src/database/repositories/index.ts +30 -0
- package/src/database/repositories/media.ts +347 -0
- package/src/database/repositories/options.ts +150 -0
- package/src/database/repositories/plugin-storage.ts +373 -0
- package/src/database/repositories/redirect.ts +480 -0
- package/src/database/repositories/revision.ts +200 -0
- package/src/database/repositories/seo.ts +176 -0
- package/src/database/repositories/taxonomy.ts +294 -0
- package/src/database/repositories/types.ts +132 -0
- package/src/database/repositories/user.ts +258 -0
- package/src/database/transaction.ts +54 -0
- package/src/database/types.ts +501 -0
- package/src/database/validate.ts +138 -0
- package/src/db/adapters.ts +125 -0
- package/src/db/index.ts +37 -0
- package/src/db/libsql.ts +23 -0
- package/src/db/postgres.ts +30 -0
- package/src/db/sqlite.ts +27 -0
- package/src/emdash-runtime.ts +2096 -0
- package/src/fields/boolean.ts +34 -0
- package/src/fields/datetime.ts +44 -0
- package/src/fields/file.ts +41 -0
- package/src/fields/image.ts +34 -0
- package/src/fields/index.ts +42 -0
- package/src/fields/integer.ts +50 -0
- package/src/fields/json.ts +37 -0
- package/src/fields/multiselect.ts +48 -0
- package/src/fields/number.ts +52 -0
- package/src/fields/portable-text.ts +33 -0
- package/src/fields/reference.ts +29 -0
- package/src/fields/richtext.ts +31 -0
- package/src/fields/select.ts +46 -0
- package/src/fields/slug.ts +38 -0
- package/src/fields/text.ts +55 -0
- package/src/fields/textarea.ts +52 -0
- package/src/fields/types.ts +64 -0
- package/src/i18n/config.ts +68 -0
- package/src/import/index.ts +90 -0
- package/src/import/menus.ts +436 -0
- package/src/import/registry.ts +111 -0
- package/src/import/sections.ts +103 -0
- package/src/import/settings.ts +281 -0
- package/src/import/sources/wordpress-plugin.ts +641 -0
- package/src/import/sources/wordpress-rest.ts +191 -0
- package/src/import/sources/wxr.ts +330 -0
- package/src/import/ssrf.ts +260 -0
- package/src/import/types.ts +418 -0
- package/src/import/utils.ts +412 -0
- package/src/index.ts +481 -0
- package/src/loader.ts +770 -0
- package/src/mcp/server.ts +1463 -0
- package/src/media/index.ts +32 -0
- package/src/media/local-runtime.ts +213 -0
- package/src/media/local.ts +46 -0
- package/src/media/normalize.ts +190 -0
- package/src/media/placeholder.ts +150 -0
- package/src/media/provider-loader.ts +78 -0
- package/src/media/types.ts +279 -0
- package/src/menus/index.ts +324 -0
- package/src/menus/types.ts +112 -0
- package/src/page/context.ts +93 -0
- package/src/page/fragments.ts +89 -0
- package/src/page/index.ts +58 -0
- package/src/page/jsonld.ts +94 -0
- package/src/page/metadata.ts +185 -0
- package/src/page/seo-contributions.ts +136 -0
- package/src/plugin-utils.ts +80 -0
- package/src/plugins/adapt-sandbox-entry.ts +207 -0
- package/src/plugins/context.ts +833 -0
- package/src/plugins/cron.ts +361 -0
- package/src/plugins/define-plugin.ts +259 -0
- package/src/plugins/email-console.ts +73 -0
- package/src/plugins/email.ts +209 -0
- package/src/plugins/hooks.ts +1273 -0
- package/src/plugins/index.ts +193 -0
- package/src/plugins/manager.ts +595 -0
- package/src/plugins/manifest-schema.ts +230 -0
- package/src/plugins/marketplace.ts +460 -0
- package/src/plugins/request-meta.ts +139 -0
- package/src/plugins/routes.ts +302 -0
- package/src/plugins/sandbox/index.ts +18 -0
- package/src/plugins/sandbox/noop.ts +76 -0
- package/src/plugins/sandbox/types.ts +173 -0
- package/src/plugins/scheduler/node.ts +122 -0
- package/src/plugins/scheduler/piggyback.ts +71 -0
- package/src/plugins/scheduler/types.ts +27 -0
- package/src/plugins/state.ts +208 -0
- package/src/plugins/storage-indexes.ts +326 -0
- package/src/plugins/storage-query.ts +240 -0
- package/src/plugins/types.ts +1284 -0
- package/src/preview/helpers.ts +27 -0
- package/src/preview/index.ts +40 -0
- package/src/preview/tokens.ts +279 -0
- package/src/preview/urls.ts +118 -0
- package/src/query.ts +674 -0
- package/src/redirects/patterns.ts +224 -0
- package/src/request-context.ts +67 -0
- package/src/runtime.ts +21 -0
- package/src/schema/index.ts +29 -0
- package/src/schema/query.ts +44 -0
- package/src/schema/registry.ts +965 -0
- package/src/schema/types.ts +276 -0
- package/src/schema/zod-generator.ts +413 -0
- package/src/search/fts-manager.ts +452 -0
- package/src/search/index.ts +26 -0
- package/src/search/query.ts +396 -0
- package/src/search/text-extraction.ts +162 -0
- package/src/search/types.ts +114 -0
- package/src/sections/index.ts +226 -0
- package/src/sections/types.ts +86 -0
- package/src/seed/apply.ts +1141 -0
- package/src/seed/default.ts +86 -0
- package/src/seed/index.ts +28 -0
- package/src/seed/load.ts +35 -0
- package/src/seed/types.ts +341 -0
- package/src/seed/validate.ts +642 -0
- package/src/seo/index.ts +179 -0
- package/src/settings/index.ts +203 -0
- package/src/settings/types.ts +58 -0
- package/src/storage/index.ts +28 -0
- package/src/storage/local.ts +249 -0
- package/src/storage/s3.ts +263 -0
- package/src/storage/types.ts +204 -0
- package/src/taxonomies/index.ts +309 -0
- package/src/taxonomies/types.ts +61 -0
- package/src/ui.ts +75 -0
- package/src/utils/base64.ts +73 -0
- package/src/utils/hash.ts +36 -0
- package/src/utils/sanitize.ts +20 -0
- package/src/utils/slugify.ts +29 -0
- package/src/utils/url.ts +48 -0
- package/src/virtual-modules.d.ts +111 -0
- package/src/visual-editing/editable.ts +108 -0
- package/src/visual-editing/toolbar.ts +1229 -0
- package/src/widgets/components.ts +105 -0
- package/src/widgets/index.ts +131 -0
- package/src/widgets/types.ts +81 -0
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Request Metadata Extraction
|
|
3
|
+
*
|
|
4
|
+
* Extracts normalized metadata (IP, user agent, referer, geo) from
|
|
5
|
+
* incoming requests. Used by plugin route handlers to access request
|
|
6
|
+
* context without touching raw headers.
|
|
7
|
+
*
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import type { GeoInfo, RequestMeta } from "./types.js";
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Cloudflare Workers `cf` object shape (subset we use).
|
|
14
|
+
* Present on requests when running on Cloudflare Workers.
|
|
15
|
+
*/
|
|
16
|
+
interface CfProperties {
|
|
17
|
+
country?: string;
|
|
18
|
+
region?: string;
|
|
19
|
+
city?: string;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Loose validation for IPv4 and IPv6 addresses.
|
|
24
|
+
* Accepts digits, hex chars, dots, and colons — rejects anything else
|
|
25
|
+
* (e.g. HTML tags, scripts, or other non-IP garbage in spoofed headers).
|
|
26
|
+
*/
|
|
27
|
+
const IP_PATTERN = /^[\da-fA-F.:]+$/;
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Extract the first IP from an X-Forwarded-For header value.
|
|
31
|
+
* The header may contain a comma-separated list of IPs; the first
|
|
32
|
+
* entry is the original client IP.
|
|
33
|
+
*
|
|
34
|
+
* Returns null if the extracted value doesn't look like an IP address.
|
|
35
|
+
*/
|
|
36
|
+
function parseFirstForwardedIp(header: string): string | null {
|
|
37
|
+
const first = header.split(",")[0];
|
|
38
|
+
const trimmed = first?.trim();
|
|
39
|
+
if (!trimmed) return null;
|
|
40
|
+
return IP_PATTERN.test(trimmed) ? trimmed : null;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Get the Cloudflare `cf` object from the request, if present.
|
|
45
|
+
* Returns undefined when not running on Cloudflare Workers.
|
|
46
|
+
*/
|
|
47
|
+
function getCfObject(request: Request): CfProperties | undefined {
|
|
48
|
+
return (request as unknown as { cf?: CfProperties }).cf;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Extract geographic information from the Cloudflare `cf` object
|
|
53
|
+
* attached to the request. Returns null when not running on CF Workers.
|
|
54
|
+
*/
|
|
55
|
+
function extractGeo(cf: CfProperties | undefined): GeoInfo | null {
|
|
56
|
+
if (!cf) return null;
|
|
57
|
+
|
|
58
|
+
const country = cf.country ?? null;
|
|
59
|
+
const region = cf.region ?? null;
|
|
60
|
+
const city = cf.city ?? null;
|
|
61
|
+
|
|
62
|
+
// Only return geo if at least one field is populated
|
|
63
|
+
if (country === null && region === null && city === null) return null;
|
|
64
|
+
|
|
65
|
+
return { country, region, city };
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Extract normalized request metadata from a Request object.
|
|
70
|
+
*
|
|
71
|
+
* IP resolution order:
|
|
72
|
+
* 1. `CF-Connecting-IP` header — only trusted when a `cf` object is
|
|
73
|
+
* present on the request (proving the request came through Cloudflare's
|
|
74
|
+
* edge, which strips/overwrites client-supplied values).
|
|
75
|
+
* 2. `X-Forwarded-For` header (first entry) — best-effort, spoofable
|
|
76
|
+
* when there is no trusted reverse proxy.
|
|
77
|
+
* 3. `null`
|
|
78
|
+
*/
|
|
79
|
+
export function extractRequestMeta(request: Request): RequestMeta {
|
|
80
|
+
const headers = request.headers;
|
|
81
|
+
const cf = getCfObject(request);
|
|
82
|
+
|
|
83
|
+
// IP: only trust headers when the cf object confirms we're on Cloudflare.
|
|
84
|
+
// Without a trusted reverse proxy, X-Forwarded-For is trivially spoofable.
|
|
85
|
+
let ip: string | null = null;
|
|
86
|
+
if (cf) {
|
|
87
|
+
const cfIp = headers.get("cf-connecting-ip")?.trim();
|
|
88
|
+
if (cfIp && IP_PATTERN.test(cfIp)) {
|
|
89
|
+
ip = cfIp;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
if (!ip && cf) {
|
|
93
|
+
// Only trust X-Forwarded-For when we're behind Cloudflare (which
|
|
94
|
+
// overwrites the header). In standalone deployments without a trusted
|
|
95
|
+
// proxy, XFF is trivially spoofable.
|
|
96
|
+
const xff = headers.get("x-forwarded-for");
|
|
97
|
+
ip = xff ? parseFirstForwardedIp(xff) : null;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const userAgent = headers.get("user-agent")?.trim() || null;
|
|
101
|
+
const referer = headers.get("referer")?.trim() || null;
|
|
102
|
+
const geo = extractGeo(cf);
|
|
103
|
+
|
|
104
|
+
return { ip, userAgent, referer, geo };
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// =============================================================================
|
|
108
|
+
// Header Sanitization for Sandbox
|
|
109
|
+
// =============================================================================
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Headers that must never cross the RPC boundary to sandboxed plugins.
|
|
113
|
+
* Session tokens, auth credentials, and infrastructure headers are stripped
|
|
114
|
+
* to prevent malicious plugins from exfiltrating sensitive data.
|
|
115
|
+
*/
|
|
116
|
+
const SANDBOX_STRIPPED_HEADERS = new Set([
|
|
117
|
+
"cookie",
|
|
118
|
+
"set-cookie",
|
|
119
|
+
"authorization",
|
|
120
|
+
"proxy-authorization",
|
|
121
|
+
"cf-access-jwt-assertion",
|
|
122
|
+
"cf-access-client-id",
|
|
123
|
+
"cf-access-client-secret",
|
|
124
|
+
"x-emdash-request",
|
|
125
|
+
]);
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Copy request headers into a plain object, stripping sensitive headers
|
|
129
|
+
* that must not be exposed to sandboxed plugin code.
|
|
130
|
+
*/
|
|
131
|
+
export function sanitizeHeadersForSandbox(headers: Headers): Record<string, string> {
|
|
132
|
+
const safe: Record<string, string> = {};
|
|
133
|
+
headers.forEach((value, key) => {
|
|
134
|
+
if (!SANDBOX_STRIPPED_HEADERS.has(key)) {
|
|
135
|
+
safe[key] = value;
|
|
136
|
+
}
|
|
137
|
+
});
|
|
138
|
+
return safe;
|
|
139
|
+
}
|
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Plugin Routes v2
|
|
3
|
+
*
|
|
4
|
+
* Handles plugin API route invocation with:
|
|
5
|
+
* - Input validation via Zod schemas
|
|
6
|
+
* - Route context creation
|
|
7
|
+
* - Error handling
|
|
8
|
+
*
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { PluginContextFactory, type PluginContextFactoryOptions } from "./context.js";
|
|
12
|
+
import { extractRequestMeta } from "./request-meta.js";
|
|
13
|
+
import type { ResolvedPlugin, RouteContext, PluginRoute } from "./types.js";
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Route metadata (public flag) without the handler.
|
|
17
|
+
* Used by the catch-all route to decide auth before dispatch.
|
|
18
|
+
*/
|
|
19
|
+
export interface RouteMeta {
|
|
20
|
+
public: boolean;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Result from a route invocation
|
|
25
|
+
*/
|
|
26
|
+
export interface RouteResult<T = unknown> {
|
|
27
|
+
success: boolean;
|
|
28
|
+
data?: T;
|
|
29
|
+
error?: {
|
|
30
|
+
code: string;
|
|
31
|
+
message: string;
|
|
32
|
+
details?: unknown;
|
|
33
|
+
};
|
|
34
|
+
status: number;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Route invocation options
|
|
39
|
+
*/
|
|
40
|
+
export interface InvokeRouteOptions {
|
|
41
|
+
/** The original request */
|
|
42
|
+
request: Request;
|
|
43
|
+
/** Request body (already parsed) */
|
|
44
|
+
body?: unknown;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Route handler for a plugin
|
|
49
|
+
*/
|
|
50
|
+
export class PluginRouteHandler {
|
|
51
|
+
private contextFactory: PluginContextFactory;
|
|
52
|
+
private plugin: ResolvedPlugin;
|
|
53
|
+
|
|
54
|
+
constructor(plugin: ResolvedPlugin, factoryOptions: PluginContextFactoryOptions) {
|
|
55
|
+
this.plugin = plugin;
|
|
56
|
+
this.contextFactory = new PluginContextFactory(factoryOptions);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Invoke a route by name
|
|
61
|
+
*/
|
|
62
|
+
async invoke(routeName: string, options: InvokeRouteOptions): Promise<RouteResult> {
|
|
63
|
+
const route = this.plugin.routes[routeName];
|
|
64
|
+
|
|
65
|
+
if (!route) {
|
|
66
|
+
return {
|
|
67
|
+
success: false,
|
|
68
|
+
error: {
|
|
69
|
+
code: "ROUTE_NOT_FOUND",
|
|
70
|
+
message: `Route "${routeName}" not found in plugin "${this.plugin.id}"`,
|
|
71
|
+
},
|
|
72
|
+
status: 404,
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Validate input if schema is provided
|
|
77
|
+
let validatedInput: unknown;
|
|
78
|
+
if (route.input) {
|
|
79
|
+
const parseResult = route.input.safeParse(options.body);
|
|
80
|
+
if (!parseResult.success) {
|
|
81
|
+
return {
|
|
82
|
+
success: false,
|
|
83
|
+
error: {
|
|
84
|
+
code: "VALIDATION_ERROR",
|
|
85
|
+
message: "Invalid request body",
|
|
86
|
+
details: parseResult.error.format(),
|
|
87
|
+
},
|
|
88
|
+
status: 400,
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
validatedInput = parseResult.data;
|
|
92
|
+
} else {
|
|
93
|
+
validatedInput = options.body;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// Create route context
|
|
97
|
+
const baseContext = this.contextFactory.createContext(this.plugin);
|
|
98
|
+
const routeContext: RouteContext = {
|
|
99
|
+
...baseContext,
|
|
100
|
+
input: validatedInput,
|
|
101
|
+
request: options.request,
|
|
102
|
+
requestMeta: extractRequestMeta(options.request),
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
// Execute handler
|
|
106
|
+
try {
|
|
107
|
+
const result = await route.handler(routeContext);
|
|
108
|
+
return {
|
|
109
|
+
success: true,
|
|
110
|
+
data: result,
|
|
111
|
+
status: 200,
|
|
112
|
+
};
|
|
113
|
+
} catch (error) {
|
|
114
|
+
// Handle known error types
|
|
115
|
+
if (error instanceof PluginRouteError) {
|
|
116
|
+
return {
|
|
117
|
+
success: false,
|
|
118
|
+
error: {
|
|
119
|
+
code: error.code,
|
|
120
|
+
message: error.message,
|
|
121
|
+
details: error.details,
|
|
122
|
+
},
|
|
123
|
+
status: error.status,
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// Unknown error
|
|
128
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
129
|
+
return {
|
|
130
|
+
success: false,
|
|
131
|
+
error: {
|
|
132
|
+
code: "INTERNAL_ERROR",
|
|
133
|
+
message: `Route handler failed: ${message}`,
|
|
134
|
+
},
|
|
135
|
+
status: 500,
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Get all route names
|
|
142
|
+
*/
|
|
143
|
+
getRouteNames(): string[] {
|
|
144
|
+
return Object.keys(this.plugin.routes);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Check if a route exists
|
|
149
|
+
*/
|
|
150
|
+
hasRoute(name: string): boolean {
|
|
151
|
+
return name in this.plugin.routes;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Get route metadata without invoking the handler.
|
|
156
|
+
* Returns null if the route doesn't exist.
|
|
157
|
+
*/
|
|
158
|
+
getRouteMeta(name: string): RouteMeta | null {
|
|
159
|
+
const route: PluginRoute | undefined = this.plugin.routes[name];
|
|
160
|
+
if (!route) return null;
|
|
161
|
+
return { public: route.public === true };
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Error class for plugin routes
|
|
167
|
+
* Allows plugins to return structured errors with specific HTTP status codes
|
|
168
|
+
*/
|
|
169
|
+
export class PluginRouteError extends Error {
|
|
170
|
+
constructor(
|
|
171
|
+
public code: string,
|
|
172
|
+
message: string,
|
|
173
|
+
public status: number = 400,
|
|
174
|
+
public details?: unknown,
|
|
175
|
+
) {
|
|
176
|
+
super(message);
|
|
177
|
+
this.name = "PluginRouteError";
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Create a bad request error (400)
|
|
182
|
+
*/
|
|
183
|
+
static badRequest(message: string, details?: unknown): PluginRouteError {
|
|
184
|
+
return new PluginRouteError("BAD_REQUEST", message, 400, details);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Create an unauthorized error (401)
|
|
189
|
+
*/
|
|
190
|
+
static unauthorized(message: string = "Unauthorized"): PluginRouteError {
|
|
191
|
+
return new PluginRouteError("UNAUTHORIZED", message, 401);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Create a forbidden error (403)
|
|
196
|
+
*/
|
|
197
|
+
static forbidden(message: string = "Forbidden"): PluginRouteError {
|
|
198
|
+
return new PluginRouteError("FORBIDDEN", message, 403);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Create a not found error (404)
|
|
203
|
+
*/
|
|
204
|
+
static notFound(message: string = "Not found"): PluginRouteError {
|
|
205
|
+
return new PluginRouteError("NOT_FOUND", message, 404);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* Create a conflict error (409)
|
|
210
|
+
*/
|
|
211
|
+
static conflict(message: string, details?: unknown): PluginRouteError {
|
|
212
|
+
return new PluginRouteError("CONFLICT", message, 409, details);
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* Create an internal error (500)
|
|
217
|
+
*/
|
|
218
|
+
static internal(message: string = "Internal error"): PluginRouteError {
|
|
219
|
+
return new PluginRouteError("INTERNAL_ERROR", message, 500);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* Registry for all plugin route handlers
|
|
225
|
+
*/
|
|
226
|
+
export class PluginRouteRegistry {
|
|
227
|
+
private handlers: Map<string, PluginRouteHandler> = new Map();
|
|
228
|
+
|
|
229
|
+
constructor(private factoryOptions: PluginContextFactoryOptions) {}
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* Register a plugin's routes
|
|
233
|
+
*/
|
|
234
|
+
register(plugin: ResolvedPlugin): void {
|
|
235
|
+
const handler = new PluginRouteHandler(plugin, this.factoryOptions);
|
|
236
|
+
this.handlers.set(plugin.id, handler);
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* Unregister a plugin's routes
|
|
241
|
+
*/
|
|
242
|
+
unregister(pluginId: string): void {
|
|
243
|
+
this.handlers.delete(pluginId);
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
/**
|
|
247
|
+
* Invoke a plugin route
|
|
248
|
+
*/
|
|
249
|
+
async invoke(
|
|
250
|
+
pluginId: string,
|
|
251
|
+
routeName: string,
|
|
252
|
+
options: InvokeRouteOptions,
|
|
253
|
+
): Promise<RouteResult> {
|
|
254
|
+
const handler = this.handlers.get(pluginId);
|
|
255
|
+
|
|
256
|
+
if (!handler) {
|
|
257
|
+
return {
|
|
258
|
+
success: false,
|
|
259
|
+
error: {
|
|
260
|
+
code: "PLUGIN_NOT_FOUND",
|
|
261
|
+
message: `Plugin "${pluginId}" not found`,
|
|
262
|
+
},
|
|
263
|
+
status: 404,
|
|
264
|
+
};
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
return handler.invoke(routeName, options);
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* Get all registered plugin IDs
|
|
272
|
+
*/
|
|
273
|
+
getPluginIds(): string[] {
|
|
274
|
+
return [...this.handlers.keys()];
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
/**
|
|
278
|
+
* Get routes for a plugin
|
|
279
|
+
*/
|
|
280
|
+
getRoutes(pluginId: string): string[] {
|
|
281
|
+
return this.handlers.get(pluginId)?.getRouteNames() ?? [];
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
/**
|
|
285
|
+
* Get route metadata for a specific plugin route.
|
|
286
|
+
* Returns null if the plugin or route doesn't exist.
|
|
287
|
+
*/
|
|
288
|
+
getRouteMeta(pluginId: string, routeName: string): RouteMeta | null {
|
|
289
|
+
const handler = this.handlers.get(pluginId);
|
|
290
|
+
if (!handler) return null;
|
|
291
|
+
return handler.getRouteMeta(routeName);
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
/**
|
|
296
|
+
* Create a route registry
|
|
297
|
+
*/
|
|
298
|
+
export function createRouteRegistry(
|
|
299
|
+
factoryOptions: PluginContextFactoryOptions,
|
|
300
|
+
): PluginRouteRegistry {
|
|
301
|
+
return new PluginRouteRegistry(factoryOptions);
|
|
302
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Plugin Sandbox Exports
|
|
3
|
+
*
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export { NoopSandboxRunner, SandboxNotAvailableError, createNoopSandboxRunner } from "./noop.js";
|
|
7
|
+
|
|
8
|
+
export type {
|
|
9
|
+
SandboxRunner,
|
|
10
|
+
SandboxedPlugin,
|
|
11
|
+
SandboxRunnerFactory,
|
|
12
|
+
SandboxOptions,
|
|
13
|
+
SandboxEmailMessage,
|
|
14
|
+
SandboxEmailSendCallback,
|
|
15
|
+
ResourceLimits,
|
|
16
|
+
PluginCodeStorage,
|
|
17
|
+
SerializedRequest,
|
|
18
|
+
} from "./types.js";
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* No-op Sandbox Runner
|
|
3
|
+
*
|
|
4
|
+
* Default implementation that doesn't support sandboxing.
|
|
5
|
+
* Used on platforms without Worker Loader (Node.js, Deno, etc.).
|
|
6
|
+
*
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import type { PluginManifest } from "../types.js";
|
|
10
|
+
import type { SandboxRunner, SandboxedPlugin, SandboxOptions } from "./types.js";
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Error thrown when attempting to use sandboxing on an unsupported platform.
|
|
14
|
+
*/
|
|
15
|
+
export class SandboxNotAvailableError extends Error {
|
|
16
|
+
constructor() {
|
|
17
|
+
super(
|
|
18
|
+
"Plugin sandboxing is not available on this platform. " +
|
|
19
|
+
"Sandboxed plugins require Cloudflare Workers with Worker Loader. " +
|
|
20
|
+
"Use trusted plugins (from config) instead, or deploy to Cloudflare.",
|
|
21
|
+
);
|
|
22
|
+
this.name = "SandboxNotAvailableError";
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* No-op sandbox runner for platforms without isolation support.
|
|
28
|
+
*
|
|
29
|
+
* - `isAvailable()` returns false
|
|
30
|
+
* - `load()` throws SandboxNotAvailableError
|
|
31
|
+
* - `terminateAll()` is a no-op
|
|
32
|
+
*
|
|
33
|
+
* This is the default runner when no platform adapter is configured.
|
|
34
|
+
*/
|
|
35
|
+
export class NoopSandboxRunner implements SandboxRunner {
|
|
36
|
+
/**
|
|
37
|
+
* Always returns false - sandboxing is not available.
|
|
38
|
+
*/
|
|
39
|
+
isAvailable(): boolean {
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Always throws - can't load sandboxed plugins without isolation.
|
|
45
|
+
*/
|
|
46
|
+
async load(
|
|
47
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
48
|
+
_manifest: PluginManifest,
|
|
49
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
50
|
+
_code: string,
|
|
51
|
+
): Promise<SandboxedPlugin> {
|
|
52
|
+
throw new SandboxNotAvailableError();
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* No-op - sandboxing not available, email callback is irrelevant.
|
|
57
|
+
*/
|
|
58
|
+
setEmailSend(): void {
|
|
59
|
+
// Nothing to do
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* No-op - nothing to terminate.
|
|
64
|
+
*/
|
|
65
|
+
async terminateAll(): Promise<void> {
|
|
66
|
+
// Nothing to do
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Create a no-op sandbox runner.
|
|
72
|
+
* This is used as the default when no platform adapter is configured.
|
|
73
|
+
*/
|
|
74
|
+
export function createNoopSandboxRunner(_options?: SandboxOptions): SandboxRunner {
|
|
75
|
+
return new NoopSandboxRunner();
|
|
76
|
+
}
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Plugin Sandbox Types
|
|
3
|
+
*
|
|
4
|
+
* Defines interfaces for running plugins in sandboxed V8 isolates.
|
|
5
|
+
* The SandboxRunner interface is implemented by platform adapters
|
|
6
|
+
* (e.g., Cloudflare Worker Loader) to provide isolation.
|
|
7
|
+
*
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import type { Kysely } from "kysely";
|
|
11
|
+
|
|
12
|
+
import type { Database } from "../../database/types.js";
|
|
13
|
+
import type { PluginManifest, RequestMeta } from "../types.js";
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Resource limits for sandboxed plugins.
|
|
17
|
+
* Enforced by the sandbox runtime (e.g., Worker Loader).
|
|
18
|
+
*/
|
|
19
|
+
export interface ResourceLimits {
|
|
20
|
+
/** CPU time per invocation in milliseconds (default: 50ms) */
|
|
21
|
+
cpuMs?: number;
|
|
22
|
+
/** Memory limit in MB (default: 128MB) */
|
|
23
|
+
memoryMb?: number;
|
|
24
|
+
/** Maximum subrequests per invocation (default: 10) */
|
|
25
|
+
subrequests?: number;
|
|
26
|
+
/** Wall-clock time limit in milliseconds (default: 30000ms) */
|
|
27
|
+
wallTimeMs?: number;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Storage interface for loading plugin code.
|
|
32
|
+
* Could be R2, local filesystem, or any other storage backend.
|
|
33
|
+
*/
|
|
34
|
+
export interface PluginCodeStorage {
|
|
35
|
+
/** Get plugin bundle code by path */
|
|
36
|
+
get(path: string): Promise<string | null>;
|
|
37
|
+
/** Check if a bundle exists */
|
|
38
|
+
exists(path: string): Promise<boolean>;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Serialized email message for sandbox RPC transport.
|
|
43
|
+
* Matches the core EmailMessage type but uses only serializable fields.
|
|
44
|
+
*/
|
|
45
|
+
export interface SandboxEmailMessage {
|
|
46
|
+
to: string;
|
|
47
|
+
subject: string;
|
|
48
|
+
text: string;
|
|
49
|
+
html?: string;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Callback for sending email from a sandboxed plugin.
|
|
54
|
+
* The sandbox runner wires this up from the EmailPipeline.
|
|
55
|
+
*
|
|
56
|
+
* @param message - The email message to send
|
|
57
|
+
* @param pluginId - The sending plugin's ID (used as source)
|
|
58
|
+
*/
|
|
59
|
+
export type SandboxEmailSendCallback = (
|
|
60
|
+
message: SandboxEmailMessage,
|
|
61
|
+
pluginId: string,
|
|
62
|
+
) => Promise<void>;
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Options for creating a sandbox runner
|
|
66
|
+
*/
|
|
67
|
+
export interface SandboxOptions {
|
|
68
|
+
/** Storage interface for loading plugin code */
|
|
69
|
+
storage?: PluginCodeStorage;
|
|
70
|
+
/** Database for bridge operations */
|
|
71
|
+
db: Kysely<Database>;
|
|
72
|
+
/** Default resource limits */
|
|
73
|
+
limits?: ResourceLimits;
|
|
74
|
+
/** Site info for plugin context (injected into wrapper at generation time) */
|
|
75
|
+
siteInfo?: { name: string; url: string; locale: string };
|
|
76
|
+
/** Email send callback, wired from the EmailPipeline by the runtime */
|
|
77
|
+
emailSend?: SandboxEmailSendCallback;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* A sandboxed plugin instance.
|
|
82
|
+
* Provides methods to invoke hooks and routes in the isolated environment.
|
|
83
|
+
*/
|
|
84
|
+
export interface SandboxedPlugin {
|
|
85
|
+
/** Unique identifier: `${manifest.id}:${manifest.version}` */
|
|
86
|
+
readonly id: string;
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Invoke a hook in the sandboxed plugin.
|
|
90
|
+
*
|
|
91
|
+
* @param hookName - Name of the hook (e.g., "content:beforeSave")
|
|
92
|
+
* @param event - Event data to pass to the hook
|
|
93
|
+
* @returns Hook result (transformed content, void, etc.)
|
|
94
|
+
*/
|
|
95
|
+
invokeHook(hookName: string, event: unknown): Promise<unknown>;
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Invoke an API route in the sandboxed plugin.
|
|
99
|
+
*
|
|
100
|
+
* @param routeName - Name of the route
|
|
101
|
+
* @param input - Validated input data
|
|
102
|
+
* @param request - Serialized request info for context
|
|
103
|
+
* @returns Route response data
|
|
104
|
+
*/
|
|
105
|
+
invokeRoute(routeName: string, input: unknown, request: SerializedRequest): Promise<unknown>;
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Terminate the sandboxed plugin.
|
|
109
|
+
* Releases resources and prevents further invocations.
|
|
110
|
+
*/
|
|
111
|
+
terminate(): Promise<void>;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Serialized request for RPC transport.
|
|
116
|
+
* Worker Loader can't pass Request objects directly.
|
|
117
|
+
*/
|
|
118
|
+
export interface SerializedRequest {
|
|
119
|
+
url: string;
|
|
120
|
+
method: string;
|
|
121
|
+
headers: Record<string, string>;
|
|
122
|
+
/** Normalized request metadata extracted before RPC serialization */
|
|
123
|
+
meta: RequestMeta;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Sandbox runner interface.
|
|
128
|
+
* Platform adapters implement this to provide plugin isolation.
|
|
129
|
+
*/
|
|
130
|
+
export interface SandboxRunner {
|
|
131
|
+
/**
|
|
132
|
+
* Check if sandboxing is available on this platform.
|
|
133
|
+
* Returns false for platforms that don't support isolation.
|
|
134
|
+
*/
|
|
135
|
+
isAvailable(): boolean;
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Load a sandboxed plugin from code.
|
|
139
|
+
*
|
|
140
|
+
* @param manifest - Plugin manifest with metadata and capabilities
|
|
141
|
+
* @param code - The bundled plugin JavaScript code
|
|
142
|
+
* @returns A sandboxed plugin instance
|
|
143
|
+
* @throws If sandboxing is not available or plugin can't be loaded
|
|
144
|
+
*/
|
|
145
|
+
load(manifest: PluginManifest, code: string): Promise<SandboxedPlugin>;
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Set the email send callback for sandboxed plugins.
|
|
149
|
+
* Called after the EmailPipeline is created, since the pipeline
|
|
150
|
+
* doesn't exist when the sandbox runner is constructed.
|
|
151
|
+
*/
|
|
152
|
+
setEmailSend(callback: SandboxEmailSendCallback | null): void;
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Terminate all loaded sandboxed plugins.
|
|
156
|
+
* Called during shutdown or when reconfiguring.
|
|
157
|
+
*/
|
|
158
|
+
terminateAll(): Promise<void>;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Factory function type for creating sandbox runners.
|
|
163
|
+
* Exported by platform adapters (e.g., @emdash-cms/adapter-cloudflare/sandbox).
|
|
164
|
+
*
|
|
165
|
+
* @example
|
|
166
|
+
* ```typescript
|
|
167
|
+
* // In @emdash-cms/adapter-cloudflare/sandbox.ts
|
|
168
|
+
* export const createSandboxRunner: SandboxRunnerFactory = (options) => {
|
|
169
|
+
* return new CloudflareSandboxRunner(options);
|
|
170
|
+
* };
|
|
171
|
+
* ```
|
|
172
|
+
*/
|
|
173
|
+
export type SandboxRunnerFactory = (options: SandboxOptions) => SandboxRunner;
|