@stytch/react 14.0.1 → 16.0.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/CHANGELOG.md CHANGED
@@ -1,5 +1,23 @@
1
1
  # @stytch/react
2
2
 
3
+ ## 16.0.0
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies [f604dcb]
8
+ - @stytch/vanilla-js@4.7.0
9
+
10
+ ## 15.0.0
11
+
12
+ ### Minor Changes
13
+
14
+ - 223e30e: Add `useStytchOrganization` hook for B2B
15
+
16
+ ### Patch Changes
17
+
18
+ - Updated dependencies [223e30e]
19
+ - @stytch/vanilla-js@4.2.0
20
+
3
21
  ## 14.0.1
4
22
 
5
23
  ### Patch Changes
@@ -1,7 +1,7 @@
1
1
  /// <reference types="react" />
2
2
  import React from "react";
3
3
  import { ReactNode } from "react";
4
- import { Member, MemberSession, StytchB2BUIClient } from "@stytch/vanilla-js/b2b";
4
+ import { Member, MemberSession, Organization, StytchB2BUIClient } from "@stytch/vanilla-js/b2b";
5
5
  import { StytchB2BHeadlessClient } from "@stytch/vanilla-js/b2b/headless";
6
6
  import { PermissionsMap } from "@stytch/core/public";
7
7
  import { Callbacks, StyleConfig, StytchB2BUIConfig } from "@stytch/vanilla-js";
@@ -29,6 +29,16 @@ type SWRMemberSession = {
29
29
  */
30
30
  fromCache: boolean;
31
31
  };
32
+ type SWROrganization = {
33
+ /**
34
+ * Either the active {@link Organization} object, or null if the user is not logged in.
35
+ */
36
+ organization: Organization | null;
37
+ /**
38
+ * If true, indicates that the value returned is from the application cache and a state refresh is in progress.
39
+ */
40
+ fromCache: boolean;
41
+ };
32
42
  /**
33
43
  * Returns the active Member.
34
44
  * Check the fromCache property to determine if the member data is from persistent storage.
@@ -50,6 +60,14 @@ declare const useStytchMember: () => SWRMember;
50
60
  * @returns A {@link SWRMemberSession}
51
61
  */
52
62
  declare const useStytchMemberSession: () => SWRMemberSession;
