@empereur-rouge/pms-sdk 0.3.1 → 0.3.3

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.cjs CHANGED
@@ -625,6 +625,147 @@ var PmsClient = class {
625
625
  return res;
626
626
  }
627
627
  // ═══════════════════════════════════════════════════════════════════════
628
+ // Activité du wallet
629
+ // ═══════════════════════════════════════════════════════════════════════
630
+ /**
631
+ * Récupère l'activité complète d'un wallet avec classification sémantique.
632
+ *
633
+ * Chaque activité est classifiée (transfer_in, fee_received, nft_mint, freeze, etc.)
634
+ * avec direction, montant et contrepartie.
635
+ *
636
+ * @param address - Adresse du wallet (bech32 ou hex)
637
+ * @param options - Filtres et pagination
638
+ * @returns Activités paginées
639
+ *
640
+ * @example
641
+ * ```typescript
642
+ * // Toute l'activité
643
+ * const activity = await client.getActivity("8eabc...");
644
+ *
645
+ * // Seulement les fees reçues
646
+ * const fees = await client.getActivity("8eabc...", {
647
+ * type: ["fee_received"],
648
+ * limit: 20,
649
+ * });
650
+ *
651
+ * // Pagination
652
+ * const page2 = await client.getActivity("8eabc...", {
653
+ * after_ts: activity.next_after_ts,
654
+ * after_id: activity.next_after_id,
655
+ * });
656
+ * ```
657
+ */
658
+ async getActivity(address, options) {
659
+ const params = new URLSearchParams();
660
+ if (options?.type && options.type.length > 0) {
661
+ params.set("type", options.type.join(","));
662
+ }
663
+ if (options?.limit !== void 0) {
664
+ params.set("limit", String(options.limit));
665
+ }
666
+ if (options?.after_ts !== void 0) {
667
+ params.set("after_ts", String(options.after_ts));
668
+ }
669
+ if (options?.after_id !== void 0) {
670
+ params.set("after_id", options.after_id);
671
+ }
672
+ if (options?.asset_id !== void 0) {
673
+ params.set("asset_id", options.asset_id);
674
+ }
675
+ const qs = params.toString();
676
+ const path = `/v1/wallet/${encodeURIComponent(address)}/activity${qs ? `?${qs}` : ""}`;
677
+ return this.fetch(path);
678
+ }
679
+ /**
680
+ * Écoute l'activité d'un wallet en temps réel via Server-Sent Events (SSE).
681
+ *
682
+ * Retourne une fonction de nettoyage pour fermer la connexion.
683
+ *
684
+ * @param address - Adresse du wallet (bech32 ou hex)
685
+ * @param options - Callbacks et filtres
686
+ * @returns Fonction pour fermer le flux SSE
687
+ *
688
+ * @example
689
+ * ```typescript
690
+ * const stop = client.streamActivity("8eabc...", {
691
+ * type: ["transfer_in", "fee_received"],
692
+ * onActivity: (item) => {
693
+ * console.log(`${item.activity_type}: ${item.amount} ${item.direction}`);
694
+ * },
695
+ * onError: (err) => console.error(err),
696
+ * });
697
+ *
698
+ * // Plus tard: fermer la connexion
699
+ * stop();
700
+ * ```
701
+ */
702
+ streamActivity(address, options) {
703
+ const params = new URLSearchParams();
704
+ if (options.type && options.type.length > 0) {
705
+ params.set("type", options.type.join(","));
706
+ }
707
+ const qs = params.toString();
708
+ const path = `/v1/wallet/${encodeURIComponent(address)}/activity/stream${qs ? `?${qs}` : ""}`;
709
+ const url = `${this.config.nodeUrl}${path}`;
710
+ const controller = new AbortController();
711
+ const signal = options.signal ? mergeAbortSignals(options.signal, controller.signal) : controller.signal;
712
+ (async () => {
713
+ try {
714
+ const headers = {
715
+ "Accept": "text/event-stream"
716
+ };
717
+ if (this.config.apiKey) {
718
+ headers["X-API-Key"] = this.config.apiKey;
719
+ }
720
+ const resp = await fetch(url, { headers, signal });
721
+ if (!resp.ok) {
722
+ throw new Error(`SSE connection failed: ${resp.status} ${resp.statusText}`);
723
+ }
724
+ if (!resp.body) {
725
+ throw new Error("SSE response has no body");
726
+ }
727
+ const reader = resp.body.getReader();
728
+ const decoder = new TextDecoder();
729
+ let buffer = "";
730
+ while (true) {
731
+ const { done, value } = await reader.read();
732
+ if (done) break;
733
+ buffer += decoder.decode(value, { stream: true });
734
+ const lines = buffer.split("\n");
735
+ buffer = lines.pop() ?? "";
736
+ let currentEvent = "";
737
+ let currentData = "";
738
+ for (const line of lines) {
739
+ if (line.startsWith("event:")) {
740
+ currentEvent = line.slice(6).trim();
741
+ } else if (line.startsWith("data:")) {
742
+ currentData = line.slice(5).trim();
743
+ } else if (line === "" && currentData) {
744
+ if (currentEvent === "activity" && currentData) {
745
+ try {
746
+ const item = JSON.parse(currentData);
747
+ options.onActivity(item);
748
+ } catch (e) {
749
+ }
750
+ } else if (currentEvent === "warning") {
751
+ }
752
+ currentEvent = "";
753
+ currentData = "";
754
+ }
755
+ }
756
+ }
757
+ options.onClose?.();
758
+ } catch (err) {
759
+ if (err.name === "AbortError") {
760
+ options.onClose?.();
761
+ } else {
762
+ options.onError?.(err instanceof Error ? err : new Error(String(err)));
763
+ }
764
+ }
765
+ })();
766
+ return () => controller.abort();
767
+ }
768
+ // ═══════════════════════════════════════════════════════════════════════
628
769
  // Méthodes d'écriture (POST)
