Skip to main content

DURABLE_OBJECT_TEMPLATE_JS

Constant DURABLE_OBJECT_TEMPLATE_JS 

Source
pub const DURABLE_OBJECT_TEMPLATE_JS: &str = r#"
// Auto-generated. One class per shard type.
// Wires up fetch handling, WebSocket accept/hibernation, and alarm-based ticks.
export class ShardDO {
  constructor(state, env) {
    this.state = state;
    this.env = env;
    this.sockets = new Map(); // sid -> WebSocket
    this.tickRateHz = env.TICK_RATE_HZ || 20;
  }

  async fetch(req) {
    const url = new URL(req.url);
    const sid = url.searchParams.get('sid') || 'anon';

    if (req.headers.get('Upgrade') === 'websocket') {
      const pair = new WebSocketPair();
      const [client, server] = Object.values(pair);
      this.state.acceptWebSocket(server); // hibernation-compatible
      this.sockets.set(sid, server);
      if (!(await this.state.storage.get('alarm_set'))) {
        await this.state.storage.setAlarm(Date.now() + (1000 / this.tickRateHz));
        await this.state.storage.put('alarm_set', true);
      }
      return new Response(null, { status: 101, webSocket: client });
    }
    return new Response('not found', { status: 404 });
  }

  async webSocketMessage(ws, message) {
    // Forward input JSON into the shard's input queue (via bound Wasm fn).
    this.env.SHARD_IMPORT.pushInput(this.state.id.toString(), message);
  }

  async webSocketClose(ws) {
    for (const [sid, s] of this.sockets) {
      if (s === ws) this.sockets.delete(sid);
    }
  }

  async alarm() {
    // Run one tick and broadcast to all connected sockets.
    const snapshot = this.env.SHARD_IMPORT.runTick(this.state.id.toString());
    for (const ws of this.sockets.values()) {
      try { ws.send(snapshot); } catch {}
    }
    // Reschedule.
    await this.state.storage.setAlarm(Date.now() + (1000 / this.tickRateHz));
  }
}
"#;
Expand description

The boilerplate a user adds to their Workers bundle’s JS entry file.

This can’t be generated from Rust alone (the DO class must be exported from JS so the Workers runtime can instantiate it), so we ship this as a string constant that the pylon deploy --target workers command can drop into the generated bundle.