edge-workers-sdk
v0.2.0
Published
AssemblyScript SDK for edge-workers
Readme
edge-workers-sdk
AssemblyScript SDK for writing Edge Workers. Provides typed HttpRequest / HttpResponse objects, a handler-registration API, and an outbound fetch() for calling external services. WASM ABI and JSON wire format are handled internally.
Install
npm install edge-workers-sdkConfigure
This SDK depends on json-as, which uses an AssemblyScript compile-time transformer. You must enable it in your project's asconfig.json:
{
"options": {
"transform": ["json-as"]
}
}Without this, the SDK will not compile.
A working example lives at examples/ifconfig/. Run make example to build it.
Quick start
import { onClientRequest, onClientResponse } from "edge-workers-sdk";
// Re-export the WASM ABI exports the host calls into.
// Only re-export the phases you actually handle.
export {
alloc,
on_client_request,
on_client_response,
} from "edge-workers-sdk/assembly/index";
onClientRequest((req) => {
if (req.uri == "/healthz") {
req.respondText(200, "ok");
return;
}
req.setHeader("x-edge-worker", "hello");
});
onClientResponse((resp) => {
resp.setHeader("x-served-by", "edge-worker");
});Compile with asc as usual. You must re-export alloc and the phase-specific ABI exports (on_client_request, on_origin_request, on_client_response, on_origin_response) for the host to find them.
Phases
The host invokes the worker at up to four points per request. Each maps to one registration function and one ABI export:
| Phase | Register with | ABI export | When it runs |
| --- | --- | --- | --- |
| Client request | onClientRequest | on_client_request | Before cache lookup. Only phase that can call fetch(). |
| Origin request | onOriginRequest | on_origin_request | On cache miss, before going to origin. |
| Client response | onClientResponse | on_client_response | After cache lookup, before sending to client. |
| Origin response | onOriginResponse | on_origin_response | On cache miss, after origin responds. |
Only re-export the ABI symbols for phases your worker actually handles.
API
Registration
onClientRequest((req: HttpRequest) => void): voidonOriginRequest((req: HttpRequest) => void): voidonClientResponse((resp: HttpResponse) => void): voidonOriginResponse((resp: HttpResponse) => void): void
Each registers a handler for the corresponding phase. Mutate req / resp in place. In the request phases, req.respond(...) / req.respondText(...) short-circuits the chain and returns the given response.
HttpRequest
| Field | Type | Notes |
| --- | --- | --- |
| method | string | HTTP method (e.g. "GET") |
| uri | string | Request URI |
| headers | string[][] | Array of [name, value] pairs |
| body | Uint8Array \| null | Raw request body bytes |
| earlyResponse | HttpResponse \| null | Set via respond() to short-circuit upstream |
Methods:
getHeader(name)— case-insensitive lookup, returnsstring \| nullsetHeader(name, value)— replaces if present, appends otherwiseremoveHeader(name)— removes all matching headerstext()— UTF-8 decode ofbody; throws on invalid UTF-8bytes()— alias forbody(mirrors WHATWGResponse.bytes())json<T>()— parsebodyas JSON intoT(json-as@jsonclass); throws on invalid JSON or null bodysetBodyText(text)— UTF-8 encodetextintobodyrespond(status, body?, headers?)— short-circuit with a binary body; bypass upstream and return this responserespondText(status, body?, headers?)— same asrespondbut takes astringbody (UTF-8 encoded)bypassChallenge()— setsx-bypass-challenge: 1to skip the bot/security challenge
HttpResponse
| Field / getter | Type | Notes |
| --- | --- | --- |
| status | u16 | HTTP status code (0 on transport error from fetch) |
| ok | bool | true iff status is in 200..299 |
| headers | string[][] | Array of [name, value] pairs |
| body | Uint8Array \| null | Raw response body bytes |
| errorKind | string \| null | Set by fetch() on transport-level failure. Always null for proxy responses. |
| errorMessage | string \| null | Human-readable detail when errorKind != null |
Methods:
getHeader/setHeader/removeHeader— same as onHttpRequesttext()/bytes()/json<T>()— same body accessors as onHttpRequestsetBodyText(text)— UTF-8 encodetextintobodyisError()—trueifferrorKind != nullforceCache()— setsx-cache-force: 1to force this response to be cachedbypassCache()— setsx-cache-bypass: 1to prevent this response from being cached
fetch(url, method?, headers?, body?) → HttpResponse
Make an outbound HTTP request from the guest. Returns an HttpResponse (the same type used by the proxy callbacks). Synchronous from the guest's perspective — wasmtime suspends execution while the host's async fetch runs.
Available only in the client-request phase (before cache lookup). Calling it from any other phase returns an HttpResponse with errorKind set.
The returned response covers both success and failure:
- Transport-level failures (timeout, connection refused, body too large, etc.) come back with
errorKind/errorMessagepopulated andstatus === 0. Useresp.isError()to check. - HTTP-level failures (4xx, 5xx) come back as normal responses with
errorKind === nullandok === false.
AssemblyScript does not support exceptions, so errors are surfaced via fields rather than thrown — unlike WHATWG / Node
fetch.
| Param | Type | Default |
| --- | --- | --- |
| url | string | required |
| method | string | "GET" |
| headers | string[][] | [] |
| body | Uint8Array \| null | null |
import { fetch, onClientRequest } from "edge-workers-sdk";
onClientRequest((req) => {
const bodyBytes = Uint8Array.wrap(String.UTF8.encode('{"foo":"bar"}'));
const resp = fetch(
"https://api.example.com/v1/x",
"POST",
[["authorization", "Bearer ..."]],
bodyBytes,
);
if (resp.isError()) {
req.respondText(502, "fetch failed: " + resp.errorKind!);
return;
}
if (!resp.ok) {
req.respondText(resp.status, "upstream error");
return;
}
const json = resp.text();
// ...
});errorKind values: timeout, too_many_inflight, request_too_large, response_too_large, body_read, transport, plus a host-defined value (e.g. phase_not_allowed) when called outside the client-request phase.
Host-enforced limits (do not need to be re-checked in the guest):
- 2 s end-to-end timeout
- 10 MiB request body cap
- 10 MiB response body cap
- Per-worker concurrency limit (FIFO queue)
getenv(name) → string | null
Look up an environment variable provided by the host. Returns null if the variable is not set.
import { getenv, onClientRequest } from "edge-workers-sdk";
onClientRequest((req) => {
const apiKey = getenv("API_KEY");
if (apiKey !== null) {
req.setHeader("authorization", "Bearer " + apiKey);
}
});Notes
- Bodies are raw bytes (
Uint8Array). Usetext()/setBodyText()for UTF-8;json<T>()for typed JSON; everything else (binary content, gzip, etc.) is just bytes. - Headers are preserved in the order they arrive and are compared case-insensitively.
