@quiltt/react 4.5.0 → 5.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,29 @@
1
1
  # @quiltt/react
2
2
 
3
+ ## 5.0.0
4
+
5
+ ### Major Changes
6
+
7
+ - [#394](https://github.com/quiltt/quiltt-js/pull/394) [`2ba646a`](https://github.com/quiltt/quiltt-js/commit/2ba646a2efcb7bef7949dab74778ab1c3babdb84) Thanks [@zubairaziz](https://github.com/zubairaziz)! - Migrate Apollo Client to v4
8
+
9
+ ### Minor Changes
10
+
11
+ - [#395](https://github.com/quiltt/quiltt-js/pull/395) [`f635500`](https://github.com/quiltt/quiltt-js/commit/f635500f17ab8a76aa0fb87ed7f4971e63a93f12) Thanks [@zubairaziz](https://github.com/zubairaziz)! - Enhanced SDK telemetry with standardized User-Agent headers
12
+
13
+ ### Patch Changes
14
+
15
+ - Updated dependencies [[`f635500`](https://github.com/quiltt/quiltt-js/commit/f635500f17ab8a76aa0fb87ed7f4971e63a93f12), [`2ba646a`](https://github.com/quiltt/quiltt-js/commit/2ba646a2efcb7bef7949dab74778ab1c3babdb84)]:
16
+ - @quiltt/core@5.0.0
17
+
18
+ ## 4.5.1
19
+
20
+ ### Patch Changes
21
+
22
+ - [#389](https://github.com/quiltt/quiltt-js/pull/389) [`a6a2a7e`](https://github.com/quiltt/quiltt-js/commit/a6a2a7ea94c7204a69b53f191ee738bcdc520a10) Thanks [@zubairaziz](https://github.com/zubairaziz)! - Upgrade React versions across all projects
23
+
24
+ - Updated dependencies [[`a6a2a7e`](https://github.com/quiltt/quiltt-js/commit/a6a2a7ea94c7204a69b53f191ee738bcdc520a10)]:
25
+ - @quiltt/core@4.5.1
26
+
3
27
  ## 4.5.0
4
28
 
5
29
  ### Minor Changes
package/README.md CHANGED
@@ -7,24 +7,26 @@
7
7
 
8
8
  See the guides [here](https://www.quiltt.dev/connector/sdks/react).
9
9
 
10
+ For general project information and contributing guidelines, see the [main repository README](../../README.md).
11
+
10
12
  ## Installation
11
13
 
12
14
  With `npm`:
13
15
 
14
16
  ```shell
15
- $ npm install @quiltt/react
17
+ npm install @quiltt/react
16
18
  ```
17
19
 
18
20
  With `yarn`:
19
21
 
20
22
  ```shell
21
- $ yarn add @quiltt/react
23
+ yarn add @quiltt/react
22
24
  ```
23
25
 
24
26
  With `pnpm`:
25
27
 
26
28
  ```shell
27
- $ pnpm add @quiltt/react
29
+ pnpm add @quiltt/react
28
30
  ```
29
31
 
30
32
  ## Core Modules and Types
@@ -61,7 +63,7 @@ export const App = () => {
61
63
  connectorId="<CONNECTOR_ID>"
62
64
  onExitSuccess={handleExitSuccess}
63
65
  className="my-css-class"
64
- styles={{ borderWidth: '2px' }}
66
+ style={{ borderWidth: '2px' }}
65
67
  // ... other props to pass through to the button
66
68
  >
67
69
  Add Account
@@ -95,7 +97,7 @@ export const App = () => {
95
97
  connectorId="<CONNECTOR_ID>"
96
98
  onExitSuccess={handleExitSuccess}
97
99
  className="my-css-class"
98
- styles={{ height: '100%' }}
100
+ style={{ height: '100%' }}
99
101
  // ... other props to pass through to the container
100
102
  />
101
103
  )
@@ -137,7 +139,7 @@ import { useQuilttConnector } from '@quiltt/react'
137
139
 
138
140
  const App = () => {
139
141
  const { open } = useQuilttConnector('<CONNECTOR_ID>', {
140
- onEvent: (type) => console.log(`Received Quiltt Event: ${type}`)
142
+ onEvent: (type) => console.log(`Received Quiltt Event: ${type}`),
141
143
  onExitSuccess: (metadata) => console.log("Connector onExitSuccess", metadata.connectionId),
142
144
  })
143
145
 
@@ -204,4 +206,9 @@ This project is licensed under the terms of the MIT license. See the [LICENSE](L
204
206
 
205
207
  ## Contributing
206
208
 
207
- For information on how to contribute to this project, please refer to the [CONTRIBUTING.md](CONTRIBUTING.md) file.
209
+ For information on how to contribute to this project, please refer to the [repository contributing guidelines](../../CONTRIBUTING.md).
210
+
211
+ ## Related Packages
212
+
213
+ - [`@quiltt/core`](../core#readme) - Essential functionality and types
214
+ - [`@quiltt/react-native`](../react-native#readme) - React Native and Expo components
@@ -0,0 +1,58 @@
1
+ 'use client';
2
+ import { useRef, useMemo, useEffect } from 'react';
3
+ import { QuilttClient, InMemoryCache, createVersionLink } from '@quiltt/core';
4
+ import { ApolloProvider } from '@apollo/client/react';
5
+ import './QuilttSettings-12s-BK-0SQME.js';
6
+ import './useSession-12s-BlrWOArd.js';
7
+ import 'use-debounce';
8
+ import './QuilttProviderRender-12s-DtQtubjL.js';
9
+ import { jsx } from 'react/jsx-runtime';
10
+ import { u as useQuilttSession } from './useQuilttSession-12s-_8sB_8aP.js';
11
+ import { a as getPlatformInfo, i as isDeepEqual } from './useQuilttConnector-12s-DfCZ1lpS.js';
12
+
13
+ /**
14
+ * If a token is provided, will validate the token against the api and then import
15
+ * it into trusted storage. While this process is happening, the component is put
16
+ * into a loading state and the children are not rendered to prevent race conditions
17
+ * from triggering within the transitionary state.
18
+ */ const QuilttAuthProvider = ({ graphqlClient, token, children })=>{
19
+ const { session, importSession } = useQuilttSession();
20
+ const previousSessionRef = useRef(session);
21
+ const previousTokenRef = useRef(undefined);
22
+ // Memoize the client to avoid unnecessary re-renders
23
+ const apolloClient = useMemo(()=>graphqlClient || new QuilttClient({
24
+ cache: new InMemoryCache(),
25
+ versionLink: createVersionLink(getPlatformInfo())
26
+ }), [
27
+ graphqlClient
28
+ ]);
29
+ // Import passed in token (only if value has changed)
30
+ useEffect(()=>{
31
+ if (token && token !== previousTokenRef.current) {
32
+ importSession(token);
33
+ previousTokenRef.current = token;
34
+ } else if (!token) {
35
+ // Reset ref when token becomes undefined to allow re-import of same token later
36
+ previousTokenRef.current = undefined;
37
+ }
38
+ }, [
39
+ token,
40
+ importSession
41
+ ]);
42
+ // Reset Client Store when session changes (using deep comparison)
43
+ useEffect(()=>{
44
+ if (!isDeepEqual(session, previousSessionRef.current)) {
45
+ apolloClient.resetStore();
46
+ previousSessionRef.current = session;
47
+ }
48
+ }, [
49
+ session,
50
+ apolloClient
51
+ ]);
52
+ return /*#__PURE__*/ jsx(ApolloProvider, {
53
+ client: apolloClient,
54
+ children: children
55
+ });
56
+ };
57
+
58
+ export { QuilttAuthProvider as Q };
package/dist/index.d.ts CHANGED
@@ -1,8 +1,12 @@
1
+ export { ApolloClient, ApolloQueryResult, DocumentNode, ErrorPolicy, FetchPolicy, InMemoryCache, NetworkStatus, NormalizedCacheObject, ObservableQuery, OperationVariables, TypedDocumentNode, WatchQueryFetchPolicy, gql } from '@apollo/client';
2
+ export { CombinedGraphQLErrors, CombinedProtocolErrors, LinkError, LocalStateError, ServerError, ServerParseError, UnconventionalError } from '@apollo/client/errors';
3
+ import { useApolloClient } from '@apollo/client/react';
4
+ export { ApolloProvider, MutationHookOptions, MutationResult, QueryHookOptions, QueryResult, SubscriptionHookOptions, SubscriptionResult, createQueryPreloader, skipToken, useApolloClient, useBackgroundQuery, useFragment, useLazyQuery, useLoadableQuery, useMutation, useQuery, useQueryRefHandlers, useReactiveVar, useReadQuery, useSubscription, useSuspenseQuery } from '@apollo/client/react';
5
+ export { MockedProvider } from '@apollo/client/testing/react';
1
6
  import { ConnectorSDKCallbacks, Maybe, QuilttJWT, PasscodePayload, UnprocessableData, AuthAPI, UsernamePayload, ConnectorSDKConnectorOptions, InstitutionsData, QuilttClient } from '@quiltt/core';
2
7
  export * from '@quiltt/core';
3
8
  import * as react_jsx_runtime from 'react/jsx-runtime';
4
9
  import { JSX, ComponentType, ElementType, PropsWithChildren, MouseEvent, RefObject, useEffect, Dispatch, SetStateAction, FC } from 'react';
5
- import { useApolloClient } from '@apollo/client/react/hooks/useApolloClient.js';
6
10
 
7
11
  type PropsOf<Tag> = Tag extends keyof JSX.IntrinsicElements ? JSX.IntrinsicElements[Tag] : Tag extends ComponentType<infer Props> ? Props & JSX.IntrinsicAttributes : never;
8
12
 
package/dist/index.js CHANGED
@@ -1,19 +1,22 @@
1
+ export { ApolloClient, InMemoryCache, NetworkStatus, ObservableQuery, gql } from '@apollo/client';
2
+ export { CombinedGraphQLErrors, CombinedProtocolErrors, LinkError, LocalStateError, ServerError, ServerParseError, UnconventionalError } from '@apollo/client/errors';
3
+ export { ApolloProvider, createQueryPreloader, skipToken, useApolloClient, useBackgroundQuery, useFragment, useLazyQuery, useLoadableQuery, useMutation, useQuery, useQueryRefHandlers, useReactiveVar, useReadQuery, useSubscription, useSuspenseQuery } from '@apollo/client/react';
4
+ export { MockedProvider } from '@apollo/client/testing/react';
1
5
  export * from '@quiltt/core';
2
6
  import { jsx } from 'react/jsx-runtime';
3
7
  import { useRef, useEffect } from 'react';
4
- import { u as useQuilttConnector } from './useQuilttConnector-12s-7jon0A8C.js';
5
- import { u as useQuilttRenderGuard } from './useQuilttRenderGuard-12s-BbUitnF1.js';
6
- import { i as isDeepEqual, Q as QuilttAuthProvider } from './QuilttAuthProvider-12s-BCpwSX-3.js';
7
- export { b as useAuthenticateSession, a as useIdentifySession, u as useImportSession, c as useRevokeSession } from './QuilttAuthProvider-12s-BCpwSX-3.js';
8
+ import { i as isDeepEqual, u as useQuilttConnector } from './useQuilttConnector-12s-DfCZ1lpS.js';
9
+ import { u as useQuilttRenderGuard } from './useQuilttRenderGuard-12s-CsS2Ma6Q.js';
8
10
  export { u as useEventListener } from './useEventListener-12s-D_-6QIXa.js';
9
11
  export { u as useIsomorphicLayoutEffect } from './useIsomorphicLayoutEffect-12s-DeTHOKz1.js';
10
- export { u as useQuilttClient } from './useQuilttClient-12s-CAAUait1.js';
11
- export { u as useQuilttInstitutions } from './useQuilttInstitutions-12s-Ca5smTKo.js';
12
- export { u as useQuilttResolvable } from './useQuilttResolvable-12s-CNvWZe0V.js';
13
- export { u as useQuilttSession } from './useQuilttSession-12s-D10t5Wfh.js';
12
+ export { a as useAuthenticateSession, b as useIdentifySession, c as useImportSession, u as useQuilttSession, d as useRevokeSession } from './useQuilttSession-12s-_8sB_8aP.js';
13
+ export { u as useQuilttClient } from './useQuilttClient-12s-Dj_MtYTU.js';
14
+ export { u as useQuilttInstitutions } from './useQuilttInstitutions-12s-ClSQJPmP.js';
15
+ export { u as useQuilttResolvable } from './useQuilttResolvable-12s-Dm4vsARj.js';
14
16
  export { u as useQuilttSettings } from './useQuilttSettings-12s--rCJoNHD.js';
15
- export { u as useSession } from './useSession-12s-7GOn4sUn.js';
16
- export { u as useStorage } from './useStorage-12s-DHcq3Kuh.js';
17
+ export { u as useSession } from './useSession-12s-BlrWOArd.js';
18
+ export { u as useStorage } from './useStorage-12s-CpG6X57D.js';
19
+ import { Q as QuilttAuthProvider } from './QuilttAuthProvider-12s-C_Wt9rkK.js';
17
20
  import { Q as QuilttProviderRender } from './QuilttProviderRender-12s-DtQtubjL.js';
18
21
  import { Q as QuilttSettingsProvider } from './QuilttSettingsProvider-12s-ZcmFmOiZ.js';
19
22
 
@@ -1,5 +1,5 @@
1
1
  'use client';
2
- import { useApolloClient } from '@apollo/client/react/hooks/useApolloClient.js';
2
+ import { useApolloClient } from '@apollo/client/react';
3
3
 
4
4
  const useQuilttClient = useApolloClient;
5
5
 
@@ -1,14 +1,86 @@
1
1
  'use client';
2
- import { useState, useRef, useEffect, useCallback } from 'react';
3
- import { cdnBase } from '@quiltt/core';
4
- import { u as useQuilttSession } from './useQuilttSession-12s-D10t5Wfh.js';
2
+ import React, { useState, useRef, useEffect, useCallback } from 'react';
3
+ import { getBrowserInfo, getUserAgent as getUserAgent$1, cdnBase } from '@quiltt/core';
4
+ import { u as useQuilttSession } from './useQuilttSession-12s-_8sB_8aP.js';
5
5
  import { u as useScript } from './useScript-12s-JCgaTW9n.js';
6
- import { i as isDeepEqual } from './QuilttAuthProvider-12s-BCpwSX-3.js';
7
6
 
8
- var version = "4.5.0";
7
+ /**
8
+ * Performs a deep equality comparison between two values
9
+ *
10
+ * This function recursively compares all properties to determine if they are equal.
11
+ *
12
+ * @example
13
+ * ```ts
14
+ * isDeepEqual({ a: 1, b: { c: 2 } }, { a: 1, b: { c: 2 } }) // true
15
+ * isDeepEqual({ a: 1, b: { c: 2 } }, { a: 1, b: { c: 3 } }) // false
16
+ * ```
17
+ */ const isDeepEqual = (obj1, obj2)=>{
18
+ // Handle primitive types and null/undefined
19
+ if (obj1 === obj2) return true;
20
+ if (obj1 === null || obj2 === null || typeof obj1 !== 'object' || typeof obj2 !== 'object') return false;
21
+ // Handle special object types
22
+ if (obj1 instanceof Date && obj2 instanceof Date) {
23
+ return obj1.getTime() === obj2.getTime();
24
+ }
25
+ if (obj1 instanceof RegExp && obj2 instanceof RegExp) {
26
+ return obj1.toString() === obj2.toString();
27
+ }
28
+ if (obj1 instanceof Map && obj2 instanceof Map) {
29
+ if (obj1.size !== obj2.size) return false;
30
+ for (const [key, value] of obj1){
31
+ if (!obj2.has(key) || !isDeepEqual(value, obj2.get(key))) return false;
32
+ }
33
+ return true;
34
+ }
35
+ if (obj1 instanceof Set && obj2 instanceof Set) {
36
+ if (obj1.size !== obj2.size) return false;
37
+ const arr2 = Array.from(obj2);
38
+ for (const item of obj1){
39
+ if (!arr2.some((value)=>isDeepEqual(item, value))) return false;
40
+ }
41
+ return true;
42
+ }
43
+ // Handle arrays
44
+ if (Array.isArray(obj1) && Array.isArray(obj2)) {
45
+ if (obj1.length !== obj2.length) return false;
46
+ return obj1.every((value, index)=>isDeepEqual(value, obj2[index]));
47
+ }
48
+ // If one is array and other isn't, they're not equal
49
+ if (Array.isArray(obj1) || Array.isArray(obj2)) return false;
50
+ const keys1 = Object.keys(obj1);
51
+ const keys2 = Object.keys(obj2);
52
+ if (keys1.length !== keys2.length) return false;
53
+ return keys1.every((key)=>{
54
+ return Object.hasOwn(obj2, key) && isDeepEqual(obj1[key], obj2[key]);
55
+ });
56
+ };
57
+
58
+ /**
59
+ * Gets the React version from the runtime
60
+ */ const getReactVersion = ()=>{
61
+ return React.version || 'unknown';
62
+ };
63
+ /**
64
+ * Generates platform information string for React web
65
+ * Format: React/<version>; <browser>/<version>
66
+ */ const getPlatformInfo = ()=>{
67
+ const reactVersion = getReactVersion();
68
+ const browserInfo = getBrowserInfo();
69
+ return `React/${reactVersion}; ${browserInfo}`;
70
+ };
71
+ /**
72
+ * Generates User-Agent string for React SDK
73
+ * Format: Quiltt/<sdk-version> (React/<react-version>; <browser>/<version>)
74
+ */ const getUserAgent = (sdkVersion)=>{
75
+ const platformInfo = getPlatformInfo();
76
+ return getUserAgent$1(sdkVersion, platformInfo);
77
+ };
78
+
79
+ var version = "5.0.0";
9
80
 
10
81
  const useQuilttConnector = (connectorId, options)=>{
11
- const status = useScript(`${cdnBase}/v1/connector.js?agent=react-${version}`, {
82
+ const userAgent = getUserAgent(version);
83
+ const status = useScript(`${cdnBase}/v1/connector.js?agent=${encodeURIComponent(userAgent)}`, {
12
84
  nonce: options?.nonce
13
85
  });
14
86
  // This ensures we're not destructuring `session` before the script has loaded
@@ -170,4 +242,4 @@ const useQuilttConnector = (connectorId, options)=>{
170
242
  };
171
243
  };
172
244
 
173
- export { useQuilttConnector as u, version as v };
245
+ export { getPlatformInfo as a, getUserAgent as g, isDeepEqual as i, useQuilttConnector as u, version as v };
@@ -2,25 +2,14 @@
2
2
  import { useMemo, useState, useRef, useEffect, useCallback } from 'react';
3
3
  import { ConnectorsAPI } from '@quiltt/core';
4
4
  import { useDebounce } from 'use-debounce';
5
- import { v as version } from './useQuilttConnector-12s-7jon0A8C.js';
6
- import { u as useSession } from './useSession-12s-7GOn4sUn.js';
5
+ import { g as getUserAgent, v as version } from './useQuilttConnector-12s-DfCZ1lpS.js';
6
+ import { u as useSession } from './useSession-12s-BlrWOArd.js';
7
7
 
8
8
  const useQuilttInstitutions = (connectorId, onErrorCallback)=>{
9
- const agent = useMemo(()=>{
10
- // Try deprecated navigator.product first (still used in some RN versions)
11
- if (typeof navigator !== 'undefined' && navigator.product === 'ReactNative') {
12
- return `react-native-${version}`;
13
- }
14
- // Detect React Native by its unique environment characteristics
15
- const isReactNative = !!// Has window (unlike Node.js)
16
- (typeof window !== 'undefined' && // No document in window (unlike browsers)
17
- typeof window.document === 'undefined' && // Has navigator (unlike Node.js)
18
- typeof navigator !== 'undefined');
19
- return isReactNative ? `react-native-${version}` : `react-${version}`;
20
- }, []);
21
- const connectorsAPI = useMemo(()=>new ConnectorsAPI(connectorId, agent), [
9
+ const userAgent = useMemo(()=>getUserAgent(version), []);
10
+ const connectorsAPI = useMemo(()=>new ConnectorsAPI(connectorId, userAgent), [
22
11
  connectorId,
23
- agent
12
+ userAgent
24
13
  ]);
25
14
  const [session] = useSession();
26
15
  const [searchTermInput, setSearchTermInput] = useState('');
@@ -21,8 +21,7 @@ import { Q as QuilttProviderRender } from './QuilttProviderRender-12s-DtQtubjL.j
21
21
  const hasWarnedRef = useRef(false);
22
22
  useEffect(()=>{
23
23
  // Only run in development mode and warn once per component instance
24
- // Support both Node.js (process.env) and Vite (import.meta.env) environments
25
- const isProduction = process.env.NODE_ENV === 'production' || typeof import.meta !== 'undefined' && import.meta.env?.PROD;
24
+ const isProduction = process.env.NODE_ENV === 'production';
26
25
  if (isProduction) return;
27
26
  if (isRenderingProvider && !hasWarnedRef.current) {
28
27
  hasWarnedRef.current = true;
@@ -1,25 +1,14 @@
1
1
  'use client';
2
2
  import { useMemo, useState, useRef, useEffect, useCallback } from 'react';
3
3
  import { ConnectorsAPI } from '@quiltt/core';
4
- import { v as version } from './useQuilttConnector-12s-7jon0A8C.js';
5
- import { u as useSession } from './useSession-12s-7GOn4sUn.js';
4
+ import { g as getUserAgent, v as version } from './useQuilttConnector-12s-DfCZ1lpS.js';
5
+ import { u as useSession } from './useSession-12s-BlrWOArd.js';
6
6
 
7
7
  const useQuilttResolvable = (connectorId, onErrorCallback)=>{
8
- const agent = useMemo(()=>{
9
- // Try deprecated navigator.product first (still used in some RN versions)
10
- if (typeof navigator !== 'undefined' && navigator.product === 'ReactNative') {
11
- return `react-native-${version}`;
12
- }
13
- // Detect React Native by its unique environment characteristics
14
- const isReactNative = !!// Has window (unlike Node.js)
15
- (typeof window !== 'undefined' && // No document in window (unlike browsers)
16
- typeof window.document === 'undefined' && // Has navigator (unlike Node.js)
17
- typeof navigator !== 'undefined');
18
- return isReactNative ? `react-native-${version}` : `react-${version}`;
19
- }, []);
20
- const connectorsAPI = useMemo(()=>new ConnectorsAPI(connectorId, agent), [
8
+ const userAgent = useMemo(()=>getUserAgent(version), []);
9
+ const connectorsAPI = useMemo(()=>new ConnectorsAPI(connectorId, userAgent), [
21
10
  connectorId,
22
- agent
11
+ userAgent
23
12
  ]);
24
13
  const [session] = useSession();
25
14
  const [isLoading, setIsLoading] = useState(false);
@@ -0,0 +1,135 @@
1
+ 'use client';
2
+ import { useCallback, useMemo } from 'react';
3
+ import { JsonWebTokenParse, AuthAPI } from '@quiltt/core';
4
+ import { u as useQuilttSettings } from './useQuilttSettings-12s--rCJoNHD.js';
5
+ import { u as useSession } from './useSession-12s-BlrWOArd.js';
6
+
7
+ const useAuthenticateSession = (auth, setSession)=>{
8
+ const authenticateSession = useCallback(async (payload, callbacks)=>{
9
+ const response = await auth.authenticate(payload);
10
+ switch(response.status){
11
+ case 201:
12
+ setSession(response.data.token);
13
+ if (callbacks.onSuccess) return callbacks.onSuccess();
14
+ break;
15
+ case 401:
16
+ if (callbacks.onFailure) return callbacks.onFailure();
17
+ break;
18
+ case 422:
19
+ if (callbacks.onError) return callbacks.onError(response.data);
20
+ break;
21
+ default:
22
+ throw new Error(`AuthAPI.authenticate: Unexpected response status ${response.status}`);
23
+ }
24
+ }, [
25
+ auth,
26
+ setSession
27
+ ]);
28
+ return authenticateSession;
29
+ };
30
+
31
+ const useIdentifySession = (auth, setSession)=>{
32
+ const identifySession = useCallback(async (payload, callbacks)=>{
33
+ const response = await auth.identify(payload);
34
+ switch(response.status){
35
+ case 201:
36
+ setSession(response.data.token);
37
+ if (callbacks.onSuccess) return callbacks.onSuccess();
38
+ break;
39
+ case 202:
40
+ if (callbacks.onChallenged) return callbacks.onChallenged();
41
+ break;
42
+ case 403:
43
+ if (callbacks.onForbidden) return callbacks.onForbidden();
44
+ break;
45
+ case 422:
46
+ if (callbacks.onError) return callbacks.onError(response.data);
47
+ break;
48
+ default:
49
+ throw new Error(`AuthAPI.identify: Unexpected response status ${response.status}`);
50
+ }
51
+ }, [
52
+ auth,
53
+ setSession
54
+ ]);
55
+ return identifySession;
56
+ };
57
+
58
+ /**
59
+ * Optionally Accepts environmentId to validate session is from with your desired environment
60
+ */ const useImportSession = (auth, session, setSession, environmentId)=>{
61
+ const importSession = useCallback(async (token)=>{
62
+ // Is there a token?
63
+ if (!token) return !!session;
64
+ // Is this token already imported?
65
+ if (session && session.token === token) return true;
66
+ const jwt = JsonWebTokenParse(token);
67
+ // Is this token a valid JWT?
68
+ if (!jwt) return false;
69
+ // Is this token within the expected environment?
70
+ if (environmentId && jwt.claims.eid !== environmentId) return false;
71
+ // Is this token active?
72
+ const response = await auth.ping(token);
73
+ switch(response.status){
74
+ case 200:
75
+ setSession(token);
76
+ return true;
77
+ case 401:
78
+ return false;
79
+ default:
80
+ throw new Error(`AuthAPI.ping: Unexpected response status ${response.status}`);
81
+ }
82
+ }, [
83
+ auth,
84
+ session,
85
+ setSession,
86
+ environmentId
87
+ ]);
88
+ return importSession;
89
+ };
90
+
91
+ const useRevokeSession = (auth, session, setSession)=>{
92
+ const revokeSession = useCallback(async ()=>{
93
+ if (!session) return;
94
+ await auth.revoke(session.token);
95
+ setSession(null);
96
+ }, [
97
+ auth,
98
+ session,
99
+ setSession
100
+ ]);
101
+ return revokeSession;
102
+ };
103
+
104
+ const useQuilttSession = (environmentId)=>{
105
+ const { clientId } = useQuilttSettings();
106
+ const [session, setSession] = useSession();
107
+ const auth = useMemo(()=>new AuthAPI(clientId), [
108
+ clientId
109
+ ]);
110
+ const importSession = useImportSession(auth, session, setSession, environmentId);
111
+ const identifySession = useIdentifySession(auth, setSession);
112
+ const authenticateSession = useAuthenticateSession(auth, setSession);
113
+ const revokeSession = useRevokeSession(auth, session, setSession);
114
+ /**
115
+ * Forget current session.
116
+ * @param token specific token to forget, to help guard against async processes clearing the wrong session
117
+ */ const forgetSession = useCallback(async (token)=>{
118
+ if (!token || session && token && token === session.token) {
119
+ setSession(null);
120
+ }
121
+ }, [
122
+ session,
123
+ setSession
124
+ ]);
125
+ return {
126
+ session,
127
+ importSession,
128
+ identifySession,
129
+ authenticateSession,
130
+ revokeSession,
131
+ forgetSession
132
+ };
133
+ };
134
+
135
+ export { useAuthenticateSession as a, useIdentifySession as b, useImportSession as c, useRevokeSession as d, useQuilttSession as u };
@@ -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-12s-DHcq3Kuh.js';
4
+ import { u as useStorage } from './useStorage-12s-CpG6X57D.js';
5
5
 
6
6
  // Initialize JWT parser with our specific claims type
7
7
  const parse = JsonWebTokenParse;
@@ -43,24 +43,14 @@ import { GlobalStorage } from '@quiltt/core';
43
43
  hookState
44
44
  ]);
45
45
  useEffect(()=>{
46
- // Subscribe to storage changes and ensure state is synchronized
47
- // Reruns when key or state changes to maintain consistency
48
- GlobalStorage.subscribe(key, (newValue)=>{
49
- // Only update if the value is different from current state
50
- if (newValue !== hookState) {
51
- setHookState(newValue);
52
- }
53
- });
54
- // Initial sync
55
- const initialValue = getStorage();
56
- if (initialValue !== hookState) {
57
- setHookState(initialValue);
58
- }
59
- return ()=>GlobalStorage.unsubscribe(key, setHookState);
46
+ // Subscribe to storage changes from other sources (e.g., other hook instances, browser tabs)
47
+ const handleStorageChange = (newValue)=>{
48
+ setHookState(newValue);
49
+ };
50
+ GlobalStorage.subscribe(key, handleStorageChange);
51
+ return ()=>GlobalStorage.unsubscribe(key, handleStorageChange);
60
52
  }, [
61
- key,
62
- hookState,
63
- getStorage
53
+ key
64
54
  ]);
65
55
  return [
66
56
  hookState,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@quiltt/react",
3
- "version": "4.5.0",
3
+ "version": "5.0.0",
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.14.0",
38
- "use-debounce": "^10.0.4",
39
- "@quiltt/core": "4.5.0"
37
+ "@apollo/client": "^4.1.3",
38
+ "use-debounce": "^10.1.0",
39
+ "@quiltt/core": "5.0.0"
40
40
  },
41
41
  "devDependencies": {
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
- "react": "18.3.1",
48
- "react-dom": "18.3.1",
49
- "rimraf": "6.0.1",
50
- "typescript": "5.9.2"
42
+ "@biomejs/biome": "2.3.13",
43
+ "@types/node": "24.10.9",
44
+ "@types/react": "19.2.10",
45
+ "@types/react-dom": "19.2.3",
46
+ "bunchee": "6.9.4",
47
+ "react": "19.2.4",
48
+ "react-dom": "19.2.4",
49
+ "rimraf": "6.1.2",
50
+ "typescript": "5.9.3"
51
51
  },
52
52
  "peerDependencies": {
53
53
  "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0",
@@ -1,6 +1,6 @@
1
1
  'use client'
2
2
 
3
- import { useApolloClient } from '@apollo/client/react/hooks/useApolloClient.js'
3
+ import { useApolloClient } from '@apollo/client/react'
4
4
 
5
5
  export const useQuilttClient = useApolloClient
6
6
 
@@ -11,7 +11,7 @@ import { cdnBase } from '@quiltt/core'
11
11
 
12
12
  import { useQuilttSession } from '@/hooks/useQuilttSession'
13
13
  import { useScript } from '@/hooks/useScript'
14
- import { isDeepEqual } from '@/utils/isDeepEqual'
14
+ import { getUserAgent, isDeepEqual } from '@/utils'
15
15
  import { version } from '@/version'
16
16
 
17
17
  declare const Quiltt: ConnectorSDK
@@ -20,7 +20,8 @@ export const useQuilttConnector = (
20
20
  connectorId?: string,
21
21
  options?: ConnectorSDKConnectorOptions
22
22
  ) => {
23
- const status = useScript(`${cdnBase}/v1/connector.js?agent=react-${version}`, {
23
+ const userAgent = getUserAgent(version)
24
+ const status = useScript(`${cdnBase}/v1/connector.js?agent=${encodeURIComponent(userAgent)}`, {
24
25
  nonce: options?.nonce,
25
26
  })
26
27
 
@@ -6,7 +6,9 @@ import type { ErrorData, InstitutionsData } from '@quiltt/core'
6
6
  import { ConnectorsAPI } from '@quiltt/core'
7
7
  import { useDebounce } from 'use-debounce'
8
8
 
9
- import { version } from '../version'
9
+ import { getUserAgent } from '@/utils'
10
+ import { version } from '@/version'
11
+
10
12
  import useSession from './useSession'
11
13
 
12
14
  export type UseQuilttInstitutions = (
@@ -20,28 +22,11 @@ export type UseQuilttInstitutions = (
20
22
  }
21
23
 
22
24
  export const useQuilttInstitutions: UseQuilttInstitutions = (connectorId, onErrorCallback) => {
23
- const agent = useMemo(() => {
24
- // Try deprecated navigator.product first (still used in some RN versions)
25
- if (typeof navigator !== 'undefined' && navigator.product === 'ReactNative') {
26
- return `react-native-${version}`
27
- }
28
-
29
- // Detect React Native by its unique environment characteristics
30
- const isReactNative = !!(
31
- // Has window (unlike Node.js)
32
- (
33
- typeof window !== 'undefined' &&
34
- // No document in window (unlike browsers)
35
- typeof window.document === 'undefined' &&
36
- // Has navigator (unlike Node.js)
37
- typeof navigator !== 'undefined'
38
- )
39
- )
40
-
41
- return isReactNative ? `react-native-${version}` : `react-${version}`
42
- }, [])
43
-
44
- const connectorsAPI = useMemo(() => new ConnectorsAPI(connectorId, agent), [connectorId, agent])
25
+ const userAgent = useMemo(() => getUserAgent(version), [])
26
+ const connectorsAPI = useMemo(
27
+ () => new ConnectorsAPI(connectorId, userAgent),
28
+ [connectorId, userAgent]
29
+ )
45
30
  const [session] = useSession()
46
31
 
47
32
  const [searchTermInput, setSearchTermInput] = useState('')
@@ -25,10 +25,7 @@ export const useQuilttRenderGuard = (componentName: string) => {
25
25
 
26
26
  useEffect(() => {
27
27
  // Only run in development mode and warn once per component instance
28
- // Support both Node.js (process.env) and Vite (import.meta.env) environments
29
- const isProduction =
30
- process.env.NODE_ENV === 'production' ||
31
- (typeof import.meta !== 'undefined' && (import.meta as any).env?.PROD)
28
+ const isProduction = process.env.NODE_ENV === 'production'
32
29
 
33
30
  if (isProduction) return
34
31
 
@@ -5,7 +5,9 @@ import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
5
5
  import type { ErrorData, ResolvableData } from '@quiltt/core'
6
6
  import { ConnectorsAPI } from '@quiltt/core'
7
7
 
8
- import { version } from '../version'
8
+ import { getUserAgent } from '@/utils'
9
+ import { version } from '@/version'
10
+
9
11
  import useSession from './useSession'
10
12
 
11
13
  export type UseQuilttResolvable = (
@@ -25,28 +27,11 @@ export type UseQuilttResolvable = (
25
27
  }
26
28
 
27
29
  export const useQuilttResolvable: UseQuilttResolvable = (connectorId, onErrorCallback) => {
28
- const agent = useMemo(() => {
29
- // Try deprecated navigator.product first (still used in some RN versions)
30
- if (typeof navigator !== 'undefined' && navigator.product === 'ReactNative') {
31
- return `react-native-${version}`
32
- }
33
-
34
- // Detect React Native by its unique environment characteristics
35
- const isReactNative = !!(
36
- // Has window (unlike Node.js)
37
- (
38
- typeof window !== 'undefined' &&
39
- // No document in window (unlike browsers)
40
- typeof window.document === 'undefined' &&
41
- // Has navigator (unlike Node.js)
42
- typeof navigator !== 'undefined'
43
- )
44
- )
45
-
46
- return isReactNative ? `react-native-${version}` : `react-${version}`
47
- }, [])
48
-
49
- const connectorsAPI = useMemo(() => new ConnectorsAPI(connectorId, agent), [connectorId, agent])
30
+ const userAgent = useMemo(() => getUserAgent(version), [])
31
+ const connectorsAPI = useMemo(
32
+ () => new ConnectorsAPI(connectorId, userAgent),
33
+ [connectorId, userAgent]
34
+ )
50
35
  const [session] = useSession()
51
36
 
52
37
  const [isLoading, setIsLoading] = useState(false)
@@ -52,23 +52,15 @@ export const useStorage = <T>(
52
52
  )
53
53
 
54
54
  useEffect(() => {
55
- // Subscribe to storage changes and ensure state is synchronized
56
- // Reruns when key or state changes to maintain consistency
57
- GlobalStorage.subscribe(key, (newValue) => {
58
- // Only update if the value is different from current state
59
- if (newValue !== hookState) {
60
- setHookState(newValue)
61
- }
62
- })
63
-
64
- // Initial sync
65
- const initialValue = getStorage()
66
- if (initialValue !== hookState) {
67
- setHookState(initialValue)
55
+ // Subscribe to storage changes from other sources (e.g., other hook instances, browser tabs)
56
+ const handleStorageChange = (newValue: Maybe<T> | undefined) => {
57
+ setHookState(newValue)
68
58
  }
69
59
 
70
- return () => GlobalStorage.unsubscribe(key, setHookState)
71
- }, [key, hookState, getStorage])
60
+ GlobalStorage.subscribe(key, handleStorageChange)
61
+
62
+ return () => GlobalStorage.unsubscribe(key, handleStorageChange)
63
+ }, [key])
72
64
 
73
65
  return [hookState, setStorage]
74
66
  }
package/src/index.ts CHANGED
@@ -1,3 +1,64 @@
1
+ // ============================================================================
2
+ // Core Module - Apollo Client core functionality
3
+ // ============================================================================
4
+ export type {
5
+ ApolloQueryResult,
6
+ DocumentNode,
7
+ ErrorPolicy,
8
+ FetchPolicy,
9
+ NormalizedCacheObject,
10
+ OperationVariables,
11
+ TypedDocumentNode,
12
+ WatchQueryFetchPolicy,
13
+ } from '@apollo/client'
14
+ export {
15
+ ApolloClient,
16
+ gql,
17
+ InMemoryCache,
18
+ NetworkStatus,
19
+ ObservableQuery,
20
+ } from '@apollo/client'
21
+ // ============================================================================
22
+ // Errors Module - Error handling utilities
23
+ // ============================================================================
24
+ export {
25
+ CombinedGraphQLErrors,
26
+ CombinedProtocolErrors,
27
+ LinkError,
28
+ LocalStateError,
29
+ ServerError,
30
+ ServerParseError,
31
+ UnconventionalError,
32
+ } from '@apollo/client/errors'
33
+ // ============================================================================
34
+ // React Module - React hooks and components
35
+ // ============================================================================
36
+ export type {
37
+ MutationHookOptions,
38
+ MutationResult,
39
+ QueryHookOptions,
40
+ QueryResult,
41
+ SubscriptionHookOptions,
42
+ SubscriptionResult,
43
+ } from '@apollo/client/react'
44
+ export {
45
+ ApolloProvider,
46
+ createQueryPreloader,
47
+ skipToken,
48
+ useApolloClient,
49
+ useBackgroundQuery,
50
+ useFragment,
51
+ useLazyQuery,
52
+ useLoadableQuery,
53
+ useMutation,
54
+ useQuery,
55
+ useQueryRefHandlers,
56
+ useReactiveVar,
57
+ useReadQuery,
58
+ useSubscription,
59
+ useSuspenseQuery,
60
+ } from '@apollo/client/react'
61
+ export { MockedProvider } from '@apollo/client/testing/react'
1
62
  export * from '@quiltt/core'
2
63
 
3
64
  export * from './components'
@@ -3,11 +3,11 @@
3
3
  import type { FC, PropsWithChildren } from 'react'
4
4
  import { useEffect, useMemo, useRef } from 'react'
5
5
 
6
- import { ApolloProvider } from '@apollo/client/react/context/ApolloProvider.js'
7
- import { InMemoryCache, QuilttClient } from '@quiltt/core'
6
+ import { ApolloProvider } from '@apollo/client/react'
7
+ import { createVersionLink, InMemoryCache, QuilttClient } from '@quiltt/core'
8
8
 
9
9
  import { useQuilttSession } from '@/hooks'
10
- import { isDeepEqual } from '@/utils'
10
+ import { getPlatformInfo, isDeepEqual } from '@/utils'
11
11
 
12
12
  export type QuilttAuthProviderProps = PropsWithChildren & {
13
13
  /** A custom QuilttClient instance to use instead of the default */
@@ -29,7 +29,7 @@ export const QuilttAuthProvider: FC<QuilttAuthProviderProps> = ({
29
29
  }) => {
30
30
  const { session, importSession } = useQuilttSession()
31
31
  const previousSessionRef = useRef(session)
32
- const previousTokenRef = useRef<string | undefined>()
32
+ const previousTokenRef = useRef<string | undefined>(undefined)
33
33
 
34
34
  // Memoize the client to avoid unnecessary re-renders
35
35
  const apolloClient = useMemo(
@@ -37,6 +37,7 @@ export const QuilttAuthProvider: FC<QuilttAuthProviderProps> = ({
37
37
  graphqlClient ||
38
38
  new QuilttClient({
39
39
  cache: new InMemoryCache(),
40
+ versionLink: createVersionLink(getPlatformInfo()),
40
41
  }),
41
42
  [graphqlClient]
42
43
  )
@@ -1 +1,2 @@
1
1
  export * from './isDeepEqual'
2
+ export * from './telemetry'
@@ -0,0 +1,33 @@
1
+ import React from 'react'
2
+
3
+ import { getUserAgent as coreGetUserAgent, getBrowserInfo } from '@quiltt/core'
4
+
5
+ // Re-export getBrowserInfo
6
+ export { getBrowserInfo }
7
+
8
+ /**
9
+ * Gets the React version from the runtime
10
+ */
11
+ export const getReactVersion = (): string => {
12
+ return React.version || 'unknown'
13
+ }
14
+
15
+ /**
16
+ * Generates platform information string for React web
17
+ * Format: React/<version>; <browser>/<version>
18
+ */
19
+ export const getPlatformInfo = (): string => {
20
+ const reactVersion = getReactVersion()
21
+ const browserInfo = getBrowserInfo()
22
+
23
+ return `React/${reactVersion}; ${browserInfo}`
24
+ }
25
+
26
+ /**
27
+ * Generates User-Agent string for React SDK
28
+ * Format: Quiltt/<sdk-version> (React/<react-version>; <browser>/<version>)
29
+ */
30
+ export const getUserAgent = (sdkVersion: string): string => {
31
+ const platformInfo = getPlatformInfo()
32
+ return coreGetUserAgent(sdkVersion, platformInfo)
33
+ }
@@ -1,205 +0,0 @@
1
- 'use client';
2
- import { useCallback, useRef, useMemo, useEffect } from 'react';
3
- import { JsonWebTokenParse, QuilttClient, InMemoryCache } from '@quiltt/core';
4
- import '@apollo/client/react/hooks/useApolloClient.js';
5
- import './QuilttSettings-12s-BK-0SQME.js';
6
- import './useSession-12s-7GOn4sUn.js';
7
- import 'use-debounce';
8
- import './QuilttProviderRender-12s-DtQtubjL.js';
9
- import { jsx } from 'react/jsx-runtime';
10
- import { ApolloProvider } from '@apollo/client/react/context/ApolloProvider.js';
11
- import { u as useQuilttSession } from './useQuilttSession-12s-D10t5Wfh.js';
12
-
13
- const useAuthenticateSession = (auth, setSession)=>{
14
- const authenticateSession = useCallback(async (payload, callbacks)=>{
15
- const response = await auth.authenticate(payload);
16
- switch(response.status){
17
- case 201:
18
- setSession(response.data.token);
19
- if (callbacks.onSuccess) return callbacks.onSuccess();
20
- break;
21
- case 401:
22
- if (callbacks.onFailure) return callbacks.onFailure();
23
- break;
24
- case 422:
25
- if (callbacks.onError) return callbacks.onError(response.data);
26
- break;
27
- default:
28
- throw new Error(`AuthAPI.authenticate: Unexpected response status ${response.status}`);
29
- }
30
- }, [
31
- auth,
32
- setSession
33
- ]);
34
- return authenticateSession;
35
- };
36
-
37
- const useIdentifySession = (auth, setSession)=>{
38
- const identifySession = useCallback(async (payload, callbacks)=>{
39
- const response = await auth.identify(payload);
40
- switch(response.status){
41
- case 201:
42
- setSession(response.data.token);
43
- if (callbacks.onSuccess) return callbacks.onSuccess();
44
- break;
45
- case 202:
46
- if (callbacks.onChallenged) return callbacks.onChallenged();
47
- break;
48
- case 403:
49
- if (callbacks.onForbidden) return callbacks.onForbidden();
50
- break;
51
- case 422:
52
- if (callbacks.onError) return callbacks.onError(response.data);
53
- break;
54
- default:
55
- throw new Error(`AuthAPI.identify: Unexpected response status ${response.status}`);
56
- }
57
- }, [
58
- auth,
59
- setSession
60
- ]);
61
- return identifySession;
62
- };
63
-
64
- /**
65
- * Optionally Accepts environmentId to validate session is from with your desired environment
66
- */ const useImportSession = (auth, session, setSession, environmentId)=>{
67
- const importSession = useCallback(async (token)=>{
68
- // Is there a token?
69
- if (!token) return !!session;
70
- // Is this token already imported?
71
- if (session && session.token === token) return true;
72
- const jwt = JsonWebTokenParse(token);
73
- // Is this token a valid JWT?
74
- if (!jwt) return false;
75
- // Is this token within the expected environment?
76
- if (environmentId && jwt.claims.eid !== environmentId) return false;
77
- // Is this token active?
78
- const response = await auth.ping(token);
79
- switch(response.status){
80
- case 200:
81
- setSession(token);
82
- return true;
83
- case 401:
84
- return false;
85
- default:
86
- throw new Error(`AuthAPI.ping: Unexpected response status ${response.status}`);
87
- }
88
- }, [
89
- auth,
90
- session,
91
- setSession,
92
- environmentId
93
- ]);
94
- return importSession;
95
- };
96
-
97
- const useRevokeSession = (auth, session, setSession)=>{
98
- const revokeSession = useCallback(async ()=>{
99
- if (!session) return;
100
- await auth.revoke(session.token);
101
- setSession(null);
102
- }, [
103
- auth,
104
- session,
105
- setSession
106
- ]);
107
- return revokeSession;
108
- };
109
-
110
- /**
111
- * Performs a deep equality comparison between two values
112
- *
113
- * This function recursively compares all properties to determine if they are equal.
114
- *
115
- * @example
116
- * ```ts
117
- * isDeepEqual({ a: 1, b: { c: 2 } }, { a: 1, b: { c: 2 } }) // true
118
- * isDeepEqual({ a: 1, b: { c: 2 } }, { a: 1, b: { c: 3 } }) // false
119
- * ```
120
- */ const isDeepEqual = (obj1, obj2)=>{
121
- // Handle primitive types and null/undefined
122
- if (obj1 === obj2) return true;
123
- if (obj1 === null || obj2 === null || typeof obj1 !== 'object' || typeof obj2 !== 'object') return false;
124
- // Handle special object types
125
- if (obj1 instanceof Date && obj2 instanceof Date) {
126
- return obj1.getTime() === obj2.getTime();
127
- }
128
- if (obj1 instanceof RegExp && obj2 instanceof RegExp) {
129
- return obj1.toString() === obj2.toString();
130
- }
131
- if (obj1 instanceof Map && obj2 instanceof Map) {
132
- if (obj1.size !== obj2.size) return false;
133
- for (const [key, value] of obj1){
134
- if (!obj2.has(key) || !isDeepEqual(value, obj2.get(key))) return false;
135
- }
136
- return true;
137
- }
138
- if (obj1 instanceof Set && obj2 instanceof Set) {
139
- if (obj1.size !== obj2.size) return false;
140
- const arr2 = Array.from(obj2);
141
- for (const item of obj1){
142
- if (!arr2.some((value)=>isDeepEqual(item, value))) return false;
143
- }
144
- return true;
145
- }
146
- // Handle arrays
147
- if (Array.isArray(obj1) && Array.isArray(obj2)) {
148
- if (obj1.length !== obj2.length) return false;
149
- return obj1.every((value, index)=>isDeepEqual(value, obj2[index]));
150
- }
151
- // If one is array and other isn't, they're not equal
152
- if (Array.isArray(obj1) || Array.isArray(obj2)) return false;
153
- const keys1 = Object.keys(obj1);
154
- const keys2 = Object.keys(obj2);
155
- if (keys1.length !== keys2.length) return false;
156
- return keys1.every((key)=>{
157
- return Object.hasOwn(obj2, key) && isDeepEqual(obj1[key], obj2[key]);
158
- });
159
- };
160
-
161
- /**
162
- * If a token is provided, will validate the token against the api and then import
163
- * it into trusted storage. While this process is happening, the component is put
164
- * into a loading state and the children are not rendered to prevent race conditions
165
- * from triggering within the transitionary state.
166
- */ const QuilttAuthProvider = ({ graphqlClient, token, children })=>{
167
- const { session, importSession } = useQuilttSession();
168
- const previousSessionRef = useRef(session);
169
- const previousTokenRef = useRef();
170
- // Memoize the client to avoid unnecessary re-renders
171
- const apolloClient = useMemo(()=>graphqlClient || new QuilttClient({
172
- cache: new InMemoryCache()
173
- }), [
174
- graphqlClient
175
- ]);
176
- // Import passed in token (only if value has changed)
177
- useEffect(()=>{
178
- if (token && token !== previousTokenRef.current) {
179
- importSession(token);
180
- previousTokenRef.current = token;
181
- } else if (!token) {
182
- // Reset ref when token becomes undefined to allow re-import of same token later
183
- previousTokenRef.current = undefined;
184
- }
185
- }, [
186
- token,
187
- importSession
188
- ]);
189
- // Reset Client Store when session changes (using deep comparison)
190
- useEffect(()=>{
191
- if (!isDeepEqual(session, previousSessionRef.current)) {
192
- apolloClient.resetStore();
193
- previousSessionRef.current = session;
194
- }
195
- }, [
196
- session,
197
- apolloClient
198
- ]);
199
- return /*#__PURE__*/ jsx(ApolloProvider, {
200
- client: apolloClient,
201
- children: children
202
- });
203
- };
204
-
205
- export { QuilttAuthProvider as Q, useIdentifySession as a, useAuthenticateSession as b, useRevokeSession as c, isDeepEqual as i, useImportSession as u };
@@ -1,39 +0,0 @@
1
- 'use client';
2
- import { useMemo, useCallback } from 'react';
3
- import { AuthAPI } from '@quiltt/core';
4
- import { u as useImportSession, a as useIdentifySession, b as useAuthenticateSession, c as useRevokeSession } from './QuilttAuthProvider-12s-BCpwSX-3.js';
5
- import { u as useQuilttSettings } from './useQuilttSettings-12s--rCJoNHD.js';
6
- import { u as useSession } from './useSession-12s-7GOn4sUn.js';
7
-
8
- const useQuilttSession = (environmentId)=>{
9
- const { clientId } = useQuilttSettings();
10
- const [session, setSession] = useSession();
11
- const auth = useMemo(()=>new AuthAPI(clientId), [
12
- clientId
13
- ]);
14
- const importSession = useImportSession(auth, session, setSession, environmentId);
15
- const identifySession = useIdentifySession(auth, setSession);
16
- const authenticateSession = useAuthenticateSession(auth, setSession);
17
- const revokeSession = useRevokeSession(auth, session, setSession);
18
- /**
19
- * Forget current session.
20
- * @param token specific token to forget, to help guard against async processes clearing the wrong session
21
- */ const forgetSession = useCallback(async (token)=>{
22
- if (!token || session && token && token === session.token) {
23
- setSession(null);
24
- }
25
- }, [
26
- session,
27
- setSession
28
- ]);
29
- return {
30
- session,
31
- importSession,
32
- identifySession,
33
- authenticateSession,
34
- revokeSession,
35
- forgetSession
36
- };
37
- };
38
-
39
- export { useQuilttSession as u };