@empereur-rouge/pms-sdk 0.5.0 → 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/dist/index.d.ts CHANGED
@@ -269,8 +269,29 @@ interface TokenMetadata {
269
269
  * demurrage. Voir [`effectiveValue`] pour le calcul côté client.
270
270
  */
271
271
  demurrage_bps_per_day?: number;
272
+ /**
273
+ * Mint collatéralisé (protocole 2.3 v2, dag-pms v0.11.0) : adresse de
274
+ * réserve sur le même ledger. Chaque mint exige
275
+ * `(circulation + minté) × collateral_ratio_bps / 10000` couvert par
276
+ * les UTXOs de réserve ENCORE time-lockés à cette adresse.
277
+ */
278
+ collateral_address?: string;
279
+ /** Asset du collatéral (absent = natif du ledger). */
280
+ collateral_asset_id?: string;
281
+ /** Ratio de couverture en bps (10000 = 1:1). Présent ssi collateral_address. */
282
+ collateral_ratio_bps?: number;
272
283
  }
273
- /** Mise à jour de configuration */
284
+ /**
285
+ * Mise à jour de configuration.
286
+ *
287
+ * Sérialisation serde externally-tagged côté moteur : chaque variant est un
288
+ * objet à clé unique (`{ "SetFeeRate": { "bps": 300 } }`). Les noms de
289
+ * variants sont en PascalCase, les champs en snake_case.
290
+ *
291
+ * Selon le sens du changement (durcissement vs assouplissement), le moteur
292
+ * applique la mise à jour instantanément (200) ou la place sous timelock de
293
+ * gouvernance (202) — voir [`PmsClient.setConfig`] / [`ConfigChangeResult`].
294
+ */
274
295
  type ConfigUpdate = {
275
296
  SetFeeRate: {
276
297
  bps: number;
@@ -291,6 +312,24 @@ type ConfigUpdate = {
291
312
  SetMintEnabled: {
292
313
  enabled: boolean;
293
314
  };
315
+ } | {
316
+ /**
317
+ * Couloir d'émission (plan §3, dag-pms v0.18.0). Tous les champs
318
+ * sont REQUIS et en basis points (sauf la durée d'epoch en
319
+ * secondes). Élargir le couloir (hausser le plafond / la cible) est
320
+ * un assouplissement → timelocké ; le resserrer est un durcissement
321
+ * → instantané.
322
+ */
323
+ SetEmissionCorridor: {
324
+ /** Plafond d'émission par epoch (bps). */
325
+ ceiling_bps: number;
326
+ /** Plancher d'émission par epoch (bps). */
327
+ floor_bps: number;
328
+ /** Cible d'émission par epoch (bps). */
329
+ target_bps: number;
330
+ /** Durée d'une epoch d'émission (secondes). */
331
+ epoch_duration_sec: number;
332
+ };
294
333
  };
295
334
  /**
296
335
  * Dernier snapshot de preuve de réserves ancré (protocole 2.6).
@@ -309,6 +348,120 @@ interface ReservesLatest {
309
348
  /** Horodatage du calcul (UNIX ms) */
310
349
  computed_at_ms: number;
311
350
  }
351
+ /**
352
+ * Palier de gouvernance d'une proposition.
353
+ *
354
+ * Casse en **minuscules** (`"operator" | "policy" | "constitution"`), cohérente
355
+ * entre requêtes et réponses depuis dag-pms v0.18.1 : le moteur accepte le
356
+ * `tier` en minuscules dans la REQUÊTE `propose` (en plus du PascalCase
357
+ * historique) et le renvoie toujours en minuscules dans les RÉPONSES (propose
358
+ * result, pending, history, blocks) via `GovernanceTier::as_str()`. Un `tier`
359
+ * reçu peut donc être comparé directement (`proposal.tier === "operator"`) sans
360
+ * normalisation de casse.
361
+ */
362
+ type GovernanceTier = "operator" | "policy" | "constitution";
363
+ /**
364
+ * Statut d'une proposition de gouvernance (forme renvoyée par les lectures
365
+ * publiques, en minuscules).
366
+ */
367
+ type GovernanceStatus = "pending" | "enacted" | "cancelled";
368
+ /**
369
+ * Proposition de gouvernance ancrée dans le DAG.
370
+ *
371
+ * Retournée par [`PmsClient.getGovernancePending`] et
372
+ * [`PmsClient.getGovernanceHistory`]. Le champ `update` est le `ConfigUpdate`
373
+ * brut (externally-tagged) que la proposition appliquera à son enactment.
374
+ */
375
+ interface GovernanceProposal {
376
+ /** Identifiant de la proposition (SHA-256 hex). */
377
+ proposal_id: string;
378
+ /** Palier de gouvernance. */
379
+ tier: GovernanceTier;
380
+ /** Statut courant. */
381
+ status: GovernanceStatus;
382
+ /** Raison libre fournie par le proposant (peut être vide). */
383
+ reason: string;
384
+ /** Horodatage de l'annonce (UNIX ms). */
385
+ announced_at_ms: number;
386
+ /** Horodatage à partir duquel l'enactment est autorisé (UNIX ms). */
387
+ enact_after_ms: number;
388
+ /** Mise à jour de config à appliquer. */
389
+ update: ConfigUpdate;
390
+ /** ID du bloc DAG de la proposition. */
391
+ proposal_block_id: string;
392
+ /** ID du bloc d'enactment (null tant que non-enacté). */
393
+ enact_block_id: string | null;
394
+ /** ID du bloc d'annulation (null tant que non-annulé). */
395
+ cancel_block_id: string | null;
396
+ }
397
+ /**
398
+ * Un bloc de gouvernance individuel du DAG (proposition, enactment, ou
399
+ * annulation), tel que retourné par [`PmsClient.getGovernanceBlocks`].
400
+ */
401
+ interface GovernanceBlock {
402
+ /** ID du bloc DAG. */
403
+ block_id: string;
404
+ /** Nature du bloc. */
405
+ kind: "proposal" | "enact" | "cancel";
406
+ /** Identifiant de la proposition à laquelle ce bloc se rattache. */
407
+ proposal_id: string;
408
+ /** Palier de gouvernance. */
409
+ tier: GovernanceTier;
410
+ /** Statut de la proposition au moment du snapshot. */
411
+ status: GovernanceStatus;
412
+ /** Mise à jour de config portée par la proposition. */
413
+ update: ConfigUpdate;
414
+ /** Raison libre. */
415
+ reason: string;
416
+ /** Horodatage de l'annonce (UNIX ms). */
417
+ announced_at_ms: number;
418
+ /** Horodatage d'enactment autorisé (UNIX ms). */
419
+ enact_after_ms: number;
420
+ }
421
+ /**
422
+ * Requête de proposition de gouvernance
423
+ * ([`PmsClient.proposeGovernance`]).
424
+ */
425
+ interface ProposeGovernanceRequest {
426
+ /** Mise à jour de config à proposer. */
427
+ update: ConfigUpdate;
428
+ /** Palier (minuscules — voir [`GovernanceTier`]). */
429
+ tier: GovernanceTier;
430
+ /** Raison libre (optionnelle, défaut côté moteur = chaîne vide). */
431
+ reason?: string;
432
+ }
433
+ /**
434
+ * Résultat de POST /admin/governance/propose.
435
+ *
436
+ * Le `tier` est renvoyé par le moteur en minuscules (voir [`GovernanceTier`]).
437
+ * La même casse est utilisée pour l'envoi de la requête.
438
+ */
439
+ interface ProposeResult {
440
+ /** Statut de l'appel (ex: "ok"). */
441
+ status: string;
442
+ /** Identifiant de la proposition créée (SHA-256 hex). */
443
+ proposal_id: string;
444
+ /** ID du bloc DAG de la proposition. */
445
+ block_id: string;
446
+ /** Palier assigné. */
447
+ tier: GovernanceTier;
448
+ /** Horodatage de l'annonce (UNIX ms). */
449
+ announced_at_ms: number;
450
+ /** Horodatage à partir duquel l'enactment est autorisé (UNIX ms). */
451
+ enact_after_ms: number;
452
+ }
453
+ /**
454
+ * Résultat d'un enactment ou d'une annulation de proposition
455
+ * (POST /admin/governance/enact/{id} et /cancel/{id}).
456
+ */
457
+ interface GovernanceActionResult {
458
+ /** Statut de l'appel (ex: "ok"). */
459
+ status: string;
460
+ /** Identifiant de la proposition concernée. */
461
+ proposal_id: string;
462
+ /** ID du bloc DAG d'enactment/annulation. */
463
+ block_id: string;
464
+ }
312
465
  /** Bloc du DAG */
313
466
  interface Block {
314
467
  /** ID unique du bloc (hash) */
@@ -503,6 +656,19 @@ interface PmsClientConfig {
503
656
  * Exemple: "pk_live_abc123..." ou "pk_test_xyz789..."
504
657
  */
505
658
  apiKey: string;
659
+ /**
660
+ * Jeton d'administration (optionnel).
661
+ *
662
+ * Requis UNIQUEMENT pour les méthodes admin (gouvernance propose/enact/
663
+ * cancel, [`PmsClient.setConfig`]). Envoyé dans l'en-tête
664
+ * `Authorization: Bearer <adminToken>`. Les lectures publiques (y compris
665
+ * de gouvernance) n'en ont PAS besoin. Si une méthode admin est appelée
666
+ * sans `adminToken`, le client lève une erreur explicite avant tout appel
667
+ * réseau.
668
+ *
669
+ * NE JAMAIS committer ce jeton ni l'exposer côté navigateur.
670
+ */
671
+ adminToken?: string;
506
672
  /** URLs des noeuds seeds (optionnel, pour racing et fallback) */
507
673
  seedNodes?: string[];
508
674
  /** ID du réseau (défaut: "pms-mainnet") */
@@ -639,6 +805,96 @@ interface RuntimeConfig {
639
805
  interface NodePublicConfig extends RuntimeConfig {
640
806
  fee_recipient: string;
641
807
  }
808
+ /**
809
+ * Résultat de POST /admin/config — union discriminée sur `applied`.
810
+ *
811
+ * Le moteur distingue deux issues selon le SENS de la mise à jour :
812
+ * - **durcissement** (tighten, ex: réduire un plafond, désactiver le mint) :
813
+ * appliqué INSTANTANÉMENT — HTTP 200, `status: "applied"`. → `applied: true`.
814
+ * - **assouplissement** (loosen, ex: hausser un plafond, réactiver le mint) :
815
+ * placé sous TIMELOCK de gouvernance, PAS encore appliqué — HTTP 202,
816
+ * `status: "proposed"`. → `applied: false`. Le changement s'auto-enacte
817
+ * quand le timelock expire, ou via [`PmsClient.enactProposal`].
818
+ *
819
+ * Le SDK NE traite JAMAIS un 202 comme un succès appliqué : inspectez
820
+ * `result.applied` avant de supposer que le changement est en vigueur.
821
+ */
822
+ type ConfigChangeResult = ConfigChangeApplied | ConfigChangeProposed;
823
+ /** Variante "appliqué instantanément" (HTTP 200). */
824
+ interface ConfigChangeApplied {
825
+ /** Discriminant : le changement est en vigueur. */
826
+ applied: true;
827
+ /** Statut moteur (toujours "applied" pour cette variante). */
828
+ status: "applied";
829
+ /** Mode lisible (ex: "instant (tighten)"). */
830
+ mode: string;
831
+ /** Description lisible de la mise à jour appliquée. */
832
+ updateApplied: string;
833
+ /** Palier de gouvernance déduit (minuscules côté moteur). */
834
+ tier: string;
835
+ /** Identifiant de la proposition implicite. */
836
+ proposalId: string;
837
+ /** ID du bloc DAG de proposition. */
838
+ proposalBlockId: string;
839
+ /** ID du bloc DAG d'enactment (immédiat). */
840
+ enactBlockId: string;
841
+ /** Config runtime résultante (null si lecture impossible côté moteur). */
842
+ config: RuntimeConfig | null;
843
+ }
844
+ /** Variante "proposé, timelocké" (HTTP 202). */
845
+ interface ConfigChangeProposed {
846
+ /** Discriminant : le changement n'est PAS encore en vigueur. */
847
+ applied: false;
848
+ /** Statut moteur (toujours "proposed" pour cette variante). */
849
+ status: "proposed";
850
+ /** Mode lisible (ex: "timelocked (loosen)"). */
851
+ mode: string;
852
+ /** Description lisible de la mise à jour proposée. */
853
+ update: string;
854
+ /** Palier de gouvernance déduit (minuscules côté moteur). */
855
+ tier: string;
856
+ /** Identifiant de la proposition créée. */
857
+ proposalId: string;
858
+ /** ID du bloc DAG de proposition. */
859
+ proposalBlockId: string;
860
+ /** Horodatage de l'annonce (UNIX ms). */
861
+ announcedAtMs: number;
862
+ /** Horodatage à partir duquel l'enactment est autorisé (UNIX ms). */
863
+ enactAfterMs: number;
864
+ /** Message explicatif du moteur. */
865
+ message: string;
866
+ }
867
+ /**
868
+ * Codes d'erreur numériques stables renvoyés par le moteur PMS.
869
+ *
870
+ * Le moteur renvoie ses erreurs au format JSON `{"code": NNNN, "message":
871
+ * "..."}`. Les clients DOIVENT brancher sur le `code` numérique (stable) et
872
+ * non sur le `message` (susceptible de changer de formulation).
873
+ *
874
+ * Tranches : `1xxx` auth/authz, `2xxx` validation requête, `3xxx`
875
+ * état/business, `4xxx` crypto/sécurité, `5xxx` ressource/quota, `9xxx`
876
+ * interne.
877
+ *
878
+ * Le code est exposé sur l'erreur levée via la propriété `code` (voir
879
+ * [`PmsError`]).
880
+ */
881
+ declare const ErrorCode: {
882
+ /** En-tête d'authentification manquant (admin requis). */
883
+ readonly MissingAuth: 1001;
884
+ /** Jeton d'authentification invalide. */
885
+ readonly InvalidAuth: 1002;
886
+ /**
887
+ * Proposition de gouvernance rejetée (timelock non écoulé, proposition
888
+ * non en attente, ou identifiant inconnu). HTTP 409.
889
+ */
890
+ readonly GovernanceRejected: 3071;
891
+ /** Émission native (mint) désactivée. HTTP 503. */
892
+ readonly MintDisabled: 5031;
893
+ /** Erreur interne générique (dette : handler non encore migré). */
894
+ readonly Internal: 9999;
895
+ };
896
+ /** Valeur numérique d'un code d'erreur ([`ErrorCode`]). */
897
+ type ErrorCodeValue = (typeof ErrorCode)[keyof typeof ErrorCode];
642
898
 
643
899
  /**
644
900
  * PmsWallet - Wallet pour le réseau PMS.
@@ -881,6 +1137,119 @@ declare class PmsClient {
881
1137
  * `GET /v1/reserves/latest`). 404 si aucun snapshot n'a encore été ancré.
882
1138
  */
883
1139
  getLatestReserves(): Promise<ReservesLatest>;
1140
+ /**
1141
+ * Liste les propositions de gouvernance EN ATTENTE (statut `pending`).
1142
+ *
1143
+ * Lecture publique — aucun `adminToken` requis.
1144
+ *
1145
+ * @returns Le tableau des propositions en attente (vide si aucune).
1146
+ *
1147
+ * @example
1148
+ * ```typescript
1149
+ * const pending = await client.getGovernancePending();
1150
+ * for (const p of pending) {
1151
+ * console.log(`${p.proposal_id} enacts after ${new Date(p.enact_after_ms)}`);
1152
+ * }
1153
+ * ```
1154
+ */
1155
+ getGovernancePending(): Promise<GovernanceProposal[]>;
1156
+ /**
1157
+ * Liste les propositions de gouvernance TERMINÉES (enactées ou annulées).
1158
+ *
1159
+ * Lecture publique — aucun `adminToken` requis.
1160
+ *
1161
+ * @returns Le tableau de l'historique des propositions (vide si aucune).
1162
+ */
1163
+ getGovernanceHistory(): Promise<GovernanceProposal[]>;
1164
+ /**
1165
+ * Liste les blocs de gouvernance ancrés dans le DAG (un par proposition,
1166
+ * enactment, ou annulation).
1167
+ *
1168
+ * Lecture publique — aucun `adminToken` requis.
1169
+ *
1170
+ * @returns `{ count, blocks }` — le nombre et la liste des blocs.
1171
+ */
1172
+ getGovernanceBlocks(): Promise<{
1173
+ count: number;
1174
+ blocks: GovernanceBlock[];
1175
+ }>;
1176
+ /**
1177
+ * Soumet une proposition de gouvernance ancrée dans le DAG.
1178
+ *
1179
+ * Méthode ADMIN — requiert `adminToken` dans la config du client
1180
+ * (envoyé en `Authorization: Bearer <adminToken>`). Lève une erreur
1181
+ * explicite avant tout appel réseau si le jeton est absent.
1182
+ *
1183
+ * @param req.update - Mise à jour de config à proposer.
1184
+ * @param req.tier - Palier de gouvernance (minuscules, voir
1185
+ * [`GovernanceTier`]).
1186
+ * @param req.reason - Raison libre (optionnelle).
1187
+ * @returns `{ status, proposal_id, block_id, tier, announced_at_ms,
1188
+ * enact_after_ms }`.
1189
+ *
1190
+ * @example
1191
+ * ```typescript
1192
+ * const res = await client.proposeGovernance({
1193
+ * update: { SetEmissionCorridor: { ceiling_bps: 1500, floor_bps: 0, target_bps: 1000, epoch_duration_sec: 86400 } },
1194
+ * tier: "constitution",
1195
+ * reason: "raise emission ceiling for Q3",
1196
+ * });
1197
+ * console.log(res.proposal_id, "enacts after", new Date(res.enact_after_ms));
1198
+ * ```
1199
+ */
1200
+ proposeGovernance(req: ProposeGovernanceRequest): Promise<ProposeResult>;
1201
+ /**
1202
+ * Enacte une proposition de gouvernance dont le timelock est écoulé.
1203
+ *
1204
+ * Méthode ADMIN — requiert `adminToken`. Le moteur rejette (HTTP 409,
1205
+ * code [`ErrorCode.GovernanceRejected`] = 3071) si le timelock n'est pas
1206
+ * écoulé, si la proposition n'est pas en attente, ou si l'identifiant est
1207
+ * inconnu.
1208
+ *
1209
+ * @param proposalId - Identifiant de la proposition à enacter.
1210
+ * @param reason - Raison libre (optionnelle).
1211
+ * @returns `{ status, proposal_id, block_id }`.
1212
+ */
1213
+ enactProposal(proposalId: string, reason?: string): Promise<GovernanceActionResult>;
1214
+ /**
1215
+ * Annule une proposition de gouvernance en attente.
1216
+ *
1217
+ * Méthode ADMIN — requiert `adminToken`. Rejet HTTP 409 / code 3071 si la
1218
+ * proposition n'est pas en attente ou si l'identifiant est inconnu.
1219
+ *
1220
+ * @param proposalId - Identifiant de la proposition à annuler.
1221
+ * @param reason - Raison libre (optionnelle).
1222
+ * @returns `{ status, proposal_id, block_id }`.
1223
+ */
1224
+ cancelProposal(proposalId: string, reason?: string): Promise<GovernanceActionResult>;
1225
+ /**
1226
+ * Applique (ou propose) une mise à jour de configuration.
1227
+ *
1228
+ * Méthode ADMIN — requiert `adminToken`. Le moteur distingue DEUX issues
1229
+ * selon le sens du changement, et le SDK les EXPOSE explicitement via une
1230
+ * union discriminée sur `applied` — un 202 n'est JAMAIS traité comme un
1231
+ * succès appliqué :
1232
+ * - **HTTP 200** (durcissement) → `{ applied: true, ... }` : la mise à
1233
+ * jour est instantanément en vigueur.
1234
+ * - **HTTP 202** (assouplissement) → `{ applied: false, proposalId,
1235
+ * enactAfterMs, ... }` : la mise à jour est placée sous timelock de
1236
+ * gouvernance, PAS encore appliquée. Elle s'auto-enacte à l'expiration
1237
+ * du timelock, ou via [`enactProposal`].
1238
+ *
1239
+ * @param update - Mise à jour de config (envoyée brute, sans wrapper).
1240
+ * @returns Une [`ConfigChangeResult`] discriminée sur `applied`.
1241
+ *
1242
+ * @example
1243
+ * ```typescript
1244
+ * const r = await client.setConfig({ SetMintEnabled: { enabled: false } });
1245
+ * if (r.applied) {
1246
+ * console.log("appliqué instantanément:", r.updateApplied);
1247
+ * } else {
1248
+ * console.log("timelocké, enact après", new Date(r.enactAfterMs));
1249
+ * }
1250
+ * ```
1251
+ */
1252
+ setConfig(update: ConfigUpdate): Promise<ConfigChangeResult>;
884
1253
  /**
885
1254
  * Crée un nouveau wallet côté serveur (custodial).
886
1255
  * Le serveur génère le wallet et retourne toutes les clés + adresse Bech32.
@@ -1228,15 +1597,97 @@ declare class PmsClient {
1228
1597
  * Utilise crypto.getRandomValues pour la sécurité cryptographique.
1229
1598
  */
1230
1599
  private generateRandomHex;
1600
+ /**
1601
+ * @internal
1602
+ * Garantit qu'un `adminToken` est configuré avant un appel admin.
1603
+ * Lève une erreur claire (sans appel réseau) sinon.
1604
+ */
1605
+ private requireAdminToken;
1606
+ /**
1607
+ * @internal
1608
+ * Effectue un appel admin authentifié (en-tête `Authorization: Bearer`).
1609
+ *
1610
+ * Les écritures admin ne sont PAS idempotentes — pas de retry automatique
1611
+ * (single-attempt via la branche non-idempotente de `fetchUrl`). L'auth est
1612
+ * injectée par appel (pas dans le bloc d'en-têtes partagé de `fetchOnce`)
1613
+ * pour éviter de fuiter le jeton admin vers des nœuds découverts/seeds lors
1614
+ * du racing — cf. `submitBlockRacing`. `method` ne sert qu'au libellé de
1615
+ * l'erreur "jeton manquant".
1616
+ */
1617
+ private fetchAdmin;
1618
+ /**
1619
+ * @internal
1620
+ * Variante d'appel admin qui expose le STATUT HTTP en plus du corps parsé.
1621
+ * Nécessaire pour [`setConfig`], qui doit distinguer 200 (applied) de 202
1622
+ * (proposed) — deux corps de réponse différents pour deux issues. Délègue à
1623
+ * la même primitive `fetchOnceWithStatus` que tous les autres appels, donc
1624
+ * hérite du merge de signal et du tagging d'abort sans duplication.
1625
+ */
1626
+ private fetchAdminWithStatus;
1627
+ /**
1628
+ * @internal
1629
+ * Vérifie la présence du jeton admin (sinon erreur claire, sans réseau) et
1630
+ * injecte l'en-tête `Authorization: Bearer <token>` dans un RequestInit.
1631
+ */
1632
+ private withAdminAuth;
1231
1633
  private fetch;
1232
1634
  /**
1233
1635
  * Single-attempt HTTP request. Throws a tagged error on transient conditions
1234
1636
  * (network failure, per-attempt abort, 5xx) so the retry loop can decide
1235
1637
  * whether to retry. 4xx and other non-2xx are thrown as fatal HttpError.
1638
+ *
1639
+ * Thin wrapper over `fetchOnceWithStatus` that discards the HTTP status —
1640
+ * every caller that only needs the parsed body goes through here.
1236
1641
  */
1237
1642
  private fetchOnce;
1643
+ /**
1644
+ * Single-attempt HTTP request returning BOTH the numeric HTTP status and the
1645
+ * parsed body. The shared fetch primitive: applies the default headers
1646
+ * (`Content-Type`, public `X-API-Key`), merges the caller's signal with the
1647
+ * per-attempt timeout, tags per-attempt aborts as `PerAttemptTimeoutError`
1648
+ * (so the retry loop can act on them), and constructs `HttpError` on non-2xx.
1649
+ *
1650
+ * NOTE: admin `Authorization: Bearer` is NOT injected here — it is added
1651
+ * per-admin-call by `withAdminAuth` so the admin token never leaks to
1652
+ * discovered/seed nodes during `submitBlockRacing`. Only the public,
1653
+ * scoped `X-API-Key` is broadcast.
1654
+ */
1655
+ private fetchOnceWithStatus;
1238
1656
  private fetchUrl;
1239
1657
  }
1658
+ /**
1659
+ * Error type for HTTP non-2xx responses.
1660
+ *
1661
+ * Carries the HTTP status + `Retry-After` header (for the retry loop) AND,
1662
+ * when the engine returns its stable `{"code": NNNN, "message": "..."}` JSON
1663
+ * body, the parsed numeric `code` and engine `message`. Consumers branch on
1664
+ * the stable numeric `code` (see {@link ErrorCode}) rather than the message
1665
+ * string:
1666
+ *
1667
+ * ```typescript
1668
+ * import { ErrorCode } from "@empereur-rouge/pms-sdk";
1669
+ * try {
1670
+ * await client.setConfig({ SetMintEnabled: { enabled: true } });
1671
+ * } catch (e) {
1672
+ * if ((e as any).code === ErrorCode.GovernanceRejected) { ... }
1673
+ * }
1674
+ * ```
1675
+ *
1676
+ * Backward compatible: `.message` keeps the original `HTTP <status> (...)`
1677
+ * format; `.code` is `undefined` when the body was not the `{code,message}`
1678
+ * shape (e.g. plaintext, legacy `{"error":"..."}`).
1679
+ */
1680
+ declare class HttpError extends Error {
1681
+ readonly status: number;
1682
+ readonly retryAfter: string | null;
1683
+ /** Raw response body text (may be empty). */
1684
+ readonly body: string;
1685
+ /** Stable numeric error code parsed from `{code,message}`, if present. */
1686
+ readonly code?: number;
1687
+ /** Engine-provided message from `{code,message}`, if present. */
1688
+ readonly engineMessage?: string;
1689
+ constructor(status: number, message: string, retryAfter: string | null, body?: string);
1690
+ }
1240
1691
 
1241
1692
  /**
1242
1693
  * Utilitaires cryptographiques pour le SDK PMS.
@@ -1376,4 +1827,4 @@ declare function spendableUtxos<T extends Utxo>(utxos: T[], nowMs?: number): T[]
1376
1827
  */
1377
1828
  declare function decryptPayload(encrypted: EncryptedPayload, recipientPrivateKeyHex: string): string;
1378
1829
 
1379
- export { type ActivityDirection, type ActivityItem, type ActivityOptions, type ActivityResp, type ActivityType, type BalanceInfo, type Block, type BurnNftResponse, type CoordinatorInfoResponse, type Cosigner, type CubeAttributes, DAY_MS, type HistoryItem, type LedgerInfo, type ListLedgersOptions, type MintCubeResponse, type NftMetadata, type NftResponse, PmsClient, type PmsClientConfig, PmsWallet, type PrepareTxRequest, type PrepareTxResponse, type ReservesLatest, type RuntimeConfig, type SendTxResponse, type SpendCondition, type StreamActivityOptions, type SubmitResponse, type SupplyInfo, type TokenMetadata, type TxInput, type TxOutput, type TxUtxo, type Unlock, type Utxo, type UtxoDetail, type WalletHistoryResp, type WalletResponse, decryptPayload, effectiveValue, formatAmount, fromHex, hashlockHash, isValidMnemonic, makeUnlock, multisigAddress, parseAmount, spendableUtxos, toHex, txSigningMessage };
1830
+ export { type ActivityDirection, type ActivityItem, type ActivityOptions, type ActivityResp, type ActivityType, type BalanceInfo, type Block, type BurnNftResponse, type ConfigChangeApplied, type ConfigChangeProposed, type ConfigChangeResult, type ConfigUpdate, type CoordinatorInfoResponse, type Cosigner, type CubeAttributes, DAY_MS, ErrorCode, type ErrorCodeValue, type GovernanceActionResult, type GovernanceBlock, type GovernanceProposal, type GovernanceStatus, type GovernanceTier, type HistoryItem, HttpError, type LedgerInfo, type ListLedgersOptions, type MintCubeResponse, type NftMetadata, type NftResponse, PmsClient, type PmsClientConfig, PmsWallet, type PrepareTxRequest, type PrepareTxResponse, type ProposeGovernanceRequest, type ProposeResult, type ReservesLatest, type RuntimeConfig, type SendTxResponse, type SpendCondition, type StreamActivityOptions, type SubmitResponse, type SupplyInfo, type TokenMetadata, type TxInput, type TxOutput, type TxUtxo, type Unlock, type Utxo, type UtxoDetail, type WalletHistoryResp, type WalletResponse, decryptPayload, effectiveValue, formatAmount, fromHex, hashlockHash, isValidMnemonic, makeUnlock, multisigAddress, parseAmount, spendableUtxos, toHex, txSigningMessage };