@empereur-rouge/pms-sdk 0.3.8 → 0.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -118,6 +118,7 @@ Le client permet d'interagir avec l'API REST des nœuds PMS.
118
118
  const client = new PmsClient({
119
119
  nodeUrl: "https://node.pms.network", // URL du nœud principal
120
120
  apiKey: "pk_live_votre_cle_ici", // Clé API (obligatoire)
121
+ adminToken: "admin_token_ici", // Optionnel: requis pour les méthodes admin (gouvernance, setConfig)
121
122
  seedNodes: [ // Optionnel: nœuds de secours
122
123
  "https://node2.pms.network",
123
124
  "https://node3.pms.network",
@@ -132,6 +133,9 @@ const client = new PmsClient({
132
133
  > [!IMPORTANT]
133
134
  > La clé API est **obligatoire**. Obtenez-la depuis votre dashboard PMS ou auprès de l'administrateur du réseau.
134
135
 
136
+ > [!WARNING]
137
+ > `adminToken` n'est requis que pour les méthodes admin (gouvernance `propose`/`enact`/`cancel`, `setConfig`). Il est envoyé en `Authorization: Bearer <adminToken>`, uniquement vers le nœud principal (jamais vers les seeds lors du racing). **Ne jamais l'exposer côté navigateur ni le committer.** Les lectures publiques de gouvernance n'en ont pas besoin.
138
+
135
139
  #### Wallet (Custodial — Server-Side)
136
140
 
137
141
  Ces méthodes créent/restaurent des wallets **côté serveur**. L'adresse retournée est au format Bech32 (ex: `8e1a...`).
@@ -448,6 +452,78 @@ const result = await client.burnNfts({
448
452
 
449
453
  ---
450
454
 
455
+ ### Gouvernance & Émission
456
+
457
+ La gouvernance est ancrée dans le DAG : un changement de config peut être **proposé** (avec un palier et un timelock), puis **enacté** une fois le timelock écoulé, ou **annulé**. Les lectures sont publiques ; les écritures requièrent `adminToken`.
458
+
459
+ #### Lectures publiques (aucun `adminToken` requis)
460
+
461
+ ```typescript
462
+ // Propositions en attente (statut "pending")
463
+ const pending = await client.getGovernancePending();
464
+ // [{ proposal_id, tier, status: "pending", reason, announced_at_ms, enact_after_ms, update, proposal_block_id, enact_block_id, cancel_block_id }]
465
+
466
+ // Propositions terminées (enactées ou annulées)
467
+ const history = await client.getGovernanceHistory();
468
+
469
+ // Blocs de gouvernance ancrés dans le DAG
470
+ const { count, blocks } = await client.getGovernanceBlocks();
471
+ // blocks: [{ block_id, kind: "proposal" | "enact" | "cancel", proposal_id, tier, status, update, reason, announced_at_ms, enact_after_ms }]
472
+ ```
473
+
474
+ #### Actions admin (requièrent `adminToken`)
475
+
476
+ ```typescript
477
+ // Proposer un changement de config (ici, le couloir d'émission)
478
+ const proposal = await client.proposeGovernance({
479
+ update: { SetEmissionCorridor: { ceiling_bps: 1500, floor_bps: 0, target_bps: 1000, epoch_duration_sec: 86400 } },
480
+ tier: "constitution", // "operator" | "policy" | "constitution" (minuscules)
481
+ reason: "raise emission ceiling for Q3",
482
+ });
483
+ // { status: "ok", proposal_id, block_id, tier, announced_at_ms, enact_after_ms }
484
+
485
+ // Enacter une proposition dont le timelock est écoulé
486
+ await client.enactProposal(proposal.proposal_id, "timelock elapsed");
487
+ // { status: "ok", proposal_id, block_id }
488
+
489
+ // Annuler une proposition en attente
490
+ await client.cancelProposal(proposal.proposal_id);
491
+ ```
492
+
493
+ #### `setConfig` — 200 (appliqué) vs 202 (timelocké)
494
+
495
+ Un **durcissement** (ex: réduire un plafond, désactiver le mint) est appliqué instantanément ; un **assouplissement** est placé sous timelock de gouvernance. Le SDK expose les deux cas via une union discriminée sur `applied` — **un 202 n'est jamais traité comme un succès appliqué** :
496
+
497
+ ```typescript
498
+ const r = await client.setConfig({ SetMintEnabled: { enabled: false } });
499
+ if (r.applied) {
500
+ // HTTP 200 — en vigueur immédiatement
501
+ console.log("appliqué:", r.updateApplied, "bloc:", r.enactBlockId);
502
+ } else {
503
+ // HTTP 202 — proposé, PAS encore en vigueur
504
+ console.log("timelocké, enact après", new Date(r.enactAfterMs), "via", r.proposalId);
505
+ }
506
+ ```
507
+
508
+ #### Codes d'erreur stables
509
+
510
+ Le moteur renvoie ses erreurs au format `{ "code": NNNN, "message": "..." }`. Branchez sur le `code` numérique (stable), pas sur le message :
511
+
512
+ ```typescript
513
+ import { ErrorCode, HttpError } from "@empereur-rouge/pms-sdk";
514
+
515
+ try {
516
+ await client.enactProposal(proposalId);
517
+ } catch (e) {
518
+ if (e instanceof HttpError && e.code === ErrorCode.GovernanceRejected) {
519
+ // 3071 — timelock non écoulé, proposition non en attente, ou id inconnu
520
+ }
521
+ }
522
+ // Codes notables : GovernanceRejected (3071), MintDisabled (5031), MissingAuth (1001), InvalidAuth (1002).
523
+ ```
524
+
525
+ ---
526
+
451
527
  ### API Avancée
452
528
 
453
529
  Pour les cas d'usage avancés (construction manuelle de blocs, chiffrement custom), importez depuis le module `advanced` :