JavaScript SDK
The JavaScript SDK, @owncast/plugin-sdk, is the most common way to write an Owncast plugin. You write JavaScript or TypeScript, and the CLI bundles it into a single installable plugin that runs sandboxed inside the Owncast server. If you're choosing an authoring path, see the plugins overview.
This page is the JavaScript-specific layer: scaffolding, definePlugin, the CLI, and TypeScript. 处理程序、API、权限和清单在两个 SDK 中的工作方式相同,并且各自有参考页面。
与参考文档的对应关系
The shared reference names APIs in their canonical form, which is the JavaScript form: so you can read it as-is. 快速导览:
| 在参考文档中 | 在 JavaScript 中 |
|---|---|
| 定义一个处理程序 | a method on definePlugin({ ... }) |
事件的处理程序(例如 chat.message.received) | onChatMessage(msg): 使用 camelCase,on + 事件名 |
调用主机 API(例如 owncast.chat.sendAction) | identical: owncast.chat.sendAction(text) |
| 有效载荷字段 | camelCase: msg.user.displayName, msg.clientId |
| 过滤结果 | filter.pass() / filter.modify(payload) / filter.drop(reason) |
| Declare a plugin-owned custom hook | on: { "my.event"(payload) { … } }. Owned as <your-slug>.my.event |
| 构建 / 测试你的插件 | npm run package / npm test |
先决条件
- An Owncast server you can administer, version 0.3.0 or newer.
- Node.js 18 or newer (
node --versionto check).
为新插件生成脚手架
You don't install the SDK by hand. Scaffold a project with create-owncast-plugin and the generated package.json already lists @owncast/plugin-sdk as a dependency:
npx create-owncast-plugin@latest my-plugin
cd my-plugin
npm install # fetches the test and serve helpers
将所需的 slug 作为参数传入。 脚手架将其用于目录名、输出文件名和 URL 前缀。 slug 由小写字母、数字和连字符组成,且以字母开头。
You now have:
my-plugin/
├── package.json
├── plugin.manifest.json display name, slug, version, permissions
├── README.md how to build, test, package, and install it
├── INSTRUCTIONS.md optional, rendered as a tab in the admin
├── AGENTS.md notes for AI coding agents
├── .agents/ a bundled skill for AI coding agents
├── src/
│ └── plugin.js your code, with a sample handler
└── __tests__/
└── plugin.test.js a sample scenario test
npm install also creates node_modules/. None of these are created for you, but you can add an icon.png (shown in the admin plugin list), a public/ directory (static files served at /plugins/my-plugin/), and an assets/ directory (files the host inlines for manifest fields).
npm install runs a postinstall step that fetches the prebuilt test and serve host binaries (the scenario runner and the dev server). Building and packaging a plugin need no download. This postinstall is the only network step, and everything after is local.
Write a plugin
A plugin is the object you pass to definePlugin. Define a method for each event you want to react to: the SDK derives the manifest's subscription list from which methods are present, so there's no separate list to keep in sync.
const { definePlugin, owncast, filter } = require('@owncast/plugin-sdk');
module.exports = definePlugin({
onChatMessage(msg) {
owncast.chat.send(`echo: ${msg.body}`);
},
filterChatMessage(msg) {
return msg.body.includes('spam') ? filter.drop('spam') : filter.pass();
},
});
The package exports four things you'll use:
definePlugin(handlers): registers your handlers and returns the plugin object to export.owncast: the host API namespace (owncast.chat.send(...),owncast.kv.get(...), and the rest). Method names are camelCase. Each call is gated by the matching permission you declare in your manifest. See the API 参考.filter: the constructor for filter results:filter.pass(),filter.modify(payload),filter.drop(reason). Used only fromfilterChatMessage.authCheck: verdict helpers for theonAuthCheckhandler of anauth.gateplugin:authCheck.ok(),authCheck.refresh({ ttl? }),authCheck.deny(reason?).
处理程序名称使用 camelCase,并映射到 处理程序参考 中列出的运行时事件:onChatMessage, filterChatMessage, onChatUserJoined, onStreamStarted, onTick, onFediverseFollow, onHttpRequest, and so on. Payload fields are camelCase too (msg.user.displayName, msg.clientId).
Beyond top-level methods, custom-event handlers are passed as a nested object keyed by event type: on: { "my.event"(payload) {} }. Dynamic viewer pages use plain functions. onTabContent(ctx) receives the requested manifest.tabs object key as ctx.slug. onPageContent(ctx) receives manifest.extraPageContent.slug. Two more take no key: onPageStyles() and onPageScripts() return CSS and JavaScript injected into the viewer page at request time, gated on ui.modify. Rather than hand-rolling prefix parsing in onChatMessage, you can declare a commands table that the host's built-in !help picks up automatically. Both are shown for JavaScript on the subject pages: 处理程序, 命令, and UI.
TypeScript
The package ships index.d.ts, so you get autocomplete and type-checking on every event payload and host API with no extra setup. Name your entry src/plugin.ts and the CLI compiles it the same way:
import { definePlugin, owncast, filter, ChatMessage } from '@owncast/plugin-sdk';
export default definePlugin({
onChatMessage(msg: ChatMessage) {
owncast.chat.send(`echo: ${msg.body}`);
},
});
The build detects src/plugin.ts, src/plugin.js, plugin.ts, or plugin.js in that order. Types are declarations only: there's no separate compile step or tsconfig required.
The CLI
The SDK installs an owncast-plugin CLI, exposed through the package.json scripts the scaffold writes:
| Command | Script | What it does |
|---|---|---|
owncast-plugin build | npm run build | Bundles src/plugin.{js,ts} into an intermediate build artifact |
owncast-plugin test | npm test | Builds, then runs the __tests__/ scenarios through the real runtime |
owncast-plugin serve | npm run serve | Local dev server at http://localhost:8080/plugins/<slug>/ |
owncast-plugin package | npm run package | Builds and bundles everything into <slug>.ocpkg: the file you ship |
npm run package # produces my-plugin.ocpkg
npm test # runs your scenarios
npm run serve # iterate against a local dev server
npm run package only rebuilds when the bundle is missing. After changing source, run npm run build first so the package doesn't ship stale code.
The .ocpkg is the single distribution artifact: it contains your manifest, the bundled code, your public/ and assets/ directories, and an optional icon.png and INSTRUCTIONS.md. See Packaging & distribution for what goes inside and how to install it.
In JavaScript, npm test runs __tests__/*.test.js files calling runScenarios (build the array with loops, helpers, and fixtures), or static __tests__/*.test.json files. The full scenario data model and the local dev server (npm run serve) are on the Testing page.
Constraints to know
The CLI bundles your code into a single file that runs inside the server's sandbox, not in Node. That sandbox shapes how you write a plugin:
- Use
owncast.http.fetchfor outbound HTTP, not the globalfetch,axios, or a package that wraps Node'shttp. Network access goes through the host API and is gated on thenetwork.fetchpermission. See the APIs reference. - Not every npm package works. Pure-JavaScript packages bundle in fine. Anything that needs the Node.js runtime does not. See 第三方库.
Third-party libraries
npm packages work only if they're pure JavaScript. A plugin runs in a sandbox, not Node, so a package that touches fs, net, http/https, path, crypto, process, or child_process bundles cleanly and then throws when that code runs.
A package can also hit a Node built-in on a path you never exercise, so test the parts you use. For outbound HTTP, use owncast.http.fetch, not an HTTP-client package.
The page-content-demo example uses the mustache package this way.
What's in the package
index.js: the runtime withdefinePlugin, command handlers, theowncast.*host wrappers, and filter helpers.index.d.ts: TypeScript declarations for every event payload and host API.testing.js: therunScenarios/runScenarioFilestest API.bin/owncast-plugin: the CLI (build,test,serve,package).scripts/postinstall.js: fetches the prebuilt test and serve host binaries on install, used bynpm testandnpm run serve.
Where to go next
- 处理程序参考: every event you can subscribe to and its payload shape.
- API 参考: every
owncast.*method and the permission it needs. - 测试: the full scenario data model.
- 打包与分发: building the
.ocpkgand installing it. - 示例插件: one per feature, each a complete starting point you can copy.
- SDK 源码: the
@owncast/plugin-sdkpackage and toolchain.
Improve this page
See something missing or incorrect? Edit this page and improve the documentation for everyone.