629
770
  // ═══════════════════════════════════════════════════════════════════════
630
771
  /**
@@ -1119,6 +1260,13 @@ var PmsClient = class {
1119
1260
  }
1120
1261
  }
1121
1262
  };
1263
+ function mergeAbortSignals(a, b) {
1264
+ const controller = new AbortController();
1265
+ const onAbort = () => controller.abort();
1266
+ a.addEventListener("abort", onAbort, { once: true });
1267
+ b.addEventListener("abort", onAbort, { once: true });
1268
+ return controller.signal;
1269
+ }
1122
1270
  // Annotate the CommonJS export names for ESM import in node:
1123
1271
  0 && (module.exports = {
1124
1272
  PmsClient,
package/dist/index.d.cts CHANGED
@@ -529,6 +529,83 @@ interface WalletHistoryResp {
529
529
  items: HistoryItem[];
530
530
  count: number;
531
531
  }
532
+ /**
533
+ * Type d'activité sémantique pour un wallet.
534
+ *
535
+ * - Transferts: "transfer_in", "transfer_out", "transfer_self"
536
+ * - Fees: "fee_received"
537
+ * - Minting: "mint"
538
+ * - NFT: "nft_mint", "nft_transfer_in", "nft_transfer_out", "nft_burn", "nft_use"
539
+ * - Bridge: "bridge_lock_in", "bridge_lock_out", "bridge_mint"
540
+ * - Compliance: "freeze", "unfreeze", "seized", "seize_received", "reversed", "reverse_received"
541
+ * - Token: "token_create"
542
+ * - Reward: "reward"
543
+ */
544
+ type ActivityType = "transfer_in" | "transfer_out" | "transfer_self" | "fee_received" | "reward" | "mint" | "nft_mint" | "nft_transfer_in" | "nft_transfer_out" | "nft_burn" | "nft_use" | "bridge_lock_in" | "bridge_lock_out" | "bridge_mint" | "freeze" | "unfreeze" | "seized" | "seize_received" | "reversed" | "reverse_received" | "token_create";
545
+ /** Direction de l'activité */
546
+ type ActivityDirection = "in" | "out" | "info";
547
+ /** Élément d'activité classifié pour un wallet */
548
+ interface ActivityItem {
549
+ /** ID du bloc contenant l'activité */
550
+ block_id: string;
551
+ /** Timestamp en millisecondes */
552
+ ts_ms: number;
553
+ /** Type d'activité sémantique */
554
+ activity_type: ActivityType;
555
+ /** Direction: "in" (reçu), "out" (envoyé), "info" (informatif) */
556
+ direction: ActivityDirection;
557
+ /** Montant net pour cette adresse (positif = reçu), absent pour NFT/compliance */
558
+ amount?: string;
559
+ /** Asset ID (undefined = PMS natif) */
560
+ asset_id?: string;
561
+ /** Adresse de la contrepartie */
562
+ counterparty?: string;
563
+ /** Ledger ID d'origine (absent en mode single-ledger "main") */
564
+ ledger_id?: string;
565
+ /** Payload brut pour détails complets */
566
+ payload: any;
567
+ }
568
+ /** Réponse de l'endpoint GET /v1/wallet/{address}/activity */
569
+ interface ActivityResp {
570
+ /** Adresse du wallet */
571
+ address: string;
572
+ /** Éléments d'activité classifiés */
573
+ items: ActivityItem[];
574
+ /** Nombre d'éléments retournés */
575
+ count: number;
576
+ /** Timestamp cursor pour la pagination (next page) */
577
+ next_after_ts?: number;
578
+ /** Block ID cursor pour la pagination (next page) */
579
+ next_after_id?: string;
580
+ /** Indique s'il y a plus de résultats */
581
+ has_more: boolean;
582
+ }
583
+ /** Options pour getActivity() */
584
+ interface ActivityOptions {
585
+ /** Filtrer par type(s) d'activité (ex: ["fee_received", "transfer_in"]) */
586
+ type?: ActivityType[];
587
+ /** Nombre max d'éléments (défaut: 50, max: 500) */
588
+ limit?: number;
589
+ /** Cursor de pagination: timestamp */
590
+ after_ts?: number;
591
+ /** Cursor de pagination: block ID */
592
+ after_id?: string;
593
+ /** Filtrer par asset ID */
594
+ asset_id?: string;
595
+ }
596
+ /** Options pour streamActivity() */
597
+ interface StreamActivityOptions {
598
+ /** Filtrer par type(s) d'activité */
599
+ type?: ActivityType[];
600
+ /** Callback appelé pour chaque activité en temps réel */
601
+ onActivity: (item: ActivityItem) => void;
602
+ /** Callback appelé en cas d'erreur */
603
+ onError?: (error: Error) => void;
604
+ /** Callback appelé à la fermeture du flux */
605
+ onClose?: () => void;
606
+ /** Signal d'annulation */
607
+ signal?: AbortSignal;
608
+ }
532
609
  interface RuntimeConfig {
533
610
  fee_rate_bps: number;
534
611
  base_fee: string;
@@ -743,6 +820,59 @@ declare class PmsClient {
743
820
  limit?: number;
744
821
  decryptionWallet?: PmsWallet;
745
822
  }): Promise<WalletHistoryResp>;
