diff --git a/packages/docs/.gitignore b/packages/docs/.gitignore index c8a7336..0ff5702 100644 --- a/packages/docs/.gitignore +++ b/packages/docs/.gitignore @@ -1,2 +1,6 @@ .vercel .env*.local + +# Generated changelogs (built from GitHub releases) +docs/reference/changelog.md +docs/sdk/changelog-*.md diff --git a/packages/docs/docs/reference/changelog.md b/packages/docs/docs/reference/changelog.md deleted file mode 100644 index 2ce9a94..0000000 --- a/packages/docs/docs/reference/changelog.md +++ /dev/null @@ -1,72 +0,0 @@ -# Changelog - -## v2.1.0 — Native OAuth & Instance Settings - -- **Built-in OAuth** — replaced external AIP OAuth dependency with native `atrium-oauth` integration; HappyView manages the full OAuth flow internally -- **Instance settings** — new `instance_settings` key/value table for configurable instance metadata (app name, logo, ToS, privacy policy) with env var fallback -- **OAuth branding** — authorization screens now show configurable app name, logo, terms of service, and privacy policy links via the `/oauth-client-metadata.json` endpoint -- **Logo upload** — upload a logo image via `PUT /admin/settings/logo` (stored in DB, served at `GET /settings/logo`) -- **`settings:manage` permission** — new permission for managing instance settings, included in Manager and Full Access templates -- **Redirect URI support** — `/auth/login` accepts optional `redirect_uri` parameter for post-login navigation -- **CORS improvements** — origin-mirroring CORS with credentials support for cross-origin auth flows - -## v2.0.0 — User Permissions & Settings Restructure - -- **User permissions system** — replaced the `admins` table with a `users` table supporting 20 granular permissions, permission templates (Viewer, Operator, Manager, Full Access), and a super user concept with escalation and self-modification guards -- **API key permissions** — API keys now have explicit scoped permissions instead of inheriting full admin access; effective permissions are the intersection of the key's permissions and the user's permissions -- **User handles** — user handles are now displayed alongside DIDs throughout the dashboard -- **Settings sub-pages** — Settings page restructured into Users, ENV Variables, and API Keys sub-pages with collapsible sidebar navigation -- **Dashboard route prefix** — all dashboard pages now live under the `/dashboard` route prefix -- **New endpoints** — `GET /admin/users/{id}`, `PATCH /admin/users/{id}/permissions`, `POST /admin/users/transfer-super`, `GET/POST/DELETE /admin/script-variables` -- **New event types** — `user.permissions_updated`, `user.super_transferred`, `auth.permission_denied`, `api_key.created`, `api_key.revoked`, `script_variable.upserted`, `script_variable.deleted`, `hook.executed`, `hook.dead_lettered` - -## v1.9.0 — Event Logs - -- **Event logging** — system-wide audit trail for lexicon changes, record operations, Lua script executions/errors, admin actions, backfill jobs, and Jetstream connectivity -- **`GET /admin/events`** — query event logs with filtering by event type, category, severity, and subject, with cursor pagination -- **Lua error context** — script errors capture full debugging context: error message, script source, input payload, and caller DID -- **Automatic retention cleanup** — configurable via `EVENT_LOG_RETENTION_DAYS` (default 30 days) - -## v1.8.0 — Advanced Queries - -- **`db.backlinks()`** — find records that reference a given AT URI -- **`db.raw()`** — run raw read-only SQL with parameterized queries and automatic column type mapping - -## v1.7.1 — Patch - -- Fixed Docker Compose database URLs for local dev - -## v1.7.0 — Lua DB API Improvements - -- **`toarray()`** utility — force Lua tables to serialize as JSON arrays (fixes empty `{}` vs `[]`) -- **`db.search()`** — text search on record fields with relevance ranking -- **Array serialization fix** — `db.query()` and `db.search()` now always return proper arrays for `records` - -## v1.6.2 — Patch - -- Fixed auth: use original auth scheme instead of hardcoded DPoP - -## v1.6.1 — Patch - -- Fixed broken dynamic page routes - -## v1.6.0 — Record Management - -- **Delete records** from the dashboard and API (individual and bulk collection deletion) -- **"View Records" buttons** on lexicon pages -- Bug fixes: backfill now loads previously deleted records, empty collections shown in dropdown - -## v1.5.1 — Patch - -- Removed backfill toggle from query/procedure lexicons (only applies to record lexicons) - -## v1.5.0 — Lua Scripting & Dashboard Overhaul - -- **Lua scripting** — attach custom Lua scripts to query and procedure lexicons -- **Docusaurus docs site** with GitHub Pages deploy -- **Dark mode** for the dashboard -- **Records table** reworked with dynamic columns, column visibility, and better scrolling -- **Backfill stats tracking** -- **Network and local lexicons merged** into a unified view -- **Shiki code highlighting** in the dashboard -- Bug fixes: rogue record storage, collection dropdown, dynamic page builds diff --git a/packages/docs/package.json b/packages/docs/package.json index 78d92e5..7ccc467 100644 --- a/packages/docs/package.json +++ b/packages/docs/package.json @@ -4,7 +4,8 @@ "private": true, "scripts": { "start": "docusaurus start", - "build": "docusaurus build", + "generate-changelogs": "node scripts/generate-changelogs.mjs", + "build": "npm run generate-changelogs && docusaurus build", "clear": "docusaurus clear" }, "dependencies": { diff --git a/packages/docs/scripts/generate-changelogs.mjs b/packages/docs/scripts/generate-changelogs.mjs new file mode 100644 index 0000000..efe9c0f --- /dev/null +++ b/packages/docs/scripts/generate-changelogs.mjs @@ -0,0 +1,172 @@ +#!/usr/bin/env node + +const REPO = "gamesgamesgamesgamesgames/happyview"; +const API_BASE = "https://api.github.com"; + +const CHANGELOGS = [ + { + name: "HappyView", + output: "docs/reference/changelog.md", + sidebarLabel: "Changelog", + match: (tag) => /^v\d/.test(tag), + formatVersion: (tag) => tag, + }, + { + name: "@happyview/oauth-client", + output: "docs/sdk/changelog-oauth-client.md", + sidebarLabel: "Changelog", + match: (tag) => tag.startsWith("@happyview/oauth-client-v"), + formatVersion: (tag) => tag.replace("@happyview/oauth-client-", ""), + }, + { + name: "@happyview/oauth-client-browser", + output: "docs/sdk/changelog-oauth-client-browser.md", + sidebarLabel: "Changelog", + match: (tag) => tag.startsWith("@happyview/oauth-client-browser-v"), + formatVersion: (tag) => tag.replace("@happyview/oauth-client-browser-", ""), + }, + { + name: "@happyview/lex-agent", + output: "docs/sdk/changelog-lex-agent.md", + sidebarLabel: "Changelog", + match: (tag) => tag.startsWith("@happyview/lex-agent-v"), + formatVersion: (tag) => tag.replace("@happyview/lex-agent-", ""), + }, +]; + +const token = process.env.GITHUB_TOKEN || process.env.GH_TOKEN; + +async function fetchAllReleases() { + const releases = []; + let page = 1; + + while (true) { + const url = `${API_BASE}/repos/${REPO}/releases?per_page=100&page=${page}`; + const headers = { Accept: "application/vnd.github+json" }; + if (token) headers.Authorization = `Bearer ${token}`; + + const res = await fetch(url, { headers }); + + if (!res.ok) { + if (res.status === 403 && !token) { + console.warn( + "GitHub API rate limit hit. Set GITHUB_TOKEN or GH_TOKEN to authenticate." + ); + return null; + } + throw new Error(`GitHub API error: ${res.status} ${res.statusText}`); + } + + const batch = await res.json(); + if (batch.length === 0) break; + releases.push(...batch); + page++; + } + + return releases; +} + +function cleanReleaseBody(body) { + if (!body) return ""; + let cleaned = body.trim(); + cleaned = cleaned.replace(/^#{1,3}\s+.*?\d+\.\d+\.\d+.*\n*/m, ""); + cleaned = cleaned.trim(); + return cleaned; +} + +function buildMarkdown(changelog, releases) { + const matching = releases + .filter((r) => !r.prerelease && changelog.match(r.tag_name)) + .sort((a, b) => new Date(b.published_at) - new Date(a.published_at)); + + if (matching.length === 0) return null; + + const lines = [ + "---", + `sidebar_label: "${changelog.sidebarLabel}"`, + "---", + "", + `# ${changelog.name} Changelog`, + "", + ``, + "", + ]; + + for (const release of matching) { + const version = changelog.formatVersion(release.tag_name); + const date = release.published_at.slice(0, 10); + const title = release.name && release.name !== release.tag_name + ? `${version} — ${release.name}` + : version; + + lines.push(`## ${title}`); + lines.push(""); + lines.push(`*Released ${date}*`); + lines.push(""); + + const body = cleanReleaseBody(release.body); + if (body) { + lines.push(body); + } + + lines.push(""); + } + + return lines.join("\n"); +} + +import { writeFileSync, readFileSync, existsSync } from "node:fs"; +import { resolve, dirname } from "node:path"; +import { mkdirSync } from "node:fs"; + +const ROOT = dirname(new URL(import.meta.url).pathname).replace( + /\/scripts$/, + "" +); + +async function main() { + console.log("Fetching releases from GitHub..."); + const releases = await fetchAllReleases(); + + if (releases === null) { + console.warn("Skipping changelog generation (no API access). Using existing files."); + return; + } + + console.log(`Found ${releases.length} total releases.`); + + const generated = []; + + for (const changelog of CHANGELOGS) { + let md = buildMarkdown(changelog, releases); + if (!md) { + md = [ + "---", + `sidebar_label: "${changelog.sidebarLabel}"`, + "---", + "", + `# ${changelog.name} Changelog`, + "", + ``, + "", + "No releases yet.", + "", + ].join("\n"); + console.log(` ${changelog.name}: no releases found, wrote placeholder.`); + } else { + console.log(` ${changelog.name}: wrote ${changelog.output}`); + } + + const outPath = resolve(ROOT, changelog.output); + mkdirSync(dirname(outPath), { recursive: true }); + writeFileSync(outPath, md); + generated.push(changelog); + } + + console.log(`Generated ${generated.length} changelog(s).`); +} + +main().catch((err) => { + console.error("Changelog generation failed:", err.message); + process.exit(1); +}); diff --git a/packages/docs/sidebars.ts b/packages/docs/sidebars.ts index 0b90bc7..66ab8fb 100644 --- a/packages/docs/sidebars.ts +++ b/packages/docs/sidebars.ts @@ -271,6 +271,27 @@ const sidebars: SidebarsConfig = { id: "sdk/oauth-client-browser", label: "Browser Client", }, + { + type: "category", + label: "Changelogs", + items: [ + { + type: "doc", + id: "sdk/changelog-oauth-client", + label: "OAuth Client", + }, + { + type: "doc", + id: "sdk/changelog-oauth-client-browser", + label: "Browser Client", + }, + { + type: "doc", + id: "sdk/changelog-lex-agent", + label: "Lex Agent", + }, + ], + }, ], }, { @@ -409,6 +430,11 @@ const sidebars: SidebarsConfig = { id: "reference/troubleshooting", label: "Troubleshooting", }, + { + type: "doc", + id: "reference/changelog", + label: "Changelog", + }, ], }, ],