@quiltt/react 5.0.0 → 5.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (82) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/README.md +12 -0
  3. package/dist/components/QuilttProviderRender-12s-pvnc98Lj.cjs +6 -0
  4. package/dist/components/QuilttSettings-12s-cLPT_GLC.cjs +6 -0
  5. package/dist/components/index.cjs +212 -0
  6. package/dist/components/index.d.ts +56 -0
  7. package/dist/components/index.js +209 -0
  8. package/dist/{useQuilttConnector-12s-DfCZ1lpS.js → components/useQuilttConnector-12s-3VgurfwU.js} +6 -77
  9. package/dist/components/useQuilttConnector-12s-zU4NFJ-H.cjs +174 -0
  10. package/dist/components/useQuilttRenderGuard-12s-D9WbRzZO.cjs +36 -0
  11. package/dist/components/useQuilttSession-12s-BjyJL1qZ.cjs +133 -0
  12. package/dist/components/useQuilttSession-12s-VOH0S5zh.js +133 -0
  13. package/dist/components/useQuilttSettings-12s-aDLXY6z3.cjs +10 -0
  14. package/dist/components/useScript-12s-CMIDUHrx.cjs +92 -0
  15. package/dist/{useSession-12s-BlrWOArd.js → components/useSession-12s-BNPsfKY-.js} +27 -6
  16. package/dist/components/useSession-12s-BNotXj5T.cjs +90 -0
  17. package/dist/components/useStorage-12s-D7nllsrI.cjs +61 -0
  18. package/dist/contexts/QuilttSettings-12s-BK-0SQME.js +6 -0
  19. package/dist/contexts/QuilttSettings-12s-cLPT_GLC.cjs +6 -0
  20. package/dist/contexts/index.cjs +7 -0
  21. package/dist/contexts/index.d.ts +8 -0
  22. package/dist/contexts/index.js +1 -0
  23. package/dist/hooks/QuilttProviderRender-12s-DtQtubjL.js +6 -0
  24. package/dist/hooks/QuilttProviderRender-12s-pvnc98Lj.cjs +6 -0
  25. package/dist/hooks/QuilttSettings-12s-BK-0SQME.js +6 -0
  26. package/dist/hooks/QuilttSettings-12s-cLPT_GLC.cjs +6 -0
  27. package/dist/hooks/index.cjs +31 -0
  28. package/dist/hooks/index.d.ts +142 -0
  29. package/dist/hooks/index.js +11 -0
  30. package/dist/hooks/useEventListener-12s-CV8cLxWu.cjs +34 -0
  31. package/dist/hooks/useIsomorphicLayoutEffect-12s-B8KjaroI.cjs +9 -0
  32. package/dist/hooks/useQuilttClient-12s-flQYSVdG.cjs +6 -0
  33. package/dist/hooks/useQuilttConnector-12s-BLZ0GoAH.js +174 -0
  34. package/dist/hooks/useQuilttConnector-12s-sP-k4D3J.cjs +175 -0
  35. package/dist/hooks/useQuilttInstitutions-12s-BU_Vm7TY.cjs +82 -0
  36. package/dist/{useQuilttInstitutions-12s-ClSQJPmP.js → hooks/useQuilttInstitutions-12s-ByXIt9W6.js} +3 -2
  37. package/dist/hooks/useQuilttRenderGuard-12s-CsS2Ma6Q.js +36 -0
  38. package/dist/hooks/useQuilttRenderGuard-12s-D9WbRzZO.cjs +36 -0
  39. package/dist/{useQuilttResolvable-12s-Dm4vsARj.js → hooks/useQuilttResolvable-12s-C5DByktm.js} +3 -2
  40. package/dist/hooks/useQuilttResolvable-12s-CGEfKPVU.cjs +76 -0
  41. package/dist/hooks/useQuilttSession-12s-C8kq5S2Y.cjs +139 -0
  42. package/dist/{useQuilttSession-12s-_8sB_8aP.js → hooks/useQuilttSession-12s-DQFfjmob.js} +1 -1
  43. package/dist/hooks/useQuilttSettings-12s--rCJoNHD.js +10 -0
  44. package/dist/hooks/useQuilttSettings-12s-aDLXY6z3.cjs +10 -0
  45. package/dist/hooks/useScript-12s-CMIDUHrx.cjs +92 -0
  46. package/dist/hooks/useScript-12s-JCgaTW9n.js +92 -0
  47. package/dist/hooks/useSession-12s-BNPsfKY-.js +90 -0
  48. package/dist/hooks/useSession-12s-BNotXj5T.cjs +90 -0
  49. package/dist/hooks/useStorage-12s-CpG6X57D.js +61 -0
  50. package/dist/hooks/useStorage-12s-D7nllsrI.cjs +61 -0
  51. package/dist/index.cjs +149 -0
  52. package/dist/index.d.ts +3 -216
  53. package/dist/index.js +3 -190
  54. package/dist/{QuilttAuthProvider-12s-C_Wt9rkK.js → providers/QuilttAuthProvider-12s-CDgQbarX.js} +14 -12
  55. package/dist/providers/QuilttAuthProvider-12s-D__FY1Qn.cjs +60 -0
  56. package/dist/providers/QuilttProviderRender-12s-DtQtubjL.js +6 -0
  57. package/dist/providers/QuilttProviderRender-12s-pvnc98Lj.cjs +6 -0
  58. package/dist/providers/QuilttSettings-12s-BK-0SQME.js +6 -0
  59. package/dist/providers/QuilttSettings-12s-cLPT_GLC.cjs +6 -0
  60. package/dist/providers/QuilttSettingsProvider-12s-D7e8dsOE.cjs +19 -0
  61. package/dist/{QuilttSettingsProvider-12s-ZcmFmOiZ.js → providers/QuilttSettingsProvider-12s-DND2gPQm.js} +8 -5
  62. package/dist/providers/index.cjs +34 -0
  63. package/dist/providers/index.d.ts +28 -0
  64. package/dist/providers/index.js +30 -0
  65. package/dist/utils/index.cjs +89 -0
  66. package/dist/utils/index.d.ts +31 -0
  67. package/dist/utils/index.js +77 -0
  68. package/package.json +33 -7
  69. package/src/components/QuilttContainer.tsx +3 -0
  70. package/src/hooks/useSession.ts +32 -6
  71. package/src/providers/QuilttAuthProvider.tsx +8 -2
  72. package/src/providers/QuilttProvider.tsx +5 -1
  73. package/src/providers/QuilttSettingsProvider.tsx +4 -5
  74. /package/dist/{QuilttProviderRender-12s-DtQtubjL.js → components/QuilttProviderRender-12s-DtQtubjL.js} +0 -0
  75. /package/dist/{QuilttSettings-12s-BK-0SQME.js → components/QuilttSettings-12s-BK-0SQME.js} +0 -0
  76. /package/dist/{useQuilttRenderGuard-12s-CsS2Ma6Q.js → components/useQuilttRenderGuard-12s-CsS2Ma6Q.js} +0 -0
  77. /package/dist/{useQuilttSettings-12s--rCJoNHD.js → components/useQuilttSettings-12s--rCJoNHD.js} +0 -0
  78. /package/dist/{useScript-12s-JCgaTW9n.js → components/useScript-12s-JCgaTW9n.js} +0 -0
  79. /package/dist/{useStorage-12s-CpG6X57D.js → components/useStorage-12s-CpG6X57D.js} +0 -0
  80. /package/dist/{useEventListener-12s-D_-6QIXa.js → hooks/useEventListener-12s-D_-6QIXa.js} +0 -0
  81. /package/dist/{useIsomorphicLayoutEffect-12s-DeTHOKz1.js → hooks/useIsomorphicLayoutEffect-12s-DeTHOKz1.js} +0 -0
  82. /package/dist/{useQuilttClient-12s-Dj_MtYTU.js → hooks/useQuilttClient-12s-Dj_MtYTU.js} +0 -0
