plugins contribute dock tiles, and the doc says what is actually built
offscale had no dock tile: that field comes from the app store's catalogue, so a plugin installed through the plugin system was reachable only by typing its url or following the link on /plugins. built at runtime rather than baked into the generated bundle, deliberately — WHO sees a tile is a permission question, and a grant takes effect on the next request rather than the next build. presentation comes from the manifest and the route from mountPrefix, so there is one source for both, and is the plugin's first permission so the endpoint can filter a tile out for an account that cannot reach the screen. two sources for tiles today, because the app store still has its own catalogue. one when it is rebuilt on this. the doc now records the system as complete rather than half-stubbed, including the three bugs the extraction found — the sidecar-before-mount ordering, the missing tailwind, and the build that could delete its own shell — and what is genuinely still open. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
+45
-36
@@ -605,48 +605,57 @@ Used for both `/api/...` and the frontend route. Nothing else in the codebase ma
|
||||
|
||||
---
|
||||
|
||||
## What is built, as of 2026-08-14
|
||||
## What is built — complete, as of 2026-08-15
|
||||
|
||||
The plugin system works end to end for a plugin that has an `api/router.ts`. Verified against a running
|
||||
server, with **no restart at any point**:
|
||||
**Offscale is a plugin, and nothing in the system is a stub.** Validated by the owner against the live
|
||||
server across repeated install / enable / disable / uninstall cycles, checking PM2 and the frontend each
|
||||
time.
|
||||
|
||||
```
|
||||
/api/example/ping BEFORE install 404
|
||||
AFTER install 200 {"plugin":"example","ok":true}
|
||||
AFTER disable 404
|
||||
AFTER enable 200
|
||||
AFTER uninstall 404
|
||||
core routes throughout 200
|
||||
```
|
||||
| Piece | Where |
|
||||
| --------------------------------------- | ---------------------------------------------------- |
|
||||
| Manifest, `mountPrefix`, validation | `servers/plugins/manifest.ts` |
|
||||
| Discovery by convention | `servers/plugins/discover.ts` |
|
||||
| Disk ⋈ database, mounts, dock manifests | `servers/plugins/mount.ts` |
|
||||
| Install runner, four verbs, streamed | `servers/plugins/install.ts` |
|
||||
| PM2 ecosystem entry | `servers/plugins/ecosystem.ts` |
|
||||
| Schema barrel + `db:push` | `servers/plugins/schema.ts` |
|
||||
| `Plugins.gen.tsx` + `Bun.build` | `servers/plugins/generate.ts` |
|
||||
| `buildHonoApp` / `rebuildHonoApp` | `servers/hono.ts` |
|
||||
| Capability registration | `capabilities/registry.ts` → `setPluginCapabilities` |
|
||||
| Install state | `plugin_installs` |
|
||||
| The screen | `/plugins`, two panels, SSE log |
|
||||
| The reference plugin | `plugins/example/` |
|
||||
| **The first real plugin** | `plugins/offscale/` — 45 files |
|
||||
|
||||
| Piece | Where |
|
||||
| ------------------------------------------- | --------------------------------------------- |
|
||||
| Manifest type, `mountPrefix`, validation | `servers/plugins/manifest.ts` |
|
||||
| Discovery by convention | `servers/plugins/discover.ts` |
|
||||
| Disk ⋈ database, and the rebuild | `servers/plugins/mount.ts` |
|
||||
| `buildHonoApp` / `rebuildHonoApp` | `servers/hono.ts` |
|
||||
| The closure that makes the swap take effect | `server.tsx`, the `/api/*` route |
|
||||
| Install state | `plugin_installs` (`officer_db/src/plugins/`) |
|
||||
| The four verbs | `servers/api/plugins/router.ts`, owner-only |
|
||||
| The screen | `/plugins` — two panels, `?selected=` |
|
||||
| The reference plugin | `plugins/example/` — meant to be read |
|
||||
Nothing needs a restart. Routes swap by rebuilding the Hono app, the sidecar gets a PM2 entry, the
|
||||
frontend is regenerated and rebuilt in ~3s, capabilities are registered before routes mount, and the
|
||||
whole thing survives a restart because boot regenerates and mounts before `serve()`.
|
||||
|
||||
### Not wired yet
|
||||
### Three bugs the extraction found
|
||||
|
||||
Worth recording because none were visible from reading:
|
||||
|
||||
1. **Install started the sidecar before mounting.** `createSidecarProxy` learns its port from a one-shot
|
||||
`<name>:server` event and subscribes when the plugin's router is first imported — at mount. So the
|
||||
announcement fired into a void: process online, routes mounted, every request `503 sidecar not
|
||||
available`. It would have hit every plugin with an HTTP sidecar; `example` never caught it because it
|
||||
has no listener to announce. Install and enable now mount first.
|
||||
2. **The built SPA had no Tailwind.** `bunfig.toml` declares the plugin under `[serve.static]`, which
|
||||
applies to Bun's static serving and not to a programmatic `Bun.build()`.
|
||||
3. **The build could destroy itself.** Clearing `build/` before building meant a failed build left
|
||||
nothing, and two overlapping builds could delete each other's shell. It now stages and swaps.
|
||||
|
||||
### Still open
|
||||
|
||||
- **The schema push.** A plugin with `db/schema.ts` installs, but its tables are not created. Marked
|
||||
`[open]` in the router.
|
||||
- **The sidecar's PM2 entry.** A plugin with `sidecar/` installs, but no process starts. This is the same
|
||||
hole `app-store/pm2.ts:23-29` documents for the app store, and it is the next thing to build.
|
||||
- **Websocket providers.** `server.reload({ routes })` is proven but not called; Bun's route table is
|
||||
still the six hardcoded providers.
|
||||
- **Totality across plugin routes.** `PROTECTED_API_PREFIXES` remains the core list, so plugin mounts are
|
||||
not covered by the boot check — and the check is reading the wrong list anyway (see below). The
|
||||
assertion wants moving into `buildHonoApp`, which is now the single place routes are mounted.
|
||||
|
||||
### Deliberately not done
|
||||
|
||||
**Offscale is not extracted.** The infrastructure is ready for it, but moving it means deleting working
|
||||
code across ~50 files, and that should happen with someone watching rather than unattended.
|
||||
still the hardcoded providers. No plugin owns a socket yet.
|
||||
- **Totality across plugin routes.** `PROTECTED_API_PREFIXES` is still the core list, and the check reads
|
||||
`Object.keys(handlers)` while Bun serves the route table. The assertion wants moving into
|
||||
`buildHonoApp`, which is now the single place routes are mounted.
|
||||
- **Two dock sources.** The app store keeps its own catalogue, so tiles come from there and from the
|
||||
plugin system. One when the app store is rebuilt on this.
|
||||
- **Members.** Offscale is `ownerOnly` — read/write for members needs its queries resolving to the
|
||||
OWNER's rows rather than the caller's, which is a change inside the plugin.
|
||||
|
||||
---
|
||||
|
||||
|
||||
Reference in New Issue
Block a user