@accesly/react 1.1.3 → 1.2.0

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.cts CHANGED
@@ -1,4 +1,4 @@
1
- import { Environment, CognitoConfig, AuthClient, SessionStorage, DeviceStore, TelemetrySink, TokenManager, AccesslyEndpoints, AuthStatus, CredentialRecord, EncryptedEnvelope, WalletActivityEvent } from '@accesly/core';
1
+ import { Environment, CognitoConfig, AuthClient, SessionStorage, DeviceStore, TelemetrySink, TokenManager, AccesslyEndpoints, AuthStatus, CredentialRecord, EncryptedEnvelope } from '@accesly/core';
2
2
  import * as react from 'react';
3
3
  import { ReactNode } from 'react';
4
4
 
@@ -60,6 +60,13 @@ declare const AcceslyContext: react.Context<AcceslyContextValue | null>;
60
60
 
61
61
  interface EnvironmentDefaults {
62
62
  readonly apiUrl: string;
63
+ /**
64
+ * Lambda Function URL del `wallet-stream` Lambda — Server-Sent Events
65
+ * que multiplexa status + balance + activity en una sola conexión.
66
+ * Si está vacío, los hooks `useBalance` / `useWalletActivity` /
67
+ * `useWalletStatus` caen al polling fallback (mucho menos eficiente).
68
+ */
69
+ readonly walletStreamUrl: string;
63
70
  readonly cognito: CognitoConfig;
64
71
  readonly stellar: {
65
72
  readonly networkPassphrase: string;
@@ -650,101 +657,151 @@ interface AcceslyHook {
650
657
  declare function useAccesly(): AcceslyHook;
651
658
 
652
659
  /**
653
- * `useWalletStatus()` — hook event-driven que sustituye al
654
- * `setInterval(fetchRemote, 30_000)` que cada integrador escribía en su
655
- * `Wallet.tsx` / `CreateWallet.tsx`.
656
- *
657
- * Comportamiento:
658
- *
659
- * 1. **SSE-first.** Si la infra del backend expone `GET /wallets/stream`
660
- * (Lambda function URL con response streaming), el hook se suscribe vía
661
- * `EventSource` y reacciona instantáneamente a cambios on-chain. Cero
662
- * polling, cero latencia.
660
+ * `useWalletStatus()` — status on-chain del Smart Account del user actual con
661
+ * push real-time vía SSE.
663
662
  *
664
- * 2. **Polling con backoff inteligente como fallback.** Si SSE no está
665
- * disponible (backend viejo, sandbox sin streaming, browser sin
666
- * `EventSource`), cae a polling con backoff exponencial:
667
- * - mientras la wallet NO está `'on-chain'`: 2s → 5s → 10s → 20s →
668
- * 30s (cap).
669
- * - si llega `'on-chain'` o el tab queda oculto: polling pausado.
670
- * - llamadas de `refresh()` resetean el backoff a 2s.
671
- * Mucho mejor UX que el `30s` constante del legacy.
663
+ * Reemplaza el polling cada 30s del legacy. Comportamiento:
672
664
  *
673
- * 3. **`document.visibilityState` aware.** Pausa cuando el tab está oculto;
674
- * retoma + refresca inmediatamente cuando vuelve a visible.
665
+ * 1. SSE-first: si `walletStreamUrl` está configurado y `EventSource` existe,
666
+ * se suscribe al canal `status` del `wallet-stream` Lambda. Cero polling.
667
+ * 2. Fallback a polling backoff (1s → 30s) si SSE no está disponible.
668
+ * 3. Pausa cuando `document.hidden`, retoma al volver.
669
+ * 4. `refresh()` fuerza fetch HTTP inmediato.
675
670
  *
676
- * 4. **Cross-tab via `BroadcastChannel`.** Si el user tiene la app abierta
677
- * en 2 tabs, el primero que reciba un update lo emite por el canal
678
- * `accesly:wallet:<username>` y los otros tabs lo aplican sin hacer su
679
- * propio fetch — un solo round-trip por update.
680
- *
681
- * Devuelve `{ status, walletAddress, onChain, isStale, refresh }`. `refresh()`
682
- * fuerza un fetch inmediato + resetea backoff. `isStale` = `true` si no se ha
683
- * podido confirmar status en > 60s (red/Soroban RPC caído).
671
+ * El status del Smart Account vive en DDB (lo que el backend reporta de su
672
+ * verificación contra Soroban). El backend push-ea cambios cuando los detecta
673
+ * (cada 5s en el loop del wallet-stream).
684
674
  */
685
675
  type WalletStatusValue = 'on-chain' | 'pending-deploy' | 'unknown' | 'no-wallet';
686
676
  interface UseWalletStatusResult {
687
- /** Status actual. `'no-wallet'` si el backend nunca recibió un POST /wallets. */
688
677
  readonly status: WalletStatusValue;
689
- /** Address C…, o null si no hay wallet. */
690
678
  readonly walletAddress: string | null;
691
- /** Mirror del campo `onChain` del backend (true / false / null). */
692
679
  readonly onChain: boolean | null;
693
- /** True si el último fetch exitoso fue hace más de 60s — UI puede mostrar warning. */
694
680
  readonly isStale: boolean;
695
- /** Fuerza fetch inmediato + resetea backoff. Llamalo tras submit/recovery. */
696
681
  refresh(): Promise<void>;
697
682
  }
698
683
  declare function useWalletStatus(): UseWalletStatusResult;
699
684
 
700
685
  /**
701
- * `useBalance(walletAddress?)` — hook que devuelve el balance XLM del Smart
702
- * Account con auto-refresh.
686
+ * `useBalance(walletAddress?)` — devuelve el balance XLM del Smart Account
687
+ * con push real-time vía SSE.
688
+ *
689
+ * Si SSE está configurado (env tiene `walletStreamUrl` y `EventSource` existe),
690
+ * el hook se suscribe al canal `balance` del `wallet-stream` Lambda y se
691
+ * actualiza instantáneamente cuando cambia el balance on-chain.
703
692
  *
704
- * Si no se le pasa `walletAddress`, intenta auto-resolverlo via
705
- * `wallet.getStoredCredential(username)` del DeviceStore el flujo más
706
- * común (un solo wallet por user en este device).
693
+ * Fallback automático a polling cada 10s si SSE no está disponible (entorno
694
+ * que no lo soporta o backend self-hosteado sin el endpoint).
707
695
  *
708
- * Polling: 8s mientras tab visible, pausa cuando hidden, retoma al volver.
709
- * También se refresca inmediatamente cuando `useWalletStatus` reporta
710
- * `'on-chain'` (via cross-tab `BroadcastChannel`) para mostrar el balance
711
- * tras un deploy fresco.
696
+ * El `walletAddress` se auto-resuelve desde el `DeviceStore` si no se pasa
697
+ * (cubrir el caso "wallet del user actual sin tener que pasarla a mano").
712
698
  */
713
699
  interface UseBalanceResult {
714
700
  /** Stroops como string base-10. `null` mientras se carga o no hay address. */
715
701
  readonly stroops: string | null;
716
702
  /** Mismo balance como string decimal en XLM. `null` mientras se carga. */
717
703
  readonly xlm: string | null;
718
- /** True durante el primer fetch (subsiguientes ediciones son silent). */
719
704
  readonly isLoading: boolean;
720
- /** Error del último fetch, si lo hubo. */
721
705
  readonly error: Error | null;
722
- /** Fuerza fetch inmediato. */
706
+ /** Fuerza fetch HTTP inmediato (útil tras una operación del user). */
723
707
  refresh(): Promise<void>;
724
708
  }
725
709
  declare function useBalance(walletAddress?: string | null): UseBalanceResult;
726
710
 
727
711
  /**
728
- * `useWalletActivity(walletAddress?, opts?)` — hook que devuelve los últimos
729
- * eventos on-chain del Smart Account, auto-refrescados cada 20s mientras la
730
- * tab está visible.
712
+ * `WalletSubscription` — singleton manager por wallet address que abre UNA
713
+ * sola conexión `EventSource` al `wallet-stream` Lambda y desmultiplexa los
714
+ * eventos a múltiples subscribers (hooks).
715
+ *
716
+ * Beneficios:
717
+ * - 3 hooks (`useBalance`, `useWalletActivity`, `useWalletStatus`) sobre la
718
+ * misma wallet → 1 sola conexión TCP, no 3 polls separados.
719
+ * - Auto-reconnect cuando el server cierra (default de EventSource — `retry:`).
720
+ * - Ref-count: la conexión se abre con el primer subscriber y se cierra
721
+ * cuando no quedan listeners (`useEffect` cleanup en cada hook).
722
+ * - Eventos cacheados: el último valor recibido de cada tipo se replay-ea
723
+ * a nuevos subscribers para que no esperen el próximo push.
724
+ *
725
+ * Sin SSE configurado (`walletStreamUrl` vacío) o cuando `EventSource` no
726
+ * existe (SSR / workers), los hooks individuales detectan el flag
727
+ * `unavailable` y caen al polling fallback que ya existe.
728
+ */
729
+ type WalletStreamEventType = 'status' | 'balance' | 'activity';
730
+ interface WalletStreamStatusPayload {
731
+ readonly walletAddress: string | null;
732
+ readonly onChain: boolean | null;
733
+ }
734
+ interface WalletStreamBalancePayload {
735
+ readonly stroops: string;
736
+ readonly xlm: string;
737
+ }
738
+ /**
739
+ * Activity emitida por el backend ya **filtrada y tipada** — solo eventos
740
+ * relevantes para una wallet de Accesly (rotación de signers + transfers
741
+ * IN/OUT de XLM). Otros eventos on-chain (debug, errores host, eventos
742
+ * irrelevantes) se descartan en el server.
743
+ */
744
+ type WalletActivityItem = {
745
+ readonly type: 'signer-rotated';
746
+ readonly txHash: string;
747
+ readonly ledger: number;
748
+ readonly timestamp: string | null;
749
+ readonly newOwnerEd25519Hex: string;
750
+ } | {
751
+ readonly type: 'transfer-in';
752
+ readonly txHash: string;
753
+ readonly ledger: number;
754
+ readonly timestamp: string | null;
755
+ readonly from: string;
756
+ readonly amountStroops: string;
757
+ } | {
758
+ readonly type: 'transfer-out';
759
+ readonly txHash: string;
760
+ readonly ledger: number;
761
+ readonly timestamp: string | null;
762
+ readonly to: string;
763
+ readonly amountStroops: string;
764
+ };
765
+ interface WalletStreamActivityPayload {
766
+ readonly events: readonly WalletActivityItem[];
767
+ }
768
+ type Listener<T> = (payload: T) => void;
769
+ /**
770
+ * Suscribirse a un tipo de evento de la wallet. Devuelve una función
771
+ * de cleanup que el caller (típicamente `useEffect`) debe llamar para
772
+ * desuscribir y, eventualmente, cerrar la conexión SSE.
773
+ *
774
+ * Si SSE no está disponible (URL vacía, EventSource undefined), devuelve
775
+ * `null` para indicar al caller que use el fallback de polling.
776
+ */
777
+ declare function subscribeToWalletEvent<T extends WalletStreamEventType>(streamUrl: string, walletAddress: string, eventType: T, listener: T extends 'status' ? Listener<WalletStreamStatusPayload> : T extends 'balance' ? Listener<WalletStreamBalancePayload> : Listener<WalletStreamActivityPayload>): (() => void) | null;
778
+ /**
779
+ * Cierra TODAS las conexiones SSE activas. Útil para tests o cuando el user
780
+ * cierra sesión y querés limpiar conexiones colgadas. Llamar en `auth.signOut`
781
+ * lo tienen pendiente como mejora — por ahora el cleanup natural de los
782
+ * unmount basta.
783
+ */
784
+ declare function closeAllWalletSubscriptions(): void;
785
+
786
+ /**
787
+ * `useWalletActivity(walletAddress?, opts?)` — actividad on-chain relevante de
788
+ * la wallet (rotate_signer + transfers in/out de XLM) con push real-time vía SSE.
731
789
  *
732
- * Pasos:
733
- * 1. Resuelve `walletAddress` desde el DeviceStore si no se pasa explícito.
734
- * 2. Fetch inicial inmediato guarda en estado.
735
- * 3. Polling cada 20s (pausado si tab oculta).
736
- * 4. `refresh()` para fetch on-demand tras una operación del user.
790
+ * El backend YA filtra eventos irrelevantes — el integrador solo recibe
791
+ * `WalletActivityItem` tipados (`signer-rotated` | `transfer-in` | `transfer-out`).
792
+ * Sin parsing manual de XDR ni lógica de filtrado client-side.
737
793
  *
738
- * Mejor UX que el "ver explorer link" porque la app puede renderizar la
739
- * lista de tx en su propio look — sin abrir otro tab a Stellar Expert.
794
+ * Fallback: si SSE no está disponible, polling cada 25s al endpoint
795
+ * `/wallets/:address/activity`. Mucho menos eficiente pero garantiza data.
740
796
  */
741
797
 
742
798
  interface UseWalletActivityOptions {
743
- /** Cantidad de eventos a pedir. Default 20, max 50. */
799
+ /** Cantidad de eventos a mostrar (cap del buffer del cliente). Default 20. */
744
800
  readonly limit?: number;
745
801
  }
746
802
  interface UseWalletActivityResult {
747
- readonly events: readonly WalletActivityEvent[];
803
+ /** Eventos tipados, más recientes primero. */
804
+ readonly events: readonly WalletActivityItem[];
748
805
  readonly isLoading: boolean;
749
806
  readonly error: Error | null;
750
807
  refresh(): Promise<void>;
@@ -775,4 +832,4 @@ declare function useWalletActivity(walletAddress?: string | null, opts?: UseWall
775
832
  */
776
833
  declare const REACT_ADAPTER_VERSION = "0.0.0";
777
834
 
778
- export { AcceslyContext, type AcceslyContextValue, type AcceslyHook, AcceslyProvider, type AcceslyProviderProps, type AuthNamespace, type BootstrapWalletInput, type CreateWalletInput, type CreatedWalletInfo, ENVIRONMENT_DEFAULTS, type EnsureWalletResult, type EnvironmentDefaults, type FinalizeRecoveryInput, type FinalizeRecoveryResult, type KycNamespace, NotImplementedYetError, REACT_ADAPTER_VERSION, type ReconstructedSeed, type RecoveryNamespace, type RemoteWalletInfo, type RetryDeployResult, type SendXlmInput, type SendXlmResult, type SessionNamespace, type SettingsNamespace, type TxNamespace, type UnlockedSigningMaterial, type UseBalanceResult, type UseWalletActivityOptions, type UseWalletActivityResult, type UseWalletStatusResult, type WalletNamespace, type WalletStatus, type WalletStatusValue, type YieldNamespace, useAccesly, useBalance, useWalletActivity, useWalletStatus };
835
+ export { AcceslyContext, type AcceslyContextValue, type AcceslyHook, AcceslyProvider, type AcceslyProviderProps, type AuthNamespace, type BootstrapWalletInput, type CreateWalletInput, type CreatedWalletInfo, ENVIRONMENT_DEFAULTS, type EnsureWalletResult, type EnvironmentDefaults, type FinalizeRecoveryInput, type FinalizeRecoveryResult, type KycNamespace, NotImplementedYetError, REACT_ADAPTER_VERSION, type ReconstructedSeed, type RecoveryNamespace, type RemoteWalletInfo, type RetryDeployResult, type SendXlmInput, type SendXlmResult, type SessionNamespace, type SettingsNamespace, type TxNamespace, type UnlockedSigningMaterial, type UseBalanceResult, type UseWalletActivityOptions, type UseWalletActivityResult, type UseWalletStatusResult, type WalletActivityItem, type WalletNamespace, type WalletStatus, type WalletStatusValue, type WalletStreamActivityPayload, type WalletStreamBalancePayload, type WalletStreamEventType, type WalletStreamStatusPayload, type YieldNamespace, closeAllWalletSubscriptions, subscribeToWalletEvent, useAccesly, useBalance, useWalletActivity, useWalletStatus };
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { Environment, CognitoConfig, AuthClient, SessionStorage, DeviceStore, TelemetrySink, TokenManager, AccesslyEndpoints, AuthStatus, CredentialRecord, EncryptedEnvelope, WalletActivityEvent } from '@accesly/core';
1
+ import { Environment, CognitoConfig, AuthClient, SessionStorage, DeviceStore, TelemetrySink, TokenManager, AccesslyEndpoints, AuthStatus, CredentialRecord, EncryptedEnvelope } from '@accesly/core';
2
2
  import * as react from 'react';
3
3
  import { ReactNode } from 'react';
4
4
 
@@ -60,6 +60,13 @@ declare const AcceslyContext: react.Context<AcceslyContextValue | null>;
60
60
 
61
61
  interface EnvironmentDefaults {
62
62
  readonly apiUrl: string;
63
+ /**
64
+ * Lambda Function URL del `wallet-stream` Lambda — Server-Sent Events
65
+ * que multiplexa status + balance + activity en una sola conexión.
66
+ * Si está vacío, los hooks `useBalance` / `useWalletActivity` /
67
+ * `useWalletStatus` caen al polling fallback (mucho menos eficiente).
68
+ */
69
+ readonly walletStreamUrl: string;
63
70
  readonly cognito: CognitoConfig;
64
71
  readonly stellar: {
65
72
  readonly networkPassphrase: string;
@@ -650,101 +657,151 @@ interface AcceslyHook {
650
657
  declare function useAccesly(): AcceslyHook;
651
658
 
652
659
  /**
653
- * `useWalletStatus()` — hook event-driven que sustituye al
654
- * `setInterval(fetchRemote, 30_000)` que cada integrador escribía en su
655
- * `Wallet.tsx` / `CreateWallet.tsx`.
656
- *
657
- * Comportamiento:
658
- *
659
- * 1. **SSE-first.** Si la infra del backend expone `GET /wallets/stream`
660
- * (Lambda function URL con response streaming), el hook se suscribe vía
661
- * `EventSource` y reacciona instantáneamente a cambios on-chain. Cero
662
- * polling, cero latencia.
660
+ * `useWalletStatus()` — status on-chain del Smart Account del user actual con
661
+ * push real-time vía SSE.
663
662
  *
664
- * 2. **Polling con backoff inteligente como fallback.** Si SSE no está
665
- * disponible (backend viejo, sandbox sin streaming, browser sin
666
- * `EventSource`), cae a polling con backoff exponencial:
667
- * - mientras la wallet NO está `'on-chain'`: 2s → 5s → 10s → 20s →
668
- * 30s (cap).
669
- * - si llega `'on-chain'` o el tab queda oculto: polling pausado.
670
- * - llamadas de `refresh()` resetean el backoff a 2s.
671
- * Mucho mejor UX que el `30s` constante del legacy.
663
+ * Reemplaza el polling cada 30s del legacy. Comportamiento:
672
664
  *
673
- * 3. **`document.visibilityState` aware.** Pausa cuando el tab está oculto;
674
- * retoma + refresca inmediatamente cuando vuelve a visible.
665
+ * 1. SSE-first: si `walletStreamUrl` está configurado y `EventSource` existe,
666
+ * se suscribe al canal `status` del `wallet-stream` Lambda. Cero polling.
667
+ * 2. Fallback a polling backoff (1s → 30s) si SSE no está disponible.
668
+ * 3. Pausa cuando `document.hidden`, retoma al volver.
669
+ * 4. `refresh()` fuerza fetch HTTP inmediato.
675
670
  *
676
- * 4. **Cross-tab via `BroadcastChannel`.** Si el user tiene la app abierta
677
- * en 2 tabs, el primero que reciba un update lo emite por el canal
678
- * `accesly:wallet:<username>` y los otros tabs lo aplican sin hacer su
679
- * propio fetch — un solo round-trip por update.
680
- *
681
- * Devuelve `{ status, walletAddress, onChain, isStale, refresh }`. `refresh()`
682
- * fuerza un fetch inmediato + resetea backoff. `isStale` = `true` si no se ha
683
- * podido confirmar status en > 60s (red/Soroban RPC caído).
671
+ * El status del Smart Account vive en DDB (lo que el backend reporta de su
672
+ * verificación contra Soroban). El backend push-ea cambios cuando los detecta
673
+ * (cada 5s en el loop del wallet-stream).
684
674
  */
685
675
  type WalletStatusValue = 'on-chain' | 'pending-deploy' | 'unknown' | 'no-wallet';
686
676
  interface UseWalletStatusResult {
687
- /** Status actual. `'no-wallet'` si el backend nunca recibió un POST /wallets. */
688
677
  readonly status: WalletStatusValue;
689
- /** Address C…, o null si no hay wallet. */
690
678
  readonly walletAddress: string | null;
691
- /** Mirror del campo `onChain` del backend (true / false / null). */
692
679
  readonly onChain: boolean | null;
693
- /** True si el último fetch exitoso fue hace más de 60s — UI puede mostrar warning. */
694
680
  readonly isStale: boolean;
695
- /** Fuerza fetch inmediato + resetea backoff. Llamalo tras submit/recovery. */
696
681
  refresh(): Promise<void>;
697
682
  }
698
683
  declare function useWalletStatus(): UseWalletStatusResult;
699
684
 
700
685
  /**
701
- * `useBalance(walletAddress?)` — hook que devuelve el balance XLM del Smart
702
- * Account con auto-refresh.
686
+ * `useBalance(walletAddress?)` — devuelve el balance XLM del Smart Account
687
+ * con push real-time vía SSE.
688
+ *
689
+ * Si SSE está configurado (env tiene `walletStreamUrl` y `EventSource` existe),
690
+ * el hook se suscribe al canal `balance` del `wallet-stream` Lambda y se
691
+ * actualiza instantáneamente cuando cambia el balance on-chain.
703
692
  *
704
- * Si no se le pasa `walletAddress`, intenta auto-resolverlo via
705
- * `wallet.getStoredCredential(username)` del DeviceStore el flujo más
706
- * común (un solo wallet por user en este device).
693
+ * Fallback automático a polling cada 10s si SSE no está disponible (entorno
694
+ * que no lo soporta o backend self-hosteado sin el endpoint).
707
695
  *
708
- * Polling: 8s mientras tab visible, pausa cuando hidden, retoma al volver.
709
- * También se refresca inmediatamente cuando `useWalletStatus` reporta
710
- * `'on-chain'` (via cross-tab `BroadcastChannel`) para mostrar el balance
711
- * tras un deploy fresco.
696
+ * El `walletAddress` se auto-resuelve desde el `DeviceStore` si no se pasa
697
+ * (cubrir el caso "wallet del user actual sin tener que pasarla a mano").
712
698
  */
713
699
  interface UseBalanceResult {
714
700
  /** Stroops como string base-10. `null` mientras se carga o no hay address. */
715
701
  readonly stroops: string | null;
716
702
  /** Mismo balance como string decimal en XLM. `null` mientras se carga. */
717
703
  readonly xlm: string | null;
718
- /** True durante el primer fetch (subsiguientes ediciones son silent). */
719
704
  readonly isLoading: boolean;
720
- /** Error del último fetch, si lo hubo. */
721
705
  readonly error: Error | null;
722
- /** Fuerza fetch inmediato. */
706
+ /** Fuerza fetch HTTP inmediato (útil tras una operación del user). */
723
707
  refresh(): Promise<void>;
724
708
  }
725
709
  declare function useBalance(walletAddress?: string | null): UseBalanceResult;
726
710
 
727
711
  /**
728
- * `useWalletActivity(walletAddress?, opts?)` — hook que devuelve los últimos
729
- * eventos on-chain del Smart Account, auto-refrescados cada 20s mientras la
730
- * tab está visible.
712
+ * `WalletSubscription` — singleton manager por wallet address que abre UNA
713
+ * sola conexión `EventSource` al `wallet-stream` Lambda y desmultiplexa los
714
+ * eventos a múltiples subscribers (hooks).
715
+ *
716
+ * Beneficios:
717
+ * - 3 hooks (`useBalance`, `useWalletActivity`, `useWalletStatus`) sobre la
718
+ * misma wallet → 1 sola conexión TCP, no 3 polls separados.
719
+ * - Auto-reconnect cuando el server cierra (default de EventSource — `retry:`).
720
+ * - Ref-count: la conexión se abre con el primer subscriber y se cierra
721
+ * cuando no quedan listeners (`useEffect` cleanup en cada hook).
722
+ * - Eventos cacheados: el último valor recibido de cada tipo se replay-ea
723
+ * a nuevos subscribers para que no esperen el próximo push.
724
+ *
725
+ * Sin SSE configurado (`walletStreamUrl` vacío) o cuando `EventSource` no
726
+ * existe (SSR / workers), los hooks individuales detectan el flag
727
+ * `unavailable` y caen al polling fallback que ya existe.
728
+ */
729
+ type WalletStreamEventType = 'status' | 'balance' | 'activity';
730
+ interface WalletStreamStatusPayload {
731
+ readonly walletAddress: string | null;
732
+ readonly onChain: boolean | null;
733
+ }
734
+ interface WalletStreamBalancePayload {
735
+ readonly stroops: string;
736
+ readonly xlm: string;
737
+ }
738
+ /**
739
+ * Activity emitida por el backend ya **filtrada y tipada** — solo eventos
740
+ * relevantes para una wallet de Accesly (rotación de signers + transfers
741
+ * IN/OUT de XLM). Otros eventos on-chain (debug, errores host, eventos
742
+ * irrelevantes) se descartan en el server.
743
+ */
744
+ type WalletActivityItem = {
745
+ readonly type: 'signer-rotated';
746
+ readonly txHash: string;
747
+ readonly ledger: number;
748
+ readonly timestamp: string | null;
749
+ readonly newOwnerEd25519Hex: string;
750
+ } | {
751
+ readonly type: 'transfer-in';
752
+ readonly txHash: string;
753
+ readonly ledger: number;
754
+ readonly timestamp: string | null;
755
+ readonly from: string;
756
+ readonly amountStroops: string;
757
+ } | {
758
+ readonly type: 'transfer-out';
759
+ readonly txHash: string;
760
+ readonly ledger: number;
761
+ readonly timestamp: string | null;
762
+ readonly to: string;
763
+ readonly amountStroops: string;
764
+ };
765
+ interface WalletStreamActivityPayload {
766
+ readonly events: readonly WalletActivityItem[];
767
+ }
768
+ type Listener<T> = (payload: T) => void;
769
+ /**
770
+ * Suscribirse a un tipo de evento de la wallet. Devuelve una función
771
+ * de cleanup que el caller (típicamente `useEffect`) debe llamar para
772
+ * desuscribir y, eventualmente, cerrar la conexión SSE.
773
+ *
774
+ * Si SSE no está disponible (URL vacía, EventSource undefined), devuelve
775
+ * `null` para indicar al caller que use el fallback de polling.
776
+ */
777
+ declare function subscribeToWalletEvent<T extends WalletStreamEventType>(streamUrl: string, walletAddress: string, eventType: T, listener: T extends 'status' ? Listener<WalletStreamStatusPayload> : T extends 'balance' ? Listener<WalletStreamBalancePayload> : Listener<WalletStreamActivityPayload>): (() => void) | null;
778
+ /**
779
+ * Cierra TODAS las conexiones SSE activas. Útil para tests o cuando el user
780
+ * cierra sesión y querés limpiar conexiones colgadas. Llamar en `auth.signOut`
781
+ * lo tienen pendiente como mejora — por ahora el cleanup natural de los
782
+ * unmount basta.
783
+ */
784
+ declare function closeAllWalletSubscriptions(): void;
785
+
786
+ /**
787
+ * `useWalletActivity(walletAddress?, opts?)` — actividad on-chain relevante de
788
+ * la wallet (rotate_signer + transfers in/out de XLM) con push real-time vía SSE.
731
789
  *
732
- * Pasos:
733
- * 1. Resuelve `walletAddress` desde el DeviceStore si no se pasa explícito.
734
- * 2. Fetch inicial inmediato guarda en estado.
735
- * 3. Polling cada 20s (pausado si tab oculta).
736
- * 4. `refresh()` para fetch on-demand tras una operación del user.
790
+ * El backend YA filtra eventos irrelevantes — el integrador solo recibe
791
+ * `WalletActivityItem` tipados (`signer-rotated` | `transfer-in` | `transfer-out`).
792
+ * Sin parsing manual de XDR ni lógica de filtrado client-side.
737
793
  *
738
- * Mejor UX que el "ver explorer link" porque la app puede renderizar la
739
- * lista de tx en su propio look — sin abrir otro tab a Stellar Expert.
794
+ * Fallback: si SSE no está disponible, polling cada 25s al endpoint
795
+ * `/wallets/:address/activity`. Mucho menos eficiente pero garantiza data.
740
796
  */
741
797
 
742
798
  interface UseWalletActivityOptions {
743
- /** Cantidad de eventos a pedir. Default 20, max 50. */
799
+ /** Cantidad de eventos a mostrar (cap del buffer del cliente). Default 20. */
744
800
  readonly limit?: number;
745
801
  }
746
802
  interface UseWalletActivityResult {
747
- readonly events: readonly WalletActivityEvent[];
803
+ /** Eventos tipados, más recientes primero. */
804
+ readonly events: readonly WalletActivityItem[];
748
805
  readonly isLoading: boolean;
749
806
  readonly error: Error | null;
750
807
  refresh(): Promise<void>;
@@ -775,4 +832,4 @@ declare function useWalletActivity(walletAddress?: string | null, opts?: UseWall
775
832
  */
776
833
  declare const REACT_ADAPTER_VERSION = "0.0.0";
777
834
 
778
- export { AcceslyContext, type AcceslyContextValue, type AcceslyHook, AcceslyProvider, type AcceslyProviderProps, type AuthNamespace, type BootstrapWalletInput, type CreateWalletInput, type CreatedWalletInfo, ENVIRONMENT_DEFAULTS, type EnsureWalletResult, type EnvironmentDefaults, type FinalizeRecoveryInput, type FinalizeRecoveryResult, type KycNamespace, NotImplementedYetError, REACT_ADAPTER_VERSION, type ReconstructedSeed, type RecoveryNamespace, type RemoteWalletInfo, type RetryDeployResult, type SendXlmInput, type SendXlmResult, type SessionNamespace, type SettingsNamespace, type TxNamespace, type UnlockedSigningMaterial, type UseBalanceResult, type UseWalletActivityOptions, type UseWalletActivityResult, type UseWalletStatusResult, type WalletNamespace, type WalletStatus, type WalletStatusValue, type YieldNamespace, useAccesly, useBalance, useWalletActivity, useWalletStatus };
835
+ export { AcceslyContext, type AcceslyContextValue, type AcceslyHook, AcceslyProvider, type AcceslyProviderProps, type AuthNamespace, type BootstrapWalletInput, type CreateWalletInput, type CreatedWalletInfo, ENVIRONMENT_DEFAULTS, type EnsureWalletResult, type EnvironmentDefaults, type FinalizeRecoveryInput, type FinalizeRecoveryResult, type KycNamespace, NotImplementedYetError, REACT_ADAPTER_VERSION, type ReconstructedSeed, type RecoveryNamespace, type RemoteWalletInfo, type RetryDeployResult, type SendXlmInput, type SendXlmResult, type SessionNamespace, type SettingsNamespace, type TxNamespace, type UnlockedSigningMaterial, type UseBalanceResult, type UseWalletActivityOptions, type UseWalletActivityResult, type UseWalletStatusResult, type WalletActivityItem, type WalletNamespace, type WalletStatus, type WalletStatusValue, type WalletStreamActivityPayload, type WalletStreamBalancePayload, type WalletStreamEventType, type WalletStreamStatusPayload, type YieldNamespace, closeAllWalletSubscriptions, subscribeToWalletEvent, useAccesly, useBalance, useWalletActivity, useWalletStatus };