@rockerone/xprnkit 0.3.12 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. package/README.md +571 -834
  2. package/build/components/identity/xprn-account-list.d.ts +5 -5
  3. package/build/components/identity/xprn-account-list.js +15 -20
  4. package/build/components/identity/xprn-avatar.js +1 -1
  5. package/build/components/identity/xprn-identity-proof-gate.d.ts +5 -4
  6. package/build/components/identity/xprn-identity-proof-gate.js +10 -12
  7. package/build/components/identity/xprn-identity.d.ts +10 -0
  8. package/build/components/identity/xprn-identity.js +3 -3
  9. package/build/components/identity/xprn-session-actor.js +1 -1
  10. package/build/components/identity/xprn-session-name.d.ts +0 -6
  11. package/build/components/identity/xprn-session-name.js +6 -9
  12. package/build/components/swap/xprn-swap-provider.js +1 -1
  13. package/build/components/xprn-container.js +1 -1
  14. package/build/components/xprn-session.d.ts +10 -0
  15. package/build/components/xprn-session.js +15 -4
  16. package/build/components/xprn-transaction.js +5 -5
  17. package/build/global.css +4 -4
  18. package/build/hooks/index.d.ts +0 -0
  19. package/build/hooks/index.js +1 -0
  20. package/build/hooks/useIdentityProof.d.ts +2 -0
  21. package/build/hooks/useIdentityProof.js +14 -0
  22. package/build/hooks/useProfileList.d.ts +2 -0
  23. package/build/hooks/useProfileList.js +13 -0
  24. package/build/index.d.ts +1 -1
  25. package/build/index.js +1 -1
  26. package/build/interfaces/config.d.ts +12 -0
  27. package/build/interfaces/identity-proof.d.ts +28 -0
  28. package/build/interfaces/identity-proof.js +1 -0
  29. package/build/interfaces/index.d.ts +4 -0
  30. package/build/interfaces/index.js +4 -0
  31. package/build/interfaces/profile.d.ts +5 -0
  32. package/build/interfaces/profile.js +1 -0
  33. package/build/providers/xprnkit-provider.d.ts +23 -0
  34. package/build/providers/xprnkit-provider.js +224 -0
  35. package/build/services/identity-proof/authenticate-identity-proof.d.ts +2 -0
  36. package/build/services/identity-proof/authenticate-identity-proof.js +42 -0
  37. package/build/services/identity-proof/index.d.ts +3 -10
  38. package/build/services/identity-proof/index.js +3 -8
  39. package/build/services/identity-proof/request-identity-proof.d.ts +7 -0
  40. package/build/services/identity-proof/{create-identity-proof.js → request-identity-proof.js} +2 -17
  41. package/build/services/identity-proof/verify-identity-proof.d.ts +5 -22
  42. package/build/services/identity-proof/verify-identity-proof.js +58 -68
  43. package/build/utils/identity-proof-storage.d.ts +14 -0
  44. package/build/utils/identity-proof-storage.js +33 -0
  45. package/build/utils/index.d.ts +1 -1
  46. package/build/utils/index.js +1 -1
  47. package/build/utils/profile-storage.d.ts +17 -0
  48. package/build/utils/profile-storage.js +48 -0
  49. package/build/utils/storage-key.d.ts +1 -0
  50. package/build/utils/storage-key.js +3 -0
  51. package/build/utils/xprnkit-storage.d.ts +9 -0
  52. package/build/utils/xprnkit-storage.js +23 -0
  53. package/package.json +3 -2
  54. package/build/providers/XPRNProvider.d.ts +0 -96
  55. package/build/providers/XPRNProvider.js +0 -473
  56. package/build/services/identity-proof/create-identity-proof.d.ts +0 -23
  57. package/build/services/identity-proof/types.d.ts +0 -82
  58. package/build/services/identity-proof/use-identity-proof.d.ts +0 -38
  59. package/build/services/identity-proof/use-identity-proof.js +0 -145
  60. package/build/services/identity-proof/validate-identity-proof.d.ts +0 -51
  61. package/build/services/identity-proof/validate-identity-proof.js +0 -93
  62. package/build/utils/auth-storage.d.ts +0 -126
  63. package/build/utils/auth-storage.js +0 -216
  64. /package/build/{services/identity-proof/types.js → interfaces/config.js} +0 -0
