SDK JavaScript
Le SDK JavaScript, @owncast/plugin-sdk, est le moyen le plus courant d'écrire un plugin Owncast. Vous écrivez en JavaScript ou TypeScript, et la CLI l'assemble en un seul plugin installable qui s'exécute en sandbox sur le serveur Owncast. If you're choosing an authoring path, see the plugins overview.
Les SDK de plugins sont tout nouveaux dans Owncast 0.3.0 et l'API est encore en évolution. Si vous rencontrez un bug ou avez une suggestion, veuillez ouvrir un problème ou discuter en direct avec la communauté.
Cette page est la couche spécifique à JavaScript : création de la structure, definePlugin, la CLI, et TypeScript. Les gestionnaires, API, permissions, et le manifeste fonctionnent de la même manière dans les deux SDK et disposent de leurs propres pages de référence.
Comment cela s'aligne avec la documentation de référence
Les noms des API de référence partagées sont dans leur forme canonique, qui est la forme JavaScript : vous pouvez donc les lire tels quels. Orientation rapide :
| Dans la référence | En JavaScript |
|---|---|
| Définir un gestionnaire | une méthode sur definePlugin({ ... }) |
Gestionnaire pour un événement (par exemple, chat.message.received) | onChatMessage(msg) : camelCase, on + l'événement |
Appeler une API hôte (par exemple, owncast.chat.sendAction) | identique : owncast.chat.sendAction(text) |
| Champs de charges utiles | camelCase : msg.user.displayName, msg.clientId |
| Filtrer le résultat | filter.pass() / filter.modify(payload) / filter.drop(reason) |
| Declare a plugin-owned custom hook | on: { "my.event"(payload) { … } }. Owned as <your-slug>.my.event |
| Construire / tester votre plugin | npm run package / npm test |
Prérequis
- Un serveur Owncast que vous pouvez administrer, version 0.3.0 ou plus récente.
- Node.js 18 ou plus récent (
node --versionpour vérifier).
Créer un nouveau plugin
Vous n'installez pas le SDK manuellement. Créez une structure de projet avec create-owncast-plugin et le package.json généré liste déjà @owncast/plugin-sdk comme dépendance :
npx create-owncast-plugin@latest my-plugin
cd my-plugin
npm install # fetches the test and serve helpers
Passez le slug que vous souhaitez comme argument. La structure l'utilise pour le nom du répertoire, le nom de fichier de sortie, et le préfixe de l'URL. Les slugs sont des lettres minuscules, des chiffres, et des tirets, commençant par une lettre.
Vous avez maintenant :
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 crée également node_modules/. Aucun de ces éléments n'est créé pour vous, mais vous pouvez ajouter un icon.png (affiché dans la liste des plugins de l'admin), un répertoire public/ (fichiers statiques servis à /plugins/my-plugin/), et un répertoire assets/ (fichiers que l'hôte inclut pour les champs du manifeste).
npm install exécute une étape post-installation qui télécharge les binaires hôtes préconstruits pour le test et le serveur (le runner de scénario et le serveur dev). Construire et empaqueter un plugin ne nécessite aucun téléchargement. Cette post-installation est la seule étape réseau, et tout ce qui suit est local.
Écrire un plugin
Un plugin est l'objet que vous passez à definePlugin. Définissez une méthode pour chaque événement auquel vous souhaitez réagir : le SDK dérive la liste des abonnements du manifeste en fonction des méthodes présentes, donc il n'y a pas de liste séparée à maintenir à jour.
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): enregistre vos gestionnaires et retourne l'objet plugin à exporter.owncast: l'espace de noms de l'API hôte (owncast.chat.send(...),owncast.kv.get(...), et le reste). Les noms de méthodes sont camelCase. Chaque appel est contrôlé par la permission correspondante que vous déclarez dans votre manifeste. Consultez la référence des API.filter: le constructeur pour les résultats de filtre :filter.pass(),filter.modify(payload),filter.drop(reason). Utilisé uniquement depuisfilterChatMessage.authCheck: verdict helpers for theonAuthCheckhandler of anauth.gateplugin:authCheck.ok(),authCheck.refresh({ ttl? }),authCheck.deny(reason?).
Les noms de gestionnaire sont camelCase et correspondent aux événements d'exécution répertoriés dans la référence des gestionnaires : onChatMessage, filterChatMessage, onChatUserJoined, onStreamStarted, onTick, onFediverseFollow, onHttpRequest, et ainsi de suite. Les champs de charge utile sont également 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. Deux autres ne prennent pas de clé : onPageStyles() et onPageScripts() retournent du CSS et du JavaScript injectés dans la page de visionnage lors de la demande, contrôlés sur 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. Les deux sont montrés pour JavaScript sur les pages sujettes : Gestionnaires, Commandes, et UI.
TypeScript
Le paquet expédie index.d.ts, vous obtenez donc la complétion automatique et la vérification des types sur chaque charge utile d'événement et API hôte sans configuration supplémentaire. Nommez votre entrée src/plugin.ts et la CLI le compile de la même manière :
import { definePlugin, owncast, filter, ChatMessage } from '@owncast/plugin-sdk';
export default definePlugin({
onChatMessage(msg: ChatMessage) {
owncast.chat.send(`echo: ${msg.body}`);
},
});
La compilation détecte src/plugin.ts, src/plugin.js, plugin.ts, ou plugin.js dans cet ordre. Les types sont des déclarations uniquement : il n'y a pas d'étape de compilation séparée ou de tsconfig requis.
La CLI
Le SDK installe un CLI owncast-plugin, exposé par les scripts package.json que la structure écrit :
| Commande | Script | Ce que cela fait |
|---|---|---|
owncast-plugin build | npm run build | Regroupe src/plugin.{js,ts} dans un artefact de construction intermédiaire |
owncast-plugin test | npm test | Construit, puis exécute les scénarios __tests__/ à travers le véritable environnement d'exécution |
owncast-plugin serve | npm run serve | Serveur de développement local à http://localhost:8080/plugins/<slug>/ |
owncast-plugin package | npm run package | Construit et regroupe tout dans <slug>.ocpkg : le fichier que vous expédiez |
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.
Le .ocpkg est l'artefact de distribution unique : il contient votre manifeste, le code groupé, vos répertoires public/ et assets/, et un icon.png et INSTRUCTIONS.md optionnels. Consultez Emballage & distribution pour savoir ce qui à l'intérieur et comment l'installer.
En JavaScript, npm test exécute des fichiers __tests__/*.test.js appelant runScenarios (construisez le tableau avec des boucles, helpers, et fixtures), ou des fichiers statiques __tests__/*.test.json. Le modèle complet de données de scénario et le serveur de développement local (npm run serve) sont sur la page Test.
Contraintes à connaître
La CLI regroupe votre code en un seul fichier qui s'exécute à l'intérieur du sandbox du serveur, pas dans Node. Ce sandbox façonne la manière dont vous écrivez un plugin :
- Utilisez
owncast.http.fetchpour HTTP sortant, pas lefetchglobal,axios, ou un paquet qui enveloppe lehttpde Node. L'accès réseau passe par l'API hôte et est contrôlé par la permissionnetwork.fetch. Consultez la référence des API. - Tous les paquets npm ne fonctionnent pas. Les paquets JavaScript pur s'empaquettent bien. Tout ce qui nécessite le runtime Node.js ne fonctionne pas. Consultez Bibliothèques tierces.
Bibliothèques tierces
Les paquets npm fonctionnent uniquement s'ils sont pure JavaScript. Un plugin s'exécute dans un sandbox, pas Node, donc un paquet qui touche fs, net, http/https, path, crypto, process, ou child_process s'empaquette proprement puis se bloque lorsque ce code s'exécute.
Un paquet peut également toucher à un intégré Node sur un chemin que vous n'exercez jamais, donc testez les parties que vous utilisez. Pour HTTP sortant, utilisez owncast.http.fetch, pas un paquet client HTTP.
L'exemple page-content-demo utilise le paquet mustache de cette manière.
Qu'y a-t-il dans le paquet
index.js: le runtime avecdefinePlugin, les gestionnaires de commandes, les wrappers hôtesowncast.*, et les helpers de filtre.index.d.ts: déclarations TypeScript pour chaque charge utile d'événement et API hôte.testing.js: l'API de testrunScenarios/runScenarioFiles.bin/owncast-plugin: la CLI (build,test,serve,package).scripts/postinstall.js: télécharge les binaires hôtes préconstruits lors de l'installation, utilisés parnpm testetnpm run serve.
Où aller ensuite
- Référence des gestionnaires : chaque événement auquel vous pouvez vous abonner et sa forme de charge utile.
- Référence des API : chaque méthode
owncast.*et la permission dont elle a besoin. - Test : le modèle complet de données de scénario.
- Emballage & distribution : construction de la
.ocpkget de son installation. - Plugins d'exemple : un par fonctionnalité, chacun étant un point de départ complet que vous pouvez copier.
- Source du SDK : le paquet
@owncast/plugin-sdket l'outil.
Improve this page
See something missing or incorrect? Edit the English version of this page or help improve translations.
