decane-connect-kit 1.0.3 → 2.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +1107 -247
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +187 -35
- package/dist/index.d.ts +187 -35
- package/dist/index.js +1109 -246
- package/dist/index.js.map +1 -1
- package/package.json +9 -7
package/dist/index.d.cts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import * as _simplewebauthn_browser from '@simplewebauthn/browser';
|
|
1
2
|
import React, { ReactNode } from 'react';
|
|
2
3
|
|
|
3
4
|
type ChainType = "evm" | "solana" | "tron" | "bitcoin";
|
|
@@ -133,14 +134,6 @@ interface BitcoinProvider {
|
|
|
133
134
|
|
|
134
135
|
declare function createDecane(config?: DecaneConfig): DecaneProvider;
|
|
135
136
|
|
|
136
|
-
interface PhraseGenerationResult {
|
|
137
|
-
phrase: string;
|
|
138
|
-
challenge: Array<{
|
|
139
|
-
position: number;
|
|
140
|
-
expected: string;
|
|
141
|
-
}>;
|
|
142
|
-
}
|
|
143
|
-
|
|
144
137
|
declare class ApiClient {
|
|
145
138
|
private readonly baseUrl;
|
|
146
139
|
private readonly apiKey;
|
|
@@ -162,6 +155,8 @@ declare class ApiClient {
|
|
|
162
155
|
evmAddress: string;
|
|
163
156
|
solanaAddress: string;
|
|
164
157
|
}): Promise<void>;
|
|
158
|
+
getWebAuthnRegisterOptions(jwt: string, rpId: string, rpName: string): Promise<_simplewebauthn_browser.PublicKeyCredentialCreationOptionsJSON>;
|
|
159
|
+
postWebAuthnRegister(jwt: string, response: _simplewebauthn_browser.RegistrationResponseJSON, origin: string): Promise<void>;
|
|
165
160
|
revoke(jwt: string): Promise<void>;
|
|
166
161
|
hasRecoveryBackup(jwt: string): Promise<boolean>;
|
|
167
162
|
getRecoveryBackup(jwt: string): Promise<{
|
|
@@ -180,7 +175,14 @@ declare class ApiClient {
|
|
|
180
175
|
prfSalt: Uint8Array;
|
|
181
176
|
}): Promise<void>;
|
|
182
177
|
deleteRecoveryBackup(jwt: string): Promise<void>;
|
|
183
|
-
|
|
178
|
+
markRecoveryShareSaved(jwt: string): Promise<void>;
|
|
179
|
+
getRecoveryStatus(jwt: string): Promise<{
|
|
180
|
+
hasRecoveryShare: boolean;
|
|
181
|
+
savedAt: string | null;
|
|
182
|
+
nagged: boolean;
|
|
183
|
+
shareSetVersion: number;
|
|
184
|
+
}>;
|
|
185
|
+
dismissRecoveryNag(jwt: string): Promise<void>;
|
|
184
186
|
}
|
|
185
187
|
|
|
186
188
|
type RecoveryProgress = {
|
|
@@ -189,11 +191,57 @@ type RecoveryProgress = {
|
|
|
189
191
|
type: 'passkey-failed';
|
|
190
192
|
reason: string;
|
|
191
193
|
} | {
|
|
192
|
-
type: '
|
|
194
|
+
type: 'recovery-file-prompt';
|
|
195
|
+
} | {
|
|
196
|
+
type: 'password-prompt';
|
|
197
|
+
passwordHint: string | null;
|
|
193
198
|
} | {
|
|
194
|
-
type: '
|
|
199
|
+
type: 'recovery-verifying';
|
|
200
|
+
} | {
|
|
201
|
+
type: 'rotated';
|
|
202
|
+
shareSetVersion: number;
|
|
195
203
|
};
|
|
196
204
|
|
|
205
|
+
interface RecoveryShareFile {
|
|
206
|
+
version: number;
|
|
207
|
+
type: 'decane-recovery-share';
|
|
208
|
+
shareSetVersion: number;
|
|
209
|
+
kdf: 'pbkdf2-sha256';
|
|
210
|
+
kdfParams: {
|
|
211
|
+
iterations: number;
|
|
212
|
+
salt: string;
|
|
213
|
+
};
|
|
214
|
+
cipher: 'aes-256-gcm';
|
|
215
|
+
iv: string;
|
|
216
|
+
ciphertext: string;
|
|
217
|
+
addresses: {
|
|
218
|
+
evm: string;
|
|
219
|
+
solana: string;
|
|
220
|
+
};
|
|
221
|
+
passwordHint: string | null;
|
|
222
|
+
createdAt: string;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
interface PortableBackup {
|
|
226
|
+
version: number;
|
|
227
|
+
type: 'decane-portable-backup';
|
|
228
|
+
shareSetVersion: number;
|
|
229
|
+
kdf: 'pbkdf2-sha256';
|
|
230
|
+
kdfParams: {
|
|
231
|
+
iterations: number;
|
|
232
|
+
salt: string;
|
|
233
|
+
};
|
|
234
|
+
cipher: 'aes-256-gcm';
|
|
235
|
+
iv: string;
|
|
236
|
+
ciphertext: string;
|
|
237
|
+
addresses: {
|
|
238
|
+
evm: string;
|
|
239
|
+
solana: string;
|
|
240
|
+
};
|
|
241
|
+
passwordHint: string | null;
|
|
242
|
+
createdAt: string;
|
|
243
|
+
}
|
|
244
|
+
|
|
197
245
|
type Chain = `evm:${number}` | `solana:${'mainnet' | 'devnet'}`;
|
|
198
246
|
interface DecaneConnectConfig {
|
|
199
247
|
apiKey: string;
|
|
@@ -206,18 +254,36 @@ interface DecaneConnectConfig {
|
|
|
206
254
|
rpName?: string;
|
|
207
255
|
rpcUrls?: Record<string, string>;
|
|
208
256
|
teeUrl?: string;
|
|
209
|
-
/** Offer
|
|
210
|
-
|
|
211
|
-
/**
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
257
|
+
/** Offer to save a recovery-share file at signup. Default true. Never blocks onboarding. */
|
|
258
|
+
offerRecoveryAtSignup?: boolean;
|
|
259
|
+
/** Ask the user whether they want a recovery share and, if so, a password for it. */
|
|
260
|
+
onRecoveryShareOffer?: (addresses: {
|
|
261
|
+
evmAddress: string;
|
|
262
|
+
solanaAddress: string;
|
|
263
|
+
}) => Promise<{
|
|
264
|
+
wants: boolean;
|
|
265
|
+
password: string;
|
|
266
|
+
passwordHint?: string;
|
|
267
|
+
}>;
|
|
268
|
+
/** Hand the built file + suggested filename to the dApp, which owns the actual download. */
|
|
269
|
+
onRecoveryFileReady?: (file: RecoveryShareFile, filename: string) => Promise<void>;
|
|
270
|
+
/** Prompt for a recovery-share file (and its password) during Flow B. Return null to cancel. */
|
|
271
|
+
promptForRecoveryFile?: () => Promise<{
|
|
272
|
+
value: unknown;
|
|
273
|
+
getPassword: () => Promise<string | null>;
|
|
274
|
+
} | null>;
|
|
275
|
+
/**
|
|
276
|
+
* Every successful recovery/rotation invalidates the previous recovery
|
|
277
|
+
* file — this MUST prompt for a new password and block progress until the
|
|
278
|
+
* dApp confirms the user saved the new file (see MIGRATE_SSS_RECOVERY.md §10).
|
|
279
|
+
*/
|
|
280
|
+
onRecoveryRotated?: (addresses: {
|
|
281
|
+
evmAddress: string;
|
|
282
|
+
solanaAddress: string;
|
|
283
|
+
}) => Promise<{
|
|
284
|
+
password: string;
|
|
285
|
+
passwordHint?: string;
|
|
218
286
|
}>;
|
|
219
|
-
/** Prompt for a phrase during recovery. Return null to cancel. */
|
|
220
|
-
promptForRecoveryPhrase?: () => Promise<string | null>;
|
|
221
287
|
/** Recovery stage callbacks, for dApp UI. */
|
|
222
288
|
onRecoveryProgress?: (event: RecoveryProgress) => void;
|
|
223
289
|
}
|
|
@@ -250,6 +316,12 @@ interface DecaneConnect {
|
|
|
250
316
|
verifyEmailCode(email: string, code: string): Promise<ConnectResult>;
|
|
251
317
|
unlock(): Promise<void>;
|
|
252
318
|
isUnlocked(): boolean;
|
|
319
|
+
/**
|
|
320
|
+
* True when the user's identity is known from a previous visit but there is
|
|
321
|
+
* no live session, so unlock() cannot succeed and they must sign in again.
|
|
322
|
+
* Check this before offering an "Unlock" action.
|
|
323
|
+
*/
|
|
324
|
+
needsReconnect(): boolean;
|
|
253
325
|
sessionExpiresAt(): number | null;
|
|
254
326
|
signMessage(req: SignMessageRequest): Promise<string>;
|
|
255
327
|
sendTransaction(req: SendTransactionRequest): Promise<string>;
|
|
@@ -259,16 +331,32 @@ interface DecaneConnect {
|
|
|
259
331
|
evm?: string;
|
|
260
332
|
solana?: string;
|
|
261
333
|
} | null;
|
|
262
|
-
/**
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
}
|
|
334
|
+
/**
|
|
335
|
+
* Voluntary share rotation — after a suspected device compromise, or just
|
|
336
|
+
* to invalidate an old recovery file. Requires a fresh WebAuthn assertion.
|
|
337
|
+
* Returns the new recovery-share file (the caller still owns delivering it
|
|
338
|
+
* to the user — this does not download anything itself).
|
|
339
|
+
*/
|
|
340
|
+
rotateShares(opts: {
|
|
341
|
+
password: string;
|
|
342
|
+
passwordHint?: string;
|
|
343
|
+
}): Promise<RecoveryShareFile>;
|
|
344
|
+
/**
|
|
345
|
+
* The two-share bearer portable backup (device + recovery). This file plus
|
|
346
|
+
* its password gives complete control of the wallet — see the mandatory
|
|
347
|
+
* warning-screen requirements in MIGRATE_SSS_RECOVERY.md §10. Requires a
|
|
348
|
+
* fresh WebAuthn assertion and rotates the share set on every export.
|
|
349
|
+
*/
|
|
350
|
+
exportPortableBackup(opts: {
|
|
351
|
+
password: string;
|
|
352
|
+
passwordHint?: string;
|
|
353
|
+
}): Promise<PortableBackup>;
|
|
354
|
+
/** Whether the user has ever saved a recovery-share file (UX flag only — Decane never stores the share). */
|
|
355
|
+
hasRecoveryShare(): Promise<boolean>;
|
|
356
|
+
/** True at most once per account: no recovery share saved, never nagged, wallet holds value. */
|
|
357
|
+
shouldPromptRecovery(): Promise<boolean>;
|
|
358
|
+
/** Call regardless of the user's answer — the recovery nag fires once, ever. */
|
|
359
|
+
dismissRecoveryPrompt(): Promise<void>;
|
|
272
360
|
/** Whether a wrapped-share backup exists on the server. */
|
|
273
361
|
hasBackup(): Promise<boolean>;
|
|
274
362
|
/** Delete the server-side backup. Disables Flow A recovery. */
|
|
@@ -319,6 +407,22 @@ declare class SessionExpiredError extends DecaneConnectError {
|
|
|
319
407
|
declare class UnlockRequiredError extends DecaneConnectError {
|
|
320
408
|
constructor();
|
|
321
409
|
}
|
|
410
|
+
/**
|
|
411
|
+
* unlock() was called after a page reload (or any other loss of the in-memory
|
|
412
|
+
* auth state). We still know *who* the user is — their identity and addresses
|
|
413
|
+
* are persisted — but unlock() needs a live JWT to open a TEE session, and
|
|
414
|
+
* JWTs are deliberately never persisted. So there is no unlock() that can
|
|
415
|
+
* succeed here; the user has to re-authenticate.
|
|
416
|
+
*
|
|
417
|
+
* This is its own error type rather than a generic CallSequenceError because
|
|
418
|
+
* it is a *routing* signal, not a programming mistake: the correct response is
|
|
419
|
+
* to show the sign-in UI, which callers can only do reliably if they can tell
|
|
420
|
+
* this case apart from "you never called connect()". Prefer checking
|
|
421
|
+
* needsReconnect() up front so this never has to be caught at all.
|
|
422
|
+
*/
|
|
423
|
+
declare class ReconnectRequiredError extends DecaneConnectError {
|
|
424
|
+
constructor();
|
|
425
|
+
}
|
|
322
426
|
declare class UserCancelledError extends DecaneConnectError {
|
|
323
427
|
constructor();
|
|
324
428
|
}
|
|
@@ -349,7 +453,16 @@ declare class AttestationError extends DecaneConnectError {
|
|
|
349
453
|
declare class RecoveryFailedError extends DecaneConnectError {
|
|
350
454
|
constructor(reason: string);
|
|
351
455
|
}
|
|
352
|
-
declare class
|
|
456
|
+
declare class InvalidRecoveryFileError extends DecaneConnectError {
|
|
457
|
+
constructor();
|
|
458
|
+
}
|
|
459
|
+
declare class WrongPasswordError extends DecaneConnectError {
|
|
460
|
+
constructor();
|
|
461
|
+
}
|
|
462
|
+
declare class RecoveryWalletMismatchError extends DecaneConnectError {
|
|
463
|
+
constructor();
|
|
464
|
+
}
|
|
465
|
+
declare class ExportNotAuthorizedError extends DecaneConnectError {
|
|
353
466
|
constructor();
|
|
354
467
|
}
|
|
355
468
|
|
|
@@ -467,6 +580,16 @@ interface SocialAuthState {
|
|
|
467
580
|
isNewUser: boolean;
|
|
468
581
|
isUnlocked: boolean;
|
|
469
582
|
sessionExpiresAt: number | null;
|
|
583
|
+
/**
|
|
584
|
+
* True when `addresses` came from persisted (localStorage) identity only,
|
|
585
|
+
* with no live session. This is NOT the same as "locked" — every unlock()
|
|
586
|
+
* requires a fresh, valid JWT to open a TEE session, and JWTs are
|
|
587
|
+
* deliberately never persisted (short-lived, security-sensitive), so
|
|
588
|
+
* there is no legitimate "just unlock" path in this state. A consumer
|
|
589
|
+
* should route this into a full reconnect (connectWithGoogle() /
|
|
590
|
+
* connectWithEmail()), not unlock() — which will always throw here.
|
|
591
|
+
*/
|
|
592
|
+
needsReconnect: boolean;
|
|
470
593
|
}
|
|
471
594
|
interface DecaneKitProps {
|
|
472
595
|
config?: DecaneConfig;
|
|
@@ -481,8 +604,24 @@ interface SocialWalletModalProps {
|
|
|
481
604
|
socialAuth: SocialAuthState;
|
|
482
605
|
onUnlock: () => Promise<void>;
|
|
483
606
|
onDisconnect: () => Promise<void>;
|
|
607
|
+
onGoogleSignIn: () => Promise<void>;
|
|
608
|
+
onEmailStart: (email: string) => Promise<{
|
|
609
|
+
codeRequired: true;
|
|
610
|
+
}>;
|
|
611
|
+
onEmailVerify: (email: string, code: string) => Promise<void>;
|
|
612
|
+
authMethods?: Array<"google" | "email">;
|
|
613
|
+
onRotateShares: (opts: {
|
|
614
|
+
password: string;
|
|
615
|
+
passwordHint?: string;
|
|
616
|
+
}) => Promise<RecoveryShareFile>;
|
|
617
|
+
onExportPortableBackup: (opts: {
|
|
618
|
+
password: string;
|
|
619
|
+
passwordHint?: string;
|
|
620
|
+
}) => Promise<PortableBackup>;
|
|
621
|
+
rpcUrls?: Record<string, string>;
|
|
622
|
+
chains?: string[];
|
|
484
623
|
}
|
|
485
|
-
declare function SocialWalletModal({ open, onClose, theme, socialAuth, onUnlock, onDisconnect, }: SocialWalletModalProps): React.ReactPortal | null;
|
|
624
|
+
declare function SocialWalletModal({ open, onClose, theme, socialAuth, onUnlock, onDisconnect, onGoogleSignIn, onEmailStart, onEmailVerify, authMethods, onRotateShares, onExportPortableBackup, rpcUrls, chains, }: SocialWalletModalProps): React.ReactPortal | null;
|
|
486
625
|
|
|
487
626
|
declare function useSocialAuth(): {
|
|
488
627
|
isConnected: boolean;
|
|
@@ -493,6 +632,7 @@ declare function useSocialAuth(): {
|
|
|
493
632
|
solana?: string;
|
|
494
633
|
} | null;
|
|
495
634
|
sessionExpiresAt: number | null;
|
|
635
|
+
needsReconnect: boolean;
|
|
496
636
|
googleLoading: boolean;
|
|
497
637
|
emailLoading: boolean;
|
|
498
638
|
error: string | null;
|
|
@@ -514,6 +654,7 @@ declare function useSocialWallet(): {
|
|
|
514
654
|
solana?: string;
|
|
515
655
|
} | null;
|
|
516
656
|
sessionExpiresAt: number | null;
|
|
657
|
+
needsReconnect: boolean;
|
|
517
658
|
modalOpen: boolean;
|
|
518
659
|
openModal: () => void;
|
|
519
660
|
closeModal: () => void;
|
|
@@ -529,6 +670,17 @@ declare function useSocialWallet(): {
|
|
|
529
670
|
gasPrice?: bigint;
|
|
530
671
|
}) => Promise<string>;
|
|
531
672
|
signSolanaTransaction: (tx: Uint8Array) => Promise<Uint8Array<ArrayBufferLike>>;
|
|
673
|
+
rotateShares: (opts: {
|
|
674
|
+
password: string;
|
|
675
|
+
passwordHint?: string;
|
|
676
|
+
}) => Promise<RecoveryShareFile>;
|
|
677
|
+
exportPortableBackup: (opts: {
|
|
678
|
+
password: string;
|
|
679
|
+
passwordHint?: string;
|
|
680
|
+
}) => Promise<PortableBackup>;
|
|
681
|
+
hasRecoveryShare: () => Promise<boolean>;
|
|
682
|
+
shouldPromptRecovery: () => Promise<boolean>;
|
|
683
|
+
dismissRecoveryPrompt: () => Promise<void>;
|
|
532
684
|
loading: boolean;
|
|
533
685
|
error: string | null;
|
|
534
686
|
clearError: () => void;
|
|
@@ -605,4 +757,4 @@ declare function useSignTypedData(): {
|
|
|
605
757
|
reset: () => void;
|
|
606
758
|
};
|
|
607
759
|
|
|
608
|
-
export { type ActiveSession, AttestationError, type AuthResult, BUILT_IN_CHAINS, type CAIP25Method, type CAIP25SessionRequest, type CAIP25SessionResult, CHAINS, CallSequenceError, type Chain, type ChainDescriptor, type ChainId, type ChainScope, type ChainSupport, type ChainType, type ConnectMode, type ConnectResult, type DecaneConfig, type DecaneConnect, type DecaneConnectConfig, DecaneConnectError, DecaneError, DecaneErrorCode, DecaneKit, type DecaneProvider,
|
|
760
|
+
export { type ActiveSession, AttestationError, type AuthResult, BUILT_IN_CHAINS, type CAIP25Method, type CAIP25SessionRequest, type CAIP25SessionResult, CHAINS, CallSequenceError, type Chain, type ChainDescriptor, type ChainId, type ChainScope, type ChainSupport, type ChainType, type ConnectMode, type ConnectResult, type DecaneConfig, type DecaneConnect, type DecaneConnectConfig, DecaneConnectError, DecaneError, DecaneErrorCode, DecaneKit, type DecaneProvider, ExportNotAuthorizedError, InvalidApiKeyError, InvalidPinError, InvalidRecoveryFileError, NetworkError, NewDeviceError, OriginNotAllowedError, type PortableBackup, PromptPinNotConfiguredError, ReconnectRequiredError, RecoveryFailedError, type RecoveryProgress, type RecoveryShareFile, RecoveryWalletMismatchError, type SdkEvent, type SendTransactionRequest, SessionExpiredError, ShareCorruptedError, type SignMessageRequest, type SocialAuthState, type SocialConfig, SocialWalletModal, type Theme, type TxParams, type UnifiedWalletAccount, UnlockRequiredError, UserCancelledError, WalletSelector, WebAuthnNotSupportedError, type WrappedShareMeta, WrongPasswordError, createDecane, createDecaneConnect, startEmailAuth, useChainSwitch, useDecane, useSendTransaction, useSignMessage, useSignTypedData, useSocialAuth, useSocialWallet, useWalletSelector, verifyEmailCode };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import * as _simplewebauthn_browser from '@simplewebauthn/browser';
|
|
1
2
|
import React, { ReactNode } from 'react';
|
|
2
3
|
|
|
3
4
|
type ChainType = "evm" | "solana" | "tron" | "bitcoin";
|
|
@@ -133,14 +134,6 @@ interface BitcoinProvider {
|
|
|
133
134
|
|
|
134
135
|
declare function createDecane(config?: DecaneConfig): DecaneProvider;
|
|
135
136
|
|
|
136
|
-
interface PhraseGenerationResult {
|
|
137
|
-
phrase: string;
|
|
138
|
-
challenge: Array<{
|
|
139
|
-
position: number;
|
|
140
|
-
expected: string;
|
|
141
|
-
}>;
|
|
142
|
-
}
|
|
143
|
-
|
|
144
137
|
declare class ApiClient {
|
|
145
138
|
private readonly baseUrl;
|
|
146
139
|
private readonly apiKey;
|
|
@@ -162,6 +155,8 @@ declare class ApiClient {
|
|
|
162
155
|
evmAddress: string;
|
|
163
156
|
solanaAddress: string;
|
|
164
157
|
}): Promise<void>;
|
|
158
|
+
getWebAuthnRegisterOptions(jwt: string, rpId: string, rpName: string): Promise<_simplewebauthn_browser.PublicKeyCredentialCreationOptionsJSON>;
|
|
159
|
+
postWebAuthnRegister(jwt: string, response: _simplewebauthn_browser.RegistrationResponseJSON, origin: string): Promise<void>;
|
|
165
160
|
revoke(jwt: string): Promise<void>;
|
|
166
161
|
hasRecoveryBackup(jwt: string): Promise<boolean>;
|
|
167
162
|
getRecoveryBackup(jwt: string): Promise<{
|
|
@@ -180,7 +175,14 @@ declare class ApiClient {
|
|
|
180
175
|
prfSalt: Uint8Array;
|
|
181
176
|
}): Promise<void>;
|
|
182
177
|
deleteRecoveryBackup(jwt: string): Promise<void>;
|
|
183
|
-
|
|
178
|
+
markRecoveryShareSaved(jwt: string): Promise<void>;
|
|
179
|
+
getRecoveryStatus(jwt: string): Promise<{
|
|
180
|
+
hasRecoveryShare: boolean;
|
|
181
|
+
savedAt: string | null;
|
|
182
|
+
nagged: boolean;
|
|
183
|
+
shareSetVersion: number;
|
|
184
|
+
}>;
|
|
185
|
+
dismissRecoveryNag(jwt: string): Promise<void>;
|
|
184
186
|
}
|
|
185
187
|
|
|
186
188
|
type RecoveryProgress = {
|
|
@@ -189,11 +191,57 @@ type RecoveryProgress = {
|
|
|
189
191
|
type: 'passkey-failed';
|
|
190
192
|
reason: string;
|
|
191
193
|
} | {
|
|
192
|
-
type: '
|
|
194
|
+
type: 'recovery-file-prompt';
|
|
195
|
+
} | {
|
|
196
|
+
type: 'password-prompt';
|
|
197
|
+
passwordHint: string | null;
|
|
193
198
|
} | {
|
|
194
|
-
type: '
|
|
199
|
+
type: 'recovery-verifying';
|
|
200
|
+
} | {
|
|
201
|
+
type: 'rotated';
|
|
202
|
+
shareSetVersion: number;
|
|
195
203
|
};
|
|
196
204
|
|
|
205
|
+
interface RecoveryShareFile {
|
|
206
|
+
version: number;
|
|
207
|
+
type: 'decane-recovery-share';
|
|
208
|
+
shareSetVersion: number;
|
|
209
|
+
kdf: 'pbkdf2-sha256';
|
|
210
|
+
kdfParams: {
|
|
211
|
+
iterations: number;
|
|
212
|
+
salt: string;
|
|
213
|
+
};
|
|
214
|
+
cipher: 'aes-256-gcm';
|
|
215
|
+
iv: string;
|
|
216
|
+
ciphertext: string;
|
|
217
|
+
addresses: {
|
|
218
|
+
evm: string;
|
|
219
|
+
solana: string;
|
|
220
|
+
};
|
|
221
|
+
passwordHint: string | null;
|
|
222
|
+
createdAt: string;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
interface PortableBackup {
|
|
226
|
+
version: number;
|
|
227
|
+
type: 'decane-portable-backup';
|
|
228
|
+
shareSetVersion: number;
|
|
229
|
+
kdf: 'pbkdf2-sha256';
|
|
230
|
+
kdfParams: {
|
|
231
|
+
iterations: number;
|
|
232
|
+
salt: string;
|
|
233
|
+
};
|
|
234
|
+
cipher: 'aes-256-gcm';
|
|
235
|
+
iv: string;
|
|
236
|
+
ciphertext: string;
|
|
237
|
+
addresses: {
|
|
238
|
+
evm: string;
|
|
239
|
+
solana: string;
|
|
240
|
+
};
|
|
241
|
+
passwordHint: string | null;
|
|
242
|
+
createdAt: string;
|
|
243
|
+
}
|
|
244
|
+
|
|
197
245
|
type Chain = `evm:${number}` | `solana:${'mainnet' | 'devnet'}`;
|
|
198
246
|
interface DecaneConnectConfig {
|
|
199
247
|
apiKey: string;
|
|
@@ -206,18 +254,36 @@ interface DecaneConnectConfig {
|
|
|
206
254
|
rpName?: string;
|
|
207
255
|
rpcUrls?: Record<string, string>;
|
|
208
256
|
teeUrl?: string;
|
|
209
|
-
/** Offer
|
|
210
|
-
|
|
211
|
-
/**
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
257
|
+
/** Offer to save a recovery-share file at signup. Default true. Never blocks onboarding. */
|
|
258
|
+
offerRecoveryAtSignup?: boolean;
|
|
259
|
+
/** Ask the user whether they want a recovery share and, if so, a password for it. */
|
|
260
|
+
onRecoveryShareOffer?: (addresses: {
|
|
261
|
+
evmAddress: string;
|
|
262
|
+
solanaAddress: string;
|
|
263
|
+
}) => Promise<{
|
|
264
|
+
wants: boolean;
|
|
265
|
+
password: string;
|
|
266
|
+
passwordHint?: string;
|
|
267
|
+
}>;
|
|
268
|
+
/** Hand the built file + suggested filename to the dApp, which owns the actual download. */
|
|
269
|
+
onRecoveryFileReady?: (file: RecoveryShareFile, filename: string) => Promise<void>;
|
|
270
|
+
/** Prompt for a recovery-share file (and its password) during Flow B. Return null to cancel. */
|
|
271
|
+
promptForRecoveryFile?: () => Promise<{
|
|
272
|
+
value: unknown;
|
|
273
|
+
getPassword: () => Promise<string | null>;
|
|
274
|
+
} | null>;
|
|
275
|
+
/**
|
|
276
|
+
* Every successful recovery/rotation invalidates the previous recovery
|
|
277
|
+
* file — this MUST prompt for a new password and block progress until the
|
|
278
|
+
* dApp confirms the user saved the new file (see MIGRATE_SSS_RECOVERY.md §10).
|
|
279
|
+
*/
|
|
280
|
+
onRecoveryRotated?: (addresses: {
|
|
281
|
+
evmAddress: string;
|
|
282
|
+
solanaAddress: string;
|
|
283
|
+
}) => Promise<{
|
|
284
|
+
password: string;
|
|
285
|
+
passwordHint?: string;
|
|
218
286
|
}>;
|
|
219
|
-
/** Prompt for a phrase during recovery. Return null to cancel. */
|
|
220
|
-
promptForRecoveryPhrase?: () => Promise<string | null>;
|
|
221
287
|
/** Recovery stage callbacks, for dApp UI. */
|
|
222
288
|
onRecoveryProgress?: (event: RecoveryProgress) => void;
|
|
223
289
|
}
|
|
@@ -250,6 +316,12 @@ interface DecaneConnect {
|
|
|
250
316
|
verifyEmailCode(email: string, code: string): Promise<ConnectResult>;
|
|
251
317
|
unlock(): Promise<void>;
|
|
252
318
|
isUnlocked(): boolean;
|
|
319
|
+
/**
|
|
320
|
+
* True when the user's identity is known from a previous visit but there is
|
|
321
|
+
* no live session, so unlock() cannot succeed and they must sign in again.
|
|
322
|
+
* Check this before offering an "Unlock" action.
|
|
323
|
+
*/
|
|
324
|
+
needsReconnect(): boolean;
|
|
253
325
|
sessionExpiresAt(): number | null;
|
|
254
326
|
signMessage(req: SignMessageRequest): Promise<string>;
|
|
255
327
|
sendTransaction(req: SendTransactionRequest): Promise<string>;
|
|
@@ -259,16 +331,32 @@ interface DecaneConnect {
|
|
|
259
331
|
evm?: string;
|
|
260
332
|
solana?: string;
|
|
261
333
|
} | null;
|
|
262
|
-
/**
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
}
|
|
334
|
+
/**
|
|
335
|
+
* Voluntary share rotation — after a suspected device compromise, or just
|
|
336
|
+
* to invalidate an old recovery file. Requires a fresh WebAuthn assertion.
|
|
337
|
+
* Returns the new recovery-share file (the caller still owns delivering it
|
|
338
|
+
* to the user — this does not download anything itself).
|
|
339
|
+
*/
|
|
340
|
+
rotateShares(opts: {
|
|
341
|
+
password: string;
|
|
342
|
+
passwordHint?: string;
|
|
343
|
+
}): Promise<RecoveryShareFile>;
|
|
344
|
+
/**
|
|
345
|
+
* The two-share bearer portable backup (device + recovery). This file plus
|
|
346
|
+
* its password gives complete control of the wallet — see the mandatory
|
|
347
|
+
* warning-screen requirements in MIGRATE_SSS_RECOVERY.md §10. Requires a
|
|
348
|
+
* fresh WebAuthn assertion and rotates the share set on every export.
|
|
349
|
+
*/
|
|
350
|
+
exportPortableBackup(opts: {
|
|
351
|
+
password: string;
|
|
352
|
+
passwordHint?: string;
|
|
353
|
+
}): Promise<PortableBackup>;
|
|
354
|
+
/** Whether the user has ever saved a recovery-share file (UX flag only — Decane never stores the share). */
|
|
355
|
+
hasRecoveryShare(): Promise<boolean>;
|
|
356
|
+
/** True at most once per account: no recovery share saved, never nagged, wallet holds value. */
|
|
357
|
+
shouldPromptRecovery(): Promise<boolean>;
|
|
358
|
+
/** Call regardless of the user's answer — the recovery nag fires once, ever. */
|
|
359
|
+
dismissRecoveryPrompt(): Promise<void>;
|
|
272
360
|
/** Whether a wrapped-share backup exists on the server. */
|
|
273
361
|
hasBackup(): Promise<boolean>;
|
|
274
362
|
/** Delete the server-side backup. Disables Flow A recovery. */
|
|
@@ -319,6 +407,22 @@ declare class SessionExpiredError extends DecaneConnectError {
|
|
|
319
407
|
declare class UnlockRequiredError extends DecaneConnectError {
|
|
320
408
|
constructor();
|
|
321
409
|
}
|
|
410
|
+
/**
|
|
411
|
+
* unlock() was called after a page reload (or any other loss of the in-memory
|
|
412
|
+
* auth state). We still know *who* the user is — their identity and addresses
|
|
413
|
+
* are persisted — but unlock() needs a live JWT to open a TEE session, and
|
|
414
|
+
* JWTs are deliberately never persisted. So there is no unlock() that can
|
|
415
|
+
* succeed here; the user has to re-authenticate.
|
|
416
|
+
*
|
|
417
|
+
* This is its own error type rather than a generic CallSequenceError because
|
|
418
|
+
* it is a *routing* signal, not a programming mistake: the correct response is
|
|
419
|
+
* to show the sign-in UI, which callers can only do reliably if they can tell
|
|
420
|
+
* this case apart from "you never called connect()". Prefer checking
|
|
421
|
+
* needsReconnect() up front so this never has to be caught at all.
|
|
422
|
+
*/
|
|
423
|
+
declare class ReconnectRequiredError extends DecaneConnectError {
|
|
424
|
+
constructor();
|
|
425
|
+
}
|
|
322
426
|
declare class UserCancelledError extends DecaneConnectError {
|
|
323
427
|
constructor();
|
|
324
428
|
}
|
|
@@ -349,7 +453,16 @@ declare class AttestationError extends DecaneConnectError {
|
|
|
349
453
|
declare class RecoveryFailedError extends DecaneConnectError {
|
|
350
454
|
constructor(reason: string);
|
|
351
455
|
}
|
|
352
|
-
declare class
|
|
456
|
+
declare class InvalidRecoveryFileError extends DecaneConnectError {
|
|
457
|
+
constructor();
|
|
458
|
+
}
|
|
459
|
+
declare class WrongPasswordError extends DecaneConnectError {
|
|
460
|
+
constructor();
|
|
461
|
+
}
|
|
462
|
+
declare class RecoveryWalletMismatchError extends DecaneConnectError {
|
|
463
|
+
constructor();
|
|
464
|
+
}
|
|
465
|
+
declare class ExportNotAuthorizedError extends DecaneConnectError {
|
|
353
466
|
constructor();
|
|
354
467
|
}
|
|
355
468
|
|
|
@@ -467,6 +580,16 @@ interface SocialAuthState {
|
|
|
467
580
|
isNewUser: boolean;
|
|
468
581
|
isUnlocked: boolean;
|
|
469
582
|
sessionExpiresAt: number | null;
|
|
583
|
+
/**
|
|
584
|
+
* True when `addresses` came from persisted (localStorage) identity only,
|
|
585
|
+
* with no live session. This is NOT the same as "locked" — every unlock()
|
|
586
|
+
* requires a fresh, valid JWT to open a TEE session, and JWTs are
|
|
587
|
+
* deliberately never persisted (short-lived, security-sensitive), so
|
|
588
|
+
* there is no legitimate "just unlock" path in this state. A consumer
|
|
589
|
+
* should route this into a full reconnect (connectWithGoogle() /
|
|
590
|
+
* connectWithEmail()), not unlock() — which will always throw here.
|
|
591
|
+
*/
|
|
592
|
+
needsReconnect: boolean;
|
|
470
593
|
}
|
|
471
594
|
interface DecaneKitProps {
|
|
472
595
|
config?: DecaneConfig;
|
|
@@ -481,8 +604,24 @@ interface SocialWalletModalProps {
|
|
|
481
604
|
socialAuth: SocialAuthState;
|
|
482
605
|
onUnlock: () => Promise<void>;
|
|
483
606
|
onDisconnect: () => Promise<void>;
|
|
607
|
+
onGoogleSignIn: () => Promise<void>;
|
|
608
|
+
onEmailStart: (email: string) => Promise<{
|
|
609
|
+
codeRequired: true;
|
|
610
|
+
}>;
|
|
611
|
+
onEmailVerify: (email: string, code: string) => Promise<void>;
|
|
612
|
+
authMethods?: Array<"google" | "email">;
|
|
613
|
+
onRotateShares: (opts: {
|
|
614
|
+
password: string;
|
|
615
|
+
passwordHint?: string;
|
|
616
|
+
}) => Promise<RecoveryShareFile>;
|
|
617
|
+
onExportPortableBackup: (opts: {
|
|
618
|
+
password: string;
|
|
619
|
+
passwordHint?: string;
|
|
620
|
+
}) => Promise<PortableBackup>;
|
|
621
|
+
rpcUrls?: Record<string, string>;
|
|
622
|
+
chains?: string[];
|
|
484
623
|
}
|
|
485
|
-
declare function SocialWalletModal({ open, onClose, theme, socialAuth, onUnlock, onDisconnect, }: SocialWalletModalProps): React.ReactPortal | null;
|
|
624
|
+
declare function SocialWalletModal({ open, onClose, theme, socialAuth, onUnlock, onDisconnect, onGoogleSignIn, onEmailStart, onEmailVerify, authMethods, onRotateShares, onExportPortableBackup, rpcUrls, chains, }: SocialWalletModalProps): React.ReactPortal | null;
|
|
486
625
|
|
|
487
626
|
declare function useSocialAuth(): {
|
|
488
627
|
isConnected: boolean;
|
|
@@ -493,6 +632,7 @@ declare function useSocialAuth(): {
|
|
|
493
632
|
solana?: string;
|
|
494
633
|
} | null;
|
|
495
634
|
sessionExpiresAt: number | null;
|
|
635
|
+
needsReconnect: boolean;
|
|
496
636
|
googleLoading: boolean;
|
|
497
637
|
emailLoading: boolean;
|
|
498
638
|
error: string | null;
|
|
@@ -514,6 +654,7 @@ declare function useSocialWallet(): {
|
|
|
514
654
|
solana?: string;
|
|
515
655
|
} | null;
|
|
516
656
|
sessionExpiresAt: number | null;
|
|
657
|
+
needsReconnect: boolean;
|
|
517
658
|
modalOpen: boolean;
|
|
518
659
|
openModal: () => void;
|
|
519
660
|
closeModal: () => void;
|
|
@@ -529,6 +670,17 @@ declare function useSocialWallet(): {
|
|
|
529
670
|
gasPrice?: bigint;
|
|
530
671
|
}) => Promise<string>;
|
|
531
672
|
signSolanaTransaction: (tx: Uint8Array) => Promise<Uint8Array<ArrayBufferLike>>;
|
|
673
|
+
rotateShares: (opts: {
|
|
674
|
+
password: string;
|
|
675
|
+
passwordHint?: string;
|
|
676
|
+
}) => Promise<RecoveryShareFile>;
|
|
677
|
+
exportPortableBackup: (opts: {
|
|
678
|
+
password: string;
|
|
679
|
+
passwordHint?: string;
|
|
680
|
+
}) => Promise<PortableBackup>;
|
|
681
|
+
hasRecoveryShare: () => Promise<boolean>;
|
|
682
|
+
shouldPromptRecovery: () => Promise<boolean>;
|
|
683
|
+
dismissRecoveryPrompt: () => Promise<void>;
|
|
532
684
|
loading: boolean;
|
|
533
685
|
error: string | null;
|
|
534
686
|
clearError: () => void;
|
|
@@ -605,4 +757,4 @@ declare function useSignTypedData(): {
|
|
|
605
757
|
reset: () => void;
|
|
606
758
|
};
|
|
607
759
|
|
|
608
|
-
export { type ActiveSession, AttestationError, type AuthResult, BUILT_IN_CHAINS, type CAIP25Method, type CAIP25SessionRequest, type CAIP25SessionResult, CHAINS, CallSequenceError, type Chain, type ChainDescriptor, type ChainId, type ChainScope, type ChainSupport, type ChainType, type ConnectMode, type ConnectResult, type DecaneConfig, type DecaneConnect, type DecaneConnectConfig, DecaneConnectError, DecaneError, DecaneErrorCode, DecaneKit, type DecaneProvider,
|
|
760
|
+
export { type ActiveSession, AttestationError, type AuthResult, BUILT_IN_CHAINS, type CAIP25Method, type CAIP25SessionRequest, type CAIP25SessionResult, CHAINS, CallSequenceError, type Chain, type ChainDescriptor, type ChainId, type ChainScope, type ChainSupport, type ChainType, type ConnectMode, type ConnectResult, type DecaneConfig, type DecaneConnect, type DecaneConnectConfig, DecaneConnectError, DecaneError, DecaneErrorCode, DecaneKit, type DecaneProvider, ExportNotAuthorizedError, InvalidApiKeyError, InvalidPinError, InvalidRecoveryFileError, NetworkError, NewDeviceError, OriginNotAllowedError, type PortableBackup, PromptPinNotConfiguredError, ReconnectRequiredError, RecoveryFailedError, type RecoveryProgress, type RecoveryShareFile, RecoveryWalletMismatchError, type SdkEvent, type SendTransactionRequest, SessionExpiredError, ShareCorruptedError, type SignMessageRequest, type SocialAuthState, type SocialConfig, SocialWalletModal, type Theme, type TxParams, type UnifiedWalletAccount, UnlockRequiredError, UserCancelledError, WalletSelector, WebAuthnNotSupportedError, type WrappedShareMeta, WrongPasswordError, createDecane, createDecaneConnect, startEmailAuth, useChainSwitch, useDecane, useSendTransaction, useSignMessage, useSignTypedData, useSocialAuth, useSocialWallet, useWalletSelector, verifyEmailCode };
|