@openfort/react-native 0.1.20 → 0.1.22

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 (48) hide show
  1. package/dist/components/AuthBoundary.js +4 -1
  2. package/dist/core/index.js +1 -1
  3. package/dist/core/provider.js +20 -7
  4. package/dist/hooks/auth/useEmailAuth.js +108 -8
  5. package/dist/hooks/auth/useGuestAuth.js +16 -6
  6. package/dist/hooks/auth/useOAuth.js +14 -5
  7. package/dist/hooks/auth/useWalletAuth.js +29 -10
  8. package/dist/hooks/core/useOpenfort.js +3 -17
  9. package/dist/hooks/wallet/index.js +4 -2
  10. package/dist/hooks/wallet/solanaProvider.js +77 -0
  11. package/dist/hooks/wallet/useEmbeddedEthereumWallet.js +517 -0
  12. package/dist/hooks/wallet/useEmbeddedSolanaWallet.js +455 -0
  13. package/dist/hooks/wallet/utils.js +75 -0
  14. package/dist/lib/hookConsistency.js +6 -0
  15. package/dist/native/oauth.js +13 -0
  16. package/dist/native/storage.js +4 -0
  17. package/dist/native/webview.js +15 -1
  18. package/dist/types/components/AuthBoundary.d.ts +1 -0
  19. package/dist/types/core/index.d.ts +1 -1
  20. package/dist/types/core/provider.d.ts +20 -6
  21. package/dist/types/hooks/auth/useEmailAuth.d.ts +24 -12
  22. package/dist/types/hooks/auth/useGuestAuth.d.ts +17 -8
  23. package/dist/types/hooks/auth/useOAuth.d.ts +15 -7
  24. package/dist/types/hooks/auth/useWalletAuth.d.ts +29 -10
  25. package/dist/types/hooks/core/useOpenfort.d.ts +2 -13
  26. package/dist/types/hooks/wallet/index.d.ts +2 -1
  27. package/dist/types/hooks/wallet/solanaProvider.d.ts +75 -0
  28. package/dist/types/hooks/wallet/useEmbeddedEthereumWallet.d.ts +104 -0
  29. package/dist/types/hooks/wallet/useEmbeddedSolanaWallet.d.ts +111 -0
  30. package/dist/types/hooks/wallet/utils.d.ts +17 -0
  31. package/dist/types/index.js +1 -2
  32. package/dist/types/lib/hookConsistency.d.ts +6 -0
  33. package/dist/types/native/oauth.d.ts +13 -0
  34. package/dist/types/native/storage.d.ts +4 -0
  35. package/dist/types/native/webview.d.ts +14 -0
  36. package/dist/types/types/auth.d.ts +0 -41
  37. package/dist/types/types/index.d.ts +3 -30
  38. package/dist/types/types/oauth.d.ts +0 -38
  39. package/dist/types/types/wallet.d.ts +120 -216
  40. package/package.json +1 -1
  41. package/dist/hooks/auth/useCreateWalletPostAuth.js +0 -34
  42. package/dist/hooks/wallet/useWallets.js +0 -436
  43. package/dist/types/config.js +0 -1
  44. package/dist/types/hooks/auth/useCreateWalletPostAuth.d.ts +0 -1
  45. package/dist/types/hooks/wallet/useWallets.d.ts +0 -78
  46. package/dist/types/predicates.js +0 -120
  47. package/dist/types/types/config.d.ts +0 -39
  48. package/dist/types/types/predicates.d.ts +0 -118
