@quiltt/react 4.2.3 → 4.3.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 (31) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/dist/{QuilttAuthProvider-client-C25Tg4_a.js → QuilttAuthProvider-12s-BZuGySu0.js} +27 -25
  3. package/dist/{QuilttSettingsProvider-client-Va7uJ_dQ.js → QuilttSettingsProvider-12s-ZcmFmOiZ.js} +1 -1
  4. package/dist/index.d.ts +69 -72
  5. package/dist/index.js +23 -22
  6. package/dist/{useEventListener-client-DVM5xwKY.js → useEventListener-12s-D_-6QIXa.js} +1 -1
  7. package/dist/{useQuilttConnector-client-aEGkRKpA.js → useQuilttConnector-12s-CL6uHdqe.js} +53 -55
  8. package/dist/{useQuilttInstitutions-client-Dtapf_wl.js → useQuilttInstitutions-12s-FLdw-CQZ.js} +3 -3
  9. package/dist/{useQuilttSession-client-DhsbThvI.js → useQuilttSession-12s-CM6ALGSN.js} +3 -3
  10. package/dist/{useQuilttSettings-client-BOCBjFXe.js → useQuilttSettings-12s--rCJoNHD.js} +1 -1
  11. package/dist/{useSession-client-CCAvnROP.js → useSession-12s-7GOn4sUn.js} +1 -1
  12. package/package.json +9 -9
  13. package/src/components/QuilttButton.tsx +1 -1
  14. package/src/components/QuilttContainer.tsx +1 -1
  15. package/src/hooks/helpers/useEventListener.ts +6 -4
  16. package/src/hooks/session/index.ts +1 -1
  17. package/src/hooks/session/useImportSession.ts +1 -2
  18. package/src/hooks/useQuilttConnector.ts +73 -54
  19. package/src/hooks/useQuilttInstitutions.ts +2 -3
  20. package/src/hooks/useQuilttSession.ts +2 -2
  21. package/src/hooks/useSession.ts +1 -1
  22. package/src/index.ts +2 -1
  23. package/src/providers/QuilttAuthProvider.tsx +17 -10
  24. package/src/providers/QuilttProvider.tsx +13 -9
  25. package/src/providers/QuilttSettingsProvider.tsx +2 -2
  26. package/src/utils/isDeepEqual.ts +1 -4
  27. /package/dist/{QuilttSettings-client-BK-0SQME.js → QuilttSettings-12s-BK-0SQME.js} +0 -0
  28. /package/dist/{useIsomorphicLayoutEffect-client-DeTHOKz1.js → useIsomorphicLayoutEffect-12s-DeTHOKz1.js} +0 -0
  29. /package/dist/{useQuilttClient-client-CAAUait1.js → useQuilttClient-12s-CAAUait1.js} +0 -0
  30. /package/dist/{useScript-client-JCgaTW9n.js → useScript-12s-JCgaTW9n.js} +0 -0
  31. /package/dist/{useStorage-client-DHcq3Kuh.js → useStorage-12s-DHcq3Kuh.js} +0 -0
package/CHANGELOG.md CHANGED
@@ -1,5 +1,25 @@
1
1
  # @quiltt/react
2
2
 
