Skip to content

feat(host-cloudflare): adopt dynamic-worker engine, retire QuickJS#15

Open
amondnet wants to merge 3 commits into
mainfrom
amondnet/evaluate-adopting-dynamic-worker-engine-for-host
Open

feat(host-cloudflare): adopt dynamic-worker engine, retire QuickJS#15
amondnet wants to merge 3 commits into
mainfrom
amondnet/evaluate-adopting-dynamic-worker-engine-for-host

Conversation

@amondnet

@amondnet amondnet commented Jun 25, 2026

Copy link
Copy Markdown

Summary

Cloudflare Worker Loaders (Dynamic Workers) reached open beta on 2026-03-24, lifting the closed-beta constraint that kept apps/host-cloudflare on the interim QuickJS-WASM substrate. This swaps the engine seam to the dynamic-worker executor (the same one apps/cloud uses) behind the existing CodeExecutor seam, the "one-Layer change" the prior code comment described, and retires QuickJS entirely for this host.

What changed

  • wrangler.jsonc: add the worker_loaders LOADER binding.
  • config.ts: add LOADER: WorkerLoader to CloudflareEnv; bump @cloudflare/workers-types to the version carrying the WorkerLoader type.
  • execution.ts: makeCloudflareCodeExecutorProvider(loader) wraps makeDynamicWorkerExecutor; the executor stack layer threads the loader.
  • app.ts / session-durable-object.ts: pass env.LOADER explicitly (the host's per-request binding pattern, not cloud's ambient cloudflare:workers env); drop the QuickJS preload.
  • Remove QuickJS: quickjs.ts, the vendored quickjs-engine.wasm, the vendor-wasm script, and the runtime-quickjs / quickjs-emscripten deps.
  • Docs: refresh the stale README seam table (engine row + the DO-backed MCP session row) and the closed-beta comments.

Why

The dynamic-worker runtime gains capability QuickJS could not provide: structured-clone fidelity at the tool boundary (Blob/File/Uint8Array, Date/Map/Set), nodejs_compat, configurable outbound, and isolate-level isolation. It also converges host-cloudflare onto the same single engine as cloud.

Verification

  • Gates: typecheck (0 errors), lint (0), format:check (clean).
  • apps/host-cloudflare tests: 3 files / 13 tests pass on real workerd + Miniflare (unstable_dev) with the LOADER binding, covering /api/executions, MCP execute, DO session survival, and a new Buffer/nodejs_compat capability test (impossible on QuickJS, so it doubles as a regression guard).
  • e2e --project cloudflare: browser-approval and the newly-wired mcp-execute (OAuth-connect then run code in the sandbox) pass.

Note on the e2e suite

scenarios/microsoft-graph-full.test.ts times out at its 300s limit in this environment, but this is pre-existing and unrelated: it does not touch the engine seam (it fetches and parses the full ~37MB Graph spec over the network), and it times out identically with this change reverted. Removing the QuickJS WASM module from the main isolate only reduces its memory footprint.

Deployment requirement

Worker Loaders open beta requires a paid Workers plan.

Closes #12


Summary by cubic

Cloudflare 호스트의 실행 엔진을 QuickJS‑WASM에서 동적 워커 엔진(Worker Loaders)로 전환했습니다. 구조화된 복제와 nodejs_compat를 지원하며, LOADER 누락 시 부팅 단계에서 명확한 오류로 가드합니다.

  • ⚠️ Breaking Changes

    • Cloudflare Workers 유료 플랜 필요.
    • wrangler.jsoncworker_loaders 바인딩 추가: [{ "binding": "LOADER" }].
    • 환경 타입에 LOADER: WorkerLoader 필요.
    • QuickJS 관련 자산/의존성 제거: scripts/vendor-quickjs-wasm.ts, src/quickjs-engine.wasm, src/quickjs.ts, @executor-js/runtime-quickjs, quickjs-emscripten-core, @jitl/quickjs-wasmfile-release-sync.
    • 엔진 패키지 교체: @executor-js/runtime-dynamic-worker. @cloudflare/workers-types 최신으로 상향.
  • How to test

    • wrangler.jsoncworker_loaders 바인딩 추가 후 배포 또는 로컬 실행(wrangler unstable_dev 또는 wrangler dev).
    • 기본 실행 확인: POST /api/executionsexport default 6 * 7 전송 → 결과 42.
    • Node 호환 확인: export default Buffer.from("hello").toString("base64")aGVsbG8= 응답.
    • MCP 경로 확인: 세션 생성 후 tools/listtools/callexecute가 동적 워커 엔진에서 실행되는지 확인.

Written for commit f9037f5. Summary will update on new commits.

Review in cubic

