@thunderid/react 1.11.3 → 1.12.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/dist/cjs/components/auth/DeviceGrant/DeviceGrant.cjs +220 -28
- package/dist/cjs/components/auth/DeviceGrant/DeviceGrant.cjs.map +1 -1
- package/dist/cjs/components/auth/SignIn/SignIn.cjs +3 -19
- package/dist/cjs/components/auth/SignIn/SignIn.cjs.map +1 -1
- package/dist/cjs/index.cjs +1 -1
- package/dist/components/auth/DeviceGrant/DeviceGrant.d.ts +2 -0
- package/dist/components/auth/DeviceGrant/DeviceGrant.d.ts.map +1 -1
- package/dist/components/auth/DeviceGrant/DeviceGrant.js +221 -29
- package/dist/components/auth/DeviceGrant/DeviceGrant.js.map +1 -1
- package/dist/components/auth/SignIn/SignIn.d.ts.map +1 -1
- package/dist/components/auth/SignIn/SignIn.js +4 -20
- package/dist/components/auth/SignIn/SignIn.js.map +1 -1
- package/dist/index.js +1 -1
- package/package.json +2 -2
|
@@ -3,6 +3,8 @@ const require_useThunderID = require('../../../contexts/ThunderID/useThunderID.c
|
|
|
3
3
|
const require_useTranslation = require('../../../hooks/useTranslation.cjs');
|
|
4
4
|
const require_flowTransformer = require('../../../utils/flowTransformer.cjs');
|
|
5
5
|
const require_BaseDeviceGrant = require('./BaseDeviceGrant.cjs');
|
|
6
|
+
const require_useOAuthCallback = require('../../../hooks/auth/useOAuthCallback.cjs');
|
|
7
|
+
const require_oauth = require('../../../utils/oauth.cjs');
|
|
6
8
|
let __thunderid_browser = require("@thunderid/browser");
|
|
7
9
|
__thunderid_browser = require_rolldown_runtime.__toESM(__thunderid_browser);
|
|
8
10
|
let react = require("react");
|
|
@@ -11,6 +13,10 @@ let react_jsx_runtime = require("react/jsx-runtime");
|
|
|
11
13
|
react_jsx_runtime = require_rolldown_runtime.__toESM(react_jsx_runtime);
|
|
12
14
|
|
|
13
15
|
//#region src/components/auth/DeviceGrant/DeviceGrant.tsx
|
|
16
|
+
const toDeviceGrantError = (cause, fallbackMessage) => {
|
|
17
|
+
if (cause instanceof __thunderid_browser.ThunderIDAPIError || cause instanceof __thunderid_browser.ThunderIDRuntimeError) return cause;
|
|
18
|
+
return new __thunderid_browser.ThunderIDRuntimeError(cause instanceof Error ? cause.message : fallbackMessage, "DEVICE_GRANT_ERROR", "react", cause);
|
|
19
|
+
};
|
|
14
20
|
const clearVerificationParameters = () => {
|
|
15
21
|
if (!window.location.href) return;
|
|
16
22
|
const url = new URL(window.location.href);
|
|
@@ -19,11 +25,51 @@ const clearVerificationParameters = () => {
|
|
|
19
25
|
window.history.replaceState(window.history.state, "", url.toString());
|
|
20
26
|
};
|
|
21
27
|
const hasUserCodeInput = (components) => components.some((component) => component.ref === "user_code" || Array.isArray(component.components) && hasUserCodeInput(component.components));
|
|
28
|
+
const findAction = (components, actionId) => {
|
|
29
|
+
for (const component of components) {
|
|
30
|
+
if (component.id === actionId) return component;
|
|
31
|
+
if (component.components) {
|
|
32
|
+
const nestedAction = findAction(component.components, actionId);
|
|
33
|
+
if (nestedAction) return nestedAction;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
const parseConsentPurposes = (value) => {
|
|
38
|
+
let parsed = value;
|
|
39
|
+
if (typeof parsed === "string") try {
|
|
40
|
+
parsed = JSON.parse(parsed);
|
|
41
|
+
} catch {
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
44
|
+
if (Array.isArray(parsed)) return parsed;
|
|
45
|
+
if (typeof parsed === "object" && parsed !== null && "purposes" in parsed && Array.isArray(parsed.purposes)) return parsed.purposes;
|
|
46
|
+
return null;
|
|
47
|
+
};
|
|
48
|
+
const CONSENT_REASON_KEY = "__consent_reason__";
|
|
49
|
+
const flattenComponents = (items) => items.flatMap((component) => [component, ...flattenComponents(component.components ?? [])]);
|
|
50
|
+
const findConsentSubmitActionId = (items) => {
|
|
51
|
+
const actions = flattenComponents(items).filter((component) => component.id && component.eventType?.toUpperCase() === "SUBMIT");
|
|
52
|
+
return (actions.find((component) => component.variant?.toLowerCase() !== "primary") ?? actions[0])?.id;
|
|
53
|
+
};
|
|
54
|
+
const compileConsentInputs = (inputs, actionId, components, additionalData) => {
|
|
55
|
+
const action = actionId ? findAction(components, actionId) : void 0;
|
|
56
|
+
const purposes = parseConsentPurposes(additionalData["consentPrompt"]);
|
|
57
|
+
const consentReason = inputs[CONSENT_REASON_KEY];
|
|
58
|
+
const cleanInputs = { ...inputs };
|
|
59
|
+
delete cleanInputs[CONSENT_REASON_KEY];
|
|
60
|
+
const isSubmitAction = Boolean(action && action.eventType?.toUpperCase() !== "TRIGGER");
|
|
61
|
+
const isTimeout = consentReason === __thunderid_browser.ConsentConstants.REASON_TIMEOUT;
|
|
62
|
+
const isDeny = isTimeout || Boolean(action && isSubmitAction && action.variant?.toLowerCase() !== "primary");
|
|
63
|
+
return (0, __thunderid_browser.compileConsentDecisions)(cleanInputs, isSubmitAction ? purposes : null, {
|
|
64
|
+
approved: !isDeny,
|
|
65
|
+
...isTimeout ? { reason: __thunderid_browser.ConsentConstants.REASON_TIMEOUT } : isDeny ? { reason: __thunderid_browser.ConsentConstants.REASON_USER_DENIED } : {}
|
|
66
|
+
});
|
|
67
|
+
};
|
|
22
68
|
/**
|
|
23
69
|
* Runs the application's configured Device Grant flow and exposes its state for custom renderers.
|
|
24
70
|
*/
|
|
25
71
|
const DeviceGrant = ({ children = void 0, className = "", onComplete = void 0, onError = void 0, preferences = {}, size = "medium", variant = "default",...baseProps }) => {
|
|
26
|
-
const { applicationId, baseUrl, meta } = require_useThunderID.default();
|
|
72
|
+
const { applicationId, baseUrl, getStorageManager, isInitialized, isLoading: sdkLoading, meta, vendor } = require_useThunderID.default();
|
|
27
73
|
const { t } = require_useTranslation.default(preferences?.i18n);
|
|
28
74
|
const [components, setComponents] = (0, react.useState)([]);
|
|
29
75
|
const [additionalData, setAdditionalData] = (0, react.useState)({});
|
|
@@ -31,14 +77,56 @@ const DeviceGrant = ({ children = void 0, className = "", onComplete = void 0, o
|
|
|
31
77
|
const [serverFieldErrors, setServerFieldErrors] = (0, react.useState)(null);
|
|
32
78
|
const [executionId, setExecutionId] = (0, react.useState)("");
|
|
33
79
|
const [challengeToken, setChallengeToken] = (0, react.useState)("");
|
|
80
|
+
const [isStorageReady, setIsStorageReady] = (0, react.useState)(false);
|
|
81
|
+
const challengeTokenRef = (0, react.useRef)("");
|
|
34
82
|
const [error, setError] = (0, react.useState)(null);
|
|
35
83
|
const [isLoading, setIsLoading] = (0, react.useState)(() => {
|
|
84
|
+
if (typeof window !== "undefined" && [
|
|
85
|
+
"code",
|
|
86
|
+
"state",
|
|
87
|
+
"error"
|
|
88
|
+
].some((parameter) => new URL(window.location.href).searchParams.has(parameter))) return false;
|
|
36
89
|
if (applicationId) return true;
|
|
37
90
|
return typeof window !== "undefined" && Boolean(new URL(window.location.href).searchParams.get("applicationId"));
|
|
38
91
|
});
|
|
39
92
|
const [result, setResult] = (0, react.useState)(null);
|
|
93
|
+
const [isTimeoutDisabled, setIsTimeoutDisabled] = (0, react.useState)(false);
|
|
40
94
|
const flowStartAttempted = (0, react.useRef)(false);
|
|
41
95
|
const verificationParametersRead = (0, react.useRef)(false);
|
|
96
|
+
const oauthCodeProcessedRef = (0, react.useRef)(false);
|
|
97
|
+
const executionIdStorageKey = `${vendor}_device_grant_execution_id`;
|
|
98
|
+
(0, react.useEffect)(() => {
|
|
99
|
+
if (!isInitialized || sdkLoading) return;
|
|
100
|
+
(async () => {
|
|
101
|
+
try {
|
|
102
|
+
const storedChallengeToken = (await (await getStorageManager?.())?.getTemporaryData())?.["challengeToken"];
|
|
103
|
+
if (typeof storedChallengeToken === "string") {
|
|
104
|
+
challengeTokenRef.current = storedChallengeToken;
|
|
105
|
+
setChallengeToken(storedChallengeToken);
|
|
106
|
+
}
|
|
107
|
+
} catch {} finally {
|
|
108
|
+
setIsStorageReady(true);
|
|
109
|
+
}
|
|
110
|
+
})();
|
|
111
|
+
}, [
|
|
112
|
+
getStorageManager,
|
|
113
|
+
isInitialized,
|
|
114
|
+
sdkLoading
|
|
115
|
+
]);
|
|
116
|
+
const persistExecutionId = (0, react.useCallback)((id) => {
|
|
117
|
+
setExecutionId(id ?? "");
|
|
118
|
+
if (id) sessionStorage.setItem(executionIdStorageKey, id);
|
|
119
|
+
else sessionStorage.removeItem(executionIdStorageKey);
|
|
120
|
+
}, [executionIdStorageKey]);
|
|
121
|
+
const persistChallengeToken = (0, react.useCallback)(async (token) => {
|
|
122
|
+
challengeTokenRef.current = token ?? "";
|
|
123
|
+
setChallengeToken(token ?? "");
|
|
124
|
+
try {
|
|
125
|
+
const storageManager = await getStorageManager();
|
|
126
|
+
if (storageManager) if (token) await storageManager.setTemporaryDataParameter("challengeToken", token);
|
|
127
|
+
else await storageManager.removeTemporaryDataParameter("challengeToken");
|
|
128
|
+
} catch {}
|
|
129
|
+
}, [getStorageManager]);
|
|
42
130
|
const handleError = (0, react.useCallback)((flowError) => {
|
|
43
131
|
setComponents([]);
|
|
44
132
|
setAdditionalData({});
|
|
@@ -47,15 +135,23 @@ const DeviceGrant = ({ children = void 0, className = "", onComplete = void 0, o
|
|
|
47
135
|
setResult("failure");
|
|
48
136
|
onError?.(flowError);
|
|
49
137
|
}, [onError]);
|
|
50
|
-
const applyResponse = (0, react.useCallback)((response) => {
|
|
138
|
+
const applyResponse = (0, react.useCallback)(async (response) => {
|
|
139
|
+
const redirectURL = response.data?.["redirectURL"] ?? response.redirectUrl;
|
|
140
|
+
if (response.type === __thunderid_browser.EmbeddedSignInFlowType.Redirection && typeof redirectURL === "string") {
|
|
141
|
+
persistExecutionId(response.executionId ?? null);
|
|
142
|
+
await persistChallengeToken(response.challengeToken ?? null);
|
|
143
|
+
require_oauth.initiateOAuthRedirect(redirectURL, vendor);
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
51
146
|
const normalized = require_flowTransformer.normalizeFlowResponse(response, t, {
|
|
52
147
|
throwOnError: false,
|
|
53
148
|
resolveTranslations: false
|
|
54
149
|
}, meta);
|
|
55
|
-
|
|
56
|
-
|
|
150
|
+
persistExecutionId(response.flowStatus === __thunderid_browser.EmbeddedSignInFlowStatus.Incomplete ? response.executionId ?? null : null);
|
|
151
|
+
await persistChallengeToken(response.flowStatus === __thunderid_browser.EmbeddedSignInFlowStatus.Incomplete ? response.challengeToken ?? null : null);
|
|
57
152
|
setComponents(normalized.components);
|
|
58
153
|
setAdditionalData(normalized.additionalData);
|
|
154
|
+
setIsTimeoutDisabled(false);
|
|
59
155
|
setServerFieldErrors(response.data?.fieldErrors ?? null);
|
|
60
156
|
setError(response.error ? new Error(require_flowTransformer.extractErrorMessage(response, t)) : null);
|
|
61
157
|
if (response.flowStatus === __thunderid_browser.EmbeddedSignInFlowStatus.Complete) {
|
|
@@ -64,7 +160,7 @@ const DeviceGrant = ({ children = void 0, className = "", onComplete = void 0, o
|
|
|
64
160
|
return;
|
|
65
161
|
}
|
|
66
162
|
if (response.flowStatus === __thunderid_browser.EmbeddedSignInFlowStatus.Error) {
|
|
67
|
-
const flowError = new
|
|
163
|
+
const flowError = new __thunderid_browser.ThunderIDRuntimeError(require_flowTransformer.extractErrorMessage(response, t, "deviceGrant.messages.failed"), "DEVICE_GRANT_ERROR", "react");
|
|
68
164
|
setError(flowError);
|
|
69
165
|
setResult("failure");
|
|
70
166
|
onError?.(flowError);
|
|
@@ -75,24 +171,41 @@ const DeviceGrant = ({ children = void 0, className = "", onComplete = void 0, o
|
|
|
75
171
|
meta,
|
|
76
172
|
onComplete,
|
|
77
173
|
onError,
|
|
78
|
-
|
|
174
|
+
persistChallengeToken,
|
|
175
|
+
persistExecutionId,
|
|
176
|
+
t,
|
|
177
|
+
vendor
|
|
79
178
|
]);
|
|
80
|
-
const startFlow = (0, react.useCallback)(async (appId) => {
|
|
179
|
+
const startFlow = (0, react.useCallback)(async (appId, resumeId) => {
|
|
81
180
|
setIsLoading(true);
|
|
82
181
|
setError(null);
|
|
83
182
|
try {
|
|
84
|
-
const
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
183
|
+
const challengeFromStorage = challengeTokenRef.current;
|
|
184
|
+
let response;
|
|
185
|
+
try {
|
|
186
|
+
response = await (0, __thunderid_browser.executeEmbeddedDeviceGrantFlow)({
|
|
187
|
+
baseUrl,
|
|
188
|
+
payload: resumeId ? {
|
|
189
|
+
executionId: resumeId,
|
|
190
|
+
...challengeFromStorage ? { challengeToken: challengeFromStorage } : {}
|
|
191
|
+
} : {
|
|
192
|
+
applicationId: appId,
|
|
193
|
+
flowType: __thunderid_browser.EmbeddedFlowType.DeviceGrant,
|
|
194
|
+
inputs: {}
|
|
195
|
+
}
|
|
196
|
+
});
|
|
197
|
+
} catch (resumeError) {
|
|
198
|
+
if (resumeId && resumeError instanceof __thunderid_browser.ThunderIDAPIError && resumeError.statusCode === 400) {
|
|
199
|
+
persistExecutionId(null);
|
|
200
|
+
await persistChallengeToken(null);
|
|
201
|
+
throw new __thunderid_browser.ThunderIDRuntimeError(t("deviceGrant.errors.continue"), "DEVICE_GRANT_ERROR", "react");
|
|
90
202
|
}
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
203
|
+
throw resumeError;
|
|
204
|
+
}
|
|
205
|
+
if (!resumeId) clearVerificationParameters();
|
|
206
|
+
await applyResponse(response);
|
|
94
207
|
} catch (flowError) {
|
|
95
|
-
handleError(flowError
|
|
208
|
+
handleError(toDeviceGrantError(flowError, t("deviceGrant.errors.continue")));
|
|
96
209
|
} finally {
|
|
97
210
|
setIsLoading(false);
|
|
98
211
|
}
|
|
@@ -100,6 +213,8 @@ const DeviceGrant = ({ children = void 0, className = "", onComplete = void 0, o
|
|
|
100
213
|
applyResponse,
|
|
101
214
|
baseUrl,
|
|
102
215
|
handleError,
|
|
216
|
+
persistChallengeToken,
|
|
217
|
+
persistExecutionId,
|
|
103
218
|
t
|
|
104
219
|
]);
|
|
105
220
|
(0, react.useEffect)(() => {
|
|
@@ -111,17 +226,24 @@ const DeviceGrant = ({ children = void 0, className = "", onComplete = void 0, o
|
|
|
111
226
|
}
|
|
112
227
|
const applicationIdFromUrl = url.searchParams.get("applicationId");
|
|
113
228
|
const appId = applicationIdFromUrl?.trim() ? applicationIdFromUrl : applicationId;
|
|
229
|
+
const storedExecutionId = sessionStorage.getItem(executionIdStorageKey);
|
|
230
|
+
const hasOAuthCallback = url.searchParams.has("code") || url.searchParams.has("state") || url.searchParams.has("error");
|
|
231
|
+
if (!isInitialized || sdkLoading || !isStorageReady || hasOAuthCallback || oauthCodeProcessedRef.current) return;
|
|
114
232
|
if (flowStartAttempted.current) return;
|
|
115
|
-
if (!appId) {
|
|
233
|
+
if (!appId && !storedExecutionId) {
|
|
116
234
|
flowStartAttempted.current = true;
|
|
117
|
-
handleError(new
|
|
235
|
+
handleError(new __thunderid_browser.ThunderIDRuntimeError(t("deviceGrant.errors.start"), "DEVICE_GRANT_ERROR", "react"));
|
|
118
236
|
return;
|
|
119
237
|
}
|
|
120
238
|
flowStartAttempted.current = true;
|
|
121
|
-
startFlow(appId);
|
|
239
|
+
startFlow(appId ?? "", storedExecutionId ?? void 0);
|
|
122
240
|
}, [
|
|
123
241
|
applicationId,
|
|
242
|
+
executionIdStorageKey,
|
|
124
243
|
handleError,
|
|
244
|
+
isInitialized,
|
|
245
|
+
isStorageReady,
|
|
246
|
+
sdkLoading,
|
|
125
247
|
startFlow,
|
|
126
248
|
t
|
|
127
249
|
]);
|
|
@@ -131,24 +253,92 @@ const DeviceGrant = ({ children = void 0, className = "", onComplete = void 0, o
|
|
|
131
253
|
setResult(null);
|
|
132
254
|
try {
|
|
133
255
|
if (!executionId) return;
|
|
134
|
-
|
|
256
|
+
const action = payload.action ?? actionId;
|
|
257
|
+
const inputs = compileConsentInputs(payload.inputs ?? {}, action, components, additionalData);
|
|
258
|
+
if (!hasUserCodeInput(components)) inputs["user_code"] = void 0;
|
|
259
|
+
await applyResponse(await (0, __thunderid_browser.executeEmbeddedDeviceGrantFlow)({
|
|
135
260
|
baseUrl,
|
|
136
261
|
payload: {
|
|
137
|
-
action
|
|
138
|
-
challengeToken,
|
|
262
|
+
action,
|
|
263
|
+
challengeToken: challengeTokenRef.current || challengeToken,
|
|
139
264
|
executionId,
|
|
140
|
-
inputs
|
|
141
|
-
...Object.fromEntries(Object.entries(payload.inputs ?? {}).filter(([key]) => !key.startsWith("__consent_opt__"))),
|
|
142
|
-
...!hasUserCodeInput(components) ? { user_code: void 0 } : {}
|
|
143
|
-
}
|
|
265
|
+
inputs
|
|
144
266
|
}
|
|
145
267
|
}));
|
|
146
268
|
} catch (flowError) {
|
|
147
|
-
handleError(flowError
|
|
269
|
+
handleError(toDeviceGrantError(flowError, t("deviceGrant.errors.continue")));
|
|
148
270
|
} finally {
|
|
149
271
|
setIsLoading(false);
|
|
150
272
|
}
|
|
151
273
|
};
|
|
274
|
+
const timeoutContextRef = (0, react.useRef)({
|
|
275
|
+
components: [],
|
|
276
|
+
hasConsentPrompt: false,
|
|
277
|
+
submit
|
|
278
|
+
});
|
|
279
|
+
timeoutContextRef.current = {
|
|
280
|
+
components,
|
|
281
|
+
hasConsentPrompt: Boolean(additionalData["consentPrompt"]),
|
|
282
|
+
submit
|
|
283
|
+
};
|
|
284
|
+
const timeoutSubmittedForRef = (0, react.useRef)(null);
|
|
285
|
+
(0, react.useEffect)(() => {
|
|
286
|
+
const timeoutMs = Number(additionalData["stepTimeout"]) || 0;
|
|
287
|
+
if (timeoutMs <= 0 || !executionId) {
|
|
288
|
+
setIsTimeoutDisabled(false);
|
|
289
|
+
return;
|
|
290
|
+
}
|
|
291
|
+
const timerId = setTimeout(() => {
|
|
292
|
+
setIsTimeoutDisabled(true);
|
|
293
|
+
const expiredError = new __thunderid_browser.ThunderIDRuntimeError(t("errors.signin.timeout") || "Time allowed to complete the step has expired.", "DEVICE_GRANT_ERROR", "react");
|
|
294
|
+
const context = timeoutContextRef.current;
|
|
295
|
+
const actionId = context.hasConsentPrompt ? findConsentSubmitActionId(context.components) : void 0;
|
|
296
|
+
if (actionId && timeoutSubmittedForRef.current !== timeoutMs) {
|
|
297
|
+
timeoutSubmittedForRef.current = timeoutMs;
|
|
298
|
+
context.submit({
|
|
299
|
+
action: actionId,
|
|
300
|
+
inputs: { [CONSENT_REASON_KEY]: __thunderid_browser.ConsentConstants.REASON_TIMEOUT }
|
|
301
|
+
});
|
|
302
|
+
return;
|
|
303
|
+
}
|
|
304
|
+
handleError(expiredError);
|
|
305
|
+
}, Math.max(0, timeoutMs - Date.now()));
|
|
306
|
+
return () => clearTimeout(timerId);
|
|
307
|
+
}, [
|
|
308
|
+
additionalData,
|
|
309
|
+
executionId,
|
|
310
|
+
handleError,
|
|
311
|
+
t
|
|
312
|
+
]);
|
|
313
|
+
require_useOAuthCallback.useOAuthCallback({
|
|
314
|
+
currentExecutionId: executionId || null,
|
|
315
|
+
executionIdStorageKey,
|
|
316
|
+
isInitialized: isInitialized && !sdkLoading && isStorageReady,
|
|
317
|
+
isSubmitting: isLoading,
|
|
318
|
+
onError: (callbackError) => {
|
|
319
|
+
persistExecutionId(null);
|
|
320
|
+
persistChallengeToken(null);
|
|
321
|
+
handleError(toDeviceGrantError(callbackError, String(callbackError)));
|
|
322
|
+
},
|
|
323
|
+
onFlowChange: (response) => void applyResponse(response),
|
|
324
|
+
onSubmit: async ({ executionId: callbackExecutionId, inputs }) => {
|
|
325
|
+
setIsLoading(true);
|
|
326
|
+
try {
|
|
327
|
+
return await (0, __thunderid_browser.executeEmbeddedDeviceGrantFlow)({
|
|
328
|
+
baseUrl,
|
|
329
|
+
payload: {
|
|
330
|
+
challengeToken: challengeTokenRef.current || challengeToken,
|
|
331
|
+
executionId: callbackExecutionId,
|
|
332
|
+
inputs
|
|
333
|
+
}
|
|
334
|
+
});
|
|
335
|
+
} finally {
|
|
336
|
+
setIsLoading(false);
|
|
337
|
+
}
|
|
338
|
+
},
|
|
339
|
+
processedRef: oauthCodeProcessedRef,
|
|
340
|
+
setExecutionId: persistExecutionId
|
|
341
|
+
});
|
|
152
342
|
const handleBaseSubmit = (payload, component) => submit(payload, component.id);
|
|
153
343
|
const fieldErrors = (0, react.useMemo)(() => {
|
|
154
344
|
const errors = {};
|
|
@@ -164,6 +354,7 @@ const DeviceGrant = ({ children = void 0, className = "", onComplete = void 0, o
|
|
|
164
354
|
fieldErrors,
|
|
165
355
|
initialValues,
|
|
166
356
|
isLoading,
|
|
357
|
+
isTimeoutDisabled,
|
|
167
358
|
meta,
|
|
168
359
|
onSubmit: submit,
|
|
169
360
|
result
|
|
@@ -176,6 +367,7 @@ const DeviceGrant = ({ children = void 0, className = "", onComplete = void 0, o
|
|
|
176
367
|
error,
|
|
177
368
|
initialValues,
|
|
178
369
|
isLoading,
|
|
370
|
+
isTimeoutDisabled,
|
|
179
371
|
onError: handleError,
|
|
180
372
|
onSubmit: handleBaseSubmit,
|
|
181
373
|
preferences,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DeviceGrant.cjs","names":["DeviceGrant: FC<DeviceGrantProps>","useThunderID","useTranslation","normalizeFlowResponse","extractErrorMessage","EmbeddedSignInFlowStatus","EmbeddedFlowType","errors: Record<string, string>","BaseDeviceGrant"],"sources":["../../../../../src/components/auth/DeviceGrant/DeviceGrant.tsx"],"sourcesContent":["// Copyright 2025-2026 The ThunderID Authors\n// SPDX-License-Identifier: Apache-2.0\n\nimport {EmbeddedFlowType, EmbeddedSignInFlowStatus, executeEmbeddedDeviceGrantFlow} from '@thunderid/browser';\nimport type {EmbeddedFlowComponent, EmbeddedSignInFlowRequest, FlowMetadataResponse} from '@thunderid/browser';\nimport {useCallback, useEffect, useMemo, useRef, useState} from 'react';\nimport type {FC, ReactElement, ReactNode} from 'react';\nimport BaseDeviceGrant, {type BaseDeviceGrantProps, type DeviceGrantResult} from './BaseDeviceGrant';\nimport useThunderID from '../../../contexts/ThunderID/useThunderID';\nimport useTranslation from '../../../hooks/useTranslation';\nimport {extractErrorMessage, normalizeFlowResponse} from '../../../utils/flowTransformer';\n\ntype EmbeddedDeviceGrantFlowResponse = Awaited<ReturnType<typeof executeEmbeddedDeviceGrantFlow>>;\ntype DeviceGrantFieldError = NonNullable<EmbeddedDeviceGrantFlowResponse['data']['fieldErrors']>[number];\n\n/** Values exposed to consumers that provide custom Device Grant UI. */\nexport interface DeviceGrantRenderProps {\n /** Additional values returned for the active flow step. */\n additionalData: Record<string, unknown>;\n /** Components returned by the configured flow. */\n components: EmbeddedFlowComponent[];\n /** Current flow error, when one needs to be shown. */\n error: Error | null;\n /** First server validation message for each field. */\n fieldErrors: Record<string, string>;\n /** Values prefilled from the verification URI. */\n initialValues: Record<string, string>;\n /** Whether a flow request is in progress. */\n isLoading: boolean;\n /** Flow metadata used to resolve application-specific template values. */\n meta: FlowMetadataResponse | null;\n /** Submits user-code input or continues the active flow. */\n onSubmit: (payload: EmbeddedSignInFlowRequest) => Promise<void>;\n /** Terminal flow result when the flow has no configured prompt to render. */\n result: DeviceGrantResult;\n}\n\nexport type DeviceGrantProps = Omit<\n BaseDeviceGrantProps,\n 'children' | 'components' | 'error' | 'initialValues' | 'isLoading' | 'onSubmit' | 'result' | 'serverFieldErrors'\n> & {\n /** Render props for Gate or other consumers that provide their own flow UI. */\n children?: (props: DeviceGrantRenderProps) => ReactNode;\n onComplete?: (response: EmbeddedDeviceGrantFlowResponse) => void;\n};\n\nconst clearVerificationParameters = (): void => {\n if (!window.location.href) return;\n const url = new URL(window.location.href);\n url.searchParams.delete('user_code');\n url.searchParams.delete('applicationId');\n window.history.replaceState(window.history.state, '', url.toString());\n};\n\nconst hasUserCodeInput = (components: EmbeddedFlowComponent[]): boolean =>\n components.some(\n (component: EmbeddedFlowComponent) =>\n component.ref === 'user_code' || (Array.isArray(component.components) && hasUserCodeInput(component.components)),\n );\n\n/**\n * Runs the application's configured Device Grant flow and exposes its state for custom renderers.\n */\nconst DeviceGrant: FC<DeviceGrantProps> = ({\n children = undefined,\n className = '',\n onComplete = undefined,\n onError = undefined,\n preferences = {},\n size = 'medium',\n variant = 'default',\n ...baseProps\n}: DeviceGrantProps): ReactElement => {\n const {applicationId, baseUrl, meta} = useThunderID();\n const {t} = useTranslation(preferences?.i18n);\n const [components, setComponents] = useState<EmbeddedFlowComponent[]>([]);\n const [additionalData, setAdditionalData] = useState<Record<string, unknown>>({});\n const [initialValues, setInitialValues] = useState<Record<string, string>>({});\n const [serverFieldErrors, setServerFieldErrors] = useState<\n EmbeddedDeviceGrantFlowResponse['data']['fieldErrors'] | null\n >(null);\n const [executionId, setExecutionId] = useState('');\n const [challengeToken, setChallengeToken] = useState('');\n const [error, setError] = useState<Error | null>(null);\n const [isLoading, setIsLoading] = useState(() => {\n if (applicationId) return true;\n return typeof window !== 'undefined' && Boolean(new URL(window.location.href).searchParams.get('applicationId'));\n });\n const [result, setResult] = useState<DeviceGrantResult>(null);\n const flowStartAttempted = useRef(false);\n const verificationParametersRead = useRef(false);\n\n const handleError = useCallback(\n (flowError: Error): void => {\n setComponents([]);\n setAdditionalData({});\n setServerFieldErrors(null);\n setError(flowError);\n setResult('failure');\n onError?.(flowError);\n },\n [onError],\n );\n\n const applyResponse = useCallback(\n (response: EmbeddedDeviceGrantFlowResponse): void => {\n const normalized = normalizeFlowResponse(\n response,\n t,\n {\n throwOnError: false,\n resolveTranslations: false,\n },\n meta,\n );\n setExecutionId(response.executionId);\n setChallengeToken(response.challengeToken ?? '');\n setComponents(normalized.components);\n setAdditionalData(normalized.additionalData);\n setServerFieldErrors(response.data?.fieldErrors ?? null);\n setError(response.error ? new Error(extractErrorMessage(response, t)) : null);\n\n if (response.flowStatus === EmbeddedSignInFlowStatus.Complete) {\n setResult('success');\n onComplete?.(response);\n return;\n }\n\n if (response.flowStatus === EmbeddedSignInFlowStatus.Error) {\n const flowError = new Error(extractErrorMessage(response, t, 'deviceGrant.messages.failed'));\n setError(flowError);\n setResult('failure');\n onError?.(flowError);\n return;\n }\n\n setResult(null);\n },\n [meta, onComplete, onError, t],\n );\n\n const startFlow = useCallback(\n async (appId: string): Promise<void> => {\n setIsLoading(true);\n setError(null);\n try {\n const response = await executeEmbeddedDeviceGrantFlow({\n baseUrl,\n payload: {\n applicationId: appId,\n flowType: EmbeddedFlowType.DeviceGrant,\n inputs: {},\n },\n });\n clearVerificationParameters();\n applyResponse(response);\n } catch (flowError) {\n handleError(flowError instanceof Error ? flowError : new Error(t('deviceGrant.errors.continue')));\n } finally {\n setIsLoading(false);\n }\n },\n [applyResponse, baseUrl, handleError, t],\n );\n\n useEffect(() => {\n const url = new URL(window.location.href);\n if (!verificationParametersRead.current) {\n verificationParametersRead.current = true;\n const userCode = url.searchParams.get('user_code') ?? '';\n if (userCode) setInitialValues({user_code: userCode});\n }\n\n const applicationIdFromUrl = url.searchParams.get('applicationId');\n const appId = applicationIdFromUrl?.trim() ? applicationIdFromUrl : applicationId;\n if (flowStartAttempted.current) return;\n if (!appId) {\n flowStartAttempted.current = true;\n handleError(new Error(t('deviceGrant.errors.start')));\n return;\n }\n\n flowStartAttempted.current = true;\n void startFlow(appId);\n }, [applicationId, handleError, startFlow, t]);\n\n const submit = async (payload: EmbeddedSignInFlowRequest, actionId?: string): Promise<void> => {\n setIsLoading(true);\n setError(null);\n setResult(null);\n try {\n if (!executionId) return;\n\n const response = await executeEmbeddedDeviceGrantFlow({\n baseUrl,\n payload: {\n action: payload.action ?? actionId,\n challengeToken,\n executionId,\n inputs: {\n ...Object.fromEntries(\n Object.entries(payload.inputs ?? {}).filter(\n ([key]: [string, unknown]) => !key.startsWith('__consent_opt__'),\n ),\n ),\n ...(!hasUserCodeInput(components) ? {user_code: undefined} : {}),\n },\n },\n });\n applyResponse(response);\n } catch (flowError) {\n handleError(flowError instanceof Error ? flowError : new Error(t('deviceGrant.errors.continue')));\n } finally {\n setIsLoading(false);\n }\n };\n\n const handleBaseSubmit = (payload: EmbeddedSignInFlowRequest, component: EmbeddedFlowComponent): Promise<void> =>\n submit(payload, component.id);\n\n const fieldErrors = useMemo<Record<string, string>>(() => {\n const errors: Record<string, string> = {};\n (serverFieldErrors ?? []).forEach((fieldError: DeviceGrantFieldError) => {\n if (!(fieldError.identifier in errors)) errors[fieldError.identifier] = fieldError.message;\n });\n\n return errors;\n }, [serverFieldErrors]);\n\n if (children) {\n return (\n <>\n {children({\n additionalData,\n components,\n error,\n fieldErrors,\n initialValues,\n isLoading,\n meta,\n onSubmit: submit,\n result,\n })}\n </>\n );\n }\n\n return (\n <BaseDeviceGrant\n {...baseProps}\n className={className}\n components={components}\n additionalData={additionalData}\n error={error}\n initialValues={initialValues}\n isLoading={isLoading}\n onError={handleError}\n onSubmit={handleBaseSubmit}\n preferences={preferences}\n result={result}\n serverFieldErrors={serverFieldErrors}\n size={size}\n variant={variant}\n />\n );\n};\n\nexport default DeviceGrant;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"DeviceGrant.cjs","names":["ThunderIDAPIError","ThunderIDRuntimeError","parsed: unknown","actions: EmbeddedFlowComponent[]","consentReason: unknown","cleanInputs: Record<string, unknown>","ConsentConstants","DeviceGrant: FC<DeviceGrantProps>","useThunderID","useTranslation","EmbeddedSignInFlowType","normalizeFlowResponse","EmbeddedSignInFlowStatus","extractErrorMessage","response: EmbeddedDeviceGrantFlowResponse","EmbeddedFlowType","errors: Record<string, string>","BaseDeviceGrant"],"sources":["../../../../../src/components/auth/DeviceGrant/DeviceGrant.tsx"],"sourcesContent":["// Copyright 2025-2026 The ThunderID Authors\n// SPDX-License-Identifier: Apache-2.0\n\nimport {\n compileConsentDecisions,\n ConsentConstants,\n EmbeddedFlowType,\n EmbeddedSignInFlowStatus,\n EmbeddedSignInFlowType,\n ThunderIDAPIError,\n ThunderIDRuntimeError,\n executeEmbeddedDeviceGrantFlow,\n} from '@thunderid/browser';\nimport type {\n ConsentPurposeData,\n EmbeddedFlowComponent,\n EmbeddedSignInFlowRequest,\n FlowMetadataResponse,\n} from '@thunderid/browser';\nimport {useCallback, useEffect, useMemo, useRef, useState} from 'react';\nimport type {FC, ReactElement, ReactNode} from 'react';\nimport BaseDeviceGrant, {type BaseDeviceGrantProps, type DeviceGrantResult} from './BaseDeviceGrant';\nimport useThunderID from '../../../contexts/ThunderID/useThunderID';\nimport {useOAuthCallback} from '../../../hooks/auth/useOAuthCallback';\nimport useTranslation from '../../../hooks/useTranslation';\nimport {extractErrorMessage, normalizeFlowResponse} from '../../../utils/flowTransformer';\nimport {initiateOAuthRedirect} from '../../../utils/oauth';\n\ntype EmbeddedDeviceGrantFlowResponse = Awaited<ReturnType<typeof executeEmbeddedDeviceGrantFlow>>;\ntype DeviceGrantFieldError = NonNullable<EmbeddedDeviceGrantFlowResponse['data']['fieldErrors']>[number];\n\nconst toDeviceGrantError = (cause: unknown, fallbackMessage: string): Error => {\n if (cause instanceof ThunderIDAPIError || cause instanceof ThunderIDRuntimeError) return cause;\n return new ThunderIDRuntimeError(\n cause instanceof Error ? cause.message : fallbackMessage,\n 'DEVICE_GRANT_ERROR',\n 'react',\n cause,\n );\n};\n\n/** Values exposed to consumers that provide custom Device Grant UI. */\nexport interface DeviceGrantRenderProps {\n /** Additional values returned for the active flow step. */\n additionalData: Record<string, unknown>;\n /** Components returned by the configured flow. */\n components: EmbeddedFlowComponent[];\n /** Current flow error, when one needs to be shown. */\n error: Error | null;\n /** First server validation message for each field. */\n fieldErrors: Record<string, string>;\n /** Values prefilled from the verification URI. */\n initialValues: Record<string, string>;\n /** Whether a flow request is in progress. */\n isLoading: boolean;\n /** Whether the active flow step has expired. */\n isTimeoutDisabled: boolean;\n /** Flow metadata used to resolve application-specific template values. */\n meta: FlowMetadataResponse | null;\n /** Submits user-code input or continues the active flow. */\n onSubmit: (payload: EmbeddedSignInFlowRequest) => Promise<void>;\n /** Terminal flow result when the flow has no configured prompt to render. */\n result: DeviceGrantResult;\n}\n\nexport type DeviceGrantProps = Omit<\n BaseDeviceGrantProps,\n 'children' | 'components' | 'error' | 'initialValues' | 'isLoading' | 'onSubmit' | 'result' | 'serverFieldErrors'\n> & {\n /** Render props for Gate or other consumers that provide their own flow UI. */\n children?: (props: DeviceGrantRenderProps) => ReactNode;\n onComplete?: (response: EmbeddedDeviceGrantFlowResponse) => void;\n};\n\nconst clearVerificationParameters = (): void => {\n if (!window.location.href) return;\n const url = new URL(window.location.href);\n url.searchParams.delete('user_code');\n url.searchParams.delete('applicationId');\n window.history.replaceState(window.history.state, '', url.toString());\n};\n\nconst hasUserCodeInput = (components: EmbeddedFlowComponent[]): boolean =>\n components.some(\n (component: EmbeddedFlowComponent) =>\n component.ref === 'user_code' || (Array.isArray(component.components) && hasUserCodeInput(component.components)),\n );\n\nconst findAction = (components: EmbeddedFlowComponent[], actionId: string): EmbeddedFlowComponent | undefined => {\n for (const component of components) {\n if (component.id === actionId) return component;\n if (component.components) {\n const nestedAction = findAction(component.components, actionId);\n if (nestedAction) return nestedAction;\n }\n }\n return undefined;\n};\n\nconst parseConsentPurposes = (value: unknown): ConsentPurposeData[] | null => {\n let parsed: unknown = value;\n if (typeof parsed === 'string') {\n try {\n parsed = JSON.parse(parsed) as unknown;\n } catch {\n return null;\n }\n }\n if (Array.isArray(parsed)) return parsed as ConsentPurposeData[];\n if (typeof parsed === 'object' && parsed !== null && 'purposes' in parsed && Array.isArray(parsed.purposes)) {\n return parsed.purposes as ConsentPurposeData[];\n }\n return null;\n};\n\nconst CONSENT_REASON_KEY = '__consent_reason__';\n\nconst flattenComponents = (items: EmbeddedFlowComponent[]): EmbeddedFlowComponent[] =>\n items.flatMap((component: EmbeddedFlowComponent) => [component, ...flattenComponents(component.components ?? [])]);\n\nconst findConsentSubmitActionId = (items: EmbeddedFlowComponent[]): string | undefined => {\n const actions: EmbeddedFlowComponent[] = flattenComponents(items).filter(\n (component: EmbeddedFlowComponent) => component.id && component.eventType?.toUpperCase() === 'SUBMIT',\n );\n return (\n actions.find((component: EmbeddedFlowComponent) => component.variant?.toLowerCase() !== 'primary') ?? actions[0]\n )?.id;\n};\n\nconst compileConsentInputs = (\n inputs: Record<string, unknown>,\n actionId: string | undefined,\n components: EmbeddedFlowComponent[],\n additionalData: Record<string, unknown>,\n): Record<string, unknown> => {\n const action = actionId ? findAction(components, actionId) : undefined;\n const purposes = parseConsentPurposes(additionalData['consentPrompt']);\n const consentReason: unknown = inputs[CONSENT_REASON_KEY];\n const cleanInputs: Record<string, unknown> = {...inputs};\n delete cleanInputs[CONSENT_REASON_KEY];\n const isSubmitAction = Boolean(action && action.eventType?.toUpperCase() !== 'TRIGGER');\n const isTimeout = consentReason === ConsentConstants.REASON_TIMEOUT;\n const isDeny = isTimeout || Boolean(action && isSubmitAction && action.variant?.toLowerCase() !== 'primary');\n\n return compileConsentDecisions(cleanInputs, isSubmitAction ? purposes : null, {\n approved: !isDeny,\n ...(isTimeout\n ? {reason: ConsentConstants.REASON_TIMEOUT}\n : isDeny\n ? {reason: ConsentConstants.REASON_USER_DENIED}\n : {}),\n });\n};\n\n/**\n * Runs the application's configured Device Grant flow and exposes its state for custom renderers.\n */\nconst DeviceGrant: FC<DeviceGrantProps> = ({\n children = undefined,\n className = '',\n onComplete = undefined,\n onError = undefined,\n preferences = {},\n size = 'medium',\n variant = 'default',\n ...baseProps\n}: DeviceGrantProps): ReactElement => {\n const {\n applicationId,\n baseUrl,\n getStorageManager,\n isInitialized,\n isLoading: sdkLoading,\n meta,\n vendor,\n } = useThunderID();\n const {t} = useTranslation(preferences?.i18n);\n const [components, setComponents] = useState<EmbeddedFlowComponent[]>([]);\n const [additionalData, setAdditionalData] = useState<Record<string, unknown>>({});\n const [initialValues, setInitialValues] = useState<Record<string, string>>({});\n const [serverFieldErrors, setServerFieldErrors] = useState<\n EmbeddedDeviceGrantFlowResponse['data']['fieldErrors'] | null\n >(null);\n const [executionId, setExecutionId] = useState('');\n const [challengeToken, setChallengeToken] = useState('');\n const [isStorageReady, setIsStorageReady] = useState(false);\n const challengeTokenRef = useRef('');\n const [error, setError] = useState<Error | null>(null);\n const [isLoading, setIsLoading] = useState(() => {\n if (\n typeof window !== 'undefined' &&\n ['code', 'state', 'error'].some((parameter: string) => new URL(window.location.href).searchParams.has(parameter))\n ) {\n return false;\n }\n if (applicationId) return true;\n return typeof window !== 'undefined' && Boolean(new URL(window.location.href).searchParams.get('applicationId'));\n });\n const [result, setResult] = useState<DeviceGrantResult>(null);\n const [isTimeoutDisabled, setIsTimeoutDisabled] = useState(false);\n const flowStartAttempted = useRef(false);\n const verificationParametersRead = useRef(false);\n const oauthCodeProcessedRef = useRef(false);\n const executionIdStorageKey = `${vendor}_device_grant_execution_id`;\n\n useEffect(() => {\n if (!isInitialized || sdkLoading) return;\n void (async (): Promise<void> => {\n try {\n const storageManager = await getStorageManager?.();\n const temporaryData = await storageManager?.getTemporaryData();\n const storedChallengeToken = temporaryData?.['challengeToken'];\n if (typeof storedChallengeToken === 'string') {\n challengeTokenRef.current = storedChallengeToken;\n setChallengeToken(storedChallengeToken);\n }\n } catch {\n // Flow continuation can still proceed without a cached token if the server permits it.\n } finally {\n setIsStorageReady(true);\n }\n })();\n }, [getStorageManager, isInitialized, sdkLoading]);\n\n const persistExecutionId = useCallback(\n (id: string | null): void => {\n setExecutionId(id ?? '');\n if (id) sessionStorage.setItem(executionIdStorageKey, id);\n else sessionStorage.removeItem(executionIdStorageKey);\n },\n [executionIdStorageKey],\n );\n\n const persistChallengeToken = useCallback(\n async (token: string | null): Promise<void> => {\n challengeTokenRef.current = token ?? '';\n setChallengeToken(token ?? '');\n try {\n const storageManager = await getStorageManager();\n if (storageManager) {\n if (token) await storageManager.setTemporaryDataParameter('challengeToken', token);\n else await storageManager.removeTemporaryDataParameter('challengeToken');\n }\n } catch {\n // The in-memory value is still available for same-page flow continuation.\n }\n },\n [getStorageManager],\n );\n\n const handleError = useCallback(\n (flowError: Error): void => {\n setComponents([]);\n setAdditionalData({});\n setServerFieldErrors(null);\n setError(flowError);\n setResult('failure');\n onError?.(flowError);\n },\n [onError],\n );\n\n const applyResponse = useCallback(\n async (response: EmbeddedDeviceGrantFlowResponse): Promise<void> => {\n const redirectURL =\n (response.data as Record<string, unknown> | undefined)?.['redirectURL'] ?? response.redirectUrl;\n if (response.type === EmbeddedSignInFlowType.Redirection && typeof redirectURL === 'string') {\n persistExecutionId(response.executionId ?? null);\n await persistChallengeToken(response.challengeToken ?? null);\n initiateOAuthRedirect(redirectURL, vendor);\n return;\n }\n\n const normalized = normalizeFlowResponse(\n response,\n t,\n {\n throwOnError: false,\n resolveTranslations: false,\n },\n meta,\n );\n persistExecutionId(\n response.flowStatus === EmbeddedSignInFlowStatus.Incomplete ? (response.executionId ?? null) : null,\n );\n await persistChallengeToken(\n response.flowStatus === EmbeddedSignInFlowStatus.Incomplete ? (response.challengeToken ?? null) : null,\n );\n setComponents(normalized.components);\n setAdditionalData(normalized.additionalData);\n setIsTimeoutDisabled(false);\n setServerFieldErrors(response.data?.fieldErrors ?? null);\n setError(response.error ? new Error(extractErrorMessage(response, t)) : null);\n\n if (response.flowStatus === EmbeddedSignInFlowStatus.Complete) {\n setResult('success');\n onComplete?.(response);\n return;\n }\n\n if (response.flowStatus === EmbeddedSignInFlowStatus.Error) {\n const flowError = new ThunderIDRuntimeError(\n extractErrorMessage(response, t, 'deviceGrant.messages.failed'),\n 'DEVICE_GRANT_ERROR',\n 'react',\n );\n setError(flowError);\n setResult('failure');\n onError?.(flowError);\n return;\n }\n\n setResult(null);\n },\n [meta, onComplete, onError, persistChallengeToken, persistExecutionId, t, vendor],\n );\n\n const startFlow = useCallback(\n async (appId: string, resumeId?: string): Promise<void> => {\n setIsLoading(true);\n setError(null);\n try {\n const challengeFromStorage = challengeTokenRef.current;\n let response: EmbeddedDeviceGrantFlowResponse;\n try {\n response = await executeEmbeddedDeviceGrantFlow({\n baseUrl,\n payload: resumeId\n ? {executionId: resumeId, ...(challengeFromStorage ? {challengeToken: challengeFromStorage} : {})}\n : {applicationId: appId, flowType: EmbeddedFlowType.DeviceGrant, inputs: {}},\n });\n } catch (resumeError) {\n if (resumeId && resumeError instanceof ThunderIDAPIError && resumeError.statusCode === 400) {\n persistExecutionId(null);\n await persistChallengeToken(null);\n throw new ThunderIDRuntimeError(t('deviceGrant.errors.continue'), 'DEVICE_GRANT_ERROR', 'react');\n }\n throw resumeError;\n }\n if (!resumeId) clearVerificationParameters();\n await applyResponse(response);\n } catch (flowError) {\n handleError(toDeviceGrantError(flowError, t('deviceGrant.errors.continue')));\n } finally {\n setIsLoading(false);\n }\n },\n [applyResponse, baseUrl, handleError, persistChallengeToken, persistExecutionId, t],\n );\n\n useEffect(() => {\n const url = new URL(window.location.href);\n if (!verificationParametersRead.current) {\n verificationParametersRead.current = true;\n const userCode = url.searchParams.get('user_code') ?? '';\n if (userCode) setInitialValues({user_code: userCode});\n }\n\n const applicationIdFromUrl = url.searchParams.get('applicationId');\n const appId = applicationIdFromUrl?.trim() ? applicationIdFromUrl : applicationId;\n const storedExecutionId = sessionStorage.getItem(executionIdStorageKey);\n const hasOAuthCallback =\n url.searchParams.has('code') || url.searchParams.has('state') || url.searchParams.has('error');\n if (!isInitialized || sdkLoading || !isStorageReady || hasOAuthCallback || oauthCodeProcessedRef.current) return;\n if (flowStartAttempted.current) return;\n if (!appId && !storedExecutionId) {\n flowStartAttempted.current = true;\n handleError(new ThunderIDRuntimeError(t('deviceGrant.errors.start'), 'DEVICE_GRANT_ERROR', 'react'));\n return;\n }\n\n flowStartAttempted.current = true;\n void startFlow(appId ?? '', storedExecutionId ?? undefined);\n }, [applicationId, executionIdStorageKey, handleError, isInitialized, isStorageReady, sdkLoading, startFlow, t]);\n\n const submit = async (payload: EmbeddedSignInFlowRequest, actionId?: string): Promise<void> => {\n setIsLoading(true);\n setError(null);\n setResult(null);\n try {\n if (!executionId) return;\n\n const action = payload.action ?? actionId;\n const inputs = compileConsentInputs(payload.inputs ?? {}, action, components, additionalData);\n if (!hasUserCodeInput(components)) inputs['user_code'] = undefined;\n\n const response = await executeEmbeddedDeviceGrantFlow({\n baseUrl,\n payload: {\n action,\n challengeToken: challengeTokenRef.current || challengeToken,\n executionId,\n inputs,\n },\n });\n await applyResponse(response);\n } catch (flowError) {\n handleError(toDeviceGrantError(flowError, t('deviceGrant.errors.continue')));\n } finally {\n setIsLoading(false);\n }\n };\n\n const timeoutContextRef = useRef<{\n components: EmbeddedFlowComponent[];\n hasConsentPrompt: boolean;\n submit: typeof submit;\n }>({components: [], hasConsentPrompt: false, submit});\n timeoutContextRef.current = {components, hasConsentPrompt: Boolean(additionalData['consentPrompt']), submit};\n const timeoutSubmittedForRef = useRef<number | null>(null);\n\n useEffect(() => {\n const timeoutMs = Number(additionalData['stepTimeout']) || 0;\n if (timeoutMs <= 0 || !executionId) {\n setIsTimeoutDisabled(false);\n return undefined;\n }\n\n const timerId = setTimeout(\n () => {\n setIsTimeoutDisabled(true);\n const expiredError = new ThunderIDRuntimeError(\n t('errors.signin.timeout') || 'Time allowed to complete the step has expired.',\n 'DEVICE_GRANT_ERROR',\n 'react',\n );\n const context = timeoutContextRef.current;\n const actionId = context.hasConsentPrompt ? findConsentSubmitActionId(context.components) : undefined;\n if (actionId && timeoutSubmittedForRef.current !== timeoutMs) {\n timeoutSubmittedForRef.current = timeoutMs;\n void context.submit({action: actionId, inputs: {[CONSENT_REASON_KEY]: ConsentConstants.REASON_TIMEOUT}});\n return;\n }\n handleError(expiredError);\n },\n Math.max(0, timeoutMs - Date.now()),\n );\n\n return () => clearTimeout(timerId);\n }, [additionalData, executionId, handleError, t]);\n\n useOAuthCallback({\n currentExecutionId: executionId || null,\n executionIdStorageKey,\n isInitialized: isInitialized && !sdkLoading && isStorageReady,\n isSubmitting: isLoading,\n onError: (callbackError: unknown) => {\n persistExecutionId(null);\n void persistChallengeToken(null);\n handleError(toDeviceGrantError(callbackError, String(callbackError)));\n },\n onFlowChange: (response: EmbeddedDeviceGrantFlowResponse) => void applyResponse(response),\n onSubmit: async ({executionId: callbackExecutionId, inputs}) => {\n setIsLoading(true);\n try {\n return await executeEmbeddedDeviceGrantFlow({\n baseUrl,\n payload: {\n challengeToken: challengeTokenRef.current || challengeToken,\n executionId: callbackExecutionId,\n inputs,\n },\n });\n } finally {\n setIsLoading(false);\n }\n },\n processedRef: oauthCodeProcessedRef,\n setExecutionId: persistExecutionId,\n });\n\n const handleBaseSubmit = (payload: EmbeddedSignInFlowRequest, component: EmbeddedFlowComponent): Promise<void> =>\n submit(payload, component.id);\n\n const fieldErrors = useMemo<Record<string, string>>(() => {\n const errors: Record<string, string> = {};\n (serverFieldErrors ?? []).forEach((fieldError: DeviceGrantFieldError) => {\n if (!(fieldError.identifier in errors)) errors[fieldError.identifier] = fieldError.message;\n });\n\n return errors;\n }, [serverFieldErrors]);\n\n if (children) {\n return (\n <>\n {children({\n additionalData,\n components,\n error,\n fieldErrors,\n initialValues,\n isLoading,\n isTimeoutDisabled,\n meta,\n onSubmit: submit,\n result,\n })}\n </>\n );\n }\n\n return (\n <BaseDeviceGrant\n {...baseProps}\n className={className}\n components={components}\n additionalData={additionalData}\n error={error}\n initialValues={initialValues}\n isLoading={isLoading}\n isTimeoutDisabled={isTimeoutDisabled}\n onError={handleError}\n onSubmit={handleBaseSubmit}\n preferences={preferences}\n result={result}\n serverFieldErrors={serverFieldErrors}\n size={size}\n variant={variant}\n />\n );\n};\n\nexport default DeviceGrant;\n"],"mappings":"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"}
|
|
@@ -409,7 +409,7 @@ const SignIn = ({ className, preferences, size = "medium", onSuccess, onError, v
|
|
|
409
409
|
const handleSubmit = async (payload) => {
|
|
410
410
|
const effectiveExecutionId = payload.executionId || currentExecutionId;
|
|
411
411
|
if (!effectiveExecutionId) throw new Error("No active flow ID");
|
|
412
|
-
|
|
412
|
+
let processedInputs = { ...payload.inputs };
|
|
413
413
|
const consentReason = processedInputs[CONSENT_REASON_KEY];
|
|
414
414
|
delete processedInputs[CONSENT_REASON_KEY];
|
|
415
415
|
if (additionalData?.["consentPrompt"]) try {
|
|
@@ -433,25 +433,9 @@ const SignIn = ({ className, preferences, size = "medium", onSuccess, onError, v
|
|
|
433
433
|
if (consentReason === __thunderid_browser.ConsentConstants.REASON_TIMEOUT) isDeny = true;
|
|
434
434
|
if (!isDeny && require_isConsentApprovalBlocked.default(purposes, processedInputs)) return;
|
|
435
435
|
const reason = consentReason ?? (isDeny ? __thunderid_browser.ConsentConstants.REASON_USER_DENIED : void 0);
|
|
436
|
-
|
|
436
|
+
processedInputs = (0, __thunderid_browser.compileConsentDecisions)(processedInputs, purposes, {
|
|
437
437
|
approved: !isDeny,
|
|
438
|
-
...reason ? { reason } : {}
|
|
439
|
-
purposes: purposes.map((p) => ({
|
|
440
|
-
approved: !isDeny,
|
|
441
|
-
elements: [...(p.essential || []).map((e) => ({
|
|
442
|
-
approved: !isDeny,
|
|
443
|
-
name: e.name
|
|
444
|
-
})), ...(p.optional || []).map((e) => {
|
|
445
|
-
const key = `__consent_opt__${p.purposeId}__${e.name}`;
|
|
446
|
-
const approved = !isDeny && processedInputs[key] === "true";
|
|
447
|
-
return (0, __thunderid_browser.getConsentElementDecision)(p.purposeId, e, approved, processedInputs);
|
|
448
|
-
})],
|
|
449
|
-
purposeName: p.purposeName
|
|
450
|
-
}))
|
|
451
|
-
};
|
|
452
|
-
processedInputs["consent_decisions"] = JSON.stringify(decisions);
|
|
453
|
-
Object.keys(processedInputs).forEach((key) => {
|
|
454
|
-
if (key.startsWith("__consent_opt__") || key.startsWith(__thunderid_browser.CONSENT_MODIFIED_KEY_PREFIX) || key.startsWith(__thunderid_browser.CONSENT_INVALID_KEY_PREFIX)) delete processedInputs[key];
|
|
438
|
+
...reason ? { reason } : {}
|
|
455
439
|
});
|
|
456
440
|
} catch (e) {}
|
|
457
441
|
try {
|