Skip to content
Runtime APIs / Fetch events

Runtime APIs

Fetch events

How OpenOrange supplies the Worker fetch execution context.

Status: Partial

Configuration

No Orange-specific configuration is required. A module Worker exports a Wrangler-compatible fetch(request, env, context) handler.

How it works

OpenOrange creates one execution context per request. context.props contains the runtime-supplied properties, context.exports contains the supplied loopback export object, and context.waitUntil(promise) registers background work. The runtime controller drains all registered promises, including work registered while an earlier promise is settling, and retains fulfilled and rejected outcomes for later diagnostics.

  • The controlled loader constructs an extensible environment from configured bindings, installs the Cloudflare global manifest, imports the Worker, preserves its named exports, and rejects unsupported event handlers.
  • The env, exports, withEnv(), withExports(), and withEnvAndExports() exports of cloudflare:workers follow workerd: env is readable while the Worker module evaluates, both proxies follow the current async-context override, and mutations through env change the environment object passed to handlers.
  • Orange does not read the disallow_importable_env flag.
  • Durable Object classes appear in context.exports and exports as their namespaces.
  • WorkerEntrypoint is exported as a base class that stores ctx and env. A default export that extends WorkerEntrypoint handles each request with a new instance.
  • Dispatch invokes the default module Worker’s fetch handler and requires it to return an OpenOrange Response.
  • The dispatch result includes that response and a promise for all waitUntil() outcomes.

For development, a dedicated Node.js child owns the HTTP listener and runtime lifecycle. It streams request and response bodies, dispatches requests inside the child, and reports readiness, startup failures, request failures, background failures, signals, and clean shutdown to the parent CLI over IPC.

request.url uses the request’s Host header. Under orange serve, its scheme is https: when the cluster’s gateway sends X-Forwarded-Proto: https, so a Worker sees the URL its client used, as on Cloudflare. orange dev takes requests directly and ignores that header.

Unsupported context APIs fail when called instead of being silently ignored. ctx.cache is undefined, as in local workerd.

Conformance

The conformance check compiles a module Worker against the pinned ExportedHandler<Env> fetch signature and proves an invalid response type is rejected. The generated event registry check verifies the context has exactly the Cloudflare ExecutionContext keys and is assignable to its generic contract. Runtime tests cover entrypoint ordering, named exports, environment injection, response validation, waitUntil() draining, each unsupported API, and the dedicated process lifecycle over a real HTTP socket.

Deviations

  • passThroughOnException() is a no-op, because Orange has no origin to fall back to. An exception after the call still fails the request with a 500 response.
  • abort() releases the context’s I/O objects and throws the reason, because Node.js cannot stop running JavaScript.
  • context.cache and context.access are undefined, as in local workerd.
  • context.tracing runs every span callback with a no-op span whose isTraced is false, because Orange has no trace collector.
  • Background promise outcomes are returned to the runtime process, which reports rejected work to the parent CLI for local diagnostics.

Compatibility

From the latest conformance run. Scores on the compatibility page; every binding on the status page.

Workers

Drop-in

Runs on Node.js runtime with workerd-shaped globals, cloudflare:* and node:* modules.

fetch, scheduled, and queue handlers run unchanged. Compatibility dates and flags are not applied.

Scales by Runner count. Stateless requests go to any runner in the pool. Not measured across runners here.

In the feature matrix

Supportedvars (string values)Each string in vars appears on env as a string.Wrangler converts each string var to a plain_text binding, and Orange puts the string on env. 4 files
Notes
Named environments follow Wrangler's rules, because Orange reads the config with Wrangler's unstable_readConfig.
Source
src/config/load-wrangler.ts:787-792packages/runtime-node/src/runner.ts:471-473src/runtime/bindings.test.ts:138-148src/config/load-wrangler.test.ts:13-32
Supportedvars (JSON values)Each non-string value in vars appears on env as a parsed JSON value.Wrangler converts each non-string var to a json binding, and Orange puts the value on env. 3 files
Notes
A .dev.vars or .env key with the same name replaces the JSON value with a string.
Source
src/config/load-wrangler.ts:793-794packages/runtime-node/src/runner.ts:471-473src/runtime/bindings.test.ts:138-148
Supported.dev.vars secretswrangler dev loads keys from .dev.vars (or .dev.vars.<env>) into env as secret text.Orange calls Wrangler's unstable_getVarsForDev, so .dev.vars keys reach env as strings, like wrangler dev. 3 files
Notes
A .dev.vars key replaces a var with the same name. It does not replace a binding of another type, such as a Secrets Store secret. When the config has secrets.required, only listed keys and keys that are also vars load, and a missing required key prints a warning.
Source
src/config/load-wrangler.ts:889-919src/config/load-wrangler.ts:1435-1460src/runtime/bindings.test.ts:138-148
Supported.env secretsWhen no .dev.vars file exists, wrangler dev loads .env files into env as secret text.Orange gets the same behavior from Wrangler's unstable_getVarsForDev. A .env key reaches env as a string. 2 files
Notes
Orange passes no custom env file list, so Wrangler reads its default .env files. CLOUDFLARE_LOAD_DEV_VARS_FROM_DOT_ENV and CLOUDFLARE_INCLUDE_PROCESS_ENV apply as in Wrangler. Verified by loading a config with a .env file and no .dev.vars.
Not verified by a test
Not covered by a repository test. Verified once by a manual config load on the devbox.
Source
src/config/load-wrangler.ts:893-906src/config/load-wrangler.ts:1435-1460
Supportedctx.exports loopback bindingsctx.exports exposes this Worker's entrypoints as service stubs and its Durable Object classes as namespaces.Builds ctx.exports from the Worker's named exports: entrypoints become loopback service stubs, and Durable Object classes become namespaces, including classes without a binding. 1/1 pass · 4 files
Notes
ctx.exports in a Durable Object throws DurableObjectState.exports is not implemented. import { exports } from "cloudflare:workers" reads the same object.
Tests
  • api-tests--importable-exports-test › importableExports Pass
