@versini/auth0-react-thin 2.23.0 → 2.24.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/auth0-context.d.ts +9 -0
- package/dist/auth0-context.d.ts.map +1 -1
- package/dist/auth0-provider.d.ts.map +1 -1
- package/dist/auth0-react.cjs.js +161 -41
- package/dist/auth0-react.cjs.js.map +1 -1
- package/dist/auth0-react.esm.js +148 -47
- package/dist/auth0-react.esm.js.map +1 -1
- package/dist/auth0-react.js +161 -41
- package/dist/auth0-react.js.map +1 -1
- package/dist/auth0-react.min.js +1 -1
- package/dist/auth0-react.min.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/use-auth0-suspense.d.ts +35 -0
- package/dist/use-auth0-suspense.d.ts.map +1 -0
- package/package.json +3 -3
- package/src/auth0-context.tsx +10 -0
- package/src/auth0-provider.tsx +82 -10
- package/src/index.tsx +4 -0
- package/src/use-auth0-suspense.tsx +71 -0
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export { default as Auth0Provider, Auth0ProviderOptions, Auth0ProviderWithConfigOptions, Auth0ProviderWithClientOptions, AppState, ConnectedAccount } from './auth0-provider';
|
|
2
2
|
export { default as useAuth0 } from './use-auth0';
|
|
3
|
+
export { default as useAuth0Suspense, Auth0SuspenseContextInterface, } from './use-auth0-suspense';
|
|
3
4
|
export { default as withAuth0, WithAuth0Props } from './with-auth0';
|
|
4
5
|
export { default as withAuthenticationRequired, WithAuthenticationRequiredOptions, } from './with-authentication-required';
|
|
5
6
|
export { default as Auth0Context, Auth0ContextInterface, initialContext, LogoutOptions, RedirectLoginOptions, } from './auth0-context';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.tsx"],"names":[],"mappings":"AAAA,OAAO,EACL,OAAO,IAAI,aAAa,EACxB,oBAAoB,EACpB,8BAA8B,EAC9B,8BAA8B,EAC9B,QAAQ,EACR,gBAAgB,EACjB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,OAAO,IAAI,QAAQ,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AACpE,OAAO,EACL,OAAO,IAAI,0BAA0B,EACrC,iCAAiC,GAClC,MAAM,gCAAgC,CAAC;AACxC,OAAO,EACL,OAAO,IAAI,YAAY,EACvB,qBAAqB,EACrB,cAAc,EACd,aAAa,EACb,oBAAoB,GACrB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,mBAAmB,EACnB,iBAAiB,EACjB,kBAAkB,EAClB,wBAAwB,EACxB,gBAAgB,EAChB,aAAa,EACb,uBAAuB,EACvB,OAAO,EACP,IAAI,EACJ,MAAM,EACN,aAAa,EACb,iBAAiB,EACjB,SAAS,EACT,YAAY,EACZ,gBAAgB,EAChB,mBAAmB,EACnB,iBAAiB,EACjB,cAAc,EACd,mBAAmB,EACnB,wBAAwB,EACxB,kBAAkB,EAClB,yBAAyB,EACzB,YAAY,EACZ,iBAAiB,EACjB,6BAA6B,EAC7B,4BAA4B,EAC5B,YAAY,EACZ,YAAY,EACZ,0BAA0B,EAC1B,qBAAqB,EACrB,QAAQ,EACR,mBAAmB,EACnB,gBAAgB,EAEhB,QAAQ,EACR,0BAA0B,EAC1B,kBAAkB,EAClB,iBAAiB,EACjB,cAAc,EACd,yBAAyB,EAEzB,YAAY,EACZ,oBAAoB,EACpB,qBAAqB,EACrB,oBAAoB,EAEpB,iBAAiB,GAClB,MAAM,qBAAqB,CAAC;AAC7B,YAAY,EACV,yBAAyB,EACzB,aAAa,EACb,uBAAuB,EAEvB,YAAY,EACZ,aAAa,EACb,aAAa,EACb,YAAY,EACZ,eAAe,EACf,eAAe,EACf,iBAAiB,EACjB,iBAAiB,EACjB,gBAAgB,EAChB,kBAAkB,EAClB,4BAA4B,EAC5B,iBAAiB,EACjB,YAAY,EACZ,gBAAgB,EAEhB,gBAAgB,EAChB,oBAAoB,EACpB,mBAAmB,EAEnB,kBAAkB,EAClB,oBAAoB,EACpB,wBAAwB,EACxB,MAAM,EACN,iCAAiC,EACjC,0BAA0B,EAC1B,2BAA2B,EAC3B,uBAAuB,GACxB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.tsx"],"names":[],"mappings":"AAAA,OAAO,EACL,OAAO,IAAI,aAAa,EACxB,oBAAoB,EACpB,8BAA8B,EAC9B,8BAA8B,EAC9B,QAAQ,EACR,gBAAgB,EACjB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,OAAO,IAAI,QAAQ,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,EACL,OAAO,IAAI,gBAAgB,EAC3B,6BAA6B,GAC9B,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AACpE,OAAO,EACL,OAAO,IAAI,0BAA0B,EACrC,iCAAiC,GAClC,MAAM,gCAAgC,CAAC;AACxC,OAAO,EACL,OAAO,IAAI,YAAY,EACvB,qBAAqB,EACrB,cAAc,EACd,aAAa,EACb,oBAAoB,GACrB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,mBAAmB,EACnB,iBAAiB,EACjB,kBAAkB,EAClB,wBAAwB,EACxB,gBAAgB,EAChB,aAAa,EACb,uBAAuB,EACvB,OAAO,EACP,IAAI,EACJ,MAAM,EACN,aAAa,EACb,iBAAiB,EACjB,SAAS,EACT,YAAY,EACZ,gBAAgB,EAChB,mBAAmB,EACnB,iBAAiB,EACjB,cAAc,EACd,mBAAmB,EACnB,wBAAwB,EACxB,kBAAkB,EAClB,yBAAyB,EACzB,YAAY,EACZ,iBAAiB,EACjB,6BAA6B,EAC7B,4BAA4B,EAC5B,YAAY,EACZ,YAAY,EACZ,0BAA0B,EAC1B,qBAAqB,EACrB,QAAQ,EACR,mBAAmB,EACnB,gBAAgB,EAEhB,QAAQ,EACR,0BAA0B,EAC1B,kBAAkB,EAClB,iBAAiB,EACjB,cAAc,EACd,yBAAyB,EAEzB,YAAY,EACZ,oBAAoB,EACpB,qBAAqB,EACrB,oBAAoB,EAEpB,iBAAiB,GAClB,MAAM,qBAAqB,CAAC;AAC7B,YAAY,EACV,yBAAyB,EACzB,aAAa,EACb,uBAAuB,EAEvB,YAAY,EACZ,aAAa,EACb,aAAa,EACb,YAAY,EACZ,eAAe,EACf,eAAe,EACf,iBAAiB,EACjB,iBAAiB,EACjB,gBAAgB,EAChB,kBAAkB,EAClB,4BAA4B,EAC5B,iBAAiB,EACjB,YAAY,EACZ,gBAAgB,EAEhB,gBAAgB,EAChB,oBAAoB,EACpB,mBAAmB,EAEnB,kBAAkB,EAClB,oBAAoB,EACpB,wBAAwB,EACxB,MAAM,EACN,iCAAiC,EACjC,0BAA0B,EAC1B,2BAA2B,EAC3B,uBAAuB,GACxB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { User } from '@auth0/auth0-spa-js';
|
|
3
|
+
import { Auth0ContextInterface } from './auth0-context';
|
|
4
|
+
/**
|
|
5
|
+
* The value returned by `useAuth0Suspense`: the full `useAuth0` interface minus
|
|
6
|
+
* `isLoading` and the internal `_initPromise`. `error` is
|
|
7
|
+
* retained for post-init failures such as `loginWithPopup`.
|
|
8
|
+
*/
|
|
9
|
+
export type Auth0SuspenseContextInterface<TUser extends User = User> = Omit<Auth0ContextInterface<TUser>, 'isLoading' | '_initPromise'>;
|
|
10
|
+
/**
|
|
11
|
+
* ```jsx
|
|
12
|
+
* <Suspense fallback={<Spinner />}>
|
|
13
|
+
* <Profile />
|
|
14
|
+
* </Suspense>
|
|
15
|
+
*
|
|
16
|
+
* function Profile() {
|
|
17
|
+
* const { user, isAuthenticated } = useAuth0Suspense();
|
|
18
|
+
* return isAuthenticated ? <p>Hello {user.name}</p> : <p>Please log in</p>;
|
|
19
|
+
* }
|
|
20
|
+
* ```
|
|
21
|
+
*
|
|
22
|
+
* Suspense-enabled variant of `useAuth0`. Suspends the component until Auth0
|
|
23
|
+
* initialization completes (letting the nearest `<Suspense>` fallback render),
|
|
24
|
+
* and throws initialization errors so the nearest Error Boundary can handle
|
|
25
|
+
* them. Requires React 19 or later.
|
|
26
|
+
*
|
|
27
|
+
* If initialization fails and the app later becomes authenticated by other
|
|
28
|
+
* means, the session is re-checked once; retrying the Error Boundary then
|
|
29
|
+
* renders if that check succeeded, or throws again if it did not.
|
|
30
|
+
*
|
|
31
|
+
* TUser is an optional type param to provide a type to the `user` field.
|
|
32
|
+
*/
|
|
33
|
+
declare const useAuth0Suspense: <TUser extends User = User>(context?: React.Context<Auth0ContextInterface<User>>) => Auth0SuspenseContextInterface<TUser>;
|
|
34
|
+
export default useAuth0Suspense;
|
|
35
|
+
//# sourceMappingURL=use-auth0-suspense.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-auth0-suspense.d.ts","sourceRoot":"","sources":["../src/use-auth0-suspense.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,EAAE,IAAI,EAAE,MAAM,qBAAqB,CAAC;AAC3C,OAAqB,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AAEtE;;;;GAIG;AACH,MAAM,MAAM,6BAA6B,CAAC,KAAK,SAAS,IAAI,GAAG,IAAI,IAAI,IAAI,CACzE,qBAAqB,CAAC,KAAK,CAAC,EAC5B,WAAW,GAAG,cAAc,CAC7B,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,QAAA,MAAM,gBAAgB,GAAI,KAAK,SAAS,IAAI,GAAG,IAAI,EACjD,oDAAsB,KACrB,6BAA6B,CAAC,KAAK,CA0BrC,CAAC;AAEF,eAAe,gBAAgB,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"author": "Auth0",
|
|
3
3
|
"name": "@versini/auth0-react-thin",
|
|
4
|
-
"version": "2.
|
|
5
|
-
"description": "Unofficial slim fork of @auth0/auth0-react@2.
|
|
4
|
+
"version": "2.24.0",
|
|
5
|
+
"description": "Unofficial slim fork of @auth0/auth0-react@2.24.0 — bundle-size build, not affiliated with Auth0/Okta. See @versini/auth0-thin.",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"auth0",
|
|
8
8
|
"fork",
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"dependencies": {
|
|
35
35
|
"@auth0/auth0-spa-js": "^2.24.1"
|
|
36
36
|
},
|
|
37
|
-
"forkedFrom": "@auth0/auth0-react@2.
|
|
37
|
+
"forkedFrom": "@auth0/auth0-react@2.24.0",
|
|
38
38
|
"publishConfig": {
|
|
39
39
|
"access": "public"
|
|
40
40
|
}
|
package/src/auth0-context.tsx
CHANGED
|
@@ -474,6 +474,16 @@ export interface Auth0ContextInterface<TUser extends User = User>
|
|
|
474
474
|
* ```
|
|
475
475
|
*/
|
|
476
476
|
myAccount: MyAccountApiClient;
|
|
477
|
+
|
|
478
|
+
/**
|
|
479
|
+
* Internal. A promise that resolves when Auth0 initialization completes and
|
|
480
|
+
* rejects with the initialization error if it fails. Consumed by
|
|
481
|
+
* `useAuth0Suspense`, which also treats its absence as "no provider" — do not
|
|
482
|
+
* add a stub value for this field to `initialContext`. Not part of the
|
|
483
|
+
* supported public API.
|
|
484
|
+
* @ignore
|
|
485
|
+
*/
|
|
486
|
+
_initPromise?: Promise<void>;
|
|
477
487
|
}
|
|
478
488
|
|
|
479
489
|
/**
|
package/src/auth0-provider.tsx
CHANGED
|
@@ -157,6 +157,32 @@ const defaultOnRedirectCallback = (appState?: AppState): void => {
|
|
|
157
157
|
);
|
|
158
158
|
};
|
|
159
159
|
|
|
160
|
+
/**
|
|
161
|
+
* @ignore
|
|
162
|
+
*/
|
|
163
|
+
interface InitDeferred {
|
|
164
|
+
promise: Promise<void>;
|
|
165
|
+
resolve: () => void;
|
|
166
|
+
reject: (error: Error) => void;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* @ignore
|
|
171
|
+
*/
|
|
172
|
+
const createInitDeferred = (): InitDeferred => {
|
|
173
|
+
let resolve!: () => void;
|
|
174
|
+
let reject!: (error: Error) => void;
|
|
175
|
+
const promise = new Promise<void>((res, rej) => {
|
|
176
|
+
resolve = res;
|
|
177
|
+
reject = rej;
|
|
178
|
+
});
|
|
179
|
+
// Avoid unhandled-rejection warnings when no one is consuming the promise
|
|
180
|
+
// (i.e. useAuth0Suspense is not used). useAuth0Suspense attaches its own
|
|
181
|
+
// handler via use().
|
|
182
|
+
promise.catch(() => undefined);
|
|
183
|
+
return { promise, resolve, reject };
|
|
184
|
+
};
|
|
185
|
+
|
|
160
186
|
/**
|
|
161
187
|
* ```jsx
|
|
162
188
|
* <Auth0Provider
|
|
@@ -194,6 +220,17 @@ const Auth0Provider = <TUser extends User = User>(opts: Auth0ProviderOptions<TUs
|
|
|
194
220
|
() => providedClient ?? new Auth0Client(toAuth0ClientOptions(clientOpts))
|
|
195
221
|
);
|
|
196
222
|
const [state, dispatch] = useReducer(reducer<TUser>, initialAuthState as AuthState<TUser>);
|
|
223
|
+
// In state so the init retry below can swap in a fresh, non-rejected promise.
|
|
224
|
+
// Without that swap the first rejection would re-throw on every later render,
|
|
225
|
+
// making Error Boundary retries useless.
|
|
226
|
+
const [initDeferred, setInitDeferred] = useState(createInitDeferred);
|
|
227
|
+
// Set only once initialization has genuinely rejected. State, not a ref, so
|
|
228
|
+
// the retry effect re-evaluates when init fails *after* the app has become
|
|
229
|
+
// authenticated by some other means.
|
|
230
|
+
const [initFailed, setInitFailed] = useState(false);
|
|
231
|
+
// Guards against retrying more than once: a retry that also fails would
|
|
232
|
+
// otherwise re-trigger the effect for as long as the user stays signed in.
|
|
233
|
+
const initRetried = useRef(false);
|
|
197
234
|
const didInitialise = useRef(false);
|
|
198
235
|
|
|
199
236
|
const handleError = useCallback((error: Error) => {
|
|
@@ -201,15 +238,15 @@ const Auth0Provider = <TUser extends User = User>(opts: Auth0ProviderOptions<TUs
|
|
|
201
238
|
return error;
|
|
202
239
|
}, []);
|
|
203
240
|
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
241
|
+
// Settles `deferred` according to what initialization actually did, so
|
|
242
|
+
// `_initPromise` never claims success that did not happen. `allowRedirect`
|
|
243
|
+
// is false on a retry: the redirect callback is single-use, so a retry can
|
|
244
|
+
// only re-verify the session.
|
|
245
|
+
const runInit = useCallback(
|
|
246
|
+
async (deferred: InitDeferred, allowRedirect: boolean): Promise<void> => {
|
|
210
247
|
try {
|
|
211
248
|
let user: TUser | undefined;
|
|
212
|
-
if (hasAuthParams() && !skipRedirectCallback) {
|
|
249
|
+
if (allowRedirect && hasAuthParams() && !skipRedirectCallback) {
|
|
213
250
|
const { appState = {}, response_type, ...result } = await client.handleRedirectCallback();
|
|
214
251
|
user = await client.getUser();
|
|
215
252
|
appState.response_type = response_type;
|
|
@@ -222,11 +259,44 @@ const Auth0Provider = <TUser extends User = User>(opts: Auth0ProviderOptions<TUs
|
|
|
222
259
|
user = await client.getUser();
|
|
223
260
|
}
|
|
224
261
|
dispatch({ type: 'INITIALISED', user });
|
|
262
|
+
deferred.resolve();
|
|
225
263
|
} catch (error) {
|
|
226
|
-
|
|
264
|
+
const err = loginError(error);
|
|
265
|
+
handleError(err);
|
|
266
|
+
setInitFailed(true);
|
|
267
|
+
deferred.reject(err);
|
|
227
268
|
}
|
|
228
|
-
}
|
|
229
|
-
|
|
269
|
+
},
|
|
270
|
+
[client, onRedirectCallback, skipRedirectCallback, handleError]
|
|
271
|
+
);
|
|
272
|
+
|
|
273
|
+
useEffect(() => {
|
|
274
|
+
if (didInitialise.current) {
|
|
275
|
+
return;
|
|
276
|
+
}
|
|
277
|
+
didInitialise.current = true;
|
|
278
|
+
// Always the first deferred: `didInitialise` means this only ever runs once,
|
|
279
|
+
// so a later swap by the retry effect re-runs this effect but returns above.
|
|
280
|
+
void runInit(initDeferred, true);
|
|
281
|
+
}, [runInit, initDeferred]);
|
|
282
|
+
|
|
283
|
+
// A rejected promise stays rejected forever, so React.use() would re-throw on
|
|
284
|
+
// every later render and an Error Boundary retry could never recover. Once
|
|
285
|
+
// init has failed but the app has since become authenticated by some other
|
|
286
|
+
// means (loginWithPopup, a silent token, a passkey login), re-run the session
|
|
287
|
+
// check against a fresh deferred. The promise then reflects a real
|
|
288
|
+
// checkSession() outcome rather than an assumption that things are fine --
|
|
289
|
+
// if the session is still bad it rejects again and the boundary keeps showing
|
|
290
|
+
// the error.
|
|
291
|
+
useEffect(() => {
|
|
292
|
+
if (!initFailed || initRetried.current || !state.isAuthenticated) {
|
|
293
|
+
return;
|
|
294
|
+
}
|
|
295
|
+
initRetried.current = true;
|
|
296
|
+
const retry = createInitDeferred();
|
|
297
|
+
setInitDeferred(retry);
|
|
298
|
+
void runInit(retry, false);
|
|
299
|
+
}, [initFailed, state.isAuthenticated, runInit]);
|
|
230
300
|
|
|
231
301
|
const loginWithRedirect = useCallback(
|
|
232
302
|
(opts?: RedirectLoginOptions): Promise<void> => {
|
|
@@ -485,6 +555,7 @@ const Auth0Provider = <TUser extends User = User>(opts: Auth0ProviderOptions<TUs
|
|
|
485
555
|
mfa,
|
|
486
556
|
passkey,
|
|
487
557
|
myAccount,
|
|
558
|
+
_initPromise: initDeferred.promise,
|
|
488
559
|
};
|
|
489
560
|
}, [
|
|
490
561
|
state,
|
|
@@ -508,6 +579,7 @@ const Auth0Provider = <TUser extends User = User>(opts: Auth0ProviderOptions<TUs
|
|
|
508
579
|
mfa,
|
|
509
580
|
passkey,
|
|
510
581
|
myAccount,
|
|
582
|
+
initDeferred,
|
|
511
583
|
]);
|
|
512
584
|
|
|
513
585
|
return <context.Provider value={contextValue}>{children}</context.Provider>;
|
package/src/index.tsx
CHANGED
|
@@ -7,6 +7,10 @@ export {
|
|
|
7
7
|
ConnectedAccount
|
|
8
8
|
} from './auth0-provider';
|
|
9
9
|
export { default as useAuth0 } from './use-auth0';
|
|
10
|
+
export {
|
|
11
|
+
default as useAuth0Suspense,
|
|
12
|
+
Auth0SuspenseContextInterface,
|
|
13
|
+
} from './use-auth0-suspense';
|
|
10
14
|
export { default as withAuth0, WithAuth0Props } from './with-auth0';
|
|
11
15
|
export {
|
|
12
16
|
default as withAuthenticationRequired,
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
// Namespace import: `use` only exists as a named export from React 19, so
|
|
2
|
+
// `import { use }` fails at link time for React 16-18 consumers even if they
|
|
3
|
+
// never call this hook. Property access stays late-bound.
|
|
4
|
+
import * as React from 'react';
|
|
5
|
+
import { User } from '@auth0/auth0-spa-js';
|
|
6
|
+
import Auth0Context, { Auth0ContextInterface } from './auth0-context';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* The value returned by `useAuth0Suspense`: the full `useAuth0` interface minus
|
|
10
|
+
* `isLoading` and the internal `_initPromise`. `error` is
|
|
11
|
+
* retained for post-init failures such as `loginWithPopup`.
|
|
12
|
+
*/
|
|
13
|
+
export type Auth0SuspenseContextInterface<TUser extends User = User> = Omit<
|
|
14
|
+
Auth0ContextInterface<TUser>,
|
|
15
|
+
'isLoading' | '_initPromise'
|
|
16
|
+
>;
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* ```jsx
|
|
20
|
+
* <Suspense fallback={<Spinner />}>
|
|
21
|
+
* <Profile />
|
|
22
|
+
* </Suspense>
|
|
23
|
+
*
|
|
24
|
+
* function Profile() {
|
|
25
|
+
* const { user, isAuthenticated } = useAuth0Suspense();
|
|
26
|
+
* return isAuthenticated ? <p>Hello {user.name}</p> : <p>Please log in</p>;
|
|
27
|
+
* }
|
|
28
|
+
* ```
|
|
29
|
+
*
|
|
30
|
+
* Suspense-enabled variant of `useAuth0`. Suspends the component until Auth0
|
|
31
|
+
* initialization completes (letting the nearest `<Suspense>` fallback render),
|
|
32
|
+
* and throws initialization errors so the nearest Error Boundary can handle
|
|
33
|
+
* them. Requires React 19 or later.
|
|
34
|
+
*
|
|
35
|
+
* If initialization fails and the app later becomes authenticated by other
|
|
36
|
+
* means, the session is re-checked once; retrying the Error Boundary then
|
|
37
|
+
* renders if that check succeeded, or throws again if it did not.
|
|
38
|
+
*
|
|
39
|
+
* TUser is an optional type param to provide a type to the `user` field.
|
|
40
|
+
*/
|
|
41
|
+
const useAuth0Suspense = <TUser extends User = User>(
|
|
42
|
+
context = Auth0Context
|
|
43
|
+
): Auth0SuspenseContextInterface<TUser> => {
|
|
44
|
+
if (typeof React.use !== 'function') {
|
|
45
|
+
throw new Error(
|
|
46
|
+
'useAuth0Suspense requires React 19 or later (React.use is unavailable).'
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const ctx = React.useContext(context) as Auth0ContextInterface<TUser>;
|
|
51
|
+
|
|
52
|
+
if (!ctx._initPromise) {
|
|
53
|
+
throw new Error(
|
|
54
|
+
'useAuth0Suspense must be used within an <Auth0Provider>.'
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Suspends until the init promise resolves; re-throws if it rejected.
|
|
59
|
+
React.use(ctx._initPromise);
|
|
60
|
+
|
|
61
|
+
// Memoized so the returned object is referentially stable across renders,
|
|
62
|
+
// matching useAuth0, which hands back the provider's memoized context.
|
|
63
|
+
// Without this, `useEffect(..., [auth])` in a consumer re-runs every render.
|
|
64
|
+
return React.useMemo(() => {
|
|
65
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
66
|
+
const { isLoading, _initPromise, ...rest } = ctx;
|
|
67
|
+
return rest;
|
|
68
|
+
}, [ctx]);
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
export default useAuth0Suspense;
|