@infintywab/plugin-sdk
v1.2.0
Published
SDK de développement de plugins pour FasoOrchestra ERP (types AppAPI, classe de base, helpers, contrat de style).
Downloads
32
Readme
@infintywab/plugin-sdk
SDK officiel pour écrire des plugins FasoOrchestra ERP. Fournit le contrat de
types complet (AppAPI, Manifest, …), la classe de base ERPPlugin, le helper
definePlugin, les constantes (EVENTS, STORE_KEYS, CHANNELS) et le contrat
de style (ui, TOKENS).
À l'exécution, le plugin ne charge pas ce code : l'hôte injecte l'
AppAPIréelle dans la factory/constructeur. Le SDK n'apporte que des types (effacés au build), une classe de base triviale et des constantes. React reste externe (fourni par l'hôte viawindow) — voir le contrat de packaging.
Installation
npm i -D @infintywab/plugin-sdkBuild (émet les .d.ts)
npm run build # → dist/index.js + dist/index.d.ts (+ source maps)Le package.json expose dist/index.d.ts comme types → autocomplétion
complète dans VS Code pour tout projet qui installe le paquet.
Utilisation
import { definePlugin, type AppAPI, ui } from '@infintywab/plugin-sdk'
export const manifest = {
id: 'my-plugin',
name: 'Mon plugin',
version: '1.0.0',
license: 'MIT',
permissions: ['tasks:read'],
dependencies: [],
}
export default definePlugin((app: AppAPI) => ({
onload() {
app.registerSidebar([{ label: 'Mon plugin', path: '/mine', icon: 'package', section: 'Modules' }])
app.registerCommand({ id: 'mine.hello', label: 'Hello', run: () => app.notify(app.t('common.save')) })
app.navigate('/mine')
app.log.info('chargé', app.getPermissions())
const id = setInterval(() => {}, 1000)
app.addCleanup(() => clearInterval(id))
},
onunload() {},
}))Surface de l'AppAPI
| Domaine | Membres |
|---|---|
| Identité | pluginId |
| UI | registerRoutes, registerSidebar, registerCommand, registerDashboardWidget, registerSettingsSection, navigate |
| Notifs | notify, notifications.push/markAllRead |
| Réseau | apiGet/Post/Put/Patch/Delete, getQueryClient |
| Inter-plugins | events (pipe/on/emit/dispatch), store |
| Temps réel | onRealtime(channel, cb) |
| i18n | t(key, opts?), getLocale() |
| Journalisation | log.debug/info/warn/error |
| Permissions | getPermissions(), hasPermission() |
| Cycle de vie | addCleanup(fn) |
| Contexte | getUser(), getManifest(id) |
Style
Tout plugin repose sur le design system de l'hôte : classes via ui
(ui.card, ui.btnPrimary, ui.badgeSuccess, ui.input, ui.metricCard…) et
tokens via TOKENS (var(--color-*)). Aucune feuille de style embarquée.
Publication
Le SDK est le contrat entre le shell et tous les plugins. Toute modification
de la surface publique (AppAPI, Manifest, constantes) est un événement de
version : semver strict, sans exception.
| Changement | Version | |---|---| | Ajout d'une méthode ou d'un champ optionnel | mineure | | Correction sans impact sur la surface | corrective | | Signature modifiée, champ retiré ou rendu obligatoire | majeure |
Publier une version
npm version minor # met à jour package.json ET crée le tag vX.Y.Z
git push --follow-tags # déclenche le workflow ReleaseLe workflow refuse de publier si le tag ne correspond pas à la version du
package.json, ou si cette version existe déjà sur le registre. Il vaut mieux
échouer à la publication qu'obtenir un paquet dont le numéro ne correspond à
aucun commit.
Prérequis, une seule fois
- Le scope
@infintywabdoit exister sur npm et appartenir au compte publiant. Le créer vianpm org create infintywab, ou publier sous un autre nom en modifiant le champnamedupackage.jsonavant la première publication — un nom publié ne se reprend pas. - Secret
NPM_TOKENdans les paramètres du dépôt (Settings → Secrets and variables → Actions), avec un jeton npm de type Automation — il traverse la double authentification, contrairement à un jeton de publication classique.
--access public est passé explicitement : un paquet scopé est publié en
restricted par défaut, ce qui exige un plan payant et le rendrait inaccessible
aux consommateurs.
Provenance (optionnel)
Pour attester publiquement le lien entre le paquet et le commit qui l'a produit,
ajouter --provenance à l'étape de publication et la permission
id-token: write au job. Cela requiert un dépôt public — sur un dépôt privé,
la publication échouerait.
Consommateurs
| Dépôt | Usage |
|---|---|
| InfinityWAB/erp-Orchestra | le shell : kernel, factory et types partagés |
| InfinityWAB/branch | module organigramme (frontend/) |
| InfinityWAB/xstocks | module stock (frontend/) |
Après une version majeure, prévenir ces dépôts : ils déclarent une plage semver et ne suivront pas automatiquement.
Authentification de la CI — trusted publishing
npm a retiré les jetons Automation classiques de son interface. Les jetons
restants (granular access tokens) restent soumis à la double authentification
sur les écritures, ce qu'une CI ne peut pas satisfaire — la publication échoue
alors en EOTP.
La voie recommandée est le trusted publishing : GitHub émet à chaque exécution un jeton OIDC éphémère, signé, lié au dépôt et au workflow. Aucun secret à stocker ni à faire tourner.
Configuration, une seule fois, sur npmjs.com → page du paquet → Settings → Trusted Publisher → GitHub Actions :
| Champ | Valeur |
|---|---|
| Organization | InfinityWAB |
| Repository | ersdk |
| Workflow filename | release.yml |
| Allowed actions | npm publish |
Le secret NPM_TOKEN devient alors inutile — supprimez-le, un secret
inutilisé reste une surface d'attaque.
Le workflow est déjà prêt : Node 22, npm à jour (≥ 11.5.1) et permission
id-token: write.
Amorçage
Le Trusted Publisher se configure dans les réglages du paquet, qui doit donc exister. La toute première version se publie manuellement :
npm login
npm publish --access public --otp=<code>C'est la seule fois où un code est saisi. Les suivantes passent par la CI.
Si la publication renvoie 404
npm répond 404 au lieu de 403 pour ne pas révéler l'existence d'un scope privé.
Causes possibles : l'organisation npm n'existe pas (npm org create infintywab),
le jeton ne couvre pas le scope entier — nécessaire pour créer un paquet qui
n'existe pas encore —, ou le compte n'est pas membre de l'organisation.