823
+ /**
824
+ * Récupère l'activité complète d'un wallet avec classification sémantique.
825
+ *
826
+ * Chaque activité est classifiée (transfer_in, fee_received, nft_mint, freeze, etc.)
827
+ * avec direction, montant et contrepartie.
828
+ *
829
+ * @param address - Adresse du wallet (bech32 ou hex)
830
+ * @param options - Filtres et pagination
831
+ * @returns Activités paginées
832
+ *
833
+ * @example
834
+ * ```typescript
835
+ * // Toute l'activité
836
+ * const activity = await client.getActivity("8eabc...");
837
+ *
838
+ * // Seulement les fees reçues
839
+ * const fees = await client.getActivity("8eabc...", {
840
+ * type: ["fee_received"],
841
+ * limit: 20,
842
+ * });
843
+ *
844
+ * // Pagination
845
+ * const page2 = await client.getActivity("8eabc...", {
846
+ * after_ts: activity.next_after_ts,
847
+ * after_id: activity.next_after_id,
848
+ * });
849
+ * ```
850
+ */
851
+ getActivity(address: string, options?: ActivityOptions): Promise<ActivityResp>;
852
+ /**
853
+ * Écoute l'activité d'un wallet en temps réel via Server-Sent Events (SSE).
854
+ *
855
+ * Retourne une fonction de nettoyage pour fermer la connexion.
856
+ *
857
+ * @param address - Adresse du wallet (bech32 ou hex)
858
+ * @param options - Callbacks et filtres
859
+ * @returns Fonction pour fermer le flux SSE
860
+ *
861
+ * @example
862
+ * ```typescript
863
+ * const stop = client.streamActivity("8eabc...", {
864
+ * type: ["transfer_in", "fee_received"],
865
+ * onActivity: (item) => {
866
+ * console.log(`${item.activity_type}: ${item.amount} ${item.direction}`);
867
+ * },
868
+ * onError: (err) => console.error(err),
869
+ * });
870
+ *
871
+ * // Plus tard: fermer la connexion
872
+ * stop();
873
+ * ```
874
+ */
875
+ streamActivity(address: string, options: StreamActivityOptions): () => void;
746
876
  /**
747
877
  * Récupère la configuration publique du nœud (frais, PoW, recipient, etc.)
748
878
  */
