@quiltt/react 4.5.1 → 5.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +32 -0
- package/README.md +15 -3
- package/dist/components/QuilttProviderRender-12s-pvnc98Lj.cjs +6 -0
- package/dist/components/QuilttSettings-12s-cLPT_GLC.cjs +6 -0
- package/dist/components/index.cjs +211 -0
- package/dist/components/index.d.ts +55 -0
- package/dist/components/index.js +208 -0
- package/dist/components/useQuilttConnector-12s-BLTzI3gE.cjs +174 -0
- package/dist/components/useQuilttConnector-12s-UQQcvQrO.js +174 -0
- package/dist/components/useQuilttRenderGuard-12s-D9WbRzZO.cjs +36 -0
- package/dist/components/useQuilttSession-12s-BjyJL1qZ.cjs +133 -0
- package/dist/components/useQuilttSession-12s-VOH0S5zh.js +133 -0
- package/dist/components/useQuilttSettings-12s-aDLXY6z3.cjs +10 -0
- package/dist/components/useScript-12s-CMIDUHrx.cjs +92 -0
- package/dist/{useSession-12s-7GOn4sUn.js → components/useSession-12s-BNPsfKY-.js} +28 -7
- package/dist/components/useSession-12s-BNotXj5T.cjs +90 -0
- package/dist/{useStorage-12s-DHcq3Kuh.js → components/useStorage-12s-CpG6X57D.js} +7 -17
- package/dist/components/useStorage-12s-D7nllsrI.cjs +61 -0
- package/dist/contexts/QuilttSettings-12s-BK-0SQME.js +6 -0
- package/dist/contexts/QuilttSettings-12s-cLPT_GLC.cjs +6 -0
- package/dist/contexts/index.cjs +7 -0
- package/dist/contexts/index.d.ts +8 -0
- package/dist/contexts/index.js +1 -0
- package/dist/hooks/QuilttProviderRender-12s-DtQtubjL.js +6 -0
- package/dist/hooks/QuilttProviderRender-12s-pvnc98Lj.cjs +6 -0
- package/dist/hooks/QuilttSettings-12s-BK-0SQME.js +6 -0
- package/dist/hooks/QuilttSettings-12s-cLPT_GLC.cjs +6 -0
- package/dist/hooks/index.cjs +31 -0
- package/dist/hooks/index.d.ts +142 -0
- package/dist/hooks/index.js +11 -0
- package/dist/hooks/useEventListener-12s-CV8cLxWu.cjs +34 -0
- package/dist/hooks/useIsomorphicLayoutEffect-12s-B8KjaroI.cjs +9 -0
- package/dist/{useQuilttClient-12s-CAAUait1.js → hooks/useQuilttClient-12s-Dj_MtYTU.js} +1 -1
- package/dist/hooks/useQuilttClient-12s-flQYSVdG.cjs +6 -0
- package/dist/{useQuilttConnector-12s-D8VedbrT.js → hooks/useQuilttConnector-12s-C0KJHuZN.js} +5 -4
- package/dist/hooks/useQuilttConnector-12s-D51PZPgm.cjs +175 -0
- package/dist/hooks/useQuilttInstitutions-12s-D_Kr43s3.cjs +82 -0
- package/dist/{useQuilttInstitutions-12s-DExzPnfb.js → hooks/useQuilttInstitutions-12s-rgLHD9ye.js} +6 -16
- package/dist/hooks/useQuilttRenderGuard-12s-CsS2Ma6Q.js +36 -0
- package/dist/hooks/useQuilttRenderGuard-12s-D9WbRzZO.cjs +36 -0
- package/dist/{useQuilttResolvable-12s-C0BV3AvR.js → hooks/useQuilttResolvable-12s-BUDeH696.js} +6 -16
- package/dist/hooks/useQuilttResolvable-12s-D8wnfNBt.cjs +76 -0
- package/dist/hooks/useQuilttSession-12s-C8kq5S2Y.cjs +139 -0
- package/dist/hooks/useQuilttSession-12s-DQFfjmob.js +135 -0
- package/dist/hooks/useQuilttSettings-12s--rCJoNHD.js +10 -0
- package/dist/hooks/useQuilttSettings-12s-aDLXY6z3.cjs +10 -0
- package/dist/hooks/useScript-12s-CMIDUHrx.cjs +92 -0
- package/dist/hooks/useScript-12s-JCgaTW9n.js +92 -0
- package/dist/hooks/useSession-12s-BNPsfKY-.js +90 -0
- package/dist/hooks/useSession-12s-BNotXj5T.cjs +90 -0
- package/dist/hooks/useStorage-12s-CpG6X57D.js +61 -0
- package/dist/hooks/useStorage-12s-D7nllsrI.cjs +61 -0
- package/dist/index.cjs +149 -0
- package/dist/index.d.ts +7 -216
- package/dist/index.js +7 -191
- package/dist/providers/QuilttAuthProvider-12s-CDgQbarX.js +60 -0
- package/dist/providers/QuilttAuthProvider-12s-D__FY1Qn.cjs +60 -0
- package/dist/providers/QuilttProviderRender-12s-DtQtubjL.js +6 -0
- package/dist/providers/QuilttProviderRender-12s-pvnc98Lj.cjs +6 -0
- package/dist/providers/QuilttSettings-12s-BK-0SQME.js +6 -0
- package/dist/providers/QuilttSettings-12s-cLPT_GLC.cjs +6 -0
- package/dist/providers/QuilttSettingsProvider-12s-D7e8dsOE.cjs +19 -0
- package/dist/{QuilttSettingsProvider-12s-ZcmFmOiZ.js → providers/QuilttSettingsProvider-12s-DND2gPQm.js} +8 -5
- package/dist/providers/index.cjs +34 -0
- package/dist/providers/index.d.ts +28 -0
- package/dist/providers/index.js +30 -0
- package/dist/utils/index.cjs +89 -0
- package/dist/utils/index.d.ts +31 -0
- package/dist/utils/index.js +77 -0
- package/package.json +38 -12
- package/src/hooks/useQuilttClient.ts +1 -1
- package/src/hooks/useQuilttConnector.ts +3 -2
- package/src/hooks/useQuilttInstitutions.ts +8 -23
- package/src/hooks/useQuilttResolvable.ts +8 -23
- package/src/hooks/useSession.ts +32 -6
- package/src/hooks/useStorage.ts +7 -15
- package/src/index.ts +61 -0
- package/src/providers/QuilttAuthProvider.tsx +12 -5
- package/src/providers/QuilttProvider.tsx +5 -1
- package/src/providers/QuilttSettingsProvider.tsx +4 -5
- package/src/utils/index.ts +1 -0
- package/src/utils/telemetry.ts +33 -0
- package/dist/QuilttAuthProvider-12s-DE-ePRo_.js +0 -205
- package/dist/useQuilttSession-12s-sRvULtJv.js +0 -39
- /package/dist/{QuilttProviderRender-12s-DtQtubjL.js → components/QuilttProviderRender-12s-DtQtubjL.js} +0 -0
- /package/dist/{QuilttSettings-12s-BK-0SQME.js → components/QuilttSettings-12s-BK-0SQME.js} +0 -0
- /package/dist/{useQuilttRenderGuard-12s-CsS2Ma6Q.js → components/useQuilttRenderGuard-12s-CsS2Ma6Q.js} +0 -0
- /package/dist/{useQuilttSettings-12s--rCJoNHD.js → components/useQuilttSettings-12s--rCJoNHD.js} +0 -0
- /package/dist/{useScript-12s-JCgaTW9n.js → components/useScript-12s-JCgaTW9n.js} +0 -0
- /package/dist/{useEventListener-12s-D_-6QIXa.js → hooks/useEventListener-12s-D_-6QIXa.js} +0 -0
- /package/dist/{useIsomorphicLayoutEffect-12s-DeTHOKz1.js → hooks/useIsomorphicLayoutEffect-12s-DeTHOKz1.js} +0 -0
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
var react = require('react');
|
|
3
|
+
var core = require('@quiltt/core');
|
|
4
|
+
var useQuilttSession12s = require('./useQuilttSession-12s-BjyJL1qZ.cjs');
|
|
5
|
+
var useScript12s = require('./useScript-12s-CMIDUHrx.cjs');
|
|
6
|
+
var index_cjs = require('../utils/index.cjs');
|
|
7
|
+
|
|
8
|
+
var version = "5.0.1";
|
|
9
|
+
|
|
10
|
+
const useQuilttConnector = (connectorId, options)=>{
|
|
11
|
+
const userAgent = index_cjs.getUserAgent(version);
|
|
12
|
+
const status = useScript12s.useScript(`${core.cdnBase}/v1/connector.js?agent=${encodeURIComponent(userAgent)}`, {
|
|
13
|
+
nonce: options?.nonce
|
|
14
|
+
});
|
|
15
|
+
// This ensures we're not destructuring `session` before the script has loaded
|
|
16
|
+
const useQuilttSessionReturn = useQuilttSession12s.useQuilttSession();
|
|
17
|
+
const session = useQuilttSessionReturn?.session || null;
|
|
18
|
+
const [connector, setConnector] = react.useState();
|
|
19
|
+
const [isOpening, setIsOpening] = react.useState(false);
|
|
20
|
+
// Keep track of the previous connectionId to detect changes
|
|
21
|
+
const prevConnectionIdRef = react.useRef(options?.connectionId);
|
|
22
|
+
const prevConnectorIdRef = react.useRef(connectorId);
|
|
23
|
+
const prevInstitutionRef = react.useRef(options?.institution);
|
|
24
|
+
const connectorCreatedRef = react.useRef(false);
|
|
25
|
+
// Track whether the connector is currently open
|
|
26
|
+
const isConnectorOpenRef = react.useRef(false);
|
|
27
|
+
// Store callbacks in refs to maintain stable references
|
|
28
|
+
const callbacksRef = react.useRef(options || {});
|
|
29
|
+
react.useEffect(()=>{
|
|
30
|
+
callbacksRef.current = options || {};
|
|
31
|
+
});
|
|
32
|
+
// Set Session
|
|
33
|
+
// biome-ignore lint/correctness/useExhaustiveDependencies: trigger effects when script status changes too
|
|
34
|
+
react.useEffect(()=>{
|
|
35
|
+
if (typeof Quiltt === 'undefined') return;
|
|
36
|
+
Quiltt.authenticate(session?.token);
|
|
37
|
+
}, [
|
|
38
|
+
status,
|
|
39
|
+
session?.token
|
|
40
|
+
]);
|
|
41
|
+
// Set Connector
|
|
42
|
+
// biome-ignore lint/correctness/useExhaustiveDependencies: trigger effects when script status changes too
|
|
43
|
+
react.useEffect(()=>{
|
|
44
|
+
if (typeof Quiltt === 'undefined' || !connectorId) return;
|
|
45
|
+
const currentConnectionId = options?.connectionId;
|
|
46
|
+
const currentInstitution = options?.institution;
|
|
47
|
+
// Check for changes - use deep equality for institution object
|
|
48
|
+
const connectionIdChanged = prevConnectionIdRef.current !== currentConnectionId;
|
|
49
|
+
const connectorIdChanged = prevConnectorIdRef.current !== connectorId;
|
|
50
|
+
const institutionChanged = !index_cjs.isDeepEqual(prevInstitutionRef.current, currentInstitution);
|
|
51
|
+
const hasChanges = connectionIdChanged || connectorIdChanged || institutionChanged || !connectorCreatedRef.current;
|
|
52
|
+
// Update if there are changes, regardless of what the changes are
|
|
53
|
+
if (hasChanges) {
|
|
54
|
+
if (currentConnectionId) {
|
|
55
|
+
// Always use reconnect when connectionId is available
|
|
56
|
+
setConnector(Quiltt.reconnect(connectorId, {
|
|
57
|
+
connectionId: currentConnectionId
|
|
58
|
+
}));
|
|
59
|
+
} else {
|
|
60
|
+
// Use connect for new connections without connectionId
|
|
61
|
+
setConnector(Quiltt.connect(connectorId, {
|
|
62
|
+
institution: currentInstitution
|
|
63
|
+
}));
|
|
64
|
+
}
|
|
65
|
+
// Update refs
|
|
66
|
+
connectorCreatedRef.current = true;
|
|
67
|
+
prevConnectionIdRef.current = currentConnectionId;
|
|
68
|
+
prevConnectorIdRef.current = connectorId;
|
|
69
|
+
prevInstitutionRef.current = currentInstitution;
|
|
70
|
+
}
|
|
71
|
+
}, [
|
|
72
|
+
connectorId,
|
|
73
|
+
options?.connectionId,
|
|
74
|
+
options?.institution,
|
|
75
|
+
status
|
|
76
|
+
]);
|
|
77
|
+
// Internal handlers to track connector state (stable references)
|
|
78
|
+
const handleOpen = react.useCallback((metadata)=>{
|
|
79
|
+
isConnectorOpenRef.current = true;
|
|
80
|
+
callbacksRef.current?.onOpen?.(metadata);
|
|
81
|
+
}, []);
|
|
82
|
+
const handleExit = react.useCallback((type, metadata)=>{
|
|
83
|
+
isConnectorOpenRef.current = false;
|
|
84
|
+
callbacksRef.current?.onExit?.(type, metadata);
|
|
85
|
+
}, []);
|
|
86
|
+
// Create stable wrapper functions for callbacks
|
|
87
|
+
const stableOnEvent = react.useCallback((type, metadata)=>{
|
|
88
|
+
callbacksRef.current?.onEvent?.(type, metadata);
|
|
89
|
+
}, []);
|
|
90
|
+
const stableOnLoad = react.useCallback((metadata)=>{
|
|
91
|
+
callbacksRef.current?.onLoad?.(metadata);
|
|
92
|
+
}, []);
|
|
93
|
+
const stableOnExitSuccess = react.useCallback((metadata)=>{
|
|
94
|
+
callbacksRef.current?.onExitSuccess?.(metadata);
|
|
95
|
+
}, []);
|
|
96
|
+
const stableOnExitAbort = react.useCallback((metadata)=>{
|
|
97
|
+
callbacksRef.current?.onExitAbort?.(metadata);
|
|
98
|
+
}, []);
|
|
99
|
+
const stableOnExitError = react.useCallback((metadata)=>{
|
|
100
|
+
callbacksRef.current?.onExitError?.(metadata);
|
|
101
|
+
}, []);
|
|
102
|
+
// Register event handlers (only re-runs when connector changes)
|
|
103
|
+
react.useEffect(()=>{
|
|
104
|
+
if (!connector) return;
|
|
105
|
+
// Capture which handlers we're registering to ensure proper cleanup
|
|
106
|
+
const registered = {
|
|
107
|
+
onEvent: callbacksRef.current?.onEvent ? stableOnEvent : null,
|
|
108
|
+
onOpen: callbacksRef.current?.onOpen ? handleOpen : null,
|
|
109
|
+
onLoad: callbacksRef.current?.onLoad ? stableOnLoad : null,
|
|
110
|
+
onExit: callbacksRef.current?.onExit ? handleExit : null,
|
|
111
|
+
onExitSuccess: callbacksRef.current?.onExitSuccess ? stableOnExitSuccess : null,
|
|
112
|
+
onExitAbort: callbacksRef.current?.onExitAbort ? stableOnExitAbort : null,
|
|
113
|
+
onExitError: callbacksRef.current?.onExitError ? stableOnExitError : null
|
|
114
|
+
};
|
|
115
|
+
if (registered.onEvent) connector.onEvent(registered.onEvent);
|
|
116
|
+
if (registered.onOpen) connector.onOpen(registered.onOpen);
|
|
117
|
+
if (registered.onLoad) connector.onLoad(registered.onLoad);
|
|
118
|
+
if (registered.onExit) connector.onExit(registered.onExit);
|
|
119
|
+
if (registered.onExitSuccess) connector.onExitSuccess(registered.onExitSuccess);
|
|
120
|
+
if (registered.onExitAbort) connector.onExitAbort(registered.onExitAbort);
|
|
121
|
+
if (registered.onExitError) connector.onExitError(registered.onExitError);
|
|
122
|
+
return ()=>{
|
|
123
|
+
if (registered.onEvent) connector.offEvent(registered.onEvent);
|
|
124
|
+
if (registered.onOpen) connector.offOpen(registered.onOpen);
|
|
125
|
+
if (registered.onLoad) connector.offLoad(registered.onLoad);
|
|
126
|
+
if (registered.onExit) connector.offExit(registered.onExit);
|
|
127
|
+
if (registered.onExitSuccess) connector.offExitSuccess(registered.onExitSuccess);
|
|
128
|
+
if (registered.onExitAbort) connector.offExitAbort(registered.onExitAbort);
|
|
129
|
+
if (registered.onExitError) connector.offExitError(registered.onExitError);
|
|
130
|
+
};
|
|
131
|
+
}, [
|
|
132
|
+
connector,
|
|
133
|
+
stableOnEvent,
|
|
134
|
+
handleOpen,
|
|
135
|
+
stableOnLoad,
|
|
136
|
+
handleExit,
|
|
137
|
+
stableOnExitSuccess,
|
|
138
|
+
stableOnExitAbort,
|
|
139
|
+
stableOnExitError
|
|
140
|
+
]);
|
|
141
|
+
// This is used to hide any potential race conditions from usage; allowing
|
|
142
|
+
// interaction before the script may have loaded.
|
|
143
|
+
react.useEffect(()=>{
|
|
144
|
+
if (connector && isOpening) {
|
|
145
|
+
setIsOpening(false);
|
|
146
|
+
connector.open();
|
|
147
|
+
}
|
|
148
|
+
}, [
|
|
149
|
+
connector,
|
|
150
|
+
isOpening
|
|
151
|
+
]);
|
|
152
|
+
// Cleanup effect - runs when the hook is torn down
|
|
153
|
+
react.useEffect(()=>{
|
|
154
|
+
return ()=>{
|
|
155
|
+
if (isConnectorOpenRef.current) {
|
|
156
|
+
console.error('[Quiltt] useQuilttConnector: Component unmounted while Connector is still open. ' + 'This may lead to memory leaks or unexpected behavior. ' + 'Ensure the Connector is properly closed before component unmount.');
|
|
157
|
+
}
|
|
158
|
+
};
|
|
159
|
+
}, []);
|
|
160
|
+
const open = react.useCallback(()=>{
|
|
161
|
+
if (connectorId) {
|
|
162
|
+
setIsOpening(true);
|
|
163
|
+
} else {
|
|
164
|
+
throw new Error('Must provide `connectorId` to `open` Quiltt Connector with Method Call');
|
|
165
|
+
}
|
|
166
|
+
}, [
|
|
167
|
+
connectorId
|
|
168
|
+
]);
|
|
169
|
+
return {
|
|
170
|
+
open
|
|
171
|
+
};
|
|
172
|
+
};
|
|
173
|
+
|
|
174
|
+
exports.useQuilttConnector = useQuilttConnector;
|
|
@@ -0,0 +1,174 @@
|
|
|
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-VOH0S5zh.js';
|
|
5
|
+
import { u as useScript } from './useScript-12s-JCgaTW9n.js';
|
|
6
|
+
import { getUserAgent, isDeepEqual } from '../utils/index.js';
|
|
7
|
+
|
|
8
|
+
var version = "5.0.1";
|
|
9
|
+
|
|
10
|
+
const useQuilttConnector = (connectorId, options)=>{
|
|
11
|
+
const userAgent = getUserAgent(version);
|
|
12
|
+
const status = useScript(`${cdnBase}/v1/connector.js?agent=${encodeURIComponent(userAgent)}`, {
|
|
13
|
+
nonce: options?.nonce
|
|
14
|
+
});
|
|
15
|
+
// This ensures we're not destructuring `session` before the script has loaded
|
|
16
|
+
const useQuilttSessionReturn = useQuilttSession();
|
|
17
|
+
const session = useQuilttSessionReturn?.session || null;
|
|
18
|
+
const [connector, setConnector] = useState();
|
|
19
|
+
const [isOpening, setIsOpening] = useState(false);
|
|
20
|
+
// Keep track of the previous connectionId to detect changes
|
|
21
|
+
const prevConnectionIdRef = useRef(options?.connectionId);
|
|
22
|
+
const prevConnectorIdRef = useRef(connectorId);
|
|
23
|
+
const prevInstitutionRef = useRef(options?.institution);
|
|
24
|
+
const connectorCreatedRef = useRef(false);
|
|
25
|
+
// Track whether the connector is currently open
|
|
26
|
+
const isConnectorOpenRef = useRef(false);
|
|
27
|
+
// Store callbacks in refs to maintain stable references
|
|
28
|
+
const callbacksRef = useRef(options || {});
|
|
29
|
+
useEffect(()=>{
|
|
30
|
+
callbacksRef.current = options || {};
|
|
31
|
+
});
|
|
32
|
+
// Set Session
|
|
33
|
+
// biome-ignore lint/correctness/useExhaustiveDependencies: trigger effects when script status changes too
|
|
34
|
+
useEffect(()=>{
|
|
35
|
+
if (typeof Quiltt === 'undefined') return;
|
|
36
|
+
Quiltt.authenticate(session?.token);
|
|
37
|
+
}, [
|
|
38
|
+
status,
|
|
39
|
+
session?.token
|
|
40
|
+
]);
|
|
41
|
+
// Set Connector
|
|
42
|
+
// biome-ignore lint/correctness/useExhaustiveDependencies: trigger effects when script status changes too
|
|
43
|
+
useEffect(()=>{
|
|
44
|
+
if (typeof Quiltt === 'undefined' || !connectorId) return;
|
|
45
|
+
const currentConnectionId = options?.connectionId;
|
|
46
|
+
const currentInstitution = options?.institution;
|
|
47
|
+
// Check for changes - use deep equality for institution object
|
|
48
|
+
const connectionIdChanged = prevConnectionIdRef.current !== currentConnectionId;
|
|
49
|
+
const connectorIdChanged = prevConnectorIdRef.current !== connectorId;
|
|
50
|
+
const institutionChanged = !isDeepEqual(prevInstitutionRef.current, currentInstitution);
|
|
51
|
+
const hasChanges = connectionIdChanged || connectorIdChanged || institutionChanged || !connectorCreatedRef.current;
|
|
52
|
+
// Update if there are changes, regardless of what the changes are
|
|
53
|
+
if (hasChanges) {
|
|
54
|
+
if (currentConnectionId) {
|
|
55
|
+
// Always use reconnect when connectionId is available
|
|
56
|
+
setConnector(Quiltt.reconnect(connectorId, {
|
|
57
|
+
connectionId: currentConnectionId
|
|
58
|
+
}));
|
|
59
|
+
} else {
|
|
60
|
+
// Use connect for new connections without connectionId
|
|
61
|
+
setConnector(Quiltt.connect(connectorId, {
|
|
62
|
+
institution: currentInstitution
|
|
63
|
+
}));
|
|
64
|
+
}
|
|
65
|
+
// Update refs
|
|
66
|
+
connectorCreatedRef.current = true;
|
|
67
|
+
prevConnectionIdRef.current = currentConnectionId;
|
|
68
|
+
prevConnectorIdRef.current = connectorId;
|
|
69
|
+
prevInstitutionRef.current = currentInstitution;
|
|
70
|
+
}
|
|
71
|
+
}, [
|
|
72
|
+
connectorId,
|
|
73
|
+
options?.connectionId,
|
|
74
|
+
options?.institution,
|
|
75
|
+
status
|
|
76
|
+
]);
|
|
77
|
+
// Internal handlers to track connector state (stable references)
|
|
78
|
+
const handleOpen = useCallback((metadata)=>{
|
|
79
|
+
isConnectorOpenRef.current = true;
|
|
80
|
+
callbacksRef.current?.onOpen?.(metadata);
|
|
81
|
+
}, []);
|
|
82
|
+
const handleExit = useCallback((type, metadata)=>{
|
|
83
|
+
isConnectorOpenRef.current = false;
|
|
84
|
+
callbacksRef.current?.onExit?.(type, metadata);
|
|
85
|
+
}, []);
|
|
86
|
+
// Create stable wrapper functions for callbacks
|
|
87
|
+
const stableOnEvent = useCallback((type, metadata)=>{
|
|
88
|
+
callbacksRef.current?.onEvent?.(type, metadata);
|
|
89
|
+
}, []);
|
|
90
|
+
const stableOnLoad = useCallback((metadata)=>{
|
|
91
|
+
callbacksRef.current?.onLoad?.(metadata);
|
|
92
|
+
}, []);
|
|
93
|
+
const stableOnExitSuccess = useCallback((metadata)=>{
|
|
94
|
+
callbacksRef.current?.onExitSuccess?.(metadata);
|
|
95
|
+
}, []);
|
|
96
|
+
const stableOnExitAbort = useCallback((metadata)=>{
|
|
97
|
+
callbacksRef.current?.onExitAbort?.(metadata);
|
|
98
|
+
}, []);
|
|
99
|
+
const stableOnExitError = useCallback((metadata)=>{
|
|
100
|
+
callbacksRef.current?.onExitError?.(metadata);
|
|
101
|
+
}, []);
|
|
102
|
+
// Register event handlers (only re-runs when connector changes)
|
|
103
|
+
useEffect(()=>{
|
|
104
|
+
if (!connector) return;
|
|
105
|
+
// Capture which handlers we're registering to ensure proper cleanup
|
|
106
|
+
const registered = {
|
|
107
|
+
onEvent: callbacksRef.current?.onEvent ? stableOnEvent : null,
|
|
108
|
+
onOpen: callbacksRef.current?.onOpen ? handleOpen : null,
|
|
109
|
+
onLoad: callbacksRef.current?.onLoad ? stableOnLoad : null,
|
|
110
|
+
onExit: callbacksRef.current?.onExit ? handleExit : null,
|
|
111
|
+
onExitSuccess: callbacksRef.current?.onExitSuccess ? stableOnExitSuccess : null,
|
|
112
|
+
onExitAbort: callbacksRef.current?.onExitAbort ? stableOnExitAbort : null,
|
|
113
|
+
onExitError: callbacksRef.current?.onExitError ? stableOnExitError : null
|
|
114
|
+
};
|
|
115
|
+
if (registered.onEvent) connector.onEvent(registered.onEvent);
|
|
116
|
+
if (registered.onOpen) connector.onOpen(registered.onOpen);
|
|
117
|
+
if (registered.onLoad) connector.onLoad(registered.onLoad);
|
|
118
|
+
if (registered.onExit) connector.onExit(registered.onExit);
|
|
119
|
+
if (registered.onExitSuccess) connector.onExitSuccess(registered.onExitSuccess);
|
|
120
|
+
if (registered.onExitAbort) connector.onExitAbort(registered.onExitAbort);
|
|
121
|
+
if (registered.onExitError) connector.onExitError(registered.onExitError);
|
|
122
|
+
return ()=>{
|
|
123
|
+
if (registered.onEvent) connector.offEvent(registered.onEvent);
|
|
124
|
+
if (registered.onOpen) connector.offOpen(registered.onOpen);
|
|
125
|
+
if (registered.onLoad) connector.offLoad(registered.onLoad);
|
|
126
|
+
if (registered.onExit) connector.offExit(registered.onExit);
|
|
127
|
+
if (registered.onExitSuccess) connector.offExitSuccess(registered.onExitSuccess);
|
|
128
|
+
if (registered.onExitAbort) connector.offExitAbort(registered.onExitAbort);
|
|
129
|
+
if (registered.onExitError) connector.offExitError(registered.onExitError);
|
|
130
|
+
};
|
|
131
|
+
}, [
|
|
132
|
+
connector,
|
|
133
|
+
stableOnEvent,
|
|
134
|
+
handleOpen,
|
|
135
|
+
stableOnLoad,
|
|
136
|
+
handleExit,
|
|
137
|
+
stableOnExitSuccess,
|
|
138
|
+
stableOnExitAbort,
|
|
139
|
+
stableOnExitError
|
|
140
|
+
]);
|
|
141
|
+
// This is used to hide any potential race conditions from usage; allowing
|
|
142
|
+
// interaction before the script may have loaded.
|
|
143
|
+
useEffect(()=>{
|
|
144
|
+
if (connector && isOpening) {
|
|
145
|
+
setIsOpening(false);
|
|
146
|
+
connector.open();
|
|
147
|
+
}
|
|
148
|
+
}, [
|
|
149
|
+
connector,
|
|
150
|
+
isOpening
|
|
151
|
+
]);
|
|
152
|
+
// Cleanup effect - runs when the hook is torn down
|
|
153
|
+
useEffect(()=>{
|
|
154
|
+
return ()=>{
|
|
155
|
+
if (isConnectorOpenRef.current) {
|
|
156
|
+
console.error('[Quiltt] useQuilttConnector: Component unmounted while Connector is still open. ' + 'This may lead to memory leaks or unexpected behavior. ' + 'Ensure the Connector is properly closed before component unmount.');
|
|
157
|
+
}
|
|
158
|
+
};
|
|
159
|
+
}, []);
|
|
160
|
+
const open = useCallback(()=>{
|
|
161
|
+
if (connectorId) {
|
|
162
|
+
setIsOpening(true);
|
|
163
|
+
} else {
|
|
164
|
+
throw new Error('Must provide `connectorId` to `open` Quiltt Connector with Method Call');
|
|
165
|
+
}
|
|
166
|
+
}, [
|
|
167
|
+
connectorId
|
|
168
|
+
]);
|
|
169
|
+
return {
|
|
170
|
+
open
|
|
171
|
+
};
|
|
172
|
+
};
|
|
173
|
+
|
|
174
|
+
export { useQuilttConnector as u };
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
var react = require('react');
|
|
3
|
+
var QuilttProviderRender12s = require('./QuilttProviderRender-12s-pvnc98Lj.cjs');
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Internal hook that detects when a Quiltt SDK component may be rendered
|
|
7
|
+
* in the same component as QuilttProvider, which is an anti-pattern that
|
|
8
|
+
* can cause memory context issues and unexpected behavior.
|
|
9
|
+
*
|
|
10
|
+
* **Limitation**: Due to React context propagation, this will trigger for ALL
|
|
11
|
+
* descendants of QuilttProvider, not just direct children. This means it may
|
|
12
|
+
* produce false positives for valid nested component patterns. However, the
|
|
13
|
+
* primary use case (same-component rendering) is reliably detected.
|
|
14
|
+
*
|
|
15
|
+
* When the flag is set, this hook will emit a console error. This primarily
|
|
16
|
+
* helps catch the anti-pattern but may also flag valid nested structures.
|
|
17
|
+
*
|
|
18
|
+
* @param componentName - The name of the component calling this hook (for error messages)
|
|
19
|
+
*/ const useQuilttRenderGuard = (componentName)=>{
|
|
20
|
+
const { isRenderingProvider } = react.useContext(QuilttProviderRender12s.QuilttProviderRender);
|
|
21
|
+
const hasWarnedRef = react.useRef(false);
|
|
22
|
+
react.useEffect(()=>{
|
|
23
|
+
// Only run in development mode and warn once per component instance
|
|
24
|
+
const isProduction = process.env.NODE_ENV === 'production';
|
|
25
|
+
if (isProduction) return;
|
|
26
|
+
if (isRenderingProvider && !hasWarnedRef.current) {
|
|
27
|
+
hasWarnedRef.current = true;
|
|
28
|
+
console.error(`[Quiltt] ⚠️ POTENTIAL ANTI-PATTERN: ${componentName} may be rendered in the same component as QuilttProvider.\n\n` + `NOTE: This check uses a simple flag and may produce false positives for valid nested patterns.\n` + `If ${componentName} is in a SEPARATE component from QuilttProvider, you can safely ignore this.\n\n` + `The ANTI-PATTERN we're trying to catch:\n` + ` • Rendering Provider and SDK components in the SAME function component\n` + ` • This causes memory context issues because they run at the same React execution layer\n` + ` • React cannot properly manage the context hierarchy in this case\n\n` + `RECOMMENDED PATTERN:\n` + ` • Move QuilttProvider to a parent component or layout\n` + ` • Render ${componentName} in a child component\n\n` + `Example:\n\n` + ` // ✅ CORRECT: Provider in parent, SDK component in child (separate components)\n` + ` function Providers({ children }) {\n` + ` return (\n` + ` <QuilttProvider token={token}>\n` + ` {children}\n` + ` </QuilttProvider>\n` + ` )\n` + ` }\n\n` + ` function MyFeature() {\n` + ` return <${componentName} connectorId="..." />\n` + ` }\n\n` + ` // ❌ ANTI-PATTERN: Both in SAME component\n` + ` function MyFeature() {\n` + ` return (\n` + ` <QuilttProvider token={token}>\n` + ` <${componentName} connectorId="..." />\n` + ` </QuilttProvider>\n` + ` )\n` + ` }\n\n` + `Learn more:\n` + ` • https://github.com/quiltt/quiltt-js/tree/main/packages/react#provider-usage\n` + ` • https://react.dev/reference/react/useContext#my-component-doesnt-see-the-value-from-my-provider`);
|
|
29
|
+
}
|
|
30
|
+
}, [
|
|
31
|
+
isRenderingProvider,
|
|
32
|
+
componentName
|
|
33
|
+
]);
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
exports.useQuilttRenderGuard = useQuilttRenderGuard;
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
var react = require('react');
|
|
3
|
+
var core = require('@quiltt/core');
|
|
4
|
+
var useQuilttSettings12s = require('./useQuilttSettings-12s-aDLXY6z3.cjs');
|
|
5
|
+
var useSession12s = require('./useSession-12s-BNotXj5T.cjs');
|
|
6
|
+
|
|
7
|
+
const useAuthenticateSession = (auth, setSession)=>{
|
|
8
|
+
const authenticateSession = react.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 = react.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 = react.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 = core.JsonWebTokenParse(token);
|
|
67
|
+
// Is this token a valid JWT?
|
|
68
|
+
if (!jwt) return false;
|
|
69
|
+
// Is this token active?
|
|
70
|
+
const response = await auth.ping(token);
|
|
71
|
+
switch(response.status){
|
|
72
|
+
case 200:
|
|
73
|
+
setSession(token);
|
|
74
|
+
return true;
|
|
75
|
+
case 401:
|
|
76
|
+
return false;
|
|
77
|
+
default:
|
|
78
|
+
throw new Error(`AuthAPI.ping: Unexpected response status ${response.status}`);
|
|
79
|
+
}
|
|
80
|
+
}, [
|
|
81
|
+
auth,
|
|
82
|
+
session,
|
|
83
|
+
setSession,
|
|
84
|
+
environmentId
|
|
85
|
+
]);
|
|
86
|
+
return importSession;
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
const useRevokeSession = (auth, session, setSession)=>{
|
|
90
|
+
const revokeSession = react.useCallback(async ()=>{
|
|
91
|
+
if (!session) return;
|
|
92
|
+
await auth.revoke(session.token);
|
|
93
|
+
setSession(null);
|
|
94
|
+
}, [
|
|
95
|
+
auth,
|
|
96
|
+
session,
|
|
97
|
+
setSession
|
|
98
|
+
]);
|
|
99
|
+
return revokeSession;
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
const useQuilttSession = (environmentId)=>{
|
|
103
|
+
const { clientId } = useQuilttSettings12s.useQuilttSettings();
|
|
104
|
+
const [session, setSession] = useSession12s.useSession();
|
|
105
|
+
const auth = react.useMemo(()=>new core.AuthAPI(clientId), [
|
|
106
|
+
clientId
|
|
107
|
+
]);
|
|
108
|
+
const importSession = useImportSession(auth, session, setSession, environmentId);
|
|
109
|
+
const identifySession = useIdentifySession(auth, setSession);
|
|
110
|
+
const authenticateSession = useAuthenticateSession(auth, setSession);
|
|
111
|
+
const revokeSession = useRevokeSession(auth, session, setSession);
|
|
112
|
+
/**
|
|
113
|
+
* Forget current session.
|
|
114
|
+
* @param token specific token to forget, to help guard against async processes clearing the wrong session
|
|
115
|
+
*/ const forgetSession = react.useCallback(async (token)=>{
|
|
116
|
+
if (!token || session && token && token === session.token) {
|
|
117
|
+
setSession(null);
|
|
118
|
+
}
|
|
119
|
+
}, [
|
|
120
|
+
session,
|
|
121
|
+
setSession
|
|
122
|
+
]);
|
|
123
|
+
return {
|
|
124
|
+
session,
|
|
125
|
+
importSession,
|
|
126
|
+
identifySession,
|
|
127
|
+
authenticateSession,
|
|
128
|
+
revokeSession,
|
|
129
|
+
forgetSession
|
|
130
|
+
};
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
exports.useQuilttSession = useQuilttSession;
|
|
@@ -0,0 +1,133 @@
|
|
|
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-BNPsfKY-.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 active?
|
|
70
|
+
const response = await auth.ping(token);
|
|
71
|
+
switch(response.status){
|
|
72
|
+
case 200:
|
|
73
|
+
setSession(token);
|
|
74
|
+
return true;
|
|
75
|
+
case 401:
|
|
76
|
+
return false;
|
|
77
|
+
default:
|
|
78
|
+
throw new Error(`AuthAPI.ping: Unexpected response status ${response.status}`);
|
|
79
|
+
}
|
|
80
|
+
}, [
|
|
81
|
+
auth,
|
|
82
|
+
session,
|
|
83
|
+
setSession,
|
|
84
|
+
environmentId
|
|
85
|
+
]);
|
|
86
|
+
return importSession;
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
const useRevokeSession = (auth, session, setSession)=>{
|
|
90
|
+
const revokeSession = useCallback(async ()=>{
|
|
91
|
+
if (!session) return;
|
|
92
|
+
await auth.revoke(session.token);
|
|
93
|
+
setSession(null);
|
|
94
|
+
}, [
|
|
95
|
+
auth,
|
|
96
|
+
session,
|
|
97
|
+
setSession
|
|
98
|
+
]);
|
|
99
|
+
return revokeSession;
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
const useQuilttSession = (environmentId)=>{
|
|
103
|
+
const { clientId } = useQuilttSettings();
|
|
104
|
+
const [session, setSession] = useSession();
|
|
105
|
+
const auth = useMemo(()=>new AuthAPI(clientId), [
|
|
106
|
+
clientId
|
|
107
|
+
]);
|
|
108
|
+
const importSession = useImportSession(auth, session, setSession, environmentId);
|
|
109
|
+
const identifySession = useIdentifySession(auth, setSession);
|
|
110
|
+
const authenticateSession = useAuthenticateSession(auth, setSession);
|
|
111
|
+
const revokeSession = useRevokeSession(auth, session, setSession);
|
|
112
|
+
/**
|
|
113
|
+
* Forget current session.
|
|
114
|
+
* @param token specific token to forget, to help guard against async processes clearing the wrong session
|
|
115
|
+
*/ const forgetSession = useCallback(async (token)=>{
|
|
116
|
+
if (!token || session && token && token === session.token) {
|
|
117
|
+
setSession(null);
|
|
118
|
+
}
|
|
119
|
+
}, [
|
|
120
|
+
session,
|
|
121
|
+
setSession
|
|
122
|
+
]);
|
|
123
|
+
return {
|
|
124
|
+
session,
|
|
125
|
+
importSession,
|
|
126
|
+
identifySession,
|
|
127
|
+
authenticateSession,
|
|
128
|
+
revokeSession,
|
|
129
|
+
forgetSession
|
|
130
|
+
};
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
export { useQuilttSession as u };
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
var react = require('react');
|
|
3
|
+
var QuilttSettings12s = require('./QuilttSettings-12s-cLPT_GLC.cjs');
|
|
4
|
+
|
|
5
|
+
const useQuilttSettings = ()=>{
|
|
6
|
+
const settings = react.useContext(QuilttSettings12s.QuilttSettings);
|
|
7
|
+
return settings;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
exports.useQuilttSettings = useQuilttSettings;
|