decane-connect-kit 2.7.2 → 2.7.3
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 +90 -14
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +32 -2
- package/dist/index.d.ts +32 -2
- package/dist/index.js +89 -14
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -256,6 +256,13 @@ declare class ApiClient {
|
|
|
256
256
|
savedAt: string | null;
|
|
257
257
|
nagged: boolean;
|
|
258
258
|
shareSetVersion: number;
|
|
259
|
+
/**
|
|
260
|
+
* Whether this wallet is enrolled for server-assisted provisioning, i.e.
|
|
261
|
+
* whether a new device can be given a device share from login alone.
|
|
262
|
+
* Optional because backends older than this field simply omit it — treat
|
|
263
|
+
* `undefined` as "unknown", never as "not enrolled".
|
|
264
|
+
*/
|
|
265
|
+
enrolled?: boolean;
|
|
259
266
|
}>;
|
|
260
267
|
dismissRecoveryNag(jwt: string): Promise<void>;
|
|
261
268
|
}
|
|
@@ -521,7 +528,16 @@ interface SignTypedDataRequest {
|
|
|
521
528
|
message: Record<string, unknown>;
|
|
522
529
|
primaryType?: string;
|
|
523
530
|
}
|
|
524
|
-
type SdkEvent = 'connected' | 'disconnected' | 'session-expired' | 'session-started' | 'wallet-creating' | 'wallet-unlocking'
|
|
531
|
+
type SdkEvent = 'connected' | 'disconnected' | 'session-expired' | 'session-started' | 'wallet-creating' | 'wallet-unlocking'
|
|
532
|
+
/**
|
|
533
|
+
* Emitted when this wallet could not be enrolled for server-assisted
|
|
534
|
+
* recovery. Not fatal — the wallet works — but until it is enrolled the user
|
|
535
|
+
* cannot get a device share from login alone, so a future new device will
|
|
536
|
+
* need a passkey backup or a recovery file. The SDK retries automatically on
|
|
537
|
+
* later unlocks; surface or report this if you want visibility rather than a
|
|
538
|
+
* console line.
|
|
539
|
+
*/
|
|
540
|
+
| 'enrolment-failed';
|
|
525
541
|
interface DecaneConnect {
|
|
526
542
|
connect(): Promise<ConnectResult>;
|
|
527
543
|
connectWithGoogle(): Promise<ConnectResult>;
|
|
@@ -808,6 +824,20 @@ declare class NetworkError extends DecaneConnectError {
|
|
|
808
824
|
declare class ShareCorruptedError extends DecaneConnectError {
|
|
809
825
|
constructor();
|
|
810
826
|
}
|
|
827
|
+
/**
|
|
828
|
+
* Wallet creation exceeded its time budget.
|
|
829
|
+
*
|
|
830
|
+
* Provisioning is bounded so a stalled network or an unresponsive enclave
|
|
831
|
+
* surfaces as an error the app can act on, rather than a signup that appears to
|
|
832
|
+
* hang forever. The budget covers only the SDK's own work — key generation,
|
|
833
|
+
* share storage, opening the signer session — never time spent waiting on the
|
|
834
|
+
* user (a passkey prompt, choosing a PIN, the recovery-file dialog).
|
|
835
|
+
*
|
|
836
|
+
* Retryable: nothing is left half-created that a later sign-in cannot complete.
|
|
837
|
+
*/
|
|
838
|
+
declare class ProvisioningTimeoutError extends DecaneConnectError {
|
|
839
|
+
constructor(step: string);
|
|
840
|
+
}
|
|
811
841
|
declare class NewDeviceError extends DecaneConnectError {
|
|
812
842
|
constructor();
|
|
813
843
|
}
|
|
@@ -1238,4 +1268,4 @@ declare function useSignTypedData(): {
|
|
|
1238
1268
|
reset: () => void;
|
|
1239
1269
|
};
|
|
1240
1270
|
|
|
1241
|
-
export { type ActiveSession, AttestationError, type AuthProfile, type AuthResult, BUILT_IN_CHAINS, type BalanceResult, 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, DecaneLogo, DecaneMark, type DecaneProvider, DecaneWordmark, type Eip1193Provider, type EthereumProviderOptions, ExportNotAuthorizedError, InvalidApiKeyError, InvalidPinError, InvalidRecoveryFileError, type KingsChatTokens, NetworkError, NewDeviceError, OriginNotAllowedError, type PortableBackup, PromptPinNotConfiguredError, ReconnectRequiredError, type RecordTransactionInput, RecoveryFailedError, type RecoveryProgress, type RecoveryShareFile, RecoveryWalletMismatchError, type SdkEvent, type SendTransactionRequest, SessionExpiredError, ShareCorruptedError, type SignMessageRequest, type SignTypedDataRequest, type SignedAuthorization, type SocialAuthState, type SocialConfig, SocialWalletModal, StaleDeviceShareError, type Theme, type TransactionRecord, type TxParams, type UnifiedWalletAccount, UnlockRequiredError, UserCancelledError, WalletSelector, WebAuthnNotSupportedError, type WrappedShareMeta, WrongPasswordError, createDecane, createDecaneConnect, createEthereumProvider, loginWithKingsChatPopup, startEmailAuth, useChainSwitch, useDecane, useEthereumProvider, useSendTransaction, useSignMessage, useSignTypedData, useSocialAuth, useSocialBalance, useSocialWallet, useWalletSelector, verifyEmailCode };
|
|
1271
|
+
export { type ActiveSession, AttestationError, type AuthProfile, type AuthResult, BUILT_IN_CHAINS, type BalanceResult, 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, DecaneLogo, DecaneMark, type DecaneProvider, DecaneWordmark, type Eip1193Provider, type EthereumProviderOptions, ExportNotAuthorizedError, InvalidApiKeyError, InvalidPinError, InvalidRecoveryFileError, type KingsChatTokens, NetworkError, NewDeviceError, OriginNotAllowedError, type PortableBackup, PromptPinNotConfiguredError, ProvisioningTimeoutError, ReconnectRequiredError, type RecordTransactionInput, RecoveryFailedError, type RecoveryProgress, type RecoveryShareFile, RecoveryWalletMismatchError, type SdkEvent, type SendTransactionRequest, SessionExpiredError, ShareCorruptedError, type SignMessageRequest, type SignTypedDataRequest, type SignedAuthorization, type SocialAuthState, type SocialConfig, SocialWalletModal, StaleDeviceShareError, type Theme, type TransactionRecord, type TxParams, type UnifiedWalletAccount, UnlockRequiredError, UserCancelledError, WalletSelector, WebAuthnNotSupportedError, type WrappedShareMeta, WrongPasswordError, createDecane, createDecaneConnect, createEthereumProvider, loginWithKingsChatPopup, startEmailAuth, useChainSwitch, useDecane, useEthereumProvider, useSendTransaction, useSignMessage, useSignTypedData, useSocialAuth, useSocialBalance, useSocialWallet, useWalletSelector, verifyEmailCode };
|
package/dist/index.d.ts
CHANGED
|
@@ -256,6 +256,13 @@ declare class ApiClient {
|
|
|
256
256
|
savedAt: string | null;
|
|
257
257
|
nagged: boolean;
|
|
258
258
|
shareSetVersion: number;
|
|
259
|
+
/**
|
|
260
|
+
* Whether this wallet is enrolled for server-assisted provisioning, i.e.
|
|
261
|
+
* whether a new device can be given a device share from login alone.
|
|
262
|
+
* Optional because backends older than this field simply omit it — treat
|
|
263
|
+
* `undefined` as "unknown", never as "not enrolled".
|
|
264
|
+
*/
|
|
265
|
+
enrolled?: boolean;
|
|
259
266
|
}>;
|
|
260
267
|
dismissRecoveryNag(jwt: string): Promise<void>;
|
|
261
268
|
}
|
|
@@ -521,7 +528,16 @@ interface SignTypedDataRequest {
|
|
|
521
528
|
message: Record<string, unknown>;
|
|
522
529
|
primaryType?: string;
|
|
523
530
|
}
|
|
524
|
-
type SdkEvent = 'connected' | 'disconnected' | 'session-expired' | 'session-started' | 'wallet-creating' | 'wallet-unlocking'
|
|
531
|
+
type SdkEvent = 'connected' | 'disconnected' | 'session-expired' | 'session-started' | 'wallet-creating' | 'wallet-unlocking'
|
|
532
|
+
/**
|
|
533
|
+
* Emitted when this wallet could not be enrolled for server-assisted
|
|
534
|
+
* recovery. Not fatal — the wallet works — but until it is enrolled the user
|
|
535
|
+
* cannot get a device share from login alone, so a future new device will
|
|
536
|
+
* need a passkey backup or a recovery file. The SDK retries automatically on
|
|
537
|
+
* later unlocks; surface or report this if you want visibility rather than a
|
|
538
|
+
* console line.
|
|
539
|
+
*/
|
|
540
|
+
| 'enrolment-failed';
|
|
525
541
|
interface DecaneConnect {
|
|
526
542
|
connect(): Promise<ConnectResult>;
|
|
527
543
|
connectWithGoogle(): Promise<ConnectResult>;
|
|
@@ -808,6 +824,20 @@ declare class NetworkError extends DecaneConnectError {
|
|
|
808
824
|
declare class ShareCorruptedError extends DecaneConnectError {
|
|
809
825
|
constructor();
|
|
810
826
|
}
|
|
827
|
+
/**
|
|
828
|
+
* Wallet creation exceeded its time budget.
|
|
829
|
+
*
|
|
830
|
+
* Provisioning is bounded so a stalled network or an unresponsive enclave
|
|
831
|
+
* surfaces as an error the app can act on, rather than a signup that appears to
|
|
832
|
+
* hang forever. The budget covers only the SDK's own work — key generation,
|
|
833
|
+
* share storage, opening the signer session — never time spent waiting on the
|
|
834
|
+
* user (a passkey prompt, choosing a PIN, the recovery-file dialog).
|
|
835
|
+
*
|
|
836
|
+
* Retryable: nothing is left half-created that a later sign-in cannot complete.
|
|
837
|
+
*/
|
|
838
|
+
declare class ProvisioningTimeoutError extends DecaneConnectError {
|
|
839
|
+
constructor(step: string);
|
|
840
|
+
}
|
|
811
841
|
declare class NewDeviceError extends DecaneConnectError {
|
|
812
842
|
constructor();
|
|
813
843
|
}
|
|
@@ -1238,4 +1268,4 @@ declare function useSignTypedData(): {
|
|
|
1238
1268
|
reset: () => void;
|
|
1239
1269
|
};
|
|
1240
1270
|
|
|
1241
|
-
export { type ActiveSession, AttestationError, type AuthProfile, type AuthResult, BUILT_IN_CHAINS, type BalanceResult, 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, DecaneLogo, DecaneMark, type DecaneProvider, DecaneWordmark, type Eip1193Provider, type EthereumProviderOptions, ExportNotAuthorizedError, InvalidApiKeyError, InvalidPinError, InvalidRecoveryFileError, type KingsChatTokens, NetworkError, NewDeviceError, OriginNotAllowedError, type PortableBackup, PromptPinNotConfiguredError, ReconnectRequiredError, type RecordTransactionInput, RecoveryFailedError, type RecoveryProgress, type RecoveryShareFile, RecoveryWalletMismatchError, type SdkEvent, type SendTransactionRequest, SessionExpiredError, ShareCorruptedError, type SignMessageRequest, type SignTypedDataRequest, type SignedAuthorization, type SocialAuthState, type SocialConfig, SocialWalletModal, StaleDeviceShareError, type Theme, type TransactionRecord, type TxParams, type UnifiedWalletAccount, UnlockRequiredError, UserCancelledError, WalletSelector, WebAuthnNotSupportedError, type WrappedShareMeta, WrongPasswordError, createDecane, createDecaneConnect, createEthereumProvider, loginWithKingsChatPopup, startEmailAuth, useChainSwitch, useDecane, useEthereumProvider, useSendTransaction, useSignMessage, useSignTypedData, useSocialAuth, useSocialBalance, useSocialWallet, useWalletSelector, verifyEmailCode };
|
|
1271
|
+
export { type ActiveSession, AttestationError, type AuthProfile, type AuthResult, BUILT_IN_CHAINS, type BalanceResult, 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, DecaneLogo, DecaneMark, type DecaneProvider, DecaneWordmark, type Eip1193Provider, type EthereumProviderOptions, ExportNotAuthorizedError, InvalidApiKeyError, InvalidPinError, InvalidRecoveryFileError, type KingsChatTokens, NetworkError, NewDeviceError, OriginNotAllowedError, type PortableBackup, PromptPinNotConfiguredError, ProvisioningTimeoutError, ReconnectRequiredError, type RecordTransactionInput, RecoveryFailedError, type RecoveryProgress, type RecoveryShareFile, RecoveryWalletMismatchError, type SdkEvent, type SendTransactionRequest, SessionExpiredError, ShareCorruptedError, type SignMessageRequest, type SignTypedDataRequest, type SignedAuthorization, type SocialAuthState, type SocialConfig, SocialWalletModal, StaleDeviceShareError, type Theme, type TransactionRecord, type TxParams, type UnifiedWalletAccount, UnlockRequiredError, UserCancelledError, WalletSelector, WebAuthnNotSupportedError, type WrappedShareMeta, WrongPasswordError, createDecane, createDecaneConnect, createEthereumProvider, loginWithKingsChatPopup, startEmailAuth, useChainSwitch, useDecane, useEthereumProvider, useSendTransaction, useSignMessage, useSignTypedData, useSocialAuth, useSocialBalance, useSocialWallet, useWalletSelector, verifyEmailCode };
|
package/dist/index.js
CHANGED
|
@@ -22,6 +22,7 @@ __export(errors_exports, {
|
|
|
22
22
|
NewDeviceError: () => NewDeviceError,
|
|
23
23
|
OriginNotAllowedError: () => OriginNotAllowedError,
|
|
24
24
|
PromptPinNotConfiguredError: () => PromptPinNotConfiguredError,
|
|
25
|
+
ProvisioningTimeoutError: () => ProvisioningTimeoutError,
|
|
25
26
|
ReconnectRequiredError: () => ReconnectRequiredError,
|
|
26
27
|
RecoveryFailedError: () => RecoveryFailedError,
|
|
27
28
|
RecoveryWalletMismatchError: () => RecoveryWalletMismatchError,
|
|
@@ -33,7 +34,7 @@ __export(errors_exports, {
|
|
|
33
34
|
WebAuthnNotSupportedError: () => WebAuthnNotSupportedError,
|
|
34
35
|
WrongPasswordError: () => WrongPasswordError
|
|
35
36
|
});
|
|
36
|
-
var DecaneConnectError, InvalidApiKeyError, OriginNotAllowedError, SessionExpiredError, UnlockRequiredError, ReconnectRequiredError, UserCancelledError, WebAuthnNotSupportedError, InvalidPinError, CallSequenceError, NetworkError, ShareCorruptedError, NewDeviceError, StaleDeviceShareError, PromptPinNotConfiguredError, AttestationError, RecoveryFailedError, InvalidRecoveryFileError, WrongPasswordError, RecoveryWalletMismatchError, ExportNotAuthorizedError;
|
|
37
|
+
var DecaneConnectError, InvalidApiKeyError, OriginNotAllowedError, SessionExpiredError, UnlockRequiredError, ReconnectRequiredError, UserCancelledError, WebAuthnNotSupportedError, InvalidPinError, CallSequenceError, NetworkError, ShareCorruptedError, ProvisioningTimeoutError, NewDeviceError, StaleDeviceShareError, PromptPinNotConfiguredError, AttestationError, RecoveryFailedError, InvalidRecoveryFileError, WrongPasswordError, RecoveryWalletMismatchError, ExportNotAuthorizedError;
|
|
37
38
|
var init_errors = __esm({
|
|
38
39
|
"src/social/errors.ts"() {
|
|
39
40
|
"use strict";
|
|
@@ -104,6 +105,11 @@ var init_errors = __esm({
|
|
|
104
105
|
super("SHARE_CORRUPTED", "Stored device share is corrupted");
|
|
105
106
|
}
|
|
106
107
|
};
|
|
108
|
+
ProvisioningTimeoutError = class extends DecaneConnectError {
|
|
109
|
+
constructor(step) {
|
|
110
|
+
super("PROVISIONING_TIMEOUT", `Wallet setup timed out while ${step}. Check your connection and try again.`, true);
|
|
111
|
+
}
|
|
112
|
+
};
|
|
107
113
|
NewDeviceError = class extends DecaneConnectError {
|
|
108
114
|
constructor() {
|
|
109
115
|
super("NEW_DEVICE", "No device share found. Re-authenticate to set up this device.");
|
|
@@ -1932,6 +1938,7 @@ var ERROR_MAP = {
|
|
|
1932
1938
|
// generic failure message.
|
|
1933
1939
|
UNAUTHORIZED: ReconnectRequiredError
|
|
1934
1940
|
};
|
|
1941
|
+
var REQUEST_TIMEOUT_MS = 3e4;
|
|
1935
1942
|
var ApiClient = class {
|
|
1936
1943
|
constructor(baseUrl, apiKey, appId) {
|
|
1937
1944
|
this.baseUrl = baseUrl;
|
|
@@ -1940,9 +1947,12 @@ var ApiClient = class {
|
|
|
1940
1947
|
}
|
|
1941
1948
|
async _request(path, init) {
|
|
1942
1949
|
let res;
|
|
1950
|
+
const controller = new AbortController();
|
|
1951
|
+
const timer = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS);
|
|
1943
1952
|
try {
|
|
1944
1953
|
res = await fetch(`${this.baseUrl}${path}`, {
|
|
1945
1954
|
...init,
|
|
1955
|
+
signal: controller.signal,
|
|
1946
1956
|
headers: {
|
|
1947
1957
|
"Content-Type": "application/json",
|
|
1948
1958
|
"X-API-Key": this.apiKey,
|
|
@@ -1952,6 +1962,8 @@ var ApiClient = class {
|
|
|
1952
1962
|
});
|
|
1953
1963
|
} catch {
|
|
1954
1964
|
throw new NetworkError();
|
|
1965
|
+
} finally {
|
|
1966
|
+
clearTimeout(timer);
|
|
1955
1967
|
}
|
|
1956
1968
|
if (res.status === 404 && init?.allow404) return null;
|
|
1957
1969
|
if (!res.ok) {
|
|
@@ -2254,6 +2266,16 @@ function bytesToBase64(b) {
|
|
|
2254
2266
|
function base64ToBytes(s) {
|
|
2255
2267
|
return Uint8Array.from(atob(s), (c) => c.charCodeAt(0));
|
|
2256
2268
|
}
|
|
2269
|
+
var TEE_TIMEOUT_MS = 3e4;
|
|
2270
|
+
async function teeFetch(url, init) {
|
|
2271
|
+
const controller = new AbortController();
|
|
2272
|
+
const timer = setTimeout(() => controller.abort(), TEE_TIMEOUT_MS);
|
|
2273
|
+
try {
|
|
2274
|
+
return await fetch(url, { ...init, signal: controller.signal });
|
|
2275
|
+
} finally {
|
|
2276
|
+
clearTimeout(timer);
|
|
2277
|
+
}
|
|
2278
|
+
}
|
|
2257
2279
|
var TeeClient = class {
|
|
2258
2280
|
constructor(teeUrl) {
|
|
2259
2281
|
this.teeUrl = teeUrl;
|
|
@@ -2309,7 +2331,7 @@ var TeeClient = class {
|
|
|
2309
2331
|
*/
|
|
2310
2332
|
async openSession(deviceShare, jwt, requireAssertionPerSignature = false) {
|
|
2311
2333
|
await this.ensureAttested();
|
|
2312
|
-
const res = await
|
|
2334
|
+
const res = await teeFetch(`${this.teeUrl}/signer/session`, {
|
|
2313
2335
|
method: "POST",
|
|
2314
2336
|
headers: { Authorization: `Bearer ${jwt}`, "Content-Type": "application/json" },
|
|
2315
2337
|
body: JSON.stringify({
|
|
@@ -2341,7 +2363,7 @@ var TeeClient = class {
|
|
|
2341
2363
|
*/
|
|
2342
2364
|
async recoverWithShare(jwt, recoveryShare) {
|
|
2343
2365
|
await this.ensureAttested();
|
|
2344
|
-
const res = await
|
|
2366
|
+
const res = await teeFetch(`${this.teeUrl}/signer/recover`, {
|
|
2345
2367
|
method: "POST",
|
|
2346
2368
|
headers: { Authorization: `Bearer ${jwt}`, "Content-Type": "application/json" },
|
|
2347
2369
|
body: JSON.stringify({ recoveryShare: bytesToBase64(recoveryShare) })
|
|
@@ -2366,7 +2388,7 @@ var TeeClient = class {
|
|
|
2366
2388
|
* require proof of fresh authenticator possession, not just an active session.
|
|
2367
2389
|
*/
|
|
2368
2390
|
async completeAssertion(jwt) {
|
|
2369
|
-
const res = await
|
|
2391
|
+
const res = await teeFetch(`${this.teeUrl}/signer/assertion-challenge`, {
|
|
2370
2392
|
method: "POST",
|
|
2371
2393
|
headers: { Authorization: `Bearer ${jwt}`, "Content-Type": "application/json" },
|
|
2372
2394
|
body: JSON.stringify({ rpId: window.location.hostname })
|
|
@@ -2395,7 +2417,7 @@ var TeeClient = class {
|
|
|
2395
2417
|
*/
|
|
2396
2418
|
async enrolAuthShare(jwt, recoveryShare) {
|
|
2397
2419
|
await this.ensureAttested();
|
|
2398
|
-
const res = await
|
|
2420
|
+
const res = await teeFetch(`${this.teeUrl}/signer/auth-share`, {
|
|
2399
2421
|
method: "POST",
|
|
2400
2422
|
headers: { Authorization: `Bearer ${jwt}`, "Content-Type": "application/json" },
|
|
2401
2423
|
body: JSON.stringify({ share: bytesToBase64(recoveryShare) })
|
|
@@ -2418,7 +2440,7 @@ var TeeClient = class {
|
|
|
2418
2440
|
*/
|
|
2419
2441
|
async provisionDeviceShare(jwt) {
|
|
2420
2442
|
await this.ensureAttested();
|
|
2421
|
-
const res = await
|
|
2443
|
+
const res = await teeFetch(`${this.teeUrl}/signer/provision`, {
|
|
2422
2444
|
method: "POST",
|
|
2423
2445
|
headers: { Authorization: `Bearer ${jwt}`, "Content-Type": "application/json" }
|
|
2424
2446
|
});
|
|
@@ -2436,7 +2458,7 @@ var TeeClient = class {
|
|
|
2436
2458
|
async rotateShares(jwt) {
|
|
2437
2459
|
if (!this.handle) throw new Error("no session");
|
|
2438
2460
|
const { challengeId, assertion } = await this.completeAssertion(jwt);
|
|
2439
|
-
const res = await
|
|
2461
|
+
const res = await teeFetch(`${this.teeUrl}/signer/rotate`, {
|
|
2440
2462
|
method: "POST",
|
|
2441
2463
|
headers: { Authorization: `Bearer ${jwt}`, "Content-Type": "application/json" },
|
|
2442
2464
|
body: JSON.stringify({ handle: this.handle, challengeId, assertion, origin: window.location.origin })
|
|
@@ -2453,7 +2475,7 @@ var TeeClient = class {
|
|
|
2453
2475
|
async exportPortableBackup(jwt) {
|
|
2454
2476
|
if (!this.handle) throw new Error("no session");
|
|
2455
2477
|
const { challengeId, assertion } = await this.completeAssertion(jwt);
|
|
2456
|
-
const res = await
|
|
2478
|
+
const res = await teeFetch(`${this.teeUrl}/signer/export-portable`, {
|
|
2457
2479
|
method: "POST",
|
|
2458
2480
|
headers: { Authorization: `Bearer ${jwt}`, "Content-Type": "application/json" },
|
|
2459
2481
|
body: JSON.stringify({ handle: this.handle, challengeId, assertion, origin: window.location.origin })
|
|
@@ -2483,7 +2505,7 @@ var TeeClient = class {
|
|
|
2483
2505
|
if (!jwt) throw new Error("sign requires a jwt when per-signature assertion is enabled");
|
|
2484
2506
|
gate = await this.completeAssertion(jwt);
|
|
2485
2507
|
}
|
|
2486
|
-
const res = await
|
|
2508
|
+
const res = await teeFetch(`${this.teeUrl}/signer/sign`, {
|
|
2487
2509
|
method: "POST",
|
|
2488
2510
|
headers: { "Content-Type": "application/json" },
|
|
2489
2511
|
body: JSON.stringify({
|
|
@@ -3424,6 +3446,44 @@ async function createDecaneConnect(config) {
|
|
|
3424
3446
|
let ethProvider = null;
|
|
3425
3447
|
const persistSession = config.persistSession !== false;
|
|
3426
3448
|
const serverAssistedRecovery = true;
|
|
3449
|
+
const RECOVERY_OFFER_TIMEOUT_MS = 5 * 6e4;
|
|
3450
|
+
const selfHealAttempted = /* @__PURE__ */ new Set();
|
|
3451
|
+
async function selfHealEnrolment(userId, jwt, share) {
|
|
3452
|
+
try {
|
|
3453
|
+
if (selfHealAttempted.has(userId)) return;
|
|
3454
|
+
const status = await api.getRecoveryStatus(jwt);
|
|
3455
|
+
if (status.enrolled !== false) return;
|
|
3456
|
+
selfHealAttempted.add(userId);
|
|
3457
|
+
await new TeeClient(teeUrl).enrolAuthShare(jwt, share);
|
|
3458
|
+
} catch (e) {
|
|
3459
|
+
events.emit("enrolment-failed");
|
|
3460
|
+
console.warn(
|
|
3461
|
+
"decane-connect-kit: this wallet is not enrolled for server-assisted recovery and the automatic repair failed. It still works on this device, but a new device will need a passkey backup or a recovery file. The SDK will try again on the next unlock.",
|
|
3462
|
+
e
|
|
3463
|
+
);
|
|
3464
|
+
} finally {
|
|
3465
|
+
zeroize(share);
|
|
3466
|
+
}
|
|
3467
|
+
}
|
|
3468
|
+
const PROVISIONING_BUDGET_MS = 9e4;
|
|
3469
|
+
function withDeadline(promise, ms, step) {
|
|
3470
|
+
let timer;
|
|
3471
|
+
return Promise.race([
|
|
3472
|
+
promise,
|
|
3473
|
+
new Promise((_, reject) => {
|
|
3474
|
+
timer = setTimeout(() => reject(new ProvisioningTimeoutError(step)), Math.max(0, ms));
|
|
3475
|
+
})
|
|
3476
|
+
]).finally(() => clearTimeout(timer));
|
|
3477
|
+
}
|
|
3478
|
+
function withTimeout(promise, ms) {
|
|
3479
|
+
let timer;
|
|
3480
|
+
return Promise.race([
|
|
3481
|
+
promise,
|
|
3482
|
+
new Promise((resolve) => {
|
|
3483
|
+
timer = setTimeout(() => resolve(null), ms);
|
|
3484
|
+
})
|
|
3485
|
+
]).finally(() => clearTimeout(timer));
|
|
3486
|
+
}
|
|
3427
3487
|
const SESSION_KEY = sessionPersistKey(config.apiKey);
|
|
3428
3488
|
function persistLiveSession() {
|
|
3429
3489
|
if (!persistSession) return;
|
|
@@ -3564,6 +3624,8 @@ async function createDecaneConnect(config) {
|
|
|
3564
3624
|
({ wrappingKey, meta } = await pinSetup());
|
|
3565
3625
|
unlockMethod = "pin";
|
|
3566
3626
|
}
|
|
3627
|
+
const provisioningStartedAt = Date.now();
|
|
3628
|
+
const remainingBudget = () => PROVISIONING_BUDGET_MS - (Date.now() - provisioningStartedAt);
|
|
3567
3629
|
const master = generateMaster();
|
|
3568
3630
|
let shareSet;
|
|
3569
3631
|
let evmAddress;
|
|
@@ -3595,7 +3657,7 @@ async function createDecaneConnect(config) {
|
|
|
3595
3657
|
version: 1
|
|
3596
3658
|
});
|
|
3597
3659
|
const serverIv = generateRandomBytes(12);
|
|
3598
|
-
await api.putShare(jwt, {
|
|
3660
|
+
await withDeadline(api.putShare(jwt, {
|
|
3599
3661
|
ciphertext: shareSet.server,
|
|
3600
3662
|
iv: serverIv,
|
|
3601
3663
|
wrappedShareMeta: {
|
|
@@ -3605,7 +3667,7 @@ async function createDecaneConnect(config) {
|
|
|
3605
3667
|
evmAddress,
|
|
3606
3668
|
solanaAddress,
|
|
3607
3669
|
tronAddress
|
|
3608
|
-
});
|
|
3670
|
+
}), remainingBudget(), "storing your wallet");
|
|
3609
3671
|
zeroize(shareSet.server);
|
|
3610
3672
|
const addresses = { evm: evmAddress, solana: solanaAddress, tron: tronAddress };
|
|
3611
3673
|
if (unlockMethod === "passkey" && meta.credentialId && meta.prfSalt) {
|
|
@@ -3621,7 +3683,11 @@ async function createDecaneConnect(config) {
|
|
|
3621
3683
|
console.warn("decane-connect-kit: wrapped share backup failed; user can retry from settings.", e);
|
|
3622
3684
|
}
|
|
3623
3685
|
}
|
|
3624
|
-
const confirmed = await
|
|
3686
|
+
const confirmed = await withDeadline(
|
|
3687
|
+
session.start(shareSet.device, jwt, addresses),
|
|
3688
|
+
remainingBudget(),
|
|
3689
|
+
"opening the signing session"
|
|
3690
|
+
);
|
|
3625
3691
|
zeroize(shareSet.device);
|
|
3626
3692
|
if (confirmed.evm.toLowerCase() !== addresses.evm.toLowerCase()) {
|
|
3627
3693
|
console.warn(
|
|
@@ -3649,8 +3715,15 @@ async function createDecaneConnect(config) {
|
|
|
3649
3715
|
}
|
|
3650
3716
|
if (config.offerRecoveryAtSignup !== false && config.onRecoveryShareOffer) {
|
|
3651
3717
|
try {
|
|
3652
|
-
const choice = await
|
|
3653
|
-
|
|
3718
|
+
const choice = await withTimeout(
|
|
3719
|
+
config.onRecoveryShareOffer({ evmAddress, solanaAddress }),
|
|
3720
|
+
RECOVERY_OFFER_TIMEOUT_MS
|
|
3721
|
+
);
|
|
3722
|
+
if (!choice) {
|
|
3723
|
+
console.warn(
|
|
3724
|
+
`decane-connect-kit: onRecoveryShareOffer did not settle within ${RECOVERY_OFFER_TIMEOUT_MS / 6e4} minutes, so wallet creation continued without offering a recovery file. The wallet is fully created and enrolled; the user can generate a recovery share later via rotateShares(). Check that your handler always resolves or rejects.`
|
|
3725
|
+
);
|
|
3726
|
+
} else if (choice.wants) {
|
|
3654
3727
|
const file = await buildRecoveryShareFile(
|
|
3655
3728
|
shareSet.recovery,
|
|
3656
3729
|
choice.password,
|
|
@@ -3753,6 +3826,7 @@ async function createDecaneConnect(config) {
|
|
|
3753
3826
|
}
|
|
3754
3827
|
throw e;
|
|
3755
3828
|
}
|
|
3829
|
+
void selfHealEnrolment(userId, jwt, new Uint8Array(deviceShare));
|
|
3756
3830
|
zeroize(deviceShare);
|
|
3757
3831
|
if (recordedAddresses && recordedAddresses.evm.toLowerCase() !== addresses.evm.toLowerCase()) {
|
|
3758
3832
|
console.warn(
|
|
@@ -7204,6 +7278,7 @@ export {
|
|
|
7204
7278
|
NewDeviceError,
|
|
7205
7279
|
OriginNotAllowedError,
|
|
7206
7280
|
PromptPinNotConfiguredError,
|
|
7281
|
+
ProvisioningTimeoutError,
|
|
7207
7282
|
ReconnectRequiredError,
|
|
7208
7283
|
RecoveryFailedError,
|
|
7209
7284
|
RecoveryWalletMismatchError,
|