UNPKG

diffable-objects

Version:

A package for dynamic state tracking for Cloudflare's Durable Objects using SQLite

53 lines (52 loc) 1.8 kB
import { recursivelyObservable } from "./observable.js"; import { SqliteState } from "./sqlite.js"; import { unreachable } from "./util.js"; export * from "./decorator.js"; /** * Dynamically create a state object that persists changes to durable storage using Proxy and SQLite. * * @example * ``` * import { DurableObject } from "cloudflare:workers"; * import { state } from "diffable-objects"; * * class Counter extends DurableObject { * #state = state(this, "counter", { count: 0 }); * * async fetch(request) { * this.#state.count += 1; * return new Response(`Count: ${this.#state.count}`); * } * } * ``` * * @param ctx the DurableObject state. * @param name the name of the state, typically the name of the field. * @param initialState the initial state of this object, this must be the same every time the DO is created. * @param options options for configuring how the state is persisted. * @returns a copy of state that will persist changes. */ export function state(ctx, name, initialState, options = { snapshotPolicy: { changes: 10 }, }) { const state = new SqliteState(name, ctx.storage); const data = state.resume(initialState); return recursivelyObservable(data, { onUpdate(changes, data) { state.appendChanges(changes); maybeSnapshot(data, state, options.snapshotPolicy ?? { changes: 10 }); }, }); } function maybeSnapshot(data, state, snapshotPolicy) { if (snapshotPolicy === "every-change") { state.snapshot(data); } else if (typeof snapshotPolicy === "object" && "changes" in snapshotPolicy) { const latest = state.latestChange() ?? unreachable(); if (latest.id % snapshotPolicy.changes === 0) { state.snapshot(data); } } }