@pasosdejesus/m 0.24.0 → 0.25.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/CHANGELOG.md +16 -1
- package/dist/i18n/locales/cli.d.ts.map +1 -1
- package/dist/i18n/locales/cli.js +2 -0
- package/dist/i18n/locales/cli.js.map +1 -1
- package/dist/m.js +7 -1
- package/dist/m.js.map +1 -1
- package/dist/tasks/e2e-summary.d.ts +13 -0
- package/dist/tasks/e2e-summary.d.ts.map +1 -0
- package/dist/tasks/e2e-summary.js +117 -0
- package/dist/tasks/e2e-summary.js.map +1 -0
- package/dist/tasks/e2e.d.ts +29 -0
- package/dist/tasks/e2e.d.ts.map +1 -1
- package/dist/tasks/e2e.js +130 -36
- package/dist/tasks/e2e.js.map +1 -1
- package/dist/tasks/e2e.test.d.ts +2 -0
- package/dist/tasks/e2e.test.d.ts.map +1 -0
- package/dist/tasks/e2e.test.js +108 -0
- package/dist/tasks/e2e.test.js.map +1 -0
- package/dist/wallet/next/components/InAppWalletSetup.d.ts +11 -0
- package/dist/wallet/next/components/InAppWalletSetup.d.ts.map +1 -0
- package/dist/wallet/next/components/InAppWalletSetup.js +55 -0
- package/dist/wallet/next/components/InAppWalletSetup.js.map +1 -0
- package/dist/wallet/next/components/InAppWalletUnlock.d.ts +9 -0
- package/dist/wallet/next/components/InAppWalletUnlock.d.ts.map +1 -0
- package/dist/wallet/next/components/InAppWalletUnlock.js +29 -0
- package/dist/wallet/next/components/InAppWalletUnlock.js.map +1 -0
- package/dist/wallet/next/components.test.d.ts +2 -0
- package/dist/wallet/next/components.test.d.ts.map +1 -0
- package/dist/wallet/next/components.test.js +122 -0
- package/dist/wallet/next/components.test.js.map +1 -0
- package/dist/wallet/next/i18n.d.ts +63 -0
- package/dist/wallet/next/i18n.d.ts.map +1 -0
- package/dist/wallet/next/i18n.js +64 -0
- package/dist/wallet/next/i18n.js.map +1 -0
- package/dist/wallet/next/index.d.ts +7 -0
- package/dist/wallet/next/index.d.ts.map +1 -0
- package/dist/wallet/next/index.js +12 -0
- package/dist/wallet/next/index.js.map +1 -0
- package/dist/wallet/next/namespaces.d.ts +17 -0
- package/dist/wallet/next/namespaces.d.ts.map +1 -0
- package/dist/wallet/next/namespaces.js +17 -0
- package/dist/wallet/next/namespaces.js.map +1 -0
- package/dist/wallet/next/useInAppWallet.d.ts +55 -0
- package/dist/wallet/next/useInAppWallet.d.ts.map +1 -0
- package/dist/wallet/next/useInAppWallet.js +261 -0
- package/dist/wallet/next/useInAppWallet.js.map +1 -0
- package/dist/wallet/next/useInAppWallet.test.d.ts +2 -0
- package/dist/wallet/next/useInAppWallet.test.d.ts.map +1 -0
- package/dist/wallet/next/useInAppWallet.test.js +261 -0
- package/dist/wallet/next/useInAppWallet.test.js.map +1 -0
- package/package.json +5 -1
- package/src/e2e/README.md +16 -0
- package/src/wallet/README.md +25 -2
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { useCallback, useEffect, useSyncExternalStore } from 'react';
|
|
3
|
+
import { createWallet, deleteWallet, detectPlatformSupport, disableBiometricUnlock, emitAccountsChanged, enableBiometricUnlock, getInAppWalletProvider, getWalletInfo, hasBiometricUnlock, hasWallet, importWallet, lockWallet, unlockWallet, unlockWithBiometric as unlockWithBiometricCore, } from '../index.js';
|
|
4
|
+
/**
|
|
5
|
+
* Auto-lock after this much inactivity, like OneKey and OKX Web3 (R-#246).
|
|
6
|
+
* Dropping the key means the next action asks for the gesture (or the password on
|
|
7
|
+
* devices without WebAuthn).
|
|
8
|
+
*
|
|
9
|
+
* One hour, not ten minutes: the operator's mobile test had to unlock again
|
|
10
|
+
* while donating on `/[lang]/gdcluster/ranking` less than ten minutes after
|
|
11
|
+
* unlocking, and OneKey waits about an hour after its own fingerprint prompt.
|
|
12
|
+
* The value only bounds how long the in-memory key survives a pause; moving
|
|
13
|
+
* funds is always gated by layer L1 (a fresh gesture), so a longer pause cannot
|
|
14
|
+
* make a transfer silent. An operator or the user changing the value is
|
|
15
|
+
* https://github.com/pasosdeJesus/learn.tg/issues/248.
|
|
16
|
+
*/
|
|
17
|
+
export const INACTIVITY_LOCK_MS = 60 * 60 * 1000;
|
|
18
|
+
// Distinto de `USER_VERIFICATION_GRACE_MS` del core (15 min, R-#253): el auto-lock
|
|
19
|
+
// es por inactividad (una hora) y, al llamar a `lockWallet()`, cierra la ventana de
|
|
20
|
+
// gracia para que el próximo movimiento vuelva a pedir el gesto.
|
|
21
|
+
/**
|
|
22
|
+
* Minimum time between two inactivity resets. Activity events arrive in bursts
|
|
23
|
+
* (a scroll fires dozens of them), and restarting the timer on each one is
|
|
24
|
+
* wasted work on the low-end phones this audience uses.
|
|
25
|
+
*/
|
|
26
|
+
const ACTIVITY_RESET_THROTTLE_MS = 5 * 1000;
|
|
27
|
+
const initialState = {
|
|
28
|
+
status: 'loading',
|
|
29
|
+
walletInfo: null,
|
|
30
|
+
error: null,
|
|
31
|
+
biometricAvailable: false,
|
|
32
|
+
biometricEnabled: false,
|
|
33
|
+
lockReason: 'initial',
|
|
34
|
+
};
|
|
35
|
+
// Estado compartido por todas las instancias del hook. Sin esto, cada componente
|
|
36
|
+
// que llama a `useInAppWallet()` tiene su propia copia: `InAppWalletSetup`
|
|
37
|
+
// desbloquea la billetera y el consumidor (p. ej. `WalletSelector`) sigue viendo
|
|
38
|
+
// `locked`, de modo que la interfaz parece no hacer nada.
|
|
39
|
+
let state = initialState;
|
|
40
|
+
let initialized = false;
|
|
41
|
+
const listeners = new Set();
|
|
42
|
+
function setState(partial) {
|
|
43
|
+
state = { ...state, ...partial };
|
|
44
|
+
for (const listener of listeners)
|
|
45
|
+
listener();
|
|
46
|
+
}
|
|
47
|
+
function subscribe(listener) {
|
|
48
|
+
listeners.add(listener);
|
|
49
|
+
return () => {
|
|
50
|
+
listeners.delete(listener);
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
function getSnapshot() {
|
|
54
|
+
return state;
|
|
55
|
+
}
|
|
56
|
+
function getServerSnapshot() {
|
|
57
|
+
return initialState;
|
|
58
|
+
}
|
|
59
|
+
/** Reads the stored wallet once per page load, whoever asks first. */
|
|
60
|
+
async function initialize() {
|
|
61
|
+
if (initialized)
|
|
62
|
+
return;
|
|
63
|
+
initialized = true;
|
|
64
|
+
if (typeof window === 'undefined' || !window.indexedDB) {
|
|
65
|
+
setState({ status: 'no-wallet', walletInfo: null });
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
try {
|
|
69
|
+
const exists = await hasWallet();
|
|
70
|
+
if (!exists) {
|
|
71
|
+
setState({ status: 'no-wallet', walletInfo: null });
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
const info = await getWalletInfo();
|
|
75
|
+
// R-#246: the unlock lives in module memory. A reload locks the wallet again,
|
|
76
|
+
// which is why the biometric path exists: one gesture instead of the password.
|
|
77
|
+
let biometricEnabled = false;
|
|
78
|
+
try {
|
|
79
|
+
biometricEnabled = await hasBiometricUnlock();
|
|
80
|
+
}
|
|
81
|
+
catch {
|
|
82
|
+
biometricEnabled = false;
|
|
83
|
+
}
|
|
84
|
+
let biometricAvailable = false;
|
|
85
|
+
if (biometricEnabled) {
|
|
86
|
+
biometricAvailable = true;
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
89
|
+
try {
|
|
90
|
+
const support = await detectPlatformSupport();
|
|
91
|
+
// `prf: null` means "the engine did not say": we only know for sure after
|
|
92
|
+
// creating a credential, so treat it as possibly available.
|
|
93
|
+
biometricAvailable = support.userVerifying && support.prf !== false;
|
|
94
|
+
}
|
|
95
|
+
catch {
|
|
96
|
+
biometricAvailable = false;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
setState({
|
|
100
|
+
walletInfo: info,
|
|
101
|
+
status: state.status === 'unlocked' ? 'unlocked' : 'locked',
|
|
102
|
+
biometricEnabled,
|
|
103
|
+
biometricAvailable,
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
catch {
|
|
107
|
+
setState({ status: 'no-wallet', walletInfo: null });
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
/** Test-only: forgets the shared state and the "already initialized" flag. */
|
|
111
|
+
export function resetInAppWalletStoreForTests() {
|
|
112
|
+
state = initialState;
|
|
113
|
+
initialized = false;
|
|
114
|
+
for (const listener of listeners)
|
|
115
|
+
listener();
|
|
116
|
+
}
|
|
117
|
+
export function useInAppWallet() {
|
|
118
|
+
const snapshot = useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);
|
|
119
|
+
useEffect(() => {
|
|
120
|
+
void initialize();
|
|
121
|
+
}, []);
|
|
122
|
+
const create = useCallback(async (password) => {
|
|
123
|
+
setState({ error: null });
|
|
124
|
+
try {
|
|
125
|
+
const result = await createWallet({ password });
|
|
126
|
+
setState({ walletInfo: result.walletInfo, status: 'unlocked' });
|
|
127
|
+
return result;
|
|
128
|
+
}
|
|
129
|
+
catch (e) {
|
|
130
|
+
setState({ error: e instanceof Error ? e.message : String(e) });
|
|
131
|
+
throw e;
|
|
132
|
+
}
|
|
133
|
+
}, []);
|
|
134
|
+
const importExisting = useCallback(async (options) => {
|
|
135
|
+
setState({ error: null });
|
|
136
|
+
try {
|
|
137
|
+
const info = await importWallet(options);
|
|
138
|
+
setState({ walletInfo: info, status: 'unlocked' });
|
|
139
|
+
return info;
|
|
140
|
+
}
|
|
141
|
+
catch (e) {
|
|
142
|
+
setState({ error: e instanceof Error ? e.message : String(e) });
|
|
143
|
+
throw e;
|
|
144
|
+
}
|
|
145
|
+
}, []);
|
|
146
|
+
const unlock = useCallback(async (password) => {
|
|
147
|
+
setState({ error: null });
|
|
148
|
+
try {
|
|
149
|
+
const info = await unlockWallet(password);
|
|
150
|
+
setState({ walletInfo: info, status: 'unlocked' });
|
|
151
|
+
return info;
|
|
152
|
+
}
|
|
153
|
+
catch (e) {
|
|
154
|
+
setState({ error: e instanceof Error ? e.message : String(e) });
|
|
155
|
+
throw e;
|
|
156
|
+
}
|
|
157
|
+
}, []);
|
|
158
|
+
const unlockWithBiometric = useCallback(async () => {
|
|
159
|
+
setState({ error: null });
|
|
160
|
+
try {
|
|
161
|
+
const info = await unlockWithBiometricCore();
|
|
162
|
+
setState({ walletInfo: info, status: 'unlocked' });
|
|
163
|
+
return info;
|
|
164
|
+
}
|
|
165
|
+
catch (e) {
|
|
166
|
+
setState({ error: e instanceof Error ? e.message : String(e) });
|
|
167
|
+
throw e;
|
|
168
|
+
}
|
|
169
|
+
}, []);
|
|
170
|
+
const enableBiometric = useCallback(async (password) => {
|
|
171
|
+
setState({ error: null });
|
|
172
|
+
try {
|
|
173
|
+
await enableBiometricUnlock(password);
|
|
174
|
+
setState({ biometricEnabled: true, biometricAvailable: true });
|
|
175
|
+
}
|
|
176
|
+
catch (e) {
|
|
177
|
+
setState({ error: e instanceof Error ? e.message : String(e) });
|
|
178
|
+
throw e;
|
|
179
|
+
}
|
|
180
|
+
}, []);
|
|
181
|
+
const disableBiometric = useCallback(async () => {
|
|
182
|
+
setState({ error: null });
|
|
183
|
+
try {
|
|
184
|
+
await disableBiometricUnlock();
|
|
185
|
+
setState({ biometricEnabled: false });
|
|
186
|
+
}
|
|
187
|
+
catch (e) {
|
|
188
|
+
setState({ error: e instanceof Error ? e.message : String(e) });
|
|
189
|
+
throw e;
|
|
190
|
+
}
|
|
191
|
+
}, []);
|
|
192
|
+
const lock = useCallback(async () => {
|
|
193
|
+
await lockWallet();
|
|
194
|
+
// R-#236: quien esté suscrito al proveedor se entera de que la sesión terminó.
|
|
195
|
+
emitAccountsChanged([]);
|
|
196
|
+
setState({ status: 'locked', lockReason: 'user' });
|
|
197
|
+
}, []);
|
|
198
|
+
const remove = useCallback(async () => {
|
|
199
|
+
await deleteWallet();
|
|
200
|
+
emitAccountsChanged([]);
|
|
201
|
+
setState({ walletInfo: null, status: 'no-wallet', biometricEnabled: false, lockReason: 'deleted' });
|
|
202
|
+
}, []);
|
|
203
|
+
// R-#246: auto-lock tras inactividad (como OneKey y OKX). Suelta la clave en
|
|
204
|
+
// memoria; NO cierra la sesión (el motivo lo distingue `WalletEventListener`).
|
|
205
|
+
// `visibilitychange` se escucha en `document` (no burbujea hasta `window`, que
|
|
206
|
+
// era el defecto que dejaba el temporizador corriendo en el teléfono), y el
|
|
207
|
+
// reinicio se limita a uno cada pocos segundos para que `scroll` no lo agite.
|
|
208
|
+
useEffect(() => {
|
|
209
|
+
if (snapshot.status !== 'unlocked')
|
|
210
|
+
return;
|
|
211
|
+
const lockForIdle = () => {
|
|
212
|
+
void lockWallet();
|
|
213
|
+
emitAccountsChanged([]);
|
|
214
|
+
setState({ status: 'locked', lockReason: 'idle' });
|
|
215
|
+
};
|
|
216
|
+
let timer = window.setTimeout(lockForIdle, INACTIVITY_LOCK_MS);
|
|
217
|
+
let lastReset = Date.now();
|
|
218
|
+
const reset = () => {
|
|
219
|
+
const now = Date.now();
|
|
220
|
+
if (now - lastReset < ACTIVITY_RESET_THROTTLE_MS)
|
|
221
|
+
return;
|
|
222
|
+
lastReset = now;
|
|
223
|
+
window.clearTimeout(timer);
|
|
224
|
+
timer = window.setTimeout(lockForIdle, INACTIVITY_LOCK_MS);
|
|
225
|
+
};
|
|
226
|
+
const events = ['pointerdown', 'keydown', 'touchstart', 'click', 'scroll'];
|
|
227
|
+
for (const name of events) {
|
|
228
|
+
window.addEventListener(name, reset, { passive: true });
|
|
229
|
+
}
|
|
230
|
+
const onVisibilityChange = () => {
|
|
231
|
+
lastReset = 0;
|
|
232
|
+
reset();
|
|
233
|
+
};
|
|
234
|
+
document.addEventListener('visibilitychange', onVisibilityChange);
|
|
235
|
+
return () => {
|
|
236
|
+
window.clearTimeout(timer);
|
|
237
|
+
for (const name of events)
|
|
238
|
+
window.removeEventListener(name, reset);
|
|
239
|
+
document.removeEventListener('visibilitychange', onVisibilityChange);
|
|
240
|
+
};
|
|
241
|
+
}, [snapshot.status]);
|
|
242
|
+
const getProvider = useCallback((rpcUrl) => getInAppWalletProvider({ rpcUrl }), []);
|
|
243
|
+
return {
|
|
244
|
+
status: snapshot.status,
|
|
245
|
+
walletInfo: snapshot.walletInfo,
|
|
246
|
+
error: snapshot.error,
|
|
247
|
+
biometricAvailable: snapshot.biometricAvailable,
|
|
248
|
+
biometricEnabled: snapshot.biometricEnabled,
|
|
249
|
+
lockReason: snapshot.lockReason,
|
|
250
|
+
create,
|
|
251
|
+
importExisting,
|
|
252
|
+
unlock,
|
|
253
|
+
unlockWithBiometric,
|
|
254
|
+
enableBiometric,
|
|
255
|
+
disableBiometric,
|
|
256
|
+
lock,
|
|
257
|
+
remove,
|
|
258
|
+
getProvider,
|
|
259
|
+
};
|
|
260
|
+
}
|
|
261
|
+
//# sourceMappingURL=useInAppWallet.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useInAppWallet.js","sourceRoot":"","sources":["../../../src/wallet/next/useInAppWallet.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useInAppWallet.test.d.ts","sourceRoot":"","sources":["../../../src/wallet/next/useInAppWallet.test.tsx"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
// @vitest-environment jsdom
|
|
2
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
3
|
+
import { act, cleanup, renderHook, waitFor } from '@testing-library/react';
|
|
4
|
+
afterEach(cleanup);
|
|
5
|
+
const walletMock = vi.hoisted(() => ({
|
|
6
|
+
hasWallet: vi.fn(),
|
|
7
|
+
getWalletInfo: vi.fn(),
|
|
8
|
+
createWallet: vi.fn(),
|
|
9
|
+
importWallet: vi.fn(),
|
|
10
|
+
unlockWallet: vi.fn(),
|
|
11
|
+
unlockWithBiometric: vi.fn(),
|
|
12
|
+
enableBiometricUnlock: vi.fn(),
|
|
13
|
+
disableBiometricUnlock: vi.fn(),
|
|
14
|
+
hasBiometricUnlock: vi.fn(),
|
|
15
|
+
detectPlatformSupport: vi.fn(),
|
|
16
|
+
lockWallet: vi.fn(),
|
|
17
|
+
deleteWallet: vi.fn(),
|
|
18
|
+
getInAppWalletProvider: vi.fn(),
|
|
19
|
+
// R-#236: avisa a quien esté suscrito al proveedor cuando la billetera se bloquea.
|
|
20
|
+
emitAccountsChanged: vi.fn(),
|
|
21
|
+
setWalletDbName: vi.fn(),
|
|
22
|
+
setDestinationsPrefix: vi.fn(),
|
|
23
|
+
setRpName: vi.fn(),
|
|
24
|
+
}));
|
|
25
|
+
vi.mock('../index.js', () => walletMock);
|
|
26
|
+
import { useInAppWallet, resetInAppWalletStoreForTests, INACTIVITY_LOCK_MS } from './useInAppWallet.js';
|
|
27
|
+
const ADDRESS = '0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266';
|
|
28
|
+
const INFO = { address: ADDRESS, chain: 'celoSepolia', createdAt: 1 };
|
|
29
|
+
describe('useInAppWallet', () => {
|
|
30
|
+
beforeEach(() => {
|
|
31
|
+
vi.clearAllMocks();
|
|
32
|
+
resetInAppWalletStoreForTests();
|
|
33
|
+
walletMock.hasBiometricUnlock.mockResolvedValue(false);
|
|
34
|
+
walletMock.detectPlatformSupport.mockResolvedValue({ webauthn: false, userVerifying: false, prf: null });
|
|
35
|
+
globalThis.indexedDB = {};
|
|
36
|
+
window.indexedDB = {};
|
|
37
|
+
});
|
|
38
|
+
it('reports no-wallet when there is nothing stored', async () => {
|
|
39
|
+
walletMock.hasWallet.mockResolvedValue(false);
|
|
40
|
+
const { result } = renderHook(() => useInAppWallet());
|
|
41
|
+
await waitFor(() => expect(result.current.status).toBe('no-wallet'));
|
|
42
|
+
expect(result.current.walletInfo).toBeNull();
|
|
43
|
+
});
|
|
44
|
+
it('reports locked when a wallet exists', async () => {
|
|
45
|
+
walletMock.hasWallet.mockResolvedValue(true);
|
|
46
|
+
walletMock.getWalletInfo.mockResolvedValue(INFO);
|
|
47
|
+
const { result } = renderHook(() => useInAppWallet());
|
|
48
|
+
await waitFor(() => expect(result.current.status).toBe('locked'));
|
|
49
|
+
expect(result.current.walletInfo?.address).toBe(ADDRESS);
|
|
50
|
+
});
|
|
51
|
+
it('reports the biometric capability of the device', async () => {
|
|
52
|
+
walletMock.hasWallet.mockResolvedValue(true);
|
|
53
|
+
walletMock.getWalletInfo.mockResolvedValue(INFO);
|
|
54
|
+
walletMock.detectPlatformSupport.mockResolvedValue({ webauthn: true, userVerifying: true, prf: true });
|
|
55
|
+
const { result } = renderHook(() => useInAppWallet());
|
|
56
|
+
await waitFor(() => expect(result.current.status).toBe('locked'));
|
|
57
|
+
expect(result.current.biometricAvailable).toBe(true);
|
|
58
|
+
expect(result.current.biometricEnabled).toBe(false);
|
|
59
|
+
});
|
|
60
|
+
it('stays locked and password-only on devices without WebAuthn', async () => {
|
|
61
|
+
walletMock.hasWallet.mockResolvedValue(true);
|
|
62
|
+
walletMock.getWalletInfo.mockResolvedValue(INFO);
|
|
63
|
+
walletMock.detectPlatformSupport.mockResolvedValue({ webauthn: false, userVerifying: false, prf: null });
|
|
64
|
+
const { result } = renderHook(() => useInAppWallet());
|
|
65
|
+
await waitFor(() => expect(result.current.status).toBe('locked'));
|
|
66
|
+
expect(result.current.biometricAvailable).toBe(false);
|
|
67
|
+
});
|
|
68
|
+
it('reports biometric as enabled when a sealed key exists', async () => {
|
|
69
|
+
walletMock.hasWallet.mockResolvedValue(true);
|
|
70
|
+
walletMock.getWalletInfo.mockResolvedValue(INFO);
|
|
71
|
+
walletMock.hasBiometricUnlock.mockResolvedValue(true);
|
|
72
|
+
const { result } = renderHook(() => useInAppWallet());
|
|
73
|
+
await waitFor(() => expect(result.current.status).toBe('locked'));
|
|
74
|
+
expect(result.current.biometricEnabled).toBe(true);
|
|
75
|
+
expect(result.current.biometricAvailable).toBe(true);
|
|
76
|
+
});
|
|
77
|
+
it('unlocks with one gesture', async () => {
|
|
78
|
+
walletMock.hasWallet.mockResolvedValue(true);
|
|
79
|
+
walletMock.getWalletInfo.mockResolvedValue(INFO);
|
|
80
|
+
walletMock.hasBiometricUnlock.mockResolvedValue(true);
|
|
81
|
+
walletMock.unlockWithBiometric.mockResolvedValue(INFO);
|
|
82
|
+
const { result } = renderHook(() => useInAppWallet());
|
|
83
|
+
await waitFor(() => expect(result.current.status).toBe('locked'));
|
|
84
|
+
await act(async () => {
|
|
85
|
+
await result.current.unlockWithBiometric();
|
|
86
|
+
});
|
|
87
|
+
expect(result.current.status).toBe('unlocked');
|
|
88
|
+
expect(result.current.walletInfo?.address).toBe(ADDRESS);
|
|
89
|
+
});
|
|
90
|
+
it('records the error and keeps the wallet locked when the gesture fails', async () => {
|
|
91
|
+
walletMock.hasWallet.mockResolvedValue(true);
|
|
92
|
+
walletMock.getWalletInfo.mockResolvedValue(INFO);
|
|
93
|
+
walletMock.unlockWithBiometric.mockRejectedValue(new Error('auth-failed'));
|
|
94
|
+
const { result } = renderHook(() => useInAppWallet());
|
|
95
|
+
await waitFor(() => expect(result.current.status).toBe('locked'));
|
|
96
|
+
await act(async () => {
|
|
97
|
+
await expect(result.current.unlockWithBiometric()).rejects.toThrow('auth-failed');
|
|
98
|
+
});
|
|
99
|
+
expect(result.current.status).toBe('locked');
|
|
100
|
+
expect(result.current.error).toBe('auth-failed');
|
|
101
|
+
});
|
|
102
|
+
it('enables and disables the biometric unlock', async () => {
|
|
103
|
+
walletMock.hasWallet.mockResolvedValue(true);
|
|
104
|
+
walletMock.getWalletInfo.mockResolvedValue(INFO);
|
|
105
|
+
const { result } = renderHook(() => useInAppWallet());
|
|
106
|
+
await waitFor(() => expect(result.current.status).toBe('locked'));
|
|
107
|
+
await act(async () => {
|
|
108
|
+
await result.current.enableBiometric('123456');
|
|
109
|
+
});
|
|
110
|
+
expect(walletMock.enableBiometricUnlock).toHaveBeenCalledWith('123456');
|
|
111
|
+
expect(result.current.biometricEnabled).toBe(true);
|
|
112
|
+
await act(async () => {
|
|
113
|
+
await result.current.disableBiometric();
|
|
114
|
+
});
|
|
115
|
+
expect(result.current.biometricEnabled).toBe(false);
|
|
116
|
+
});
|
|
117
|
+
it('goes to unlocked after creating a wallet', async () => {
|
|
118
|
+
walletMock.hasWallet.mockResolvedValue(false);
|
|
119
|
+
walletMock.createWallet.mockResolvedValue({ walletInfo: INFO, mnemonic: 'one two three' });
|
|
120
|
+
const { result } = renderHook(() => useInAppWallet());
|
|
121
|
+
await waitFor(() => expect(result.current.status).toBe('no-wallet'));
|
|
122
|
+
await act(async () => {
|
|
123
|
+
await result.current.create('123456');
|
|
124
|
+
});
|
|
125
|
+
expect(result.current.status).toBe('unlocked');
|
|
126
|
+
expect(result.current.walletInfo?.address).toBe(ADDRESS);
|
|
127
|
+
});
|
|
128
|
+
it('locks the wallet after inactivity and marks the reason as idle', async () => {
|
|
129
|
+
vi.useFakeTimers();
|
|
130
|
+
try {
|
|
131
|
+
walletMock.hasWallet.mockResolvedValue(true);
|
|
132
|
+
walletMock.getWalletInfo.mockResolvedValue(INFO);
|
|
133
|
+
walletMock.unlockWallet.mockResolvedValue(INFO);
|
|
134
|
+
const { result } = renderHook(() => useInAppWallet());
|
|
135
|
+
await act(async () => {
|
|
136
|
+
await vi.advanceTimersByTimeAsync(0);
|
|
137
|
+
});
|
|
138
|
+
await act(async () => {
|
|
139
|
+
await result.current.unlock('123456');
|
|
140
|
+
});
|
|
141
|
+
expect(result.current.status).toBe('unlocked');
|
|
142
|
+
await act(async () => {
|
|
143
|
+
await vi.advanceTimersByTimeAsync(INACTIVITY_LOCK_MS + 1);
|
|
144
|
+
});
|
|
145
|
+
expect(walletMock.lockWallet).toHaveBeenCalled();
|
|
146
|
+
expect(result.current.status).toBe('locked');
|
|
147
|
+
expect(result.current.lockReason).toBe('idle');
|
|
148
|
+
}
|
|
149
|
+
finally {
|
|
150
|
+
vi.useRealTimers();
|
|
151
|
+
}
|
|
152
|
+
});
|
|
153
|
+
it('restarts the inactivity timer when the tab becomes visible again', async () => {
|
|
154
|
+
vi.useFakeTimers();
|
|
155
|
+
try {
|
|
156
|
+
walletMock.hasWallet.mockResolvedValue(true);
|
|
157
|
+
walletMock.getWalletInfo.mockResolvedValue(INFO);
|
|
158
|
+
walletMock.unlockWallet.mockResolvedValue(INFO);
|
|
159
|
+
const { result } = renderHook(() => useInAppWallet());
|
|
160
|
+
await act(async () => {
|
|
161
|
+
await vi.advanceTimersByTimeAsync(0);
|
|
162
|
+
});
|
|
163
|
+
await act(async () => {
|
|
164
|
+
await result.current.unlock('123456');
|
|
165
|
+
});
|
|
166
|
+
await act(async () => {
|
|
167
|
+
await vi.advanceTimersByTimeAsync(INACTIVITY_LOCK_MS - 1000);
|
|
168
|
+
});
|
|
169
|
+
document.dispatchEvent(new Event('visibilitychange'));
|
|
170
|
+
await act(async () => {
|
|
171
|
+
await vi.advanceTimersByTimeAsync(2000);
|
|
172
|
+
});
|
|
173
|
+
expect(result.current.status).toBe('unlocked');
|
|
174
|
+
await act(async () => {
|
|
175
|
+
await vi.advanceTimersByTimeAsync(INACTIVITY_LOCK_MS);
|
|
176
|
+
});
|
|
177
|
+
expect(result.current.status).toBe('locked');
|
|
178
|
+
}
|
|
179
|
+
finally {
|
|
180
|
+
vi.useRealTimers();
|
|
181
|
+
}
|
|
182
|
+
});
|
|
183
|
+
it('marks the reason as user when the header ✕ locks it', async () => {
|
|
184
|
+
walletMock.hasWallet.mockResolvedValue(true);
|
|
185
|
+
walletMock.getWalletInfo.mockResolvedValue(INFO);
|
|
186
|
+
walletMock.unlockWallet.mockResolvedValue(INFO);
|
|
187
|
+
const { result } = renderHook(() => useInAppWallet());
|
|
188
|
+
await waitFor(() => expect(result.current.status).toBe('locked'));
|
|
189
|
+
await act(async () => {
|
|
190
|
+
await result.current.unlock('123456');
|
|
191
|
+
});
|
|
192
|
+
await act(async () => {
|
|
193
|
+
await result.current.lock();
|
|
194
|
+
});
|
|
195
|
+
expect(result.current.lockReason).toBe('user');
|
|
196
|
+
});
|
|
197
|
+
it('goes to unlocked after importing and back to locked after locking', async () => {
|
|
198
|
+
walletMock.hasWallet.mockResolvedValue(false);
|
|
199
|
+
walletMock.importWallet.mockResolvedValue(INFO);
|
|
200
|
+
const { result } = renderHook(() => useInAppWallet());
|
|
201
|
+
await waitFor(() => expect(result.current.status).toBe('no-wallet'));
|
|
202
|
+
await act(async () => {
|
|
203
|
+
await result.current.importExisting({ mnemonic: 'one two three', password: '123456' });
|
|
204
|
+
});
|
|
205
|
+
expect(result.current.status).toBe('unlocked');
|
|
206
|
+
expect(walletMock.importWallet).toHaveBeenCalledWith({ mnemonic: 'one two three', password: '123456' });
|
|
207
|
+
await act(async () => {
|
|
208
|
+
await result.current.lock();
|
|
209
|
+
});
|
|
210
|
+
expect(result.current.status).toBe('locked');
|
|
211
|
+
expect(result.current.walletInfo?.address).toBe(ADDRESS);
|
|
212
|
+
});
|
|
213
|
+
it('records the error and rethrows when unlocking fails', async () => {
|
|
214
|
+
walletMock.hasWallet.mockResolvedValue(true);
|
|
215
|
+
walletMock.getWalletInfo.mockResolvedValue(INFO);
|
|
216
|
+
walletMock.unlockWallet.mockRejectedValue(new Error('Wrong password or corrupted wallet data'));
|
|
217
|
+
const { result } = renderHook(() => useInAppWallet());
|
|
218
|
+
await waitFor(() => expect(result.current.status).toBe('locked'));
|
|
219
|
+
await act(async () => {
|
|
220
|
+
await expect(result.current.unlock('000000')).rejects.toThrow(/Wrong password/);
|
|
221
|
+
});
|
|
222
|
+
expect(result.current.error).toMatch(/Wrong password/);
|
|
223
|
+
});
|
|
224
|
+
it('takes the provider from the core package', async () => {
|
|
225
|
+
walletMock.hasWallet.mockResolvedValue(false);
|
|
226
|
+
const provider = { request: vi.fn() };
|
|
227
|
+
walletMock.getInAppWalletProvider.mockReturnValue(provider);
|
|
228
|
+
const { result } = renderHook(() => useInAppWallet());
|
|
229
|
+
await waitFor(() => expect(result.current.status).toBe('no-wallet'));
|
|
230
|
+
expect(result.current.getProvider()).toBe(provider);
|
|
231
|
+
});
|
|
232
|
+
it('removes the wallet', async () => {
|
|
233
|
+
walletMock.hasWallet.mockResolvedValue(true);
|
|
234
|
+
walletMock.getWalletInfo.mockResolvedValue(INFO);
|
|
235
|
+
const { result } = renderHook(() => useInAppWallet());
|
|
236
|
+
await waitFor(() => expect(result.current.status).toBe('locked'));
|
|
237
|
+
await act(async () => {
|
|
238
|
+
await result.current.remove();
|
|
239
|
+
});
|
|
240
|
+
expect(walletMock.deleteWallet).toHaveBeenCalled();
|
|
241
|
+
expect(result.current.status).toBe('no-wallet');
|
|
242
|
+
});
|
|
243
|
+
it('shares the state between instances (setup and consumer agree)', async () => {
|
|
244
|
+
walletMock.hasWallet.mockResolvedValue(false);
|
|
245
|
+
walletMock.createWallet.mockResolvedValue({ walletInfo: INFO, mnemonic: 'one two three' });
|
|
246
|
+
const setup = renderHook(() => useInAppWallet());
|
|
247
|
+
const consumer = renderHook(() => useInAppWallet());
|
|
248
|
+
await waitFor(() => expect(consumer.result.current.status).toBe('no-wallet'));
|
|
249
|
+
await act(async () => {
|
|
250
|
+
await setup.result.current.create('123456');
|
|
251
|
+
});
|
|
252
|
+
expect(setup.result.current.status).toBe('unlocked');
|
|
253
|
+
expect(consumer.result.current.status).toBe('unlocked');
|
|
254
|
+
expect(consumer.result.current.walletInfo?.address).toBe(ADDRESS);
|
|
255
|
+
await act(async () => {
|
|
256
|
+
await consumer.result.current.lock();
|
|
257
|
+
});
|
|
258
|
+
expect(setup.result.current.status).toBe('locked');
|
|
259
|
+
});
|
|
260
|
+
});
|
|
261
|
+
//# sourceMappingURL=useInAppWallet.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useInAppWallet.test.js","sourceRoot":"","sources":["../../../src/wallet/next/useInAppWallet.test.tsx"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pasosdejesus/m",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.25.0",
|
|
4
4
|
"description": "Motor para crear y gestionar proyectos al estilo Pasos de Jesus.",
|
|
5
5
|
"author": "",
|
|
6
6
|
"license": "ISC",
|
|
@@ -108,6 +108,10 @@
|
|
|
108
108
|
"import": "./dist/wallet/index.js",
|
|
109
109
|
"types": "./dist/wallet/index.d.ts"
|
|
110
110
|
},
|
|
111
|
+
"./wallet/next": {
|
|
112
|
+
"import": "./dist/wallet/next/index.js",
|
|
113
|
+
"types": "./dist/wallet/next/index.d.ts"
|
|
114
|
+
},
|
|
111
115
|
"./wallet/storage": {
|
|
112
116
|
"import": "./dist/wallet/storage/index.js",
|
|
113
117
|
"types": "./dist/wallet/storage/index.d.ts"
|
package/src/e2e/README.md
CHANGED
|
@@ -151,6 +151,22 @@ Lessons that cost time here (see also learn.tg's `doc/e2e-testing.md`):
|
|
|
151
151
|
- **Receipt hashes**: the local node re-signs, so `setupFullWalletMock` re-keys the receipt
|
|
152
152
|
under `keccak256(rawTransaction)` (the hash viem waits for).
|
|
153
153
|
|
|
154
|
+
### Runner: retry and summary (`m/REQ/49` P3/P4)
|
|
155
|
+
|
|
156
|
+
```sh
|
|
157
|
+
./bin/m test:e2e --retry 2 --retry-delay 15000 # re-run failed specs (fresh WALLET_INDEX each)
|
|
158
|
+
./bin/m test:e2e:summary /tmp/site.log /tmp/local.log # compare two runs
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
- `--retry <N>` (default 0, or `E2E_RETRIES`): after the first pass, each failed spec is re-run
|
|
162
|
+
on its own up to N times; a spec is green **only by exit code**.
|
|
163
|
+
- `--retry-delay <ms>` (default 15000): pause before each retry round.
|
|
164
|
+
- `E2E_LOG_DIR` (default `/tmp`): the run writes `<dir>/e2e-<timestamp>.log` with one
|
|
165
|
+
`[e2e-result] <file> <ok|fail|skip>` line per spec per attempt (the machine-readable format).
|
|
166
|
+
- `test:e2e:summary <log…>` reads those lines (or the human format for older logs) and prints a
|
|
167
|
+
row per spec, one column per log, marking `<-- difiere` when a spec's state changes between
|
|
168
|
+
runs (environmental vs product failure).
|
|
169
|
+
|
|
154
170
|
## Environment Variables
|
|
155
171
|
|
|
156
172
|
See [doc/e2e.md](../../../../doc/e2e.md) for full reference.
|
package/src/wallet/README.md
CHANGED
|
@@ -68,6 +68,29 @@ setDestinationsPrefix('learn.tg.pdj-wallet.') // localStorage
|
|
|
68
68
|
setRpName('learn.tg') // nombre de la credencial WebAuthn
|
|
69
69
|
```
|
|
70
70
|
|
|
71
|
+
## React (`./wallet/next`)
|
|
72
|
+
|
|
73
|
+
Capa React de la billetera in-app (`m/REQ/37`, graduada de `learn.tg/packages/pdj-wallet-next`):
|
|
74
|
+
|
|
75
|
+
```tsx
|
|
76
|
+
import {
|
|
77
|
+
useInAppWallet, InAppWalletSetup, InAppWalletUnlock, configureInAppWallet,
|
|
78
|
+
} from '@pasosdejesus/m/wallet/next'
|
|
79
|
+
|
|
80
|
+
// Conserva tu namespace si ya tienes billeteras creadas:
|
|
81
|
+
configureInAppWallet({
|
|
82
|
+
dbName: 'learn-tg-pdj-wallet',
|
|
83
|
+
destinationsPrefix: 'learn.tg.pdj-wallet.',
|
|
84
|
+
rpName: 'learn.tg',
|
|
85
|
+
})
|
|
86
|
+
|
|
87
|
+
// Textos: por defecto en/es; el host puede inyectar los suyos:
|
|
88
|
+
<InAppWalletSetup lang="es" messages={{ createTitle: 'Abrir cartera' }} onDone={(a) => {}} />
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
`react` es un *optional peer*: el subpath está fuera del barrel, así que importar
|
|
92
|
+
`@pasosdejesus/m/wallet` no arrastra React.
|
|
93
|
+
|
|
71
94
|
## Pruebas
|
|
72
95
|
|
|
73
96
|
Mocks en `@pasosdejesus/m/test-utils` (`installLocalStorage`, `installIndexedDB`,
|
|
@@ -91,6 +114,6 @@ O a mano: `import { setupWalletTests } from '@pasosdejesus/m/test-utils'; setupW
|
|
|
91
114
|
## Notas
|
|
92
115
|
|
|
93
116
|
- Fase 1/2 de `m/REQ/14`: primitivas, estado, storage, provider, WebAuthn (L1/L2),
|
|
94
|
-
destinos y resolutor EIP-6963. La
|
|
95
|
-
|
|
117
|
+
destinos y resolutor EIP-6963. La capa React (hook + `InAppWalletSetup`/`InAppWalletUnlock`)
|
|
118
|
+
vive en el subpath `./wallet/next` (`m/REQ/37`).
|
|
96
119
|
- E2E con firma real: `@pasosdejesus/m/e2e` (`injectEIP6963`, `setupFullWalletMock`).
|