@stytch/react 0.9.0 → 0.10.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.
- package/CHANGELOG.md +19 -0
- package/README.md +4 -3
- package/dist/b2b/index.d.ts +93 -0
- package/dist/b2b/index.esm.d.ts +93 -0
- package/dist/b2b/index.esm.js +159 -0
- package/dist/b2b/index.js +173 -0
- package/dist/index.esm.js +2 -1
- package/dist/index.js +2 -1
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,24 @@
|
|
|
1
1
|
# @stytch/react
|
|
2
2
|
|
|
3
|
+
## 0.10.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- f1810c4: Add React Native OAuth callback, PKCE fix
|
|
8
|
+
- Updated dependencies [f1810c4]
|
|
9
|
+
- @stytch/vanilla-js@0.10.2
|
|
10
|
+
|
|
11
|
+
## 0.10.0
|
|
12
|
+
|
|
13
|
+
### Minor Changes
|
|
14
|
+
|
|
15
|
+
- Launching B2B SDKs
|
|
16
|
+
|
|
17
|
+
### Patch Changes
|
|
18
|
+
|
|
19
|
+
- Updated dependencies
|
|
20
|
+
- @stytch/vanilla-js@0.10.0
|
|
21
|
+
|
|
3
22
|
## 0.9.0
|
|
4
23
|
|
|
5
24
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -41,9 +41,9 @@ const App = () => {
|
|
|
41
41
|
},
|
|
42
42
|
},
|
|
43
43
|
styles: {
|
|
44
|
+
container: { width: '321px' },
|
|
45
|
+
colors: { primary: '#0577CA' },
|
|
44
46
|
fontFamily: '"Helvetica New", Helvetica, sans-serif',
|
|
45
|
-
width: '321px',
|
|
46
|
-
primaryColor: '#0577CA',
|
|
47
47
|
},
|
|
48
48
|
callbacks: {
|
|
49
49
|
onEvent: (message) => console.log(message),
|
|
@@ -56,7 +56,7 @@ const App = () => {
|
|
|
56
56
|
<div id="login">
|
|
57
57
|
<StytchLogin
|
|
58
58
|
config={stytchProps.loginOrSignupView}
|
|
59
|
-
styles={stytchProps.
|
|
59
|
+
styles={stytchProps.styles}
|
|
60
60
|
callbacks={stytchProps.callbacks}
|
|
61
61
|
/>
|
|
62
62
|
</div>
|
|
@@ -154,3 +154,4 @@ We've made a number of small changes to our naming conventions to make the API c
|
|
|
154
154
|
- The `<Stytch />` login component is now called `<StytchLogin />`
|
|
155
155
|
- The `OAuthProvidersTypes` enum is now called `OAuthProviders`
|
|
156
156
|
- The `SDKProductTypes` enum is now called `Products`
|
|
157
|
+
- There are some additional changes to the `styles` config documented [here](https://stytch.com/docs/sdks/javascript-sdk#resources_migration-guide_v-zero-five)
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/// <reference types="react" />
|
|
2
|
+
import React from "react";
|
|
3
|
+
import { ReactNode } from "react";
|
|
4
|
+
import { Member, MemberSession, StytchB2BHeadlessClient } from "@stytch/vanilla-js/b2b";
|
|
5
|
+
/**
|
|
6
|
+
* The Stytch Client object passed in to <StytchProvider /> in your application root.
|
|
7
|
+
*/
|
|
8
|
+
type StytchB2BClient = StytchB2BHeadlessClient;
|
|
9
|
+
type SWRMember = {
|
|
10
|
+
/**
|
|
11
|
+
* Either the active {@link Member} object, or null if the user is not logged in.
|
|
12
|
+
*/
|
|
13
|
+
member: Member | null;
|
|
14
|
+
/**
|
|
15
|
+
* If true, indicates that the value returned is from the application cache and a state refresh is in progress.
|
|
16
|
+
*/
|
|
17
|
+
fromCache: boolean;
|
|
18
|
+
};
|
|
19
|
+
type SWRMemberSession = {
|
|
20
|
+
/**
|
|
21
|
+
* Either the active {@link MemberSession} object, or null if the user is not logged in.
|
|
22
|
+
*/
|
|
23
|
+
session: MemberSession | null;
|
|
24
|
+
/**
|
|
25
|
+
* If true, indicates that the value returned is from the application cache and a state refresh is in progress.
|
|
26
|
+
*/
|
|
27
|
+
fromCache: boolean;
|
|
28
|
+
};
|
|
29
|
+
/**
|
|
30
|
+
* Returns the active Member.
|
|
31
|
+
* Check the fromCache property to determine if the member data is from persistent storage.
|
|
32
|
+
* @example
|
|
33
|
+
* const {member} = useStytchMember();
|
|
34
|
+
* return (<h1>Welcome, {member.name}</h1>);
|
|
35
|
+
* @returns A {@link SWRUser}
|
|
36
|
+
*/
|
|
37
|
+
declare const useStytchMember: () => SWRMember;
|
|
38
|
+
/**
|
|
39
|
+
* Returns the active member's Stytch member session.
|
|
40
|
+
* @example
|
|
41
|
+
* const { session } = useStytchMemberSession();
|
|
42
|
+
* useEffect(() => {
|
|
43
|
+
* if (!session) {
|
|
44
|
+
* router.replace('/login')
|
|
45
|
+
* }
|
|
46
|
+
* }, [session]);
|
|
47
|
+
* @returns A {@link SWRMemberSession}
|
|
48
|
+
*/
|
|
49
|
+
declare const useStytchMemberSession: () => SWRMemberSession;
|
|
50
|
+
/**
|
|
51
|
+
* Returns the Stytch B2B client stored in the Stytch context.
|
|
52
|
+
*
|
|
53
|
+
* @example
|
|
54
|
+
* const stytch = useStytchB2BClient();
|
|
55
|
+
* useEffect(() => {
|
|
56
|
+
* stytch.magicLinks.authenticate('...')
|
|
57
|
+
* }, [stytch]);
|
|
58
|
+
*/
|
|
59
|
+
declare const useStytchB2BClient: () => StytchB2BClient;
|
|
60
|
+
declare const withStytchB2BClient: <T extends object>(Component: React.ComponentType<T & {
|
|
61
|
+
stytch: StytchB2BClient;
|
|
62
|
+
}>) => React.ComponentType<T>;
|
|
63
|
+
declare const withStytchMember: <T extends object>(Component: React.ComponentType<T & {
|
|
64
|
+
stytchMember: Member | null;
|
|
65
|
+
stytchMemberIsFromCache: boolean;
|
|
66
|
+
}>) => React.ComponentType<T>;
|
|
67
|
+
declare const withStytchMemberSession: <T extends object>(Component: React.ComponentType<T & {
|
|
68
|
+
stytchMemberSession: MemberSession | null;
|
|
69
|
+
stytchMemberSessionIsFromCache: boolean;
|
|
70
|
+
}>) => React.ComponentType<T>;
|
|
71
|
+
type StytchB2BProviderProps = {
|
|
72
|
+
/**
|
|
73
|
+
* A Stytch client instance {@link StytchB2BHeadlessClient}
|
|
74
|
+
*/
|
|
75
|
+
stytch: StytchB2BClient;
|
|
76
|
+
children?: ReactNode;
|
|
77
|
+
};
|
|
78
|
+
/**
|
|
79
|
+
* The Stytch Context Provider.
|
|
80
|
+
* Wrap your application with this component in the root file in order to use Stytch everywhere in your app.
|
|
81
|
+
* @example
|
|
82
|
+
* const stytch = new StytchB2BHeadlessClient('public-token-<find yours in the stytch dashboard>')
|
|
83
|
+
*
|
|
84
|
+
* ReactDOM.render(
|
|
85
|
+
* <StytchB2BProvider stytch={stytch}>
|
|
86
|
+
* <App />
|
|
87
|
+
* </StytchProvider>,
|
|
88
|
+
* document.getElementById('root'),
|
|
89
|
+
* )
|
|
90
|
+
*/
|
|
91
|
+
declare const StytchB2BProvider: ({ stytch, children }: StytchB2BProviderProps) => JSX.Element;
|
|
92
|
+
export { StytchB2BProvider, useStytchB2BClient, useStytchMemberSession, useStytchMember, withStytchB2BClient, withStytchMemberSession, withStytchMember };
|
|
93
|
+
export type { StytchB2BProviderProps };
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/// <reference types="react" />
|
|
2
|
+
import React from "react";
|
|
3
|
+
import { ReactNode } from "react";
|
|
4
|
+
import { Member, MemberSession, StytchB2BHeadlessClient } from "@stytch/vanilla-js/b2b";
|
|
5
|
+
/**
|
|
6
|
+
* The Stytch Client object passed in to <StytchProvider /> in your application root.
|
|
7
|
+
*/
|
|
8
|
+
type StytchB2BClient = StytchB2BHeadlessClient;
|
|
9
|
+
type SWRMember = {
|
|
10
|
+
/**
|
|
11
|
+
* Either the active {@link Member} object, or null if the user is not logged in.
|
|
12
|
+
*/
|
|
13
|
+
member: Member | null;
|
|
14
|
+
/**
|
|
15
|
+
* If true, indicates that the value returned is from the application cache and a state refresh is in progress.
|
|
16
|
+
*/
|
|
17
|
+
fromCache: boolean;
|
|
18
|
+
};
|
|
19
|
+
type SWRMemberSession = {
|
|
20
|
+
/**
|
|
21
|
+
* Either the active {@link MemberSession} object, or null if the user is not logged in.
|
|
22
|
+
*/
|
|
23
|
+
session: MemberSession | null;
|
|
24
|
+
/**
|
|
25
|
+
* If true, indicates that the value returned is from the application cache and a state refresh is in progress.
|
|
26
|
+
*/
|
|
27
|
+
fromCache: boolean;
|
|
28
|
+
};
|
|
29
|
+
/**
|
|
30
|
+
* Returns the active Member.
|
|
31
|
+
* Check the fromCache property to determine if the member data is from persistent storage.
|
|
32
|
+
* @example
|
|
33
|
+
* const {member} = useStytchMember();
|
|
34
|
+
* return (<h1>Welcome, {member.name}</h1>);
|
|
35
|
+
* @returns A {@link SWRUser}
|
|
36
|
+
*/
|
|
37
|
+
declare const useStytchMember: () => SWRMember;
|
|
38
|
+
/**
|
|
39
|
+
* Returns the active member's Stytch member session.
|
|
40
|
+
* @example
|
|
41
|
+
* const { session } = useStytchMemberSession();
|
|
42
|
+
* useEffect(() => {
|
|
43
|
+
* if (!session) {
|
|
44
|
+
* router.replace('/login')
|
|
45
|
+
* }
|
|
46
|
+
* }, [session]);
|
|
47
|
+
* @returns A {@link SWRMemberSession}
|
|
48
|
+
*/
|
|
49
|
+
declare const useStytchMemberSession: () => SWRMemberSession;
|
|
50
|
+
/**
|
|
51
|
+
* Returns the Stytch B2B client stored in the Stytch context.
|
|
52
|
+
*
|
|
53
|
+
* @example
|
|
54
|
+
* const stytch = useStytchB2BClient();
|
|
55
|
+
* useEffect(() => {
|
|
56
|
+
* stytch.magicLinks.authenticate('...')
|
|
57
|
+
* }, [stytch]);
|
|
58
|
+
*/
|
|
59
|
+
declare const useStytchB2BClient: () => StytchB2BClient;
|
|
60
|
+
declare const withStytchB2BClient: <T extends object>(Component: React.ComponentType<T & {
|
|
61
|
+
stytch: StytchB2BClient;
|
|
62
|
+
}>) => React.ComponentType<T>;
|
|
63
|
+
declare const withStytchMember: <T extends object>(Component: React.ComponentType<T & {
|
|
64
|
+
stytchMember: Member | null;
|
|
65
|
+
stytchMemberIsFromCache: boolean;
|
|
66
|
+
}>) => React.ComponentType<T>;
|
|
67
|
+
declare const withStytchMemberSession: <T extends object>(Component: React.ComponentType<T & {
|
|
68
|
+
stytchMemberSession: MemberSession | null;
|
|
69
|
+
stytchMemberSessionIsFromCache: boolean;
|
|
70
|
+
}>) => React.ComponentType<T>;
|
|
71
|
+
type StytchB2BProviderProps = {
|
|
72
|
+
/**
|
|
73
|
+
* A Stytch client instance {@link StytchB2BHeadlessClient}
|
|
74
|
+
*/
|
|
75
|
+
stytch: StytchB2BClient;
|
|
76
|
+
children?: ReactNode;
|
|
77
|
+
};
|
|
78
|
+
/**
|
|
79
|
+
* The Stytch Context Provider.
|
|
80
|
+
* Wrap your application with this component in the root file in order to use Stytch everywhere in your app.
|
|
81
|
+
* @example
|
|
82
|
+
* const stytch = new StytchB2BHeadlessClient('public-token-<find yours in the stytch dashboard>')
|
|
83
|
+
*
|
|
84
|
+
* ReactDOM.render(
|
|
85
|
+
* <StytchB2BProvider stytch={stytch}>
|
|
86
|
+
* <App />
|
|
87
|
+
* </StytchProvider>,
|
|
88
|
+
* document.getElementById('root'),
|
|
89
|
+
* )
|
|
90
|
+
*/
|
|
91
|
+
declare const StytchB2BProvider: ({ stytch, children }: StytchB2BProviderProps) => JSX.Element;
|
|
92
|
+
export { StytchB2BProvider, useStytchB2BClient, useStytchMemberSession, useStytchMember, withStytchB2BClient, withStytchMemberSession, withStytchMember };
|
|
93
|
+
export type { StytchB2BProviderProps };
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
import React, { useRef, useState, useEffect, useCallback, createContext, useContext, useMemo } from 'react';
|
|
2
|
+
|
|
3
|
+
const noProviderError = (item, provider = 'StytchProvider') => `${item} can only be used inside <${provider}>.`;
|
|
4
|
+
const B2BProviderMustBeUniqueError = 'You cannot render a <StytchB2BProvider> inside another <StytchB2BProvider>.';
|
|
5
|
+
const noSSRError = `The @stytch/react library is not meant for use with serverside environments like NextJS.
|
|
6
|
+
Use the @stytch/nextjs library instead -
|
|
7
|
+
npm remove @stytch/react && npm install @stytch/nextjs
|
|
8
|
+
`;
|
|
9
|
+
|
|
10
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
11
|
+
function invariant(cond, message) {
|
|
12
|
+
if (!cond)
|
|
13
|
+
throw new Error(message);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// useState can cause memory leaks if it is set after the component unmounted. For example, if it is
|
|
17
|
+
// set after `await`, or in a `then`, `catch`, or `finally`, or in a setTimout/setInterval.
|
|
18
|
+
const useAsyncState = (initialState) => {
|
|
19
|
+
const isMounted = useRef(true);
|
|
20
|
+
const [state, setState] = useState(initialState);
|
|
21
|
+
useEffect(() => {
|
|
22
|
+
isMounted.current = true;
|
|
23
|
+
return () => {
|
|
24
|
+
isMounted.current = false;
|
|
25
|
+
};
|
|
26
|
+
}, []);
|
|
27
|
+
const setStateAction = useCallback((newState) => {
|
|
28
|
+
isMounted.current && setState(newState);
|
|
29
|
+
}, []);
|
|
30
|
+
return [state, setStateAction];
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const initialMember = {
|
|
34
|
+
member: null,
|
|
35
|
+
fromCache: false,
|
|
36
|
+
};
|
|
37
|
+
const initialMemberSession = {
|
|
38
|
+
session: null,
|
|
39
|
+
fromCache: false,
|
|
40
|
+
};
|
|
41
|
+
const StytchB2BContext = createContext({ isMounted: false });
|
|
42
|
+
const StytchMemberContext = createContext(initialMember);
|
|
43
|
+
const StytchMemberSessionContext = createContext(initialMemberSession);
|
|
44
|
+
const useIsMounted__INTERNAL = () => useContext(StytchB2BContext).isMounted;
|
|
45
|
+
/**
|
|
46
|
+
* Returns the active Member.
|
|
47
|
+
* Check the fromCache property to determine if the member data is from persistent storage.
|
|
48
|
+
* @example
|
|
49
|
+
* const {member} = useStytchMember();
|
|
50
|
+
* return (<h1>Welcome, {member.name}</h1>);
|
|
51
|
+
* @returns A {@link SWRUser}
|
|
52
|
+
*/
|
|
53
|
+
const useStytchMember = () => {
|
|
54
|
+
invariant(useIsMounted__INTERNAL(), noProviderError('useStytchMember', 'StytchB2BProvider'));
|
|
55
|
+
return useContext(StytchMemberContext);
|
|
56
|
+
};
|
|
57
|
+
/**
|
|
58
|
+
* Returns the active member's Stytch member session.
|
|
59
|
+
* @example
|
|
60
|
+
* const { session } = useStytchMemberSession();
|
|
61
|
+
* useEffect(() => {
|
|
62
|
+
* if (!session) {
|
|
63
|
+
* router.replace('/login')
|
|
64
|
+
* }
|
|
65
|
+
* }, [session]);
|
|
66
|
+
* @returns A {@link SWRMemberSession}
|
|
67
|
+
*/
|
|
68
|
+
const useStytchMemberSession = () => {
|
|
69
|
+
invariant(useIsMounted__INTERNAL(), noProviderError('useStytchMemberSession', 'StytchB2BProvider'));
|
|
70
|
+
return useContext(StytchMemberSessionContext);
|
|
71
|
+
};
|
|
72
|
+
/**
|
|
73
|
+
* Returns the Stytch B2B client stored in the Stytch context.
|
|
74
|
+
*
|
|
75
|
+
* @example
|
|
76
|
+
* const stytch = useStytchB2BClient();
|
|
77
|
+
* useEffect(() => {
|
|
78
|
+
* stytch.magicLinks.authenticate('...')
|
|
79
|
+
* }, [stytch]);
|
|
80
|
+
*/
|
|
81
|
+
const useStytchB2BClient = () => {
|
|
82
|
+
const ctx = useContext(StytchB2BContext);
|
|
83
|
+
invariant(ctx.isMounted, noProviderError('useStytchB2BClient', 'StytchB2BProvider'));
|
|
84
|
+
return ctx.client;
|
|
85
|
+
};
|
|
86
|
+
const withStytchB2BClient = (Component) => {
|
|
87
|
+
const WithStytch = (props) => {
|
|
88
|
+
invariant(useIsMounted__INTERNAL(), noProviderError('withStytchB2BClient', 'StytchB2BProvider'));
|
|
89
|
+
return React.createElement(Component, Object.assign({}, props, { stytch: useStytchB2BClient() }));
|
|
90
|
+
};
|
|
91
|
+
WithStytch.displayName = `withStytch(${Component.displayName || Component.name || 'Component'})`;
|
|
92
|
+
return WithStytch;
|
|
93
|
+
};
|
|
94
|
+
const withStytchMember = (Component) => {
|
|
95
|
+
const WithStytchUser = (props) => {
|
|
96
|
+
invariant(useIsMounted__INTERNAL(), noProviderError('withStytchMember', 'StytchB2BProvider'));
|
|
97
|
+
const { member, fromCache } = useStytchMember();
|
|
98
|
+
return React.createElement(Component, Object.assign({}, props, { stytchMember: member, stytchMemberIsFromCache: fromCache }));
|
|
99
|
+
};
|
|
100
|
+
WithStytchUser.displayName = `withStytchUser(${Component.displayName || Component.name || 'Component'})`;
|
|
101
|
+
return WithStytchUser;
|
|
102
|
+
};
|
|
103
|
+
const withStytchMemberSession = (Component) => {
|
|
104
|
+
const WithStytchSession = (props) => {
|
|
105
|
+
invariant(useIsMounted__INTERNAL(), noProviderError('withStytchMemberSession', 'StytchB2BProvider'));
|
|
106
|
+
const { session, fromCache } = useStytchMemberSession();
|
|
107
|
+
return React.createElement(Component, Object.assign({}, props, { stytchMemberSession: session, stytchMemberSessionIsFromCache: fromCache }));
|
|
108
|
+
};
|
|
109
|
+
WithStytchSession.displayName = `withStytchSession(${Component.displayName || Component.name || 'Component'})`;
|
|
110
|
+
return WithStytchSession;
|
|
111
|
+
};
|
|
112
|
+
/**
|
|
113
|
+
* The Stytch Context Provider.
|
|
114
|
+
* Wrap your application with this component in the root file in order to use Stytch everywhere in your app.
|
|
115
|
+
* @example
|
|
116
|
+
* const stytch = new StytchB2BHeadlessClient('public-token-<find yours in the stytch dashboard>')
|
|
117
|
+
*
|
|
118
|
+
* ReactDOM.render(
|
|
119
|
+
* <StytchB2BProvider stytch={stytch}>
|
|
120
|
+
* <App />
|
|
121
|
+
* </StytchProvider>,
|
|
122
|
+
* document.getElementById('root'),
|
|
123
|
+
* )
|
|
124
|
+
*/
|
|
125
|
+
const StytchB2BProvider = ({ stytch, children }) => {
|
|
126
|
+
invariant(!useIsMounted__INTERNAL(), B2BProviderMustBeUniqueError);
|
|
127
|
+
invariant(typeof window !== 'undefined', noSSRError);
|
|
128
|
+
const ctx = useMemo(() => ({ client: stytch, isMounted: true }), [stytch]);
|
|
129
|
+
const [member, setMember] = useAsyncState({
|
|
130
|
+
member: stytch.member.getSync(),
|
|
131
|
+
fromCache: true,
|
|
132
|
+
});
|
|
133
|
+
const [session, setMemberSession] = useAsyncState({
|
|
134
|
+
session: stytch.session.getSync(),
|
|
135
|
+
fromCache: true,
|
|
136
|
+
});
|
|
137
|
+
useEffect(() => {
|
|
138
|
+
const unsubscribeMember = stytch.member.onChange((member) => setMember({
|
|
139
|
+
member,
|
|
140
|
+
fromCache: false,
|
|
141
|
+
}));
|
|
142
|
+
const unsubscribeSession = stytch.session.onChange((session) => setMemberSession({
|
|
143
|
+
session,
|
|
144
|
+
fromCache: false,
|
|
145
|
+
}));
|
|
146
|
+
return () => {
|
|
147
|
+
unsubscribeMember();
|
|
148
|
+
unsubscribeSession();
|
|
149
|
+
};
|
|
150
|
+
}, [stytch, setMember, setMemberSession]);
|
|
151
|
+
// TODO (SDK-813): Remove this when we have a single top-level onChange handler
|
|
152
|
+
const finalMemberSession = !!session.session === !!member.member ? session : initialMemberSession;
|
|
153
|
+
const finalMember = !!session.session === !!member.member ? member : initialMember;
|
|
154
|
+
return (React.createElement(StytchB2BContext.Provider, { value: ctx },
|
|
155
|
+
React.createElement(StytchMemberContext.Provider, { value: finalMember },
|
|
156
|
+
React.createElement(StytchMemberSessionContext.Provider, { value: finalMemberSession }, children))));
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
export { StytchB2BProvider, useStytchB2BClient, useStytchMember, useStytchMemberSession, withStytchB2BClient, withStytchMember, withStytchMemberSession };
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
+
|
|
5
|
+
var React = require('react');
|
|
6
|
+
|
|
7
|
+
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
|
|
8
|
+
|
|
9
|
+
var React__default = /*#__PURE__*/_interopDefaultLegacy(React);
|
|
10
|
+
|
|
11
|
+
const noProviderError = (item, provider = 'StytchProvider') => `${item} can only be used inside <${provider}>.`;
|
|
12
|
+
const B2BProviderMustBeUniqueError = 'You cannot render a <StytchB2BProvider> inside another <StytchB2BProvider>.';
|
|
13
|
+
const noSSRError = `The @stytch/react library is not meant for use with serverside environments like NextJS.
|
|
14
|
+
Use the @stytch/nextjs library instead -
|
|
15
|
+
npm remove @stytch/react && npm install @stytch/nextjs
|
|
16
|
+
`;
|
|
17
|
+
|
|
18
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
19
|
+
function invariant(cond, message) {
|
|
20
|
+
if (!cond)
|
|
21
|
+
throw new Error(message);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// useState can cause memory leaks if it is set after the component unmounted. For example, if it is
|
|
25
|
+
// set after `await`, or in a `then`, `catch`, or `finally`, or in a setTimout/setInterval.
|
|
26
|
+
const useAsyncState = (initialState) => {
|
|
27
|
+
const isMounted = React.useRef(true);
|
|
28
|
+
const [state, setState] = React.useState(initialState);
|
|
29
|
+
React.useEffect(() => {
|
|
30
|
+
isMounted.current = true;
|
|
31
|
+
return () => {
|
|
32
|
+
isMounted.current = false;
|
|
33
|
+
};
|
|
34
|
+
}, []);
|
|
35
|
+
const setStateAction = React.useCallback((newState) => {
|
|
36
|
+
isMounted.current && setState(newState);
|
|
37
|
+
}, []);
|
|
38
|
+
return [state, setStateAction];
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
const initialMember = {
|
|
42
|
+
member: null,
|
|
43
|
+
fromCache: false,
|
|
44
|
+
};
|
|
45
|
+
const initialMemberSession = {
|
|
46
|
+
session: null,
|
|
47
|
+
fromCache: false,
|
|
48
|
+
};
|
|
49
|
+
const StytchB2BContext = React.createContext({ isMounted: false });
|
|
50
|
+
const StytchMemberContext = React.createContext(initialMember);
|
|
51
|
+
const StytchMemberSessionContext = React.createContext(initialMemberSession);
|
|
52
|
+
const useIsMounted__INTERNAL = () => React.useContext(StytchB2BContext).isMounted;
|
|
53
|
+
/**
|
|
54
|
+
* Returns the active Member.
|
|
55
|
+
* Check the fromCache property to determine if the member data is from persistent storage.
|
|
56
|
+
* @example
|
|
57
|
+
* const {member} = useStytchMember();
|
|
58
|
+
* return (<h1>Welcome, {member.name}</h1>);
|
|
59
|
+
* @returns A {@link SWRUser}
|
|
60
|
+
*/
|
|
61
|
+
const useStytchMember = () => {
|
|
62
|
+
invariant(useIsMounted__INTERNAL(), noProviderError('useStytchMember', 'StytchB2BProvider'));
|
|
63
|
+
return React.useContext(StytchMemberContext);
|
|
64
|
+
};
|
|
65
|
+
/**
|
|
66
|
+
* Returns the active member's Stytch member session.
|
|
67
|
+
* @example
|
|
68
|
+
* const { session } = useStytchMemberSession();
|
|
69
|
+
* useEffect(() => {
|
|
70
|
+
* if (!session) {
|
|
71
|
+
* router.replace('/login')
|
|
72
|
+
* }
|
|
73
|
+
* }, [session]);
|
|
74
|
+
* @returns A {@link SWRMemberSession}
|
|
75
|
+
*/
|
|
76
|
+
const useStytchMemberSession = () => {
|
|
77
|
+
invariant(useIsMounted__INTERNAL(), noProviderError('useStytchMemberSession', 'StytchB2BProvider'));
|
|
78
|
+
return React.useContext(StytchMemberSessionContext);
|
|
79
|
+
};
|
|
80
|
+
/**
|
|
81
|
+
* Returns the Stytch B2B client stored in the Stytch context.
|
|
82
|
+
*
|
|
83
|
+
* @example
|
|
84
|
+
* const stytch = useStytchB2BClient();
|
|
85
|
+
* useEffect(() => {
|
|
86
|
+
* stytch.magicLinks.authenticate('...')
|
|
87
|
+
* }, [stytch]);
|
|
88
|
+
*/
|
|
89
|
+
const useStytchB2BClient = () => {
|
|
90
|
+
const ctx = React.useContext(StytchB2BContext);
|
|
91
|
+
invariant(ctx.isMounted, noProviderError('useStytchB2BClient', 'StytchB2BProvider'));
|
|
92
|
+
return ctx.client;
|
|
93
|
+
};
|
|
94
|
+
const withStytchB2BClient = (Component) => {
|
|
95
|
+
const WithStytch = (props) => {
|
|
96
|
+
invariant(useIsMounted__INTERNAL(), noProviderError('withStytchB2BClient', 'StytchB2BProvider'));
|
|
97
|
+
return React__default['default'].createElement(Component, Object.assign({}, props, { stytch: useStytchB2BClient() }));
|
|
98
|
+
};
|
|
99
|
+
WithStytch.displayName = `withStytch(${Component.displayName || Component.name || 'Component'})`;
|
|
100
|
+
return WithStytch;
|
|
101
|
+
};
|
|
102
|
+
const withStytchMember = (Component) => {
|
|
103
|
+
const WithStytchUser = (props) => {
|
|
104
|
+
invariant(useIsMounted__INTERNAL(), noProviderError('withStytchMember', 'StytchB2BProvider'));
|
|
105
|
+
const { member, fromCache } = useStytchMember();
|
|
106
|
+
return React__default['default'].createElement(Component, Object.assign({}, props, { stytchMember: member, stytchMemberIsFromCache: fromCache }));
|
|
107
|
+
};
|
|
108
|
+
WithStytchUser.displayName = `withStytchUser(${Component.displayName || Component.name || 'Component'})`;
|
|
109
|
+
return WithStytchUser;
|
|
110
|
+
};
|
|
111
|
+
const withStytchMemberSession = (Component) => {
|
|
112
|
+
const WithStytchSession = (props) => {
|
|
113
|
+
invariant(useIsMounted__INTERNAL(), noProviderError('withStytchMemberSession', 'StytchB2BProvider'));
|
|
114
|
+
const { session, fromCache } = useStytchMemberSession();
|
|
115
|
+
return React__default['default'].createElement(Component, Object.assign({}, props, { stytchMemberSession: session, stytchMemberSessionIsFromCache: fromCache }));
|
|
116
|
+
};
|
|
117
|
+
WithStytchSession.displayName = `withStytchSession(${Component.displayName || Component.name || 'Component'})`;
|
|
118
|
+
return WithStytchSession;
|
|
119
|
+
};
|
|
120
|
+
/**
|
|
121
|
+
* The Stytch Context Provider.
|
|
122
|
+
* Wrap your application with this component in the root file in order to use Stytch everywhere in your app.
|
|
123
|
+
* @example
|
|
124
|
+
* const stytch = new StytchB2BHeadlessClient('public-token-<find yours in the stytch dashboard>')
|
|
125
|
+
*
|
|
126
|
+
* ReactDOM.render(
|
|
127
|
+
* <StytchB2BProvider stytch={stytch}>
|
|
128
|
+
* <App />
|
|
129
|
+
* </StytchProvider>,
|
|
130
|
+
* document.getElementById('root'),
|
|
131
|
+
* )
|
|
132
|
+
*/
|
|
133
|
+
const StytchB2BProvider = ({ stytch, children }) => {
|
|
134
|
+
invariant(!useIsMounted__INTERNAL(), B2BProviderMustBeUniqueError);
|
|
135
|
+
invariant(typeof window !== 'undefined', noSSRError);
|
|
136
|
+
const ctx = React.useMemo(() => ({ client: stytch, isMounted: true }), [stytch]);
|
|
137
|
+
const [member, setMember] = useAsyncState({
|
|
138
|
+
member: stytch.member.getSync(),
|
|
139
|
+
fromCache: true,
|
|
140
|
+
});
|
|
141
|
+
const [session, setMemberSession] = useAsyncState({
|
|
142
|
+
session: stytch.session.getSync(),
|
|
143
|
+
fromCache: true,
|
|
144
|
+
});
|
|
145
|
+
React.useEffect(() => {
|
|
146
|
+
const unsubscribeMember = stytch.member.onChange((member) => setMember({
|
|
147
|
+
member,
|
|
148
|
+
fromCache: false,
|
|
149
|
+
}));
|
|
150
|
+
const unsubscribeSession = stytch.session.onChange((session) => setMemberSession({
|
|
151
|
+
session,
|
|
152
|
+
fromCache: false,
|
|
153
|
+
}));
|
|
154
|
+
return () => {
|
|
155
|
+
unsubscribeMember();
|
|
156
|
+
unsubscribeSession();
|
|
157
|
+
};
|
|
158
|
+
}, [stytch, setMember, setMemberSession]);
|
|
159
|
+
// TODO (SDK-813): Remove this when we have a single top-level onChange handler
|
|
160
|
+
const finalMemberSession = !!session.session === !!member.member ? session : initialMemberSession;
|
|
161
|
+
const finalMember = !!session.session === !!member.member ? member : initialMember;
|
|
162
|
+
return (React__default['default'].createElement(StytchB2BContext.Provider, { value: ctx },
|
|
163
|
+
React__default['default'].createElement(StytchMemberContext.Provider, { value: finalMember },
|
|
164
|
+
React__default['default'].createElement(StytchMemberSessionContext.Provider, { value: finalMemberSession }, children))));
|
|
165
|
+
};
|
|
166
|
+
|
|
167
|
+
exports.StytchB2BProvider = StytchB2BProvider;
|
|
168
|
+
exports.useStytchB2BClient = useStytchB2BClient;
|
|
169
|
+
exports.useStytchMember = useStytchMember;
|
|
170
|
+
exports.useStytchMemberSession = useStytchMemberSession;
|
|
171
|
+
exports.withStytchB2BClient = withStytchB2BClient;
|
|
172
|
+
exports.withStytchMember = withStytchMember;
|
|
173
|
+
exports.withStytchMemberSession = withStytchMemberSession;
|
package/dist/index.esm.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React, { useRef, useState, useEffect, useCallback, createContext, useContext, useMemo, useLayoutEffect } from 'react';
|
|
2
2
|
|
|
3
|
-
const noProviderError = (item) => `${item} can only be used inside
|
|
3
|
+
const noProviderError = (item, provider = 'StytchProvider') => `${item} can only be used inside <${provider}>.`;
|
|
4
4
|
const providerMustBeUniqueError = 'You cannot render a <StytchProvider> inside another <StytchProvider>.';
|
|
5
5
|
const noSSRError = `The @stytch/react library is not meant for use with serverside environments like NextJS.
|
|
6
6
|
Use the @stytch/nextjs library instead -
|
|
@@ -154,6 +154,7 @@ const StytchProvider = ({ stytch, children }) => {
|
|
|
154
154
|
unsubscribeSession();
|
|
155
155
|
};
|
|
156
156
|
}, [stytch, setUser, setSession]);
|
|
157
|
+
// TODO (SDK-813): Remove this when we have a single top-level onChange handler
|
|
157
158
|
const finalSess = !!session.session === !!user.user ? session : initialSession;
|
|
158
159
|
const finalUser = !!session.session === !!user.user ? user : initialUser;
|
|
159
160
|
return (React.createElement(StytchContext.Provider, { value: ctx },
|
package/dist/index.js
CHANGED
|
@@ -8,7 +8,7 @@ function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'defau
|
|
|
8
8
|
|
|
9
9
|
var React__default = /*#__PURE__*/_interopDefaultLegacy(React);
|
|
10
10
|
|
|
11
|
-
const noProviderError = (item) => `${item} can only be used inside
|
|
11
|
+
const noProviderError = (item, provider = 'StytchProvider') => `${item} can only be used inside <${provider}>.`;
|
|
12
12
|
const providerMustBeUniqueError = 'You cannot render a <StytchProvider> inside another <StytchProvider>.';
|
|
13
13
|
const noSSRError = `The @stytch/react library is not meant for use with serverside environments like NextJS.
|
|
14
14
|
Use the @stytch/nextjs library instead -
|
|
@@ -162,6 +162,7 @@ const StytchProvider = ({ stytch, children }) => {
|
|
|
162
162
|
unsubscribeSession();
|
|
163
163
|
};
|
|
164
164
|
}, [stytch, setUser, setSession]);
|
|
165
|
+
// TODO (SDK-813): Remove this when we have a single top-level onChange handler
|
|
165
166
|
const finalSess = !!session.session === !!user.user ? session : initialSession;
|
|
166
167
|
const finalUser = !!session.session === !!user.user ? user : initialUser;
|
|
167
168
|
return (React__default['default'].createElement(StytchContext.Provider, { value: ctx },
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stytch/react",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.1",
|
|
4
4
|
"description": "Stytch's official React Library",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.esm.js",
|
|
@@ -31,14 +31,14 @@
|
|
|
31
31
|
],
|
|
32
32
|
"devDependencies": {
|
|
33
33
|
"@babel/runtime": "7.18.6",
|
|
34
|
-
"@stytch/vanilla-js": "0.
|
|
34
|
+
"@stytch/vanilla-js": "0.10.2",
|
|
35
35
|
"@testing-library/react": "12.1.3",
|
|
36
36
|
"eslint-config-custom": "0.0.0",
|
|
37
37
|
"rollup": "2.56.3",
|
|
38
38
|
"typescript": "4.7.4"
|
|
39
39
|
},
|
|
40
40
|
"peerDependencies": {
|
|
41
|
-
"@stytch/vanilla-js": "^0.
|
|
41
|
+
"@stytch/vanilla-js": "^0.10.2",
|
|
42
42
|
"react": ">= 17.0.2",
|
|
43
43
|
"react-dom": ">= 17.0.2"
|
|
44
44
|
}
|