From 1c7b54ea76a23f1e887a5834ad2b919c7f25adba Mon Sep 17 00:00:00 2001 From: cevheri Date: Tue, 30 Jun 2026 04:21:49 +0300 Subject: [PATCH 01/22] docs(playground): design spec for in-browser OPFS LibreDB editor (#19) Co-Authored-By: Claude Opus 4.8 (1M context) --- ...026-06-30-playground-opfs-editor-design.md | 178 ++++++++++++++++++ 1 file changed, 178 insertions(+) create mode 100644 docs/superpowers/specs/2026-06-30-playground-opfs-editor-design.md diff --git a/docs/superpowers/specs/2026-06-30-playground-opfs-editor-design.md b/docs/superpowers/specs/2026-06-30-playground-opfs-editor-design.md new file mode 100644 index 0000000..7267954 --- /dev/null +++ b/docs/superpowers/specs/2026-06-30-playground-opfs-editor-design.md @@ -0,0 +1,178 @@ +# /playground — in-browser, zero-backend LibreDB editor (OPFS-backed) + +**Issue:** [libredb/libredb.github.io#19](https://github.com/libredb/libredb.github.io/issues/19) +**Date:** 2026-06-30 +**Repo:** libredb-website (libredb.github.io) +**Engine guide (authoritative):** `libredb-database/docs/BROWSER.md` + +## Goal + +Add a public route `/playground` that runs a **real LibreDB database entirely in the +browser**, backed by OPFS persistence shipped in `@libredb/libredb@0.1.3`. A visitor +lands on a working database preloaded with a sample dataset and a clickable command +cheatsheet, and can operate the database without typing anything and without signing in. + +This is a **separate route**, not a change to the marketing homepage. The homepage hero +"SQL editor" stays a stylized mock; `/playground` is the "use it for real, right now" +surface. + +## Decisions (locked in brainstorming) + +- **Editor approach:** native editor built on the site's existing IDE-shell components. + The "real Studio Monaco editor" lives in the separate `libredb-studio` repo and is not + packaged for browser use — out of scope for this repo. We reuse `StudioShell`, + `Explorer`, `Console`, `CommandPalette`, `StatusBar`, and the `Sql.astro` highlighter. +- **Route name:** `/playground`. +- **Scope:** full feature set (OPFS worker + 3-lens seed + clickable cheatsheet + Reset + sandbox + in-memory fallback + `db.close()` teardown + SSR-safe island). + +## Constraints (from BROWSER.md / issue) + +- Import the **browser entry**: `@libredb/libredb/browser` (no `node:` in its import graph). +- `open()` (no path) → in-memory, works anywhere. `open({ path, fs })` → durable, needs `fs`. +- **OPFS sync access handles exist only inside a dedicated Web Worker, secure context only** + (HTTPS or `localhost`). Acquire the handle async once, then `open` is synchronous. +- **Single-writer:** `createSyncAccessHandle()` takes an exclusive lock; a second tab cannot + open the same file. For a public demo, fall back to in-memory on contention. +- **No LibreDB code during SSR** — Astro renders on Node where `window`/`navigator.storage`/ + `Worker` don't exist. All engine code runs in client-only ` +``` + +- [ ] **Step 3: Create `src/pages/playground.astro`** + +```astro +--- +import Layout from "../layouts/Layout.astro"; +import StudioShell from "../components/studio/StudioShell.astro"; +import Playground from "../components/studio/Playground.astro"; +--- + + + + + + +``` + +- [ ] **Step 4: Add the nav link in `src/components/studio/TopBar.astro`** + +Read the file first. Find the existing top-bar link/menu markup and add, following the surrounding pattern, a link whose `href="/playground"` labeled `Playground`. Do **not** modify `src/data/sections.ts` (that drives the schema explorer rows and homepage nav). Keep the change to a single anchor consistent with the existing nav items. + +- [ ] **Step 5: Verify it builds and renders** + +Run: `bun run build 2>&1 | tail -25` +Expected: build succeeds; `dist/playground/index.html` exists. +Then revert the build-mutated compose files: +Run: `git checkout -- src/data/docker-compose.example.yml public/docker-compose.example.yml 2>/dev/null; git status --short` +Expected: only the new/intended files show as changes. + +- [ ] **Step 6: Commit** + +```bash +git add src/components/studio/Cheatsheet.astro src/components/studio/Playground.astro src/pages/playground.astro src/components/studio/TopBar.astro +git commit -m "feat(playground): editor pane, cheatsheet, route, nav link (#19)" +``` + +--- + +## Task 6: Gate + browser verification (Playwright) + +**Files:** none created — verification only. + +- [ ] **Step 1: Run the full gate** + +Run: `bun run gate 2>&1 | tail -30` +Expected: typecheck, format, lint, knip, and all `bun:test` pass. Fix any failures (likely knip on unused exports — ensure every new export is consumed; prettier — run `bun run format:fix`). + +- [ ] **Step 2: Serve the production build with caching disabled** + +Run (background): `bunx http-server dist -p 8081 -c-1` +(Use a cache-disabled static server per the repo's VT runtime-testing note.) + +- [ ] **Step 3: Playwright — load and assert seed renders** + +Navigate to `http://localhost:8081/playground`. Take a snapshot. Assert: +- The result grid shows the 3 seeded users (Ada, Linus, Grace). +- The persistence badge reads `OPFS · persistent` (Chromium on localhost is a secure context with OPFS). + +- [ ] **Step 4: Playwright — click-to-run, persist, reset** + +- Click the cheatsheet button `insert into users {"id":"4","name":"Lin","age":29,"active":true}`, then `select * from users` → assert a 4th row `Lin` appears. +- Reload the page → assert `Lin` is still present (OPFS persistence across reload). +- Click `↺ Reset sandbox` → assert the grid returns to exactly the 3 seed rows. +- Click `prefix config:` → assert key/value rows for `config:*` render. + +- [ ] **Step 5: Confirm no `node:` in the client bundle** + +Run: `grep -rl "node:fs\|require(\"fs\")\|node_fs" dist/assets/*.js | head` (or scan the playground chunk). +Expected: no matches — the browser entry pulled no `node:` module into the client bundle. + +- [ ] **Step 6: Final commit (if any verification fixes were needed)** + +```bash +git add -A && git commit -m "test(playground): gate fixes + browser-verified OPFS demo (#19)" +``` + +--- + +## Self-Review + +- **Spec coverage:** Public no-login route (Task 5) ✓ · client-side OPFS Worker, no backend (Tasks 3,6) ✓ · 3-lens seed (Task 2) ✓ · clickable palette (Tasks 4,5) ✓ · persist + isolate + reset (Tasks 3,6) ✓ · no `node:fs`, marketing build unaffected (Task 6, TopBar-only nav change) ✓ · in-memory fallback + notice (Tasks 3,4,5) ✓ · `db.close()` teardown (Tasks 3,4) ✓ · no SSR engine code (Task 5 client-only ` diff --git a/src/components/studio/TopBar.astro b/src/components/studio/TopBar.astro index 9bca776..29d1f56 100644 --- a/src/components/studio/TopBar.astro +++ b/src/components/studio/TopBar.astro @@ -43,6 +43,9 @@ const DEMO = 'https://app.libredb.org'; data-action="notice" data-notice="monitoring"> Monitoring + + Playground +