@capibara-dev/sdk
v0.3.0
Published
SDK TypeScript officiel Capibara for Developers — defineApp + constructeurs typés du Kit (générés depuis les schémas de la plateforme), façades typées, harnais de test local (@capibara-dev/sdk/testing), client API publique, aides OAuth (PKCE), vérificatio
Maintainers
Readme
@capibara-dev/sdk
SDK TypeScript officiel Capibara for Developers — zéro dépendance, compatible Node ≥ 18, navigateurs et workers (fetch + WebCrypto).
Documentation complète : https://capibara.fr/dev/docs (versions Markdown
brut et llms.txt disponibles pour vos outils IA).
Installation
npm install -D @capibara-dev/sdkSans accès au registre npm, le tarball servi par le portail fait la même
chose : curl -O https://capibara.fr/dev-sdk/capibara-dev-sdk-0.3.0.tgz &&
npm install -D ./capibara-dev-sdk-0.3.0.tgz.
Dans la sandbox Capibara, @capibara-dev/sdk est fourni par la
plateforme (même API) : le paquet sert au typage, aux tests locaux et au
backend externe.
Contenu
- Types générés depuis les schémas de la plateforme (
generated.ts, ne s'édite pas) : un type par composant du Kit (KitStackNode,KitTableNode,KitFieldNode…), les propriétés de chaque constructeur (KitTextProps…), le catalogue des scopes (APP_SCOPES,AppScope), les façades typées (AppApi,APP_FACADE_NAMES,CrmContactsListInput…), les événements (APP_EVENTS), les capabilities, les catégories et les surfaces. Un test anti-dérive dans la CI de Capibara garantit qu'ils correspondent exactement au validateur du portail. defineApp+ui— le contrat du code hébergé :export default defineApp({ pages, widgets, panels, forms, siteBlocks, sitePages, actions, events, schedules, http })(siteBlocks/sitePages= surfaces du site public :viewernull, visiteur dansvisitor), les constructeurs typésui.<composant>(props, children),ui.doc,ui.ref,ui.each,ui.fallback, et les aidestoast(),navigate(),json(),text().@capibara-dev/sdk/testing— le harnais de test local :createTestContext()(KV, collections, fichiers,fetchet façades simulés en mémoire, journal),renderSurface(),runAction(),runEvent(),runSchedule(),runHttp(), et des assertions sur le Kit rendu (findNodes,hasText,kitStrings).- Backend externe —
CapibaraClient(API publique :me(),install(installId)→ façades typées,facades()), aides OAuth PKCE,verifyWebhookSignature()etcreateServerHandler()(vérification de signature + dispatch des webhooks par type d'événement). - Types du manifeste
add-on.json(AddonManifest,AddonCapability,AddonPermission,AddonPricing…) — la validation autoritaire reste celle du portail. - Moteurs gardés (DV-5) —
ctx.mail.send(e-mail transactionnel en blocs à des personnes LIÉES à l'organisation, ≤ 5, quota par jour),ctx.notify.user / permission / admins,ctx.calendar.project / remove / clear,ctx.search.index / remove / clear,ctx.approvals.request / get / cancel(décision livrée par l'événementapproval.decided). Capabilitiesmail.send,notify.send,calendar.project,search.index,approvals.request. Le harnais les simule (t.mails,t.notifications,t.calendar,t.searchDocs,t.approvals,t.decideApproval(id, 'APPROVED')).
Exemples
import { defineApp, ui, toast } from '@capibara-dev/sdk';
export default defineApp({
pages: {
home: async ({ ctx }) => ui.doc(ui.stack({ gap: 'md' }, [
ui.pageHeader({ title: `Bonjour ${ctx.viewer?.name ?? 'vous'}` }),
ui.kpi({ label: 'Compteur', value: (await ctx.kv.get<number>('count')) ?? 0 }),
ui.button({ label: '+1', action: 'count.add' }),
])),
},
actions: {
'count.add': async ({ ctx }) => {
const n = ((await ctx.kv.get<number>('count')) ?? 0) + 1;
await ctx.kv.put('count', n);
return { ...toast(`Compteur : ${n}`, 'success'), refresh: true };
},
},
});import { test } from 'node:test';
import assert from 'node:assert/strict';
import { createTestContext, renderSurface, runAction, hasText } from '@capibara-dev/sdk/testing';
import app from '../src/index';
test('le compteur s\'incrémente', async () => {
const t = createTestContext({ viewer: { name: 'Léa' } });
assert.equal(hasText(await renderSurface(app, 'page', 'home', t), 'Bonjour Léa'), true);
await runAction(app, 'count.add', t);
assert.equal(t.kv.get('count'), 1);
});// Moteurs : un e-mail lié, une validation humaine, la décision en retour.
export default defineApp({
actions: {
'refund.ask': async ({ ctx, params }) => {
await ctx.mail.send({
to: [{ partyId: params.partyId }],
subject: 'Votre demande de remboursement',
blocks: [{ type: 'text', text: 'Nous l’examinons et revenons vers vous.' }, { type: 'button', label: 'Suivre', href: '/apps/mon-app/retours' }],
});
await ctx.approvals.request({ subject: 'refund', subjectId: params.orderId, title: `Rembourser ${params.amount} € ?`, approver: { resource: 'billing-fr', action: 'write' } });
return toast('Demande envoyée', 'success');
},
},
events: {
'approval.decided': async ({ ctx, event }) => {
if (event.data.decision === 'APPROVED') await ctx.notify.admins({ title: `Remboursement ${event.data.subjectId} approuvé` });
},
},
});import { createServerHandler } from '@capibara-dev/sdk';
// Backend externe : un seul endpoint, la signature est vérifiée sur le corps BRUT.
const webhooks = createServerHandler({
secret: process.env.CAPIBARA_WEBHOOK_SECRET!,
handlers: {
'invoice.paid': async ({ tenantId, data }) => { /* … */ },
},
});
export default { fetch: (req: Request) => webhooks.fetch(req) };import { CapibaraClient } from '@capibara-dev/sdk';
const capibara = new CapibaraClient({ token: process.env.CAPIBARA_API_KEY! });
const contacts = await capibara.install(installId).crm.contacts.list({ limit: 20 });Backend externe (createBackend)
import { createBackend, defineApp, ui, CapibaraClient } from '@capibara-dev/sdk';
const app = defineApp({ pages: { home: () => ui.text({ markdown: 'Rendu depuis mon serveur.' }) } });
const backend = createBackend({
app,
secret: process.env.CAPIBARA_BACKEND_SECRET!, // portail › Code › « Backend externe »
capibara: new CapibaraClient({ token: process.env.CAPIBARA_API_KEY! }), // ctx.capibara.* via l'API publique
});
export default { fetch: (req: Request) => backend.fetch(req) }; // ou backend.handle(rawBody, headers)Le manifeste déclare backend: { url } (sans main) ; Capibara envoie les
requêtes du protocole signées (x-capibara-signature: t=…,v1=…, horodatage
≤ 5 min) — createBackend vérifie, dispatche vers defineApp (même sémantique
que la sandbox) et renvoie { ok, result, logs }. ctx.kv/data/files/
moteurs sont réservés au code hébergé (refus expliqué).
Versions
- 0.3.0 —
createBackend(backend externe : signature horodatéet=…,v1=…, dispatch identique au shim,ctx.capibaraviaCapibaraClient),verifyBackendSignature,createServerHandler({ maxAgeSec })+WEBHOOK_TIMESTAMP_HEADER, façadesbilling.documents.payLink/billing.charges.create/billing.charges.get, scopesbilling-fr.pos:*, événementssales.document.paid/pos.charge.paid, types de manifestebackend/returnHosts. - 0.2.1 — surfaces du site public (
siteBlocks,sitePages),visitordans le contexte et le harnais (createTestContext({ visitor })), typesAddonSiteBlockContribution/AddonSitePageContribution, capabilityui.site. - 0.2.0 — types générés (Kit, scopes, façades, événements), harnais
@capibara-dev/sdk/testing,createServerHandler,ui.ref/ui.fallbackconformes au Kit. - 0.1.0 — types du manifeste recopiés, client API, PKCE, webhooks.