3
+ ## 4.3.1
4
+
5
+ ### Patch Changes
6
+
7
+ - [#366](https://github.com/quiltt/quiltt-js/pull/366) [`dc376b5`](https://github.com/quiltt/quiltt-js/commit/dc376b52dd824d7867ca74677bbfd5c54eff5cdc) Thanks [@sirwolfgang](https://github.com/sirwolfgang)! - Warn if useQuilttConnector is unmounted while in use
8
+
9
+ - Updated dependencies [[`dc376b5`](https://github.com/quiltt/quiltt-js/commit/dc376b52dd824d7867ca74677bbfd5c54eff5cdc)]:
10
+ - @quiltt/core@4.3.1
11
+
12
+ ## 4.3.0
13
+
14
+ ### Minor Changes
15
+
16
+ - [#363](https://github.com/quiltt/quiltt-js/pull/363) [`641d766`](https://github.com/quiltt/quiltt-js/commit/641d76620ffbb99bc80fdc9998ac936883fe1d06) Thanks [@zubairaziz](https://github.com/zubairaziz)! - Upgrade rails/actioncable to v8
17
+
18
+ ### Patch Changes
19
+
20
+ - Updated dependencies [[`641d766`](https://github.com/quiltt/quiltt-js/commit/641d76620ffbb99bc80fdc9998ac936883fe1d06)]:
21
+ - @quiltt/core@4.3.0
22
+
3
23
  ## 4.2.3
4
24
 
5
25
  ### Patch Changes
@@ -2,59 +2,59 @@
2
2
  import { useCallback, useRef, useMemo, useEffect } from 'react';
3
3
  import { JsonWebTokenParse, QuilttClient, InMemoryCache } from '@quiltt/core';
4
4
  import '@apollo/client/react/hooks/useApolloClient.js';
5
- import './QuilttSettings-client-BK-0SQME.js';
6
- import './useSession-client-CCAvnROP.js';
5
+ import './QuilttSettings-12s-BK-0SQME.js';
6
+ import './useSession-12s-7GOn4sUn.js';
7
7
  import 'use-debounce';
8
8
  import { jsx } from 'react/jsx-runtime';
9
9
  import { ApolloProvider } from '@apollo/client/react/context/ApolloProvider.js';
10
- import { u as useQuilttSession } from './useQuilttSession-client-DhsbThvI.js';
10
+ import { u as useQuilttSession } from './useQuilttSession-12s-CM6ALGSN.js';
11
11
 
12
- const useIdentifySession = (auth, setSession)=>{
13
- const identifySession = useCallback(async (payload, callbacks)=>{
14
- const response = await auth.identify(payload);
12
+ const useAuthenticateSession = (auth, setSession)=>{
13
+ const authenticateSession = useCallback(async (payload, callbacks)=>{
14
+ const response = await auth.authenticate(payload);
15
15
  switch(response.status){
16
16
  case 201:
17
17
  setSession(response.data.token);
18
18
  if (callbacks.onSuccess) return callbacks.onSuccess();
19
19
  break;
20
- case 202:
21
- if (callbacks.onChallenged) return callbacks.onChallenged();
20
+ case 401:
21
+ if (callbacks.onFailure) return callbacks.onFailure();
22
22
  break;
23
23
  case 422:
24
24
  if (callbacks.onError) return callbacks.onError(response.data);
25
25
  break;
26
26
  default:
27
- throw new Error(`AuthAPI.identify: Unexpected response status ${response.status}`);
27
+ throw new Error(`AuthAPI.authenticate: Unexpected response status ${response.status}`);
28
28
  }
29
29
  }, [
30
30
  auth,
31
31
  setSession
32
32
  ]);
33
- return identifySession;
33
+ return authenticateSession;
34
34
  };
35
35
 
36
- const useAuthenticateSession = (auth, setSession)=>{
37
- const authenticateSession = useCallback(async (payload, callbacks)=>{
38
- const response = await auth.authenticate(payload);
36
+ const useIdentifySession = (auth, setSession)=>{
37
+ const identifySession = useCallback(async (payload, callbacks)=>{
38
+ const response = await auth.identify(payload);
39
39
  switch(response.status){
40
40
  case 201:
41
41
  setSession(response.data.token);
42
42
  if (callbacks.onSuccess) return callbacks.onSuccess();
43
43
  break;
44
- case 401:
45
- if (callbacks.onFailure) return callbacks.onFailure();
44
+ case 202:
45
+ if (callbacks.onChallenged) return callbacks.onChallenged();
46
46
  break;
47
47
  case 422:
48
48
  if (callbacks.onError) return callbacks.onError(response.data);
49
49
  break;
50
50
  default:
51
- throw new Error(`AuthAPI.authenticate: Unexpected response status ${response.status}`);
51
+ throw new Error(`AuthAPI.identify: Unexpected response status ${response.status}`);
52
52
  }
53
53
  }, [
54
54
  auth,
55
55
  setSession
56
56
  ]);
57
- return authenticateSession;
57
+ return identifySession;
58
58
  };
59
59
 
60
60
  /**
@@ -149,7 +149,7 @@ const useRevokeSession = (auth, session, setSession)=>{
149
149
  const keys2 = Object.keys(obj2);
150
150
  if (keys1.length !== keys2.length) return false;
151
151
  return keys1.every((key)=>{
152
- return Object.prototype.hasOwnProperty.call(obj2, key) && isDeepEqual(obj1[key], obj2[key]);
152
+ return Object.hasOwn(obj2, key) && isDeepEqual(obj1[key], obj2[key]);
153
153
  });
154
154
  };
155
155
 
@@ -158,13 +158,15 @@ const useRevokeSession = (auth, session, setSession)=>{
158
158
  * it into trusted storage. While this process is happening, the component is put
159
159
  * into a loading state and the children are not rendered to prevent race conditions
160
160
  * from triggering within the transitionary state.
161
- */ const QuilttAuthProvider = ({ token, children })=>{
161
+ */ const QuilttAuthProvider = ({ graphqlClient, token, children })=>{
162
162
  const { session, importSession } = useQuilttSession();
163
163
  const previousSessionRef = useRef(session);
164
- // @todo: extract into a provider so it can accessed by child components
165
- const graphQLClient = useMemo(()=>new QuilttClient({
164
+ // Memoize the client to avoid unnecessary re-renders
165
+ const apolloClient = useMemo(()=>graphqlClient || new QuilttClient({
166
166
  cache: new InMemoryCache()
167
- }), []);
167
+ }), [
168
+ graphqlClient
169
+ ]);
168
170
  // Import passed in token
169
171
  useEffect(()=>{
170
172
  if (token) importSession(token);
@@ -175,15 +177,15 @@ const useRevokeSession = (auth, session, setSession)=>{
175
177
  // Reset Client Store when session changes (using deep comparison)
176
178
  useEffect(()=>{
177
179
  if (!isDeepEqual(session, previousSessionRef.current)) {
178
- graphQLClient.resetStore();
180
+ apolloClient.resetStore();
179
181
  previousSessionRef.current = session;
180
182
  }
181
183
  }, [
182
184
  session,
183
- graphQLClient
185
+ apolloClient
184
186
  ]);
185
187
  return /*#__PURE__*/ jsx(ApolloProvider, {
186
- client: graphQLClient,
188
+ client: apolloClient,
187
189
  children: children
188
190
  });
189
191
  };
@@ -1,7 +1,7 @@
1
1
  'use client';
2
2
  import { jsx } from 'react/jsx-runtime';
3
3
  import { useState } from 'react';
4
- import { Q as QuilttSettings } from './QuilttSettings-client-BK-0SQME.js';
4
+ import { Q as QuilttSettings } from './QuilttSettings-12s-BK-0SQME.js';
5
5
 
6
6
  const QuilttSettingsProvider = ({ clientId, children })=>{
7
7
  const [_clientId] = useState(clientId);
package/dist/index.d.ts CHANGED
@@ -1,8 +1,58 @@
1
- import { Maybe, QuilttJWT, UsernamePayload, UnprocessableData, AuthAPI, PasscodePayload, ConnectorSDKConnectorOptions, InstitutionsData, ConnectorSDKCallbacks } from '@quiltt/core';
1
+ import { ConnectorSDKCallbacks, Maybe, QuilttJWT, PasscodePayload, UnprocessableData, AuthAPI, UsernamePayload, ConnectorSDKConnectorOptions, InstitutionsData, QuilttClient } from '@quiltt/core';
2
2
  export * from '@quiltt/core';
3
- import { RefObject, useEffect, Dispatch, SetStateAction, FC, PropsWithChildren, JSX, ComponentType, ElementType, MouseEvent } from 'react';
4
- import { useApolloClient } from '@apollo/client/react/hooks/useApolloClient.js';
5
3
  import * as react_jsx_runtime from 'react/jsx-runtime';
4
+ import { JSX, ComponentType, ElementType, PropsWithChildren, MouseEvent, RefObject, useEffect, Dispatch, SetStateAction, FC } from 'react';
5
+ import { useApolloClient } from '@apollo/client/react/hooks/useApolloClient.js';
6
+
7
+ type PropsOf<Tag> = Tag extends keyof JSX.IntrinsicElements ? JSX.IntrinsicElements[Tag] : Tag extends ComponentType<infer Props> ? Props & JSX.IntrinsicAttributes : never;
8
+
9
+ type BaseQuilttButtonProps<T extends ElementType> = {
10
+ as?: T;
11
+ connectorId: string;
12
+ connectionId?: string;
13
+ institution?: string;
14
+ /**
15
+ * Forces complete remount when connectionId changes.
16
+ * Useful as a fallback for ensuring clean state.
17
+ * @default false
18
+ */
19
+ forceRemountOnConnectionChange?: boolean;
20
+ onClick?: (event: MouseEvent<HTMLElement>) => void;
21
+ };
22
+ type QuilttCallbackProps = Omit<ConnectorSDKCallbacks, 'onLoad'> & {
23
+ onLoad?: ConnectorSDKCallbacks['onLoad'];
24
+ onHtmlLoad?: React.ReactEventHandler<HTMLElement>;
25
+ };
26
+ type QuilttButtonProps<T extends ElementType> = PropsWithChildren<BaseQuilttButtonProps<T> & QuilttCallbackProps>;
27
+ /**
28
+ * QuilttButton provides a clickable interface to open Quiltt connectors.
29
+ *
30
+ * When connectionId changes, the button will automatically update the existing
31
+ * connector instance with the new connection details. If you need to force a
32
+ * complete remount instead, set forceRemountOnConnectionChange to true.
33
+ */
34
+ declare const QuilttButton: <T extends ElementType = "button">({ as, connectorId, connectionId, institution, forceRemountOnConnectionChange, onEvent, onOpen, onLoad, onExit, onExitSuccess, onExitAbort, onExitError, onClick, onHtmlLoad, children, ...props }: QuilttButtonProps<T> & PropsOf<T>) => react_jsx_runtime.JSX.Element;
35
+
36
+ type QuilttContainerProps<T extends ElementType> = PropsWithChildren<{
37
+ as?: T;
38
+ connectorId: string;
39
+ connectionId?: string;
40
+ /**
41
+ * Forces complete remount when connectionId changes.
42
+ * Useful as a fallback for ensuring clean state.
43
+ * @default false
44
+ */
45
+ forceRemountOnConnectionChange?: boolean;
46
+ } & ConnectorSDKCallbacks>;
47
+ /**
48
+ * QuilttContainer uses globally shared callbacks. It's recommended you only use
49
+ * one Container at a time.
50
+ *
51
+ * When connectionId changes, the container will automatically update the existing
52
+ * connector instance with the new connection details. If you need to force a
53
+ * complete remount instead, set forceRemountOnConnectionChange to true.
54
+ */
55
+ declare const QuilttContainer: <T extends ElementType = "div">({ as, connectorId, connectionId, forceRemountOnConnectionChange, onEvent, onLoad, onExit, onExitSuccess, onExitAbort, onExitError, children, ...props }: QuilttContainerProps<T> & PropsOf<T>) => react_jsx_runtime.JSX.Element;
6
56
 
7
57
  declare function useEventListener<K extends keyof MediaQueryListEventMap>(eventName: K, handler: (event: MediaQueryListEventMap[K]) => void, element: RefObject<MediaQueryList>, options?: boolean | AddEventListenerOptions): void;
8
58
  declare function useEventListener<K extends keyof WindowEventMap>(eventName: K, handler: (event: WindowEventMap[K]) => void, element?: undefined, options?: boolean | AddEventListenerOptions): void;
@@ -31,15 +81,6 @@ type SetSession = Dispatch<SetStateAction<Maybe<string> | undefined>>;
31
81
  */
32
82
  declare const useSession: (storageKey?: string) => [Maybe<QuilttJWT> | undefined, SetSession];
33
83
 
34
- type IdentifySessionCallbacks = {
35
- onSuccess?: () => unknown;
36
- onChallenged?: () => unknown;
37
- onError?: (errors: UnprocessableData) => unknown;
38
- };
39
- type IdentifySession = (payload: UsernamePayload, callbacks: IdentifySessionCallbacks) => Promise<unknown>;
40
- type UseIdentifySession = (auth: AuthAPI, setSession: SetSession) => IdentifySession;
41
- declare const useIdentifySession: UseIdentifySession;
42
-
43
84
  type AuthenticateSessionCallbacks = {
44
85
  onSuccess?: () => unknown;
45
86
  onFailure?: () => unknown;
@@ -49,6 +90,15 @@ type AuthenticateSession = (payload: PasscodePayload, callbacks: AuthenticateSes
49
90
  type UseAuthenticateSession = (auth: AuthAPI, setSession: SetSession) => AuthenticateSession;
50
91
  declare const useAuthenticateSession: UseAuthenticateSession;
51
92
 
93
+ type IdentifySessionCallbacks = {
94
+ onSuccess?: () => unknown;
95
+ onChallenged?: () => unknown;
96
+ onError?: (errors: UnprocessableData) => unknown;
97
+ };
98
+ type IdentifySession = (payload: UsernamePayload, callbacks: IdentifySessionCallbacks) => Promise<unknown>;
99
+ type UseIdentifySession = (auth: AuthAPI, setSession: SetSession) => IdentifySession;
100
+ declare const useIdentifySession: UseIdentifySession;
101
+
52
102
  type ImportSession = (token: string) => Promise<boolean>;
53
103
  type UseImportSession = (auth: AuthAPI, session: Maybe<QuilttJWT> | undefined, setSession: SetSession, environmentId?: string) => ImportSession;
54
104
  /**
@@ -109,7 +159,9 @@ declare const useQuilttSettings: () => {
109
159
  declare const useStorage: <T>(key: string, initialState?: Maybe<T>) => [Maybe<T> | undefined, Dispatch<SetStateAction<Maybe<T> | undefined>>];
110
160
 
111
161
  type QuilttAuthProviderProps = PropsWithChildren & {
112
- /** The Session token obtained from the server */
162
+ /** A custom QuilttClient instance to use instead of the default */
163
+ graphqlClient?: QuilttClient;
164
+ /** The Quiltt Session token obtained from the server */
113
165
  token?: string;
114
166
  };
115
167
  /**
@@ -120,69 +172,14 @@ type QuilttAuthProviderProps = PropsWithChildren & {
120
172
  */
121
173
  declare const QuilttAuthProvider: FC<QuilttAuthProviderProps>;
122
174
 
123
- type QuilttProviderProps = PropsWithChildren & {
124
- /** The client ID for the client-side Auth API */
125
- clientId?: string;
126
- /** The Session token obtained from the server */
127
- token?: string;
128
- };
129
- declare const QuilttProvider: FC<QuilttProviderProps>;
130
-
131
175
  type QuilttSettingsProviderProps = PropsWithChildren & {
132
- /** The Client ID to use for the client-side Auth API */
176
+ /** The Client ID to use for the passwordless Auth API */
133
177
  clientId?: string;
134
178
  };
135
179
  declare const QuilttSettingsProvider: FC<QuilttSettingsProviderProps>;
136
180
 
137
- type PropsOf<Tag> = Tag extends keyof JSX.IntrinsicElements ? JSX.IntrinsicElements[Tag] : Tag extends ComponentType<infer Props> ? Props & JSX.IntrinsicAttributes : never;
138
-
139
- type BaseQuilttButtonProps<T extends ElementType> = {
140
- as?: T;
141
- connectorId: string;
142
- connectionId?: string;
143
- institution?: string;
144
- /**
145
- * Forces complete remount when connectionId changes.
146
- * Useful as a fallback for ensuring clean state.
147
- * @default false
148
- */
149
- forceRemountOnConnectionChange?: boolean;
150
- onClick?: (event: MouseEvent<HTMLElement>) => void;
151
- };
152
- type QuilttCallbackProps = Omit<ConnectorSDKCallbacks, 'onLoad'> & {
153
- onLoad?: ConnectorSDKCallbacks['onLoad'];
154
- onHtmlLoad?: React.ReactEventHandler<HTMLElement>;
155
- };
156
- type QuilttButtonProps<T extends ElementType> = PropsWithChildren<BaseQuilttButtonProps<T> & QuilttCallbackProps>;
157
- /**
158
- * QuilttButton provides a clickable interface to open Quiltt connectors.
159
- *
160
- * When connectionId changes, the button will automatically update the existing
161
- * connector instance with the new connection details. If you need to force a
162
- * complete remount instead, set forceRemountOnConnectionChange to true.
163
- */
164
- declare const QuilttButton: <T extends ElementType = "button">({ as, connectorId, connectionId, institution, forceRemountOnConnectionChange, onEvent, onOpen, onLoad, onExit, onExitSuccess, onExitAbort, onExitError, onClick, onHtmlLoad, children, ...props }: QuilttButtonProps<T> & PropsOf<T>) => react_jsx_runtime.JSX.Element;
165
-
166
- type QuilttContainerProps<T extends ElementType> = PropsWithChildren<{
167
- as?: T;
168
- connectorId: string;
169
- connectionId?: string;
170
- /**
171
- * Forces complete remount when connectionId changes.
172
- * Useful as a fallback for ensuring clean state.
173
- * @default false
174
- */
175
- forceRemountOnConnectionChange?: boolean;
176
- } & ConnectorSDKCallbacks>;
177
- /**
178
- * QuilttContainer uses globally shared callbacks. It's recommended you only use
179
- * one Container at a time.
180
- *
181
- * When connectionId changes, the container will automatically update the existing
182
- * connector instance with the new connection details. If you need to force a
183
- * complete remount instead, set forceRemountOnConnectionChange to true.
184
- */
185
- declare const QuilttContainer: <T extends ElementType = "div">({ as, connectorId, connectionId, forceRemountOnConnectionChange, onEvent, onLoad, onExit, onExitSuccess, onExitAbort, onExitError, children, ...props }: QuilttContainerProps<T> & PropsOf<T>) => react_jsx_runtime.JSX.Element;
181
+ type QuilttProviderProps = QuilttSettingsProviderProps & QuilttAuthProviderProps;
182
+ declare const QuilttProvider: FC<QuilttProviderProps>;
186
183
 
187
184
  export { QuilttAuthProvider, QuilttButton, QuilttContainer, QuilttProvider, QuilttSettingsProvider, useAuthenticateSession, useEventListener, useIdentifySession, useImportSession, useIsomorphicLayoutEffect, useQuilttClient, useQuilttConnector, useQuilttInstitutions, useQuilttSession, useQuilttSettings, useRevokeSession, useSession, useStorage };
188
- export type { AuthenticateSession, IdentifySession, ImportSession, RevokeSession, SetSession, UseQuilttInstitutions, UseQuilttSession };
185
+ export type { AuthenticateSession, IdentifySession, ImportSession, QuilttAuthProviderProps, QuilttSettingsProviderProps, RevokeSession, SetSession, UseQuilttInstitutions, UseQuilttSession };
package/dist/index.js CHANGED
@@ -1,28 +1,18 @@
1
1
  export * from '@quiltt/core';
2
- export { u as useEventListener } from './useEventListener-client-DVM5xwKY.js';
3
- export { u as useIsomorphicLayoutEffect } from './useIsomorphicLayoutEffect-client-DeTHOKz1.js';
4
- import { Q as QuilttAuthProvider, i as isDeepEqual } from './QuilttAuthProvider-client-C25Tg4_a.js';
5
- export { b as useAuthenticateSession, a as useIdentifySession, u as useImportSession, c as useRevokeSession } from './QuilttAuthProvider-client-C25Tg4_a.js';
6
- export { u as useQuilttClient } from './useQuilttClient-client-CAAUait1.js';
7
- import { u as useQuilttConnector } from './useQuilttConnector-client-aEGkRKpA.js';
8
- export { u as useQuilttInstitutions } from './useQuilttInstitutions-client-Dtapf_wl.js';
9
- export { u as useQuilttSession } from './useQuilttSession-client-DhsbThvI.js';
10
- export { u as useQuilttSettings } from './useQuilttSettings-client-BOCBjFXe.js';
11
- export { u as useSession } from './useSession-client-CCAvnROP.js';
12
- export { u as useStorage } from './useStorage-client-DHcq3Kuh.js';
13
2
  import { jsx } from 'react/jsx-runtime';
14
- import { Q as QuilttSettingsProvider } from './QuilttSettingsProvider-client-Va7uJ_dQ.js';
15
3
  import { useRef, useEffect } from 'react';
16
-
17
- const QuilttProvider = ({ clientId, token, children })=>{
18
- return /*#__PURE__*/ jsx(QuilttSettingsProvider, {
19
- clientId: clientId,
20
- children: /*#__PURE__*/ jsx(QuilttAuthProvider, {
21
- token: token,
22
- children: children
23
- })
24
- });
25
- };
4
+ import { u as useQuilttConnector } from './useQuilttConnector-12s-CL6uHdqe.js';
5
+ import { i as isDeepEqual, Q as QuilttAuthProvider } from './QuilttAuthProvider-12s-BZuGySu0.js';
6
+ export { b as useAuthenticateSession, a as useIdentifySession, u as useImportSession, c as useRevokeSession } from './QuilttAuthProvider-12s-BZuGySu0.js';
7
+ export { u as useEventListener } from './useEventListener-12s-D_-6QIXa.js';
8
+ export { u as useIsomorphicLayoutEffect } from './useIsomorphicLayoutEffect-12s-DeTHOKz1.js';
9
+ export { u as useQuilttClient } from './useQuilttClient-12s-CAAUait1.js';
10
+ export { u as useQuilttInstitutions } from './useQuilttInstitutions-12s-FLdw-CQZ.js';
11
+ export { u as useQuilttSession } from './useQuilttSession-12s-CM6ALGSN.js';
12
+ export { u as useQuilttSettings } from './useQuilttSettings-12s--rCJoNHD.js';
13
+ export { u as useSession } from './useSession-12s-7GOn4sUn.js';
14
+ export { u as useStorage } from './useStorage-12s-DHcq3Kuh.js';
15
+ import { Q as QuilttSettingsProvider } from './QuilttSettingsProvider-12s-ZcmFmOiZ.js';
26
16
 
27
17
  /**
28
18
  * QuilttButton provides a clickable interface to open Quiltt connectors.
@@ -169,4 +159,15 @@ const QuilttProvider = ({ clientId, token, children })=>{
169
159
  }, containerKey);
170
160
  };
171
161
 
162
+ const QuilttProvider = ({ clientId, graphqlClient, token, children })=>{
163
+ return /*#__PURE__*/ jsx(QuilttSettingsProvider, {
164
+ clientId: clientId,
165
+ children: /*#__PURE__*/ jsx(QuilttAuthProvider, {
166
+ token: token,
167
+ graphqlClient: graphqlClient,
168
+ children: children
169
+ })
170
+ });
171
+ };
172
+
172
173
  export { QuilttAuthProvider, QuilttButton, QuilttContainer, QuilttProvider, QuilttSettingsProvider, useQuilttConnector };
@@ -1,6 +1,6 @@
1
1
  'use client';
2
2
  import { useRef, useEffect } from 'react';
3
- import { u as useIsomorphicLayoutEffect } from './useIsomorphicLayoutEffect-client-DeTHOKz1.js';
3
+ import { u as useIsomorphicLayoutEffect } from './useIsomorphicLayoutEffect-12s-DeTHOKz1.js';
4
4
 
5
5
  /**
6
6
  * Supports Window, Element and Document and custom events with almost
@@ -1,10 +1,10 @@
1
1
  'use client';
2
2
  import { useState, useRef, useEffect, useCallback } from 'react';
3
3
  import { cdnBase } from '@quiltt/core';
4
- import { u as useQuilttSession } from './useQuilttSession-client-DhsbThvI.js';
5
- import { u as useScript } from './useScript-client-JCgaTW9n.js';
4
+ import { u as useQuilttSession } from './useQuilttSession-12s-CM6ALGSN.js';
5
+ import { u as useScript } from './useScript-12s-JCgaTW9n.js';
6
6
 
7
- var version = "4.2.3";
7
+ var version = "4.3.1";
8
8
 
9
9
  const useQuilttConnector = (connectorId, options)=>{
10
10
  const status = useScript(`${cdnBase}/v1/connector.js?agent=react-${version}`, {
@@ -19,6 +19,8 @@ const useQuilttConnector = (connectorId, options)=>{
19
19
  const prevConnectionIdRef = useRef(options?.connectionId);
20
20
  const prevConnectorIdRef = useRef(connectorId);
21
21
  const connectorCreatedRef = useRef(false);
22
+ // Track whether the connector is currently open
23
+ const isConnectorOpenRef = useRef(false);
22
24
  // Set Session
23
25
  // biome-ignore lint/correctness/useExhaustiveDependencies: trigger effects when script status changes too
24
26
  useEffect(()=>{
@@ -62,67 +64,55 @@ const useQuilttConnector = (connectorId, options)=>{
62
64
  options?.institution,
63
65
  status
64
66
  ]);
65
- // onEvent
66
- useEffect(()=>{
67
- if (!connector || !options?.onEvent) return;
68
- connector.onEvent(options.onEvent);
69
- return ()=>connector.offEvent(options.onEvent);
70
- }, [
71
- connector,
72
- options?.onEvent
73
- ]);
74
- // onOpen
75
- useEffect(()=>{
76
- if (!connector || !options?.onOpen) return;
77
- connector.onOpen(options.onOpen);
78
- return ()=>connector.offOpen(options.onOpen);
67
+ // Internal handlers to track connector state
68
+ const handleOpen = useCallback((metadata)=>{
69
+ isConnectorOpenRef.current = true;
70
+ options?.onOpen?.(metadata);
79
71
  }, [
80
- connector,
81
72
  options?.onOpen
82
73
  ]);
83
- // onLoad
84
- useEffect(()=>{
85
- if (!connector || !options?.onLoad) return;
86
- connector.onLoad(options.onLoad);
87
- return ()=>connector.offLoad(options.onLoad);
88
- }, [
89
- connector,
90
- options?.onLoad
91
- ]);
92
- // onExit
93
- useEffect(()=>{
94
- if (!connector || !options?.onExit) return;
95
- connector.onExit(options.onExit);
96
- return ()=>connector.offExit(options.onExit);
74
+ const handleExit = useCallback((type, metadata)=>{
75
+ isConnectorOpenRef.current = false;
76
+ options?.onExit?.(type, metadata);
97
77
  }, [
98
- connector,
99
78
  options?.onExit
100
79
  ]);
101
- // onExitSuccess
102
- useEffect(()=>{
103
- if (!connector || !options?.onExitSuccess) return;
104
- connector.onExitSuccess(options.onExitSuccess);
105
- return ()=>connector.offExitSuccess(options.onExitSuccess);
106
- }, [
107
- connector,
108
- options?.onExitSuccess
109
- ]);
110
- // onExitAbort
80
+ // Register event handlers
111
81
  useEffect(()=>{
112
- if (!connector || !options?.onExitAbort) return;
113
- connector.onExitAbort(options.onExitAbort);
114
- return ()=>connector.offExitAbort(options.onExitAbort);
115
- }, [
116
- connector,
117
- options?.onExitAbort
118
- ]);
119
- // onExitError
120
- useEffect(()=>{
121
- if (!connector || !options?.onExitError) return;
122
- connector.onExitError(options.onExitError);
123
- return ()=>connector.offExitError(options.onExitError);
82
+ if (!connector) return;
83
+ const handlers = {
84
+ onEvent: options?.onEvent,
85
+ onOpen: handleOpen,
86
+ onLoad: options?.onLoad,
87
+ onExit: handleExit,
88
+ onExitSuccess: options?.onExitSuccess,
89
+ onExitAbort: options?.onExitAbort,
90
+ onExitError: options?.onExitError
91
+ };
92
+ if (handlers.onEvent) connector.onEvent(handlers.onEvent);
93
+ if (handlers.onOpen) connector.onOpen(handlers.onOpen);
94
+ if (handlers.onLoad) connector.onLoad(handlers.onLoad);
95
+ if (handlers.onExit) connector.onExit(handlers.onExit);
96
+ if (handlers.onExitSuccess) connector.onExitSuccess(handlers.onExitSuccess);
97
+ if (handlers.onExitAbort) connector.onExitAbort(handlers.onExitAbort);
98
+ if (handlers.onExitError) connector.onExitError(handlers.onExitError);
99
+ return ()=>{
100
+ if (handlers.onEvent) connector.offEvent(handlers.onEvent);
101
+ if (handlers.onOpen) connector.offOpen(handlers.onOpen);
102
+ if (handlers.onLoad) connector.offLoad(handlers.onLoad);
103
+ if (handlers.onExit) connector.offExit(handlers.onExit);
104
+ if (handlers.onExitSuccess) connector.offExitSuccess(handlers.onExitSuccess);
105
+ if (handlers.onExitAbort) connector.offExitAbort(handlers.onExitAbort);
106
+ if (handlers.onExitError) connector.offExitError(handlers.onExitError);
107
+ };
124
108
  }, [
125
109
  connector,
110
+ options?.onEvent,
111
+ handleOpen,
112
+ options?.onLoad,
113
+ handleExit,
114
+ options?.onExitSuccess,
115
+ options?.onExitAbort,
126
116
  options?.onExitError
127
117
  ]);
128
118
  // This is used to hide any potential race conditions from usage; allowing
@@ -136,6 +126,14 @@ const useQuilttConnector = (connectorId, options)=>{
136
126
  connector,
137
127
  isOpening
138
128
  ]);
129
+ // Cleanup effect - runs when the hook is torn down
130
+ useEffect(()=>{
131
+ return ()=>{
132
+ if (isConnectorOpenRef.current) {
133
+ console.error('[Quiltt] useQuilttConnector: Component unmounted while Connector is still open. ' + 'This may lead to memory leaks or unexpected behavior. ' + 'Ensure the Connector is properly closed before component unmount.');
134
+ }
135
+ };
136
+ }, []);
139
137
  const open = useCallback(()=>{
140
138
  if (connectorId) {
141
139
  setIsOpening(true);
@@ -1,9 +1,9 @@
1
1
  'use client';
2
2
  import { useMemo, useState, useCallback, useEffect } from 'react';
3
- import { useDebounce } from 'use-debounce';
4
3
  import { InstitutionsAPI } from '@quiltt/core';
5
- import { v as version } from './useQuilttConnector-client-aEGkRKpA.js';
6
- import { u as useSession } from './useSession-client-CCAvnROP.js';
4
+ import { useDebounce } from 'use-debounce';
5
+ import { v as version } from './useQuilttConnector-12s-CL6uHdqe.js';
6
+ import { u as useSession } from './useSession-12s-7GOn4sUn.js';
7
7
 
8
8
  const useQuilttInstitutions = (connectorId, onErrorCallback)=>{
9
9
  const agent = useMemo(()=>{
@@ -1,9 +1,9 @@
1
1
  'use client';
2
2
  import { useCallback } from 'react';
3
3
  import { AuthAPI } from '@quiltt/core';
4
- import { u as useImportSession, a as useIdentifySession, b as useAuthenticateSession, c as useRevokeSession } from './QuilttAuthProvider-client-C25Tg4_a.js';
5
- import { u as useQuilttSettings } from './useQuilttSettings-client-BOCBjFXe.js';
6
- import { u as useSession } from './useSession-client-CCAvnROP.js';
4
+ import { u as useImportSession, a as useIdentifySession, b as useAuthenticateSession, c as useRevokeSession } from './QuilttAuthProvider-12s-BZuGySu0.js';
5
+ import { u as useQuilttSettings } from './useQuilttSettings-12s--rCJoNHD.js';
6
+ import { u as useSession } from './useSession-12s-7GOn4sUn.js';
7
7
 
8
8
  const useQuilttSession = (environmentId)=>{
9
9
  const { clientId } = useQuilttSettings();
@@ -1,6 +1,6 @@
1
1
  'use client';
2
2
  import { useContext } from 'react';
3
- import { Q as QuilttSettings } from './QuilttSettings-client-BK-0SQME.js';
3
+ import { Q as QuilttSettings } from './QuilttSettings-12s-BK-0SQME.js';
4
4
 
5
5
  const useQuilttSettings = ()=>{
6
6
  const settings = useContext(QuilttSettings);
@@ -1,7 +1,7 @@
1
1
  'use client';
2
2
  import { useMemo, useEffect, useCallback } from 'react';
3
3
  import { Timeoutable, JsonWebTokenParse } from '@quiltt/core';
4
- import { u as useStorage } from './useStorage-client-DHcq3Kuh.js';
4
+ import { u as useStorage } from './useStorage-12s-DHcq3Kuh.js';
5
5
 
6
6
  // Initialize JWT parser with our specific claims type
7
7
  const parse = JsonWebTokenParse;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@quiltt/react",
3
- "version": "4.2.3",
3
+ "version": "4.3.1",
4
4
  "description": "React Components and Hooks for Quiltt Connector",
5
5
  "keywords": [
6
6
  "quiltt",
@@ -34,20 +34,20 @@
34
34
  ],
35
35
  "main": "dist/index.js",
36
36
  "dependencies": {
37
- "@apollo/client": "^3.12.4",
37
+ "@apollo/client": "^3.14.0",
38
38
  "use-debounce": "^10.0.4",
39
- "@quiltt/core": "4.2.3"
39
+ "@quiltt/core": "4.3.1"
40
40
  },
41
41
  "devDependencies": {
42
- "@biomejs/biome": "1.9.4",
43
- "@types/node": "22.18.1",
44
- "@types/react": "18.3.20",
45
- "@types/react-dom": "18.3.5",
46
- "bunchee": "6.3.4",
42
+ "@biomejs/biome": "2.2.4",
43
+ "@types/node": "22.18.6",
44
+ "@types/react": "18.3.23",
45
+ "@types/react-dom": "18.3.7",
46
+ "bunchee": "6.6.0",
47
47
  "react": "18.3.1",
48
48
  "react-dom": "18.3.1",
49
49
  "rimraf": "6.0.1",
50
- "typescript": "5.8.3"
50
+ "typescript": "5.9.2"
51
51
  },
52
52
  "peerDependencies": {
53
53
  "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0",
@@ -1,5 +1,5 @@
1
- import { useEffect, useRef } from 'react'
2
1
  import type { ElementType, MouseEvent, PropsWithChildren } from 'react'
2
+ import { useEffect, useRef } from 'react'
3
3
 
4
4
  import type { ConnectorSDKCallbacks } from '@quiltt/core'
5
5
 
@@ -1,5 +1,5 @@
1
- import { useEffect, useRef } from 'react'
2
1
  import type { ElementType, PropsWithChildren } from 'react'
2
+ import { useEffect, useRef } from 'react'
3
3
 
4
4
  import type { ConnectorSDKCallbacks } from '@quiltt/core'
5
5
 
@@ -1,10 +1,13 @@
1
1
  'use client'
2
2
 
3
- import { useEffect, useRef } from 'react'
4
3
  import type { RefObject } from 'react'
4
+ import { useEffect, useRef } from 'react'
5
5
 
6
6
  import useIsomorphicLayoutEffect from './useIsomorphicLayoutEffect'
7
7
 
8
+ // Helper type for elements that support event listeners
9
+ type EventTarget = HTMLElement | MediaQueryList | Document | Window
10
+
8
11
  // MediaQueryList Event based useEventListener interface
9
12
  export function useEventListener<K extends keyof MediaQueryListEventMap>(
10
13
  eventName: K,
@@ -48,8 +51,7 @@ export function useEventListener<
48
51
  KW extends keyof WindowEventMap,
49
52
  KH extends keyof HTMLElementEventMap,
50
53
  KM extends keyof MediaQueryListEventMap,
51
- // biome-ignore lint/suspicious/noConfusingVoidType: <explanation>
52
- T extends HTMLElement | MediaQueryList | void = void,
54
+ T extends HTMLElement | MediaQueryList | Document = HTMLElement,
53
55
  >(
54
56
  eventName: KW | KH | KM,
55
57
  handler: (
@@ -67,7 +69,7 @@ export function useEventListener<
67
69
 
68
70
  useEffect(() => {
69
71
  // Define the listening target
70
- const targetElement: T | Window = element?.current ?? window
72
+ const targetElement: EventTarget = (element?.current ?? window) as EventTarget
71
73
 
72
74
  if (!targetElement?.addEventListener) return
73
75
 
@@ -1,4 +1,4 @@
1
- export * from './useIdentifySession'
2
1
  export * from './useAuthenticateSession'
2
+ export * from './useIdentifySession'
3
3
  export * from './useImportSession'
4
4
  export * from './useRevokeSession'
@@ -1,8 +1,7 @@
1
1
  import { useCallback } from 'react'
2
2
 
3
- import type { AuthAPI, Maybe, QuilttJWT } from '@quiltt/core'
3
+ import type { AuthAPI, Maybe, PrivateClaims, QuilttJWT } from '@quiltt/core'
4
4
  import { JsonWebTokenParse } from '@quiltt/core'
5
- import type { PrivateClaims } from '@quiltt/core'
6
5
 
7
6
  import type { SetSession } from '@/hooks/useSession'
8
7
 
@@ -2,12 +2,12 @@
2
2
 
3
3
  import { useCallback, useEffect, useRef, useState } from 'react'
4
4
 
5
- import { cdnBase } from '@quiltt/core'
6
5
  import type {
7
6
  ConnectorSDK,
8
7
  ConnectorSDKConnector,
9
8
  ConnectorSDKConnectorOptions,
10
9
  } from '@quiltt/core'
10
+ import { cdnBase } from '@quiltt/core'
11
11
 
12
12
  import { useQuilttSession } from '@/hooks/useQuilttSession'
13
13
  import { useScript } from '@/hooks/useScript'
@@ -35,6 +35,9 @@ export const useQuilttConnector = (
35
35
  const prevConnectorIdRef = useRef<string | undefined>(connectorId)
36
36
  const connectorCreatedRef = useRef<boolean>(false)
37
37
 
38
+ // Track whether the connector is currently open
39
+ const isConnectorOpenRef = useRef<boolean>(false)
40
+
38
41
  // Set Session
39
42
  // biome-ignore lint/correctness/useExhaustiveDependencies: trigger effects when script status changes too
40
43
  useEffect(() => {
@@ -73,61 +76,64 @@ export const useQuilttConnector = (
73
76
  }
74
77
  }, [connectorId, options?.connectionId, options?.institution, status])
75
78
 
76
- // onEvent
77
- useEffect(() => {
78
- if (!connector || !options?.onEvent) return
79
-
80
- connector.onEvent(options.onEvent)
81
- return () => connector.offEvent(options.onEvent as any)
82
- }, [connector, options?.onEvent])
83
-
84
- // onOpen
85
- useEffect(() => {
86
- if (!connector || !options?.onOpen) return
87
-
88
- connector.onOpen(options.onOpen)
89
- return () => connector.offOpen(options.onOpen as any)
90
- }, [connector, options?.onOpen])
91
-
92
- // onLoad
79
+ // Internal handlers to track connector state
80
+ const handleOpen = useCallback(
81
+ (metadata: any) => {
82
+ isConnectorOpenRef.current = true
83
+ options?.onOpen?.(metadata)
84
+ },
85
+ [options?.onOpen]
86
+ )
87
+
88
+ const handleExit = useCallback(
89
+ (type: any, metadata: any) => {
90
+ isConnectorOpenRef.current = false
91
+ options?.onExit?.(type, metadata)
92
+ },
93
+ [options?.onExit]
94
+ )
95
+
96
+ // Register event handlers
93
97
  useEffect(() => {
94
- if (!connector || !options?.onLoad) return
95
-
96
- connector.onLoad(options.onLoad)
97
- return () => connector.offLoad(options.onLoad as any)
98
- }, [connector, options?.onLoad])
99
-
100
- // onExit
101
- useEffect(() => {
102
- if (!connector || !options?.onExit) return
103
-
104
- connector.onExit(options.onExit)
105
- return () => connector.offExit(options.onExit as any)
106
- }, [connector, options?.onExit])
107
-
108
- // onExitSuccess
109
- useEffect(() => {
110
- if (!connector || !options?.onExitSuccess) return
111
-
112
- connector.onExitSuccess(options.onExitSuccess)
113
- return () => connector.offExitSuccess(options.onExitSuccess as any)
114
- }, [connector, options?.onExitSuccess])
115
-
116
- // onExitAbort
117
- useEffect(() => {
118
- if (!connector || !options?.onExitAbort) return
119
-
120
- connector.onExitAbort(options.onExitAbort)
121
- return () => connector.offExitAbort(options.onExitAbort as any)
122
- }, [connector, options?.onExitAbort])
123
-
124
- // onExitError
125
- useEffect(() => {
126
- if (!connector || !options?.onExitError) return
98
+ if (!connector) return
99
+
100
+ const handlers = {
101
+ onEvent: options?.onEvent,
102
+ onOpen: handleOpen,
103
+ onLoad: options?.onLoad,
104
+ onExit: handleExit,
105
+ onExitSuccess: options?.onExitSuccess,
106
+ onExitAbort: options?.onExitAbort,
107
+ onExitError: options?.onExitError,
108
+ }
127
109
 
128
- connector.onExitError(options.onExitError)
129
- return () => connector.offExitError(options.onExitError as any)
130
- }, [connector, options?.onExitError])
110
+ if (handlers.onEvent) connector.onEvent(handlers.onEvent)
111
+ if (handlers.onOpen) connector.onOpen(handlers.onOpen)
112
+ if (handlers.onLoad) connector.onLoad(handlers.onLoad)
113
+ if (handlers.onExit) connector.onExit(handlers.onExit)
114
+ if (handlers.onExitSuccess) connector.onExitSuccess(handlers.onExitSuccess)
115
+ if (handlers.onExitAbort) connector.onExitAbort(handlers.onExitAbort)
116
+ if (handlers.onExitError) connector.onExitError(handlers.onExitError)
117
+
118
+ return () => {
119
+ if (handlers.onEvent) connector.offEvent(handlers.onEvent)
120
+ if (handlers.onOpen) connector.offOpen(handlers.onOpen)
121
+ if (handlers.onLoad) connector.offLoad(handlers.onLoad)
122
+ if (handlers.onExit) connector.offExit(handlers.onExit)
123
+ if (handlers.onExitSuccess) connector.offExitSuccess(handlers.onExitSuccess)
124
+ if (handlers.onExitAbort) connector.offExitAbort(handlers.onExitAbort)
125
+ if (handlers.onExitError) connector.offExitError(handlers.onExitError)
126
+ }
127
+ }, [
128
+ connector,
129
+ options?.onEvent,
130
+ handleOpen,
131
+ options?.onLoad,
132
+ handleExit,
133
+ options?.onExitSuccess,
134
+ options?.onExitAbort,
135
+ options?.onExitError,
136
+ ])
131
137
 
132
138
  // This is used to hide any potential race conditions from usage; allowing
133
139
  // interaction before the script may have loaded.
@@ -138,6 +144,19 @@ export const useQuilttConnector = (
138
144
  }
139
145
  }, [connector, isOpening])
140
146
 
147
+ // Cleanup effect - runs when the hook is torn down
148
+ useEffect(() => {
149
+ return () => {
150
+ if (isConnectorOpenRef.current) {
151
+ console.error(
152
+ '[Quiltt] useQuilttConnector: Component unmounted while Connector is still open. ' +
153
+ 'This may lead to memory leaks or unexpected behavior. ' +
154
+ 'Ensure the Connector is properly closed before component unmount.'
155
+ )
156
+ }
157
+ }
158
+ }, [])
159
+
141
160
  const open = useCallback(() => {
142
161
  if (connectorId) {
143
162
  setIsOpening(true)
@@ -2,10 +2,9 @@
2
2
 
3
3
  import { useCallback, useEffect, useMemo, useState } from 'react'
4
4
 
5
- import { useDebounce } from 'use-debounce'
6
-
7
- import { InstitutionsAPI } from '@quiltt/core'
8
5
  import type { ErrorData, InstitutionsData } from '@quiltt/core'
6
+ import { InstitutionsAPI } from '@quiltt/core'
7
+ import { useDebounce } from 'use-debounce'
9
8
 
10
9
  import { version } from '../version'
11
10
  import useSession from './useSession'
@@ -2,16 +2,16 @@
2
2
 
3
3
  import { useCallback } from 'react'
4
4
 
5
- import { AuthAPI } from '@quiltt/core'
6
5
  import type { Maybe, QuilttJWT } from '@quiltt/core'
6
+ import { AuthAPI } from '@quiltt/core'
7
7
 
8
+ import type { AuthenticateSession, IdentifySession, ImportSession, RevokeSession } from './session'
8
9
  import {
9
10
  useAuthenticateSession,
10
11
  useIdentifySession,
11
12
  useImportSession,
12
13
  useRevokeSession,
13
14
  } from './session'
14
- import type { AuthenticateSession, IdentifySession, ImportSession, RevokeSession } from './session'
15
15
  import { useQuilttSettings } from './useQuilttSettings'
16
16
  import { useSession } from './useSession'
17
17
 
@@ -1,7 +1,7 @@
1
1
  'use client'
2
2
 
3
- import { useCallback, useEffect, useMemo } from 'react'
4
3
  import type { Dispatch, SetStateAction } from 'react'
4
+ import { useCallback, useEffect, useMemo } from 'react'
5
5
 
6
6
  import type { Maybe, PrivateClaims, QuilttJWT } from '@quiltt/core'
7
7
  import { JsonWebTokenParse, Timeoutable } from '@quiltt/core'
package/src/index.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  export * from '@quiltt/core'
2
+
3
+ export * from './components'
2
4
  export * from './hooks'
3
5
  export * from './providers'
4
- export * from './components'
@@ -1,7 +1,7 @@
1
1
  'use client'
2
2
 
3
- import { useEffect, useMemo, useRef } from 'react'
4
3
  import type { FC, PropsWithChildren } from 'react'
4
+ import { useEffect, useMemo, useRef } from 'react'
5
5
 
6
6
  import { ApolloProvider } from '@apollo/client/react/context/ApolloProvider.js'
7
7
  import { InMemoryCache, QuilttClient } from '@quiltt/core'
@@ -9,8 +9,10 @@ import { InMemoryCache, QuilttClient } from '@quiltt/core'
9
9
  import { useQuilttSession } from '@/hooks'
10
10
  import { isDeepEqual } from '@/utils'
11
11
 
12
- type QuilttAuthProviderProps = PropsWithChildren & {
13
- /** The Session token obtained from the server */
12
+ export type QuilttAuthProviderProps = PropsWithChildren & {
13
+ /** A custom QuilttClient instance to use instead of the default */
14
+ graphqlClient?: QuilttClient
15
+ /** The Quiltt Session token obtained from the server */
14
16
  token?: string
15
17
  }
16
18
 
@@ -20,17 +22,22 @@ type QuilttAuthProviderProps = PropsWithChildren & {
20
22
  * into a loading state and the children are not rendered to prevent race conditions
21
23
  * from triggering within the transitionary state.
22
24
  */
23
- export const QuilttAuthProvider: FC<QuilttAuthProviderProps> = ({ token, children }) => {
25
+ export const QuilttAuthProvider: FC<QuilttAuthProviderProps> = ({
26
+ graphqlClient,
27
+ token,
28
+ children,
29
+ }) => {
24
30
  const { session, importSession } = useQuilttSession()
25
31
  const previousSessionRef = useRef(session)
26
32
 
27
- // @todo: extract into a provider so it can accessed by child components
28
- const graphQLClient = useMemo(
33
+ // Memoize the client to avoid unnecessary re-renders
34
+ const apolloClient = useMemo(
29
35
  () =>
36
+ graphqlClient ||
30
37
  new QuilttClient({
31
38
  cache: new InMemoryCache(),
32
39
  }),
33
- []
40
+ [graphqlClient]
34
41
  )
35
42
 
36
43
  // Import passed in token
@@ -41,12 +48,12 @@ export const QuilttAuthProvider: FC<QuilttAuthProviderProps> = ({ token, childre
41
48
  // Reset Client Store when session changes (using deep comparison)
42
49
  useEffect(() => {
43
50
  if (!isDeepEqual(session, previousSessionRef.current)) {
44
- graphQLClient.resetStore()
51
+ apolloClient.resetStore()
45
52
  previousSessionRef.current = session
46
53
  }
47
- }, [session, graphQLClient])
54
+ }, [session, apolloClient])
48
55
 
49
- return <ApolloProvider client={graphQLClient}>{children}</ApolloProvider>
56
+ return <ApolloProvider client={apolloClient}>{children}</ApolloProvider>
50
57
  }
51
58
 
52
59
  export default QuilttAuthProvider
@@ -1,19 +1,23 @@
1
- import type { FC, PropsWithChildren } from 'react'
1
+ import type { FC } from 'react'
2
2
 
3
+ import type { QuilttAuthProviderProps } from './QuilttAuthProvider'
3
4
  import { QuilttAuthProvider } from './QuilttAuthProvider'
5
+ import type { QuilttSettingsProviderProps } from './QuilttSettingsProvider'
4
6
  import { QuilttSettingsProvider } from './QuilttSettingsProvider'
5
7
 
6
- type QuilttProviderProps = PropsWithChildren & {
7
- /** The client ID for the client-side Auth API */
8
- clientId?: string
9
- /** The Session token obtained from the server */
10
- token?: string
11
- }
8
+ type QuilttProviderProps = QuilttSettingsProviderProps & QuilttAuthProviderProps
12
9
 
13
- export const QuilttProvider: FC<QuilttProviderProps> = ({ clientId, token, children }) => {
10
+ export const QuilttProvider: FC<QuilttProviderProps> = ({
11
+ clientId,
12
+ graphqlClient,
13
+ token,
14
+ children,
15
+ }) => {
14
16
  return (
15
17
  <QuilttSettingsProvider clientId={clientId}>
16
- <QuilttAuthProvider token={token}>{children}</QuilttAuthProvider>
18
+ <QuilttAuthProvider token={token} graphqlClient={graphqlClient}>
19
+ {children}
20
+ </QuilttAuthProvider>
17
21
  </QuilttSettingsProvider>
18
22
  )
19
23
  }
@@ -5,8 +5,8 @@ import { useState } from 'react'
5
5
 
6
6
  import { QuilttSettings } from '@/contexts/QuilttSettings'
7
7
 
8
- type QuilttSettingsProviderProps = PropsWithChildren & {
9
- /** The Client ID to use for the client-side Auth API */
8
+ export type QuilttSettingsProviderProps = PropsWithChildren & {
9
+ /** The Client ID to use for the passwordless Auth API */
10
10
  clientId?: string
11
11
  }
12
12
 
@@ -52,9 +52,6 @@ export const isDeepEqual = (obj1: unknown, obj2: unknown): boolean => {
52
52
  if (keys1.length !== keys2.length) return false
53
53
 
54
54
  return keys1.every((key) => {
55
- return (
56
- Object.prototype.hasOwnProperty.call(obj2, key) &&
57
- isDeepEqual((obj1 as any)[key], (obj2 as any)[key])
58
- )
55
+ return Object.hasOwn(obj2, key) && isDeepEqual((obj1 as any)[key], (obj2 as any)[key])
59
56
  })
60
57
  }