@@ -0,0 +1,23 @@
1
+ import { formatStorageKey } from "./storage-key";
2
+ export const XPRNKIT_STORAGE_PREFIX = "xprnkit-storage";
3
+ export class XPRNKitLinkStorage {
4
+ appIdentifier;
5
+ constructor(appIdentifier) {
6
+ this.appIdentifier = appIdentifier;
7
+ }
8
+ write(key, value) {
9
+ console.log('write to xprnkit-storage', key, value);
10
+ localStorage.setItem(formatStorageKey(XPRNKIT_STORAGE_PREFIX, this.appIdentifier, key), value);
11
+ return Promise.resolve();
12
+ }
13
+ read(key) {
14
+ console.log('read from xprnkit-storage', key);
15
+ const value = localStorage.getItem(formatStorageKey(XPRNKIT_STORAGE_PREFIX, this.appIdentifier, key));
16
+ return Promise.resolve(value);
17
+ }
18
+ remove(key) {
19
+ console.log('remove from xprnkit-storage', key);
20
+ localStorage.removeItem(formatStorageKey(XPRNKIT_STORAGE_PREFIX, this.appIdentifier, key));
21
+ return Promise.resolve();
22
+ }
23
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rockerone/xprnkit",
3
- "version": "0.3.12",
3
+ "version": "0.4.1",
4
4
  "source": "src/index.ts",
5
5
  "main": "build/index.js",
6
6
  "type": "module",
@@ -12,7 +12,8 @@
12
12
  "style": "tailwindcss -i ./src/global.css -o ./build/global.css",
13
13
  "bundle": "rimraf ./build && microbundle --jsx React.createElement --jsxFragment React.Fragment",
14
14
  "dev": "microbundle watch",
15
- "types:bc": "bunx abi2ts proton.wrap -r proton_wrap > ./src/interfaces/proton_wrap.ts"
15
+ "types:bc": "bunx abi2ts proton.wrap -r proton_wrap > ./src/interfaces/proton_wrap.ts",
16
+ "prepublishOnly": "npm run build"
16
17
  },
