State Store

The StateStore interface for persisting render records, and the built-in InMemoryStore factory.

A StateStore persists render records between the moment a render is started and the moment it is queried or cleaned up. It is used exclusively by the server adapter — the lambda adapter is stateless (state lives in the encoded handle and AWS Lambda itself).


StateStore interface

interface StateStore {
  create(handle: RenderHandle, record: RenderRecord): Promise<void>;
  get(handle: RenderHandle): Promise<RenderRecord | null>;
  update(handle: RenderHandle, patch: Partial<RenderRecord>): Promise<void>;
  delete(handle: RenderHandle): Promise<void>;
}

Methods

methoddescription
create(handle, record)Insert a new render record. Called by the adapter when a render starts.
get(handle)Return the record for handle, or null if not found.
update(handle, patch)Merge patch into the existing record. Throws RenderError("not_found") if the handle does not exist.
delete(handle)Remove the record. Must be idempotent — calling on a non-existent handle must not throw.

RenderRecord

type RenderRecord = {
  status: RenderStatus;
  progress: number;
  error?: string;
  errorCode?: RenderError["code"];
  codec: Codec;
  createdAt: number;       // Unix timestamp (ms)
  meta?: Record<string, unknown>;
};

InMemoryStore()

import { InMemoryStore } from "@remocn/render-sdk";

const store = InMemoryStore(); // call as a factory — do NOT use "new"

The built-in store backed by a Map<RenderHandle, RenderRecord>. All operations are synchronous internally but wrapped in Promise to match the interface.

When to use it

  • Single-process Node.js server (default for RenderServer)
  • Tests and local development
  • Any scenario where losing in-flight render records on process restart is acceptable

When NOT to use it

  • Multi-process deployments (e.g. PM2 cluster mode, Kubernetes with replicas > 1) — each process has its own Map; a request landing on a different process cannot find the handle
  • Any deployment where renders must survive a server restart

Custom stores

Implement StateStore against any persistence backend. The interface is small enough to wrap Redis, a database, or a shared key-value store in a few lines.

import type { StateStore, RenderHandle, RenderRecord } from "@remocn/render-sdk";

function RedisStore(client: RedisClient): StateStore {
  return {
    async create(handle, record) {
      await client.set(handle, JSON.stringify(record));
    },
    async get(handle) {
      const raw = await client.get(handle);
      return raw ? JSON.parse(raw) : null;
    },
    async update(handle, patch) {
      const existing = await client.get(handle);
      if (!existing) throw new RenderError("not_found", `Handle ${handle} not found`);
      await client.set(handle, JSON.stringify({ ...JSON.parse(existing), ...patch }));
    },
    async delete(handle) {
      await client.del(handle);
    },
  };
}

Pass the custom store to RenderServer:

import { RenderServer } from "@remocn/render-sdk/server";

const adapter = RenderServer({
  serveUrl,
  workDir: "./out",
  store: RedisStore(redisClient),
});

Or pass it directly to RenderSdk to override the adapter's default:

import { RenderSdk } from "@remocn/render-sdk";

const sdk = new RenderSdk({ adapter, store: RedisStore(redisClient) });

On this page