@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 +24 -0
- package/README.md +14 -7
- package/dist/QuilttAuthProvider-12s-C_Wt9rkK.js +58 -0
- package/dist/index.d.ts +5 -1
- package/dist/index.js +13 -10
- package/dist/{useQuilttClient-12s-CAAUait1.js → useQuilttClient-12s-Dj_MtYTU.js} +1 -1
- package/dist/{useQuilttConnector-12s-7jon0A8C.js → useQuilttConnector-12s-DfCZ1lpS.js} +79 -7
- package/dist/{useQuilttInstitutions-12s-Ca5smTKo.js → useQuilttInstitutions-12s-ClSQJPmP.js} +5 -16
- package/dist/{useQuilttRenderGuard-12s-BbUitnF1.js → useQuilttRenderGuard-12s-CsS2Ma6Q.js} +1 -2
- package/dist/{useQuilttResolvable-12s-CNvWZe0V.js → useQuilttResolvable-12s-Dm4vsARj.js} +5 -16
- package/dist/useQuilttSession-12s-_8sB_8aP.js +135 -0
- package/dist/{useSession-12s-7GOn4sUn.js → useSession-12s-BlrWOArd.js} +1 -1
- package/dist/{useStorage-12s-DHcq3Kuh.js → useStorage-12s-CpG6X57D.js} +7 -17
- package/package.json +13 -13
- package/src/hooks/useQuilttClient.ts +1 -1
- package/src/hooks/useQuilttConnector.ts +3 -2
- package/src/hooks/useQuilttInstitutions.ts +8 -23
- package/src/hooks/useQuilttRenderGuard.ts +1 -4
- package/src/hooks/useQuilttResolvable.ts +8 -23
- package/src/hooks/useStorage.ts +7 -15
- package/src/index.ts +61 -0
- package/src/providers/QuilttAuthProvider.tsx +5 -4
- package/src/utils/index.ts +1 -0
- package/src/utils/telemetry.ts +33 -0
- package/dist/QuilttAuthProvider-12s-BCpwSX-3.js +0 -205
- package/dist/useQuilttSession-12s-D10t5Wfh.js +0 -39
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
|
-
|
|
17
|
+
npm install @quiltt/react
|
|
16
18
|
```
|
|
17
19
|
|
|
18
20
|
With `yarn`:
|
|
19
21
|
|
|
20
22
|
```shell
|
|
21
|
-
|
|
23
|
+
yarn add @quiltt/react
|
|
22
24
|
```
|
|
23
25
|
|
|
24
26
|
With `pnpm`:
|
|
25
27
|
|
|
26
28
|
```shell
|
|
27
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 [
|
|
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-
|
|
5
|
-
import { u as useQuilttRenderGuard } from './useQuilttRenderGuard-12s-
|
|
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
|
|
11
|
-
export { u as
|
|
12
|
-
export { u as
|
|
13
|
-
export { u as
|
|
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-
|
|
16
|
-
export { u as useStorage } from './useStorage-12s-
|
|
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,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-
|
|
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
|
-
|
|
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
|
|
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 };
|
package/dist/{useQuilttInstitutions-12s-Ca5smTKo.js → useQuilttInstitutions-12s-ClSQJPmP.js}
RENAMED
|
@@ -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-
|
|
6
|
-
import { u as useSession } from './useSession-12s-
|
|
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
|
|
10
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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-
|
|
5
|
-
import { u as useSession } from './useSession-12s-
|
|
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
|
|
9
|
-
|
|
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
|
-
|
|
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-
|
|
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
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
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": "
|
|
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": "^
|
|
38
|
-
"use-debounce": "^10.0
|
|
39
|
-
"@quiltt/core": "
|
|
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.
|
|
43
|
-
"@types/node": "
|
|
44
|
-
"@types/react": "
|
|
45
|
-
"@types/react-dom": "
|
|
46
|
-
"bunchee": "6.
|
|
47
|
-
"react": "
|
|
48
|
-
"react-dom": "
|
|
49
|
-
"rimraf": "6.
|
|
50
|
-
"typescript": "5.9.
|
|
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",
|
|
@@ -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
|
|
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
|
|
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 {
|
|
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
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
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
|
-
|
|
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 {
|
|
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
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
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)
|
package/src/hooks/useStorage.ts
CHANGED
|
@@ -52,23 +52,15 @@ export const useStorage = <T>(
|
|
|
52
52
|
)
|
|
53
53
|
|
|
54
54
|
useEffect(() => {
|
|
55
|
-
// Subscribe to storage changes
|
|
56
|
-
|
|
57
|
-
|
|
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
|
-
|
|
71
|
-
|
|
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
|
|
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
|
)
|
package/src/utils/index.ts
CHANGED
|
@@ -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 };
|