@accesly/react 1.3.0 → 1.3.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.cts CHANGED
@@ -1,4 +1,4 @@
1
- import { Environment, CognitoConfig, AuthClient, SessionStorage, DeviceStore, TelemetrySink, TokenManager, AccesslyEndpoints, AuthStatus, CredentialRecord, EncryptedEnvelope } from '@accesly/core';
1
+ import { Environment, CognitoConfig, AuthClient, SessionStorage, DeviceStore, TelemetrySink, TokenManager, AccesslyEndpoints, AuthStatus, CredentialRecord, EncryptedEnvelope, WalletHistoryItem } from '@accesly/core';
2
2
  import * as react from 'react';
3
3
  import { ReactNode } from 'react';
4
4
 
@@ -817,69 +817,44 @@ interface UseWalletActivityResult {
817
817
  }
818
818
  declare function useWalletActivity(walletAddress?: string | null, opts?: UseWalletActivityOptions): UseWalletActivityResult;
819
819
 
820
- /**
821
- * Cliente y decoder de la **Stellar Expert public API** (indexer free, full
822
- * retention, CORS abierto). Es la fuente primaria de `useWalletHistory`.
823
- *
824
- * Endpoints usados:
825
- * - GET /contract/{walletAddress}/events — Smart Account events (rotaciones).
826
- * - GET /contract/{xlmSac}/events?topics=transfer
827
- * — Todos los transfers del SAC. Filtramos client-side por wallet.
828
- * - GET /contract/{walletAddress} — Metadata del wallet (creación).
829
- *
830
- * Rate limit anonymous: ~1 req/s. Para zaramos cross-tab via BroadcastChannel
831
- * en el hook que consume este módulo.
832
- */
833
-
834
- type StellarExpertNetwork = 'testnet' | 'mainnet';
835
-
836
820
  /**
837
821
  * `useWalletHistory(walletAddress?, opts?)` — historial completo de la wallet
838
- * con Stellar Expert como indexer primario y opcional Soroban RPC autenticado
839
- * para tail real-time.
822
+ * pre-decodificado desde Stellar Expert (indexer free, full retention).
823
+ *
824
+ * El backend de Accesly **proxea** las requests a Stellar Expert porque SE
825
+ * bloquea CORS desde browsers (Cloudflare retorna 403 en cross-origin). El
826
+ * proxy hace el call server-side, decodea topics + amounts, y devuelve items
827
+ * tipados listos para renderizar.
840
828
  *
841
- * Características:
842
- * - 100% client-side, sin backend custom.
843
- * - Historia completa (mes+) gracias a la retention de Stellar Expert.
844
- * - Cache en `localStorage` per-wallet con TTL 12h → return instantáneo entre
845
- * page reloads y route changes.
829
+ * Features:
830
+ * - Cache en `localStorage` per-wallet con TTL 12h → render instantáneo en
831
+ * reloads + navegación.
846
832
  * - Polling cada 30s para nuevos events. Pausa si tab oculta.
847
- * - `BroadcastChannel` cross-tab para compartir SE rate limit — solo UN tab
848
- * hace fetch; los demás escuchan el resultado.
849
- * - Optimistic updates: el SDK puede llamar `historyOptimisticPush(addr, item)`
850
- * cuando acaba de mandar una tx exitosa para que aparezca inmediato sin
851
- * esperar el indexing de SE (~30-60s típico).
852
- * - Override de Soroban RPC: pasa `{ sorobanRpcUrl, sorobanRpcAuth }` para
853
- * que el tail (últimos eventos) venga via RPC con tu API key — sin lag.
833
+ * - `BroadcastChannel` cross-tab para compartir fetches — solo UN tab hace
834
+ * el request, los demás escuchan el resultado vía canal.
835
+ * - Optimistic updates: el SDK inserta el item al instante cuando `tx.send`
836
+ * confirma, sin esperar el indexing de SE (~30-60s típico).
854
837
  */
855
838
 
