Skip to main content
StatefulActor is the base class you extend. Subclass it, declare async methods, and they become RPC-callable from a stub. It holds this.ctx (see Actor Context) and this.env (your bindings).
import { StatefulActor } from "@telnyx/edge-runtime";

export class Account extends StatefulActor {
  async debit(amount: number): Promise<{ ok: boolean; balance: number }> {
    const balance = (await this.ctx.storage.get<number>("balance")) ?? 0;
    if (balance < amount) return { ok: false, balance };
    await this.ctx.storage.put("balance", balance - amount);
    return { ok: true, balance: balance - amount };
  }
}

Construction

You don’t construct actors yourself — the runtime does. The base constructor wires this.ctx and this.env, so a subclass that doesn’t need init logic can omit its constructor entirely.
class MyActor extends StatefulActor<Env> {
  // no constructor needed — this.ctx and this.env are wired by the base
}
If you do need one-shot init (preload state, set up an initial alarm), override the constructor and call ctx.blockConcurrencyWhile — see Actor Context.

Dispatch Rules

  • Public methods are RPC-callable from a stub — declare them async (every stub call is a Promise on the caller’s side regardless).
  • Methods whose names start with _ are internal helpers and are not RPC-exposed — the runtime rejects the call.
  • The _ prefix is the only opt-out. TypeScript’s private keyword is erased at runtime and does not stop remote calls; name internal helpers with a leading _.
  • fetch(req), alarm(info), the constructor, and methods defined on StatefulActor itself (not your subclass) are special and not auto-RPC.
  • Methods have a wall-clock budget (30s by default). A call that exceeds it fails with ActorMethodTimeoutError — see Errors.

alarm(alarmInfo)

Optional alarm handler. Override to handle scheduled work. The base implementation is a no-op.
async alarm(info: AlarmInfo): Promise<void> {
  // at-least-once delivery — be idempotent
  // info.retryCount is 0 on first delivery; info.isRetry is true on retries
}
See Alarms for the delivery contract and retry policy.

fetch(req)

Optional HTTP-style entry. The base default returns 404. Override if you want callers to reach the actor over a raw Request instead of RPC methods:
async fetch(req: Request): Promise<Response> {
  return new Response("hello from " + this.ctx.id);
}
Callable from a binding as env.BINDING.idFromName(name).fetch(req).