Source
packages/runtime-node/src/bindings/service.ts:529-554packages/runtime-node/src/runtime.ts:168-175packages/runtime-node/src/runner.ts:649-674packages/runtime-node/src/bindings/durable-objects/state.ts:374-378
Partialimport { env } from "cloudflare:workers"The env object is importable at module scope and in handlers.The importable env is the same object as the handler env, readable while the module evaluates. 0/2 pass · 2 files
Notes
importable-env-test fails because the runner drops its KV binding. disable-importable-env-test fails because Orange ignores the disallow_importable_env flag.
Tests
  • api-tests--importable-env-test › importableEnv 🍊 open-orange v0.0.1 · by rivet.dev | | Worker api-tests--importable-env-test Fail · File fails at load
  • api-tests--disable-importable-env-test › test 🍊 open-orange v0.0.1 · by rivet.dev | | Worker api-tests--disable-importable-env-test Fail · File fails at load
Source
packages/runtime-node/src/modules/cloudflare-workers/env.ts:38-85packages/runtime-node/src/runtime.ts:145-146
Supportedassets bindingassets.binding gives the Worker a Fetcher for its static assets.env.ASSETS.fetch() serves the assets directory with not_found_handling and follows redirects like a Fetcher. 3 files
Supportedfetch handler (object default export)export default { fetch(request, env, ctx) } handles each HTTP request.Each inbound HTTP request calls fetch(request, env, ctx) with a new ExecutionContext. 1/1 pass · 3 files
Notes
A handler that throws gives a plain-text 500 Internal Server Error, not the Cloudflare 1101 error page. A non-Response result fails with Worker fetch handler must return a Response.
Tests
  • api-tests--fetch-test › test Pass
Source
packages/runtime-node/src/runtime.ts:75-82packages/runtime-node/src/events/fetch.ts:27-61packages/runtime-node/src/runner.ts:951-1015
Supportedfetch handler (WorkerEntrypoint class default export)export default class extends WorkerEntrypoint { fetch(request) } creates an instance per request.Constructs the class with (ctx, env) for each request and calls its fetch(request). 1/1 pass · 2 files
Notes
A class without fetch() loads, and each request fails with Handler does not export a fetch() function., as in workerd.
Tests
  • api-tests--js-rpc-test › defaultExportClass Pass
Source
packages/runtime-node/src/runtime.ts:65-76packages/runtime-node/src/runtime.ts:154-159
PartialNamed WorkerEntrypoint exportsNamed entrypoint exports receive fetch, RPC, and connect calls from service bindings, including bindings from other Workers.Named entrypoints receive fetch, RPC, and connect calls from this Worker's own service bindings and ctx.exports. 2/3 pass · 2 files
Notes
Other Workers cannot call them, because cross-Worker service bindings are stubs. js-rpc-test namedServiceBinding times out (cause not checked). extendingEntrypointClasses and testConstructEntrypoint pass.
Not verified by a test
The cause of the namedServiceBinding timeout is not checked.
Tests
  • api-tests--js-rpc-test › extendingEntrypointClasses Pass
  • api-tests--js-rpc-test › testConstructEntrypoint Pass
  • api-tests--js-rpc-test › namedServiceBinding TimeoutError: The operation was aborted due to timeout Fail · Hangs (60s timeout)
Source
packages/runtime-node/src/bindings/service.ts:97-130packages/runtime-node/src/bindings/service.ts:529-553