63
+ /**
64
+ * Returns the active Stytch organization.
65
+ * @example
66
+ * const { organization } = useStytchOrganization();
67
+ * return organization ? <p>Welcome to {organization.organization_name}</p> : <p>Log in to continue!</p>;
68
+ * @returns A {@link SWROrganization}
69
+ */
70
+ declare const useStytchOrganization: () => SWROrganization;
53
71
  type SWRIsAuthorized = {
54
72
  /**
55
73
  * Whether the logged-in member is allowed to perform the specified action on the specified resource.
@@ -94,6 +112,10 @@ declare const withStytchMemberSession: <T extends object>(Component: React.Compo
94
112
  stytchMemberSession: MemberSession | null;
95
113
  stytchMemberSessionIsFromCache: boolean;
96
114
  }>) => React.ComponentType<T>;
115
+ declare const withStytchOrganization: <T extends object>(Component: React.ComponentType<T & {
116
+ stytchOrganization: Organization | null;
117
+ stytchOrganizationIsFromCache: boolean;
118
+ }>) => React.ComponentType<T>;
97
119
  /**
98
120
  * Wrap your component with this HOC in order to receive the permissions for the logged-in member.
99
121
  * Evaluates all permissions granted to the logged-in member.
@@ -241,5 +263,5 @@ interface StytchB2BProps {
241
263
  * @param props {@link StytchB2BProps}
242
264
  */
243
265
  declare const StytchB2B: ({ styles, callbacks, config }: StytchB2BProps) => React.JSX.Element;
244
- export { StytchB2BProvider, useStytchB2BClient, useStytchMemberSession, useStytchMember, useStytchIsAuthorized, withStytchB2BClient, withStytchMemberSession, withStytchMember, withStytchPermissions, StytchB2B };
266
+ export { StytchB2BProvider, useStytchB2BClient, useStytchMemberSession, useStytchMember, useStytchIsAuthorized, useStytchOrganization, withStytchB2BClient, withStytchMemberSession, withStytchMember, withStytchOrganization, withStytchPermissions, StytchB2B };
245
267
  export type { StytchB2BProviderProps };
@@ -1,7 +1,7 @@
1
1
  /// <reference types="react" />
2
2
  import React from "react";
3
3
  import { ReactNode } from "react";
4
- import { Member, MemberSession, StytchB2BUIClient } from "@stytch/vanilla-js/b2b";
4
+ import { Member, MemberSession, Organization, StytchB2BUIClient } from "@stytch/vanilla-js/b2b";
5
5
  import { StytchB2BHeadlessClient } from "@stytch/vanilla-js/b2b/headless";
6
6
  import { PermissionsMap } from "@stytch/core/public";
7
7
  import { Callbacks, StyleConfig, StytchB2BUIConfig } from "@stytch/vanilla-js";
@@ -29,6 +29,16 @@ type SWRMemberSession = {
29
29
  */
30
30
  fromCache: boolean;
31
31
  };
32
+ type SWROrganization = {
33
+ /**
34
+ * Either the active {@link Organization} object, or null if the user is not logged in.
35
+ */
36
+ organization: Organization | null;
37
+ /**
38
+ * If true, indicates that the value returned is from the application cache and a state refresh is in progress.
39
+ */
40
+ fromCache: boolean;
41
+ };
32
42
  /**
33
43
  * Returns the active Member.
34
44
  * Check the fromCache property to determine if the member data is from persistent storage.
@@ -50,6 +60,14 @@ declare const useStytchMember: () => SWRMember;
50
60
  * @returns A {@link SWRMemberSession}
51
61
  */
52
62
  declare const useStytchMemberSession: () => SWRMemberSession;
63
+ /**
64
+ * Returns the active Stytch organization.
65
+ * @example
66
+ * const { organization } = useStytchOrganization();
67
+ * return organization ? <p>Welcome to {organization.organization_name}</p> : <p>Log in to continue!</p>;
68
+ * @returns A {@link SWROrganization}
69
+ */
70
+ declare const useStytchOrganization: () => SWROrganization;
53
71
  type SWRIsAuthorized = {
54
72
  /**
55
73
  * Whether the logged-in member is allowed to perform the specified action on the specified resource.
@@ -94,6 +112,10 @@ declare const withStytchMemberSession: <T extends object>(Component: React.Compo
94
112
  stytchMemberSession: MemberSession | null;
95
113
  stytchMemberSessionIsFromCache: boolean;
96
114
  }>) => React.ComponentType<T>;
115
+ declare const withStytchOrganization: <T extends object>(Component: React.ComponentType<T & {
116
+ stytchOrganization: Organization | null;
117
+ stytchOrganizationIsFromCache: boolean;
118
+ }>) => React.ComponentType<T>;
97
119
  /**
98
120
  * Wrap your component with this HOC in order to receive the permissions for the logged-in member.
99
121
  * Evaluates all permissions granted to the logged-in member.
@@ -241,5 +263,5 @@ interface StytchB2BProps {
241
263
  * @param props {@link StytchB2BProps}
242
264
  */
243
265
  declare const StytchB2B: ({ styles, callbacks, config }: StytchB2BProps) => React.JSX.Element;
244
- export { StytchB2BProvider, useStytchB2BClient, useStytchMemberSession, useStytchMember, useStytchIsAuthorized, withStytchB2BClient, withStytchMemberSession, withStytchMember, withStytchPermissions, StytchB2B };
266
+ export { StytchB2BProvider, useStytchB2BClient, useStytchMemberSession, useStytchMember, useStytchIsAuthorized, useStytchOrganization, withStytchB2BClient, withStytchMemberSession, withStytchMember, withStytchOrganization, withStytchPermissions, StytchB2B };
245
267
  export type { StytchB2BProviderProps };
@@ -41,9 +41,14 @@ const initialMemberSession = {
41
41
  session: null,
42
42
  fromCache: false,
43
43
  };
44
+ const initialOrganization = {
45
+ organization: null,
46
+ fromCache: false,
47
+ };
44
48
  const StytchB2BContext = createContext({ isMounted: false });
45
49
  const StytchMemberContext = createContext(initialMember);
46
50
  const StytchMemberSessionContext = createContext(initialMemberSession);
51
+ const StytchOrganizationContext = createContext(initialOrganization);
47
52
  const useIsMounted__INTERNAL = () => useContext(StytchB2BContext).isMounted;
48
53
  const isUIClient = (client) => {
49
54
  return client.mount !== undefined;
@@ -75,6 +80,17 @@ const useStytchMemberSession = () => {
75
80
  invariant(useIsMounted__INTERNAL(), noProviderError('useStytchMemberSession', 'StytchB2BProvider'));
76
81
  return useContext(StytchMemberSessionContext);
77
82
  };
83
+ /**
84
+ * Returns the active Stytch organization.
85
+ * @example
86
+ * const { organization } = useStytchOrganization();
87
+ * return organization ? <p>Welcome to {organization.organization_name}</p> : <p>Log in to continue!</p>;
88
+ * @returns A {@link SWROrganization}
89
+ */
90
+ const useStytchOrganization = () => {
91
+ invariant(useIsMounted__INTERNAL(), noProviderError('useStytchOrganization', 'StytchB2BProvider'));
92
+ return useContext(StytchOrganizationContext);
93
+ };
78
94
  /**
79
95
  * Determines whether the logged-in member is allowed to perform the specified action on the specified resource.
80
96
  * Returns `true` if the member can perform the action, `false` otherwise.
@@ -100,7 +116,7 @@ const useStytchIsAuthorized = (resourceId, action) => {
100
116
  fromCache: false,
101
117
  isAuthorized,
102
118
  }));
103
- }, [client, session === null || session === void 0 ? void 0 : session.roles, resourceId, action]);
119
+ }, [client, session === null || session === void 0 ? void 0 : session.roles, resourceId, action, setIsAuthorized]);
104
120
  return isAuthorized;
105
121
  };
106
122
  /**
@@ -143,6 +159,15 @@ const withStytchMemberSession = (Component) => {
143
159
  WithStytchSession.displayName = `withStytchSession(${Component.displayName || Component.name || 'Component'})`;
144
160
  return WithStytchSession;
145
161
  };
162
+ const withStytchOrganization = (Component) => {
163
+ const WithStytchOrganization = (props) => {
164
+ invariant(useIsMounted__INTERNAL(), noProviderError('withStytchOrganization', 'StytchB2BProvider'));
165
+ const { organization, fromCache } = useStytchOrganization();
166
+ return React.createElement(Component, Object.assign({}, props, { stytchOrganization: organization, stytchOrganizationIsFromCache: fromCache }));
167
+ };
168
+ WithStytchOrganization.displayName = `withStytchOrganization(${Component.displayName || Component.name || 'Component'})`;
169
+ return WithStytchOrganization;
170
+ };
146
171
  /**
147
172
  * Wrap your component with this HOC in order to receive the permissions for the logged-in member.
148
173
  * Evaluates all permissions granted to the logged-in member.
@@ -174,7 +199,7 @@ const withStytchPermissions = (Component) => {
174
199
  client.rbac
175
200
  .allPermissions()
176
201
  .then((permissions) => setPermissions({ loaded: true, value: permissions }));
177
- }, [client, session === null || session === void 0 ? void 0 : session.roles]);
202
+ }, [client, session === null || session === void 0 ? void 0 : session.roles, setPermissions]);
178
203
  if (!permissions.loaded) {
179
204
  return null;
180
205
  }
@@ -208,6 +233,10 @@ const StytchB2BProvider = ({ stytch, children }) => {
208
233
  session: stytch.session.getSync(),
209
234
  fromCache: true,
210
235
  });
236
+ const [organization, setOrganization] = useAsyncState({
237
+ organization: stytch.organization.getSync(),
238
+ fromCache: true,
239
+ });
211
240
  useEffect(() => {
212
241
  const unsubscribeMember = stytch.self.onChange((member) => setMember({
213
242
  member,
@@ -217,17 +246,25 @@ const StytchB2BProvider = ({ stytch, children }) => {
217
246
  session,
218
247
  fromCache: false,
219
248
  }));
249
+ const unsubscribeOrganization = stytch.organization.onChange((organization) => setOrganization({
250
+ organization,
251
+ fromCache: false,
252
+ }));
220
253
  return () => {
221
254
  unsubscribeMember();
222
255
  unsubscribeSession();
256
+ unsubscribeOrganization();
223
257
  };
224
- }, [stytch, setMember, setMemberSession]);
258
+ }, [stytch, setMember, setMemberSession, setOrganization]);
225
259
  // TODO (SDK-813): Remove this when we have a single top-level onChange handler
226
- const finalMemberSession = !!session.session === !!member.member ? session : initialMemberSession;
227
- const finalMember = !!session.session === !!member.member ? member : initialMember;
260
+ const allValuesReady = !!member.member === !!session.session && !!session.session === !!organization.organization;
261
+ const finalValues = allValuesReady
262
+ ? { member, session, organization }
263
+ : { member: initialMember, session: initialMemberSession, organization: initialOrganization };
228
264
  return (React.createElement(StytchB2BContext.Provider, { value: ctx },
229
- React.createElement(StytchMemberContext.Provider, { value: finalMember },
230
- React.createElement(StytchMemberSessionContext.Provider, { value: finalMemberSession }, children))));
265
+ React.createElement(StytchOrganizationContext.Provider, { value: finalValues.organization },
266
+ React.createElement(StytchMemberContext.Provider, { value: finalValues.member },
267
+ React.createElement(StytchMemberSessionContext.Provider, { value: finalValues.session }, children)))));
231
268
  };
232
269
 
233
270
  /**
@@ -285,8 +322,9 @@ const StytchB2B = ({ styles, callbacks, config }) => {
285
322
  elementId: `#${containerEl.current.id}`,
286
323
  styles,
287
324
  });
325
+ // eslint-disable-next-line react-hooks/exhaustive-deps -- SDK-1354
288
326
  }, [stytchClient, styles, callbacks]);
289
327
  return React.createElement("div", { ref: containerEl });
290
328
  };
291
329
 
292
- export { StytchB2B, StytchB2BProvider, useStytchB2BClient, useStytchIsAuthorized, useStytchMember, useStytchMemberSession, withStytchB2BClient, withStytchMember, withStytchMemberSession, withStytchPermissions };
330
+ export { StytchB2B, StytchB2BProvider, useStytchB2BClient, useStytchIsAuthorized, useStytchMember, useStytchMemberSession, useStytchOrganization, withStytchB2BClient, withStytchMember, withStytchMemberSession, withStytchOrganization, withStytchPermissions };
package/dist/b2b/index.js CHANGED
@@ -49,9 +49,14 @@ const initialMemberSession = {
49
49
  session: null,
50
50
  fromCache: false,
51
51
  };
52
+ const initialOrganization = {
53
+ organization: null,
54
+ fromCache: false,
55
+ };
52
56
  const StytchB2BContext = React.createContext({ isMounted: false });
53
57
  const StytchMemberContext = React.createContext(initialMember);
54
58
  const StytchMemberSessionContext = React.createContext(initialMemberSession);
59
+ const StytchOrganizationContext = React.createContext(initialOrganization);
55
60
  const useIsMounted__INTERNAL = () => React.useContext(StytchB2BContext).isMounted;
56
61
  const isUIClient = (client) => {
57
62
  return client.mount !== undefined;
@@ -83,6 +88,17 @@ const useStytchMemberSession = () => {
83
88
  invariant(useIsMounted__INTERNAL(), noProviderError('useStytchMemberSession', 'StytchB2BProvider'));
84
89
  return React.useContext(StytchMemberSessionContext);
85
90
  };
91
+ /**
92
+ * Returns the active Stytch organization.
93
+ * @example
94
+ * const { organization } = useStytchOrganization();
95
+ * return organization ? <p>Welcome to {organization.organization_name}</p> : <p>Log in to continue!</p>;
96
+ * @returns A {@link SWROrganization}
97
+ */
98
+ const useStytchOrganization = () => {
99
+ invariant(useIsMounted__INTERNAL(), noProviderError('useStytchOrganization', 'StytchB2BProvider'));
100
+ return React.useContext(StytchOrganizationContext);
101
+ };
86
102
  /**
87
103
  * Determines whether the logged-in member is allowed to perform the specified action on the specified resource.
88
104
  * Returns `true` if the member can perform the action, `false` otherwise.
@@ -108,7 +124,7 @@ const useStytchIsAuthorized = (resourceId, action) => {
108
124
  fromCache: false,
109
125
  isAuthorized,
110
126
  }));
111
- }, [client, session === null || session === void 0 ? void 0 : session.roles, resourceId, action]);
127
+ }, [client, session === null || session === void 0 ? void 0 : session.roles, resourceId, action, setIsAuthorized]);
112
128
  return isAuthorized;
113
129
  };
114
130
  /**
@@ -151,6 +167,15 @@ const withStytchMemberSession = (Component) => {
151
167
  WithStytchSession.displayName = `withStytchSession(${Component.displayName || Component.name || 'Component'})`;
152
168
  return WithStytchSession;
153
169
  };
170
+ const withStytchOrganization = (Component) => {
171
+ const WithStytchOrganization = (props) => {
172
+ invariant(useIsMounted__INTERNAL(), noProviderError('withStytchOrganization', 'StytchB2BProvider'));
173
+ const { organization, fromCache } = useStytchOrganization();
174
+ return React__default['default'].createElement(Component, Object.assign({}, props, { stytchOrganization: organization, stytchOrganizationIsFromCache: fromCache }));
175
+ };
176
+ WithStytchOrganization.displayName = `withStytchOrganization(${Component.displayName || Component.name || 'Component'})`;
177
+ return WithStytchOrganization;
178
+ };
154
179
  /**
155
180
  * Wrap your component with this HOC in order to receive the permissions for the logged-in member.
156
181
  * Evaluates all permissions granted to the logged-in member.
@@ -182,7 +207,7 @@ const withStytchPermissions = (Component) => {
182
207
  client.rbac
183
208
  .allPermissions()
184
209
  .then((permissions) => setPermissions({ loaded: true, value: permissions }));
185
- }, [client, session === null || session === void 0 ? void 0 : session.roles]);
210
+ }, [client, session === null || session === void 0 ? void 0 : session.roles, setPermissions]);
186
211
  if (!permissions.loaded) {
187
212
  return null;
188
213
  }
@@ -216,6 +241,10 @@ const StytchB2BProvider = ({ stytch, children }) => {
216
241
  session: stytch.session.getSync(),
217
242
  fromCache: true,
218
243
  });
244
+ const [organization, setOrganization] = useAsyncState({
245
+ organization: stytch.organization.getSync(),
246
+ fromCache: true,
247
+ });
219
248
  React.useEffect(() => {
220
249
  const unsubscribeMember = stytch.self.onChange((member) => setMember({
221
250
  member,
@@ -225,17 +254,25 @@ const StytchB2BProvider = ({ stytch, children }) => {
225
254
  session,
226
255
  fromCache: false,
227
256
  }));
257
+ const unsubscribeOrganization = stytch.organization.onChange((organization) => setOrganization({
258
+ organization,
259
+ fromCache: false,
260
+ }));
228
261
  return () => {
229
262
  unsubscribeMember();
230
263
  unsubscribeSession();
264
+ unsubscribeOrganization();
231
265
  };
232
- }, [stytch, setMember, setMemberSession]);
266
+ }, [stytch, setMember, setMemberSession, setOrganization]);
233
267
  // TODO (SDK-813): Remove this when we have a single top-level onChange handler
234
- const finalMemberSession = !!session.session === !!member.member ? session : initialMemberSession;
235
- const finalMember = !!session.session === !!member.member ? member : initialMember;
268
+ const allValuesReady = !!member.member === !!session.session && !!session.session === !!organization.organization;
269
+ const finalValues = allValuesReady
270
+ ? { member, session, organization }
271
+ : { member: initialMember, session: initialMemberSession, organization: initialOrganization };
236
272
  return (React__default['default'].createElement(StytchB2BContext.Provider, { value: ctx },
237
- React__default['default'].createElement(StytchMemberContext.Provider, { value: finalMember },
238
- React__default['default'].createElement(StytchMemberSessionContext.Provider, { value: finalMemberSession }, children))));
273
+ React__default['default'].createElement(StytchOrganizationContext.Provider, { value: finalValues.organization },
274
+ React__default['default'].createElement(StytchMemberContext.Provider, { value: finalValues.member },
275
+ React__default['default'].createElement(StytchMemberSessionContext.Provider, { value: finalValues.session }, children)))));
239
276
  };
240
277
 
241
278
  /**
@@ -293,6 +330,7 @@ const StytchB2B = ({ styles, callbacks, config }) => {
293
330
  elementId: `#${containerEl.current.id}`,
294
331
  styles,
295
332
  });
333
+ // eslint-disable-next-line react-hooks/exhaustive-deps -- SDK-1354
296
334
  }, [stytchClient, styles, callbacks]);
297
335
  return React__default['default'].createElement("div", { ref: containerEl });
298
336
  };
@@ -303,7 +341,9 @@ exports.useStytchB2BClient = useStytchB2BClient;
303
341
  exports.useStytchIsAuthorized = useStytchIsAuthorized;
304
342
  exports.useStytchMember = useStytchMember;
305
343
  exports.useStytchMemberSession = useStytchMemberSession;
344
+ exports.useStytchOrganization = useStytchOrganization;
306
345
  exports.withStytchB2BClient = withStytchB2BClient;
307
346
  exports.withStytchMember = withStytchMember;
308
347
  exports.withStytchMemberSession = withStytchMemberSession;
348
+ exports.withStytchOrganization = withStytchOrganization;
309
349
  exports.withStytchPermissions = withStytchPermissions;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stytch/react",
3
- "version": "14.0.1",
3
+ "version": "16.0.0",
4
4
  "description": "Stytch's official React Library",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.esm.js",
@@ -33,15 +33,17 @@
33
33
  ],
34
34
  "devDependencies": {
35
35
  "@babel/runtime": "7.18.6",
36
- "@stytch/vanilla-js": "4.1.1",
36
+ "@stytch/vanilla-js": "4.7.0",
37
37
  "@testing-library/react": "14.0.0",
38
38
  "eslint-config-custom": "0.0.1",
39
+ "react": "18.2.0",
40
+ "react-dom": "18.2.0",
39
41
  "react-test-renderer": "18.0.0",
40
42
  "rollup": "2.56.3",
41
- "typescript": "4.7.4"
43
+ "typescript": "5.3.3"
42
44
  },
43
45
  "peerDependencies": {
44
- "@stytch/vanilla-js": "^4.1.1",
46
+ "@stytch/vanilla-js": "^4.7.0",
45
47
  "react": ">= 17.0.2",
46
48
  "react-dom": ">= 17.0.2"
47
49
  }