@@ -915,4 +1045,4 @@ declare function formatAmount(sats: bigint): string;
915
1045
  */
916
1046
  declare function decryptPayload(encrypted: EncryptedPayload, recipientPrivateKeyHex: string): string;
917
1047
 
918
- export { type BalanceInfo, type Block, type BurnNftResponse, type CoordinatorInfoResponse, type CubeAttributes, type HistoryItem, type MintCubeResponse, type NftMetadata, type NftResponse, PmsClient, type PmsClientConfig, PmsWallet, type PrepareTxRequest, type PrepareTxResponse, type RuntimeConfig, type SubmitResponse, type SupplyInfo, type TokenMetadata, type Utxo, type UtxoDetail, type WalletHistoryResp, type WalletResponse, decryptPayload, formatAmount, fromHex, isValidMnemonic, parseAmount, toHex };
1048
+ export { type ActivityDirection, type ActivityItem, type ActivityOptions, type ActivityResp, type ActivityType, type BalanceInfo, type Block, type BurnNftResponse, type CoordinatorInfoResponse, type CubeAttributes, type HistoryItem, type MintCubeResponse, type NftMetadata, type NftResponse, PmsClient, type PmsClientConfig, PmsWallet, type PrepareTxRequest, type PrepareTxResponse, type RuntimeConfig, type StreamActivityOptions, type SubmitResponse, type SupplyInfo, type TokenMetadata, type Utxo, type UtxoDetail, type WalletHistoryResp, type WalletResponse, decryptPayload, formatAmount, fromHex, isValidMnemonic, parseAmount, toHex };
package/dist/index.d.ts CHANGED
@@ -529,6 +529,83 @@ interface WalletHistoryResp {
529
529
  items: HistoryItem[];
530
530
  count: number;
531
531
  }
