import type { Database } from "bun:sqlite"; import * as TID from "@atcute/tid"; import { getDevAccounts } from "../../atproto/env.ts"; import { createDiff } from "../../lib/diff.ts"; interface SeedNote { slug: string; title: string; content: string; } function seedWiki( db: Database, owner: { did: string; handle: string }, slug: string, name: string, description: string, notes: SeedNote[], ): void { const wikiAtUri = `at://${owner.did}/wiki.lichen.wiki/${slug}`; db.run( "INSERT INTO wikis (slug, did, name, visibility, description, at_uri) VALUES (?, ?, ?, ?, ?, ?)", [slug, owner.did, name, "public", description, wikiAtUri], ); db.run( "INSERT INTO memberships (wiki_at_uri, wiki_slug, did, role, at_uri) VALUES (?, ?, ?, ?, ?)", [ wikiAtUri, slug, owner.did, "admin", `at://${owner.did}/wiki.lichen.membership/${TID.now()}`, ], ); for (const note of notes) { const noteAtUri = `at://${owner.did}/wiki.lichen.note/${TID.now()}`; const revisionAtUri = `at://${owner.did}/wiki.lichen.noteRevision/${TID.now()}`; db.run( "INSERT INTO notes (slug, wiki_at_uri, wiki_slug, title, did, at_uri) VALUES (?, ?, ?, ?, ?, ?)", [note.slug, wikiAtUri, slug, note.title, owner.did, noteAtUri], ); // Initial revision + snapshot so the seeded note has a history entry. db.run( `INSERT INTO revisions (note_at_uri, did, at_uri, parent_revision_uri, diff, message) VALUES (?, ?, ?, NULL, ?, ?)`, [ noteAtUri, owner.did, revisionAtUri, createDiff("", note.content), "Initial content", ], ); db.run( "INSERT INTO snapshots (note_at_uri, revision_at_uri, content) VALUES (?, ?, ?)", [noteAtUri, revisionAtUri, note.content], ); db.run( `INSERT INTO current_note (note_at_uri, content, latest_revision_uri, updated_at) VALUES (?, ?, ?, datetime('now'))`, [noteAtUri, note.content, revisionAtUri], ); } } export function seedIfEmpty(db: Database): void { const count = db.query("SELECT COUNT(*) as n FROM wikis").get() as { n: number; }; if (count.n > 0) return; const accounts = getDevAccounts(); if (!accounts) return; const alice = accounts["alice"]; const bob = accounts["bob"]; if (!alice || !bob) return; console.log("Seeding database with sample data..."); db.run("BEGIN TRANSACTION"); try { for (const account of Object.values(accounts)) { db.run( "INSERT OR IGNORE INTO profile_cache (did, handle) VALUES (?, ?)", [account.did, account.handle], ); } seedWiki( db, alice, "alices-garden", "Alice's Garden", "A sample public wiki owned by Alice for exploring Lichen.", [ { slug: "home", title: "Home", content: `# Welcome to Alice's Garden This is the **home page**. Try editing it, then check the history. - [[hello|Hello]] — a sample note - [[@bob.test/bobs-notebook/home|Bob's Notebook]] — Alice contributes there too `, }, { slug: "hello", title: "Hello", content: `# Hello A short note. Edit me to see how diffs work. `, }, ], ); seedWiki( db, bob, "bobs-notebook", "Bob's Notebook", "A sample public wiki owned by Bob. Alice has contributor access.", [ { slug: "home", title: "Home", content: `# Bob's Notebook Bob owns this wiki. Alice can edit notes here as a contributor. `, }, ], ); // Alice is a contributor on Bob's wiki — log in as alice and edit it. db.run( "INSERT INTO memberships (wiki_at_uri, wiki_slug, did, role, at_uri) VALUES (?, ?, ?, ?, ?)", [ `at://${bob.did}/wiki.lichen.wiki/bobs-notebook`, "bobs-notebook", alice.did, "contributor", `at://${bob.did}/wiki.lichen.membership/${TID.now()}`, ], ); db.run("COMMIT"); } catch (err) { db.run("ROLLBACK"); throw err; } }