@@ -0,0 +1,28 @@
1
+ import { FC, PropsWithChildren } from 'react';
2
+ import { QuilttClient } from '@quiltt/core';
3
+
4
+ type QuilttAuthProviderProps = PropsWithChildren & {
5
+ /** A custom QuilttClient instance to use instead of the default */
6
+ graphqlClient?: QuilttClient;
7
+ /** The Quiltt Session token obtained from the server */
8
+ token?: string;
9
+ };
10
+ /**
11
+ * If a token is provided, will validate the token against the api and then import
12
+ * it into trusted storage. While this process is happening, the component is put
13
+ * into a loading state and the children are not rendered to prevent race conditions
14
+ * from triggering within the transitionary state.
15
+ */
16
+ declare const QuilttAuthProvider: FC<QuilttAuthProviderProps>;
17
+
18
+ type QuilttSettingsProviderProps = PropsWithChildren & {
19
+ /** The Client ID to use for the passwordless Auth API */
20
+ clientId?: string;
21
+ };
22
+ declare const QuilttSettingsProvider: FC<QuilttSettingsProviderProps>;
23
+
24
+ type QuilttProviderProps = QuilttSettingsProviderProps & QuilttAuthProviderProps;
25
+ declare const QuilttProvider: FC<QuilttProviderProps>;
26
+
27
+ export { QuilttAuthProvider, QuilttProvider, QuilttSettingsProvider };
28
+ export type { QuilttAuthProviderProps, QuilttSettingsProviderProps };
@@ -0,0 +1,30 @@
1
+ import { Q as QuilttAuthProvider } from './QuilttAuthProvider-12s-CDgQbarX.js';
2
+ import { jsx } from 'react/jsx-runtime';
3
+ import { useMemo } from 'react';
4
+ import { Q as QuilttProviderRender } from './QuilttProviderRender-12s-DtQtubjL.js';
5
+ import { Q as QuilttSettingsProvider } from './QuilttSettingsProvider-12s-DND2gPQm.js';
6
+
7
+ const QuilttProvider = ({ clientId, graphqlClient, token, children })=>{
8
+ // Set a context flag that SDK components can check to warn about potential anti-patterns.
9
+ // LIMITATION: This flags ALL descendants due to React context propagation, not just same-component usage.
10
+ // Will produce false positives for valid patterns like: <QuilttProvider><MyPage /></QuilttProvider>
11
+ // where MyPage renders SDK components (which is correct usage).
12
+ // The flag-based approach is simple but imprecise - a proper solution would require render stack tracking.
13
+ // Memoize context value to prevent unnecessary re-renders
14
+ const renderContextValue = useMemo(()=>({
15
+ isRenderingProvider: true
16
+ }), []);
17
+ return /*#__PURE__*/ jsx(QuilttProviderRender.Provider, {
18
+ value: renderContextValue,
19
+ children: /*#__PURE__*/ jsx(QuilttSettingsProvider, {
20
+ clientId: clientId,
21
+ children: /*#__PURE__*/ jsx(QuilttAuthProvider, {
22
+ token: token,
23
+ graphqlClient: graphqlClient,
24
+ children: children
25
+ })
26
+ })
27
+ });
28
+ };
29
+
30
+ export { QuilttAuthProvider, QuilttProvider, QuilttSettingsProvider };
@@ -0,0 +1,89 @@
1
+ Object.defineProperty(exports, '__esModule', { value: true });
2
+
3
+ var React = require('react');
4
+ var core = require('@quiltt/core');
5
+
6
+ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
7
+
8
+ var React__default = /*#__PURE__*/_interopDefault(React);
9
+
10
+ /**
11
+ * Performs a deep equality comparison between two values
12
+ *
13
+ * This function recursively compares all properties to determine if they are equal.
14
+ *
15
+ * @example
16
+ * ```ts
17
+ * isDeepEqual({ a: 1, b: { c: 2 } }, { a: 1, b: { c: 2 } }) // true
18
+ * isDeepEqual({ a: 1, b: { c: 2 } }, { a: 1, b: { c: 3 } }) // false
19
+ * ```
20
+ */ const isDeepEqual = (obj1, obj2)=>{
21
+ // Handle primitive types and null/undefined
22
+ if (obj1 === obj2) return true;
23
+ if (obj1 === null || obj2 === null || typeof obj1 !== 'object' || typeof obj2 !== 'object') return false;
24
+ // Handle special object types
25
+ if (obj1 instanceof Date && obj2 instanceof Date) {
26
+ return obj1.getTime() === obj2.getTime();
27
+ }
28
+ if (obj1 instanceof RegExp && obj2 instanceof RegExp) {
29
+ return obj1.toString() === obj2.toString();
30
+ }
31
+ if (obj1 instanceof Map && obj2 instanceof Map) {
32
+ if (obj1.size !== obj2.size) return false;
33
+ for (const [key, value] of obj1){
34
+ if (!obj2.has(key) || !isDeepEqual(value, obj2.get(key))) return false;
35
+ }
36
+ return true;
37
+ }
38
+ if (obj1 instanceof Set && obj2 instanceof Set) {
39
+ if (obj1.size !== obj2.size) return false;
40
+ const arr2 = Array.from(obj2);
41
+ for (const item of obj1){
42
+ if (!arr2.some((value)=>isDeepEqual(item, value))) return false;
43
+ }
44
+ return true;
45
+ }
46
+ // Handle arrays
47
+ if (Array.isArray(obj1) && Array.isArray(obj2)) {
48
+ if (obj1.length !== obj2.length) return false;
49
+ return obj1.every((value, index)=>isDeepEqual(value, obj2[index]));
50
+ }
51
+ // If one is array and other isn't, they're not equal
52
+ if (Array.isArray(obj1) || Array.isArray(obj2)) return false;
53
+ const keys1 = Object.keys(obj1);
54
+ const keys2 = Object.keys(obj2);
55
+ if (keys1.length !== keys2.length) return false;
56
+ return keys1.every((key)=>{
57
+ return Object.hasOwn(obj2, key) && isDeepEqual(obj1[key], obj2[key]);
58
+ });
59
+ };
60
+
61
+ /**
62
+ * Gets the React version from the runtime
63
+ */ const getReactVersion = ()=>{
64
+ return React__default.default.version || 'unknown';
65
+ };
66
+ /**
67
+ * Generates platform information string for React web
68
+ * Format: React/<version>; <browser>/<version>
69
+ */ const getPlatformInfo = ()=>{
70
+ const reactVersion = getReactVersion();
71
+ const browserInfo = core.getBrowserInfo();
72
+ return `React/${reactVersion}; ${browserInfo}`;
73
+ };
74
+ /**
75
+ * Generates User-Agent string for React SDK
76
+ * Format: Quiltt/<sdk-version> (React/<react-version>; <browser>/<version>)
77
+ */ const getUserAgent = (sdkVersion)=>{
78
+ const platformInfo = getPlatformInfo();
79
+ return core.getUserAgent(sdkVersion, platformInfo);
80
+ };
81
+
82
+ Object.defineProperty(exports, "getBrowserInfo", {
83
+ enumerable: true,
84
+ get: function () { return core.getBrowserInfo; }
85
+ });
86
+ exports.getPlatformInfo = getPlatformInfo;
87
+ exports.getReactVersion = getReactVersion;
88
+ exports.getUserAgent = getUserAgent;
89
+ exports.isDeepEqual = isDeepEqual;
@@ -0,0 +1,31 @@
1
+ export { getBrowserInfo } from '@quiltt/core';
2
+
3
+ /**
4
+ * Performs a deep equality comparison between two values
5
+ *
6
+ * This function recursively compares all properties to determine if they are equal.
7
+ *
8
+ * @example
9
+ * ```ts
10
+ * isDeepEqual({ a: 1, b: { c: 2 } }, { a: 1, b: { c: 2 } }) // true
11
+ * isDeepEqual({ a: 1, b: { c: 2 } }, { a: 1, b: { c: 3 } }) // false
12
+ * ```
13
+ */
14
+ declare const isDeepEqual: (obj1: unknown, obj2: unknown) => boolean;
15
+
16
+ /**
17
+ * Gets the React version from the runtime
18
+ */
19
+ declare const getReactVersion: () => string;
20
+ /**
21
+ * Generates platform information string for React web
22
+ * Format: React/<version>; <browser>/<version>
23
+ */
24
+ declare const getPlatformInfo: () => string;
25
+ /**
26
+ * Generates User-Agent string for React SDK
27
+ * Format: Quiltt/<sdk-version> (React/<react-version>; <browser>/<version>)
28
+ */
29
+ declare const getUserAgent: (sdkVersion: string) => string;
30
+
31
+ export { getPlatformInfo, getReactVersion, getUserAgent, isDeepEqual };
@@ -0,0 +1,77 @@
1
+ import React from 'react';
2
+ import { getBrowserInfo, getUserAgent as getUserAgent$1 } from '@quiltt/core';
3
+ export { getBrowserInfo } from '@quiltt/core';
4
+
5
+ /**
6
+ * Performs a deep equality comparison between two values
7
+ *
8
+ * This function recursively compares all properties to determine if they are equal.
9
+ *
10
+ * @example
11
+ * ```ts
12
+ * isDeepEqual({ a: 1, b: { c: 2 } }, { a: 1, b: { c: 2 } }) // true
13
+ * isDeepEqual({ a: 1, b: { c: 2 } }, { a: 1, b: { c: 3 } }) // false
14
+ * ```
15
+ */ const isDeepEqual = (obj1, obj2)=>{
16
+ // Handle primitive types and null/undefined
17
+ if (obj1 === obj2) return true;
18
+ if (obj1 === null || obj2 === null || typeof obj1 !== 'object' || typeof obj2 !== 'object') return false;
19
+ // Handle special object types
20
+ if (obj1 instanceof Date && obj2 instanceof Date) {
21
+ return obj1.getTime() === obj2.getTime();
22
+ }
23
+ if (obj1 instanceof RegExp && obj2 instanceof RegExp) {
24
+ return obj1.toString() === obj2.toString();
25
+ }
26
+ if (obj1 instanceof Map && obj2 instanceof Map) {
27
+ if (obj1.size !== obj2.size) return false;
28
+ for (const [key, value] of obj1){
29
+ if (!obj2.has(key) || !isDeepEqual(value, obj2.get(key))) return false;
30
+ }
31
+ return true;
32
+ }
33
+ if (obj1 instanceof Set && obj2 instanceof Set) {
34
+ if (obj1.size !== obj2.size) return false;
35
+ const arr2 = Array.from(obj2);
36
+ for (const item of obj1){
37
+ if (!arr2.some((value)=>isDeepEqual(item, value))) return false;
38
+ }
39
+ return true;
40
+ }
41
+ // Handle arrays
42
+ if (Array.isArray(obj1) && Array.isArray(obj2)) {
43
+ if (obj1.length !== obj2.length) return false;
44
+ return obj1.every((value, index)=>isDeepEqual(value, obj2[index]));
45
+ }
46
+ // If one is array and other isn't, they're not equal
47
+ if (Array.isArray(obj1) || Array.isArray(obj2)) return false;
48
+ const keys1 = Object.keys(obj1);
49
+ const keys2 = Object.keys(obj2);
50
+ if (keys1.length !== keys2.length) return false;
51
+ return keys1.every((key)=>{
52
+ return Object.hasOwn(obj2, key) && isDeepEqual(obj1[key], obj2[key]);
53
+ });
54
+ };
55
+
56
+ /**
57
+ * Gets the React version from the runtime
58
+ */ const getReactVersion = ()=>{
59
+ return React.version || 'unknown';
60
+ };
61
+ /**
62
+ * Generates platform information string for React web
63
+ * Format: React/<version>; <browser>/<version>
64
+ */ const getPlatformInfo = ()=>{
65
+ const reactVersion = getReactVersion();
66
+ const browserInfo = getBrowserInfo();
67
+ return `React/${reactVersion}; ${browserInfo}`;
68
+ };
69
+ /**
70
+ * Generates User-Agent string for React SDK
71
+ * Format: Quiltt/<sdk-version> (React/<react-version>; <browser>/<version>)
72
+ */ const getUserAgent = (sdkVersion)=>{
73
+ const platformInfo = getPlatformInfo();
74
+ return getUserAgent$1(sdkVersion, platformInfo);
75
+ };
76
+
77
+ export { getPlatformInfo, getReactVersion, getUserAgent, isDeepEqual };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@quiltt/react",
3
- "version": "5.0.0",
3
+ "version": "5.0.2",
4
4
  "description": "React Components and Hooks for Quiltt Connector",