532
+ /**
533
+ * Type d'activité sémantique pour un wallet.
534
+ *
535
+ * - Transferts: "transfer_in", "transfer_out", "transfer_self"
536
+ * - Fees: "fee_received"
537
+ * - Minting: "mint"
538
+ * - NFT: "nft_mint", "nft_transfer_in", "nft_transfer_out", "nft_burn", "nft_use"
539
+ * - Bridge: "bridge_lock_in", "bridge_lock_out", "bridge_mint"
540
+ * - Compliance: "freeze", "unfreeze", "seized", "seize_received", "reversed", "reverse_received"
541
+ * - Token: "token_create"
542
+ * - Reward: "reward"
543
+ */
544
+ type ActivityType = "transfer_in" | "transfer_out" | "transfer_self" | "fee_received" | "reward" | "mint" | "nft_mint" | "nft_transfer_in" | "nft_transfer_out" | "nft_burn" | "nft_use" | "bridge_lock_in" | "bridge_lock_out" | "bridge_mint" | "freeze" | "unfreeze" | "seized" | "seize_received" | "reversed" | "reverse_received" | "token_create";
545
+ /** Direction de l'activité */
546
+ type ActivityDirection = "in" | "out" | "info";
547
+ /** Élément d'activité classifié pour un wallet */
548
+ interface ActivityItem {
549
+ /** ID du bloc contenant l'activité */
550
+ block_id: string;
551
+ /** Timestamp en millisecondes */
552
+ ts_ms: number;
553
+ /** Type d'activité sémantique */
554
+ activity_type: ActivityType;
555
+ /** Direction: "in" (reçu), "out" (envoyé), "info" (informatif) */
556
+ direction: ActivityDirection;
557
+ /** Montant net pour cette adresse (positif = reçu), absent pour NFT/compliance */
558
+ amount?: string;
559
+ /** Asset ID (undefined = PMS natif) */
560
+ asset_id?: string;
561
+ /** Adresse de la contrepartie */
562
+ counterparty?: string;
563
+ /** Ledger ID d'origine (absent en mode single-ledger "main") */
564
+ ledger_id?: string;
565
+ /** Payload brut pour détails complets */
566
+ payload: any;
567
+ }
568
+ /** Réponse de l'endpoint GET /v1/wallet/{address}/activity */
569
+ interface ActivityResp {
570
+ /** Adresse du wallet */
571
+ address: string;
572
+ /** Éléments d'activité classifiés */
573
+ items: ActivityItem[];
574
+ /** Nombre d'éléments retournés */
575
+ count: number;
576
+ /** Timestamp cursor pour la pagination (next page) */
577
+ next_after_ts?: number;
578
+ /** Block ID cursor pour la pagination (next page) */
579
+ next_after_id?: string;
580
+ /** Indique s'il y a plus de résultats */
581
+ has_more: boolean;
582
+ }
583
+ /** Options pour getActivity() */
584
+ interface ActivityOptions {
585
+ /** Filtrer par type(s) d'activité (ex: ["fee_received", "transfer_in"]) */
586
+ type?: ActivityType[];
587
+ /** Nombre max d'éléments (défaut: 50, max: 500) */
588
+ limit?: number;
589
+ /** Cursor de pagination: timestamp */
590
+ after_ts?: number;
591
+ /** Cursor de pagination: block ID */
592
+ after_id?: string;
593
+ /** Filtrer par asset ID */
594
+ asset_id?: string;
595
+ }
596
+ /** Options pour streamActivity() */
597
+ interface StreamActivityOptions {
598
+ /** Filtrer par type(s) d'activité */
599
+ type?: ActivityType[];
600
+ /** Callback appelé pour chaque activité en temps réel */
601
+ onActivity: (item: ActivityItem) => void;
602
+ /** Callback appelé en cas d'erreur */
603
+ onError?: (error: Error) => void;
604
+ /** Callback appelé à la fermeture du flux */
605
+ onClose?: () => void;
606
+ /** Signal d'annulation */
607
+ signal?: AbortSignal;
608
+ }
532
609
  interface RuntimeConfig {
533
610
  fee_rate_bps: number;
534
611
  base_fee: string;
@@ -743,6 +820,59 @@ declare class PmsClient {
743
820
  limit?: number;
744
821
  decryptionWallet?: PmsWallet;
745
822
  }): Promise<WalletHistoryResp>;
823
+ /**
824
+ * Récupère l'activité complète d'un wallet avec classification sémantique.
825
+ *
826
+ * Chaque activité est classifiée (transfer_in, fee_received, nft_mint, freeze, etc.)
827
+ * avec direction, montant et contrepartie.
828
+ *
829
+ * @param address - Adresse du wallet (bech32 ou hex)
830
+ * @param options - Filtres et pagination
831
+ * @returns Activités paginées
832
+ *
833
+ * @example
834
+ * ```typescript
835
+ * // Toute l'activité
836
+ * const activity = await client.getActivity("8eabc...");
837
+ *
838
+ * // Seulement les fees reçues
839
+ * const fees = await client.getActivity("8eabc...", {
840
+ * type: ["fee_received"],
841
+ * limit: 20,
842
+ * });
843
+ *
844
+ * // Pagination
845
+ * const page2 = await client.getActivity("8eabc...", {
846
+ * after_ts: activity.next_after_ts,
847
+ * after_id: activity.next_after_id,
848
+ * });
849
+ * ```
850
+ */
851
+ getActivity(address: string, options?: ActivityOptions): Promise<ActivityResp>;
852
+ /**
853
+ * Écoute l'activité d'un wallet en temps réel via Server-Sent Events (SSE).
854
+ *
855
+ * Retourne une fonction de nettoyage pour fermer la connexion.
856
+ *
857
+ * @param address - Adresse du wallet (bech32 ou hex)
858
+ * @param options - Callbacks et filtres
859
+ * @returns Fonction pour fermer le flux SSE
860
+ *
861
+ * @example
862
+ * ```typescript
863
+ * const stop = client.streamActivity("8eabc...", {
864
+ * type: ["transfer_in", "fee_received"],
865
+ * onActivity: (item) => {
866
+ * console.log(`${item.activity_type}: ${item.amount} ${item.direction}`);
867
+ * },
868
+ * onError: (err) => console.error(err),
869
+ * });
870
+ *
871
+ * // Plus tard: fermer la connexion
872
+ * stop();
873
+ * ```
874
+ */
875
+ streamActivity(address: string, options: StreamActivityOptions): () => void;
746
876
  /**
747
877
  * Récupère la configuration publique du nœud (frais, PoW, recipient, etc.)
748
878
  */
