@stytch/react 19.4.4 → 19.5.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 (51) hide show
  1. package/CHANGELOG.md +31 -0
  2. package/README.md +7 -7
  3. package/b2b/headless/package.json +6 -0
  4. package/b2b/ui/package.json +6 -0
  5. package/dist/{StytchB2BContext-09d376ba.d.ts → StytchB2BContext-9c062712.d.ts} +127 -23
  6. package/dist/{StytchB2BContext-09d376ba.js → StytchB2BContext-9c062712.js} +85 -42
  7. package/dist/{StytchB2BContext-a8d57249.d.ts → StytchB2BContext-c5062f9b.d.ts} +127 -23
  8. package/dist/{StytchB2BContext-a8d57249.js → StytchB2BContext-c5062f9b.js} +95 -52
  9. package/dist/StytchSSRProxy-34c789b5.d.ts +3 -0
  10. package/dist/StytchSSRProxy-34c789b5.js +48 -0
  11. package/dist/StytchSSRProxy-86bc42b3.d.ts +3 -0
  12. package/dist/StytchSSRProxy-86bc42b3.js +54 -0
  13. package/dist/adminPortal/index.d.ts +1 -1
  14. package/dist/adminPortal/index.esm.d.ts +1 -1
  15. package/dist/adminPortal/index.esm.js +5 -4
  16. package/dist/adminPortal/index.js +5 -4
  17. package/dist/b2b/index.d.ts +170 -6
  18. package/dist/b2b/index.esm.d.ts +170 -6
  19. package/dist/b2b/index.esm.js +85 -8
  20. package/dist/b2b/index.headless.d.ts +16 -0
  21. package/dist/b2b/index.headless.esm.d.ts +16 -0
  22. package/dist/b2b/index.headless.esm.js +24 -0
  23. package/dist/b2b/index.headless.js +28 -0
  24. package/dist/b2b/index.js +93 -16
  25. package/dist/b2b/index.ui.d.ts +17 -0
  26. package/dist/b2b/index.ui.esm.d.ts +17 -0
  27. package/dist/b2b/index.ui.esm.js +25 -0
  28. package/dist/b2b/index.ui.js +29 -0
  29. package/dist/errors-d9d5fbc8.d.ts +5 -0
  30. package/dist/index-b14d4efe.d.ts +1 -1
  31. package/dist/index.d.ts +92 -54
  32. package/dist/index.esm.d.ts +92 -54
  33. package/dist/index.esm.js +112 -38
  34. package/dist/index.headless.d.ts +16 -0
  35. package/dist/index.headless.esm.d.ts +16 -0
  36. package/dist/index.headless.esm.js +24 -0
  37. package/dist/index.headless.js +28 -0
  38. package/dist/index.js +126 -52
  39. package/dist/index.ui.d.ts +17 -0
  40. package/dist/index.ui.esm.d.ts +17 -0
  41. package/dist/index.ui.esm.js +25 -0
  42. package/dist/index.ui.js +29 -0
  43. package/dist/useIsomorphicLayoutEffect-1babb81e.d.ts +24 -0
  44. package/dist/{invariant-568a7633.js → useIsomorphicLayoutEffect-1babb81e.js} +5 -13
  45. package/dist/useIsomorphicLayoutEffect-65746ef3.d.ts +24 -0
  46. package/dist/{invariant-ae5a5bce.js → useIsomorphicLayoutEffect-65746ef3.js} +4 -16
  47. package/headless/package.json +6 -0
  48. package/package.json +7 -4
  49. package/ui/package.json +6 -0
  50. package/dist/invariant-568a7633.d.ts +0 -27
  51. package/dist/invariant-ae5a5bce.d.ts +0 -27
@@ -1,15 +1,29 @@
1
1
  /// <reference types="react" />
2
2
  import React from 'react';
3
3
  import { ReactNode } from "react";
4
+ import { PermissionsMap } from '@stytch/core/public';
4
5
  import { Member, MemberSession, Organization, StytchB2BUIClient } from '@stytch/vanilla-js/b2b';
5
6
  import { StytchB2BHeadlessClient, StytchProjectConfigurationInput } from '@stytch/vanilla-js/b2b/headless';
6
- import { PermissionsMap } from '@stytch/core/public';
7
7
  /**
8
8
  * The Stytch Client object passed in to <StytchB2BProvider /> in your application root.
9
9
  * Either a StytchB2BUIClient or StytchB2BHeadlessClient.
10
10
  */
11
11
  type StytchB2BClient<TProjectConfiguration extends StytchProjectConfigurationInput> = StytchB2BHeadlessClient<TProjectConfiguration> | StytchB2BUIClient<TProjectConfiguration>;
