@rockerone/xprnkit 0.3.9 → 0.3.11
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 +10 -11
- package/build/providers/XPRNProvider.js +47 -33
- 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,
|
|
@@ -6,15 +6,18 @@ import { type StoredSessionRef } from "../utils";
|
|
|
6
6
|
import { type IdentityProofStatus } from "../services/identity-proof";
|
|
7
7
|
/**
|
|
8
8
|
* Identity proof data returned from authentication
|
|
9
|
+
* All fields are optional - dev can store whatever they want
|
|
9
10
|
*/
|
|
10
11
|
export type XPRNIdentityProof = {
|
|
11
|
-
actor
|
|
12
|
+
actor?: string;
|
|
12
13
|
/** Public key (optional - not available for browser/WebAuth wallets) */
|
|
13
14
|
publicKey?: string;
|
|
14
15
|
/** JWT token from the identity proof verification */
|
|
15
16
|
token?: string;
|
|
16
17
|
/** Additional data from the verification response */
|
|
17
18
|
data?: any;
|
|
19
|
+
/** Allow any additional fields for custom flows */
|
|
20
|
+
[key: string]: any;
|
|
18
21
|
};
|
|
19
22
|
/**
|
|
20
23
|
* @deprecated Use XPRNIdentityProof instead
|
|
@@ -35,12 +38,8 @@ export type XPRNIdentityProofConfig = {
|
|
|
35
38
|
validationUrl?: string;
|
|
36
39
|
/** Time in seconds before expiration to trigger validation (default: 300) */
|
|
37
40
|
validationBuffer?: number;
|
|
38
|
-
/** Automatically authenticate on connect (default: false) */
|
|
39
|
-
enforceOnConnect?: boolean;
|
|
40
41
|
/** Automatically re-authenticate when token expires (default: false) */
|
|
41
42
|
autoReauthenticate?: boolean;
|
|
42
|
-
/** Require identity proof for the app (default: false) */
|
|
43
|
-
required?: boolean;
|
|
44
43
|
/** Additional headers for identity proof requests */
|
|
45
44
|
headers?: Record<string, string>;
|
|
46
45
|
/** Request timeout in milliseconds */
|
|
@@ -58,8 +57,6 @@ export type XPRProviderConfig = {
|
|
|
58
57
|
identityProof?: XPRNIdentityProofConfig;
|
|
59
58
|
/** @deprecated Use identityProof.createUrl instead */
|
|
60
59
|
authenticationUrl?: string;
|
|
61
|
-
/** @deprecated Use identityProof.enforceOnConnect instead */
|
|
62
|
-
enforceAuthentication?: boolean;
|
|
63
60
|
};
|
|
64
61
|
type XPRNProviderProps = {
|
|
65
62
|
children: React.ReactNode | React.ReactNode[];
|
|
@@ -73,15 +70,17 @@ type XPRNProviderContext = {
|
|
|
73
70
|
rpc: JsonRpc | null;
|
|
74
71
|
identityProof: XPRNIdentityProof | null;
|
|
75
72
|
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
73
|
/** True if identity proof is enabled (config.identityProof is defined) */
|
|
81
74
|
isIdentityProofEnabled: boolean;
|
|
82
75
|
connect: (restore?: boolean, onSession?: (session: LinkSession, link: ProtonWebLink | Link) => void, onProfile?: (profile: XPRNProfile) => void, onIdentityProof?: (proof: XPRNIdentityProof) => void, onIdentityProofError?: (error: Error) => void) => void;
|
|
83
76
|
disconnect: () => Promise<void>;
|
|
84
77
|
requestIdentityProof: (success: (res: XPRNIdentityProof) => void, fail: (e: any) => void) => void;
|
|
78
|
+
/** Set identity proof data manually (for custom auth flows) */
|
|
79
|
+
setIdentityProof: (data: XPRNIdentityProof | null) => void;
|
|
80
|
+
/** Clear identity proof and reset status to idle */
|
|
81
|
+
clearIdentityProof: () => void;
|
|
82
|
+
/** Set identity proof status manually (for custom auth flows) */
|
|
83
|
+
setIdentityProofStatus: (status: IdentityProofStatus) => void;
|
|
85
84
|
listStoredSessions: () => StoredSessionRef[];
|
|
86
85
|
switchToSession: (auth: string, chainId: string) => Promise<void>;
|
|
87
86
|
addTransactionError: (rawMessage: string) => void;
|
|
@@ -14,12 +14,13 @@ 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 () => { },
|
|
22
20
|
requestIdentityProof: () => { },
|
|
21
|
+
setIdentityProof: () => { },
|
|
22
|
+
clearIdentityProof: () => { },
|
|
23
|
+
setIdentityProofStatus: () => { },
|
|
23
24
|
listStoredSessions: () => [],
|
|
24
25
|
switchToSession: async () => { },
|
|
25
26
|
addTransactionError: () => { },
|
|
@@ -44,15 +45,12 @@ export const XPRNProvider = ({ children, config, }) => {
|
|
|
44
45
|
if (config.authenticationUrl) {
|
|
45
46
|
return {
|
|
46
47
|
createUrl: config.authenticationUrl,
|
|
47
|
-
enforceOnConnect: config.enforceAuthentication,
|
|
48
48
|
};
|
|
49
49
|
}
|
|
50
50
|
return null;
|
|
51
|
-
}, [config.identityProof, config.authenticationUrl
|
|
52
|
-
// Helper
|
|
51
|
+
}, [config.identityProof, config.authenticationUrl]);
|
|
52
|
+
// Helper boolean
|
|
53
53
|
const isIdentityProofEnabled = identityProofConfig !== null;
|
|
54
|
-
const isIdentityProofRequired = identityProofConfig?.required ?? false;
|
|
55
|
-
const needsIdentityProof = isIdentityProofEnabled && session !== null && identityProof === null;
|
|
56
54
|
// Internal refs
|
|
57
55
|
const jsonRpcRef = useRef(new JsonRpc(config.endpoints));
|
|
58
56
|
const errorsStackRef = useRef([]);
|
|
@@ -64,8 +62,12 @@ export const XPRNProvider = ({ children, config, }) => {
|
|
|
64
62
|
const isAuthenticatingRef = useRef(false);
|
|
65
63
|
const isSwitchingSessionRef = useRef(false);
|
|
66
64
|
const sessionRef = useRef(null);
|
|
67
|
-
|
|
65
|
+
const linkRef = useRef(null);
|
|
66
|
+
// Queue for pending callbacks when requestIdentityProof is called while already in progress
|
|
67
|
+
const pendingCallbacksRef = useRef([]);
|
|
68
|
+
// Keep refs in sync with state
|
|
68
69
|
sessionRef.current = session;
|
|
70
|
+
linkRef.current = link;
|
|
69
71
|
// List stored sessions from proton-web-sdk localStorage
|
|
70
72
|
const listStoredSessions = useCallback(() => {
|
|
71
73
|
return sessionStorage.getLinkList(config.requesterAccount);
|
|
@@ -222,12 +224,15 @@ export const XPRNProvider = ({ children, config, }) => {
|
|
|
222
224
|
});
|
|
223
225
|
}, [config]);
|
|
224
226
|
const disconnect = useCallback(async () => {
|
|
225
|
-
|
|
227
|
+
// Use refs to get latest values (avoid stale closure issues)
|
|
228
|
+
const currentSession = sessionRef.current;
|
|
229
|
+
const currentLink = linkRef.current;
|
|
230
|
+
if (!currentSession || !currentLink) {
|
|
226
231
|
console.warn("No session to disconnect");
|
|
227
232
|
return;
|
|
228
233
|
}
|
|
229
234
|
try {
|
|
230
|
-
await
|
|
235
|
+
await currentLink.removeSession(config.requesterAccount, currentSession.auth, currentSession.chainId);
|
|
231
236
|
}
|
|
232
237
|
catch (e) {
|
|
233
238
|
console.error("Error removing session:", e);
|
|
@@ -238,7 +243,7 @@ export const XPRNProvider = ({ children, config, }) => {
|
|
|
238
243
|
setIdentityProof(null);
|
|
239
244
|
setIdentityProofStatus("idle");
|
|
240
245
|
// Note: Keep link reference for potential session switching
|
|
241
|
-
}, [
|
|
246
|
+
}, [config.requesterAccount]);
|
|
242
247
|
const addTxError = useCallback((message) => {
|
|
243
248
|
errorsStackRef.current.push(parseTransactionErrorMessage(message));
|
|
244
249
|
}, []);
|
|
@@ -253,8 +258,9 @@ export const XPRNProvider = ({ children, config, }) => {
|
|
|
253
258
|
fail(new Error("Identity proof not configured"));
|
|
254
259
|
return;
|
|
255
260
|
}
|
|
261
|
+
// Idempotent: if already in progress, queue callbacks to be called when complete
|
|
256
262
|
if (isAuthenticatingRef.current) {
|
|
257
|
-
|
|
263
|
+
pendingCallbacksRef.current.push({ success, fail });
|
|
258
264
|
return;
|
|
259
265
|
}
|
|
260
266
|
isAuthenticatingRef.current = true;
|
|
@@ -286,6 +292,12 @@ export const XPRNProvider = ({ children, config, }) => {
|
|
|
286
292
|
if (onIdentityProofRef.current) {
|
|
287
293
|
onIdentityProofRef.current(identityProofData);
|
|
288
294
|
}
|
|
295
|
+
// Call all queued callbacks with success
|
|
296
|
+
const pendingCallbacks = pendingCallbacksRef.current;
|
|
297
|
+
pendingCallbacksRef.current = [];
|
|
298
|
+
for (const cb of pendingCallbacks) {
|
|
299
|
+
cb.success(identityProofData);
|
|
300
|
+
}
|
|
289
301
|
}
|
|
290
302
|
catch (error) {
|
|
291
303
|
setIdentityProofStatus("error");
|
|
@@ -294,6 +306,12 @@ export const XPRNProvider = ({ children, config, }) => {
|
|
|
294
306
|
if (onIdentityProofErrorRef.current) {
|
|
295
307
|
onIdentityProofErrorRef.current(error instanceof Error ? error : new Error(String(error)));
|
|
296
308
|
}
|
|
309
|
+
// Call all queued callbacks with error
|
|
310
|
+
const pendingCallbacks = pendingCallbacksRef.current;
|
|
311
|
+
pendingCallbacksRef.current = [];
|
|
312
|
+
for (const cb of pendingCallbacks) {
|
|
313
|
+
cb.fail(error);
|
|
314
|
+
}
|
|
297
315
|
}
|
|
298
316
|
finally {
|
|
299
317
|
isAuthenticatingRef.current = false;
|
|
@@ -359,7 +377,7 @@ export const XPRNProvider = ({ children, config, }) => {
|
|
|
359
377
|
return false;
|
|
360
378
|
}
|
|
361
379
|
}, [identityProofConfig, config.requesterAccount]);
|
|
362
|
-
// Handle token restoration
|
|
380
|
+
// Handle token restoration when session is established (no auto-authentication)
|
|
363
381
|
// Note: This effect is skipped when switchToSession is handling the identity proof state
|
|
364
382
|
useEffect(() => {
|
|
365
383
|
// Skip if we're in the middle of a session switch (switchToSession handles this)
|
|
@@ -367,28 +385,19 @@ export const XPRNProvider = ({ children, config, }) => {
|
|
|
367
385
|
return;
|
|
368
386
|
if (!session || identityProof)
|
|
369
387
|
return;
|
|
370
|
-
if (!identityProofConfig)
|
|
388
|
+
if (!identityProofConfig?.validationUrl)
|
|
371
389
|
return;
|
|
372
390
|
const actor = session.auth.actor.toString();
|
|
373
391
|
const permission = session.auth.permission.toString();
|
|
374
392
|
const chainId = session.chainId.toString();
|
|
375
|
-
// Check if there's a stored token and try to validate it
|
|
393
|
+
// Check if there's a stored token and try to validate it silently
|
|
376
394
|
const storedEntry = sessionStorage.get(config.requesterAccount, { actor, permission }, chainId);
|
|
377
395
|
const hasStoredToken = storedEntry?.identityProofToken && typeof storedEntry.identityProofToken === 'string' && storedEntry.identityProofToken.length > 0;
|
|
378
|
-
if (hasStoredToken
|
|
379
|
-
// Try to validate stored token silently
|
|
380
|
-
validateStoredToken(actor, permission, chainId)
|
|
381
|
-
if (!isValid && (identityProofConfig.enforceOnConnect || identityProofConfig.required)) {
|
|
382
|
-
// Token invalid and identity proof is required - trigger full auth flow
|
|
383
|
-
requestIdentityProof(() => { }, () => { });
|
|
384
|
-
}
|
|
385
|
-
});
|
|
386
|
-
}
|
|
387
|
-
else if (identityProofConfig.enforceOnConnect || identityProofConfig.required) {
|
|
388
|
-
// No stored token (or no validation URL) but identity proof is required - trigger auth flow
|
|
389
|
-
requestIdentityProof(() => { }, () => { });
|
|
396
|
+
if (hasStoredToken) {
|
|
397
|
+
// Try to validate stored token silently - dev handles the result via callbacks
|
|
398
|
+
validateStoredToken(actor, permission, chainId);
|
|
390
399
|
}
|
|
391
|
-
}, [session, identityProof, identityProofConfig, config.requesterAccount, validateStoredToken
|
|
400
|
+
}, [session, identityProof, identityProofConfig, config.requesterAccount, validateStoredToken]);
|
|
392
401
|
// Handle profile callbacks
|
|
393
402
|
useEffect(() => {
|
|
394
403
|
if (profile && onProfileRef.current) {
|
|
@@ -405,6 +414,11 @@ export const XPRNProvider = ({ children, config, }) => {
|
|
|
405
414
|
connect(true);
|
|
406
415
|
}
|
|
407
416
|
}, [config.restoreSession, connect, session]);
|
|
417
|
+
// Helper to clear identity proof
|
|
418
|
+
const clearIdentityProof = useCallback(() => {
|
|
419
|
+
setIdentityProof(null);
|
|
420
|
+
setIdentityProofStatus("idle");
|
|
421
|
+
}, []);
|
|
408
422
|
const providerValue = useMemo(() => {
|
|
409
423
|
return {
|
|
410
424
|
// Config
|
|
@@ -417,14 +431,15 @@ export const XPRNProvider = ({ children, config, }) => {
|
|
|
417
431
|
// Identity proof state
|
|
418
432
|
identityProof,
|
|
419
433
|
identityProofStatus,
|
|
420
|
-
// Helper booleans
|
|
421
|
-
needsIdentityProof,
|
|
422
|
-
isIdentityProofRequired,
|
|
423
434
|
isIdentityProofEnabled,
|
|
424
435
|
// Core methods
|
|
425
436
|
connect,
|
|
426
437
|
disconnect,
|
|
427
438
|
requestIdentityProof,
|
|
439
|
+
// Identity proof setters (for custom flows)
|
|
440
|
+
setIdentityProof,
|
|
441
|
+
clearIdentityProof,
|
|
442
|
+
setIdentityProofStatus,
|
|
428
443
|
// Session switching
|
|
429
444
|
listStoredSessions,
|
|
430
445
|
switchToSession,
|
|
@@ -442,12 +457,11 @@ export const XPRNProvider = ({ children, config, }) => {
|
|
|
442
457
|
profile,
|
|
443
458
|
identityProof,
|
|
444
459
|
identityProofStatus,
|
|
445
|
-
needsIdentityProof,
|
|
446
|
-
isIdentityProofRequired,
|
|
447
460
|
isIdentityProofEnabled,
|
|
448
461
|
connect,
|
|
449
462
|
disconnect,
|
|
450
463
|
requestIdentityProof,
|
|
464
|
+
clearIdentityProof,
|
|
451
465
|
listStoredSessions,
|
|
452
466
|
switchToSession,
|
|
453
467
|
addTxError,
|
|
@@ -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 */
|