SDK JavaScript
O SDK JavaScript, @owncast/plugin-sdk, é a forma mais comum de escrever um plugin do Owncast. Você escreve em JavaScript ou TypeScript, e o CLI o empacota em um único plugin instalável que é executado em sandbox dentro do servidor Owncast. If you're choosing an authoring path, see the plugins overview.
Os SDKs de plugin são totalmente novos no Owncast 0.3.0 e a API ainda está evoluindo. Se você encontrar um bug ou tiver uma sugestão, por favor abra uma issue ou converse ao vivo com a comunidade.
Esta página é a camada específica para JavaScript: scaffolding, definePlugin, o CLI e TypeScript. Manipuladores, APIs, permissões e o manifesto funcionam da mesma forma em ambos os SDKs e têm suas próprias páginas de referência.
Como isso se relaciona com a documentação de referência
A referência compartilhada nomeia as APIs em sua forma canônica, que é a forma JavaScript: assim você pode lê-la como está. Orientação rápida:
| Na referência | Em JavaScript |
|---|---|
| Definir um manipulador | a method on definePlugin({ ... }) |
Manipulador para um evento (ex.: chat.message.received) | onChatMessage(msg): camelCase, on + o evento |
Chamar uma API do host (ex.: owncast.chat.sendAction) | idêntico: owncast.chat.sendAction(text) |
| Campos do payload | camelCase: msg.user.displayName, msg.clientId |
| Resultado do filtro | filter.pass() / filter.modify(payload) / filter.drop(reason) |
| Declare a plugin-owned custom hook | on: { "my.event"(payload) { … } }. Owned as <your-slug>.my.event |
| Compile / teste seu plugin | npm run package / npm test |
Pré-requisitos
- Um servidor Owncast que você possa administrar, versão 0.3.0 ou mais recente.
- Node.js 18 ou superior (
node --versionpara verificar).
Scaffold um novo plugin
Você não instala o SDK manualmente. Estruture um projeto com create-owncast-plugin e o package.json gerado já lista @owncast/plugin-sdk como dependência:
npx create-owncast-plugin@latest my-plugin
cd my-plugin
npm install # fetches the test and serve helpers
Passe o slug desejado como argumento. O scaffold usa isso para o nome do diretório, o nome do arquivo de saída e o prefixo da URL. Slugs são letras minúsculas, dígitos e hífens, começando com uma letra.
Agora você tem:
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/. Nenhum desses é criado para você, mas você pode adicionar um icon.png (exibido na lista de plugins do administrador), um diretório public/ (arquivos estáticos servidos em /plugins/my-plugin/) e um diretório assets/ (arquivos que o host incorpora para os campos do manifesto).
npm install executa um passo postinstall que busca os binários pré-compilados do host de teste e serve (o scenario runner e o servidor de desenvolvimento). Compilar e empacotar um plugin não requer download. Esse postinstall é a única etapa que usa rede, e tudo o que vem depois é local.
Escreva um plugin
Um plugin é o objeto que você passa para definePlugin. Defina um método para cada evento ao qual você queira reagir: o SDK deriva a lista de assinaturas do manifesto a partir dos métodos presentes, então não há uma lista separada para manter sincronizada.
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): registra seus handlers e retorna o objeto do plugin para exportar.owncast: o namespace da API do host (owncast.chat.send(...),owncast.kv.get(...), e o resto). Nomes de método são camelCase. Cada chamada é controlada pela permissão correspondente declarada no manifesto. Veja a referência de APIs.filter: o construtor para resultados de filtro:filter.pass(),filter.modify(payload),filter.drop(reason). Usado apenas emfilterChatMessage.authCheck: verdict helpers for theonAuthCheckhandler of anauth.gateplugin:authCheck.ok(),authCheck.refresh({ ttl? }),authCheck.deny(reason?).
Os nomes dos handlers são em camelCase e mapeiam para os eventos em tempo de execução listados na referência de manipuladores: onChatMessage, filterChatMessage, onChatUserJoined, onStreamStarted, onTick, onFediverseFollow, onHttpRequest, and so on. Os campos do payload também são camelCase (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. Outros dois não recebem chave: onPageStyles() e onPageScripts() retornam CSS e JavaScript injetados na página do visualizador no momento da requisição, condicionados a 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. Ambos são mostrados para JavaScript nas páginas sobre os assuntos: Manipuladores, Comandos e UI.
TypeScript
O pacote inclui index.d.ts, então você obtém autocompletar e verificação de tipos em cada payload de evento e API do host sem configuração extra. Nomeie sua entrada src/plugin.ts e o CLI a compila da mesma forma:
import { definePlugin, owncast, filter, ChatMessage } from '@owncast/plugin-sdk';
export default definePlugin({
onChatMessage(msg: ChatMessage) {
owncast.chat.send(`echo: ${msg.body}`);
},
});
O build detecta src/plugin.ts, src/plugin.js, plugin.ts ou plugin.js nessa ordem. Os tipos são apenas declarações: não há uma etapa de compilação separada nem tsconfig necessária.
O CLI
O SDK instala um CLI owncast-plugin, exposto através dos scripts em package.json que o scaffold gera:
| Comando | Script | O que faz |
|---|---|---|
owncast-plugin build | npm run build | Empacota src/plugin.{js,ts} em um artefato de build intermediário |
owncast-plugin test | npm test | Compila e depois executa os cenários de __tests__/ através do runtime real |
owncast-plugin serve | npm run serve | Servidor de desenvolvimento local em http://localhost:8080/plugins/<slug>/ |
owncast-plugin package | npm run package | Compila e empacota tudo em <slug>.ocpkg: o arquivo que você distribui |
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.
O .ocpkg é o único artefato de distribuição: contém seu manifesto, o código empacotado, seus diretórios public/ e assets/, e um opcional icon.png e INSTRUCTIONS.md. Veja Empacotamento e distribuição para saber o que vai dentro e como instalá-lo.
Em JavaScript, npm test executa arquivos __tests__/*.test.js chamando runScenarios (construa o array com loops, helpers e fixtures), ou arquivos estáticos __tests__/*.test.json. O modelo completo de dados de cenário e o servidor de desenvolvimento local (npm run serve) estão na página Testes.
Restrições a saber
O CLI empacota seu código em um único arquivo que roda dentro do sandbox do servidor, não no Node. Esse sandbox molda como você escreve um plugin:
- Use
owncast.http.fetchpara HTTP de saída, não ofetchglobal,axios, ou um pacote que envolva ohttpdo Node. O acesso à rede passa pela API do host e é condicionado pela permissãonetwork.fetch. Veja a referência de APIs. - Nem todo pacote npm funciona. Pacotes puramente JavaScript empacotam sem problemas. Qualquer coisa que precise do runtime do Node.js não funciona. Veja Bibliotecas de terceiros.
Bibliotecas de terceiros
Pacotes npm funcionam apenas se forem JavaScript puro. Um plugin roda em um sandbox, não no Node, então um pacote que acessa fs, net, http/https, path, crypto, process ou child_process empacota normalmente e então lança um erro quando esse código for executado.
Um pacote também pode acionar um recurso interno do Node em um caminho que você nunca usa, então teste as partes que você utiliza. Para HTTP de saída, use owncast.http.fetch, não um pacote cliente HTTP.
O exemplo page-content-demo usa o pacote mustache dessa maneira.
O que há no pacote
index.js: o runtime comdefinePlugin, handlers de comando, os wrappers do hostowncast.*e helpers de filtro.index.d.ts: Declarações TypeScript para cada payload de evento e API do host.testing.js: a API de testerunScenarios/runScenarioFiles.bin/owncast-plugin: o CLI (build,test,serve,package).scripts/postinstall.js: busca os binários pré-compilados do host de teste e serve na instalação, usado pornpm testenpm run serve.
Para onde ir a seguir
- Referência de manipuladores: cada evento ao qual você pode se inscrever e a forma de seu payload.
- Referência de APIs: cada método
owncast.*e a permissão que ele necessita. - Testes: o modelo completo de dados de cenário.
- Empacotamento e distribuição: construir o
.ocpkge instalá-lo. - Plugins de exemplo: um por recurso, cada um um ponto de partida completo que você pode copiar.
- Código-fonte do SDK: o pacote
@owncast/plugin-sdke o toolchain.
Improve this page
See something missing or incorrect? Edit this page and improve the documentation for everyone.