@@ -0,0 +1,455 @@
1
+ import { AccountTypeEnum, ChainTypeEnum, EmbeddedState } from '@openfort/openfort-js';
2
+ import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
3
+ import { useOpenfortContext } from '../../core/context';
4
+ import { onError, onSuccess } from '../../lib/hookConsistency';
5
+ import { logger } from '../../lib/logger';
6
+ import { OpenfortError, OpenfortErrorType } from '../../types/openfortError';
7
+ import { OpenfortSolanaProvider } from './solanaProvider';
8
+ import { buildRecoveryParams } from './utils';
9
+ /**
10
+ * Hook for managing embedded Solana wallets.
11
+ *
12
+ * This hook provides comprehensive management of embedded Solana (SVM) wallets including
13
+ * creation, recovery, activation, and transaction signing. Returns a discriminated union
14
+ * state that enables type-safe wallet interactions based on connection status.
15
+ *
16
+ * **Note:** Solana wallets are always EOA (Externally Owned Accounts) and work across
17
+ * all Solana networks (mainnet, devnet, testnet).
18
+ *
19
+ * **Recovery Methods:**
20
+ * - Automatic recovery (via encryption session)
21
+ * - Password-based recovery
22
+ *
23
+ * @param options - Configuration options including:
24
+ * - `onCreateSuccess` - Callback when wallet is created
25
+ * - `onCreateError` - Callback when wallet creation fails
26
+ * - `onSetActiveSuccess` - Callback when wallet is activated/recovered
27
+ * - `onSetActiveError` - Callback when wallet activation fails
28
+ *
29
+ * @returns Discriminated union state based on `status` field:
30
+ * - **'disconnected'**: No active wallet. Properties: `create`, `setActive`, `wallets`
31
+ * - **'connecting'**: Activating wallet. Properties: same as disconnected
32
+ * - **'reconnecting'**: Reconnecting to wallet. Properties: same as disconnected + `activeWallet`
33
+ * - **'creating'**: Creating new wallet. Properties: same as disconnected
34
+ * - **'needs-recovery'**: Recovery required. Properties: same as reconnecting
35
+ * - **'connected'**: Wallet ready. Properties: all + `provider` (Solana wallet adapter)
36
+ * - **'error'**: Operation failed. Properties: all + `error` message + optional `activeWallet`
37
+ *
38
+ * @example
39
+ * ```tsx
40
+ * import { useEmbeddedSolanaWallet } from '@openfort/react-native';
41
+ * import { Transaction } from '@solana/web3.js';
42
+ * import { ActivityIndicator } from 'react-native';
43
+ *
44
+ * function SolanaWalletComponent() {
45
+ * const solana = useEmbeddedSolanaWallet({
46
+ * onCreateSuccess: (account, provider) => {
47
+ * console.log('Solana wallet created:', account.address);
48
+ * console.log('Public key:', provider.publicKey);
49
+ * },
50
+ * });
51
+ *
52
+ * // Handle loading states
53
+ * if (solana.status === 'creating' || solana.status === 'connecting') {
54
+ * return <ActivityIndicator />;
55
+ * }
56
+ *
57
+ * // Create first wallet
58
+ * if (solana.status === 'disconnected' && solana.wallets.length === 0) {
59
+ * return (
60
+ * <Button
61
+ * onPress={() => solana.create({ recoveryPassword: 'optional' })}
62
+ * title="Create Solana Wallet"
63
+ * />
64
+ * );
65
+ * }
66
+ *
67
+ * // Activate existing wallet
68
+ * if (solana.status === 'disconnected' && solana.wallets.length > 0) {
69
+ * return (
70
+ * <Button
71
+ * onPress={() => solana.setActive({
72
+ * address: solana.wallets[0].address,
73
+ * recoveryPassword: 'optional'
74
+ * })}
75
+ * title="Connect Solana Wallet"
76
+ * />
77
+ * );
78
+ * }
79
+ *
80
+ * // Use connected wallet
81
+ * if (solana.status === 'connected') {
82
+ * const signTransaction = async () => {
83
+ * const transaction = new Transaction();
84
+ * // ... add instructions to transaction
85
+ *
86
+ * const signed = await solana.provider.signTransaction(transaction);
87
+ * console.log('Signed transaction:', signed);
88
+ * };
89
+ *
90
+ * const signMessage = async () => {
91
+ * const message = 'Hello Solana!';
92
+ * const signature = await solana.provider.signMessage(message);
93
+ * console.log('Message signature:', signature);
94
+ * };
95
+ *
96
+ * return (
97
+ * <View>
98
+ * <Text>Connected: {solana.activeWallet.address}</Text>
99
+ * <Button onPress={signTransaction} title="Sign Transaction" />
100
+ * <Button onPress={signMessage} title="Sign Message" />
101
+ * </View>
102
+ * );
103
+ * }
104
+ *
105
+ * return null;
106
+ * }
107
+ * ```
108
+ */
109
+ export function useEmbeddedSolanaWallet(options = {}) {
110
+ const { client, walletConfig, embeddedState } = useOpenfortContext();
111
+ const [embeddedAccounts, setEmbeddedAccounts] = useState([]);
112
+ const [activeWalletId, setActiveWalletId] = useState(null);
113
+ const [activeAccount, setActiveAccount] = useState(null);
114
+ const [provider, setProvider] = useState(null);
115
+ const recoverPromiseRef = useRef(null);
116
+ const [status, setStatus] = useState({
117
+ status: 'idle',
118
+ });
119
+ // Fetch Solana embedded accounts
120
+ const fetchEmbeddedAccounts = useCallback(async () => {
121
+ if (!client || embeddedState === EmbeddedState.NONE || embeddedState === EmbeddedState.UNAUTHENTICATED) {
122
+ setEmbeddedAccounts([]);
123
+ return;
124
+ }
125
+ try {
126
+ const accounts = await client.embeddedWallet.list({
127
+ chainType: ChainTypeEnum.SVM,
128
+ accountType: AccountTypeEnum.EOA,
129
+ limit: 100,
130
+ });
131
+ setEmbeddedAccounts(accounts);
132
+ }
133
+ catch {
134
+ setEmbeddedAccounts([]);
135
+ }
136
+ }, [client, embeddedState]);
137
+ useEffect(() => {
138
+ fetchEmbeddedAccounts();
139
+ }, [fetchEmbeddedAccounts]);
140
+ // Sync active wallet ID and account with client
141
+ useEffect(() => {
142
+ ;
143
+ (async () => {
144
+ try {
145
+ const embeddedAccount = await client.embeddedWallet.get();
146
+ // here we check in case the current account is not SVM
147
+ if (embeddedAccount.chainType === ChainTypeEnum.SVM) {
148
+ setActiveWalletId(embeddedAccount.id);
149
+ setActiveAccount(embeddedAccount);
150
+ }
151
+ else {
152
+ setActiveWalletId(null);
153
+ setActiveAccount(null);
154
+ }
155
+ }
156
+ catch {
157
+ setActiveWalletId(null);
158
+ setActiveAccount(null);
159
+ }
160
+ })();
161
+ }, [client]);
162
+ // Get Solana provider
163
+ const getSolanaProvider = useCallback(async (account) => {
164
+ // Helper function to sign a single transaction
165
+ const signSingleTransaction = async (transaction) => {
166
+ // Extract the message bytes from the transaction
167
+ // For @solana/kit compiledTransaction, the messageBytes property contains what needs to be signed
168
+ let messageBytes;
169
+ if (transaction.messageBytes) {
170
+ // @solana/kit compiled transaction
171
+ messageBytes = transaction.messageBytes;
172
+ }
173
+ else if (transaction.serializeMessage) {
174
+ // @solana/web3.js Transaction
175
+ messageBytes = transaction.serializeMessage();
176
+ }
177
+ else if (transaction instanceof Uint8Array) {
178
+ // Raw bytes
179
+ messageBytes = transaction;
180
+ }
181
+ else {
182
+ throw new OpenfortError('Unsupported transaction format. Expected @solana/kit compiled transaction, @solana/web3.js Transaction, or Uint8Array', OpenfortErrorType.WALLET_ERROR);
183
+ }
184
+ // Convert Uint8Array to Buffer JSON format for React Native WebView serialization
185
+ // This is necessary because React Native's postMessage only accepts strings,
186
+ // and Uint8Array serializes incorrectly as {0:1, 1:2, ...} instead of {type:"Buffer", data:[...]}
187
+ const bufferFormatMessage = {
188
+ type: 'Buffer',
189
+ data: Array.from(messageBytes),
190
+ };
191
+ // Sign the message bytes (hashMessage: false for Solana - Ed25519 signs raw bytes)
192
+ // Note: We cast to any because the iframe will deserialize the Buffer format correctly,
193
+ // but TypeScript doesn't know about this serialization detail
194
+ const signatureBase58 = await client.embeddedWallet.signMessage(bufferFormatMessage, {
195
+ hashMessage: false,
196
+ });
197
+ // Return the signature in the expected format
198
+ // Different libraries expect different return formats, so we return a flexible object
199
+ return {
200
+ signature: signatureBase58,
201
+ publicKey: account.address,
202
+ };
203
+ };
204
+ const provider = new OpenfortSolanaProvider({
205
+ account,
206
+ signTransaction: signSingleTransaction,
207
+ signAllTransactions: async (transactions) => {
208
+ // Sign each transaction sequentially
209
+ const signedTransactions = [];
210
+ for (const transaction of transactions) {
211
+ const signed = await signSingleTransaction(transaction);
212
+ signedTransactions.push(signed);
213
+ }
214
+ return signedTransactions;
215
+ },
216
+ signMessage: async (message) => {
217
+ // Sign message using openfort-js (with hashMessage: false for Solana)
218
+ const result = await client.embeddedWallet.signMessage(message, { hashMessage: false });
219
+ return result;
220
+ },
221
+ });
222
+ return provider;
223
+ }, [client.embeddedWallet]);
224
+ // Initialize provider when recovering an active wallet on mount
225
+ useEffect(() => {
226
+ // Only initialize if we have an account but no provider
227
+ if (!activeAccount || provider) {
228
+ return;
229
+ }
230
+ // Don't interfere with user-initiated actions
231
+ if (['creating', 'connecting', 'reconnecting', 'loading'].includes(status.status)) {
232
+ return;
233
+ }
234
+ // Only initialize if embedded state is ready
235
+ if (embeddedState !== EmbeddedState.READY) {
236
+ return;
237
+ }
238
+ ;
239
+ (async () => {
240
+ try {
241
+ logger.info('Initializing provider for recovered Solana wallet session');
242
+ setStatus({ status: 'connecting' });
243
+ const solProvider = await getSolanaProvider(activeAccount);
244
+ setProvider(solProvider);
245
+ setStatus({ status: 'success' });
246
+ }
247
+ catch (e) {
248
+ const error = e instanceof OpenfortError
249
+ ? e
250
+ : new OpenfortError('Failed to initialize provider for active Solana wallet', OpenfortErrorType.WALLET_ERROR, { error: e });
251
+ logger.error('Solana provider initialization failed', error);
252
+ setStatus({ status: 'error', error });
253
+ }
254
+ })();
255
+ }, [activeAccount, provider, embeddedState, status.status, getSolanaProvider]);
256
+ // Build wallets list (simple deduplication by address)
257
+ const wallets = useMemo(() => {
258
+ return embeddedAccounts.map((account, index) => ({
259
+ address: account.address,
260
+ chainType: ChainTypeEnum.SVM,
261
+ walletIndex: index,
262
+ getProvider: async () => await getSolanaProvider(account),
263
+ }));
264
+ }, [embeddedAccounts, getSolanaProvider]);
265
+ // Create wallet action
266
+ const create = useCallback(async (createOptions) => {
267
+ logger.info('Creating Solana wallet with options', createOptions);
268
+ try {
269
+ setStatus({ status: 'creating' });
270
+ // Build recovery params (only use recoveryPassword, ignore createAdditional)
271
+ const recoveryParams = await buildRecoveryParams(createOptions?.recoveryPassword ? { recoveryPassword: createOptions.recoveryPassword } : undefined, walletConfig);
272
+ // Create embedded wallet
273
+ const embeddedAccount = await client.embeddedWallet.create({
274
+ chainType: ChainTypeEnum.SVM,
275
+ recoveryParams,
276
+ accountType: AccountTypeEnum.EOA, // Solana wallets are EOA
277
+ });
278
+ logger.info('Embedded Solana wallet created');
279
+ // Get provider
280
+ const solProvider = await getSolanaProvider(embeddedAccount);
281
+ setProvider(solProvider);
282
+ // Refresh accounts and set as active
283
+ await fetchEmbeddedAccounts();
284
+ setActiveWalletId(embeddedAccount.id);
285
+ setActiveAccount(embeddedAccount);
286
+ setStatus({ status: 'success' });
287
+ onSuccess({
288
+ options: createOptions,
289
+ data: {
290
+ account: embeddedAccount,
291
+ provider: solProvider,
292
+ },
293
+ });
294
+ if (createOptions?.onSuccess) {
295
+ createOptions.onSuccess({ account: embeddedAccount, provider: solProvider });
296
+ }
297
+ if (options.onCreateSuccess) {
298
+ options.onCreateSuccess(embeddedAccount, solProvider);
299
+ }
300
+ return embeddedAccount;
301
+ }
302
+ catch (e) {
303
+ const error = e instanceof OpenfortError
304
+ ? e
305
+ : new OpenfortError('Failed to create Solana wallet', OpenfortErrorType.WALLET_ERROR, { error: e });
306
+ setStatus({ status: 'error', error });
307
+ onError({
308
+ options: createOptions,
309
+ error,
310
+ });
311
+ if (createOptions?.onError) {
312
+ createOptions.onError(error);
313
+ }
314
+ if (options.onCreateError) {
315
+ options.onCreateError(error);
316
+ }
317
+ throw error;
318
+ }
319
+ }, [client, walletConfig, options, getSolanaProvider, fetchEmbeddedAccounts]);
320
+ // Set active wallet action
321
+ const setActive = useCallback(async (setActiveOptions) => {
322
+ // Prevent concurrent recoveries
323
+ if (recoverPromiseRef.current) {
324
+ await recoverPromiseRef.current;
325
+ return;
326
+ }
327
+ if (wallets.length === 0) {
328
+ const error = new OpenfortError('No embedded Solana wallets available to set as active', OpenfortErrorType.WALLET_ERROR);
329
+ onError({
330
+ options: setActiveOptions,
331
+ error,
332
+ });
333
+ if (setActiveOptions.onError) {
334
+ setActiveOptions.onError(error);
335
+ }
336
+ if (options.onSetActiveError) {
337
+ options.onSetActiveError(error);
338
+ }
339
+ throw error;
340
+ }
341
+ setStatus({ status: 'connecting' });
342
+ recoverPromiseRef.current = (async () => {
343
+ try {
344
+ // Find account to recover by address only
345
+ const embeddedAccountToRecover = embeddedAccounts.find((account) => account.address.toLowerCase() === setActiveOptions.address.toLowerCase());
346
+ if (!embeddedAccountToRecover) {
347
+ throw new OpenfortError(`No embedded Solana account found for address ${setActiveOptions.address}`, OpenfortErrorType.WALLET_ERROR);
348
+ }
349
+ // Build recovery params
350
+ const recoveryParams = await buildRecoveryParams(setActiveOptions, walletConfig);
351
+ // Recover the embedded wallet
352
+ const embeddedAccount = await client.embeddedWallet.recover({
353
+ account: embeddedAccountToRecover.id,
354
+ recoveryParams,
355
+ });
356
+ // Get provider
357
+ const solProvider = await getSolanaProvider(embeddedAccount);
358
+ setProvider(solProvider);
359
+ // Find the wallet index in the accounts list
360
+ const walletIndex = embeddedAccounts.findIndex((acc) => acc.address.toLowerCase() === embeddedAccount.address.toLowerCase());
361
+ const wallet = {
362
+ address: embeddedAccount.address,
363
+ chainType: ChainTypeEnum.SVM,
364
+ walletIndex: walletIndex >= 0 ? walletIndex : 0,
365
+ getProvider: async () => solProvider,
366
+ };
367
+ recoverPromiseRef.current = null;
368
+ setStatus({ status: 'success' });
369
+ setActiveWalletId(embeddedAccount.id);
370
+ setActiveAccount(embeddedAccount);
371
+ onSuccess({
372
+ options: setActiveOptions,
373
+ data: {
374
+ wallet,
375
+ provider: solProvider,
376
+ },
377
+ });
378
+ if (setActiveOptions.onSuccess) {
379
+ setActiveOptions.onSuccess({ wallet, provider: solProvider });
380
+ }
381
+ if (options.onSetActiveSuccess) {
382
+ options.onSetActiveSuccess(wallet, solProvider);
383
+ }
384
+ return { wallet, provider: solProvider };
385
+ }
386
+ catch (e) {
387
+ recoverPromiseRef.current = null;
388
+ const error = e instanceof OpenfortError
389
+ ? e
390
+ : new OpenfortError('Failed to set active Solana wallet', OpenfortErrorType.WALLET_ERROR);
391
+ setStatus({ status: 'error', error });
392
+ onError({
393
+ options: setActiveOptions,
394
+ error,
395
+ });
396
+ if (setActiveOptions.onError) {
397
+ setActiveOptions.onError(error);
398
+ }
399
+ if (options.onSetActiveError) {
400
+ options.onSetActiveError(error);
401
+ }
402
+ throw error;
403
+ }
404
+ })();
405
+ await recoverPromiseRef.current;
406
+ }, [client, walletConfig, embeddedAccounts, options, wallets.length, getSolanaProvider]);
407
+ // Build active wallet from embeddedWallet.get()
408
+ const activeWallet = useMemo(() => {
409
+ if (!activeWalletId || !activeAccount)
410
+ return null;
411
+ // Find the wallet index in the accounts list
412
+ const accountIndex = embeddedAccounts.findIndex((acc) => acc.id === activeWalletId);
413
+ return {
414
+ address: activeAccount.address,
415
+ chainType: ChainTypeEnum.SVM,
416
+ walletIndex: accountIndex >= 0 ? accountIndex : 0,
417
+ getProvider: async () => await getSolanaProvider(activeAccount),
418
+ };
419
+ }, [activeWalletId, activeAccount, embeddedAccounts, getSolanaProvider]);
420
+ // Build discriminated union state
421
+ const state = useMemo(() => {
422
+ const baseActions = {
423
+ create,
424
+ wallets,
425
+ setActive,
426
+ };
427
+ // Priority 1: Explicit action states (user-initiated operations)
428
+ if (status.status === 'creating') {
429
+ return { ...baseActions, status: 'creating', activeWallet: null };
430
+ }
431
+ if (status.status === 'connecting' || status.status === 'reconnecting' || status.status === 'loading') {
432
+ return { ...baseActions, status: 'connecting' };
433
+ }
434
+ if (status.status === 'error') {
435
+ return { ...baseActions, status: 'error', activeWallet, error: status.error?.message || 'Unknown error' };
436
+ }
437
+ // Priority 2: Check authentication state from context
438
+ if (embeddedState !== EmbeddedState.READY && embeddedState !== EmbeddedState.CREATING_ACCOUNT) {
439
+ // Not authenticated or no embedded wallet capability
440
+ return { ...baseActions, status: 'disconnected', activeWallet: null };
441
+ }
442
+ // Priority 3: Data-driven connection state
443
+ if (activeWallet && provider) {
444
+ // Fully connected - have both wallet and provider
445
+ return { ...baseActions, status: 'connected', activeWallet, provider };
446
+ }
447
+ if (activeAccount && !provider) {
448
+ // Have wallet but provider not initialized yet (mount recovery in progress)
449
+ return { ...baseActions, status: 'connecting' };
450
+ }
451
+ // Default: disconnected (authenticated but no wallet selected)
452
+ return { ...baseActions, status: 'disconnected', activeWallet: null };
453
+ }, [status, activeWallet, activeAccount, provider, wallets, embeddedState, create, setActive]);
454
+ return state;
455
+ }
@@ -0,0 +1,75 @@
1
+ import { RecoveryMethod } from '@openfort/openfort-js';
2
+ import { OpenfortError, OpenfortErrorType } from '../../types/openfortError';
3
+ /**
4
+ * Resolves an encryption session from wallet configuration.
5
+ *
6
+ * This utility handles encryption session resolution for automatic wallet recovery.
7
+ * It supports both callback-based session retrieval and endpoint-based session creation.
8
+ *
9
+ * @param walletConfig - The embedded wallet configuration from the provider
10
+ * @returns A promise that resolves to the encryption session string
11
+ * @throws {OpenfortError} When wallet config is missing or session cannot be retrieved
12
+ *
13
+ * @internal
14
+ */
15
+ async function resolveEncryptionSession(walletConfig) {
16
+ if (!walletConfig) {
17
+ throw new OpenfortError('Encryption session configuration is required', OpenfortErrorType.WALLET_ERROR);
18
+ }
19
+ // Try callback-based session retrieval first
20
+ if (walletConfig.getEncryptionSession) {
21
+ return await walletConfig.getEncryptionSession();
22
+ }
23
+ // Try endpoint-based session creation
24
+ if (walletConfig.createEncryptedSessionEndpoint) {
25
+ try {
26
+ const response = await fetch(walletConfig.createEncryptedSessionEndpoint, {
27
+ method: 'POST',
28
+ headers: {
29
+ 'Content-Type': 'application/json',
30
+ },
31
+ });
32
+ if (!response.ok) {
33
+ throw new OpenfortError('Failed to create encryption session', OpenfortErrorType.WALLET_ERROR, {
34
+ status: response.status,
35
+ });
36
+ }
37
+ const body = (await response.json());
38
+ if (!body?.session || typeof body.session !== 'string') {
39
+ throw new OpenfortError('Encryption session response is missing the `session` property', OpenfortErrorType.WALLET_ERROR);
40
+ }
41
+ return body.session;
42
+ }
43
+ catch (error) {
44
+ if (error instanceof OpenfortError) {
45
+ throw error;
46
+ }
47
+ throw new OpenfortError('Failed to create encryption session', OpenfortErrorType.WALLET_ERROR, { error });
48
+ }
49
+ }
50
+ throw new OpenfortError('Encryption session configuration is required', OpenfortErrorType.WALLET_ERROR);
51
+ }
52
+ /**
53
+ * Builds recovery parameters from options and wallet configuration.
54
+ *
55
+ * This utility constructs the appropriate RecoveryParams object based on whether
56
+ * a recovery password is provided or automatic recovery should be used.
57
+ *
58
+ * @param options - Options containing optional recovery password
59
+ * @param walletConfig - The embedded wallet configuration from the provider
60
+ * @returns A promise that resolves to RecoveryParams for the SDK
61
+ *
62
+ * @internal
63
+ */
64
+ export async function buildRecoveryParams(options, walletConfig) {
65
+ if (options?.recoveryPassword) {
66
+ return {
67
+ recoveryMethod: RecoveryMethod.PASSWORD,
68
+ password: options.recoveryPassword,
69
+ };
70
+ }
71
+ return {
72
+ recoveryMethod: RecoveryMethod.AUTOMATIC,
73
+ encryptionSession: await resolveEncryptionSession(walletConfig),
74
+ };
75
+ }
@@ -5,6 +5,9 @@
5
5
  * ensuring consistent callback execution across all hooks in the SDK.
