examples/live-notes Public
// Copies of a note's text in R2, saved by its room every SNAPSHOT_EVERY versions (room.ts). The// room's own SQLite holds only the latest text and the last LOG_SIZE ops; these let anyone read// what the note said further back, without waking the room.//// Keys are snapshots/<object id>/<version>.txt. The object id is the room's// idFromName(note id), which the Worker computes the same way, so it can list and read a note's// snapshots straight from the bucket. Versions are zero-padded so keys list in version order.import type { Note } from "./room.ts";export type SnapshotInfo = { version: number; saved_at: string; size: number };export type SnapshotPage = { snapshots: SnapshotInfo[]; next: number | null };export const PAGE = 100;const DIGITS = 12;export function snapshotKey(objectId: string, version: number): string { return `snapshots/${objectId}/${String(version).padStart(DIGITS, "0")}.txt`;}export async function saveSnapshot(bucket: R2Bucket, objectId: string, note: Note): Promise<void> { await bucket.put(snapshotKey(objectId, note.version), note.text, { httpMetadata: { contentType: "text/plain; charset=utf-8" }, });}// A note's snapshots in version order, PAGE at a time, starting after version `after`.export async function listSnapshots(bucket: R2Bucket, objectId: string, after = 0): Promise<SnapshotPage> { const prefix = `snapshots/${objectId}/`; const page = await bucket.list({ prefix, startAfter: snapshotKey(objectId, after), limit: PAGE }); const snapshots = page.objects.map((o) => ({ version: Number(o.key.slice(prefix.length, -".txt".length)), saved_at: o.uploaded.toISOString(), size: o.size, })); return { snapshots, next: page.truncated ? (snapshots.at(-1)?.version ?? null) : null };}// The note's text at `version`, or null when there is no snapshot of that version.export async function readSnapshot(bucket: R2Bucket, objectId: string, version: number): Promise<string | null> { const object = await bucket.get(snapshotKey(objectId, version)); return object ? object.text() : null;}