Contracten
Modules kennen elkaars code niet. Wil je module iets van Tabbr of van een andere module — wie heeft de rol
INSTRUCTEUR?, heeft deze persoon toestemming gegeven voor foto’s? — dan gaat dat via een contract: een
.d.ts met een frontend- en/of backenddeel, en een eigen versienummer.
Zo kan een module bijgewerkt worden zonder dat een andere breekt, zolang het contract binnen zijn major blijft.
Een contract gebruiken
Section titled “Een contract gebruiken”"uses": { "sys.access": "^1" },"optionalUses": { "tabbr.consent": "^1" }uses: je module heeft het nodig; ze kan alleen geïnstalleerd worden waar de club het contract heeft.optionalUses: je module gebruikt het als het er is (API 1.3).
npm run fetch-contracts # tabbr-module fetch-types --contractsDit haalt de .d.ts van elk contract op naar contracts/<naam>.d.ts. Commit die bestanden.
import { inject } from '@angular/core';import { MODULE_CONTRACTS } from '@tabbr/module-sdk';
const consents = await inject(MODULE_CONTRACTS, { optional: true })?.get('tabbr.consent');// null als de club de module Toestemmingen niet heeftif (await consents?.ensure('groups.photos', { context: `Het fotoalbum van ${group.name}` })) { openAlbum();}const instructeurs = tabbr.uses['sys.access'].personsWithRole('INSTRUCTEUR');const mag = tabbr.uses['tabbr.consent']?.personsWith('zweefapp.share') ?? [];De bestaande contracten
Section titled “De bestaande contracten”GET /api/contracts geeft de contracten die er in een club zijn.
sys.access (Tabbr) — rollen
Section titled “sys.access (Tabbr) — rollen”| Kant | Methode | Wat ze doet |
|---|---|---|
| frontend + backend | roles() |
De rollen van de club: { code, name, system }. |
| frontend + backend | personsWithRole(code) |
Wie die rol heeft. |
| backend | rolesOf(personId) |
De rollen van een persoon, met hun bron (roleCode, source). |
| backend | setManagedRoles(personId, codes) |
De rollen die jouw module aan iemand geeft. Rollen die met de hand gegeven zijn, blijven. |
| backend | managedRoles(personId), managedAssignments() |
Wat jouw module gegeven heeft. |
De laatste drie vragen "manageRoles": true in je backend-blok. Een module kan nooit een systeemrol
(ADMIN) geven.
tabbr.consent (module Toestemmingen)
Section titled “tabbr.consent (module Toestemmingen)”| Kant | Methode | Wat ze doet |
|---|---|---|
| frontend | status(code) |
Het antwoord van de ingelogde gebruiker. |
| frontend + backend | statusOf(code, personIds) |
De antwoorden van meerdere personen. |
| frontend | ensure(code, { context }) |
Vraagt het als het nog niet beantwoord is; true als de persoon akkoord is. |
| frontend | personFilter(code, status?) |
Een filter voor een lijst of ontvangers. |
| frontend | openPending() |
Opent de openstaande vragen. |
| backend | personsWith(code, status?) |
Wie akkoord is (of een andere status). |
Een status is granted, refused, withdrawn, expired, open of unknownType. Alleen granted
betekent toestemming.
Zelf een contract aanbieden
Section titled “Zelf een contract aanbieden”Een module kan zelf een contract aanbieden (API 1.3), zoals de module Toestemmingen tabbr.consent aanbiedt.
-
Kies de naam. Een contract heet naar zijn uitgever: het pakket
acme/groupsbiedtacme.groupsaan.sys.is voorbehouden aan Tabbr. -
Schrijf de
.d.ts. Op zichzelf staand (geen imports), met eenFrontend- en/ofBackend-interface:contracts/acme.groups.d.ts export interface Frontend {/** de groepen waar de ingelogde gebruiker lid van is */myGroups(): Promise<{ id: string; name: string }[]>;}export interface Backend {membersOf(groupId: string): string[];} -
Declareer het in het manifest:
"provides": { "acme.groups": { "version": "1.0.0", "types": "contracts/acme.groups.d.ts" } } -
Implementeer het. In de frontend als
providesop je moduleklasse, in de backend alsexport const providesin je entry-bestand:src/app/module/module.ts readonly provides = { 'acme.groups': this.store.contract };backend/src/index.ts export const provides = {'acme.groups': {membersOf(groupId: string) { /* … */ return ids; },},};
Backend-oproepen draaien in de sandbox van de aanbieder, met JSON in en uit. Een lus (A roept B roept A) wordt geweigerd.