v0.6.5: Renderer pipeline, docs rewrite, architecture diagrams
All checks were successful
CI/CD / detect-changes (pull_request) Successful in 4s
CI/CD / test-frontend (pull_request) Successful in 6s
CI/CD / test-go-pg (pull_request) Successful in 2m43s
CI/CD / test-sqlite (pull_request) Successful in 2m51s
CI/CD / build-and-deploy (pull_request) Successful in 1m13s
All checks were successful
CI/CD / detect-changes (pull_request) Successful in 4s
CI/CD / test-frontend (pull_request) Successful in 6s
CI/CD / test-go-pg (pull_request) Successful in 2m43s
CI/CD / test-sqlite (pull_request) Successful in 2m51s
CI/CD / build-and-deploy (pull_request) Successful in 1m13s
Lift block rendering to kernel SDK primitives (sw.renderers + sw.markdown) so all surfaces share one markdown pipeline. Rewrite docs for external audience — remove all fork history references. Add Mermaid architecture diagrams, CONTRIBUTING guide, and extension tutorial. - sw.renderers SDK module: kernel-level renderer registry - sw.markdown SDK module: unified marked v16 + DOMPurify pipeline - Browser extension script loader for renderer injection - Notes + Docs surfaces migrated to sw.markdown.renderSync() - 4 renderer extensions rewritten to IIFE + sw.renderers.register() - 6 Mermaid diagrams in ARCHITECTURE.md - CONTRIBUTING.md + TUTORIAL-FIRST-EXTENSION.md - DESIGN-WORKFLOWS.md replaces fork-era design doc - Surface alias routes removed from main.go - ICD/SDK runners migrated to /admin/packages/ endpoints - 13 new renderer tests - Docs, CHANGELOG, ROADMAP cleaned of fork references Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
119
docs/TUTORIAL-FIRST-EXTENSION.md
Normal file
119
docs/TUTORIAL-FIRST-EXTENSION.md
Normal file
@@ -0,0 +1,119 @@
|
||||
# Build Your First Browser Extension
|
||||
|
||||
This tutorial walks through building a browser extension that renders custom
|
||||
code blocks, modeled on the CSV Table Viewer that ships with Switchboard.
|
||||
|
||||
**Prerequisites:** A running Switchboard instance, a text editor, and `zip`.
|
||||
|
||||
## Step 1: Create the Directory
|
||||
|
||||
```sh
|
||||
mkdir -p my-extension/js
|
||||
```
|
||||
|
||||
## Step 2: Write the Manifest
|
||||
|
||||
Create `my-extension/manifest.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "my-extension",
|
||||
"title": "My Extension",
|
||||
"version": "0.1.0",
|
||||
"type": "extension",
|
||||
"tier": "browser",
|
||||
"author": "you",
|
||||
"description": "Renders demo code blocks as styled HTML",
|
||||
"permissions": [],
|
||||
"settings": {}
|
||||
}
|
||||
```
|
||||
|
||||
- **id** -- unique identifier, used as the install key
|
||||
- **type** -- `extension` for browser-only packages; `full` or `surface` for
|
||||
packages with backend routes
|
||||
- **tier** -- `browser` for client-side JS; `starlark` for server-side scripting
|
||||
|
||||
## Step 3: Write the Browser Script
|
||||
|
||||
Create `my-extension/js/script.js`. Browser extensions use the IIFE pattern
|
||||
and register with the SDK through `sw.renderers`:
|
||||
|
||||
```js
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
function register() {
|
||||
if (!window.sw?.renderers) return;
|
||||
|
||||
sw.renderers.register('demo-block', {
|
||||
type: 'block',
|
||||
priority: 10,
|
||||
match(lang) {
|
||||
return (lang || '').toLowerCase() === 'demo';
|
||||
},
|
||||
render(lang, code, container) {
|
||||
container.innerHTML =
|
||||
'<div style="padding:12px;background:var(--bg-2);' +
|
||||
'border:1px solid var(--border);border-radius:8px">' +
|
||||
'<strong>Demo:</strong> ' + code +
|
||||
'</div>';
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (window.sw?._sdk) {
|
||||
register();
|
||||
} else {
|
||||
document.addEventListener('sw:ready', register, { once: true });
|
||||
}
|
||||
})();
|
||||
```
|
||||
|
||||
The IIFE wrapper keeps variables out of global scope. `sw.renderers.register`
|
||||
takes a name and an options object: `type: 'block'` targets fenced code blocks,
|
||||
`match` checks the language tag, and `render` receives the language, raw code,
|
||||
and a container element. The `sw:ready` event fires once the SDK initializes;
|
||||
if already loaded, register immediately. Use CSS variables like `var(--bg-2)`
|
||||
and `var(--border)` to follow the active theme.
|
||||
|
||||
## Step 4: Package It
|
||||
|
||||
```sh
|
||||
cd my-extension
|
||||
zip -r ../my-extension.pkg manifest.json js/
|
||||
```
|
||||
|
||||
The `.pkg` format is a ZIP with `manifest.json` at the root. Optional
|
||||
directories: `js/`, `css/`, `assets/`. If working inside `packages/`, use
|
||||
the build script instead: `bash build.sh my-extension`.
|
||||
|
||||
## Step 5: Install It
|
||||
|
||||
```sh
|
||||
curl -X POST http://localhost:3000/api/v1/admin/packages/install \
|
||||
-H "Authorization: Bearer <token>" \
|
||||
-F "file=@my-extension.pkg"
|
||||
```
|
||||
|
||||
You can also install through the Admin UI under the Packages section.
|
||||
|
||||
## Step 6: Enable and Test
|
||||
|
||||
1. Open the admin panel, navigate to Packages, confirm "My Extension" is enabled.
|
||||
2. Go to any markdown surface (Chat, Notes, etc.).
|
||||
3. Enter a fenced code block with the `demo` language tag.
|
||||
|
||||
You should see styled output instead of a plain code block.
|
||||
|
||||
## Going Further
|
||||
|
||||
- **Add CSS** -- create a `css/` directory; stylesheets are injected automatically.
|
||||
- **Post-renderers** -- register with `type: 'post'` to run after block renderers
|
||||
finish (the Mermaid extension uses this for async SVG rendering).
|
||||
- **Settings** -- declare a `settings` object in the manifest for admin-configurable values.
|
||||
- **Server-side logic** -- set `tier: "starlark"` and add `script.star` for
|
||||
backend API routes and database tables.
|
||||
|
||||
See `PACKAGE-FORMAT.md` for the full manifest spec and `EXTENSION-GUIDE.md`
|
||||
for advanced patterns.
|
||||
Reference in New Issue
Block a user