@openfort/react-native 0.0.3 → 0.1.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 (91) hide show
  1. package/README.md +0 -85
  2. package/dist/components/AuthBoundary.js +83 -0
  3. package/dist/components/index.js +10 -0
  4. package/dist/constants/config.js +9 -0
  5. package/dist/constants/index.js +1 -0
  6. package/dist/core/client.js +78 -0
  7. package/dist/core/context.js +37 -0
  8. package/dist/core/index.js +10 -0
  9. package/dist/core/provider.js +224 -0
  10. package/dist/core/storage.js +141 -0
  11. package/dist/hooks/auth/index.js +13 -0
  12. package/dist/hooks/auth/useAuthCallback.js +1 -0
  13. package/dist/hooks/auth/useCreateWalletPostAuth.js +22 -0
  14. package/dist/hooks/auth/useEmailAuth.js +169 -0
  15. package/dist/hooks/auth/useGuestAuth.js +52 -0
  16. package/dist/hooks/auth/useOAuth.js +292 -0
  17. package/dist/hooks/auth/useSignOut.js +48 -0
  18. package/dist/hooks/auth/useUser.js +1 -0
  19. package/dist/hooks/auth/useWalletAuth.js +122 -0
  20. package/dist/hooks/core/index.js +10 -0
  21. package/dist/hooks/core/useOpenfort.js +50 -0
  22. package/dist/hooks/core/useOpenfortClient.js +29 -0
  23. package/dist/hooks/core/useSignOut.js +7 -0
  24. package/dist/hooks/core/useUser.js +10 -0
  25. package/dist/hooks/index.js +15 -0
  26. package/dist/hooks/wallet/index.js +7 -0
  27. package/dist/hooks/wallet/useWallets.js +389 -0
  28. package/dist/index.js +24 -1
  29. package/dist/lib/hookConsistency.js +16 -0
  30. package/dist/native/index.js +6 -0
  31. package/dist/native/oauth.js +183 -0
  32. package/dist/native/storage.js +178 -0
  33. package/dist/native/webview.js +157 -0
  34. package/dist/types/auth.js +1 -0
  35. package/dist/types/baseFlowState.js +8 -0
  36. package/dist/types/components/AuthBoundary.d.ts +85 -0
  37. package/dist/types/components/index.d.ts +10 -0
  38. package/dist/types/config.js +1 -0
  39. package/dist/types/constants/config.d.ts +9 -0
  40. package/dist/types/constants/index.d.ts +1 -0
  41. package/dist/types/core/client.d.ts +24 -0
  42. package/dist/types/core/context.d.ts +61 -0
  43. package/dist/types/core/index.d.ts +8 -0
  44. package/dist/types/core/provider.d.ts +126 -0
  45. package/dist/types/core/storage.d.ts +34 -0
  46. package/dist/types/hex.js +1 -0
  47. package/dist/types/hookOption.js +1 -0
  48. package/dist/types/hooks/auth/index.d.ts +9 -0
  49. package/dist/types/hooks/auth/useAuthCallback.d.ts +0 -0
  50. package/dist/types/hooks/auth/useCreateWalletPostAuth.d.ts +6 -0
  51. package/dist/types/hooks/auth/useEmailAuth.d.ts +54 -0
  52. package/dist/types/hooks/auth/useGuestAuth.d.ts +39 -0
  53. package/dist/types/hooks/auth/useOAuth.d.ts +62 -0
  54. package/dist/types/hooks/auth/useSignOut.d.ts +9 -0
  55. package/dist/types/hooks/auth/useUser.d.ts +0 -0
  56. package/dist/types/hooks/auth/useWalletAuth.d.ts +42 -0
  57. package/dist/types/hooks/core/index.d.ts +9 -0
  58. package/dist/types/hooks/core/useOpenfort.d.ts +38 -0
  59. package/dist/types/hooks/core/useOpenfortClient.d.ts +29 -0
  60. package/dist/types/hooks/core/useSignOut.d.ts +3 -0
  61. package/dist/types/hooks/core/useUser.d.ts +5 -0
  62. package/dist/types/hooks/index.d.ts +12 -0
  63. package/dist/types/hooks/wallet/index.d.ts +6 -0
  64. package/dist/types/hooks/wallet/useWallets.d.ts +74 -0
  65. package/dist/types/index.d.ts +18 -1
  66. package/dist/types/index.js +2 -0
  67. package/dist/types/lib/hookConsistency.d.ts +14 -0
  68. package/dist/types/native/index.d.ts +5 -0
  69. package/dist/types/native/oauth.d.ts +91 -0
  70. package/dist/types/native/storage.d.ts +50 -0
  71. package/dist/types/native/webview.d.ts +50 -0
  72. package/dist/types/oauth.js +8 -0
  73. package/dist/types/openfortError.js +27 -0
  74. package/dist/types/predicates.js +101 -0
  75. package/dist/types/state.js +1 -0
  76. package/dist/types/types/auth.d.ts +168 -0
  77. package/dist/types/types/baseFlowState.d.ts +14 -0
  78. package/dist/types/types/config.d.ts +71 -0
  79. package/dist/types/types/hex.d.ts +1 -0
  80. package/dist/types/types/hookOption.d.ts +9 -0
  81. package/dist/types/types/index.d.ts +38 -0
  82. package/dist/types/types/oauth.d.ts +74 -0
  83. package/dist/types/types/openfortError.d.ts +13 -0
  84. package/dist/types/types/predicates.d.ts +64 -0
  85. package/dist/types/types/state.d.ts +0 -0
  86. package/dist/types/types/wallet.d.ts +262 -0
  87. package/dist/types/wallet.js +1 -0
  88. package/package.json +33 -19
  89. package/dist/Iframe.js +0 -84
  90. package/dist/types/Iframe.d.ts +0 -6
  91. package/polyfills/index.ts +0 -89