856
839
  /**
857
840
  * Inyecta un item de history "optimistically" — útil cuando acabás de hacer
858
841
  * `tx.send` y querés que aparezca al instante sin esperar el indexing de SE.
859
- * El item queda en memoria hasta que el próximo fetch del hook lo descarte
860
- * (porque ya está en el feed real) o hasta `clearOptimistic(walletAddress)`.
861
- *
862
- * Usado internamente por `tx.send`; expuesto al integrador para casos custom.
842
+ * El item queda hasta que el próximo fetch confirma que ya está en el feed.
863
843
  */
864
- declare function historyOptimisticPush(walletAddress: string, item: WalletActivityItem): void;
844
+ declare function historyOptimisticPush(walletAddress: string, item: WalletHistoryItem | WalletActivityItem): void;
865
845
  declare function historyClearOptimistic(walletAddress: string): void;
866
846
  interface UseWalletHistoryOptions {
867
- /** `'testnet'` (default) o `'mainnet'`. */
868
- readonly network?: StellarExpertNetwork;
869
847
  /** Intervalo de poll para nuevos events (ms). Default 30s, 0 desactiva. */
870
848
  readonly pollIntervalMs?: number;
871
849
  /**
872
- * Override del Soroban RPC para tail real-time. Si se provee, el hook usa
873
- * tu RPC autenticado en vez de hacer poll a Stellar Expert para detectar
874
- * nuevos events. Recomendado para producción.
850
+ * Cuántos transfers del XLM_SAC scan-ear por fetch. Default 50, max 500
851
+ * (5 paginated calls). En testnet hay millones de transfers globalmente; si
852
+ * tu wallet tiene pocos transfers, sube este número para encontrarlos.
875
853
  */
876
- readonly sorobanRpcUrl?: string;
877
- readonly sorobanRpcAuth?: string;
878
- /** Cantidad de transfers del XLM_SAC a scan-ear por fetch. Default 50. */
879
854
  readonly transferScanLimit?: number;
880
855
  }
