From 043364e43ef8e87a79929c99f438fe2bba2fcd78 Mon Sep 17 00:00:00 2001 From: Gabe Kangas Date: Sat, 1 Aug 2026 12:44:28 -0700 Subject: [PATCH 1/2] feat: key manifest pages and tabs --- docs/PLUGIN_AUTHOR_GUIDE.md | 40 ++++++++-------- docs/WIRE_PROTOCOL.md | 46 +++++++++++++------ examples/js/README.md | 2 +- .../js/action-buttons/plugin.manifest.json | 7 ++- examples/js/admin-demo/plugin.manifest.json | 12 ++--- examples/js/file-manager/plugin.manifest.json | 7 ++- examples/js/manual-video-settings/README.md | 2 +- .../plugin.manifest.json | 7 ++- examples/js/page-content-demo/INSTRUCTIONS.md | 6 +-- examples/js/page-content-demo/README.md | 6 +-- .../js/page-content-demo/plugin.manifest.json | 9 ++-- examples/js/rules-tab/plugin.manifest.json | 16 +++---- examples/js/tabs-demo/INSTRUCTIONS.md | 12 ++--- examples/js/tabs-demo/README.md | 10 ++-- examples/js/tabs-demo/plugin.manifest.json | 10 ++-- examples/js/theme-hub/plugin.manifest.json | 7 ++- examples/python/README.md | 2 +- .../action-buttons/plugin.manifest.json | 7 ++- .../python/admin-demo/plugin.manifest.json | 12 ++--- .../python/file-manager/plugin.manifest.json | 7 ++- .../python/manual-video-settings/README.md | 2 +- .../plugin.manifest.json | 7 ++- .../python/page-content-demo/INSTRUCTIONS.md | 6 +-- examples/python/page-content-demo/README.md | 6 +-- .../page-content-demo/plugin.manifest.json | 9 ++-- examples/python/tabs-demo/INSTRUCTIONS.md | 12 ++--- examples/python/tabs-demo/README.md | 10 ++-- .../python/tabs-demo/plugin.manifest.json | 10 ++-- .../python/theme-hub/plugin.manifest.json | 7 ++- rules-tab/plugin.manifest.json | 16 +++---- .../skills/create-owncast-plugin-js/SKILL.md | 3 +- .../skills/create-owncast-plugin-py/SKILL.md | 3 +- 32 files changed, 159 insertions(+), 159 deletions(-) diff --git a/docs/PLUGIN_AUTHOR_GUIDE.md b/docs/PLUGIN_AUTHOR_GUIDE.md index a29166f..5e08f14 100644 --- a/docs/PLUGIN_AUTHOR_GUIDE.md +++ b/docs/PLUGIN_AUTHOR_GUIDE.md @@ -654,7 +654,7 @@ Sends are fire-and-forget: the call returns immediately and never blocks, even i Notes: - Up to 64 simultaneous connections per plugin. Over that the endpoint returns 503. `EventSource` reconnects automatically. -- If the channel matches one of your `admin.pages[]` globs it's auth-gated like any admin route, handy for an admin-only stats stream. +- If the channel matches one of your `admin.pages` path globs, it is auth-gated like any admin route. This is useful for an admin-only stats stream. - The endpoint is host-owned and reserved: your `onHttpRequest` never sees `/_sse/...` requests, and you can't serve your own route there. ### Knowing who is connected @@ -738,32 +738,33 @@ Prefer it over building a bespoke settings page and KV plumbing. ## Admin pages -Plugins can register pages that appear in the Owncast admin UI for configuration. Declare them in the manifest: +Plugins can register pages that appear in the Owncast admin UI for configuration. Each `pages` object key is a plugin-relative path glob: ```json { "permissions": ["http.serve"], "admin": { - "pages": [ - { "title": "Settings", "path": "/admin", "icon": "gear" }, - { "title": "Settings", "path": "/admin/*" } - ] + "pages": { + "/admin": { "title": "Settings", "icon": "gear" }, + "/admin/*": { "title": "Settings" } + } } } ``` -- `path` is a glob (e.g. `"/admin"`, `"/admin/*"`). Requests under `/plugins//` that match any declared glob are **auth-gated by the host**, unauthenticated requests get `401` before your plugin code ever runs. +- Each key is a path glob such as `"/admin"` or `"/admin/*"`. Requests under `/plugins//` that match any declared glob are **auth-gated by the host**. Unauthenticated requests get `401` before your plugin code runs. - Owncast's admin renders each declared page as a tab inside `/admin/plugins/configure?id=`, embedded as an iframe pointed at `/plugins//`. Each plugin gets its own bookmarkable URL plus a sidebar entry under **Plugins** in the admin nav. - Both static assets and dynamic endpoints under matched paths are auth-gated. You don't have to check `req.authenticated` yourself. -- The host auto-injects an admin-themed stylesheet (`/styles/admin/plugin-iframe.css`) into HTML responses on admin paths so plain ``/`