@@ -915,4 +1045,4 @@ declare function formatAmount(sats: bigint): string;
915
1045
  */
916
1046
  declare function decryptPayload(encrypted: EncryptedPayload, recipientPrivateKeyHex: string): string;
917
1047
 
918
- export { type BalanceInfo, type Block, type BurnNftResponse, type CoordinatorInfoResponse, type CubeAttributes, type HistoryItem, type MintCubeResponse, type NftMetadata, type NftResponse, PmsClient, type PmsClientConfig, PmsWallet, type PrepareTxRequest, type PrepareTxResponse, type RuntimeConfig, type SubmitResponse, type SupplyInfo, type TokenMetadata, type Utxo, type UtxoDetail, type WalletHistoryResp, type WalletResponse, decryptPayload, formatAmount, fromHex, isValidMnemonic, parseAmount, toHex };
1048
+ export { type ActivityDirection, type ActivityItem, type ActivityOptions, type ActivityResp, type ActivityType, type BalanceInfo, type Block, type BurnNftResponse, type CoordinatorInfoResponse, type CubeAttributes, type HistoryItem, type MintCubeResponse, type NftMetadata, type NftResponse, PmsClient, type PmsClientConfig, PmsWallet, type PrepareTxRequest, type PrepareTxResponse, type RuntimeConfig, type StreamActivityOptions, type SubmitResponse, type SupplyInfo, type TokenMetadata, type Utxo, type UtxoDetail, type WalletHistoryResp, type WalletResponse, decryptPayload, formatAmount, fromHex, isValidMnemonic, parseAmount, toHex };
package/dist/index.js CHANGED
@@ -592,6 +592,147 @@ var PmsClient = class {
592
592
  return res;
593
593
  }
594
594
  // ═══════════════════════════════════════════════════════════════════════
