canvas-free.openapps.xyz

Source

This app’s code and revision history are public. Download a copy or explore the files below.

Public
The app’s code and revision history are public.
Owned app · rev 93fdaafeda16
Run it yourself
Take the whole tree and run it on your own machine. The download needs no account. Cloning needs a sign-in.
Download .zip
bounded clone 788ba0fa01083b300ad50913
A copy you download is not bounded. The guarantees this app runs under - declared egress, proven invariants, writes that fail closed - live in the runtime serving this page, not in the files. What you get is auditable source you can read and run, with no runtime guarantees attached.
← All files
src/lib/boards.ts
// Making, re-keying and deleting boards. Loaded when someone starts or opens a board, not with the
// landing page.
import { get, getFiles, set, setMany, serverTimestamp } from "@bounded-sh/client";
import { me } from "./bounded";
import { editPath, forgetBoard, rememberBoard } from "./mine";
import { randomId, type Seed } from "../../functions/lib/canvas";

/** Makes a board owned by this browser and returns where to open it. */
export async function createBoard(title: string, seed: Seed | null): Promise<string> {
  const uid = await me();
  const id = randomId(20);
  const edit = randomId(24);
  const admin = randomId(24);
  await setMany([
    { path: `boards/${id}`, document: { title, editOn: true, viewOn: true, seed: seed ? JSON.stringify(seed) : "", createdBy: uid, createdAt: serverTimestamp() } },
    { path: `boards/${id}/joins/${uid}`, document: { at: serverTimestamp(), key: edit } },
    { path: `boards/${id}/owners/${uid}`, document: { at: serverTimestamp() } },
    { path: `boardkeys/${id}`, document: { key: admin } },
    { path: `editkeys/${id}`, document: { key: edit } },
  ]);
  rememberBoard({ id, title, edit, admin });
  return editPath(id, edit);
}

/** Owners only: replaces the edit key, which stops the old edit link at once. Returns the new key. */
export async function newEditKey(id: string): Promise<string> {
  const uid = await me();
  const key = randomId(24);
  await set(`editkeys/${id}`, { key });
  await set(`boards/${id}/joins/${uid}`, { key });
  rememberBoard({ id, edit: key });
  return key;
}

/** Owners only: turns both links off, removes everything on the board, then the board itself. */
export async function deleteBoard(id: string) {
  await set(`boards/${id}`, { editOn: false, viewOn: false });
  for (const sub of ["els", "cursors"]) {
    // Each pass deletes the first page; stop when nothing is left (or after far more passes than any board needs).
    for (let pass = 0; pass < 500; pass++) {
      const res = (await get(`boards/${id}/${sub}`, { limit: 100 })) as { data: { id: string }[] };
      if (!res?.data?.length) break;
      await setMany(res.data.map((r) => ({ path: `boards/${id}/${sub}/${r.id}`, document: null })));
    }
  }
  const files = (await getFiles(`boards/${id}/files`)) as { data?: { path: string }[] };
  for (const f of files?.data || []) await set(f.path, null);
  await set(`boards/${id}`, null);
  forgetBoard(id);
}

Change history

Point OpenApps links to openapps.free
93fdaafeda · 18 hours ago
Bind AGENT_ADDRESS in policy constants
bf8f43b096 · 20 hours ago
Use functions.openapps.xyz alias, add OpenApp contribution strip
56f1a381b2 · 20 hours ago
Bounded source sync
9ec707aeb8 · 1 day ago
Bounded source sync
5645481c23 · 1 day ago
Bounded source sync
c38fe71874 · 1 day ago
Bounded source sync
28c0350b40 · 1 day ago