@empereur-rouge/pms-sdk 0.3.1 → 0.3.2

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,81 @@ 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
+ /** Payload brut pour détails complets */
564
+ payload: any;
565
+ }
566
+ /** Réponse de l'endpoint GET /v1/wallet/{address}/activity */
567
+ interface ActivityResp {
568
+ /** Adresse du wallet */
569
+ address: string;
570
+ /** Éléments d'activité classifiés */
571
+ items: ActivityItem[];
572
+ /** Nombre d'éléments retournés */
573
+ count: number;
574
+ /** Timestamp cursor pour la pagination (next page) */
575
+ next_after_ts?: number;
576
+ /** Block ID cursor pour la pagination (next page) */
577
+ next_after_id?: string;
578
+ /** Indique s'il y a plus de résultats */
579
+ has_more: boolean;
580
+ }
581
+ /** Options pour getActivity() */
582
+ interface ActivityOptions {
583
+ /** Filtrer par type(s) d'activité (ex: ["fee_received", "transfer_in"]) */
584
+ type?: ActivityType[];
585
+ /** Nombre max d'éléments (défaut: 50, max: 500) */
586
+ limit?: number;
587
+ /** Cursor de pagination: timestamp */
588
+ after_ts?: number;
589
+ /** Cursor de pagination: block ID */
590
+ after_id?: string;
591
+ /** Filtrer par asset ID */
592
+ asset_id?: string;
593
+ }
594
+ /** Options pour streamActivity() */
595
+ interface StreamActivityOptions {
596
+ /** Filtrer par type(s) d'activité */
597
+ type?: ActivityType[];
598
+ /** Callback appelé pour chaque activité en temps réel */
599
+ onActivity: (item: ActivityItem) => void;
600
+ /** Callback appelé en cas d'erreur */
601
+ onError?: (error: Error) => void;
602
+ /** Callback appelé à la fermeture du flux */
603
+ onClose?: () => void;
604
+ /** Signal d'annulation */
605
+ signal?: AbortSignal;
606
+ }
532
607
  interface RuntimeConfig {
533
608
  fee_rate_bps: number;
534
609
  base_fee: string;
@@ -743,6 +818,59 @@ declare class PmsClient {
743
818
  limit?: number;
744
819
  decryptionWallet?: PmsWallet;
745
820
  }): Promise<WalletHistoryResp>;
821
+ /**
822
+ * Récupère l'activité complète d'un wallet avec classification sémantique.
823
+ *
824
+ * Chaque activité est classifiée (transfer_in, fee_received, nft_mint, freeze, etc.)
825
+ * avec direction, montant et contrepartie.
826
+ *
827
+ * @param address - Adresse du wallet (bech32 ou hex)
828
+ * @param options - Filtres et pagination
829
+ * @returns Activités paginées
830
+ *
831
+ * @example
832
+ * ```typescript
833
+ * // Toute l'activité
834
+ * const activity = await client.getActivity("8eabc...");
835
+ *
836
+ * // Seulement les fees reçues
837
+ * const fees = await client.getActivity("8eabc...", {
838
+ * type: ["fee_received"],
839
+ * limit: 20,
840
+ * });
841
+ *
842
+ * // Pagination
843
+ * const page2 = await client.getActivity("8eabc...", {
844
+ * after_ts: activity.next_after_ts,
845
+ * after_id: activity.next_after_id,
846
+ * });
847
+ * ```
848
+ */
849
+ getActivity(address: string, options?: ActivityOptions): Promise<ActivityResp>;
850
+ /**
851
+ * Écoute l'activité d'un wallet en temps réel via Server-Sent Events (SSE).
852
+ *
853
+ * Retourne une fonction de nettoyage pour fermer la connexion.
854
+ *
855
+ * @param address - Adresse du wallet (bech32 ou hex)
856
+ * @param options - Callbacks et filtres
857
+ * @returns Fonction pour fermer le flux SSE
858
+ *
859
+ * @example
860
+ * ```typescript
861
+ * const stop = client.streamActivity("8eabc...", {
862
+ * type: ["transfer_in", "fee_received"],
863
+ * onActivity: (item) => {
864
+ * console.log(`${item.activity_type}: ${item.amount} ${item.direction}`);
865
+ * },
866
+ * onError: (err) => console.error(err),
867
+ * });
868
+ *
869
+ * // Plus tard: fermer la connexion
870
+ * stop();
871
+ * ```
872
+ */
873
+ streamActivity(address: string, options: StreamActivityOptions): () => void;
746
874
  /**
747
875
  * Récupère la configuration publique du nœud (frais, PoW, recipient, etc.)
748
876
  */
@@ -915,4 +1043,4 @@ declare function formatAmount(sats: bigint): string;
915
1043
  */
916
1044
  declare function decryptPayload(encrypted: EncryptedPayload, recipientPrivateKeyHex: string): string;
