@intra-mart/smartlime 1.5.0 → 2.0.0-dev.20241121
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/lib/_shared/renderTarget.d.ts +11 -11
- package/lib/_shared/renderTarget.js +2 -2
- package/lib/packages/OAuth/Context.d.ts +13 -1
- package/lib/packages/OAuth/hooks/index.d.ts +1 -0
- package/lib/packages/OAuth/hooks/index.js +1 -0
- package/lib/packages/OAuth/hooks/useAuthError.d.ts +2 -0
- package/lib/packages/OAuth/hooks/useAuthError.js +15 -0
- package/lib/packages/OAuth/hooks/useAuthState.d.ts +1 -1
- package/lib/packages/OAuth/hooks/useAuthStateEffect.d.ts +1 -1
- package/lib/packages/OAuth/hooks/useStartAuth.d.ts +1 -1
- package/lib/packages/OAuth/index.d.ts +8 -13
- package/lib/packages/OAuth/index.js +64 -36
- package/package.json +1 -1
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
type ForceRender = () => void;
|
|
2
|
-
export declare const createRenderTarget: () => {
|
|
3
|
-
addEventListener: (callback: ForceRender) => void;
|
|
4
|
-
removeEventListener: (callback: ForceRender) => void;
|
|
5
|
-
dispatch: () => void;
|
|
1
|
+
type ForceRender<T> = (args?: T) => void;
|
|
2
|
+
export declare const createRenderTarget: <T = undefined>() => {
|
|
3
|
+
addEventListener: (callback: ForceRender<T>) => void;
|
|
4
|
+
removeEventListener: (callback: ForceRender<T>) => void;
|
|
5
|
+
dispatch: (args?: T | undefined) => void;
|
|
6
6
|
};
|
|
7
|
-
export type CreateRenderTarget = typeof createRenderTarget
|
|
8
|
-
export type RenderTarget = ReturnType<CreateRenderTarget
|
|
9
|
-
export declare const useRenderTarget: () => {
|
|
10
|
-
addEventListener: (callback: ForceRender) => void;
|
|
11
|
-
removeEventListener: (callback: ForceRender) => void;
|
|
12
|
-
dispatch: () => void;
|
|
7
|
+
export type CreateRenderTarget<T = undefined> = typeof createRenderTarget<T>;
|
|
8
|
+
export type RenderTarget<T = undefined> = ReturnType<CreateRenderTarget<T>>;
|
|
9
|
+
export declare const useRenderTarget: <T = undefined>() => {
|
|
10
|
+
addEventListener: (callback: ForceRender<T>) => void;
|
|
11
|
+
removeEventListener: (callback: ForceRender<T>) => void;
|
|
12
|
+
dispatch: (args?: T | undefined) => void;
|
|
13
13
|
};
|
|
14
14
|
export {};
|
|
@@ -12,11 +12,11 @@ export const createRenderTarget = () => {
|
|
|
12
12
|
}
|
|
13
13
|
}
|
|
14
14
|
};
|
|
15
|
-
const dispatch = () => {
|
|
15
|
+
const dispatch = (args) => {
|
|
16
16
|
for (let i = 0, l = listenerList.length; i < l; i++) {
|
|
17
17
|
const listener = listenerList[i];
|
|
18
18
|
if (listener)
|
|
19
|
-
listener();
|
|
19
|
+
listener(args);
|
|
20
20
|
}
|
|
21
21
|
};
|
|
22
22
|
return {
|
|
@@ -1,6 +1,17 @@
|
|
|
1
1
|
/// <reference types="react" />
|
|
2
|
-
import { AuthState, StartAuthResult } from '.';
|
|
3
2
|
import { RenderTarget } from '../../_shared/renderTarget';
|
|
3
|
+
import { AuthSessionResult } from 'expo-auth-session';
|
|
4
|
+
import { IMOAuthError } from './IMOAuthError';
|
|
5
|
+
export type AuthState = 'initializing' | 'unauthorized' | 'authorized';
|
|
6
|
+
export type StartAuthResult = {
|
|
7
|
+
readonly type: 'cancel' | 'dismiss' | 'opened' | 'locked' | 'error';
|
|
8
|
+
readonly detail: AuthSessionResult;
|
|
9
|
+
} | {
|
|
10
|
+
readonly type: 'success';
|
|
11
|
+
} | {
|
|
12
|
+
readonly type: 'exception';
|
|
13
|
+
readonly exceptionDetail: unknown;
|
|
14
|
+
};
|
|
4
15
|
export interface OAuthContext {
|
|
5
16
|
getAuthState: () => AuthState;
|
|
6
17
|
getToken: () => string | null;
|
|
@@ -10,5 +21,6 @@ export interface OAuthContext {
|
|
|
10
21
|
startAuth: () => Promise<StartAuthResult>;
|
|
11
22
|
tokenRenderTarget: RenderTarget;
|
|
12
23
|
authStateRenderTarget: RenderTarget;
|
|
24
|
+
authErrorRenderTarget: RenderTarget<IMOAuthError>;
|
|
13
25
|
}
|
|
14
26
|
export declare const Context: import("react").Context<OAuthContext | null>;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { useContext, useEffect } from 'react';
|
|
2
|
+
import { Context as DefaultContext } from '../Context';
|
|
3
|
+
import { IMOAuthError } from '../IMOAuthError';
|
|
4
|
+
export const useAuthError = (callBack) => {
|
|
5
|
+
const oauthContext = useContext(DefaultContext);
|
|
6
|
+
if (oauthContext == null) {
|
|
7
|
+
throw new IMOAuthError('useAuthError requires either a Context provide or an ancestor element with a IMOAuthProvider.');
|
|
8
|
+
}
|
|
9
|
+
useEffect(() => {
|
|
10
|
+
oauthContext.authErrorRenderTarget.addEventListener(callBack);
|
|
11
|
+
return () => {
|
|
12
|
+
oauthContext.authErrorRenderTarget.removeEventListener(callBack);
|
|
13
|
+
};
|
|
14
|
+
}, [callBack]);
|
|
15
|
+
};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import { Context as DefaultContext } from '../Context';
|
|
2
|
-
export declare const useAuthState: (Context?: typeof DefaultContext) => import("
|
|
2
|
+
export declare const useAuthState: (Context?: typeof DefaultContext) => import("../Context").AuthState;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import { Context as DefaultContext } from '../Context';
|
|
2
|
-
export declare const useStartAuth: (Context?: typeof DefaultContext) => () => Promise<import("
|
|
2
|
+
export declare const useStartAuth: (Context?: typeof DefaultContext) => () => Promise<import("../Context").StartAuthResult>;
|
|
@@ -1,22 +1,13 @@
|
|
|
1
1
|
/// <reference types="react" />
|
|
2
|
-
import
|
|
2
|
+
import * as SecureStore from 'expo-secure-store';
|
|
3
|
+
import { Prompt } from 'expo-auth-session';
|
|
3
4
|
import { Context as DefaultContext } from './Context';
|
|
4
|
-
export type AuthState = 'initializing' | 'unauthorized' | 'authorized';
|
|
5
5
|
export type TokenState = {
|
|
6
6
|
baseUrl: string;
|
|
7
7
|
accessToken: string;
|
|
8
8
|
refreshToken?: string;
|
|
9
9
|
expirationDate?: number;
|
|
10
10
|
};
|
|
11
|
-
export type StartAuthResult = {
|
|
12
|
-
readonly type: 'cancel' | 'dismiss' | 'opened' | 'locked' | 'error';
|
|
13
|
-
readonly detail: AuthSessionResult;
|
|
14
|
-
} | {
|
|
15
|
-
readonly type: 'success';
|
|
16
|
-
} | {
|
|
17
|
-
readonly type: 'exception';
|
|
18
|
-
readonly exceptionDetail: unknown;
|
|
19
|
-
};
|
|
20
11
|
export declare const IMPrompt: {
|
|
21
12
|
readonly Login: Prompt.Login;
|
|
22
13
|
readonly None: Prompt.None;
|
|
@@ -29,12 +20,16 @@ interface RequestConfig {
|
|
|
29
20
|
state?: string;
|
|
30
21
|
prompt?: Prompt.Login | Prompt.None;
|
|
31
22
|
}
|
|
23
|
+
interface SecureStoreConfig {
|
|
24
|
+
storeKey?: string;
|
|
25
|
+
keychainAccessible?: SecureStore.KeychainAccessibilityConstant;
|
|
26
|
+
}
|
|
32
27
|
interface IMOAuthProps {
|
|
33
28
|
children: JSX.Element;
|
|
34
29
|
requestConfig: RequestConfig;
|
|
35
30
|
remainingTimeToRunRefresh?: number;
|
|
36
|
-
|
|
31
|
+
secureStore?: SecureStoreConfig;
|
|
37
32
|
oauthContext?: typeof DefaultContext;
|
|
38
33
|
}
|
|
39
|
-
export declare const IMOAuth: ({ children, requestConfig, remainingTimeToRunRefresh,
|
|
34
|
+
export declare const IMOAuth: ({ children, requestConfig, remainingTimeToRunRefresh, secureStore, oauthContext, }: IMOAuthProps) => import("react").JSX.Element;
|
|
40
35
|
export {};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as SecureStore from 'expo-secure-store';
|
|
2
2
|
import { exchangeCodeAsync, loadAsync, Prompt, refreshAsync, } from 'expo-auth-session';
|
|
3
3
|
import { useCallback, useLayoutEffect, useMemo, useRef, } from 'react';
|
|
4
|
-
import { Context as DefaultContext } from './Context';
|
|
4
|
+
import { Context as DefaultContext, } from './Context';
|
|
5
5
|
import { IMOAuthError } from './IMOAuthError';
|
|
6
6
|
import { useRenderTarget } from '../../_shared/renderTarget';
|
|
7
7
|
import { useIMBaseUrl } from '../..';
|
|
@@ -51,10 +51,17 @@ const useDiscovery = () => {
|
|
|
51
51
|
};
|
|
52
52
|
}, [encodedBaseUrl]);
|
|
53
53
|
};
|
|
54
|
-
const
|
|
54
|
+
const useStoreConfig = (secureStore) => {
|
|
55
|
+
const storeKey = secureStore?.storeKey;
|
|
56
|
+
const keychainAccessible = secureStore?.keychainAccessible;
|
|
55
57
|
return useMemo(() => {
|
|
56
|
-
return
|
|
57
|
-
|
|
58
|
+
return {
|
|
59
|
+
storeKey: storeKey ? storeKey : DEFAULT_STORAGE_KEY,
|
|
60
|
+
keychainAccessible: keychainAccessible !== void 0
|
|
61
|
+
? keychainAccessible
|
|
62
|
+
: SecureStore.WHEN_UNLOCKED,
|
|
63
|
+
};
|
|
64
|
+
}, [storeKey, keychainAccessible]);
|
|
58
65
|
};
|
|
59
66
|
const useRemainingTimeToRunRefresh = (remainingTimeToRunRefresh) => {
|
|
60
67
|
return useMemo(() => {
|
|
@@ -63,20 +70,26 @@ const useRemainingTimeToRunRefresh = (remainingTimeToRunRefresh) => {
|
|
|
63
70
|
: DEFAULT_REMAINING_TIME_TO_RUN_REFRESH;
|
|
64
71
|
}, [remainingTimeToRunRefresh]);
|
|
65
72
|
};
|
|
66
|
-
const saveTokenStorage = async (
|
|
73
|
+
const saveTokenStorage = async (storeConfig, baseUrl, accessToken, refreshToken, expirationDate) => {
|
|
67
74
|
const item = {
|
|
68
75
|
baseUrl,
|
|
69
76
|
accessToken,
|
|
70
77
|
refreshToken,
|
|
71
78
|
expirationDate,
|
|
72
79
|
};
|
|
73
|
-
return await SecureStore.setItemAsync(
|
|
80
|
+
return await SecureStore.setItemAsync(storeConfig.storeKey, JSON.stringify(item), {
|
|
81
|
+
keychainAccessible: storeConfig.keychainAccessible,
|
|
82
|
+
});
|
|
74
83
|
};
|
|
75
|
-
const deleteTokenStorage = async (
|
|
76
|
-
return await SecureStore.deleteItemAsync(
|
|
84
|
+
const deleteTokenStorage = async (storeConfig) => {
|
|
85
|
+
return await SecureStore.deleteItemAsync(storeConfig.storeKey, {
|
|
86
|
+
keychainAccessible: storeConfig.keychainAccessible,
|
|
87
|
+
});
|
|
77
88
|
};
|
|
78
|
-
const getTokenStorage = async (
|
|
79
|
-
const state = await SecureStore.getItemAsync(
|
|
89
|
+
const getTokenStorage = async (storeConfig) => {
|
|
90
|
+
const state = await SecureStore.getItemAsync(storeConfig.storeKey, {
|
|
91
|
+
keychainAccessible: storeConfig.keychainAccessible,
|
|
92
|
+
});
|
|
80
93
|
if (state == null)
|
|
81
94
|
return;
|
|
82
95
|
const result = JSON.parse(state);
|
|
@@ -116,7 +129,7 @@ const checkExpirationDateOfToken = (expirationDate, remainingTimeToRunRefresh) =
|
|
|
116
129
|
return true;
|
|
117
130
|
return false;
|
|
118
131
|
};
|
|
119
|
-
const useRefresh = (
|
|
132
|
+
const useRefresh = (storeConfig, refreshTokenRef, expirationDateRef, requestConfig, discovery, setToken, destroy) => {
|
|
120
133
|
const baseUrl = useIMBaseUrl();
|
|
121
134
|
const lockedRef = useRef(false);
|
|
122
135
|
const waitingLineRef = useRef([]);
|
|
@@ -163,7 +176,7 @@ const useRefresh = (storageKey, refreshTokenRef, expirationDateRef, requestConfi
|
|
|
163
176
|
}, discovery);
|
|
164
177
|
const { accessToken, refreshToken, expiresIn } = tokenResponse;
|
|
165
178
|
const expirationDate = expiresIn ? createExpirationDate(expiresIn) : 0;
|
|
166
|
-
await saveTokenStorage(
|
|
179
|
+
await saveTokenStorage(storeConfig, baseUrl, accessToken, refreshToken, expirationDate);
|
|
167
180
|
refreshTokenRef.current = refreshToken ? refreshToken : null;
|
|
168
181
|
expirationDateRef.current = expirationDate;
|
|
169
182
|
setToken(accessToken);
|
|
@@ -178,36 +191,49 @@ const useRefresh = (storageKey, refreshTokenRef, expirationDateRef, requestConfi
|
|
|
178
191
|
throw error;
|
|
179
192
|
}
|
|
180
193
|
}
|
|
181
|
-
}, [
|
|
194
|
+
}, [storeConfig, requestConfig, discovery, destroy]);
|
|
182
195
|
};
|
|
183
|
-
const useStartAuth = (
|
|
196
|
+
const useStartAuth = (storeConfig, remainingTimeToRunRefresh, refreshTokenRef, expirationDateRef, requestConfig, discovery, setToken, refresh, setAuthState, authErrorRenderTarget) => {
|
|
184
197
|
const currentBaseUrl = useIMBaseUrl();
|
|
185
198
|
useLayoutEffect(() => {
|
|
186
199
|
(async () => {
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
if (
|
|
195
|
-
|
|
200
|
+
try {
|
|
201
|
+
const tokenState = await getTokenStorage(storeConfig);
|
|
202
|
+
if (tokenState) {
|
|
203
|
+
const { baseUrl, accessToken, refreshToken, expirationDate } = tokenState;
|
|
204
|
+
const expired = checkExpirationDateOfToken(expirationDate ? expirationDate : 0, remainingTimeToRunRefresh);
|
|
205
|
+
refreshTokenRef.current = refreshToken ? refreshToken : null;
|
|
206
|
+
expirationDateRef.current = expirationDate ? expirationDate : null;
|
|
207
|
+
if (currentBaseUrl === baseUrl) {
|
|
208
|
+
if (expired) {
|
|
209
|
+
await refresh(); // NOTE consideration of how users can catch errors thrown here.
|
|
210
|
+
}
|
|
211
|
+
else {
|
|
212
|
+
setToken(accessToken);
|
|
213
|
+
}
|
|
214
|
+
setAuthState('authorized');
|
|
196
215
|
}
|
|
197
216
|
else {
|
|
198
|
-
|
|
217
|
+
setAuthState('unauthorized');
|
|
199
218
|
}
|
|
200
|
-
setAuthState('authorized');
|
|
201
219
|
}
|
|
202
220
|
else {
|
|
203
221
|
setAuthState('unauthorized');
|
|
204
222
|
}
|
|
205
223
|
}
|
|
206
|
-
|
|
224
|
+
catch (e) {
|
|
207
225
|
setAuthState('unauthorized');
|
|
226
|
+
authErrorRenderTarget.dispatch(new IMOAuthError('an exception occurred while checking the token state.', {
|
|
227
|
+
cause: e,
|
|
228
|
+
}));
|
|
208
229
|
}
|
|
209
230
|
})();
|
|
210
|
-
}, [
|
|
231
|
+
}, [
|
|
232
|
+
storeConfig.storeKey,
|
|
233
|
+
storeConfig.keychainAccessible,
|
|
234
|
+
remainingTimeToRunRefresh,
|
|
235
|
+
refresh,
|
|
236
|
+
]);
|
|
211
237
|
const startAuth = useCallback(async () => {
|
|
212
238
|
const authRequest = await loadAsync({
|
|
213
239
|
...requestConfig,
|
|
@@ -236,7 +262,7 @@ const useStartAuth = (storageKey, remainingTimeToRunRefresh, refreshTokenRef, ex
|
|
|
236
262
|
}, discovery);
|
|
237
263
|
const { accessToken, refreshToken, expiresIn } = tokenResponse;
|
|
238
264
|
const expirationDate = expiresIn ? createExpirationDate(expiresIn) : 0;
|
|
239
|
-
await saveTokenStorage(
|
|
265
|
+
await saveTokenStorage(storeConfig, currentBaseUrl, accessToken, refreshToken, expirationDate);
|
|
240
266
|
refreshTokenRef.current = refreshToken ? refreshToken : null;
|
|
241
267
|
expirationDateRef.current = expirationDate;
|
|
242
268
|
setToken(accessToken);
|
|
@@ -256,14 +282,14 @@ const useStartAuth = (storageKey, remainingTimeToRunRefresh, refreshTokenRef, ex
|
|
|
256
282
|
}, [requestConfig, discovery]);
|
|
257
283
|
return startAuth;
|
|
258
284
|
};
|
|
259
|
-
const useDestroy = (
|
|
285
|
+
const useDestroy = (storeConfig, refreshTokenRef, expirationDateRef, setToken, setAuthState) => {
|
|
260
286
|
return useCallback(async () => {
|
|
261
|
-
await deleteTokenStorage(
|
|
287
|
+
await deleteTokenStorage(storeConfig);
|
|
262
288
|
setToken(null);
|
|
263
289
|
refreshTokenRef.current = null;
|
|
264
290
|
expirationDateRef.current = null;
|
|
265
291
|
setAuthState('unauthorized');
|
|
266
|
-
}, [
|
|
292
|
+
}, [storeConfig, setAuthState]);
|
|
267
293
|
};
|
|
268
294
|
const useGetTokenAsync = (tokenRef, expirationDateRef, remainingTimeToRunRefresh, refresh) => {
|
|
269
295
|
return useCallback(async () => {
|
|
@@ -276,7 +302,7 @@ const useGetTokenAsync = (tokenRef, expirationDateRef, remainingTimeToRunRefresh
|
|
|
276
302
|
return tokenRef.current;
|
|
277
303
|
}, [refresh]);
|
|
278
304
|
};
|
|
279
|
-
export const IMOAuth = ({ children, requestConfig, remainingTimeToRunRefresh,
|
|
305
|
+
export const IMOAuth = ({ children, requestConfig, remainingTimeToRunRefresh, secureStore, oauthContext, }) => {
|
|
280
306
|
const Context = oauthContext || DefaultContext;
|
|
281
307
|
const contextRef = useRef();
|
|
282
308
|
const authStateRenderTarget = useRenderTarget();
|
|
@@ -285,13 +311,14 @@ export const IMOAuth = ({ children, requestConfig, remainingTimeToRunRefresh, st
|
|
|
285
311
|
const [tokenRef, setToken, getToken] = useTokenRef(tokenRenderTarget);
|
|
286
312
|
const refreshTokenRef = useRef(null);
|
|
287
313
|
const expirationDateRef = useRef(null);
|
|
288
|
-
const
|
|
314
|
+
const storeConfig = useStoreConfig(secureStore);
|
|
289
315
|
const _remainingTimeToRunRefresh = useRemainingTimeToRunRefresh(remainingTimeToRunRefresh);
|
|
290
316
|
const _requestConfig = useRequestConfig(requestConfig);
|
|
291
317
|
const _discovery = useDiscovery();
|
|
292
|
-
const
|
|
293
|
-
const
|
|
294
|
-
const
|
|
318
|
+
const authErrorRenderTarget = useRenderTarget();
|
|
319
|
+
const destroy = useDestroy(storeConfig, refreshTokenRef, expirationDateRef, setToken, setAuthState);
|
|
320
|
+
const refresh = useRefresh(storeConfig, refreshTokenRef, expirationDateRef, _requestConfig, _discovery, setToken, destroy);
|
|
321
|
+
const startAuth = useStartAuth(storeConfig, _remainingTimeToRunRefresh, refreshTokenRef, expirationDateRef, _requestConfig, _discovery, setToken, refresh, setAuthState, authErrorRenderTarget);
|
|
295
322
|
const getTokenAsync = useGetTokenAsync(tokenRef, expirationDateRef, _remainingTimeToRunRefresh, refresh);
|
|
296
323
|
contextRef.current = {
|
|
297
324
|
getAuthState,
|
|
@@ -302,6 +329,7 @@ export const IMOAuth = ({ children, requestConfig, remainingTimeToRunRefresh, st
|
|
|
302
329
|
startAuth,
|
|
303
330
|
tokenRenderTarget,
|
|
304
331
|
authStateRenderTarget,
|
|
332
|
+
authErrorRenderTarget,
|
|
305
333
|
};
|
|
306
334
|
return (<Context.Provider value={contextRef.current}>{children}</Context.Provider>);
|
|
307
335
|
};
|