595
+ // Activité du wallet
596
+ // ═══════════════════════════════════════════════════════════════════════
597
+ /**
598
+ * Récupère l'activité complète d'un wallet avec classification sémantique.
599
+ *
600
+ * Chaque activité est classifiée (transfer_in, fee_received, nft_mint, freeze, etc.)
601
+ * avec direction, montant et contrepartie.
602
+ *
603
+ * @param address - Adresse du wallet (bech32 ou hex)
604
+ * @param options - Filtres et pagination
605
+ * @returns Activités paginées
606
+ *
607
+ * @example
608
+ * ```typescript
609
+ * // Toute l'activité
610
+ * const activity = await client.getActivity("8eabc...");
611
+ *
612
+ * // Seulement les fees reçues
613
+ * const fees = await client.getActivity("8eabc...", {
614
+ * type: ["fee_received"],
615
+ * limit: 20,
616
+ * });
617
+ *
618
+ * // Pagination
619
+ * const page2 = await client.getActivity("8eabc...", {
620
+ * after_ts: activity.next_after_ts,
621
+ * after_id: activity.next_after_id,
622
+ * });
623
+ * ```
624
+ */
625
+ async getActivity(address, options) {
626
+ const params = new URLSearchParams();
627
+ if (options?.type && options.type.length > 0) {
628
+ params.set("type", options.type.join(","));
629
+ }
630
+ if (options?.limit !== void 0) {
631
+ params.set("limit", String(options.limit));
632
+ }
633
+ if (options?.after_ts !== void 0) {
634
+ params.set("after_ts", String(options.after_ts));
635
+ }
636
+ if (options?.after_id !== void 0) {
637
+ params.set("after_id", options.after_id);
638
+ }
639
+ if (options?.asset_id !== void 0) {
640
+ params.set("asset_id", options.asset_id);
641
+ }
642
+ const qs = params.toString();
643
+ const path = `/v1/wallet/${encodeURIComponent(address)}/activity${qs ? `?${qs}` : ""}`;
644
+ return this.fetch(path);
645
+ }
646
+ /**
647
+ * Écoute l'activité d'un wallet en temps réel via Server-Sent Events (SSE).
648
+ *
649
+ * Retourne une fonction de nettoyage pour fermer la connexion.
650
+ *
651
+ * @param address - Adresse du wallet (bech32 ou hex)
652
+ * @param options - Callbacks et filtres
653
+ * @returns Fonction pour fermer le flux SSE
654
+ *
655
+ * @example
656
+ * ```typescript
657
+ * const stop = client.streamActivity("8eabc...", {
658
+ * type: ["transfer_in", "fee_received"],
659
+ * onActivity: (item) => {
660
+ * console.log(`${item.activity_type}: ${item.amount} ${item.direction}`);
661
+ * },
662
+ * onError: (err) => console.error(err),
663
+ * });
664
+ *
665
+ * // Plus tard: fermer la connexion
666
+ * stop();
667
+ * ```
668
+ */
669
+ streamActivity(address, options) {
670
+ const params = new URLSearchParams();
671
+ if (options.type && options.type.length > 0) {
672
+ params.set("type", options.type.join(","));
673
+ }
674
+ const qs = params.toString();
675
+ const path = `/v1/wallet/${encodeURIComponent(address)}/activity/stream${qs ? `?${qs}` : ""}`;
676
+ const url = `${this.config.nodeUrl}${path}`;
677
+ const controller = new AbortController();
678
+ const signal = options.signal ? mergeAbortSignals(options.signal, controller.signal) : controller.signal;
679
+ (async () => {
680
+ try {
681
+ const headers = {
682
+ "Accept": "text/event-stream"
683
+ };
684
+ if (this.config.apiKey) {
685
+ headers["X-API-Key"] = this.config.apiKey;
686
+ }
687
+ const resp = await fetch(url, { headers, signal });
688
+ if (!resp.ok) {
689
+ throw new Error(`SSE connection failed: ${resp.status} ${resp.statusText}`);
690
+ }
691
+ if (!resp.body) {
692
+ throw new Error("SSE response has no body");
693
+ }
694
+ const reader = resp.body.getReader();
695
+ const decoder = new TextDecoder();
696
+ let buffer = "";
697
+ while (true) {
698
+ const { done, value } = await reader.read();
699
+ if (done) break;
700
+ buffer += decoder.decode(value, { stream: true });
701
+ const lines = buffer.split("\n");
702
+ buffer = lines.pop() ?? "";
703
+ let currentEvent = "";
704
+ let currentData = "";
705
+ for (const line of lines) {
706
+ if (line.startsWith("event:")) {
707
+ currentEvent = line.slice(6).trim();
708
+ } else if (line.startsWith("data:")) {
709
+ currentData = line.slice(5).trim();
710
+ } else if (line === "" && currentData) {
711
+ if (currentEvent === "activity" && currentData) {
712
+ try {
713
+ const item = JSON.parse(currentData);
714
+ options.onActivity(item);
715
+ } catch (e) {
716
+ }
717
+ } else if (currentEvent === "warning") {
718
+ }
719
+ currentEvent = "";
720
+ currentData = "";
721
+ }
722
+ }
723
+ }
724
+ options.onClose?.();
725
+ } catch (err) {
726
+ if (err.name === "AbortError") {
727
+ options.onClose?.();
728
+ } else {
729
+ options.onError?.(err instanceof Error ? err : new Error(String(err)));
730
+ }
731
+ }
732
+ })();
733
+ return () => controller.abort();
734
+ }
735
+ // ═══════════════════════════════════════════════════════════════════════
595
736
  // Méthodes d'écriture (POST)
596
737
  // ═══════════════════════════════════════════════════════════════════════
597
738
  /**
@@ -1086,6 +1227,13 @@ var PmsClient = class {
1086
1227
  }
1087
1228
  }
1088
1229
  };
1230
+ function mergeAbortSignals(a, b) {
1231
+ const controller = new AbortController();
1232
+ const onAbort = () => controller.abort();
1233
+ a.addEventListener("abort", onAbort, { once: true });
1234
+ b.addEventListener("abort", onAbort, { once: true });
1235
+ return controller.signal;
1236
+ }
1089
1237
  export {
1090
1238
  PmsClient,
1091
1239
  PmsWallet,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@empereur-rouge/pms-sdk",
3
- "version": "0.3.1",
3
+ "version": "0.3.3",
4
4
  "description": "TypeScript SDK for PMS (Planetary Monetary System) — wallet management, transactions, NFTs, and DAG interactions",
5
5
  "author": "empereur-rouge",
6
6
  "license": "MIT",