@naculus/connect-appkit-react 0.1.9 → 0.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.
Files changed (94) hide show
  1. package/README.md +4 -4
  2. package/dist/client.cjs +1 -1
  3. package/dist/client.cjs.map +1 -1
  4. package/dist/client.d.cts +144 -0
  5. package/dist/client.d.ts +144 -0
  6. package/dist/client.js +1 -1
  7. package/dist/client.js.map +1 -1
  8. package/dist/index.cjs +2 -1
  9. package/dist/index.cjs.map +1 -1
  10. package/dist/index.d.cts +2270 -0
  11. package/dist/index.d.ts +2270 -0
  12. package/dist/index.js +2 -1
  13. package/dist/index.js.map +1 -1
  14. package/package.json +30 -12
  15. package/api-extractor.json +0 -21
  16. package/src/chain-abstraction/index.ts +0 -8
  17. package/src/chain-abstraction/useCompareCosts.ts +0 -137
  18. package/src/chain-abstraction/useExecuteRoute.ts +0 -129
  19. package/src/chain-abstraction/useRouteQuote.ts +0 -168
  20. package/src/client.test.ts +0 -242
  21. package/src/client.ts +0 -265
  22. package/src/hooks/useAccount.test.ts +0 -67
  23. package/src/hooks/useAccount.ts +0 -37
  24. package/src/hooks/useBalance.test.ts +0 -459
  25. package/src/hooks/useBalance.ts +0 -170
  26. package/src/hooks/useChain.test.ts +0 -160
  27. package/src/hooks/useChain.ts +0 -53
  28. package/src/hooks/useConnect.test.ts +0 -112
  29. package/src/hooks/useConnect.ts +0 -29
  30. package/src/hooks/useDisconnect.test.ts +0 -75
  31. package/src/hooks/useDisconnect.ts +0 -32
  32. package/src/hooks/useERC20Allowance.ts +0 -93
  33. package/src/hooks/useERC20Approve.ts +0 -220
  34. package/src/hooks/useERC20Transfer.ts +0 -134
  35. package/src/hooks/useERC20TransferSimulation.ts +0 -147
  36. package/src/hooks/useEmbeddedWallet.test.ts +0 -266
  37. package/src/hooks/useEmbeddedWallet.ts +0 -181
  38. package/src/hooks/useLastTx.test.ts +0 -117
  39. package/src/hooks/useLastTx.ts +0 -73
  40. package/src/hooks/useLookupAddress.ts +0 -131
  41. package/src/hooks/useNotification.ts +0 -308
  42. package/src/hooks/useResolveName.ts +0 -128
  43. package/src/hooks/useSIWxLogin.test.ts +0 -307
  44. package/src/hooks/useSIWxLogin.ts +0 -163
  45. package/src/hooks/useSIWxSession.test.ts +0 -481
  46. package/src/hooks/useSIWxSession.ts +0 -290
  47. package/src/hooks/useSendCalls.ts +0 -103
  48. package/src/hooks/useSendTransaction.test.ts +0 -175
  49. package/src/hooks/useSendTransaction.ts +0 -80
  50. package/src/hooks/useSendUserOperation.ts +0 -313
  51. package/src/hooks/useSession.ts +0 -96
  52. package/src/hooks/useSessionKeys.ts +0 -356
  53. package/src/hooks/useSignInWithEthereum.test.ts +0 -224
  54. package/src/hooks/useSignInWithEthereum.ts +0 -46
  55. package/src/hooks/useSignInWithX.test.ts +0 -210
  56. package/src/hooks/useSignInWithX.ts +0 -141
  57. package/src/hooks/useSignMessage.test.ts +0 -151
  58. package/src/hooks/useSignMessage.ts +0 -65
  59. package/src/hooks/useSimulateTransfer.ts +0 -165
  60. package/src/hooks/useSiwxAuthSession.test.ts +0 -456
  61. package/src/hooks/useSiwxAuthSession.ts +0 -163
  62. package/src/hooks/useSmartAccount.ts +0 -194
  63. package/src/hooks/useSwitchChain.ts +0 -68
  64. package/src/hooks/useTokenBalance.test.ts +0 -337
  65. package/src/hooks/useTokenBalance.ts +0 -210
  66. package/src/hooks/useTransactionSimulation.ts +0 -401
  67. package/src/hooks/useTxHistory.test.ts +0 -108
  68. package/src/hooks/useTxHistory.ts +0 -83
  69. package/src/hooks/useTxMonitor.test.ts +0 -127
  70. package/src/hooks/useTxMonitor.ts +0 -178
  71. package/src/hooks/useUserOpStatus.ts +0 -245
  72. package/src/hooks/useValidateDestination.test.ts +0 -96
  73. package/src/hooks/useValidateDestination.ts +0 -72
  74. package/src/hooks/useViemClient.test.ts +0 -155
  75. package/src/hooks/useViemClient.ts +0 -65
  76. package/src/hooks/useWallet.test.ts +0 -133
  77. package/src/hooks/useWallet.ts +0 -39
  78. package/src/hooks/useWeb3ErrorHandler.ts +0 -102
  79. package/src/index.ts +0 -186
  80. package/src/provider/Web3ConnectProvider.test.tsx +0 -178
  81. package/src/provider/Web3ConnectProvider.tsx +0 -530
  82. package/src/token-list/TokenSelector.tsx +0 -351
  83. package/src/token-list/defaults.ts +0 -39
  84. package/src/token-list/index.ts +0 -14
  85. package/src/token-list/useTokenList.ts +0 -119
  86. package/src/token-list/useTokenSearch.ts +0 -99
  87. package/src/types/index.ts +0 -99
  88. package/src/utils/chains.ts +0 -115
  89. package/src/utils/errorMessages.ts +0 -142
  90. package/src/utils/i18n.ts +0 -90
  91. package/src/wc-generated/components.ts +0 -377
  92. package/test/setup.ts +0 -17
  93. package/test/test-utils.tsx +0 -78
  94. package/tsup.config.ts +0 -18