881
856
  interface UseWalletHistoryResult {
882
- readonly events: readonly WalletActivityItem[];
857
+ readonly events: readonly WalletHistoryItem[];
883
858
  readonly isLoading: boolean;
884
859
  readonly error: Error | null;
885
860
  readonly hasMore: boolean;
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { Environment, CognitoConfig, AuthClient, SessionStorage, DeviceStore, TelemetrySink, TokenManager, AccesslyEndpoints, AuthStatus, CredentialRecord, EncryptedEnvelope } from '@accesly/core';
1
+ import { Environment, CognitoConfig, AuthClient, SessionStorage, DeviceStore, TelemetrySink, TokenManager, AccesslyEndpoints, AuthStatus, CredentialRecord, EncryptedEnvelope, WalletHistoryItem } from '@accesly/core';
2
2
  import * as react from 'react';
3
3
  import { ReactNode } from 'react';
4
4
 
@@ -817,69 +817,44 @@ interface UseWalletActivityResult {
817
817
  }
818
818
  declare function useWalletActivity(walletAddress?: string | null, opts?: UseWalletActivityOptions): UseWalletActivityResult;
819
819
 
820
- /**
821
- * Cliente y decoder de la **Stellar Expert public API** (indexer free, full
822
- * retention, CORS abierto). Es la fuente primaria de `useWalletHistory`.
823
- *
824
- * Endpoints usados:
825
- * - GET /contract/{walletAddress}/events — Smart Account events (rotaciones).
826
- * - GET /contract/{xlmSac}/events?topics=transfer
827
- * — Todos los transfers del SAC. Filtramos client-side por wallet.
828
- * - GET /contract/{walletAddress} — Metadata del wallet (creación).
829
- *
830
- * Rate limit anonymous: ~1 req/s. Para zaramos cross-tab via BroadcastChannel
831
- * en el hook que consume este módulo.
832
- */
833
-
834
- type StellarExpertNetwork = 'testnet' | 'mainnet';
835
-
836
820
  /**
837
821
  * `useWalletHistory(walletAddress?, opts?)` — historial completo de la wallet
838
- * con Stellar Expert como indexer primario y opcional Soroban RPC autenticado
839
- * para tail real-time.
822
+ * pre-decodificado desde Stellar Expert (indexer free, full retention).
823
+ *
824
+ * El backend de Accesly **proxea** las requests a Stellar Expert porque SE
825
+ * bloquea CORS desde browsers (Cloudflare retorna 403 en cross-origin). El
826
+ * proxy hace el call server-side, decodea topics + amounts, y devuelve items
827
+ * tipados listos para renderizar.
840
828
  *
841
- * Características:
842
- * - 100% client-side, sin backend custom.
843
- * - Historia completa (mes+) gracias a la retention de Stellar Expert.
844
- * - Cache en `localStorage` per-wallet con TTL 12h → return instantáneo entre
845
- * page reloads y route changes.
829
+ * Features:
830
+ * - Cache en `localStorage` per-wallet con TTL 12h → render instantáneo en
831
+ * reloads + navegación.
846
832
  * - Polling cada 30s para nuevos events. Pausa si tab oculta.
847
- * - `BroadcastChannel` cross-tab para compartir SE rate limit — solo UN tab
848
- * hace fetch; los demás escuchan el resultado.
849
- * - Optimistic updates: el SDK puede llamar `historyOptimisticPush(addr, item)`
850
- * cuando acaba de mandar una tx exitosa para que aparezca inmediato sin
851
- * esperar el indexing de SE (~30-60s típico).
852
- * - Override de Soroban RPC: pasa `{ sorobanRpcUrl, sorobanRpcAuth }` para
853
- * que el tail (últimos eventos) venga via RPC con tu API key — sin lag.
833
+ * - `BroadcastChannel` cross-tab para compartir fetches — solo UN tab hace
834
+ * el request, los demás escuchan el resultado vía canal.
835
+ * - Optimistic updates: el SDK inserta el item al instante cuando `tx.send`
836
+ * confirma, sin esperar el indexing de SE (~30-60s típico).
854
837
  */
855
838
 
856
839
  /**
857
840
  * Inyecta un item de history "optimistically" — útil cuando acabás de hacer
858
841
  * `tx.send` y querés que aparezca al instante sin esperar el indexing de SE.
859
- * El item queda en memoria hasta que el próximo fetch del hook lo descarte
860
- * (porque ya está en el feed real) o hasta `clearOptimistic(walletAddress)`.
861
- *
862
- * Usado internamente por `tx.send`; expuesto al integrador para casos custom.
842
+ * El item queda hasta que el próximo fetch confirma que ya está en el feed.
863
843
  */
864
- declare function historyOptimisticPush(walletAddress: string, item: WalletActivityItem): void;
844
+ declare function historyOptimisticPush(walletAddress: string, item: WalletHistoryItem | WalletActivityItem): void;
865
845
  declare function historyClearOptimistic(walletAddress: string): void;
866
846
  interface UseWalletHistoryOptions {
867
- /** `'testnet'` (default) o `'mainnet'`. */
868
- readonly network?: StellarExpertNetwork;
869
847
  /** Intervalo de poll para nuevos events (ms). Default 30s, 0 desactiva. */
870
848
  readonly pollIntervalMs?: number;
871
849
  /**
872
- * Override del Soroban RPC para tail real-time. Si se provee, el hook usa
873
- * tu RPC autenticado en vez de hacer poll a Stellar Expert para detectar
874
- * nuevos events. Recomendado para producción.
850
+ * Cuántos transfers del XLM_SAC scan-ear por fetch. Default 50, max 500
851
+ * (5 paginated calls). En testnet hay millones de transfers globalmente; si
852
+ * tu wallet tiene pocos transfers, sube este número para encontrarlos.
875
853
  */
876
- readonly sorobanRpcUrl?: string;
877
- readonly sorobanRpcAuth?: string;
878
- /** Cantidad de transfers del XLM_SAC a scan-ear por fetch. Default 50. */
879
854
  readonly transferScanLimit?: number;
880
855
  }
881
856
  interface UseWalletHistoryResult {
882
- readonly events: readonly WalletActivityItem[];
857
+ readonly events: readonly WalletHistoryItem[];
883
858
  readonly isLoading: boolean;
884
859
  readonly error: Error | null;
885
860
  readonly hasMore: boolean;
package/dist/index.js CHANGED
@@ -86,170 +86,6 @@ var init_sorobanDeployStatus = __esm({
86
86
  }
87
87
  });
88
88
 
89
- // src/hooks/stellarExpert.ts
90
- async function fetchContractEvents(contractId, opts) {
91
- const params = new URLSearchParams();
92
- params.set("limit", String(opts.limit ?? 50));
93
- params.set("order", opts.order ?? "desc");
94
- if (opts.cursor) params.set("cursor", opts.cursor);
95
- if (opts.topics) params.set("topics", opts.topics);
96
- const url = `${SE_BASE}/${opts.network}/contract/${contractId}/events?${params.toString()}`;
97
- const res = await fetch(url, opts.signal ? { signal: opts.signal } : {});
98
- if (!res.ok) {
99
- throw new Error(`StellarExpert ${res.status} ${res.statusText}`);
100
- }
101
- return await res.json();
102
- }
103
- async function fetchContractMeta(contractId, network, signal) {
104
- const url = `${SE_BASE}/${network}/contract/${contractId}`;
105
- try {
106
- const res = await fetch(url, signal ? { signal } : {});
107
- if (!res.ok) return null;
108
- return await res.json();
109
- } catch {
110
- return null;
111
- }
112
- }
113
- function decodeTransferAmount(bodyXdr) {
114
- if (!bodyXdr) return "0";
115
- try {
116
- const bytes = base64ToBytes(bodyXdr);
117
- if (bytes.length < 20) return "0";
118
- let hi = 0n;
119
- for (let i = 8; i < 16; i += 1) hi = hi << 8n | BigInt(bytes[i] ?? 0);
120
- let lo = 0n;
121
- for (let i = 16; i < 24; i += 1) lo = lo << 8n | BigInt(bytes[i] ?? 0);
122
- const value = hi << 64n | lo;
123
- return value.toString();
124
- } catch {
125
- return "0";
126
- }
127
- }
128
- function base64ToBytes(s) {
129
- if (typeof Buffer !== "undefined") return new Uint8Array(Buffer.from(s, "base64"));
130
- const bin = globalThis.atob(s);
131
- const arr = new Uint8Array(bin.length);
132
- for (let i = 0; i < bin.length; i += 1) arr[i] = bin.charCodeAt(i);
133
- return arr;
134
- }
135
- function decodeSEEvent(ev, walletAddress, xlmSac, txHashByEventId) {
136
- const t0 = ev.topics[0];
137
- if (!t0) return null;
138
- const timestamp = new Date(ev.ts * 1e3).toISOString();
139
- const txHash = txHashByEventId.get(ev.id) ?? ev.id.split("-")[0] ?? "";
140
- if (ev.contract === walletAddress) {
141
- if (t0 === "signer_rotated") {
142
- return {
143
- type: "signer-rotated",
144
- txHash,
145
- ledger: ev.ts,
146
- // SE no expone ledger directamente — usamos timestamp
147
- timestamp,
148
- newOwnerEd25519Hex: ""
149
- };
150
- }
151
- return null;
152
- }
153
- if (ev.contract === xlmSac && t0 === "transfer") {
154
- const from = ev.topics[1];
155
- const to = ev.topics[2];
156
- if (!from || !to) return null;
157
- const amountStroops = decodeTransferAmount(ev.bodyXdr);
158
- if (from === walletAddress && to !== walletAddress) {
159
- return {
160
- type: "transfer-out",
161
- txHash,
162
- ledger: ev.ts,
163
- timestamp,
164
- to,
165
- amountStroops
166
- };
167
- }
168
- if (to === walletAddress && from !== walletAddress) {
169
- return {
170
- type: "transfer-in",
171
- txHash,
172
- ledger: ev.ts,
173
- timestamp,
174
- from,
175
- amountStroops
176
- };
177
- }
178
- }
179
- return null;
180
- }
181
- async function fetchWalletHistory(walletAddress, opts) {
182
- const xlmSac = opts.network === "mainnet" ? XLM_SAC_MAINNET : XLM_SAC_TESTNET;
183
- const limit = 50;
184
- const transferLimit = opts.transferScanLimit ?? 50;
185
- const [smartAccountResp, transfersResp] = await Promise.all([
186
- fetchContractEvents(walletAddress, {
187
- network: opts.network,
188
- limit,
189
- order: "desc",
190
- ...opts.smartAccountCursor ? { cursor: opts.smartAccountCursor } : {},
191
- ...opts.signal ? { signal: opts.signal } : {}
192
- }).catch((err) => {
193
- console.warn("[stellarExpert] smart account events failed", err);
194
- return { _embedded: { records: [] } };
195
- }),
196
- fetchContractEvents(xlmSac, {
197
- network: opts.network,
198
- limit: transferLimit,
199
- order: "desc",
200
- topics: "transfer",
201
- ...opts.signal ? { signal: opts.signal } : {}
202
- }).catch((err) => {
203
- console.warn("[stellarExpert] xlm sac events failed", err);
204
- return { _embedded: { records: [] } };
205
- })
206
- ]);
207
- const txHashByEventId = /* @__PURE__ */ new Map();
208
- const items = [];
209
- const saRecords = smartAccountResp._embedded?.records ?? [];
210
- const txRecords = transfersResp._embedded?.records ?? [];
211
- for (const ev of saRecords) {
212
- const decoded = decodeSEEvent(ev, walletAddress, xlmSac, txHashByEventId);
213
- if (decoded) items.push(decoded);
214
- }
215
- for (const ev of txRecords) {
216
- const decoded = decodeSEEvent(ev, walletAddress, xlmSac, txHashByEventId);
217
- if (decoded) items.push(decoded);
218
- }
219
- if (!opts.smartAccountCursor) {
220
- const meta = await fetchContractMeta(walletAddress, opts.network, opts.signal);
221
- if (meta) {
222
- items.push({
223
- type: "wallet-created",
224
- txHash: "",
225
- ledger: meta.created,
226
- timestamp: new Date(meta.created * 1e3).toISOString()
227
- });
228
- }
229
- }
230
- items.sort((a, b) => (b.ledger ?? 0) - (a.ledger ?? 0));
231
- return {
232
- items,
233
- cursors: {
234
- smartAccount: extractCursor(smartAccountResp),
235
- transfers: extractCursor(transfersResp)
236
- }
237
- };
238
- }
239
- function extractCursor(resp) {
240
- const records = resp._embedded?.records;
241
- if (!records || records.length === 0) return null;
242
- return records[records.length - 1]?.paging_token ?? records[records.length - 1]?.id ?? null;
243
- }
244
- var SE_BASE, XLM_SAC_TESTNET, XLM_SAC_MAINNET;
245
- var init_stellarExpert = __esm({
246
- "src/hooks/stellarExpert.ts"() {
247
- SE_BASE = "https://api.stellar.expert/explorer";
248
- XLM_SAC_TESTNET = "CDLZFC3SYJYDZT7K67VZ75HPJVIEUVNIXF47ZG2FB2RMQQVU2HHGCYSC";
249
- XLM_SAC_MAINNET = "CAS3J7GYLGXMF6TDJBBYYSE3HQ6BBSMLNUQ34T6TZMYMW2EVH34XOWMA";
250
- }
251
- });
252
-
253
89
  // src/hooks/useWalletHistory.ts
254
90
  var useWalletHistory_exports = {};
255
91
  __export(useWalletHistory_exports, {
@@ -311,14 +147,10 @@ function subscribeOptimistic(walletAddress, listener) {
311
147
  function useWalletHistory(walletAddress, opts = {}) {
312
148
  const { wallet, _internal } = useAccesly();
313
149
  const username = _internal.username;
314
- const network = opts.network ?? inferNetwork(_internal.env);
315
150
  const [resolvedAddress, setResolvedAddress] = useState(walletAddress ?? null);
316
151
  const [events, setEvents] = useState([]);
317
152
  const [optimistic, setOptimistic] = useState([]);
318
- const [cursors, setCursors] = useState({
319
- smartAccount: null,
320
- transfers: null
321
- });
153
+ const [cursors, setCursors] = useState({ smartAccount: null, transfers: null });
322
154
  const [isLoading, setIsLoading] = useState(true);
323
155
  const [error, setError] = useState(null);
324
156
  const [hasMore, setHasMore] = useState(true);
@@ -351,6 +183,8 @@ function useWalletHistory(walletAddress, opts = {}) {
351
183
  setOptimistic(optimisticItems.get(resolvedAddress) ?? []);
352
184
  return subscribeOptimistic(resolvedAddress, setOptimistic);
353
185
  }, [resolvedAddress]);
186
+ const endpointsRef = useStableRef(_internal.endpoints);
187
+ const transferScanLimit = opts.transferScanLimit ?? 50;
354
188
  useEffect(() => {
355
189
  if (!resolvedAddress) {
356
190
  setIsLoading(false);
@@ -376,12 +210,11 @@ function useWalletHistory(walletAddress, opts = {}) {
376
210
  }
377
211
  void (async () => {
378
212
  try {
379
- const result = await fetchWalletHistory(resolvedAddress, {
380
- network,
381
- ...opts.transferScanLimit ? { transferScanLimit: opts.transferScanLimit } : {}
213
+ const result = await endpointsRef.current.walletHistory(resolvedAddress, {
214
+ transferScanLimit
382
215
  });
383
216
  if (cancelled) return;
384
- const deduped = dedupItems(result.items);
217
+ const deduped = dedupItems(result.events);
385
218
  setEvents(deduped);
386
219
  setCursors(result.cursors);
387
220
  setIsLoading(false);
@@ -405,35 +238,31 @@ function useWalletHistory(walletAddress, opts = {}) {
405
238
  cancelled = true;
406
239
  channel?.close();
407
240
  };
408
- }, [resolvedAddress, network, opts.transferScanLimit]);
241
+ }, [resolvedAddress, transferScanLimit, endpointsRef]);
409
242
  const interval = opts.pollIntervalMs ?? POLL_INTERVAL_MS;
410
243
  useEffect(() => {
411
244
  if (!resolvedAddress || interval === 0) return void 0;
412
245
  const tick = async () => {
413
246
  if (typeof document !== "undefined" && document.hidden) return;
414
247
  try {
415
- const result = await fetchWalletHistory(resolvedAddress, {
416
- network,
417
- ...opts.transferScanLimit ? { transferScanLimit: opts.transferScanLimit } : {}
248
+ const result = await endpointsRef.current.walletHistory(resolvedAddress, {
249
+ transferScanLimit
418
250
  });
419
- setEvents((prev) => mergeAndDedup(prev, result.items));
420
- if (resolvedAddress) {
421
- const realTxHashes = new Set(result.items.map((it) => it.txHash));
422
- const optimisticsRemaining = (optimisticItems.get(resolvedAddress) ?? []).filter(
423
- (it) => !realTxHashes.has(it.txHash)
424
- );
425
- if (optimisticsRemaining.length !== (optimisticItems.get(resolvedAddress)?.length ?? 0)) {
426
- optimisticItems.set(resolvedAddress, optimisticsRemaining);
427
- const listeners = optimisticListeners.get(resolvedAddress);
428
- if (listeners) for (const fn of listeners) fn(optimisticsRemaining);
429
- }
251
+ setEvents((prev) => mergeAndDedup(prev, result.events));
252
+ const realTxHashes = new Set(result.events.map((it) => it.txHash));
253
+ const current = optimisticItems.get(resolvedAddress) ?? [];
254
+ const remaining = current.filter((it) => !realTxHashes.has(it.txHash));
255
+ if (remaining.length !== current.length) {
256
+ optimisticItems.set(resolvedAddress, remaining);
257
+ const listeners = optimisticListeners.get(resolvedAddress);
258
+ if (listeners) for (const fn of listeners) fn(remaining);
430
259
  }
431
260
  } catch {
432
261
  }
433
262
  };
434
263
  const id = setInterval(tick, interval);
435
264
  return () => clearInterval(id);
436
- }, [resolvedAddress, network, interval]);
265
+ }, [resolvedAddress, interval, transferScanLimit, endpointsRef]);
437
266
  const loadMoreImpl = useCallback(async () => {
438
267
  if (!resolvedAddress) return;
439
268
  if (!cursors.smartAccount && !cursors.transfers) {
@@ -441,27 +270,26 @@ function useWalletHistory(walletAddress, opts = {}) {
441
270
  return;
442
271
  }
443
272
  try {
444
- const result = await fetchWalletHistory(resolvedAddress, {
445
- network,
273
+ const result = await endpointsRef.current.walletHistory(resolvedAddress, {
446
274
  ...cursors.smartAccount ? { smartAccountCursor: cursors.smartAccount } : {},
447
- ...opts.transferScanLimit ? { transferScanLimit: opts.transferScanLimit } : {}
275
+ ...cursors.transfers ? { transfersCursor: cursors.transfers } : {},
276
+ transferScanLimit
448
277
  });
449
- setEvents((prev) => mergeAndDedup(prev, result.items));
278
+ setEvents((prev) => mergeAndDedup(prev, result.events));
450
279
  setCursors(result.cursors);
451
280
  setHasMore(result.cursors.smartAccount !== null || result.cursors.transfers !== null);
452
281
  } catch (err) {
453
282
  setError(err);
454
283
  }
455
- }, [resolvedAddress, network, cursors, opts.transferScanLimit]);
284
+ }, [resolvedAddress, cursors, transferScanLimit, endpointsRef]);
456
285
  const refreshImpl = useCallback(async () => {
457
286
  if (!resolvedAddress) return;
458
287
  setIsLoading(true);
459
288
  try {
460
- const result = await fetchWalletHistory(resolvedAddress, {
461
- network,
462
- ...opts.transferScanLimit ? { transferScanLimit: opts.transferScanLimit } : {}
289
+ const result = await endpointsRef.current.walletHistory(resolvedAddress, {
290
+ transferScanLimit
463
291
  });
464
- const deduped = dedupItems(result.items);
292
+ const deduped = dedupItems(result.events);
465
293
  setEvents(deduped);
466
294
  setCursors(result.cursors);
467
295
  setError(null);
@@ -475,7 +303,7 @@ function useWalletHistory(walletAddress, opts = {}) {
475
303
  } finally {
476
304
  setIsLoading(false);
477
305
  }
478
- }, [resolvedAddress, network, opts.transferScanLimit]);
306
+ }, [resolvedAddress, transferScanLimit, endpointsRef]);
479
307
  const combined = [...optimistic, ...events];
480
308
  return {
481
309
  events: combined,
@@ -486,9 +314,6 @@ function useWalletHistory(walletAddress, opts = {}) {
486
314
  refresh: refreshImpl
487
315
  };
488
316
  }
489
- function inferNetwork(env) {
490
- return env === "prod" ? "mainnet" : "testnet";
491
- }
492
317
  function dedupItems(items) {
493
318
  const seen = /* @__PURE__ */ new Set();
494
319
  const out = [];
@@ -498,7 +323,7 @@ function dedupItems(items) {
498
323
  seen.add(key);
499
324
  out.push(item);
500
325
  }
501
- out.sort((a, b) => (b.ledger ?? 0) - (a.ledger ?? 0));
326
+ out.sort((a, b) => b.ledger - a.ledger);
502
327
  return out;
503
328
  }
504
329
  function mergeAndDedup(prev, fresh) {
@@ -508,7 +333,6 @@ var POLL_INTERVAL_MS, CACHE_TTL_MS, CACHE_KEY_PREFIX, BROADCAST_CHANNEL_PREFIX,
508
333
  var init_useWalletHistory = __esm({
509
334
  "src/hooks/useWalletHistory.ts"() {
510
335
  init_useAccesly();
511
- init_stellarExpert();
512
336
  POLL_INTERVAL_MS = 3e4;
513
337
  CACHE_TTL_MS = 12 * 60 * 60 * 1e3;
514
338
  CACHE_KEY_PREFIX = "accesly:history:";
@@ -981,8 +805,8 @@ function useAccesly() {
981
805
  const sessionPlaintext = unwrapSessionFragment2(wrappedF2, ephemeral.privateKey).plaintext;
982
806
  const fragmentF2Wire = JSON.parse(new TextDecoder().decode(sessionPlaintext));
983
807
  const fragmentF2Envelope = {
984
- nonce: base64ToBytes2(fragmentF2Wire.nonce),
985
- ciphertext: base64ToBytes2(fragmentF2Wire.ciphertext)
808
+ nonce: base64ToBytes(fragmentF2Wire.nonce),
809
+ ciphertext: base64ToBytes(fragmentF2Wire.ciphertext)
986
810
  };
987
811
  const reconstructed = reconstructFromPlainAndEncrypted({
988
812
  fragmentF1Plain: input.fragmentF1Plain,
@@ -1061,18 +885,18 @@ function useAccesly() {
1061
885
  "recovery.reconstructSeed: la wallet fue creada antes de Fase 1 y no tiene F2 cipher-bound a recoveryKey. No es recuperable v\xEDa OTP."
1062
886
  );
1063
887
  }
1064
- const recoverySalt = base64ToBytes2(frag.recoverySalt);
888
+ const recoverySalt = base64ToBytes(frag.recoverySalt);
1065
889
  const recoveryKey = deriveRecoveryKey({
1066
890
  password: input.cognitoPassword,
1067
891
  salt: recoverySalt
1068
892
  });
1069
893
  const f2Envelope = {
1070
- ciphertext: base64ToBytes2(frag.fragmentF2Recovery.ciphertext),
1071
- nonce: base64ToBytes2(frag.fragmentF2Recovery.nonce)
894
+ ciphertext: base64ToBytes(frag.fragmentF2Recovery.ciphertext),
895
+ nonce: base64ToBytes(frag.fragmentF2Recovery.nonce)
1072
896
  };
1073
897
  const f3Envelope = {
1074
- ciphertext: base64ToBytes2(frag.fragmentF3Encrypted.ciphertext),
1075
- nonce: base64ToBytes2(frag.fragmentF3Encrypted.nonce)
898
+ ciphertext: base64ToBytes(frag.fragmentF3Encrypted.ciphertext),
899
+ nonce: base64ToBytes(frag.fragmentF3Encrypted.nonce)
1076
900
  };
1077
901
  const seedResult = reconstructKey({
1078
902
  fragments: [
@@ -1308,7 +1132,7 @@ function base64FromBytes(bytes) {
1308
1132
  for (let i = 0; i < bytes.length; i += 1) bin += String.fromCharCode(bytes[i] ?? 0);
1309
1133
  return globalThis.btoa(bin);
1310
1134
  }
1311
- function base64ToBytes2(s) {
1135
+ function base64ToBytes(s) {
1312
1136
  if (typeof Buffer !== "undefined") return new Uint8Array(Buffer.from(s, "base64"));
1313
1137
  const bin = globalThis.atob(s);
1314
1138
  const arr = new Uint8Array(bin.length);