@@ -0,0 +1,16 @@
1
+ export const onSuccess = ({ hookOptions, options, data, }) => {
2
+ hookOptions?.onSuccess?.(data);
3
+ hookOptions?.onSettled?.(data, null);
4
+ options?.onSuccess?.(data);
5
+ options?.onSettled?.(data, null);
6
+ return data;
7
+ };
8
+ export const onError = ({ hookOptions, options, error, }) => {
9
+ hookOptions?.onError?.(error);
10
+ hookOptions?.onSettled?.(null, error);
11
+ options?.onError?.(error);
12
+ options?.onSettled?.(null, error);
13
+ if (hookOptions?.throwOnError || options?.throwOnError)
14
+ throw error;
15
+ return { error };
16
+ };
@@ -0,0 +1,6 @@
1
+ // WebView integration
2
+ export { EmbeddedWalletWebView, WebViewUtils } from './webview';
3
+ // Storage utilities
4
+ export { isSecureStorageMessage, handleSecureStorageMessage, NativeStorageUtils, } from './storage';
5
+ // OAuth flows
6
+ export { openOAuthSession, authenticateWithApple, isAppleSignInAvailable, parseOAuthUrl, createOAuthRedirectUri, OAuthUtils, } from './oauth';
@@ -0,0 +1,183 @@
1
+ import { Platform } from 'react-native';
2
+ import * as WebBrowser from 'expo-web-browser';
3
+ import * as Linking from 'expo-linking';
4
+ import * as AppleAuthentication from 'expo-apple-authentication';
5
+ import { OAuthProvider as OAuthProviderType } from '@openfort/openfort-js';
6
+ /**
7
+ * Opens an OAuth authentication session
8
+ */
9
+ export async function openOAuthSession(config) {
10
+ try {
11
+ const result = await WebBrowser.openAuthSessionAsync(config.url, config.redirectUri, {
12
+ // Additional options can be configured here
13
+ showInRecents: false,
14
+ });
15
+ if (result.type === 'success') {
16
+ return {
17
+ type: 'success',
18
+ url: result.url,
19
+ };
20
+ }
21
+ if (result.type === 'cancel' || result.type === 'dismiss') {
22
+ return {
23
+ type: 'cancel',
24
+ };
25
+ }
26
+ return {
27
+ type: 'error',
28
+ error: 'OAuth session failed',
29
+ };
30
+ }
31
+ catch (error) {
32
+ return {
33
+ type: 'error',
34
+ error: error instanceof Error ? error.message : 'Unknown OAuth error',
35
+ };
36
+ }
37
+ }
38
+ /**
39
+ * Handles Apple Sign-In authentication for iOS
40
+ */
41
+ export async function authenticateWithApple(options) {
42
+ if (Platform.OS !== 'ios') {
43
+ throw new Error('Apple Sign-In is only available on iOS');
44
+ }
45
+ try {
46
+ const result = await AppleAuthentication.signInAsync({
47
+ state: options.state,
48
+ requestedScopes: [
49
+ AppleAuthentication.AppleAuthenticationScope.EMAIL,
50
+ AppleAuthentication.AppleAuthenticationScope.FULL_NAME,
51
+ ],
52
+ });
53
+ if (!result.authorizationCode || !result.state) {
54
+ throw new Error('Invalid Apple authentication response');
55
+ }
56
+ return {
57
+ authorizationCode: result.authorizationCode,
58
+ state: result.state,
59
+ identityToken: result.identityToken || undefined,
60
+ email: result.email || undefined,
61
+ fullName: result.fullName || undefined,
62
+ };
63
+ }
64
+ catch (error) {
65
+ if (error instanceof Error && 'code' in error && error.code === 'ERR_REQUEST_CANCELED') {
66
+ const errorCode = options.isLogin
67
+ ? 'login_with_oauth_was_cancelled_by_user'
68
+ : 'link_with_oauth_was_cancelled_by_user';
69
+ throw {
70
+ code: errorCode,
71
+ error: 'Apple login was cancelled',
72
+ };
73
+ }
74
+ throw error;
75
+ }
76
+ }
77
+ /**
78
+ * Checks if Apple Sign-In is available on the current device
79
+ */
80
+ export async function isAppleSignInAvailable() {
81
+ if (Platform.OS !== 'ios') {
82
+ return false;
83
+ }
84
+ try {
85
+ return await AppleAuthentication.isAvailableAsync();
86
+ }
87
+ catch {
88
+ return false;
89
+ }
90
+ }
91
+ /**
92
+ * Parses OAuth parameters from a URL
93
+ */
94
+ export function parseOAuthUrl(url) {
95
+ try {
96
+ const { queryParams } = Linking.parse(url);
97
+ console.log('Parsed OAuth URL:', queryParams);
98
+ return {
99
+ access_token: queryParams?.access_token,
100
+ refresh_token: queryParams?.refresh_token,
101
+ player_id: queryParams?.player_id,
102
+ error: queryParams?.error,
103
+ errorDescription: queryParams?.error_description,
104
+ };
105
+ }
106
+ catch (error) {
107
+ console.warn('Failed to parse OAuth URL:', error);
108
+ return {};
109
+ }
110
+ }
111
+ /**
112
+ * Creates a redirect URI for OAuth flows
113
+ */
114
+ export function createOAuthRedirectUri(path = '/') {
115
+ return Linking.createURL(path);
116
+ }
117
+ /**
118
+ * OAuth provider utilities
119
+ */
120
+ export const OAuthUtils = {
121
+ /**
122
+ * Checks if a provider should use native authentication
123
+ */
124
+ shouldUseNativeAuth(provider, isLegacyAppleIosBehaviorEnabled = false) {
125
+ return (Platform.OS === 'ios' &&
126
+ provider === 'apple' &&
127
+ !isLegacyAppleIosBehaviorEnabled);
128
+ },
129
+ /**
130
+ * Gets platform-specific OAuth configuration
131
+ */
132
+ getPlatformConfig() {
133
+ return {
134
+ supportsNativeApple: Platform.OS === 'ios',
135
+ platform: Platform.OS,
136
+ supportsWebBrowser: true,
137
+ };
138
+ },
139
+ /**
140
+ * Validates OAuth provider support
141
+ */
142
+ isProviderSupported(provider) {
143
+ const supportedProviders = [
144
+ OAuthProviderType.GOOGLE,
145
+ OAuthProviderType.TWITTER,
146
+ OAuthProviderType.DISCORD,
147
+ OAuthProviderType.LINE,
148
+ OAuthProviderType.FACEBOOK,
149
+ OAuthProviderType.EPIC_GAMES,
150
+ OAuthProviderType.APPLE
151
+ ];
152
+ return supportedProviders.includes(provider);
153
+ },
154
+ /**
155
+ * Gets the appropriate OAuth URL for a provider
156
+ */
157
+ getProviderUrl(provider, baseUrl) {
158
+ // Handle Twitter URL compatibility between platforms
159
+ if (provider === 'twitter' && Platform.OS === 'android') {
160
+ return baseUrl.replace('x.com', 'twitter.com');
161
+ }
162
+ return baseUrl;
163
+ },
164
+ /**
165
+ * Handles OAuth session timeout
166
+ */
167
+ createTimeoutPromise(timeoutMs = 120000) {
168
+ return new Promise((_, reject) => {
169
+ setTimeout(() => {
170
+ reject(new Error('OAuth session timed out'));
171
+ }, timeoutMs);
172
+ });
173
+ },
174
+ /**
175
+ * Combines OAuth session with timeout
176
+ */
177
+ async withTimeout(promise, timeoutMs = 120000) {
178
+ return Promise.race([
179
+ promise,
180
+ this.createTimeoutPromise(timeoutMs),
181
+ ]);
182
+ },
183
+ };
@@ -0,0 +1,178 @@
1
+ /* eslint-disable @typescript-eslint/no-explicit-any */
2
+ import * as SecureStore from 'expo-secure-store';
3
+ import { Platform } from 'react-native';
4
+ /**
5
+ * Checks if a message is a secure storage related message
6
+ */
7
+ export function isSecureStorageMessage(message) {
8
+ if (typeof message !== 'object' ||
9
+ message === null ||
10
+ !('event' in message) ||
11
+ typeof message.event !== 'string' ||
12
+ !('id' in message) ||
13
+ typeof message.id !== 'string' ||
14
+ !('data' in message) ||
15
+ typeof message.data !== 'object' ||
16
+ message.data === null) {
17
+ return false;
18
+ }
19
+ return message.event.startsWith('app:secure-storage:');
20
+ }
21
+ /**
22
+ * Handles secure storage operations from WebView messages
23
+ */
24
+ export async function handleSecureStorageMessage(message) {
25
+ console.log('Handling secure storage message:', message);
26
+ switch (message.event) {
27
+ case 'app:secure-storage:get': {
28
+ const { key } = message.data;
29
+ try {
30
+ const value = await SecureStore.getItemAsync(normalizeKey(key), {
31
+ keychainAccessible: SecureStore.AFTER_FIRST_UNLOCK_THIS_DEVICE_ONLY,
32
+ });
33
+ return {
34
+ event: message.event,
35
+ id: message.id,
36
+ data: { value },
37
+ };
38
+ }
39
+ catch (error) {
40
+ console.warn('Failed to get the value from secure store', error);
41
+ return {
42
+ event: message.event,
43
+ id: message.id,
44
+ data: { value: null },
45
+ };
46
+ }
47
+ }
48
+ case 'app:secure-storage:set': {
49
+ const { key, value } = message.data;
50
+ try {
51
+ await SecureStore.setItemAsync(normalizeKey(key), value, {
52
+ keychainAccessible: SecureStore.AFTER_FIRST_UNLOCK_THIS_DEVICE_ONLY,
53
+ });
54
+ return {
55
+ event: message.event,
56
+ id: message.id,
57
+ data: { success: true },
58
+ };
59
+ }
60
+ catch (error) {
61
+ console.warn('Failed to write the value to secure store', error);
62
+ return {
63
+ event: message.event,
64
+ id: message.id,
65
+ data: { success: false },
66
+ };
67
+ }
68
+ }
69
+ case 'app:secure-storage:remove': {
70
+ const { key } = message.data;
71
+ try {
72
+ await SecureStore.deleteItemAsync(normalizeKey(key), {
73
+ keychainAccessible: SecureStore.AFTER_FIRST_UNLOCK_THIS_DEVICE_ONLY,
74
+ });
75
+ return {
76
+ event: message.event,
77
+ id: message.id,
78
+ data: { success: true },
79
+ };
80
+ }
81
+ catch (error) {
82
+ console.warn('Failed to remove the value from secure store', error);
83
+ return {
84
+ event: message.event,
85
+ id: message.id,
86
+ data: { success: false },
87
+ };
88
+ }
89
+ }
90
+ case 'app:secure-storage:flush': {
91
+ const { origin } = message.data;
92
+ try {
93
+ // Systematically delete all known storage keys for this origin
94
+ // These are the keys used by the iframe signature service
95
+ const storageKeys = [
96
+ 'playerID', 'chainId', 'deviceID', 'accountType', 'address',
97
+ 'ownerAddress', 'share', 'account', 'chainType', 'signerId'
98
+ ];
99
+ const deletePromises = storageKeys.map(async (key) => {
100
+ const fullKey = normalizeKey(`${origin}:${key}`);
101
+ try {
102
+ await SecureStore.deleteItemAsync(fullKey, {
103
+ keychainAccessible: SecureStore.AFTER_FIRST_UNLOCK_THIS_DEVICE_ONLY,
104
+ });
105
+ }
106
+ catch (error) {
107
+ // Ignore errors for keys that don't exist
108
+ console.debug(`Key ${fullKey} not found during flush:`, error);
109
+ }
110
+ });
111
+ await Promise.all(deletePromises);
112
+ console.log('Flushed secure storage for origin:', origin);
113
+ return {
114
+ event: message.event,
115
+ id: message.id,
116
+ data: { success: true },
117
+ };
118
+ }
119
+ catch (error) {
120
+ console.warn('Failed to flush secure store', error);
121
+ return {
122
+ event: message.event,
123
+ id: message.id,
124
+ data: { success: false },
125
+ };
126
+ }
127
+ }
128
+ default:
129
+ throw new Error(`Unknown secure storage event: ${message.event}`);
130
+ }
131
+ }
132
+ /**
133
+ * Normalizes storage keys for compatibility with secure storage
134
+ */
135
+ function normalizeKey(key) {
136
+ return key.replaceAll(':', '-');
137
+ }
138
+ /**
139
+ * Native storage utilities for platform-specific operations
140
+ */
141
+ export const NativeStorageUtils = {
142
+ /**
143
+ * Checks if secure storage is available on the current platform
144
+ */
145
+ isAvailable() {
146
+ return Platform.OS === 'ios' || Platform.OS === 'android';
147
+ },
148
+ /**
149
+ * Gets the platform-specific storage options
150
+ */
151
+ getStorageOptions() {
152
+ return {
153
+ keychainAccessible: SecureStore.AFTER_FIRST_UNLOCK_THIS_DEVICE_ONLY,
154
+ };
155
+ },
156
+ /**
157
+ * Safely checks if a key exists in secure storage
158
+ */
159
+ async keyExists(key) {
160
+ try {
161
+ const value = await SecureStore.getItemAsync(normalizeKey(key), this.getStorageOptions());
162
+ return value !== null;
163
+ }
164
+ catch {
165
+ return false;
166
+ }
167
+ },
168
+ /**
169
+ * Gets all available storage information
170
+ */
171
+ async getStorageInfo() {
172
+ return {
173
+ isAvailable: this.isAvailable(),
174
+ platform: Platform.OS,
175
+ keychainAccessible: SecureStore.AFTER_FIRST_UNLOCK_THIS_DEVICE_ONLY,
176
+ };
177
+ },
178
+ };
@@ -0,0 +1,157 @@
1
+ /* eslint-disable @typescript-eslint/no-explicit-any */
2
+ import React, { useRef, useCallback, useEffect } from 'react';
3
+ import { AppState, Platform, View } from 'react-native';
4
+ import WebView from 'react-native-webview';
5
+ import { isSecureStorageMessage, handleSecureStorageMessage } from './storage';
6
+ /**
7
+ * WebView component for embedded wallet integration
8
+ * Handles secure communication between React Native and the embedded wallet WebView
9
+ * This component is hidden and only used for wallet communication
10
+ */
11
+ export const EmbeddedWalletWebView = ({ client, isClientReady, onProxyStatusChange, }) => {
12
+ const webViewRef = useRef(null);
13
+ // Handle app state changes to monitor WebView health
14
+ useEffect(() => {
15
+ const handleAppStateChange = async (nextAppState) => {
16
+ if (nextAppState === 'active') {
17
+ // Check if embedded wallet is still responsive
18
+ try {
19
+ await client.embeddedWallet.ping(500);
20
+ // if (!isResponsive) {
21
+ // onProxyStatusChange?.('reloading');
22
+ // // client.embeddedWallet.reload();
23
+ // }
24
+ }
25
+ catch (error) {
26
+ console.warn('Failed to ping embedded wallet:', error);
27
+ }
28
+ }
29
+ };
30
+ const subscription = AppState.addEventListener('change', handleAppStateChange);
31
+ return () => subscription?.remove();
32
+ }, [client, onProxyStatusChange]);
33
+ // Handle WebView load events
34
+ const handleLoad = useCallback(() => {
35
+ onProxyStatusChange?.('loaded');
36
+ }, [onProxyStatusChange]);
37
+ const handleError = useCallback((error) => {
38
+ console.error('WebView error:', error);
39
+ }, []);
40
+ // Set up WebView reference with client immediately when both are available
41
+ useEffect(() => {
42
+ if (webViewRef.current) {
43
+ // Simple message poster that uses WebView's postMessage directly
44
+ const messagePoster = {
45
+ postMessage: (message) => {
46
+ webViewRef.current?.postMessage(message);
47
+ }
48
+ };
49
+ client.embeddedWallet.setMessagePoster(messagePoster);
50
+ }
51
+ }, [client, isClientReady]);
52
+ // Clean message handler using the new penpal bridge
53
+ const handleMessage = useCallback(async (event) => {
54
+ try {
55
+ const messageData = JSON.parse(event?.nativeEvent?.data);
56
+ if (!messageData)
57
+ return;
58
+ // Handle secure storage messages
59
+ if (isSecureStorageMessage(messageData)) {
60
+ const response = await handleSecureStorageMessage(messageData);
61
+ webViewRef.current?.postMessage(JSON.stringify(response));
62
+ return;
63
+ }
64
+ // Forward all messages to the embedded wallet
65
+ client.embeddedWallet.onMessage(messageData);
66
+ }
67
+ catch (error) {
68
+ console.error('Failed to handle WebView message:', error);
69
+ // Don't crash the app on message handling errors
70
+ }
71
+ }, [client]);
72
+ // Ref callback to set up message poster immediately
73
+ const handleWebViewRef = useCallback((ref) => {
74
+ if (webViewRef.current !== ref) {
75
+ webViewRef.current = ref;
76
+ }
77
+ if (ref) {
78
+ const messagePoster = {
79
+ postMessage: (message) => {
80
+ ref.postMessage(message);
81
+ }
82
+ };
83
+ client.embeddedWallet.setMessagePoster(messagePoster);
84
+ }
85
+ }, [client]);
86
+ return (React.createElement(View, { style: { width: 0, height: 0, overflow: 'hidden' } },
87
+ React.createElement(WebView, { ref: handleWebViewRef, source: {
88
+ uri: client.embeddedWallet.getURL(),
89
+ }, webviewDebuggingEnabled: true, cacheEnabled: false, injectedJavaScriptObject: { shouldUseAppBackedStorage: true }, cacheMode: "LOAD_NO_CACHE", onLoad: handleLoad, onError: handleError, onMessage: handleMessage })));
90
+ };
91
+ /**
92
+ * Utilities for WebView integration
93
+ */
94
+ export const WebViewUtils = {
95
+ /**
96
+ * Checks if WebView is supported on the current platform
97
+ */
98
+ isSupported() {
99
+ return Platform.OS === 'ios' || Platform.OS === 'android';
100
+ },
101
+ /**
102
+ * Gets platform-specific WebView configuration
103
+ */
104
+ getPlatformConfig() {
105
+ if (Platform.OS === 'ios') {
106
+ return {
107
+ allowsInlineMediaPlayback: false,
108
+ allowsLinkPreview: false,
109
+ bounces: false,
110
+ };
111
+ }
112
+ if (Platform.OS === 'android') {
113
+ return {
114
+ domStorageEnabled: false,
115
+ javaScriptCanOpenWindowsAutomatically: false,
116
+ mixedContentMode: 'never',
117
+ };
118
+ }
119
+ return {};
120
+ },
121
+ /**
122
+ * Creates a secure message for WebView communication
123
+ */
124
+ createSecureMessage(data) {
125
+ return JSON.stringify({
126
+ timestamp: Date.now(),
127
+ platform: Platform.OS,
128
+ data,
129
+ });
130
+ },
131
+ /**
132
+ * Validates a message received from WebView
133
+ */
134
+ validateMessage(message) {
135
+ try {
136
+ const parsed = JSON.parse(message);
137
+ // Basic validation
138
+ if (typeof parsed !== 'object' || parsed === null) {
139
+ return { isValid: false, error: 'Invalid message format' };
140
+ }
141
+ return { isValid: true, data: parsed };
142
+ }
143
+ catch (error) {
144
+ return {
145
+ isValid: false,
146
+ error: error instanceof Error ? error.message : 'Failed to parse message'
147
+ };
148
+ }
149
+ },
150
+ /**
151
+ * Gets WebView user agent for the current platform
152
+ */
153
+ getUserAgent() {
154
+ const baseAgent = 'OpenfortEmbeddedWallet/1.0';
155
+ return `${baseAgent} (${Platform.OS}; ${Platform.Version})`;
156
+ },
157
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,8 @@
1
+ export const mapStatus = (status) => {
2
+ return {
3
+ isLoading: status.status === 'loading',
4
+ isError: status.status === 'error',
5
+ isSuccess: status.status === 'success',
6
+ error: status.error
7
+ };
8
+ };
@@ -0,0 +1,85 @@
1
+ import React from 'react';
2
+ /**
3
+ * Props for the AuthBoundary component
4
+ */
5
+ export interface AuthBoundaryProps {
6
+ /**
7
+ * Component to render while the SDK is initializing and not ready
8
+ */
9
+ loading: React.ReactNode;
10
+ /**
11
+ * Component to render when the user is not authenticated
12
+ */
13
+ unauthenticated: React.ReactNode;
14
+ /**
15
+ * Optional component to render when there's an error during SDK initialization
16
+ * Can be a component or a function that receives the error and returns a component
17
+ */
18
+ error?: React.ReactNode | ((error: Error) => React.ReactNode);
19
+ /**
20
+ * Children to render when the user is authenticated and the SDK is ready
21
+ */
22
+ children: React.ReactNode;
23
+ }
24
+ /**
25
+ * Authentication boundary component that conditionally renders content based on
26
+ * the user's authentication status and SDK readiness.
27
+ *
28
+ * This component simplifies protecting routes and content based on authentication state.
29
+ * It handles three main states:
30
+ * 1. Loading - SDK is initializing
31
+ * 2. Error - SDK encountered an initialization error
32
+ * 3. Unauthenticated - User is not logged in
33
+ * 4. Authenticated - User is logged in and SDK is ready
34
+ *
35
+ * @example
36
+ * ```tsx
37
+ * import { AuthBoundary } from '@openfort/react-native';
38
+ * import { Text, ActivityIndicator } from 'react-native';
39
+ *
40
+ * function App() {
41
+ * return (
42
+ * <AuthBoundary
43
+ * loading={<ActivityIndicator size="large" />}
44
+ * unauthenticated={<LoginScreen />}
45
+ * error={(error) => <Text>Error: {error.message}</Text>}
46
+ * >
47
+ * <AuthenticatedApp />
48
+ * </AuthBoundary>
49
+ * );
50
+ * }
51
+ * ```
52
+ *
53
+ * @example
54
+ * // With React Navigation
55
+ * ```tsx
56
+ * import { AuthBoundary } from '@openfort/react-native';
57
+ * import { NavigationContainer } from '@react-navigation/native';
58
+ * import { createNativeStackNavigator } from '@react-navigation/native-stack';
59
+ *
60
+ * const Stack = createNativeStackNavigator();
61
+ *
62
+ * function App() {
63
+ * return (
64
+ * <NavigationContainer>
65
+ * <AuthBoundary
66
+ * loading={<SplashScreen />}
67
+ * unauthenticated={
68
+ * <Stack.Navigator>
69
+ * <Stack.Screen name="Login" component={LoginScreen} />
70
+ * <Stack.Screen name="Signup" component={SignupScreen} />
71
+ * </Stack.Navigator>
72
+ * }
73
+ * >
74
+ * <Stack.Navigator>
75
+ * <Stack.Screen name="Home" component={HomeScreen} />
76
+ * <Stack.Screen name="Profile" component={ProfileScreen} />
77
+ * </Stack.Navigator>
78
+ * </AuthBoundary>
79
+ * </NavigationContainer>
80
+ * );
81
+ * }
82
+ * ```
83
+ */
84
+ export declare const AuthBoundary: React.FC<AuthBoundaryProps>;
85
+ export default AuthBoundary;
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Openfort React Native SDK Components
3
+ *
4
+ * This module provides React components and hooks for building user interfaces
5
+ * that integrate with the Openfort platform in React Native applications.
6
+ *
7
+ * The components are organized into the following categories:
8
+ * - Authentication boundaries and guards
9
+ */
10
+ export { AuthBoundary } from './AuthBoundary';
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,9 @@
1
+ /**
2
+ * SDK package information
3
+ */
4
+ export declare const SDK_INFO: {
5
+ readonly name: "@openfort/react-native";
6
+ readonly version: "0.1.0";
7
+ readonly description: "React Native client for Openfort";
8
+ readonly homepage: "https://openfort.io/docs";
9
+ };
@@ -0,0 +1 @@
1
+ export * from './config';
@@ -0,0 +1,24 @@
1
+ import { Openfort as OpenfortClient, OpenfortSDKConfiguration } from '@openfort/openfort-js';
2
+ /**
3
+ * Creates an instance of the Openfort client configured for Expo/React Native
4
+ *
5
+ * @param options Configuration options for the Openfort client
6
+ * @returns Configured Openfort client instance
7
+ *
8
+ * @example
9
+ * const client = createOpenfortClient({
10
+ * });
11
+ *
12
+ * const token = await client.getAccessToken();
13
+ */
14
+ export declare function createOpenfortClient({ baseConfiguration, overrides, shieldConfiguration, }: OpenfortSDKConfiguration): OpenfortClient;
15
+ /**
16
+ * Gets or creates the default Openfort client instance
17
+ * @internal
18
+ */
19
+ export declare function getDefaultClient(options?: OpenfortSDKConfiguration): OpenfortClient;
20
+ /**
21
+ * Sets the default Openfort client instance
22
+ * @internal
23
+ */
24
+ export declare function setDefaultClient(client: OpenfortClient): void;