@rockerone/xprnkit 0.3.8 → 0.3.10
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/build/components/identity/xprn-identity-proof-gate.d.ts +2 -9
- package/build/components/identity/xprn-identity-proof-gate.js +9 -14
- package/build/components/identity/xprn-session-name.js +6 -5
- package/build/providers/XPRNProvider.d.ts +1 -11
- package/build/providers/XPRNProvider.js +47 -34
- package/build/services/identity-proof/create-identity-proof.js +9 -1
- package/build/services/identity-proof/types.d.ts +0 -4
- package/package.json +1 -1
|
@@ -5,7 +5,7 @@ type XPRNIdentityProofGateProps = {
|
|
|
5
5
|
*/
|
|
6
6
|
children: React.ReactNode;
|
|
7
7
|
/**
|
|
8
|
-
* Content to render when identity proof is
|
|
8
|
+
* Content to render when identity proof is not obtained.
|
|
9
9
|
* If not provided, renders nothing.
|
|
10
10
|
*/
|
|
11
11
|
fallback?: React.ReactNode;
|
|
@@ -24,11 +24,6 @@ type XPRNIdentityProofGateProps = {
|
|
|
24
24
|
* If not provided, uses fallback.
|
|
25
25
|
*/
|
|
26
26
|
notConnected?: React.ReactNode;
|
|
27
|
-
/**
|
|
28
|
-
* If true, only gates when identityProof.required is true in config.
|
|
29
|
-
* If false (default), gates whenever identity proof is configured.
|
|
30
|
-
*/
|
|
31
|
-
onlyWhenRequired?: boolean;
|
|
32
27
|
};
|
|
33
28
|
/**
|
|
34
29
|
* Conditionally renders children based on identity proof status.
|
|
@@ -51,9 +46,7 @@ export declare const XPRNIdentityProofGate: React.FunctionComponent<XPRNIdentity
|
|
|
51
46
|
* Hook to check identity proof gate status
|
|
52
47
|
* Returns the same information used by XPRNIdentityProofGate
|
|
53
48
|
*/
|
|
54
|
-
export declare function useIdentityProofGate(
|
|
55
|
-
onlyWhenRequired?: boolean;
|
|
56
|
-
}): {
|
|
49
|
+
export declare function useIdentityProofGate(): {
|
|
57
50
|
isGateActive: boolean;
|
|
58
51
|
isConnected: boolean;
|
|
59
52
|
isInProgress: boolean;
|
|
@@ -17,16 +17,12 @@ import { useXPRN } from "../../providers/XPRNProvider";
|
|
|
17
17
|
* </XPRNIdentityProofGate>
|
|
18
18
|
* ```
|
|
19
19
|
*/
|
|
20
|
-
export const XPRNIdentityProofGate = ({ children, fallback = null, loading, error, notConnected,
|
|
21
|
-
const { session, identityProof, identityProofStatus, isIdentityProofEnabled,
|
|
20
|
+
export const XPRNIdentityProofGate = ({ children, fallback = null, loading, error, notConnected, }) => {
|
|
21
|
+
const { session, identityProof, identityProofStatus, isIdentityProofEnabled, } = useXPRN();
|
|
22
22
|
// If identity proof is not enabled, render children directly
|
|
23
23
|
if (!isIdentityProofEnabled) {
|
|
24
24
|
return _jsx(_Fragment, { children: children });
|
|
25
25
|
}
|
|
26
|
-
// If onlyWhenRequired is true and identity proof is not required, render children
|
|
27
|
-
if (onlyWhenRequired && !isIdentityProofRequired) {
|
|
28
|
-
return _jsx(_Fragment, { children: children });
|
|
29
|
-
}
|
|
30
26
|
// No session connected
|
|
31
27
|
if (!session) {
|
|
32
28
|
return _jsx(_Fragment, { children: notConnected ?? fallback });
|
|
@@ -51,26 +47,25 @@ XPRNIdentityProofGate.displayName = "XPRNIdentityProofGate";
|
|
|
51
47
|
* Hook to check identity proof gate status
|
|
52
48
|
* Returns the same information used by XPRNIdentityProofGate
|
|
53
49
|
*/
|
|
54
|
-
export function useIdentityProofGate(
|
|
55
|
-
const { session, identityProof, identityProofStatus, isIdentityProofEnabled,
|
|
56
|
-
const onlyWhenRequired = options?.onlyWhenRequired ?? false;
|
|
57
|
-
// Determine if gating should be active
|
|
58
|
-
const isGateActive = isIdentityProofEnabled && (!onlyWhenRequired || isIdentityProofRequired);
|
|
50
|
+
export function useIdentityProofGate() {
|
|
51
|
+
const { session, identityProof, identityProofStatus, isIdentityProofEnabled, requestIdentityProof, } = useXPRN();
|
|
59
52
|
// Determine current state
|
|
60
53
|
const isConnected = session !== null;
|
|
61
54
|
const isInProgress = identityProofStatus === "signing" || identityProofStatus === "verifying" || identityProofStatus === "validating";
|
|
62
55
|
const hasError = identityProofStatus === "error" || identityProofStatus === "expired";
|
|
63
56
|
const isVerified = identityProof !== null;
|
|
64
57
|
// Should render protected content?
|
|
65
|
-
const shouldRenderChildren = !
|
|
58
|
+
const shouldRenderChildren = !isIdentityProofEnabled || isVerified;
|
|
59
|
+
// Needs identity proof: enabled, connected, and not yet verified
|
|
60
|
+
const needsIdentityProof = isIdentityProofEnabled && isConnected && !isVerified;
|
|
66
61
|
return {
|
|
67
|
-
isGateActive,
|
|
62
|
+
isGateActive: isIdentityProofEnabled,
|
|
68
63
|
isConnected,
|
|
69
64
|
isInProgress,
|
|
70
65
|
hasError,
|
|
71
66
|
isVerified,
|
|
72
67
|
shouldRenderChildren,
|
|
73
|
-
needsIdentityProof
|
|
68
|
+
needsIdentityProof,
|
|
74
69
|
requestIdentityProof,
|
|
75
70
|
identityProofStatus,
|
|
76
71
|
};
|
|
@@ -7,7 +7,7 @@ import { useXPRN } from "../../providers/XPRNProvider";
|
|
|
7
7
|
* Get badge styling based on identity proof status
|
|
8
8
|
*/
|
|
9
9
|
function useIdentityProofBadgeStyle() {
|
|
10
|
-
const { identityProofStatus, isIdentityProofEnabled,
|
|
10
|
+
const { identityProofStatus, isIdentityProofEnabled, identityProof, session } = useXPRN();
|
|
11
11
|
return useMemo(() => {
|
|
12
12
|
if (!isIdentityProofEnabled) {
|
|
13
13
|
return { visible: false, className: "" };
|
|
@@ -18,6 +18,7 @@ function useIdentityProofBadgeStyle() {
|
|
|
18
18
|
const isSuccess = identityProofStatus === "success";
|
|
19
19
|
const isError = identityProofStatus === "error" || identityProofStatus === "expired";
|
|
20
20
|
const isIdle = identityProofStatus === "idle";
|
|
21
|
+
const needsIdentityProof = session !== null && identityProof === null;
|
|
21
22
|
// Build className based on status
|
|
22
23
|
let className = "";
|
|
23
24
|
if (isPending) {
|
|
@@ -42,12 +43,12 @@ function useIdentityProofBadgeStyle() {
|
|
|
42
43
|
isSuccess,
|
|
43
44
|
isError,
|
|
44
45
|
};
|
|
45
|
-
}, [identityProofStatus, isIdentityProofEnabled,
|
|
46
|
+
}, [identityProofStatus, isIdentityProofEnabled, identityProof, session]);
|
|
46
47
|
}
|
|
47
|
-
export const XPRNSessionName = ({ children, className, }) => {
|
|
48
|
-
const { profile, session
|
|
48
|
+
export const XPRNSessionName = ({ children, className, showIdentityProof = false, }) => {
|
|
49
|
+
const { profile, session } = useXPRN();
|
|
49
50
|
const badgeStyle = useIdentityProofBadgeStyle();
|
|
50
|
-
const showBadge =
|
|
51
|
+
const showBadge = showIdentityProof && badgeStyle.visible;
|
|
51
52
|
const rootClasses = classNames({
|
|
52
53
|
"flex gap-2 items-center justify-center": true,
|
|
53
54
|
[`${className}`]: className,
|
|
@@ -35,12 +35,8 @@ export type XPRNIdentityProofConfig = {
|
|
|
35
35
|
validationUrl?: string;
|
|
36
36
|
/** Time in seconds before expiration to trigger validation (default: 300) */
|
|
37
37
|
validationBuffer?: number;
|
|
38
|
-
/** Automatically authenticate on connect (default: false) */
|
|
39
|
-
enforceOnConnect?: boolean;
|
|
40
38
|
/** Automatically re-authenticate when token expires (default: false) */
|
|
41
39
|
autoReauthenticate?: boolean;
|
|
42
|
-
/** Require identity proof for the app (default: false) */
|
|
43
|
-
required?: boolean;
|
|
44
40
|
/** Additional headers for identity proof requests */
|
|
45
41
|
headers?: Record<string, string>;
|
|
46
42
|
/** Request timeout in milliseconds */
|
|
@@ -58,8 +54,6 @@ export type XPRProviderConfig = {
|
|
|
58
54
|
identityProof?: XPRNIdentityProofConfig;
|
|
59
55
|
/** @deprecated Use identityProof.createUrl instead */
|
|
60
56
|
authenticationUrl?: string;
|
|
61
|
-
/** @deprecated Use identityProof.enforceOnConnect instead */
|
|
62
|
-
enforceAuthentication?: boolean;
|
|
63
57
|
};
|
|
64
58
|
type XPRNProviderProps = {
|
|
65
59
|
children: React.ReactNode | React.ReactNode[];
|
|
@@ -73,13 +67,9 @@ type XPRNProviderContext = {
|
|
|
73
67
|
rpc: JsonRpc | null;
|
|
74
68
|
identityProof: XPRNIdentityProof | null;
|
|
75
69
|
identityProofStatus: IdentityProofStatus;
|
|
76
|
-
/** True if identity proof is configured but not yet obtained for current session */
|
|
77
|
-
needsIdentityProof: boolean;
|
|
78
|
-
/** True if identity proof is configured with required=true */
|
|
79
|
-
isIdentityProofRequired: boolean;
|
|
80
70
|
/** True if identity proof is enabled (config.identityProof is defined) */
|
|
81
71
|
isIdentityProofEnabled: boolean;
|
|
82
|
-
connect: (restore?: boolean, onSession?: (session: LinkSession, link: ProtonWebLink | Link) => void, onProfile?: (profile: XPRNProfile) => void) => void;
|
|
72
|
+
connect: (restore?: boolean, onSession?: (session: LinkSession, link: ProtonWebLink | Link) => void, onProfile?: (profile: XPRNProfile) => void, onIdentityProof?: (proof: XPRNIdentityProof) => void, onIdentityProofError?: (error: Error) => void) => void;
|
|
83
73
|
disconnect: () => Promise<void>;
|
|
84
74
|
requestIdentityProof: (success: (res: XPRNIdentityProof) => void, fail: (e: any) => void) => void;
|
|
85
75
|
listStoredSessions: () => StoredSessionRef[];
|
|
@@ -14,8 +14,6 @@ const XPRNContext = React.createContext({
|
|
|
14
14
|
rpc: null,
|
|
15
15
|
identityProof: null,
|
|
16
16
|
identityProofStatus: "idle",
|
|
17
|
-
needsIdentityProof: false,
|
|
18
|
-
isIdentityProofRequired: false,
|
|
19
17
|
isIdentityProofEnabled: false,
|
|
20
18
|
connect: () => { },
|
|
21
19
|
disconnect: async () => { },
|
|
@@ -44,26 +42,29 @@ export const XPRNProvider = ({ children, config, }) => {
|
|
|
44
42
|
if (config.authenticationUrl) {
|
|
45
43
|
return {
|
|
46
44
|
createUrl: config.authenticationUrl,
|
|
47
|
-
enforceOnConnect: config.enforceAuthentication,
|
|
48
45
|
};
|
|
49
46
|
}
|
|
50
47
|
return null;
|
|
51
|
-
}, [config.identityProof, config.authenticationUrl
|
|
52
|
-
// Helper
|
|
48
|
+
}, [config.identityProof, config.authenticationUrl]);
|
|
49
|
+
// Helper boolean
|
|
53
50
|
const isIdentityProofEnabled = identityProofConfig !== null;
|
|
54
|
-
const isIdentityProofRequired = identityProofConfig?.required ?? false;
|
|
55
|
-
const needsIdentityProof = isIdentityProofEnabled && session !== null && identityProof === null;
|
|
56
51
|
// Internal refs
|
|
57
52
|
const jsonRpcRef = useRef(new JsonRpc(config.endpoints));
|
|
58
53
|
const errorsStackRef = useRef([]);
|
|
59
54
|
const onSessionRef = useRef();
|
|
60
55
|
const onProfileRef = useRef();
|
|
56
|
+
const onIdentityProofRef = useRef();
|
|
57
|
+
const onIdentityProofErrorRef = useRef();
|
|
61
58
|
const isRestoringRef = useRef(false);
|
|
62
59
|
const isAuthenticatingRef = useRef(false);
|
|
63
60
|
const isSwitchingSessionRef = useRef(false);
|
|
64
61
|
const sessionRef = useRef(null);
|
|
65
|
-
|
|
62
|
+
const linkRef = useRef(null);
|
|
63
|
+
// Queue for pending callbacks when requestIdentityProof is called while already in progress
|
|
64
|
+
const pendingCallbacksRef = useRef([]);
|
|
65
|
+
// Keep refs in sync with state
|
|
66
66
|
sessionRef.current = session;
|
|
67
|
+
linkRef.current = link;
|
|
67
68
|
// List stored sessions from proton-web-sdk localStorage
|
|
68
69
|
const listStoredSessions = useCallback(() => {
|
|
69
70
|
return sessionStorage.getLinkList(config.requesterAccount);
|
|
@@ -162,7 +163,7 @@ export const XPRNProvider = ({ children, config, }) => {
|
|
|
162
163
|
// Mark session switch as complete
|
|
163
164
|
isSwitchingSessionRef.current = false;
|
|
164
165
|
}, [link, config.requesterAccount, config.apiMode, identityProofConfig]);
|
|
165
|
-
const connect = useCallback((restoreSession, onSession, onProfile) => {
|
|
166
|
+
const connect = useCallback((restoreSession, onSession, onProfile, onIdentityProof, onIdentityProofError) => {
|
|
166
167
|
ConnectWallet({
|
|
167
168
|
linkOptions: {
|
|
168
169
|
endpoints: config.endpoints,
|
|
@@ -177,6 +178,8 @@ export const XPRNProvider = ({ children, config, }) => {
|
|
|
177
178
|
}).then(res => {
|
|
178
179
|
onSessionRef.current = onSession;
|
|
179
180
|
onProfileRef.current = onProfile;
|
|
181
|
+
onIdentityProofRef.current = onIdentityProof;
|
|
182
|
+
onIdentityProofErrorRef.current = onIdentityProofError;
|
|
180
183
|
if (res.link && res.session) {
|
|
181
184
|
// Update state with new session
|
|
182
185
|
setLink(res.link);
|
|
@@ -218,12 +221,15 @@ export const XPRNProvider = ({ children, config, }) => {
|
|
|
218
221
|
});
|
|
219
222
|
}, [config]);
|
|
220
223
|
const disconnect = useCallback(async () => {
|
|
221
|
-
|
|
224
|
+
// Use refs to get latest values (avoid stale closure issues)
|
|
225
|
+
const currentSession = sessionRef.current;
|
|
226
|
+
const currentLink = linkRef.current;
|
|
227
|
+
if (!currentSession || !currentLink) {
|
|
222
228
|
console.warn("No session to disconnect");
|
|
223
229
|
return;
|
|
224
230
|
}
|
|
225
231
|
try {
|
|
226
|
-
await
|
|
232
|
+
await currentLink.removeSession(config.requesterAccount, currentSession.auth, currentSession.chainId);
|
|
227
233
|
}
|
|
228
234
|
catch (e) {
|
|
229
235
|
console.error("Error removing session:", e);
|
|
@@ -234,7 +240,7 @@ export const XPRNProvider = ({ children, config, }) => {
|
|
|
234
240
|
setIdentityProof(null);
|
|
235
241
|
setIdentityProofStatus("idle");
|
|
236
242
|
// Note: Keep link reference for potential session switching
|
|
237
|
-
}, [
|
|
243
|
+
}, [config.requesterAccount]);
|
|
238
244
|
const addTxError = useCallback((message) => {
|
|
239
245
|
errorsStackRef.current.push(parseTransactionErrorMessage(message));
|
|
240
246
|
}, []);
|
|
@@ -249,8 +255,9 @@ export const XPRNProvider = ({ children, config, }) => {
|
|
|
249
255
|
fail(new Error("Identity proof not configured"));
|
|
250
256
|
return;
|
|
251
257
|
}
|
|
258
|
+
// Idempotent: if already in progress, queue callbacks to be called when complete
|
|
252
259
|
if (isAuthenticatingRef.current) {
|
|
253
|
-
|
|
260
|
+
pendingCallbacksRef.current.push({ success, fail });
|
|
254
261
|
return;
|
|
255
262
|
}
|
|
256
263
|
isAuthenticatingRef.current = true;
|
|
@@ -278,10 +285,30 @@ export const XPRNProvider = ({ children, config, }) => {
|
|
|
278
285
|
sessionStorage.updateIdentityProofToken(config.requesterAccount, { actor, permission }, chainId, verifyRes.token);
|
|
279
286
|
}
|
|
280
287
|
success(identityProofData);
|
|
288
|
+
// Call connect-level callback if registered
|
|
289
|
+
if (onIdentityProofRef.current) {
|
|
290
|
+
onIdentityProofRef.current(identityProofData);
|
|
291
|
+
}
|
|
292
|
+
// Call all queued callbacks with success
|
|
293
|
+
const pendingCallbacks = pendingCallbacksRef.current;
|
|
294
|
+
pendingCallbacksRef.current = [];
|
|
295
|
+
for (const cb of pendingCallbacks) {
|
|
296
|
+
cb.success(identityProofData);
|
|
297
|
+
}
|
|
281
298
|
}
|
|
282
299
|
catch (error) {
|
|
283
300
|
setIdentityProofStatus("error");
|
|
284
301
|
fail(error);
|
|
302
|
+
// Call connect-level error callback if registered
|
|
303
|
+
if (onIdentityProofErrorRef.current) {
|
|
304
|
+
onIdentityProofErrorRef.current(error instanceof Error ? error : new Error(String(error)));
|
|
305
|
+
}
|
|
306
|
+
// Call all queued callbacks with error
|
|
307
|
+
const pendingCallbacks = pendingCallbacksRef.current;
|
|
308
|
+
pendingCallbacksRef.current = [];
|
|
309
|
+
for (const cb of pendingCallbacks) {
|
|
310
|
+
cb.fail(error);
|
|
311
|
+
}
|
|
285
312
|
}
|
|
286
313
|
finally {
|
|
287
314
|
isAuthenticatingRef.current = false;
|
|
@@ -347,7 +374,7 @@ export const XPRNProvider = ({ children, config, }) => {
|
|
|
347
374
|
return false;
|
|
348
375
|
}
|
|
349
376
|
}, [identityProofConfig, config.requesterAccount]);
|
|
350
|
-
// Handle token restoration
|
|
377
|
+
// Handle token restoration when session is established (no auto-authentication)
|
|
351
378
|
// Note: This effect is skipped when switchToSession is handling the identity proof state
|
|
352
379
|
useEffect(() => {
|
|
353
380
|
// Skip if we're in the middle of a session switch (switchToSession handles this)
|
|
@@ -355,28 +382,19 @@ export const XPRNProvider = ({ children, config, }) => {
|
|
|
355
382
|
return;
|
|
356
383
|
if (!session || identityProof)
|
|
357
384
|
return;
|
|
358
|
-
if (!identityProofConfig)
|
|
385
|
+
if (!identityProofConfig?.validationUrl)
|
|
359
386
|
return;
|
|
360
387
|
const actor = session.auth.actor.toString();
|
|
361
388
|
const permission = session.auth.permission.toString();
|
|
362
389
|
const chainId = session.chainId.toString();
|
|
363
|
-
// Check if there's a stored token and try to validate it
|
|
390
|
+
// Check if there's a stored token and try to validate it silently
|
|
364
391
|
const storedEntry = sessionStorage.get(config.requesterAccount, { actor, permission }, chainId);
|
|
365
392
|
const hasStoredToken = storedEntry?.identityProofToken && typeof storedEntry.identityProofToken === 'string' && storedEntry.identityProofToken.length > 0;
|
|
366
|
-
if (hasStoredToken
|
|
367
|
-
// Try to validate stored token silently
|
|
368
|
-
validateStoredToken(actor, permission, chainId)
|
|
369
|
-
if (!isValid && (identityProofConfig.enforceOnConnect || identityProofConfig.required)) {
|
|
370
|
-
// Token invalid and identity proof is required - trigger full auth flow
|
|
371
|
-
requestIdentityProof(() => { }, () => { });
|
|
372
|
-
}
|
|
373
|
-
});
|
|
374
|
-
}
|
|
375
|
-
else if (identityProofConfig.enforceOnConnect || identityProofConfig.required) {
|
|
376
|
-
// No stored token (or no validation URL) but identity proof is required - trigger auth flow
|
|
377
|
-
requestIdentityProof(() => { }, () => { });
|
|
393
|
+
if (hasStoredToken) {
|
|
394
|
+
// Try to validate stored token silently - dev handles the result via callbacks
|
|
395
|
+
validateStoredToken(actor, permission, chainId);
|
|
378
396
|
}
|
|
379
|
-
}, [session, identityProof, identityProofConfig, config.requesterAccount, validateStoredToken
|
|
397
|
+
}, [session, identityProof, identityProofConfig, config.requesterAccount, validateStoredToken]);
|
|
380
398
|
// Handle profile callbacks
|
|
381
399
|
useEffect(() => {
|
|
382
400
|
if (profile && onProfileRef.current) {
|
|
@@ -405,9 +423,6 @@ export const XPRNProvider = ({ children, config, }) => {
|
|
|
405
423
|
// Identity proof state
|
|
406
424
|
identityProof,
|
|
407
425
|
identityProofStatus,
|
|
408
|
-
// Helper booleans
|
|
409
|
-
needsIdentityProof,
|
|
410
|
-
isIdentityProofRequired,
|
|
411
426
|
isIdentityProofEnabled,
|
|
412
427
|
// Core methods
|
|
413
428
|
connect,
|
|
@@ -430,8 +445,6 @@ export const XPRNProvider = ({ children, config, }) => {
|
|
|
430
445
|
profile,
|
|
431
446
|
identityProof,
|
|
432
447
|
identityProofStatus,
|
|
433
|
-
needsIdentityProof,
|
|
434
|
-
isIdentityProofRequired,
|
|
435
448
|
isIdentityProofEnabled,
|
|
436
449
|
connect,
|
|
437
450
|
disconnect,
|
|
@@ -28,7 +28,15 @@ export async function createIdentityProof(session, options) {
|
|
|
28
28
|
time: new Date().toISOString().slice(0, -1),
|
|
29
29
|
});
|
|
30
30
|
// Sign the transaction without broadcasting
|
|
31
|
-
|
|
31
|
+
let txResult;
|
|
32
|
+
try {
|
|
33
|
+
txResult = await session.transact({ actions: [authenticationAction] }, { broadcast: false });
|
|
34
|
+
}
|
|
35
|
+
catch (error) {
|
|
36
|
+
// Re-throw with clearer context for wallet signing failures
|
|
37
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
38
|
+
throw new Error(`Wallet signing failed: ${message}`);
|
|
39
|
+
}
|
|
32
40
|
// Check for abort after wallet interaction
|
|
33
41
|
if (options?.signal?.aborted) {
|
|
34
42
|
throw new DOMException("Aborted", "AbortError");
|
|
@@ -34,12 +34,8 @@ export type IdentityProofConfig = {
|
|
|
34
34
|
validationUrl?: string;
|
|
35
35
|
/** Time in seconds before expiration to trigger validation (default: 300 = 5 minutes) */
|
|
36
36
|
validationBuffer?: number;
|
|
37
|
-
/** Automatically authenticate on connect (default: false) */
|
|
38
|
-
enforceOnConnect?: boolean;
|
|
39
37
|
/** Automatically re-authenticate when token expires (default: false) */
|
|
40
38
|
autoReauthenticate?: boolean;
|
|
41
|
-
/** Require identity proof for the app - enables helper booleans and gate component (default: false) */
|
|
42
|
-
required?: boolean;
|
|
43
39
|
/** Additional headers for identity proof requests */
|
|
44
40
|
headers?: Record<string, string>;
|
|
45
41
|
/** Request timeout in milliseconds */
|