Rebasely Beta: data may be purged

examples/live-notes Public

TypeScript · 43 lines · 2.0 KiB · at 70b1506

// 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;}