6
6
  *
7
7
  * @param params - Object containing hook options and success data
8
+ * @param params.hookOptions - Primary hook options (from the hook itself)
9
+ * @param params.options - Secondary hook options (from the action call)
10
+ * @param params.data - The success data to pass to callbacks
8
11
  * @returns The success data that was passed in
9
12
  *
10
13
  * @example
@@ -29,6 +32,9 @@ export const onSuccess = ({ hookOptions, options, data, }) => {
29
32
  * and optionally throws the error if throwOnError is configured.
30
33
  *
31
34
  * @param params - Object containing hook options and error information
35
+ * @param params.hookOptions - Primary hook options (from the hook itself)
36
+ * @param params.options - Secondary hook options (from the action call)
37
+ * @param params.error - The error that occurred during the operation
32
38
  * @returns Object containing the error, or throws if throwOnError is enabled
33
39
  *
34
40
  * @example
@@ -6,6 +6,11 @@ import { Platform } from 'react-native';
6
6
  import { logger } from '../lib/logger';
7
7
  /**
8
8
  * Opens an OAuth authentication session
9
+ *
10
+ * @param config - OAuth session configuration
11
+ * @param config.url - OAuth provider URL to open
12
+ * @param config.redirectUri - Redirect URI for OAuth flow callback
13
+ * @returns Promise resolving to OAuth result indicating success, cancellation, or error
9
14
  */
10
15
  export async function openOAuthSession(config) {
11
16
  try {
@@ -38,6 +43,12 @@ export async function openOAuthSession(config) {
38
43
  }
39
44
  /**
40
45
  * Handles Apple Sign-In authentication for iOS
46
+ *
47
+ * @param options - Options for Apple authentication
48
+ * @param options.state - State parameter for the OAuth flow
49
+ * @param options.isLogin - Whether this is a login or link operation (affects error codes)
50
+ * @returns Promise resolving to Apple authentication result with authorization code and user info
51
+ * @throws {Error} When not running on iOS platform or authentication fails
41
52
  */
42
53
  export async function authenticateWithApple(options) {
43
54
  if (Platform.OS !== 'ios') {
@@ -77,6 +88,8 @@ export async function authenticateWithApple(options) {
77
88
  }
78
89
  /**
79
90
  * Checks if Apple Sign-In is available on the current device
91
+ *
92
+ * @returns Promise resolving to true if Apple Sign-In is available, false otherwise
80
93
  */
81
94
  export async function isAppleSignInAvailable() {
82
95
  if (Platform.OS !== 'ios') {
@@ -160,12 +160,16 @@ function normalizeKey(key) {
160
160
  export const NativeStorageUtils = {
161
161
  /**
162
162
  * Checks if secure storage is available on the current platform.
163
+ *
164
+ * @returns True if the platform is iOS or Android, false otherwise
163
165
  */
164
166
  isAvailable() {
165
167
  return Platform.OS === 'ios' || Platform.OS === 'android';
166
168
  },
167
169
  /**
168
170
  * Gets the platform-specific storage options.
171
+ *
172
+ * @returns Secure store options with keychain accessibility configuration
169
173
  */
170
174
  getStorageOptions() {
171
175
  return {
@@ -9,6 +9,8 @@ import { handleSecureStorageMessage, isSecureStorageMessage } from './storage';
9
9
  * WebView component for embedded wallet integration
10
10
  * Handles secure communication between React Native and the embedded wallet WebView
11
11
  * This component is hidden and only used for wallet communication
12
+ *
13
+ * @param props - Component props, see {@link EmbeddedWalletWebViewProps}
12
14
  */
13
15
  export const EmbeddedWalletWebView = ({ client, isClientReady, onProxyStatusChange, }) => {
14
16
  const webViewRef = useRef(null);
@@ -42,7 +44,7 @@ export const EmbeddedWalletWebView = ({ client, isClientReady, onProxyStatusChan
42
44
  // Set up WebView reference with client immediately when both are available
43
45
  useEffect(() => {
44
46
  if (webViewRef.current) {
45
- // Simple message poster that uses WebView's postMessage directly
47
+ // Message poster with Uint8Array preprocessing for React Native
46
48
  const messagePoster = {
47
49
  postMessage: (message) => {
48
50
  webViewRef.current?.postMessage(message);
@@ -97,12 +99,16 @@ export const EmbeddedWalletWebView = ({ client, isClientReady, onProxyStatusChan
97
99
  export const WebViewUtils = {
98
100
  /**
99
101
  * Checks if WebView is supported on the current platform
102
+ *
103
+ * @returns True if the platform is iOS or Android, false otherwise
100
104
  */
101
105
  isSupported() {
102
106
  return Platform.OS === 'ios' || Platform.OS === 'android';
103
107
  },
104
108
  /**
105
109
  * Gets platform-specific WebView configuration
110
+ *
111
+ * @returns Platform-specific WebView configuration object
106
112
  */
107
113
  getPlatformConfig() {
108
114
  if (Platform.OS === 'ios') {
@@ -123,6 +129,9 @@ export const WebViewUtils = {
123
129
  },
124
130
  /**
125
131
  * Creates a secure message for WebView communication
132
+ *
133
+ * @param data - Data to include in the message
134
+ * @returns JSON-stringified message with timestamp and platform information
126
135
  */
127
136
  createSecureMessage(data) {
128
137
  return JSON.stringify({
@@ -133,6 +142,9 @@ export const WebViewUtils = {
133
142
  },
134
143
  /**
135
144
  * Validates a message received from WebView
145
+ *
146
+ * @param message - JSON string message to validate
147
+ * @returns Validation result with parsed data or error information
136
148
  */
137
149
  validateMessage(message) {
138
150
  try {
@@ -152,6 +164,8 @@ export const WebViewUtils = {
152
164
  },
153
165
  /**
154
166
  * Gets WebView user agent for the current platform
167
+ *
168
+ * @returns User agent string including platform and version information
155
169
  */
156
170
  getUserAgent() {
157
171
  const baseAgent = 'OpenfortEmbeddedWallet/1.0';
@@ -31,6 +31,7 @@ export interface AuthBoundaryProps {
31
31
  * 3. **Unauthenticated** – the user is not logged in.
32
32
  * 4. **Authenticated** – the user is logged in and the SDK is ready.
33
33
  *
34
+ * @param props - Component props, see {@link AuthBoundaryProps}
34
35
  * @example
35
36
  * ```tsx
36
37
  * import { AuthBoundary } from '@openfort/react-native';
@@ -1,6 +1,6 @@
1
1
  export type { SDKOverrides } from '@openfort/openfort-js';
2
2
  export { RecoveryMethod } from '@openfort/openfort-js';
3
- export { createOpenfortClient, getDefaultClient, setDefaultClient } from './client';
3
+ export { createOpenfortClient } from './client';
4
4
  export type { OpenfortContextValue } from './context';
5
5
  export { isOpenfortContextValue, OpenfortContext, useOpenfortContext, useOpenfortContextSafe } from './context';
6
6
  export type { CommonEmbeddedWalletConfiguration, EmbeddedWalletConfiguration, EncryptionSession, OpenfortProviderProps, } from './provider';