12
- type SWRMember = {
12
+ type SWRMemberUninitialized = {
13
+ /**
14
+ * Either the active {@link Member} object, or null if the member is not logged in.
15
+ */
16
+ member: null;
17
+ /**
18
+ * If true, indicates that the value returned is from the application cache and a state refresh is in progress.
19
+ */
20
+ fromCache: false;
21
+ /**
22
+ * If true, indicates that the SDK has completed initialization.
23
+ */
24
+ isInitialized: false;
25
+ };
26
+ type SWRMemberInitialized = {
13
27
  /**
14
28
  * Either the active {@link Member} object, or null if the member is not logged in.
15
29
  */
@@ -18,8 +32,27 @@ type SWRMember = {
18
32
  * If true, indicates that the value returned is from the application cache and a state refresh is in progress.
19
33
  */
20
34
  fromCache: boolean;
35
+ /**
36
+ * If true, indicates that the SDK has completed initialization.
37
+ */
38
+ isInitialized: true;
21
39
  };
22
- type SWRMemberSession = {
40
+ type SWRMember<TAlwaysInitialized extends boolean = boolean> = TAlwaysInitialized extends true ? SWRMemberInitialized : SWRMemberInitialized | SWRMemberUninitialized;
41
+ type SWRMemberSessionUninitialized = {
42
+ /**
43
+ * Either the active {@link MemberSession} object, or null if the member is not logged in.
44
+ */
45
+ session: null;
46
+ /**
47
+ * If true, indicates that the value returned is from the application cache and a state refresh is in progress.
48
+ */
49
+ fromCache: false;
50
+ /**
51
+ * If true, indicates that the SDK has completed initialization.
52
+ */
53
+ isInitialized: false;
54
+ };
55
+ type SWRMemberSessionInitialized = {
23
56
  /**
24
57
  * Either the active {@link MemberSession} object, or null if the member is not logged in.
25
58
  */
@@ -28,8 +61,27 @@ type SWRMemberSession = {
28
61
  * If true, indicates that the value returned is from the application cache and a state refresh is in progress.
29
62
  */
30
63
  fromCache: boolean;
64
+ /**
65
+ * If true, indicates that the SDK has completed initialization.
66
+ */
67
+ isInitialized: true;
31
68
  };
32
- type SWROrganization = {
69
+ type SWRMemberSession<TAlwaysInitialized extends boolean = boolean> = TAlwaysInitialized extends true ? SWRMemberSessionInitialized : SWRMemberSessionInitialized | SWRMemberSessionUninitialized;
70
+ type SWROrganizationUninitialized = {
71
+ /**
72
+ * Either the active {@link Organization} object, or null if the member is not logged in.
73
+ */
74
+ organization: null;
75
+ /**
76
+ * If true, indicates that the value returned is from the application cache and a state refresh is in progress.
77
+ */
78
+ fromCache: false;
79
+ /**
80
+ * If true, indicates that the SDK has completed initialization.
81
+ */
82
+ isInitialized: false;
83
+ };
84
+ type SWROrganizationInitialized = {
33
85
  /**
34
86
  * Either the active {@link Organization} object, or null if the member is not logged in.
35
87
  */
@@ -38,41 +90,72 @@ type SWROrganization = {
38
90
  * If true, indicates that the value returned is from the application cache and a state refresh is in progress.
39
91
  */
40
92
  fromCache: boolean;
93
+ /**
94
+ * If true, indicates that the SDK has completed initialization.
95
+ */
96
+ isInitialized: true;
41
97
  };
98
+ type SWROrganization<TAlwaysInitialized extends boolean = boolean> = TAlwaysInitialized extends true ? SWROrganizationInitialized : SWROrganizationInitialized | SWROrganizationUninitialized;
42
99
  declare const useIsMounted__INTERNAL: () => boolean;
43
100
  declare const isUIClient: <TProjectConfiguration extends Partial<import("@stytch/core/public").StytchProjectConfiguration>>(client: StytchB2BClient<TProjectConfiguration>) => client is StytchB2BUIClient<TProjectConfiguration>;
44
101
  /**
45
102
  * Returns the active Member.
46
103
  * The Stytch SDKs are used for client-side authentication and session management.
104
+ * Check the isInitialized property to determine if the SDK has completed initialization.
47
105
  * Check the fromCache property to determine if the member data is from persistent storage.
48
106
  * @example
49
- * const {member} = useStytchMember();
107
+ * const {member, isInitialized, fromCache} = useStytchMember();
108
+ * if (!isInitialized) {
109
+ * return <p>Loading...</p>;
110
+ * }
50
111
  * return (<h1>Welcome, {member.name}</h1>);
51
112
  */
52
- declare const useStytchMember: () => SWRMember;
113
+ declare const useStytchMember: <TAssumeHydrated extends boolean = false>() => SWRMember<TAssumeHydrated>;
53
114
  /**
54
115
  * Returns the active member's Stytch member session.
55
116
  * The Stytch SDKs are used for client-side authentication and session management.
117
+ * Check the isInitialized property to determine if the SDK has completed initialization.
56
118
  * Check the fromCache property to determine if the session data is from persistent storage.
57
119
  * @example
58
- * const { session } = useStytchMemberSession();
120
+ * const {session, isInitialized, fromCache} = useStytchMemberSession();
59
121
  * useEffect(() => {
122
+ * if (!isInitialized) {
123
+ * return;
124
+ * }
60
125
  * if (!session) {
61
126
  * router.replace('/login')
62
127
  * }
63
- * }, [session]);
128
+ * }, [session, isInitialized]);
64
129
  */
65
- declare const useStytchMemberSession: () => SWRMemberSession;
130
+ declare const useStytchMemberSession: <TAssumeHydrated extends boolean = false>() => SWRMemberSession<TAssumeHydrated>;
66
131
  /**
67
132
  * Returns the active Stytch organization.
68
133
  * The Stytch SDKs are used for client-side authentication and session management.
134
+ * Check the isInitialized property to determine if the SDK has completed initialization.
69
135
  * Check the fromCache property to determine if the organization data is from persistent storage.
70
136
  * @example
71
- * const { organization } = useStytchOrganization();
137
+ * const {organization, isInitialized, fromCache} = useStytchOrganization();
138
+ * if (!isInitialized) {
139
+ * return <p>Loading...</p>;
140
+ * }
72
141
  * return (<p>Welcome to {organization.organization_name}</p>);
73
142
  */
74
- declare const useStytchOrganization: () => SWROrganization;
75
- type SWRIsAuthorized = {
143
+ declare const useStytchOrganization: <TAssumeHydrated extends boolean = false>() => SWROrganization<TAssumeHydrated>;
144
+ type SWRIsAuthorizedUninitialized = {
145
+ /**
146
+ * Whether the logged-in member is allowed to perform the specified action on the specified resource.
147
+ */
148
+ isAuthorized: false;
149
+ /**
150
+ * If true, indicates that the value returned is from the application cache and a state refresh is in progress.
151
+ */
152
+ fromCache: false;
153
+ /**
154
+ * If true, indicates that the SDK has completed initialization.
155
+ */
156
+ isInitialized: false;
157
+ };
158
+ type SWRIsAuthorizedInitialized = {
76
159
  /**
77
160
  * Whether the logged-in member is allowed to perform the specified action on the specified resource.
78
161
  */
@@ -81,7 +164,12 @@ type SWRIsAuthorized = {
81
164
  * If true, indicates that the value returned is from the application cache and a state refresh is in progress.
82
165
  */
83
166
  fromCache: boolean;
167
+ /**
168
+ * If true, indicates that the SDK has completed initialization.
169
+ */
170
+ isInitialized: boolean;
84
171
  };
172
+ type SWRIsAuthorized<TAlwaysInitialized extends boolean> = TAlwaysInitialized extends true ? SWRIsAuthorizedInitialized : SWRIsAuthorizedInitialized | SWRIsAuthorizedUninitialized;
85
173
  /**
86
174
  * Determines whether the logged-in member is allowed to perform the specified action on the specified resource.
87
175
  * Returns `true` if the member can perform the action, `false` otherwise.
@@ -91,10 +179,10 @@ type SWRIsAuthorized = {
91
179
  *
92
180
  * Remember - authorization checks for sensitive actions should always occur on the backend as well.
93
181
  * @example
94
- * const isAuthorized = useStytchIsAuthorized<Permissions>('documents', 'edit');
182
+ * const { isAuthorized } = useStytchIsAuthorized<Permissions>('documents', 'edit');
95
183
  * return <button disabled={!isAuthorized}>Edit</button>
96
184
  */
97
- declare const useStytchIsAuthorized: (resourceId: string, action: string) => SWRIsAuthorized;
185
+ declare const useStytchIsAuthorized: <TAssumeHydrated extends boolean = false>(resourceId: string, action: string) => SWRIsAuthorized<TAssumeHydrated>;
98
186
  /**
99
187
  * Returns the Stytch B2B client stored in the Stytch context.
100
188
  *
@@ -108,16 +196,19 @@ declare const useStytchB2BClient: <TProjectConfiguration extends Partial<import(
108
196
  declare const withStytchB2BClient: <T extends object, TProjectConfiguration extends Partial<import("@stytch/core/public").StytchProjectConfiguration>>(Component: React.ComponentType<T & {
109
197
  stytch: StytchB2BHeadlessClient<TProjectConfiguration>;
110
198
  }>) => React.ComponentType<T>;
111
- declare const withStytchMember: <T extends object>(Component: React.ComponentType<T & {
199
+ declare const withStytchMember: <T extends object, TAssumeHydrated extends boolean = false>(Component: React.ComponentType<T & {
112
200
  stytchMember: Member | null;
201
+ stytchMemberIsInitialized: boolean;
113
202
  stytchMemberIsFromCache: boolean;
114
203
  }>) => React.ComponentType<T>;
115
- declare const withStytchMemberSession: <T extends object>(Component: React.ComponentType<T & {
204
+ declare const withStytchMemberSession: <T extends object, TAssumeHydrated extends boolean = false>(Component: React.ComponentType<T & {
116
205
  stytchMemberSession: MemberSession | null;
206
+ stytchMemberSessionIsInitialized: boolean;
117
207
  stytchMemberSessionIsFromCache: boolean;
118
208
  }>) => React.ComponentType<T>;
119
- declare const withStytchOrganization: <T extends object>(Component: React.ComponentType<T & {
209
+ declare const withStytchOrganization: <T extends object, TAssumeHydrated extends boolean = false>(Component: React.ComponentType<T & {
120
210
  stytchOrganization: Organization | null;
211
+ stytchOrganizationIsInitialized: boolean;
121
212
  stytchOrganizationIsFromCache: boolean;
122
213
  }>) => React.ComponentType<T>;
123
214
  /**
@@ -146,23 +237,36 @@ declare const withStytchPermissions: <Permissions_1 extends Record<string, strin
146
237
  }>) => React.ComponentType<T>;
147
238
  interface StytchB2BProviderProps<TProjectConfiguration extends StytchProjectConfigurationInput = Stytch.DefaultProjectConfiguration> {
148
239
  /**
149
- * A Stytch client instance, either a {@link StytchB2BUIClient} or {@link StytchB2BHeadlessClient}
240
+ * A Stytch client instance, created using either {@link createStytchHeadlessClient} or {@link createStytchUIClient}
150
241
  */
151
242
  stytch: StytchB2BClient<TProjectConfiguration>;
243
+ /**
244
+ * When true, the provider will assume that the component will only be
245
+ * rendered in a browser environment, either in a single-page application or
246
+ * after completing hydration of a server-rendered application. This allows
247
+ * cached values to be retrieved from the browser on the first render, meaning
248
+ * that the `isInitialized` value returned from Stytch hooks will be `true`
249
+ * starting from the first render.
250
+ *
251
+ * When `false`, the provider will defer initialization until after the first
252
+ * render, and `isInitialized` will initially be `false`.
253
+ *
254
+ * This value defaults to `false` in `@stytch/nextjs`.
255
+ */
256
+ assumeHydrated?: boolean;
152
257
  children?: ReactNode;
153
258
  }
154
259
  /**
155
260
  * The Stytch Context Provider.
156
261
  * Wrap your application with this component in order to use Stytch everywhere in your app.
157
262
  * @example
158
- * const stytch = new StytchB2BHeadlessClient('public-token-<find yours in the stytch dashboard>')
263
+ * const stytch = createStytchB2BHeadlessClient('public-token-<find yours in the stytch dashboard>')
159
264
  *
160
- * ReactDOM.render(
265
+ * return (
161
266
  * <StytchB2BProvider stytch={stytch}>
162
267
  * <App />
163
- * </StytchProvider>,
164
- * document.getElementById('root'),
268
+ * </StytchB2BProvider>
165
269
  * )
166
270
  */
167
- declare const StytchB2BProvider: <TProjectConfiguration extends Partial<import("@stytch/core/public").StytchProjectConfiguration> = Stytch.DefaultProjectConfiguration>({ stytch, children, }: StytchB2BProviderProps<TProjectConfiguration>) => JSX.Element;
271
+ declare const StytchB2BProvider: <TProjectConfiguration extends Partial<import("@stytch/core/public").StytchProjectConfiguration> = Stytch.DefaultProjectConfiguration>({ stytch, children, assumeHydrated, }: StytchB2BProviderProps<TProjectConfiguration>) => JSX.Element;
168
272
  export { useIsMounted__INTERNAL, isUIClient, useStytchMember, useStytchMemberSession, useStytchOrganization, useStytchIsAuthorized, useStytchB2BClient, withStytchB2BClient, withStytchMember, withStytchMemberSession, withStytchOrganization, withStytchPermissions, StytchB2BProviderProps, StytchB2BProvider };
@@ -1,7 +1,8 @@
1
1
  'use strict';
2
2
 
3
3
  var React = require('react');
4
- var invariant = require('./invariant-ae5a5bce.js');
4
+ var useIsomorphicLayoutEffect = require('./useIsomorphicLayoutEffect-65746ef3.js');
5
+ var StytchSSRProxy = require('./StytchSSRProxy-86bc42b3.js');
5
6
 
6
7
  function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
7
8
 
@@ -10,14 +11,17 @@ var React__default = /*#__PURE__*/_interopDefaultLegacy(React);
10
11
  const initialMember = {
11
12
  member: null,
12
13
  fromCache: false,
14
+ isInitialized: false,
13
15
  };
14
16
  const initialMemberSession = {
15
17
  session: null,
16
18
  fromCache: false,
19
+ isInitialized: false,
17
20
  };
18
21
  const initialOrganization = {
19
22
  organization: null,
20
23
  fromCache: false,
24
+ isInitialized: false,
21
25
  };
22
26
  const StytchB2BContext = React.createContext({ isMounted: false });
23
27
  const StytchMemberContext = React.createContext(initialMember);
@@ -30,41 +34,53 @@ const isUIClient = (client) => {
30
34
  /**
31
35
  * Returns the active Member.
32
36
  * The Stytch SDKs are used for client-side authentication and session management.
37
+ * Check the isInitialized property to determine if the SDK has completed initialization.
33
38
  * Check the fromCache property to determine if the member data is from persistent storage.
34
39
  * @example
35
- * const {member} = useStytchMember();
40
+ * const {member, isInitialized, fromCache} = useStytchMember();
41
+ * if (!isInitialized) {
42
+ * return <p>Loading...</p>;
43
+ * }
36
44
  * return (<h1>Welcome, {member.name}</h1>);
37
45
  */
38
46
  const useStytchMember = () => {
39
- invariant.invariant(useIsMounted__INTERNAL(), invariant.noProviderError('useStytchMember', 'StytchB2BProvider'));
47
+ useIsomorphicLayoutEffect.invariant(useIsMounted__INTERNAL(), StytchSSRProxy.noProviderError('useStytchMember', 'StytchB2BProvider'));
40
48
  return React.useContext(StytchMemberContext);
41
49
  };
42
50
  /**
43
51
  * Returns the active member's Stytch member session.
44
52
  * The Stytch SDKs are used for client-side authentication and session management.
53
+ * Check the isInitialized property to determine if the SDK has completed initialization.
45
54
  * Check the fromCache property to determine if the session data is from persistent storage.
46
55
  * @example
47
- * const { session } = useStytchMemberSession();
56
+ * const {session, isInitialized, fromCache} = useStytchMemberSession();
48
57
  * useEffect(() => {
58
+ * if (!isInitialized) {
59
+ * return;
60
+ * }
49
61
  * if (!session) {
50
62
  * router.replace('/login')
51
63
  * }
52
- * }, [session]);
64
+ * }, [session, isInitialized]);
53
65
  */
54
66
  const useStytchMemberSession = () => {
55
- invariant.invariant(useIsMounted__INTERNAL(), invariant.noProviderError('useStytchMemberSession', 'StytchB2BProvider'));
67
+ useIsomorphicLayoutEffect.invariant(useIsMounted__INTERNAL(), StytchSSRProxy.noProviderError('useStytchMemberSession', 'StytchB2BProvider'));
56
68
  return React.useContext(StytchMemberSessionContext);
57
69
  };
58
70
  /**
59
71
  * Returns the active Stytch organization.
60
72
  * The Stytch SDKs are used for client-side authentication and session management.
73
+ * Check the isInitialized property to determine if the SDK has completed initialization.
61
74
  * Check the fromCache property to determine if the organization data is from persistent storage.
62
75
  * @example
63
- * const { organization } = useStytchOrganization();
76
+ * const {organization, isInitialized, fromCache} = useStytchOrganization();
77
+ * if (!isInitialized) {
78
+ * return <p>Loading...</p>;
79
+ * }
64
80
  * return (<p>Welcome to {organization.organization_name}</p>);
65
81
  */
66
82
  const useStytchOrganization = () => {
67
- invariant.invariant(useIsMounted__INTERNAL(), invariant.noProviderError('useStytchOrganization', 'StytchB2BProvider'));
83
+ useIsomorphicLayoutEffect.invariant(useIsMounted__INTERNAL(), StytchSSRProxy.noProviderError('useStytchOrganization', 'StytchB2BProvider'));
68
84
  return React.useContext(StytchOrganizationContext);
69
85
  };
70
86
  /**
@@ -76,22 +92,35 @@ const useStytchOrganization = () => {
76
92
  *
77
93
  * Remember - authorization checks for sensitive actions should always occur on the backend as well.
78
94
  * @example
79
- * const isAuthorized = useStytchIsAuthorized<Permissions>('documents', 'edit');
95
+ * const { isAuthorized } = useStytchIsAuthorized<Permissions>('documents', 'edit');
80
96
  * return <button disabled={!isAuthorized}>Edit</button>
81
97
  */
82
98
  const useStytchIsAuthorized = (resourceId, action) => {
83
- invariant.invariant(useIsMounted__INTERNAL(), invariant.noProviderError('useStytchIsAuthorized', 'StytchB2BProvider'));
99
+ useIsomorphicLayoutEffect.invariant(useIsMounted__INTERNAL(), StytchSSRProxy.noProviderError('useStytchIsAuthorized', 'StytchB2BProvider'));
84
100
  const client = useStytchB2BClient();
85
101
  const { session } = useStytchMemberSession();
86
- const [isAuthorized, setIsAuthorized] = invariant.useAsyncState({
87
- fromCache: true,
88
- isAuthorized: client.rbac.isAuthorizedSync(resourceId, action),
102
+ const [isAuthorized, setIsAuthorized] = useIsomorphicLayoutEffect.useAsyncState({
103
+ isInitialized: false,
104
+ fromCache: false,
105
+ isAuthorized: false,
89
106
  });
90
107
  React.useEffect(() => {
91
- client.rbac.isAuthorized(resourceId, action).then((isAuthorized) => setIsAuthorized({
92
- fromCache: false,
93
- isAuthorized,
94
- }));
108
+ if (StytchSSRProxy.isStytchSSRProxy(client)) {
109
+ return;
110
+ }
111
+ setIsAuthorized({
112
+ isInitialized: true,
113
+ fromCache: true,
114
+ isAuthorized: client.rbac.isAuthorizedSync(resourceId, action),
115
+ });
116
+ }, [action, client, resourceId, setIsAuthorized]);
117
+ React.useEffect(() => {
118
+ if (StytchSSRProxy.isStytchSSRProxy(client)) {
119
+ return;
120
+ }
121
+ client.rbac.isAuthorized(resourceId, action).then((isAuthorized) => {
122
+ setIsAuthorized({ isAuthorized, fromCache: false, isInitialized: true });
123
+ });
95
124
  }, [client, session === null || session === void 0 ? void 0 : session.roles, resourceId, action, setIsAuthorized]);
96
125
  return isAuthorized;
97
126
  };
@@ -106,12 +135,12 @@ const useStytchIsAuthorized = (resourceId, action) => {
106
135
  */
107
136
  const useStytchB2BClient = () => {
108
137
  const ctx = React.useContext(StytchB2BContext);
109
- invariant.invariant(ctx.isMounted, invariant.noProviderError('useStytchB2BClient', 'StytchB2BProvider'));
138
+ useIsomorphicLayoutEffect.invariant(ctx.isMounted, StytchSSRProxy.noProviderError('useStytchB2BClient', 'StytchB2BProvider'));
110
139
  return ctx.client;
111
140
  };
112
141
  const withStytchB2BClient = (Component) => {
113
142
  const WithStytch = (props) => {
114
- invariant.invariant(useIsMounted__INTERNAL(), invariant.noProviderError('withStytchB2BClient', 'StytchB2BProvider'));
143
+ useIsomorphicLayoutEffect.invariant(useIsMounted__INTERNAL(), StytchSSRProxy.noProviderError('withStytchB2BClient', 'StytchB2BProvider'));
115
144
  return React__default["default"].createElement(Component, Object.assign({}, props, { stytch: useStytchB2BClient() }));
116
145
  };
117
146
  WithStytch.displayName = `withStytch(${Component.displayName || Component.name || 'Component'})`;
@@ -119,27 +148,27 @@ const withStytchB2BClient = (Component) => {
119
148
  };
120
149
  const withStytchMember = (Component) => {
121
150
  const WithStytchUser = (props) => {
122
- invariant.invariant(useIsMounted__INTERNAL(), invariant.noProviderError('withStytchMember', 'StytchB2BProvider'));
123
- const { member, fromCache } = useStytchMember();
124
- return React__default["default"].createElement(Component, Object.assign({}, props, { stytchMember: member, stytchMemberIsFromCache: fromCache }));
151
+ useIsomorphicLayoutEffect.invariant(useIsMounted__INTERNAL(), StytchSSRProxy.noProviderError('withStytchMember', 'StytchB2BProvider'));
152
+ const { member, isInitialized, fromCache } = useStytchMember();
153
+ return (React__default["default"].createElement(Component, Object.assign({}, props, { stytchMember: member, stytchMemberIsInitialized: isInitialized, stytchMemberIsFromCache: fromCache })));
125
154
  };
126
155
  WithStytchUser.displayName = `withStytchMember(${Component.displayName || Component.name || 'Component'})`;
127
156
  return WithStytchUser;
128
157
  };
129
158
  const withStytchMemberSession = (Component) => {
130
159
  const WithStytchSession = (props) => {
131
- invariant.invariant(useIsMounted__INTERNAL(), invariant.noProviderError('withStytchMemberSession', 'StytchB2BProvider'));
132
- const { session, fromCache } = useStytchMemberSession();
133
- return React__default["default"].createElement(Component, Object.assign({}, props, { stytchMemberSession: session, stytchMemberSessionIsFromCache: fromCache }));
160
+ useIsomorphicLayoutEffect.invariant(useIsMounted__INTERNAL(), StytchSSRProxy.noProviderError('withStytchMemberSession', 'StytchB2BProvider'));
161
+ const { session, isInitialized, fromCache } = useStytchMemberSession();
162
+ return (React__default["default"].createElement(Component, Object.assign({}, props, { stytchMemberSession: session, stytchMemberSessionIsInitialized: isInitialized, stytchMemberSessionIsFromCache: fromCache })));
134
163
  };
135
164
  WithStytchSession.displayName = `withStytchMemberSession(${Component.displayName || Component.name || 'Component'})`;
136
165
  return WithStytchSession;
137
166
  };
138
167
  const withStytchOrganization = (Component) => {
139
168
  const WithStytchOrganization = (props) => {
140
- invariant.invariant(useIsMounted__INTERNAL(), invariant.noProviderError('withStytchOrganization', 'StytchB2BProvider'));
141
- const { organization, fromCache } = useStytchOrganization();
142
- return React__default["default"].createElement(Component, Object.assign({}, props, { stytchOrganization: organization, stytchOrganizationIsFromCache: fromCache }));
169
+ useIsomorphicLayoutEffect.invariant(useIsMounted__INTERNAL(), StytchSSRProxy.noProviderError('withStytchOrganization', 'StytchB2BProvider'));
170
+ const { organization, isInitialized, fromCache } = useStytchOrganization();
171
+ return (React__default["default"].createElement(Component, Object.assign({}, props, { stytchOrganization: organization, stytchOrganizationIsInitialized: isInitialized, stytchOrganizationIsFromCache: fromCache })));
143
172
  };
144
173
  WithStytchOrganization.displayName = `withStytchOrganization(${Component.displayName || Component.name || 'Component'})`;
145
174
  return WithStytchOrganization;
@@ -167,10 +196,10 @@ const withStytchOrganization = (Component) => {
167
196
  */
168
197
  const withStytchPermissions = (Component) => {
169
198
  const WithStytchPermissions = (props) => {
170
- invariant.invariant(useIsMounted__INTERNAL(), invariant.noProviderError('useRBACPermissions', 'StytchB2BProvider'));
199
+ useIsomorphicLayoutEffect.invariant(useIsMounted__INTERNAL(), StytchSSRProxy.noProviderError('useRBACPermissions', 'StytchB2BProvider'));
171
200
  const client = useStytchB2BClient();
172
201
  const { session } = useStytchMemberSession();
173
- const [permissions, setPermissions] = invariant.useAsyncState({ loaded: false, value: null });
202
+ const [permissions, setPermissions] = useIsomorphicLayoutEffect.useAsyncState({ loaded: false, value: null });
174
203
  React.useEffect(() => {
175
204
  client.rbac
176
205
  .allPermissions()
@@ -188,34 +217,48 @@ const withStytchPermissions = (Component) => {
188
217
  * The Stytch Context Provider.
189
218
  * Wrap your application with this component in order to use Stytch everywhere in your app.
190
219
  * @example
191
- * const stytch = new StytchB2BHeadlessClient('public-token-<find yours in the stytch dashboard>')
220
+ * const stytch = createStytchB2BHeadlessClient('public-token-<find yours in the stytch dashboard>')
192
221
  *
193
- * ReactDOM.render(
222
+ * return (
194
223
  * <StytchB2BProvider stytch={stytch}>
195
224
  * <App />
196
- * </StytchProvider>,
197
- * document.getElementById('root'),
225
+ * </StytchB2BProvider>
198
226
  * )
199
227
  */
200
- const StytchB2BProvider = ({ stytch, children, }) => {
201
- invariant.invariant(!useIsMounted__INTERNAL(), invariant.B2BProviderMustBeUniqueError);
202
- invariant.invariant(typeof window !== 'undefined', invariant.noSSRError);
228
+ const StytchB2BProvider = ({ stytch, children, assumeHydrated = false, }) => {
229
+ useIsomorphicLayoutEffect.invariant(!useIsMounted__INTERNAL(), 'You cannot render a <StytchB2BProvider> inside another <StytchB2BProvider>.');
230
+ useIsomorphicLayoutEffect.invariant(!assumeHydrated || typeof window !== 'undefined', 'The `assumeHydrated` prop must be set to `false` when using StytchB2BProvider in a server environment.');
203
231
  const ctx = React.useMemo(() => ({ client: stytch, isMounted: true }), [stytch]);
204
- const [{ member, session, organization }, setClientState] = invariant.useAsyncState({
205
- session: stytch.session.getInfo(),
206
- member: stytch.self.getInfo(),
207
- organization: stytch.organization.getInfo(),
208
- });
209
- React.useEffect(() => stytch.onStateChange(() => {
210
- setClientState((oldState) => {
211
- const newState = {
212
- session: stytch.session.getInfo(),
213
- member: stytch.self.getInfo(),
214
- organization: stytch.organization.getInfo(),
215
- };
216
- return invariant.mergeWithStableProps(oldState, newState);
217
- });
218
- }), [setClientState, stytch]);
232
+ const getHydratedState = React.useCallback(() => {
233
+ return {
234
+ member: Object.assign(Object.assign({}, stytch.self.getInfo()), { isInitialized: true }),
235
+ session: Object.assign(Object.assign({}, stytch.session.getInfo()), { isInitialized: true }),
236
+ organization: Object.assign(Object.assign({}, stytch.organization.getInfo()), { isInitialized: true }),
237
+ };
238
+ }, [stytch]);
239
+ const getInitialState = () => {
240
+ return {
241
+ member: initialMember,
242
+ session: initialMemberSession,
243
+ organization: initialOrganization,
244
+ };
245
+ };
246
+ const [{ member, session, organization }, setClientState] = useIsomorphicLayoutEffect.useAsyncState(() => assumeHydrated ? getHydratedState() : getInitialState());
247
+ // Store the initial value of `assumeHydrated` in a ref, because it is
248
+ // logically only relevant for the first render
249
+ const assumeHydratedRef = React.useRef(assumeHydrated);
250
+ React.useEffect(() => {
251
+ if (StytchSSRProxy.isStytchSSRProxy(stytch)) {
252
+ return;
253
+ }
254
+ const updateState = () => {
255
+ setClientState((oldState) => useIsomorphicLayoutEffect.mergeWithStableProps(oldState, getHydratedState()));
256
+ };
257
+ if (!assumeHydratedRef.current) {
258
+ updateState();
259
+ }
260
+ return stytch.onStateChange(updateState);
261
+ }, [getHydratedState, setClientState, stytch]);
219
262
  return (React__default["default"].createElement(StytchB2BContext.Provider, { value: ctx },
220
263
  React__default["default"].createElement(StytchOrganizationContext.Provider, { value: organization },
221
264
  React__default["default"].createElement(StytchMemberContext.Provider, { value: member },
@@ -0,0 +1,3 @@
1
+ declare const isStytchSSRProxy: (proxy: any) => boolean;
2
+ declare const createStytchSSRProxy: () => any;
3
+ export { isStytchSSRProxy, createStytchSSRProxy };
@@ -0,0 +1,48 @@
1
+ const noProviderError = (item, provider = 'StytchProvider') => `${item} can only be used inside <${provider}>.`;
2
+ const providerMustBeUniqueError = 'You cannot render a <StytchProvider> inside another <StytchProvider>.';
3
+ const noHeadlessClientError = `Tried to create a Stytch Login UI element using the Stytch Headless SDK.
4
+ You must use the UI SDK to use UI elements.
5
+ Please make sure you are using a Stytch UI client, not a Stytch Headless client.`;
6
+ const cannotInvokeMethodOnServerError = (path) => `[Stytch] Invalid serverside function call to ${path}.
7
+ The Stytch Javascript SDK is intended to ony be used on the client side.
8
+ Make sure to wrap your API calls in a hook to ensure they are executed on the client.
9
+ \`\`\`
10
+ const myComponent = () => {
11
+ const stytch = useStytch();
12
+ // This will error out on the server.
13
+ stytch.magicLinks.authenticate(...);
14
+ useEffect(() => {
15
+ // This will work well
16
+ stytch.magicLinks.authenticate(...);
17
+ }, []);
18
+ }
19
+ \`\`\`
20
+
21
+ If you want to make API calls from server environments, please use the Stytch Node Library
22
+ https://www.npmjs.com/package/stytch.
23
+ `;
24
+
25
+ const SSRStubKey = Symbol('__stytch_SSRStubKey');
26
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
27
+ const isStytchSSRProxy = (proxy) => {
28
+ return !!proxy[SSRStubKey];
29
+ };
30
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
31
+ const createProxy = (path) => {
32
+ // eslint-disable-next-line @typescript-eslint/no-empty-function
33
+ const noop = () => { };
34
+ return new Proxy(noop, {
35
+ get(target, p) {
36
+ if (p === SSRStubKey) {
37
+ return true;
38
+ }
39
+ return createProxy(path + '.' + String(p));
40
+ },
41
+ apply() {
42
+ throw new Error(cannotInvokeMethodOnServerError(path));
43
+ },
44
+ });
45
+ };
46
+ const createStytchSSRProxy = () => createProxy('stytch');
47
+
48
+ export { noHeadlessClientError as a, createStytchSSRProxy as c, isStytchSSRProxy as i, noProviderError as n, providerMustBeUniqueError as p };
@@ -0,0 +1,3 @@
1
+ declare const isStytchSSRProxy: (proxy: any) => boolean;
2
+ declare const createStytchSSRProxy: () => any;
3
+ export { isStytchSSRProxy, createStytchSSRProxy };
@@ -0,0 +1,54 @@
1
+ 'use strict';
2
+
3
+ const noProviderError = (item, provider = 'StytchProvider') => `${item} can only be used inside <${provider}>.`;
4
+ const providerMustBeUniqueError = 'You cannot render a <StytchProvider> inside another <StytchProvider>.';
5
+ const noHeadlessClientError = `Tried to create a Stytch Login UI element using the Stytch Headless SDK.
6
+ You must use the UI SDK to use UI elements.
7
+ Please make sure you are using a Stytch UI client, not a Stytch Headless client.`;
8
+ const cannotInvokeMethodOnServerError = (path) => `[Stytch] Invalid serverside function call to ${path}.
9
+ The Stytch Javascript SDK is intended to ony be used on the client side.
10
+ Make sure to wrap your API calls in a hook to ensure they are executed on the client.
11
+ \`\`\`
12
+ const myComponent = () => {
13
+ const stytch = useStytch();
14
+ // This will error out on the server.
15
+ stytch.magicLinks.authenticate(...);
16
+ useEffect(() => {
17
+ // This will work well
18
+ stytch.magicLinks.authenticate(...);
19
+ }, []);
20
+ }
21
+ \`\`\`
22
+
23
+ If you want to make API calls from server environments, please use the Stytch Node Library
24
+ https://www.npmjs.com/package/stytch.
25
+ `;
26
+
27
+ const SSRStubKey = Symbol('__stytch_SSRStubKey');
28
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
29
+ const isStytchSSRProxy = (proxy) => {
30
+ return !!proxy[SSRStubKey];
31
+ };
32
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
33
+ const createProxy = (path) => {
34
+ // eslint-disable-next-line @typescript-eslint/no-empty-function
35
+ const noop = () => { };
36
+ return new Proxy(noop, {
37
+ get(target, p) {
38
+ if (p === SSRStubKey) {
39
+ return true;
40
+ }
41
+ return createProxy(path + '.' + String(p));
42
+ },
43
+ apply() {
44
+ throw new Error(cannotInvokeMethodOnServerError(path));
45
+ },
46
+ });
47
+ };
48
+ const createStytchSSRProxy = () => createProxy('stytch');
49
+
50
+ exports.createStytchSSRProxy = createStytchSSRProxy;
51
+ exports.isStytchSSRProxy = isStytchSSRProxy;
52
+ exports.noHeadlessClientError = noHeadlessClientError;
53
+ exports.noProviderError = noProviderError;
54
+ exports.providerMustBeUniqueError = providerMustBeUniqueError;
@@ -39,6 +39,6 @@ type AdminPortalSCIMProps<TProjectConfiguration extends StytchProjectConfigurati
39
39
  * See the {@link https://stytch.com/docs/b2b/sdks/javascript-sdk online reference}
40
40
  */
41
41
  declare const AdminPortalSCIM: <TProjectConfiguration extends Partial<import("@stytch/core/public").StytchProjectConfiguration> = Stytch.DefaultProjectConfiguration>(props: ExcludeInjectedOptions<AdminPortalSCIMMountOptions<Partial<import("@stytch/core/public").StytchProjectConfiguration>>>) => JSX.Element;
42
- export { AdminPortalSSO, AdminPortalOrgSettings, AdminPortalMemberManagement, AdminPortalSCIM };
43
42
  export { AdminPortalB2BProducts } from "@stytch/vanilla-js/b2b/adminPortal";
43
+ export { AdminPortalMemberManagement, AdminPortalOrgSettings, AdminPortalSCIM, AdminPortalSSO };
44
44
  export type { AdminPortalSSOProps, AdminPortalOrgSettingsProps, AdminPortalMemberManagementProps, AdminPortalSCIMProps };