5
5
  "keywords": [
6
6
  "quiltt",
@@ -22,8 +22,34 @@
22
22
  "type": "module",
23
23
  "exports": {
24
24
  ".": {
25
- "import": "./dist/index.js",
26
- "types": "./dist/index.d.ts"
25
+ "types": "./dist/index.d.ts",
26
+ "require": "./dist/index.cjs",
27
+ "import": "./dist/index.js"
28
+ },
29
+ "./hooks": {
30
+ "types": "./dist/hooks/index.d.ts",
31
+ "require": "./dist/hooks/index.cjs",
32
+ "import": "./dist/hooks/index.js"
33
+ },
34
+ "./components": {
35
+ "types": "./dist/components/index.d.ts",
36
+ "require": "./dist/components/index.cjs",
37
+ "import": "./dist/components/index.js"
38
+ },
39
+ "./providers": {
40
+ "types": "./dist/providers/index.d.ts",
41
+ "require": "./dist/providers/index.cjs",
42
+ "import": "./dist/providers/index.js"
43
+ },
44
+ "./contexts": {
45
+ "types": "./dist/contexts/index.d.ts",
46
+ "require": "./dist/contexts/index.cjs",
47
+ "import": "./dist/contexts/index.js"
48
+ },
49
+ "./utils": {
50
+ "types": "./dist/utils/index.d.ts",
51
+ "require": "./dist/utils/index.cjs",
52
+ "import": "./dist/utils/index.js"
27
53
  }
28
54
  },
29
55
  "types": "./dist/index.d.ts",
@@ -36,12 +62,12 @@
36
62
  "dependencies": {
37
63
  "@apollo/client": "^4.1.3",
38
64
  "use-debounce": "^10.1.0",
39
- "@quiltt/core": "5.0.0"
65
+ "@quiltt/core": "5.0.2"
40
66
  },
41
67
  "devDependencies": {
42
- "@biomejs/biome": "2.3.13",
43
- "@types/node": "24.10.9",
44
- "@types/react": "19.2.10",
68
+ "@biomejs/biome": "2.3.14",
69
+ "@types/node": "24.10.10",
70
+ "@types/react": "19.2.11",
45
71
  "@types/react-dom": "19.2.3",
46
72
  "bunchee": "6.9.4",
47
73
  "react": "19.2.4",
@@ -13,6 +13,7 @@ type QuilttContainerProps<T extends ElementType> = PropsWithChildren<
13
13
  as?: T
14
14
  connectorId: string
15
15
  connectionId?: string // For Reconnect Mode
16
+ institution?: string // For Connect Mode
16
17
 
17
18
  /**
18
19
  * Forces complete remount when connectionId changes.
@@ -35,6 +36,7 @@ export const QuilttContainer = <T extends ElementType = 'div'>({
35
36
  as,
36
37
  connectorId,
37
38
  connectionId,
39
+ institution,
38
40
  forceRemountOnConnectionChange = false,
39
41
  onEvent,
40
42
  onLoad,
@@ -88,6 +90,7 @@ export const QuilttContainer = <T extends ElementType = 'div'>({
88
90
 
89
91
  useQuilttConnector(connectorId, {
90
92
  connectionId,
93
+ institution,
91
94
  nonce: props?.nonce, // Pass nonce for script loading if needed
92
95
  onEvent,
93
96
  onLoad,
@@ -42,13 +42,39 @@ export const useSession = (storageKey = 'session'): [Maybe<QuilttJWT> | undefine
42
42
  const expirationMS = session.claims.exp * 1000
43
43
  const expire = () => setToken(null)
44
44
 
45
+ const checkExpiration = () => {
46
+ if (Date.now() >= expirationMS) {
47
+ expire()
48
+ return true
49
+ }
50
+ return false
51
+ }
52
+
45
53
  // Clear immediately if already expired
46
- if (Date.now() >= expirationMS) {
47
- expire()
48
- } else {
49
- // Set timer to clear session at expiration time
50
- sessionTimer.set(expire, expirationMS - Date.now())
51
- return () => sessionTimer.clear(expire)
54
+ if (checkExpiration()) {
55
+ return
56
+ }
57
+
58
+ // Set timer to clear session at expiration time
59
+ sessionTimer.set(expire, expirationMS - Date.now())
60
+
61
+ // Also check expiration when tab becomes visible (handles idle sessions)
62
+ const handleVisibilityChange = () => {
63
+ if (!document.hidden) {
64
+ checkExpiration()
65
+ }
66
+ }
67
+
68
+ // Only add listener in browser environment
69
+ if (typeof document !== 'undefined') {
70
+ document.addEventListener('visibilitychange', handleVisibilityChange)
71
+ }
72
+
73
+ return () => {
74
+ sessionTimer.clear(expire)
75
+ if (typeof document !== 'undefined') {
76
+ document.removeEventListener('visibilitychange', handleVisibilityChange)
77
+ }
52
78
  }
53
79
  }, [session, setToken])
54
80
 
@@ -30,6 +30,12 @@ export const QuilttAuthProvider: FC<QuilttAuthProviderProps> = ({
30
30
  const { session, importSession } = useQuilttSession()
31
31
  const previousSessionRef = useRef(session)
32
32
  const previousTokenRef = useRef<string | undefined>(undefined)
33
+ const importSessionRef = useRef(importSession)
34
+
35
+ // Keep importSession ref up to date
36
+ useEffect(() => {
37
+ importSessionRef.current = importSession
38
+ }, [importSession])
33
39
 
34
40
  // Memoize the client to avoid unnecessary re-renders
35
41
  const apolloClient = useMemo(
@@ -45,13 +51,13 @@ export const QuilttAuthProvider: FC<QuilttAuthProviderProps> = ({
45
51
  // Import passed in token (only if value has changed)
46
52
  useEffect(() => {
47
53
  if (token && token !== previousTokenRef.current) {
48
- importSession(token)
54
+ importSessionRef.current(token)
49
55
  previousTokenRef.current = token
50
56
  } else if (!token) {
51
57
  // Reset ref when token becomes undefined to allow re-import of same token later
52
58
  previousTokenRef.current = undefined
53
59
  }
54
- }, [token, importSession])
60
+ }, [token])
55
61
 
56
62
  // Reset Client Store when session changes (using deep comparison)
57
63
  useEffect(() => {
@@ -1,4 +1,5 @@
1
1
  import type { FC } from 'react'
2
+ import { useMemo } from 'react'
2
3
 
3
4
  import { QuilttProviderRender } from '@/contexts/QuilttProviderRender'
4
5
 
@@ -20,8 +21,11 @@ export const QuilttProvider: FC<QuilttProviderProps> = ({
20
21
  // Will produce false positives for valid patterns like: <QuilttProvider><MyPage /></QuilttProvider>
21
22
  // where MyPage renders SDK components (which is correct usage).
22
23
  // The flag-based approach is simple but imprecise - a proper solution would require render stack tracking.
24
+ // Memoize context value to prevent unnecessary re-renders
25
+ const renderContextValue = useMemo(() => ({ isRenderingProvider: true }), [])
26
+
23
27
  return (
24
- <QuilttProviderRender.Provider value={{ isRenderingProvider: true }}>
28
+ <QuilttProviderRender.Provider value={renderContextValue}>
25
29
  <QuilttSettingsProvider clientId={clientId}>
26
30
  <QuilttAuthProvider token={token} graphqlClient={graphqlClient}>
27
31
  {children}
@@ -1,7 +1,7 @@
1
1
  'use client'
2
2
 
3
3
  import type { FC, PropsWithChildren } from 'react'
4
- import { useState } from 'react'
4
+ import { useMemo } from 'react'
5
5
 
6
6
  import { QuilttSettings } from '@/contexts/QuilttSettings'
7
7
 
@@ -11,11 +11,10 @@ export type QuilttSettingsProviderProps = PropsWithChildren & {
11
11
  }
12
12
 
13
13
  export const QuilttSettingsProvider: FC<QuilttSettingsProviderProps> = ({ clientId, children }) => {
14
- const [_clientId] = useState(clientId)
14
+ // Memoize context value to prevent unnecessary re-renders
15
+ const contextValue = useMemo(() => ({ clientId }), [clientId])
15
16
 
16
- return (
17
- <QuilttSettings.Provider value={{ clientId: _clientId }}>{children}</QuilttSettings.Provider>
18
- )
17
+ return <QuilttSettings.Provider value={contextValue}>{children}</QuilttSettings.Provider>
19
18
  }
20
19
 
21
20
  export default QuilttSettingsProvider