917
1045
 
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 };
1046
+ 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,81 @@ 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
+ /** Payload brut pour détails complets */
564
+ payload: any;
565
+ }
566
+ /** Réponse de l'endpoint GET /v1/wallet/{address}/activity */
567
+ interface ActivityResp {
568
+ /** Adresse du wallet */
569
+ address: string;
570
+ /** Éléments d'activité classifiés */
571
+ items: ActivityItem[];
572
+ /** Nombre d'éléments retournés */
573
+ count: number;
574
+ /** Timestamp cursor pour la pagination (next page) */
575
+ next_after_ts?: number;
576
+ /** Block ID cursor pour la pagination (next page) */
577
+ next_after_id?: string;
578
+ /** Indique s'il y a plus de résultats */
579
+ has_more: boolean;
580
+ }
581
+ /** Options pour getActivity() */
582
+ interface ActivityOptions {
583
+ /** Filtrer par type(s) d'activité (ex: ["fee_received", "transfer_in"]) */
584
+ type?: ActivityType[];
585
+ /** Nombre max d'éléments (défaut: 50, max: 500) */
586
+ limit?: number;
587
+ /** Cursor de pagination: timestamp */
588
+ after_ts?: number;
589
+ /** Cursor de pagination: block ID */
590
+ after_id?: string;
591
+ /** Filtrer par asset ID */
592
+ asset_id?: string;
593
+ }
594
+ /** Options pour streamActivity() */
595
+ interface StreamActivityOptions {
596
+ /** Filtrer par type(s) d'activité */
597
+ type?: ActivityType[];
598
+ /** Callback appelé pour chaque activité en temps réel */
599
+ onActivity: (item: ActivityItem) => void;
600
+ /** Callback appelé en cas d'erreur */
601
+ onError?: (error: Error) => void;
602
+ /** Callback appelé à la fermeture du flux */
603
+ onClose?: () => void;
604
+ /** Signal d'annulation */
605
+ signal?: AbortSignal;
606
+ }
532
607
  interface RuntimeConfig {
533
608
  fee_rate_bps: number;
534
609
  base_fee: string;
@@ -743,6 +818,59 @@ declare class PmsClient {
743
818
  limit?: number;
744
819
  decryptionWallet?: PmsWallet;
745
820
  }): Promise<WalletHistoryResp>;
821
+ /**
822
+ * Récupère l'activité complète d'un wallet avec classification sémantique.
823
+ *
824
+ * Chaque activité est classifiée (transfer_in, fee_received, nft_mint, freeze, etc.)
825
+ * avec direction, montant et contrepartie.
826
+ *
827
+ * @param address - Adresse du wallet (bech32 ou hex)
828
+ * @param options - Filtres et pagination
829
+ * @returns Activités paginées
830
+ *
831
+ * @example
832
+ * ```typescript
833
+ * // Toute l'activité
834
+ * const activity = await client.getActivity("8eabc...");
835
+ *
836
+ * // Seulement les fees reçues
837
+ * const fees = await client.getActivity("8eabc...", {
838
+ * type: ["fee_received"],
839
+ * limit: 20,
840
+ * });
841
+ *
842
+ * // Pagination
843
+ * const page2 = await client.getActivity("8eabc...", {
844
+ * after_ts: activity.next_after_ts,
845
+ * after_id: activity.next_after_id,
846
+ * });
847
+ * ```
848
+ */
849
+ getActivity(address: string, options?: ActivityOptions): Promise<ActivityResp>;
850
+ /**
851
+ * Écoute l'activité d'un wallet en temps réel via Server-Sent Events (SSE).
852
+ *
853
+ * Retourne une fonction de nettoyage pour fermer la connexion.
854
+ *
855
+ * @param address - Adresse du wallet (bech32 ou hex)
856
+ * @param options - Callbacks et filtres
857
+ * @returns Fonction pour fermer le flux SSE
858
+ *
859
+ * @example
860
+ * ```typescript
861
+ * const stop = client.streamActivity("8eabc...", {
862
+ * type: ["transfer_in", "fee_received"],
863
+ * onActivity: (item) => {
864
+ * console.log(`${item.activity_type}: ${item.amount} ${item.direction}`);
865
+ * },
866
+ * onError: (err) => console.error(err),
867
+ * });
868
+ *
869
+ * // Plus tard: fermer la connexion
870
+ * stop();
871
+ * ```
872
+ */
873
+ streamActivity(address: string, options: StreamActivityOptions): () => void;
746
874
  /**
747
875
  * Récupère la configuration publique du nœud (frais, PoW, recipient, etc.)
748
876
  */
@@ -915,4 +1043,4 @@ declare function formatAmount(sats: bigint): string;
915
1043
  */
916
1044
  declare function decryptPayload(encrypted: EncryptedPayload, recipientPrivateKeyHex: string): string;
917
1045
 
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 };
1046
+ 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.2",
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",