@openfort/react-native 0.0.3 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (87) 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 +14 -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 +176 -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/useWalletAuth.js +133 -0
  19. package/dist/hooks/core/index.js +9 -0
  20. package/dist/hooks/core/useOpenfort.js +50 -0
  21. package/dist/hooks/core/useOpenfortClient.js +29 -0
  22. package/dist/hooks/core/useUser.js +10 -0
  23. package/dist/hooks/index.js +15 -0
  24. package/dist/hooks/wallet/index.js +7 -0
  25. package/dist/hooks/wallet/useWallets.js +389 -0
  26. package/dist/index.js +24 -1
  27. package/dist/lib/hookConsistency.js +16 -0
  28. package/dist/native/index.js +6 -0
  29. package/dist/native/oauth.js +183 -0
  30. package/dist/native/storage.js +178 -0
  31. package/dist/native/webview.js +157 -0
  32. package/dist/types/auth.js +1 -0
  33. package/dist/types/baseFlowState.js +8 -0
  34. package/dist/types/components/AuthBoundary.d.ts +85 -0
  35. package/dist/types/components/index.d.ts +10 -0
  36. package/dist/types/config.js +1 -0
  37. package/dist/types/constants/config.d.ts +9 -0
  38. package/dist/types/constants/index.d.ts +1 -0
  39. package/dist/types/core/client.d.ts +24 -0
  40. package/dist/types/core/context.d.ts +61 -0
  41. package/dist/types/core/index.d.ts +8 -0
  42. package/dist/types/core/provider.d.ts +126 -0
  43. package/dist/types/core/storage.d.ts +34 -0
  44. package/dist/types/hex.js +1 -0
  45. package/dist/types/hookOption.js +1 -0
  46. package/dist/types/hooks/auth/index.d.ts +10 -0
  47. package/dist/types/hooks/auth/useAuthCallback.d.ts +0 -0
  48. package/dist/types/hooks/auth/useCreateWalletPostAuth.d.ts +6 -0
  49. package/dist/types/hooks/auth/useEmailAuth.d.ts +59 -0
  50. package/dist/types/hooks/auth/useGuestAuth.d.ts +39 -0
  51. package/dist/types/hooks/auth/useOAuth.d.ts +62 -0
  52. package/dist/types/hooks/auth/useSignOut.d.ts +9 -0
  53. package/dist/types/hooks/auth/useWalletAuth.d.ts +48 -0
  54. package/dist/types/hooks/core/index.d.ts +8 -0
  55. package/dist/types/hooks/core/useOpenfort.d.ts +38 -0
  56. package/dist/types/hooks/core/useOpenfortClient.d.ts +29 -0
  57. package/dist/types/hooks/core/useUser.d.ts +5 -0
  58. package/dist/types/hooks/index.d.ts +12 -0
  59. package/dist/types/hooks/wallet/index.d.ts +6 -0
  60. package/dist/types/hooks/wallet/useWallets.d.ts +74 -0
  61. package/dist/types/index.d.ts +18 -1
  62. package/dist/types/index.js +2 -0
  63. package/dist/types/lib/hookConsistency.d.ts +14 -0
  64. package/dist/types/native/index.d.ts +5 -0
  65. package/dist/types/native/oauth.d.ts +91 -0
  66. package/dist/types/native/storage.d.ts +50 -0
  67. package/dist/types/native/webview.d.ts +50 -0
  68. package/dist/types/oauth.js +8 -0
  69. package/dist/types/openfortError.js +27 -0
  70. package/dist/types/predicates.js +101 -0
  71. package/dist/types/state.js +1 -0
  72. package/dist/types/types/auth.d.ts +168 -0
  73. package/dist/types/types/baseFlowState.d.ts +14 -0
  74. package/dist/types/types/config.d.ts +71 -0
  75. package/dist/types/types/hex.d.ts +1 -0
  76. package/dist/types/types/hookOption.d.ts +9 -0
  77. package/dist/types/types/index.d.ts +38 -0
  78. package/dist/types/types/oauth.d.ts +74 -0
  79. package/dist/types/types/openfortError.d.ts +13 -0
  80. package/dist/types/types/predicates.d.ts +64 -0
  81. package/dist/types/types/state.d.ts +0 -0
  82. package/dist/types/types/wallet.d.ts +262 -0
  83. package/dist/types/wallet.js +1 -0
  84. package/package.json +33 -19
  85. package/dist/Iframe.js +0 -84
  86. package/dist/types/Iframe.d.ts +0 -6
  87. package/polyfills/index.ts +0 -89
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Authentication hooks index
3
+ *
4
+ * This module re-exports all authentication-related hooks for convenient importing.
5
+ */
6
+ // Email authentication
7
+ export { useEmailAuth } from './useEmailAuth';
8
+ // OAuth authentication
9
+ export { useOAuth } from './useOAuth';
10
+ // Wallet-based authentication (SIWE)
11
+ export { useWalletAuth } from './useWalletAuth';
12
+ // Guest accounts
13
+ export { useGuestAuth } from './useGuestAuth';
14
+ export { useSignOut } from './useSignOut';
@@ -0,0 +1 @@
1
+ "use strict";
@@ -0,0 +1,22 @@
1
+ import { useCallback } from "react";
2
+ // this hook is used to create a wallet after the user has authenticated
3
+ export const useCreateWalletPostAuth = () => {
4
+ // This would connect to the wallet and set it as active
5
+ // eslint-disable-next-line no-empty-pattern
6
+ const tryUseWallet = useCallback(async ({}) => {
7
+ // if (!walletConfig || walletConfig.recoveryMethod !== RecoveryMethod.AUTOMATIC || !automaticRecovery) {
8
+ // return {};
9
+ // }
10
+ // const wallet = await setActiveWallet({
11
+ // connector: embeddedWalletId,
12
+ // });
13
+ // if (wallet.error && signOutOnError) {
14
+ // // If there was an error and we should log out, we can call the logout function
15
+ // await signOut();
16
+ // }
17
+ return { wallet: undefined };
18
+ }, [ /* walletConfig, setActiveWallet, signOut */]);
19
+ return {
20
+ tryUseWallet,
21
+ };
22
+ };
@@ -0,0 +1,176 @@
1
+ import { useCallback } from 'react';
2
+ import { useOpenfortContext } from '../../core/context';
3
+ import { onError, onSuccess } from '../../lib/hookConsistency';
4
+ import { OpenfortError, OpenfortErrorType } from '../../types/openfortError';
5
+ const mapStatus = (status) => {
6
+ return {
7
+ isLoading: status.status === 'submitting-code' || status.status === 'sending-verification-code',
8
+ isError: status.status === 'error',
9
+ isSuccess: status.status === 'done',
10
+ requiresEmailVerification: status.status === 'awaiting-code-input',
11
+ error: "error" in status ? status.error : null,
12
+ };
13
+ };
14
+ export const useEmailAuth = (hookOptions = {}) => {
15
+ const { client, setPasswordState, _internal, passwordState } = useOpenfortContext();
16
+ const signInEmail = useCallback(async (options) => {
17
+ try {
18
+ setPasswordState({ status: 'sending-verification-code' });
19
+ // Login with email and password
20
+ const result = await client.auth.logInWithEmailPassword({
21
+ email: options.email,
22
+ password: options.password,
23
+ });
24
+ // Check if action is required (email verification)
25
+ if ('action' in result) {
26
+ setPasswordState({
27
+ status: 'awaiting-code-input',
28
+ });
29
+ // Return undefined as email verification is required
30
+ return onSuccess({
31
+ hookOptions,
32
+ options,
33
+ data: { requiresEmailVerification: true },
34
+ });
35
+ }
36
+ else {
37
+ // Login successful
38
+ setPasswordState({ status: 'done' });
39
+ const user = result.player;
40
+ // Refresh user state in provider
41
+ await _internal.refreshUserState(user);
42
+ return onSuccess({
43
+ hookOptions,
44
+ options,
45
+ data: { user },
46
+ });
47
+ }
48
+ }
49
+ catch (e) {
50
+ const error = new OpenfortError('Failed to login with email and password', OpenfortErrorType.AUTHENTICATION_ERROR, { error: e });
51
+ setPasswordState({
52
+ status: 'error',
53
+ error
54
+ });
55
+ return onError({
56
+ hookOptions,
57
+ options,
58
+ error
59
+ });
60
+ }
61
+ }, [client, setPasswordState, _internal, hookOptions]);
62
+ const signUpEmail = useCallback(async (options) => {
63
+ try {
64
+ setPasswordState({ status: 'sending-verification-code' });
65
+ // Sign up with email and password
66
+ const result = await client.auth.signUpWithEmailPassword({
67
+ email: options.email,
68
+ password: options.password,
69
+ ...(options.name && { name: options.name }),
70
+ });
71
+ // Check if action is required (email verification)
72
+ if ('action' in result) {
73
+ setPasswordState({
74
+ status: 'awaiting-code-input',
75
+ });
76
+ // Return undefined as email verification is required
77
+ return onSuccess({
78
+ hookOptions,
79
+ options,
80
+ data: { requiresEmailVerification: true },
81
+ });
82
+ }
83
+ else {
84
+ // Signup successful
85
+ setPasswordState({ status: 'done' });
86
+ const user = result.player;
87
+ // Refresh user state in provider
88
+ await _internal.refreshUserState(user);
89
+ return onSuccess({
90
+ hookOptions,
91
+ options,
92
+ data: { user },
93
+ });
94
+ }
95
+ }
96
+ catch (e) {
97
+ const error = new OpenfortError('Failed to signup with email and password', OpenfortErrorType.AUTHENTICATION_ERROR, { error: e });
98
+ setPasswordState({
99
+ status: 'error',
100
+ error
101
+ });
102
+ return onError({
103
+ hookOptions,
104
+ options,
105
+ error
106
+ });
107
+ }
108
+ }, [client, setPasswordState, _internal, hookOptions]);
109
+ const linkEmail = useCallback(async (options) => {
110
+ try {
111
+ setPasswordState({ status: 'sending-verification-code' });
112
+ // Get current user access token
113
+ const accessToken = await client.getAccessToken();
114
+ if (!accessToken) {
115
+ throw new Error('User must be authenticated to link email');
116
+ }
117
+ // Link email account
118
+ const result = await client.auth.linkEmailPassword({
119
+ email: options.email,
120
+ password: options.password,
121
+ authToken: accessToken,
122
+ });
123
+ // Check if action is required (email verification)
124
+ if ('action' in result) {
125
+ setPasswordState({
126
+ status: 'awaiting-code-input',
127
+ });
128
+ // Return undefined as email verification is required
129
+ return onSuccess({
130
+ hookOptions,
131
+ options,
132
+ data: { requiresEmailVerification: true },
133
+ });
134
+ }
135
+ else {
136
+ // Link successful
137
+ setPasswordState({ status: 'done' });
138
+ // Refresh user state to reflect email linking
139
+ await _internal.refreshUserState();
140
+ return onSuccess({
141
+ hookOptions,
142
+ options,
143
+ data: { user: result },
144
+ });
145
+ }
146
+ }
147
+ catch (e) {
148
+ const error = new OpenfortError('Failed to link email and password', OpenfortErrorType.AUTHENTICATION_ERROR, { error: e });
149
+ setPasswordState({
150
+ status: 'error',
151
+ error
152
+ });
153
+ return onError({
154
+ hookOptions,
155
+ options,
156
+ error
157
+ });
158
+ }
159
+ }, [client, setPasswordState, _internal, hookOptions]);
160
+ const verifyEmail = () => { }; // TODO
161
+ const resetPassword = () => { }; // TODO
162
+ const requestResetPassword = () => { }; // TODO
163
+ const reset = () => {
164
+ setPasswordState({ status: 'initial' });
165
+ };
166
+ return {
167
+ signInEmail,
168
+ signUpEmail,
169
+ verifyEmail,
170
+ linkEmail,
171
+ requestResetPassword,
172
+ resetPassword,
173
+ reset,
174
+ ...mapStatus(passwordState),
175
+ };
176
+ };
@@ -0,0 +1,52 @@
1
+ import { useCallback, useState } from 'react';
2
+ import { useOpenfortContext } from '../../core/context';
3
+ import { onError, onSuccess } from '../../lib/hookConsistency';
4
+ import { mapStatus } from '../../types/baseFlowState';
5
+ import { OpenfortError, OpenfortErrorType } from '../../types/openfortError';
6
+ export const useGuestAuth = (hookOptions = {}) => {
7
+ const { client, _internal } = useOpenfortContext();
8
+ const { refreshUserState: updateUser } = _internal;
9
+ const [status, setStatus] = useState({
10
+ status: "idle",
11
+ });
12
+ // const { tryUseWallet } = useCreateWalletPostAuth();
13
+ const signUpGuest = useCallback(async (options = {}) => {
14
+ try {
15
+ setStatus({
16
+ status: 'loading',
17
+ });
18
+ const result = await client.auth.signUpGuest();
19
+ const user = result.player;
20
+ await updateUser(user);
21
+ // const { wallet } = await tryUseWallet({
22
+ // logoutOnError: options.logoutOnError || hookOptions.logoutOnError,
23
+ // automaticRecovery: options.automaticRecovery || hookOptions.automaticRecovery,
24
+ // });
25
+ setStatus({
26
+ status: 'success',
27
+ });
28
+ onSuccess({
29
+ hookOptions,
30
+ options,
31
+ data: { user },
32
+ });
33
+ return { user, /* wallet */ };
34
+ }
35
+ catch (error) {
36
+ const openfortError = new OpenfortError("Failed to signup guest", OpenfortErrorType.AUTHENTICATION_ERROR, { error });
37
+ setStatus({
38
+ status: 'error',
39
+ error: openfortError,
40
+ });
41
+ return onError({
42
+ hookOptions,
43
+ options,
44
+ error: openfortError,
45
+ });
46
+ }
47
+ }, [client, setStatus, updateUser, hookOptions]);
48
+ return {
49
+ signUpGuest,
50
+ ...mapStatus(status),
51
+ };
52
+ };
@@ -0,0 +1,292 @@
1
+ /**
2
+ * Hook for OAuth-based login functionality
3
+ */
4
+ import { OAuthProvider } from '@openfort/openfort-js';
5
+ import { useCallback } from 'react';
6
+ import { useOpenfortContext } from '../../core/context';
7
+ import { authenticateWithApple, createOAuthRedirectUri, isAppleSignInAvailable, OAuthUtils, openOAuthSession, parseOAuthUrl, } from '../../native';
8
+ import { mapOAuthStatus } from "../../types/oauth";
9
+ import { OpenfortError, OpenfortErrorType } from '../../types/openfortError';
10
+ import { onError, onSuccess } from '../../lib/hookConsistency';
11
+ /**
12
+ * Hook for OAuth-based authentication with supported providers
13
+ *
14
+ * This hook provides OAuth authentication flow for various providers (Google, Apple, Discord, etc.).
15
+ * It opens the provider's web authentication page and handles the OAuth flow automatically.
16
+ *
17
+ * @param opts - Configuration options including success/error callbacks
18
+ * @returns Object with login function and current OAuth flow state
19
+ *
20
+ * @example
21
+ * ```tsx
22
+ * const { login, state } = useLoginWithOAuth({
23
+ * onSuccess: (user) => console.log('OAuth login successful:', user),
24
+ * onError: (error) => console.error('OAuth login failed:', error),
25
+ * });
26
+ *
27
+ * // Login with Google
28
+ * const user = await login({ provider: 'google' });
29
+ *
30
+ * // Login with Apple (using legacy web flow on iOS if needed)
31
+ * const user = await login({
32
+ * provider: 'apple',
33
+ * isLegacyAppleIosBehaviorEnabled: true
34
+ * });
35
+ *
36
+ * // Other supported providers
37
+ * await login({ provider: 'discord' });
38
+ * await login({ provider: 'twitter' });
39
+ * ```
40
+ */
41
+ export const useOAuth = (hookOptions = {}) => {
42
+ const { client, oAuthState, setOAuthState, _internal } = useOpenfortContext();
43
+ const initOAuth = useCallback(async (options) => {
44
+ try {
45
+ setOAuthState({ status: 'loading' });
46
+ // Initialize OAuth flow
47
+ const redirectUri = options.redirectTo || createOAuthRedirectUri('/oauth/callback');
48
+ const result = await client.auth.initOAuth({
49
+ provider: options.provider,
50
+ options: {
51
+ skipBrowserRedirect: true,
52
+ redirectTo: redirectUri,
53
+ }
54
+ });
55
+ // Handle OAuth flow using native utilities
56
+ setOAuthState({ status: 'awaiting-redirect' });
57
+ // Check if we should use native Apple authentication
58
+ if (options.provider === 'apple' && !options.isLegacyAppleIosBehaviorEnabled) {
59
+ const isAppleAvailable = await isAppleSignInAvailable();
60
+ if (isAppleAvailable) {
61
+ try {
62
+ const appleResult = await authenticateWithApple({
63
+ state: result.key || '',
64
+ isLogin: true,
65
+ });
66
+ // Complete OAuth flow with Apple credentials
67
+ const authResult = await client.auth.loginWithIdToken({
68
+ provider: OAuthProvider.APPLE,
69
+ token: appleResult.identityToken,
70
+ });
71
+ setOAuthState({ status: 'done' });
72
+ const user = authResult.player;
73
+ // Refresh user state in provider
74
+ await _internal.refreshUserState(user);
75
+ return onSuccess({
76
+ options,
77
+ hookOptions,
78
+ data: { user },
79
+ });
80
+ }
81
+ catch (e) {
82
+ const error = new OpenfortError('Apple authentication failed', OpenfortErrorType.AUTHENTICATION_ERROR, { error: e });
83
+ setOAuthState({
84
+ status: 'error',
85
+ error,
86
+ });
87
+ return onError({
88
+ options,
89
+ hookOptions,
90
+ error,
91
+ });
92
+ }
93
+ }
94
+ }
95
+ // For other providers, use web-based OAuth
96
+ const providerUrl = OAuthUtils.getProviderUrl(options.provider, result.url);
97
+ const oauthResult = await OAuthUtils.withTimeout(openOAuthSession({
98
+ url: providerUrl,
99
+ redirectUri,
100
+ }), 120000 // 2 minute timeout
101
+ );
102
+ if (oauthResult.type === 'success' && oauthResult.url) {
103
+ // Parse OAuth response from redirect URL
104
+ const { access_token, refresh_token, player_id, error, errorDescription } = parseOAuthUrl(oauthResult.url);
105
+ if (error) {
106
+ throw new Error(errorDescription || error);
107
+ }
108
+ await client.auth.storeCredentials({
109
+ player: player_id,
110
+ accessToken: access_token,
111
+ refreshToken: refresh_token,
112
+ });
113
+ setOAuthState({ status: 'done' });
114
+ const user = await client.user.get();
115
+ // Refresh user state in provider
116
+ await _internal.refreshUserState(user);
117
+ return onSuccess({
118
+ options,
119
+ hookOptions,
120
+ data: { user },
121
+ });
122
+ }
123
+ else if (oauthResult.type === 'cancel') {
124
+ const error = new OpenfortError('OAuth authentication was cancelled by user', OpenfortErrorType.AUTHENTICATION_ERROR);
125
+ setOAuthState({
126
+ status: 'error',
127
+ error,
128
+ });
129
+ return onError({
130
+ options,
131
+ hookOptions,
132
+ error,
133
+ });
134
+ }
135
+ else {
136
+ const error = new OpenfortError(oauthResult.error || 'OAuth authentication failed', OpenfortErrorType.AUTHENTICATION_ERROR);
137
+ setOAuthState({
138
+ status: 'error',
139
+ error,
140
+ });
141
+ return onError({
142
+ options,
143
+ hookOptions,
144
+ error,
145
+ });
146
+ }
147
+ }
148
+ catch (e) {
149
+ const error = new OpenfortError('OAuth initialization failed', OpenfortErrorType.AUTHENTICATION_ERROR, { error: e });
150
+ setOAuthState({
151
+ status: 'error',
152
+ error
153
+ });
154
+ return onError({
155
+ options,
156
+ hookOptions,
157
+ error,
158
+ });
159
+ }
160
+ }, [client, setOAuthState, _internal]);
161
+ const linkOauth = useCallback(async (options) => {
162
+ try {
163
+ setOAuthState({ status: 'loading' });
164
+ // Get current user access token for linking
165
+ const accessToken = await client.getAccessToken();
166
+ if (!accessToken) {
167
+ throw new Error('User must be authenticated to link OAuth account');
168
+ }
169
+ // Initialize OAuth linking flow
170
+ const redirectUri = options.redirectTo || createOAuthRedirectUri('/oauth/callback');
171
+ const result = await client.auth.initLinkOAuth({
172
+ provider: options.provider,
173
+ authToken: accessToken,
174
+ options: {
175
+ skipBrowserRedirect: true,
176
+ redirectTo: redirectUri,
177
+ }
178
+ });
179
+ // Handle OAuth linking flow using native utilities
180
+ setOAuthState({ status: 'awaiting-redirect' });
181
+ // Check if we should use native Apple authentication for linking
182
+ if (options.provider === 'apple' && !options.isLegacyAppleIosBehaviorEnabled) {
183
+ const isAppleAvailable = await isAppleSignInAvailable();
184
+ if (isAppleAvailable) {
185
+ try {
186
+ const appleResult = await authenticateWithApple({
187
+ state: result.key || '',
188
+ isLogin: false, // This is a linking operation
189
+ });
190
+ // Complete OAuth linking flow with Apple credentials
191
+ const linkResult = await client.auth.loginWithIdToken({
192
+ provider: OAuthProvider.APPLE,
193
+ token: appleResult.identityToken
194
+ });
195
+ setOAuthState({ status: 'done' });
196
+ const user = linkResult.player;
197
+ // Refresh user state to reflect OAuth linking
198
+ await _internal.refreshUserState();
199
+ return onSuccess({
200
+ options,
201
+ hookOptions,
202
+ data: { user },
203
+ });
204
+ }
205
+ catch (e) {
206
+ const error = new OpenfortError('Apple linking failed', OpenfortErrorType.AUTHENTICATION_ERROR, { error: e });
207
+ setOAuthState({
208
+ status: 'error',
209
+ error,
210
+ });
211
+ return onError({
212
+ options,
213
+ hookOptions,
214
+ error,
215
+ });
216
+ }
217
+ }
218
+ }
219
+ // For other providers, use web-based OAuth
220
+ const providerUrl = OAuthUtils.getProviderUrl(options.provider, result.url);
221
+ const oauthResult = await OAuthUtils.withTimeout(openOAuthSession({
222
+ url: providerUrl,
223
+ redirectUri,
224
+ }), 120000 // 2 minute timeout
225
+ );
226
+ if (oauthResult.type === 'success' && oauthResult.url) {
227
+ // Parse OAuth response from redirect URL
228
+ const { access_token, refresh_token, player_id, error, errorDescription } = parseOAuthUrl(oauthResult.url);
229
+ if (error) {
230
+ throw new Error(errorDescription || error);
231
+ }
232
+ await client.auth.storeCredentials({
233
+ player: player_id,
234
+ accessToken: access_token,
235
+ refreshToken: refresh_token,
236
+ });
237
+ setOAuthState({ status: 'done' });
238
+ const user = await client.user.get();
239
+ // Refresh user state in provider
240
+ await _internal.refreshUserState(user);
241
+ return onSuccess({
242
+ options,
243
+ hookOptions,
244
+ data: { user },
245
+ });
246
+ }
247
+ else if (oauthResult.type === 'cancel') {
248
+ const error = new OpenfortError('OAuth linking was cancelled by user', OpenfortErrorType.AUTHENTICATION_ERROR);
249
+ setOAuthState({
250
+ status: 'error',
251
+ error,
252
+ });
253
+ return onError({
254
+ options,
255
+ hookOptions,
256
+ error,
257
+ });
258
+ }
259
+ else {
260
+ const error = new OpenfortError(oauthResult.error || 'OAuth linking failed', OpenfortErrorType.AUTHENTICATION_ERROR);
261
+ setOAuthState({
262
+ status: 'error',
263
+ error,
264
+ });
265
+ return onError({
266
+ options,
267
+ hookOptions,
268
+ error,
269
+ });
270
+ }
271
+ }
272
+ catch (e) {
273
+ const error = new OpenfortError('OAuth linking failed', OpenfortErrorType.AUTHENTICATION_ERROR, { error: e });
274
+ setOAuthState({
275
+ status: 'error',
276
+ error
277
+ });
278
+ return onError({
279
+ options,
280
+ hookOptions,
281
+ error
282
+ });
283
+ }
284
+ }, [client, setOAuthState, _internal]);
285
+ const storeCredentials = () => { }; // TODO
286
+ return {
287
+ initOAuth,
288
+ linkOauth,
289
+ storeCredentials,
290
+ ...mapOAuthStatus(oAuthState),
291
+ };
292
+ };
@@ -0,0 +1,48 @@
1
+ import { useCallback, useState } from "react";
2
+ import { useOpenfortContext } from "../../core";
3
+ import { onError, onSuccess } from "../../lib/hookConsistency";
4
+ import { mapStatus } from "../../types/baseFlowState";
5
+ import { OpenfortError, OpenfortErrorType } from "../../types/openfortError";
6
+ import { useOpenfortClient } from "../core";
7
+ export function useSignOut(hookOptions = {}) {
8
+ const client = useOpenfortClient();
9
+ const { _internal, user } = useOpenfortContext();
10
+ const [status, setStatus] = useState({
11
+ status: "idle",
12
+ });
13
+ const signOut = useCallback(async (options = {}) => {
14
+ if (!user)
15
+ return;
16
+ setStatus({
17
+ status: 'loading',
18
+ });
19
+ try {
20
+ await client.auth.logout();
21
+ _internal.refreshUserState();
22
+ setStatus({
23
+ status: 'success',
24
+ });
25
+ return onSuccess({
26
+ hookOptions,
27
+ options,
28
+ data: {},
29
+ });
30
+ }
31
+ catch (e) {
32
+ const error = new OpenfortError('Failed to sign out', OpenfortErrorType.AUTHENTICATION_ERROR, { error: e });
33
+ setStatus({
34
+ status: 'error',
35
+ error,
36
+ });
37
+ return onError({
38
+ hookOptions,
39
+ options,
40
+ error,
41
+ });
42
+ }
43
+ }, [client, user, _internal.refreshUserState, setStatus, hookOptions]);
44
+ return {
45
+ ...mapStatus(status),
46
+ signOut,
47
+ };
48
+ }