17
18
  "files": [
18
19
  "build",
@@ -1,96 +0,0 @@
1
- import type { Link, LinkSession } from "@proton/link";
2
- import { ProtonWebLink } from "@proton/web-sdk";
3
- import React from "react";
4
- import { JsonRpc } from "@proton/js";
5
- import { type StoredSessionRef } from "../utils";
6
- import { type IdentityProofStatus } from "../services/identity-proof";
7
- /**
8
- * Identity proof data returned from authentication
9
- * All fields are optional - dev can store whatever they want
10
- */
11
- export type XPRNIdentityProof = {
12
- actor?: string;
13
- /** Public key (optional - not available for browser/WebAuth wallets) */
14
- publicKey?: string;
15
- /** JWT token from the identity proof verification */
16
- token?: string;
17
- /** Additional data from the verification response */
18
- data?: any;
19
- /** Allow any additional fields for custom flows */
20
- [key: string]: any;
21
- };
22
- /**
23
- * @deprecated Use XPRNIdentityProof instead
24
- */
25
- export type XPRNAuthentication = XPRNIdentityProof;
26
- export type XPRNProfile = {
27
- displayName: string;
28
- avatar?: string;
29
- isKyc: boolean;
30
- };
31
- /**
32
- * Identity proof configuration (optional feature)
33
- */
34
- export type XPRNIdentityProofConfig = {
35
- /** URL for creating identity proof (sign + verify) */
36
- createUrl: string;
37
- /** URL for validating existing tokens (optional) */
38
- validationUrl?: string;
39
- /** Time in seconds before expiration to trigger validation (default: 300) */
40
- validationBuffer?: number;
41
- /** Automatically re-authenticate when token expires (default: false) */
42
- autoReauthenticate?: boolean;
43
- /** Additional headers for identity proof requests */
44
- headers?: Record<string, string>;
45
- /** Request timeout in milliseconds */
46
- timeout?: number;
47
- };
48
- export type XPRProviderConfig = {
49
- chainId: string;
50
- endpoints: string[];
51
- dAppName: string;
52
- requesterAccount: string;
53
- requesterLogo?: string;
54
- apiMode: "testnet" | "mainnet";
55
- restoreSession?: boolean;
56
- /** Identity proof configuration (optional - if not provided, identity proof is disabled) */
57
- identityProof?: XPRNIdentityProofConfig;
58
- /** @deprecated Use identityProof.createUrl instead */
59
- authenticationUrl?: string;
60
- };
61
- type XPRNProviderProps = {
62
- children: React.ReactNode | React.ReactNode[];
63
- config: XPRProviderConfig;
64
- };
65
- type XPRNProviderContext = {
66
- config: XPRProviderConfig | null;
67
- session: LinkSession | null;
68
- link: ProtonWebLink | Link | null;
69
- profile: XPRNProfile | null;
70
- rpc: JsonRpc | null;
71
- identityProof: XPRNIdentityProof | null;
72
- identityProofStatus: IdentityProofStatus;
73
- /** True if identity proof is enabled (config.identityProof is defined) */
74
- isIdentityProofEnabled: boolean;
75
- connect: (restore?: boolean, onSession?: (session: LinkSession, link: ProtonWebLink | Link) => void, onProfile?: (profile: XPRNProfile) => void, onIdentityProof?: (proof: XPRNIdentityProof) => void, onIdentityProofError?: (error: Error) => void) => void;
76
- disconnect: () => Promise<void>;
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;
84
- listStoredSessions: () => StoredSessionRef[];
85
- switchToSession: (auth: string, chainId: string) => Promise<void>;
86
- addTransactionError: (rawMessage: string) => void;
87
- /** @deprecated Use identityProof instead */
88
- authentication: XPRNIdentityProof | null;
89
- /** @deprecated Use identityProofStatus instead */
90
- authStatus: IdentityProofStatus;
91
- /** @deprecated Use requestIdentityProof instead */
92
- authenticate: (success: (res: any) => void, fail: (e: any) => void) => void;
93
- };
94
- export declare const XPRNProvider: React.FunctionComponent<XPRNProviderProps>;
95
- export declare function useXPRN(): XPRNProviderContext;
96
- export {};
@@ -1,473 +0,0 @@
1
- "use client";
2
- import { jsx as _jsx } from "react/jsx-runtime";
3
- import { ApiClass } from "@proton/api";
4
- import ConnectWallet from "@proton/web-sdk";
5
- import React, { useCallback, useContext, useEffect, useMemo, useRef, useState, } from "react";
6
- import { JsonRpc } from "@proton/js";
7
- import { sessionStorage, parseTransactionErrorMessage } from "../utils";
8
- import { createIdentityProof, verifyIdentityProof, validateIdentityProof, parseToken, isTokenExpired, } from "../services/identity-proof";
9
- const XPRNContext = React.createContext({
10
- config: null,
11
- session: null,
12
- link: null,
13
- profile: null,
14
- rpc: null,
15
- identityProof: null,
16
- identityProofStatus: "idle",
17
- isIdentityProofEnabled: false,
18
- connect: () => { },
19
- disconnect: async () => { },
20
- requestIdentityProof: () => { },
21
- setIdentityProof: () => { },
22
- clearIdentityProof: () => { },
23
- setIdentityProofStatus: () => { },
24
- listStoredSessions: () => [],
25
- switchToSession: async () => { },
26
- addTransactionError: () => { },
27
- // Legacy
28
- authentication: null,
29
- authStatus: "idle",
30
- authenticate: () => { },
31
- });
32
- export const XPRNProvider = ({ children, config, }) => {
33
- // Simple state for single active session
34
- const [session, setSession] = useState(null);
35
- const [link, setLink] = useState(null);
36
- const [profile, setProfile] = useState(null);
37
- const [identityProof, setIdentityProof] = useState(null);
38
- const [identityProofStatus, setIdentityProofStatus] = useState("idle");
39
- // Compute identity proof config (supports both new and legacy config)
40
- const identityProofConfig = useMemo(() => {
41
- if (config.identityProof) {
42
- return config.identityProof;
43
- }
44
- // Legacy support
45
- if (config.authenticationUrl) {
46
- return {
47
- createUrl: config.authenticationUrl,
48
- };
49
- }
50
- return null;
51
- }, [config.identityProof, config.authenticationUrl]);
52
- // Helper boolean
53
- const isIdentityProofEnabled = identityProofConfig !== null;
54
- // Internal refs
55
- const jsonRpcRef = useRef(new JsonRpc(config.endpoints));
56
- const errorsStackRef = useRef([]);
57
- const onSessionRef = useRef();
58
- const onProfileRef = useRef();
59
- const onIdentityProofRef = useRef();
60
- const onIdentityProofErrorRef = useRef();
61
- const isRestoringRef = useRef(false);
62
- const isAuthenticatingRef = useRef(false);
63
- const isSwitchingSessionRef = useRef(false);
64
- const sessionRef = useRef(null);
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
69
- sessionRef.current = session;
70
- linkRef.current = link;
71
- // List stored sessions from proton-web-sdk localStorage
72
- const listStoredSessions = useCallback(() => {
73
- return sessionStorage.getLinkList(config.requesterAccount);
74
- }, [config.requesterAccount]);
75
- // Switch to a different stored session using link.restoreSession
76
- const switchToSession = useCallback(async (auth, chainId) => {
77
- if (!link) {
78
- console.warn("Cannot switch session: No link available. Call connect() first.");
79
- return;
80
- }
81
- // Mark that we're switching sessions to prevent useEffect interference
82
- isSwitchingSessionRef.current = true;
83
- // Parse auth string (format: "actor@permission")
84
- const [actor, permission] = auth.split('@');
85
- const authObj = { actor, permission };
86
- // Use link.restoreSession to restore the session
87
- // Both Link and ProtonWebLink support this method (with different return types)
88
- const restoredSession = await link.restoreSession(config.requesterAccount, authObj, chainId);
89
- if (!restoredSession) {
90
- throw new Error(`Failed to restore session for ${auth} on chain ${chainId}`);
91
- }
92
- // Clear identity proof state immediately for the new session
93
- setSession(restoredSession);
94
- // Check if the new session has a stored identity proof token
95
- const storedEntry = sessionStorage.get(config.requesterAccount, { actor: actor, permission: permission }, chainId);
96
- if (storedEntry?.identityProofToken && identityProofConfig?.validationUrl) {
97
- // New session has a stored token - validate it
98
- setIdentityProofStatus("validating");
99
- try {
100
- const tokenClaims = parseToken(storedEntry.identityProofToken);
101
- if (tokenClaims && !isTokenExpired(tokenClaims)) {
102
- // Token exists and not expired - validate with backend
103
- const result = await validateIdentityProof({
104
- validationUrl: identityProofConfig.validationUrl,
105
- token: storedEntry.identityProofToken,
106
- headers: identityProofConfig.headers,
107
- timeout: identityProofConfig.timeout,
108
- });
109
- if (result.valid) {
110
- const newToken = result.token || storedEntry.identityProofToken;
111
- setIdentityProof({
112
- actor: actor,
113
- token: newToken,
114
- });
115
- setIdentityProofStatus("success");
116
- // Update token in storage if refreshed
117
- if (result.token && result.token !== storedEntry.identityProofToken) {
118
- sessionStorage.updateIdentityProofToken(config.requesterAccount, { actor: actor, permission: permission }, chainId, result.token);
119
- }
120
- }
121
- else {
122
- // Token invalid - clear it
123
- sessionStorage.updateIdentityProofToken(config.requesterAccount, { actor: actor, permission: permission }, chainId, null);
124
- setIdentityProof(null);
125
- setIdentityProofStatus("expired");
126
- }
127
- }
128
- else {
129
- // Token expired or invalid - clear it
130
- sessionStorage.updateIdentityProofToken(config.requesterAccount, { actor: actor, permission: permission }, chainId, null);
131
- setIdentityProof(null);
132
- setIdentityProofStatus("expired");
133
- }
134
- }
135
- catch (error) {
136
- console.error("Failed to validate token during session switch:", error);
137
- setIdentityProof(null);
138
- setIdentityProofStatus("error");
139
- }
140
- }
141
- else {
142
- // No stored token for this session - clear identity proof state
143
- setIdentityProof(null);
144
- setIdentityProofStatus("idle");
145
- }
146
- // Fetch profile for new session
147
- const api = new ApiClass(config.apiMode === "testnet" ? "proton-test" : "proton");
148
- try {
149
- const profileRes = await api.getProtonAvatar(actor);
150
- if (profileRes) {
151
- setProfile({
152
- displayName: profileRes.name,
153
- avatar: profileRes.avatar,
154
- isKyc: profileRes.kyc.length > 0,
155
- });
156
- }
157
- }
158
- catch (error) {
159
- console.error("Failed to fetch profile after session switch:", error);
160
- }
161
- // Trigger onSession callback if set
162
- if (onSessionRef.current) {
163
- onSessionRef.current(restoredSession, link);
164
- onSessionRef.current = undefined;
165
- }
166
- // Mark session switch as complete
167
- isSwitchingSessionRef.current = false;
168
- }, [link, config.requesterAccount, config.apiMode, identityProofConfig]);
169
- const connect = useCallback((restoreSession, onSession, onProfile, onIdentityProof, onIdentityProofError) => {
170
- ConnectWallet({
171
- linkOptions: {
172
- endpoints: config.endpoints,
173
- restoreSession: restoreSession || false,
174
- },
175
- selectorOptions: {
176
- appName: config.dAppName,
177
- },
178
- transportOptions: {
179
- requestAccount: config.requesterAccount,
180
- },
181
- }).then(res => {
182
- onSessionRef.current = onSession;
183
- onProfileRef.current = onProfile;
184
- onIdentityProofRef.current = onIdentityProof;
185
- onIdentityProofErrorRef.current = onIdentityProofError;
186
- if (res.link && res.session) {
187
- // Update state with new session
188
- setLink(res.link);
189
- setSession(res.session);
190
- // Clear identity proof state for new session - it will be restored if stored token exists
191
- setIdentityProof(null);
192
- setIdentityProofStatus("idle");
193
- const actor = res.session.auth.actor.toString();
194
- // Trigger onSession callback
195
- if (onSession) {
196
- onSession(res.session, res.link);
197
- }
198
- // Fetch profile data
199
- const api = new ApiClass(config.apiMode === "testnet" ? "proton-test" : "proton");
200
- const permission = res.session.auth.permission.toString();
201
- const chainId = res.session.chainId.toString();
202
- api.getProtonAvatar(actor).then(profileRes => {
203
- if (profileRes) {
204
- const xprProfile = {
205
- displayName: profileRes.name,
206
- avatar: `${profileRes.avatar}`,
207
- isKyc: profileRes.kyc.length > 0,
208
- };
209
- setProfile(xprProfile);
210
- // Save session data to storage, preserving existing token if present
211
- const existingEntry = sessionStorage.get(config.requesterAccount, { actor, permission }, chainId);
212
- sessionStorage.save(config.requesterAccount, {
213
- auth: { actor, permission },
214
- chainId,
215
- profile: xprProfile,
216
- identityProofToken: existingEntry?.identityProofToken ?? null,
217
- });
218
- if (onProfile) {
219
- onProfile(xprProfile);
220
- }
221
- }
222
- });
223
- }
224
- });
225
- }, [config]);
226
- const disconnect = useCallback(async () => {
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) {
231
- console.warn("No session to disconnect");
232
- return;
233
- }
234
- try {
235
- await currentLink.removeSession(config.requesterAccount, currentSession.auth, currentSession.chainId);
236
- }
237
- catch (e) {
238
- console.error("Error removing session:", e);
239
- }
240
- // Clear state
241
- setSession(null);
242
- setProfile(null);
243
- setIdentityProof(null);
244
- setIdentityProofStatus("idle");
245
- // Note: Keep link reference for potential session switching
246
- }, [config.requesterAccount]);
247
- const addTxError = useCallback((message) => {
248
- errorsStackRef.current.push(parseTransactionErrorMessage(message));
249
- }, []);
250
- const requestIdentityProof = useCallback(async (success, fail) => {
251
- // Use ref to get the latest session value
252
- const currentSession = sessionRef.current;
253
- if (!currentSession) {
254
- fail(new Error("No session available for identity proof"));
255
- return;
256
- }
257
- if (!identityProofConfig) {
258
- fail(new Error("Identity proof not configured"));
259
- return;
260
- }
261
- // Idempotent: if already in progress, queue callbacks to be called when complete
262
- if (isAuthenticatingRef.current) {
263
- pendingCallbacksRef.current.push({ success, fail });
264
- return;
265
- }
266
- isAuthenticatingRef.current = true;
267
- try {
268
- // Step 1: Sign with wallet
269
- setIdentityProofStatus("signing");
270
- const proof = await createIdentityProof(currentSession);
271
- // Step 2: Verify with backend
272
- setIdentityProofStatus("verifying");
273
- const verifyRes = await verifyIdentityProof(proof, { createUrl: identityProofConfig.createUrl, headers: identityProofConfig.headers });
274
- // Step 3: Update state with identity proof data
275
- const identityProofData = {
276
- publicKey: proof.signer.publicKey,
277
- actor: proof.signer.actor,
278
- token: verifyRes.token,
279
- data: verifyRes,
280
- };
281
- setIdentityProof(identityProofData);
282
- setIdentityProofStatus("success");
283
- // Save token to storage
284
- if (verifyRes.token) {
285
- const actor = currentSession.auth.actor.toString();
286
- const permission = currentSession.auth.permission.toString();
287
- const chainId = currentSession.chainId.toString();
288
- sessionStorage.updateIdentityProofToken(config.requesterAccount, { actor, permission }, chainId, verifyRes.token);
289
- }
290
- success(identityProofData);
291
- // Call connect-level callback if registered
292
- if (onIdentityProofRef.current) {
293
- onIdentityProofRef.current(identityProofData);
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
- }
301
- }
302
- catch (error) {
303
- setIdentityProofStatus("error");
304
- fail(error);
305
- // Call connect-level error callback if registered
306
- if (onIdentityProofErrorRef.current) {
307
- onIdentityProofErrorRef.current(error instanceof Error ? error : new Error(String(error)));
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
- }
315
- }
316
- finally {
317
- isAuthenticatingRef.current = false;
318
- }
319
- }, [identityProofConfig, config.requesterAccount]);
320
- // Legacy alias
321
- const authenticate = requestIdentityProof;
322
- // Validate stored token silently
323
- const validateStoredToken = useCallback(async (actor, permission, chainId) => {
324
- if (!identityProofConfig?.validationUrl) {
325
- return false;
326
- }
327
- // Get stored token from session storage
328
- const storedEntry = sessionStorage.get(config.requesterAccount, { actor, permission }, chainId);
329
- const storedToken = storedEntry?.identityProofToken;
330
- if (!storedToken) {
331
- return false;
332
- }
333
- // Parse token to check if it's expired
334
- const tokenClaims = parseToken(storedToken);
335
- if (!tokenClaims) {
336
- return false;
337
- }
338
- // Check if token is expired
339
- if (isTokenExpired(tokenClaims)) {
340
- // Clear expired token from storage
341
- sessionStorage.updateIdentityProofToken(config.requesterAccount, { actor, permission }, chainId, null);
342
- return false;
343
- }
344
- // Validate token with backend
345
- setIdentityProofStatus("validating");
346
- try {
347
- const result = await validateIdentityProof({
348
- validationUrl: identityProofConfig.validationUrl,
349
- token: storedToken,
350
- headers: identityProofConfig.headers,
351
- timeout: identityProofConfig.timeout,
352
- });
353
- if (result.valid) {
354
- // Token is valid - update state
355
- const newToken = result.token || storedToken;
356
- setIdentityProof({
357
- actor,
358
- token: newToken,
359
- });
360
- setIdentityProofStatus("success");
361
- // Update token in storage if refreshed
362
- if (result.token && result.token !== storedToken) {
363
- sessionStorage.updateIdentityProofToken(config.requesterAccount, { actor, permission }, chainId, result.token);
364
- }
365
- return true;
366
- }
367
- else {
368
- // Clear invalid token from storage
369
- sessionStorage.updateIdentityProofToken(config.requesterAccount, { actor, permission }, chainId, null);
370
- setIdentityProofStatus("expired");
371
- return false;
372
- }
373
- }
374
- catch (error) {
375
- console.error("[XPRNProvider] Token validation error:", error);
376
- setIdentityProofStatus("error");
377
- return false;
378
- }
379
- }, [identityProofConfig, config.requesterAccount]);
380
- // Handle token restoration when session is established (no auto-authentication)
381
- // Note: This effect is skipped when switchToSession is handling the identity proof state
382
- useEffect(() => {
383
- // Skip if we're in the middle of a session switch (switchToSession handles this)
384
- if (isSwitchingSessionRef.current)
385
- return;
386
- if (!session || identityProof)
387
- return;
388
- if (!identityProofConfig?.validationUrl)
389
- return;
390
- const actor = session.auth.actor.toString();
391
- const permission = session.auth.permission.toString();
392
- const chainId = session.chainId.toString();
393
- // Check if there's a stored token and try to validate it silently
394
- const storedEntry = sessionStorage.get(config.requesterAccount, { actor, permission }, chainId);
395
- const hasStoredToken = storedEntry?.identityProofToken && typeof storedEntry.identityProofToken === 'string' && storedEntry.identityProofToken.length > 0;
396
- if (hasStoredToken) {
397
- // Try to validate stored token silently - dev handles the result via callbacks
398
- validateStoredToken(actor, permission, chainId);
399
- }
400
- }, [session, identityProof, identityProofConfig, config.requesterAccount, validateStoredToken]);
401
- // Handle profile callbacks
402
- useEffect(() => {
403
- if (profile && onProfileRef.current) {
404
- onProfileRef.current(profile);
405
- onProfileRef.current = undefined;
406
- }
407
- }, [profile]);
408
- // Session restoration on mount
409
- useEffect(() => {
410
- if (isRestoringRef.current)
411
- return;
412
- if (!session && config.restoreSession) {
413
- isRestoringRef.current = true;
414
- connect(true);
415
- }
416
- }, [config.restoreSession, connect, session]);
417
- // Helper to clear identity proof
418
- const clearIdentityProof = useCallback(() => {
419
- setIdentityProof(null);
420
- setIdentityProofStatus("idle");
421
- }, []);
422
- const providerValue = useMemo(() => {
423
- return {
424
- // Config
425
- config,
426
- // Session state
427
- session,
428
- link,
429
- profile,
430
- rpc: jsonRpcRef.current,
431
- // Identity proof state
432
- identityProof,
433
- identityProofStatus,
434
- isIdentityProofEnabled,
435
- // Core methods
436
- connect,
437
- disconnect,
438
- requestIdentityProof,
439
- // Identity proof setters (for custom flows)
440
- setIdentityProof,
441
- clearIdentityProof,
442
- setIdentityProofStatus,
443
- // Session switching
444
- listStoredSessions,
445
- switchToSession,
446
- // Utility
447
- addTransactionError: addTxError,
448
- // Legacy aliases
449
- authentication: identityProof,
450
- authStatus: identityProofStatus,
451
- authenticate: requestIdentityProof,
452
- };
453
- }, [
454
- config,
455
- session,
456
- link,
457
- profile,
458
- identityProof,
459
- identityProofStatus,
460
- isIdentityProofEnabled,
461
- connect,
462
- disconnect,
463
- requestIdentityProof,
464
- clearIdentityProof,
465
- listStoredSessions,
466
- switchToSession,
467
- addTxError,
468
- ]);
469
- return (_jsx(XPRNContext.Provider, { value: providerValue, children: children }));
470
- };
471
- export function useXPRN() {
472
- return useContext(XPRNContext);
473
- }
@@ -1,23 +0,0 @@
1
- import type { LinkSession } from "@proton/web-sdk";
2
- import type { IdentityProof } from "./types";
3
- export type CreateIdentityProofOptions = {
4
- /** AbortSignal for cancellation */
5
- signal?: AbortSignal;
6
- };
7
- /**
8
- * Creates an identity proof by signing a generateauth action with the wallet.
9
- *
10
- * This is a pure function that handles only the wallet signing step.
11
- * It does NOT send the proof to any backend - use `verifyIdentityProof` for that.
12
- *
13
- * @param session - The LinkSession from the connected wallet
14
- * @param options - Optional configuration (abort signal)
15
- * @returns Promise resolving to the signed IdentityProof
16
- *
17
- * @example
18
- * ```typescript
19
- * const proof = await createIdentityProof(session);
20
- * // proof contains: { signer, transaction, signatures }
21
- * ```
22
- */
23
- export declare function createIdentityProof(session: LinkSession, options?: CreateIdentityProofOptions): Promise<IdentityProof>;