Summary by CodeRabbit

  • 새 기능

    • Cloudflare 배포가 동적 Worker 로더 기반 실행 방식으로 전환되었습니다.
    • MCP 세션이 Durable Object에 저장되어 워커 교체 후에도 유지됩니다.
    • Cloudflare Worker에서 Node API 사용 테스트가 추가되었습니다.
  • 버그 수정

    • QuickJS 사전 로딩 및 WASM 의존성이 제거되어 배포/실행 흐름이 단순해졌습니다.
    • Cloudflare 실행 환경 설정이 최신 Worker 바인딩과 호환되도록 업데이트되었습니다.

Worker Loaders (Dynamic Workers) reached open beta on 2026-03-24, lifting
the closed-beta constraint that kept host-cloudflare on the interim
QuickJS-WASM substrate. Swap the engine seam to the dynamic-worker executor
(the same one apps/cloud uses) behind the existing CodeExecutor seam.

- wrangler.jsonc: add the worker_loaders LOADER binding
- config.ts: add LOADER: WorkerLoader to CloudflareEnv; bump workers-types
- execution.ts: makeCloudflareCodeExecutorProvider(loader) wraps
  makeDynamicWorkerExecutor; thread the loader through the stack layer
- app.ts / session-durable-object.ts: pass env.LOADER explicitly (the host's
  per-request binding pattern, not cloud's ambient cloudflare:workers env)
- remove QuickJS entirely: quickjs.ts, the vendored quickjs-engine.wasm, the
  vendor-wasm script, and the runtime-quickjs / quickjs-emscripten deps
- refresh the stale README seam table (engine + DO-backed mcp session) and
  the closed-beta comments

This gains structured-clone fidelity at the tool boundary (Blob/File/
Uint8Array, Date/Map/Set), nodejs_compat, and isolate-level isolation.
Worker Loaders requires a paid Workers plan.

Closes #12
@coderabbitai

coderabbitai Bot commented Jun 25, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Currently processing new changes in this PR. This may take a few minutes, please wait...

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 21a10121-37de-4ea4-a64f-1264d575f0d1

📥 Commits

Reviewing files that changed from the base of the PR and between 2915fde and 8d9ddce.

⛔ Files ignored due to path filters (2)
  • apps/host-cloudflare/src/quickjs-engine.wasm is excluded by !**/*.wasm
  • bun.lock is excluded by !**/*.lock
📒 Files selected for processing (11)
  • apps/host-cloudflare/README.md
  • apps/host-cloudflare/package.json
  • apps/host-cloudflare/scripts/vendor-quickjs-wasm.ts
  • apps/host-cloudflare/src/app.ts
  • apps/host-cloudflare/src/config.ts
  • apps/host-cloudflare/src/execution.ts
  • apps/host-cloudflare/src/mcp/session-durable-object.ts
  • apps/host-cloudflare/src/quickjs.ts
  • apps/host-cloudflare/src/worker.e2e.node.test.ts
  • apps/host-cloudflare/wrangler.jsonc
  • e2e/vitest.config.ts
 _____________________________________
< I don't chase bugs; they surrender. >
 -------------------------------------
  \
   \   (\__/)
       (•ㅅ•)
       /   づ
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch amondnet/evaluate-adopting-dynamic-worker-engine-for-host
⚔️ Resolve merge conflicts
  • Resolve merge conflict in branch amondnet/evaluate-adopting-dynamic-worker-engine-for-host

Comment @coderabbitai help to get the list of available commands.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request replaces the in-process QuickJS-WASM execution engine with the dynamic-worker executor using Cloudflare's Worker Loaders via the LOADER binding, which enables structured-clone fidelity and Node.js compatibility. The review feedback recommends adding runtime validation for the LOADER binding to prevent unexpected failures if the binding is missing or undefined.

Comment thread apps/host-cloudflare/src/execution.ts Outdated
@greptile-apps

greptile-apps Bot commented Jun 25, 2026

Copy link
Copy Markdown

Greptile Summary

This PR replaces the QuickJS-WASM in-process code substrate for apps/host-cloudflare with the dynamic-worker executor (Worker Loaders), converging the Cloudflare host onto the same engine as the cloud app now that the feature reached open beta. The change is threaded through a clean seam: CloudflareEnv.LOADER carries the binding, makeCloudflareCodeExecutorProvider(loader) replaces the old static CloudflareCodeExecutorProvider, and a fail-fast guard throws at boot if the binding is absent.

  • Engine swap: execution.ts now calls makeDynamicWorkerExecutor({ loader }) instead of makeQuickJsExecutor(), and makeCloudflareExecutionStackLayer gains a loader parameter threaded from both the HTTP path (app.ts) and the Durable Object path (session-durable-object.ts).
  • QuickJS removal: quickjs.ts, quickjs-engine.wasm, scripts/vendor-quickjs-wasm.ts, and the associated npm deps are fully deleted; preloadQuickJs() call-sites are removed from app.ts and session-durable-object.ts.
  • Validation: A new Buffer/nodejs_compat test is added to worker.e2e.node.test.ts (impossible on QuickJS, serving as a regression guard), and scenarios/mcp-execute.test.ts is wired into the cloudflare e2e project.

Confidence Score: 5/5

Safe to merge. The engine swap is confined entirely to apps/host-cloudflare, all changed call-sites pass env.LOADER consistently, and the fail-fast guard at boot surfaces a missing binding before any execution is attempted.

Every seam that previously touched QuickJS has been updated: the executor provider, the execution stack layer, the DO constructor path, app initialization, wrangler config, and docs. The LOADER binding is threaded explicitly rather than captured in module scope, matching the established host pattern. Tests cover both the REST execution path and the MCP path end-to-end on real workerd, including a nodejs_compat regression guard that could not pass on the old engine.

No files require special attention.

Important Files Changed

Filename Overview
apps/host-cloudflare/src/execution.ts Replaces QuickJS layer with dynamic-worker executor; adds fail-fast guard for missing LOADER binding; updates makeCloudflareExecutionStackLayer signature with loader parameter.
apps/host-cloudflare/src/config.ts Adds required LOADER: WorkerLoader field to CloudflareEnv; WorkerLoader global type is provided by @cloudflare/workers-types@^4.20250620.0 via tsconfig types entry.
apps/host-cloudflare/src/mcp/session-durable-object.ts Drops preloadQuickJs() and threads self.cfEnv.LOADER into makeCloudflareExecutionStackLayer; LOADER binding propagates correctly from the main Worker env to the DO constructor.
apps/host-cloudflare/wrangler.jsonc Adds worker_loaders binding and reformats from tab- to space-indented JSON; no functional regressions in other bindings.
apps/host-cloudflare/src/worker.e2e.node.test.ts Updates test descriptions and adds a Buffer/nodejs_compat test that doubles as a regression guard proving the engine is actually dynamic-worker.
e2e/vitest.config.ts Adds scenarios/mcp-execute.test.ts to the cloudflare project's explicit include list; the file exists and has no needs constraints so it runs correctly on all targets.

Sequence Diagram

%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
    participant Client
    participant Worker as Cloudflare Worker
    participant DO as McpSessionDO
    participant Loader as LOADER (WorkerLoader)
    participant Isolate as Fresh workerd Isolate

    Note over Worker: makeCloudflareApp(env)<br/>makeCloudflareCodeExecutorProvider(env.LOADER)

    Client->>Worker: POST /api/executions
    Worker->>Loader: load(code)
    Loader->>Isolate: spawn fresh workerd isolate
    Isolate-->>Loader: result
    Loader-->>Worker: structured-clone result
    Worker-->>Client: "{ status, text }"

    Client->>Worker: POST /mcp (initialize)
    Worker->>DO: stub.fetch() via MCP_SESSION
    Note over DO: buildMcpServer(meta, dbHandle)<br/>makeCloudflareExecutionStackLayer(config, dbHandle, cfEnv.LOADER)
    DO->>Loader: load(code) on tools/call
    Loader->>Isolate: spawn fresh workerd isolate
    Isolate-->>Loader: result
    Loader-->>DO: structured-clone result
    DO-->>Client: MCP tool result
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
    participant Client
    participant Worker as Cloudflare Worker
    participant DO as McpSessionDO
    participant Loader as LOADER (WorkerLoader)
    participant Isolate as Fresh workerd Isolate

    Note over Worker: makeCloudflareApp(env)<br/>makeCloudflareCodeExecutorProvider(env.LOADER)

    Client->>Worker: POST /api/executions
    Worker->>Loader: load(code)
    Loader->>Isolate: spawn fresh workerd isolate
    Isolate-->>Loader: result
    Loader-->>Worker: structured-clone result
    Worker-->>Client: "{ status, text }"

    Client->>Worker: POST /mcp (initialize)
    Worker->>DO: stub.fetch() via MCP_SESSION
    Note over DO: buildMcpServer(meta, dbHandle)<br/>makeCloudflareExecutionStackLayer(config, dbHandle, cfEnv.LOADER)
    DO->>Loader: load(code) on tools/call
    Loader->>Isolate: spawn fresh workerd isolate
    Isolate-->>Loader: result
    Loader-->>DO: structured-clone result
    DO-->>Client: MCP tool result
Loading

Reviews (2): Last reviewed commit: "chore(host-cloudflare): guard against a ..." | Re-trigger Greptile

amondnet added 2 commits June 26, 2026 00:00
…pting-dynamic-worker-engine-for-host

# Conflicts:
#	apps/host-cloudflare/wrangler.jsonc
Apply review feedback: makeDynamicWorkerExecutor only reads the loader on the
first execute, so a missing binding would surface as an opaque defect
mid-execution. Fail at app boot with an actionable message instead.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

0 issues found across 1 file (changes from recent commits).

Requires human review: Swaps core execution engine from QuickJS to dynamic-worker, adds new LOADER binding, and updates config/deps. High-risk infrastructure and business logic change requiring human review.

Re-trigger cubic

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Evaluate adopting dynamic-worker engine for host-cloudflare (Worker Loaders now open beta)

1 participant