@@ -1,165 +0,0 @@
1
- /**
2
- * useSimulateTransfer — React hook for simulating ERC-20 token transfers.
3
- *
4
- * Wraps SimulationManager.simulateERC20Transfer in a React hook with
5
- * reactive state for loading, result, and error.
6
- *
7
- * @example
8
- * ```tsx
9
- * import { useSimulateTransfer } from "@naculus/connect-appkit-react";
10
- *
11
- * function SendForm({ token, to, amount }) {
12
- * const { result, simulate, loading } = useSimulateTransfer({
13
- * rpcUrl: "https://eth.llamarpc.com",
14
- * });
15
- *
16
- * return (
17
- * <div>
18
- * <button onClick={() => simulate(token, to, amount)} disabled={loading}>
19
- * Simulate Transfer
20
- * </button>
21
- * {result && <p>Result: {result.status}</p>}
22
- * </div>
23
- * );
24
- * }
25
- * ```
26
- */
27
-
28
- import { useState, useCallback, useRef } from "react";
29
- import { SimulationManager } from "@naculus/wallet-engine";
30
- import type { SimulationResult } from "@naculus/wallet-engine";
31
-
32
- // ── Types ──────────────────────────────────────────────────────────
33
-
34
- export interface UseSimulateTransferOptions {
35
- /** RPC URL for eth_call simulation */
36
- rpcUrl?: string;
37
- /** Default chain ID */
38
- chainId?: number;
39
- }
40
-
41
- export interface UseSimulateTransferReturn {
42
- /** Current simulation result */
43
- result: SimulationResult | null;
44
- /** Whether a simulation is in progress */
45
- loading: boolean;
46
- /** Last error (null if no error) */
47
- error: Error | null;
48
- /**
49
- * Simulate an ERC-20 transfer.
50
- *
51
- * @param tokenAddress - ERC-20 token contract address
52
- * @param from - Sender address
53
- * @param to - Recipient address
54
- * @param amount - Human-readable amount (e.g. "1.50")
55
- * @param options - Optional chainId, rpcUrl, decimals override
56
- */
57
- simulate: (
58
- tokenAddress: `0x${string}`,
59
- from: `0x${string}`,
60
- to: `0x${string}`,
61
- amount: string,
62
- options?: {
63
- chainId?: number;
64
- rpcUrl?: string;
65
- decimals?: number;
66
- },
67
- ) => Promise<SimulationResult>;
68
- /** Reset result and error state */
69
- reset: () => void;
70
- }
71
-
72
- // ── Hook ───────────────────────────────────────────────────────────
73
-
74
- /**
75
- * Hook for simulating an ERC-20 token transfer.
76
- *
77
- * Creates a SimulationManager internally and provides a `simulate`
78
- * function that builds transfer calldata automatically.
79
- *
80
- * @param options - Configuration for the underlying SimulationManager
81
- */
82
- export function useSimulateTransfer(
83
- options?: UseSimulateTransferOptions,
84
- ): UseSimulateTransferReturn {
85
- const rpcUrl = options?.rpcUrl;
86
- const chainId = options?.chainId;
87
-
88
- // ── SimulationManager ref (lazy init) ──────────────────────────
89
-
90
- const managerRef = useRef<SimulationManager | null>(null);
91
-
92
- function getManager(): SimulationManager {
93
- if (!managerRef.current) {
94
- managerRef.current = new SimulationManager({
95
- enabled: true,
96
- rpcUrl,
97
- autoSimulate: false,
98
- });
99
- }
100
- return managerRef.current;
101
- }
102
-
103
- // ── State ──────────────────────────────────────────────────────
104
-
105
- const [result, setResult] = useState<SimulationResult | null>(null);
106
- const [loading, setLoading] = useState(false);
107
- const [error, setError] = useState<Error | null>(null);
108
-
109
- // ── Simulate ───────────────────────────────────────────────────
110
-
111
- const simulate = useCallback(
112
- async (
113
- tokenAddress: `0x${string}`,
114
- from: `0x${string}`,
115
- to: `0x${string}`,
116
- amount: string,
117
- simOptions?: {
118
- chainId?: number;
119
- rpcUrl?: string;
120
- decimals?: number;
121
- },
122
- ): Promise<SimulationResult> => {
123
- setLoading(true);
124
- setError(null);
125
-
126
- try {
127
- const manager = getManager();
128
- const actualChainId = simOptions?.chainId ?? chainId ?? 1;
129
- const actualRpcUrl = simOptions?.rpcUrl ?? rpcUrl;
130
-
131
- const simResult = await manager.simulateERC20Transfer(
132
- tokenAddress,
133
- from,
134
- to,
135
- amount,
136
- actualChainId,
137
- simOptions?.decimals,
138
- );
139
-
140
- setResult(simResult);
141
- return simResult;
142
- } catch (err) {
143
- const errorObj =
144
- err instanceof Error ? err : new Error(String(err));
145
- setError(errorObj);
146
- throw errorObj;
147
- } finally {
148
- setLoading(false);
149
- }
150
- },
151
- [rpcUrl, chainId],
152
- );
153
-
154
- // ── Reset ──────────────────────────────────────────────────────
155
-
156
- const reset = useCallback(() => {
157
- setResult(null);
158
- setError(null);
159
- setLoading(false);
160
- }, []);
161
-
162
- // ── Return ─────────────────────────────────────────────────────
163
-
164
- return { result, loading, error, simulate, reset };
165
- }
@@ -1,456 +0,0 @@
1
- /// <reference types="vitest" />
2
- /// @vitest-environment jsdom
3
-
4
- import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
5
- import { renderHook, act, waitFor } from "@testing-library/react";
6
-
7
- // ── localStorage polyfill for Node 26 ────────────────────────────
8
-
9
- if (typeof globalThis.localStorage === 'undefined') {
10
- const store: Record<string, string> = {};
11
- const lsMock = {
12
- getItem: (key: string) => store[key] ?? null,
13
- setItem: (key: string, value: string) => { store[key] = value; },
14
- removeItem: (key: string) => { delete store[key]; },
15
- clear: () => { Object.keys(store).forEach(k => delete store[k]); },
16
- get length() { return Object.keys(store).length; },
17
- key: (index: number) => Object.keys(store)[index] ?? null,
18
- };
19
- Object.defineProperty(globalThis, 'localStorage', {
20
- value: new Proxy(lsMock, {
21
- ownKeys: () => Object.keys(store),
22
- getOwnPropertyDescriptor: () => ({ configurable: true, enumerable: true }),
23
- }),
24
- writable: true, configurable: true,
25
- });
26
- if (typeof window !== 'undefined') {
27
- Object.defineProperty(window, 'localStorage', {
28
- value: new Proxy(lsMock, {
29
- ownKeys: () => Object.keys(store),
30
- getOwnPropertyDescriptor: () => ({ configurable: true, enumerable: true }),
31
- }),
32
- writable: true, configurable: true,
33
- });
34
- }
35
- }
36
-
37
- // ── Mocks ────────────────────────────────────────────────────────
38
-
39
- const mockUseWeb3 = vi.fn();
40
- vi.mock("../provider/Web3ConnectProvider", () => ({
41
- useWeb3: () => mockUseWeb3(),
42
- Web3ConnectProvider: ({ children }: { children: React.ReactNode }) => children,
43
- }));
44
-
45
- const mockSignMessage = vi.fn();
46
- const mockGetClient = vi.fn();
47
- vi.mock("../client", () => ({
48
- getClient: () => mockGetClient(),
49
- }));
50
-
51
- // We need to mock useSignInWithX since useSiwxAuthSession composes it
52
- const mockUseSignInWithX = vi.fn();
53
- vi.mock("./useSignInWithX", () => ({
54
- useSignInWithX: () => mockUseSignInWithX(),
55
- }));
56
-
57
- import { useSiwxAuthSession } from "./useSiwxAuthSession";
58
-
59
- // ── Test Fixtures ────────────────────────────────────────────────
60
-
61
- function createSiwxResult(overrides: Record<string, unknown> = {}) {
62
- const defaultExpiry = new Date(Date.now() + 3600000).toISOString(); // 1 hour from now
63
- return {
64
- message: {
65
- raw: "localhost wants you to sign in",
66
- domain: "localhost",
67
- address: "eip155:1:0x1234567890123456789012345678901234567890",
68
- statement: "Sign in to test",
69
- uri: "http://localhost",
70
- version: 1,
71
- chainId: "eip155:1",
72
- nonce: "abc123xyz",
73
- issuedAt: new Date().toISOString(),
74
- expirationTime: defaultExpiry,
75
- notBefore: null,
76
- resources: [],
77
- requestId: null,
78
- ...(overrides.message ?? {}),
79
- },
80
- signature: "0xdeadbeef",
81
- ...overrides,
82
- };
83
- }
84
-
85
- // ── Storage Helpers ──────────────────────────────────────────────
86
-
87
- function setLocalStorage(key: string, value: unknown) {
88
- localStorage.setItem(`naculus_${key}`, JSON.stringify(value));
89
- }
90
-
91
- function getLocalStorage(key: string) {
92
- const v = localStorage.getItem(`naculus_${key}`);
93
- return v ? JSON.parse(v) : null;
94
- }
95
-
96
- function clearLocalStorage() {
97
- const keys = Object.keys(localStorage).filter((k) => k.startsWith("naculus_"));
98
- keys.forEach((k) => localStorage.removeItem(k));
99
- }
100
-
101
- // ── Tests ───────────────────────────────────────────────────────
102
-
103
- describe("useSiwxAuthSession", () => {
104
- beforeEach(() => {
105
- vi.clearAllMocks();
106
- clearLocalStorage();
107
-
108
- // Default mock for useSignInWithX
109
- mockUseSignInWithX.mockReturnValue({
110
- signIn: vi.fn(),
111
- isSigningIn: false,
112
- result: null,
113
- error: null,
114
- clearError: vi.fn(),
115
- });
116
-
117
- // Default mock for Web3 context
118
- mockUseWeb3.mockReturnValue({
119
- session: {
120
- topic: "test-topic",
121
- namespaces: {
122
- eip155: {
123
- chains: ["eip155:1"],
124
- accounts: ["eip155:1:0x1234567890123456789012345678901234567890"],
125
- },
126
- },
127
- },
128
- chainId: "eip155:1",
129
- });
130
- });
131
-
132
- afterEach(() => {
133
- clearLocalStorage();
134
- });
135
-
136
- // ── Initial State ──────────────────────────────────────────────
137
-
138
- it("should have initial unsigned state", () => {
139
- const { result } = renderHook(() => useSiwxAuthSession());
140
-
141
- expect(result.current.isSignedIn).toBe(false);
142
- expect(result.current.siwxResult).toBeNull();
143
- expect(result.current.isSigningIn).toBe(false);
144
- expect(result.current.error).toBeNull();
145
- expect(result.current.isRestoring).toBe(true); // still restoring
146
- });
147
-
148
- it("should finish restoring when no saved auth exists", async () => {
149
- const { result } = renderHook(() => useSiwxAuthSession());
150
-
151
- await waitFor(() => {
152
- expect(result.current.isRestoring).toBe(false);
153
- });
154
-
155
- expect(result.current.isSignedIn).toBe(false);
156
- expect(result.current.siwxResult).toBeNull();
157
- });
158
-
159
- // ── Persisted Auth Restore ─────────────────────────────────────
160
-
161
- it("should restore a valid persisted auth session", async () => {
162
- const siwxResult = createSiwxResult();
163
- setLocalStorage("siwx_auth", siwxResult);
164
-
165
- const { result } = renderHook(() => useSiwxAuthSession());
166
-
167
- await waitFor(() => {
168
- expect(result.current.isRestoring).toBe(false);
169
- });
170
-
171
- expect(result.current.isSignedIn).toBe(true);
172
- expect(result.current.siwxResult).not.toBeNull();
173
- expect(result.current.siwxResult!.signature).toBe("0xdeadbeef");
174
- expect(result.current.error).toBeNull();
175
- });
176
-
177
- it("should auto-restore off when autoRestore=false", async () => {
178
- setLocalStorage("siwx_auth", createSiwxResult());
179
-
180
- const { result } = renderHook(() => useSiwxAuthSession({ autoRestore: false }));
181
-
182
- // Auto-restore set to false, so isRestoring should quickly be false
183
- await waitFor(() => {
184
- expect(result.current.isRestoring).toBe(false);
185
- });
186
-
187
- // Should not have restored the auth
188
- expect(result.current.isSignedIn).toBe(false);
189
- expect(result.current.siwxResult).toBeNull();
190
- });
191
-
192
- it("should discard expired persisted auth", async () => {
193
- const expired = createSiwxResult({
194
- message: {
195
- expirationTime: new Date(Date.now() - 10000).toISOString(), // 10s ago
196
- },
197
- });
198
- setLocalStorage("siwx_auth", expired);
199
-
200
- const { result } = renderHook(() => useSiwxAuthSession());
201
-
202
- await waitFor(() => {
203
- expect(result.current.isRestoring).toBe(false);
204
- });
205
-
206
- expect(result.current.isSignedIn).toBe(false);
207
- expect(result.current.siwxResult).toBeNull();
208
-
209
- // Verify it was cleaned from storage
210
- expect(getLocalStorage("siwx_auth")).toBeNull();
211
- });
212
-
213
- it("should discard notBefore-violated persisted auth", async () => {
214
- const futureNotBefore = createSiwxResult({
215
- message: {
216
- notBefore: new Date(Date.now() + 3600000).toISOString(), // 1h in future
217
- expirationTime: new Date(Date.now() + 7200000).toISOString(),
218
- },
219
- });
220
- setLocalStorage("siwx_auth", futureNotBefore);
221
-
222
- const { result } = renderHook(() => useSiwxAuthSession());
223
-
224
- await waitFor(() => {
225
- expect(result.current.isRestoring).toBe(false);
226
- });
227
-
228
- expect(result.current.isSignedIn).toBe(false);
229
- expect(result.current.siwxResult).toBeNull();
230
- expect(getLocalStorage("siwx_auth")).toBeNull();
231
- });
232
-
233
- it("should restore auth without expirationTime", async () => {
234
- const noExpiry = createSiwxResult({
235
- message: { expirationTime: null },
236
- });
237
- setLocalStorage("siwx_auth", noExpiry);
238
-
239
- const { result } = renderHook(() => useSiwxAuthSession());
240
-
241
- await waitFor(() => {
242
- expect(result.current.isRestoring).toBe(false);
243
- });
244
-
245
- expect(result.current.isSignedIn).toBe(true);
246
- });
247
-
248
- // ── Sign In ────────────────────────────────────────────────────
249
-
250
- it("should persist SIWx result on successful sign-in", async () => {
251
- const mockResult = createSiwxResult({ signature: "0xpersisted_sig" });
252
- const mockSignIn = vi.fn().mockResolvedValue(mockResult);
253
- mockUseSignInWithX.mockReturnValue({
254
- signIn: mockSignIn,
255
- isSigningIn: false,
256
- result: null,
257
- error: null,
258
- clearError: vi.fn(),
259
- });
260
-
261
- const { result } = renderHook(() => useSiwxAuthSession());
262
-
263
- // Wait for restore check to complete
264
- await waitFor(() => {
265
- expect(result.current.isRestoring).toBe(false);
266
- });
267
-
268
- let returned: Awaited<ReturnType<typeof result.current.signIn>> | undefined;
269
-
270
- await act(async () => {
271
- returned = await result.current.signIn({
272
- statement: "Test sign-in",
273
- });
274
- });
275
-
276
- expect(returned!.signature).toBe("0xpersisted_sig");
277
- expect(result.current.isSignedIn).toBe(true);
278
- expect(result.current.siwxResult!.signature).toBe("0xpersisted_sig");
279
-
280
- // Verify it was persisted to storage
281
- const stored = getLocalStorage("siwx_auth");
282
- expect(stored).not.toBeNull();
283
- expect(stored.signature).toBe("0xpersisted_sig");
284
- });
285
-
286
- it("should handle sign-in failure without persisting", async () => {
287
- const mockSignIn = vi.fn().mockRejectedValue(new Error("User rejected"));
288
- mockUseSignInWithX.mockReturnValue({
289
- signIn: mockSignIn,
290
- isSigningIn: false,
291
- result: null,
292
- error: null,
293
- clearError: vi.fn(),
294
- });
295
-
296
- const { result } = renderHook(() => useSiwxAuthSession());
297
-
298
- await waitFor(() => {
299
- expect(result.current.isRestoring).toBe(false);
300
- });
301
-
302
- await act(async () => {
303
- try {
304
- await result.current.signIn();
305
- } catch {
306
- // expected
307
- }
308
- });
309
-
310
- expect(result.current.isSignedIn).toBe(false);
311
- expect(result.current.error).not.toBeNull();
312
- expect(result.current.error!.message).toBe("User rejected");
313
-
314
- // Should NOT have persisted anything
315
- expect(getLocalStorage("siwx_auth")).toBeNull();
316
- });
317
-
318
- // ── Sign Out ───────────────────────────────────────────────────
319
-
320
- it("should clear persisted auth on sign-out", async () => {
321
- const mockResult = createSiwxResult({ signature: "0xwill_clear" });
322
- const mockSignIn = vi.fn().mockResolvedValue(mockResult);
323
- mockUseSignInWithX.mockReturnValue({
324
- signIn: mockSignIn,
325
- isSigningIn: false,
326
- result: null,
327
- error: null,
328
- clearError: vi.fn(),
329
- });
330
-
331
- const { result } = renderHook(() => useSiwxAuthSession());
332
-
333
- await waitFor(() => {
334
- expect(result.current.isRestoring).toBe(false);
335
- });
336
-
337
- // Sign in first
338
- await act(async () => {
339
- await result.current.signIn();
340
- });
341
-
342
- expect(result.current.isSignedIn).toBe(true);
343
- expect(getLocalStorage("siwx_auth")).not.toBeNull();
344
-
345
- // Sign out
346
- await act(async () => {
347
- result.current.signOut();
348
- });
349
-
350
- expect(result.current.isSignedIn).toBe(false);
351
- expect(result.current.siwxResult).toBeNull();
352
- expect(getLocalStorage("siwx_auth")).toBeNull();
353
- });
354
-
355
- // ── Edge Cases ─────────────────────────────────────────────────
356
-
357
- it("should use custom storage prefix", async () => {
358
- const mockResult = createSiwxResult({ signature: "0xprefix_test" });
359
- const mockSignIn = vi.fn().mockResolvedValue(mockResult);
360
- mockUseSignInWithX.mockReturnValue({
361
- signIn: mockSignIn,
362
- isSigningIn: false,
363
- result: null,
364
- error: null,
365
- clearError: vi.fn(),
366
- });
367
-
368
- const { result } = renderHook(() =>
369
- useSiwxAuthSession({ storagePrefix: "myapp_", autoRestore: false })
370
- );
371
-
372
- await act(async () => {
373
- await result.current.signIn();
374
- });
375
-
376
- // Should use custom prefix
377
- expect(localStorage.getItem("myapp_siwx_auth")).not.toBeNull();
378
- });
379
-
380
- it("should allow sign-in after sign-out", async () => {
381
- const mockResult1 = createSiwxResult({ signature: "0xfirst" });
382
- const mockResult2 = createSiwxResult({ signature: "0xsecond" });
383
- const mockSignIn = vi.fn()
384
- .mockResolvedValueOnce(mockResult1)
385
- .mockResolvedValueOnce(mockResult2);
386
- mockUseSignInWithX.mockReturnValue({
387
- signIn: mockSignIn,
388
- isSigningIn: false,
389
- result: null,
390
- error: null,
391
- clearError: vi.fn(),
392
- });
393
-
394
- const { result } = renderHook(() => useSiwxAuthSession({ autoRestore: false }));
395
-
396
- // Sign in first time
397
- await act(async () => {
398
- await result.current.signIn({ statement: "First" });
399
- });
400
- expect(result.current.siwxResult!.signature).toBe("0xfirst");
401
-
402
- // Sign out
403
- await act(async () => {
404
- result.current.signOut();
405
- });
406
- expect(result.current.isSignedIn).toBe(false);
407
-
408
- // Sign in again
409
- await act(async () => {
410
- await result.current.signIn({ statement: "Second" });
411
- });
412
- expect(result.current.siwxResult!.signature).toBe("0xsecond");
413
- });
414
-
415
- it("should restore auth with custom prefix", async () => {
416
- const siwxResult = createSiwxResult();
417
- localStorage.setItem("custom_siwx_auth", JSON.stringify(siwxResult));
418
-
419
- const { result } = renderHook(() =>
420
- useSiwxAuthSession({ storagePrefix: "custom_" })
421
- );
422
-
423
- await waitFor(() => {
424
- expect(result.current.isSignedIn).toBe(true);
425
- });
426
- });
427
-
428
- it("should clear error via clearError", async () => {
429
- const mockSignIn = vi.fn().mockRejectedValue(new Error("Something went wrong"));
430
- mockUseSignInWithX.mockReturnValue({
431
- signIn: mockSignIn,
432
- isSigningIn: false,
433
- result: null,
434
- error: null,
435
- clearError: vi.fn(),
436
- });
437
-
438
- const { result } = renderHook(() => useSiwxAuthSession({ autoRestore: false }));
439
-
440
- await act(async () => {
441
- try {
442
- await result.current.signIn();
443
- } catch {
444
- // expected
445
- }
446
- });
447
-
448
- expect(result.current.error).not.toBeNull();
449
-
450
- act(() => {
451
- result.current.clearError();
452
- });
453
-
454
- expect(result.current.error).toBeNull();
455
- });
456
- });