decane-connect-kit 2.23.0 → 2.24.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 +145 -14
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +18 -1
- package/dist/index.d.ts +18 -1
- package/dist/index.js +144 -14
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -358,6 +358,19 @@ interface DecaneConnect {
|
|
|
358
358
|
connectWithToken(token: string, opts?: {
|
|
359
359
|
providerId?: string;
|
|
360
360
|
}): Promise<ConnectResult>;
|
|
361
|
+
/**
|
|
362
|
+
* Adopt a Decane access token another app of the same project handed over
|
|
363
|
+
* (in a URL, say): signed in at once, unlocked on the first signature.
|
|
364
|
+
*
|
|
365
|
+
* The token is the one every API call carries as a Bearer. The backend
|
|
366
|
+
* judges it — a revoked or foreign token is refused — and the session lasts
|
|
367
|
+
* as long as the token does, at most two hours; when it lapses the client
|
|
368
|
+
* emits `session-expired` and reads as signed out. No enclave session is
|
|
369
|
+
* opened: the first `unlock()` (or any signing call) provisions or unwraps
|
|
370
|
+
* the device share as an ordinary returning sign-in would, and with
|
|
371
|
+
* `deferDeviceProtection` prompts for nothing.
|
|
372
|
+
*/
|
|
373
|
+
connectWithAccessToken(token: string): Promise<ConnectResult>;
|
|
361
374
|
verifyEmailCode(email: string, code: string): Promise<ConnectResult>;
|
|
362
375
|
/**
|
|
363
376
|
* Send a 6-digit sign-in code by SMS (delivered via Termii).
|
|
@@ -1130,6 +1143,9 @@ declare class PromptPasswordNotConfiguredError extends DecaneConnectError {
|
|
|
1130
1143
|
declare class WrongUnlockPasswordError extends DecaneConnectError {
|
|
1131
1144
|
constructor();
|
|
1132
1145
|
}
|
|
1146
|
+
declare class InvalidAccessTokenError extends DecaneConnectError {
|
|
1147
|
+
constructor(reason: string);
|
|
1148
|
+
}
|
|
1133
1149
|
declare class UnlockTokenRejectedError extends DecaneConnectError {
|
|
1134
1150
|
constructor();
|
|
1135
1151
|
}
|
|
@@ -1423,6 +1439,7 @@ declare function useSocialAuth(): {
|
|
|
1423
1439
|
signInWithToken: (token: string, opts?: {
|
|
1424
1440
|
providerId?: string;
|
|
1425
1441
|
}) => Promise<void>;
|
|
1442
|
+
signInWithAccessToken: (token: string) => Promise<void>;
|
|
1426
1443
|
signInWithCustomAuth: (() => Promise<void>) | undefined;
|
|
1427
1444
|
signInWithPasskey: () => Promise<void>;
|
|
1428
1445
|
unlock: () => Promise<void>;
|
|
@@ -1598,4 +1615,4 @@ declare class WeakPasswordError extends Error {
|
|
|
1598
1615
|
*/
|
|
1599
1616
|
declare function validateUnlockPassword(password: string): void;
|
|
1600
1617
|
|
|
1601
|
-
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, MIN_PASSWORD_LENGTH, NetworkError, NewDeviceError, OriginNotAllowedError, type PortableBackup, PromptPasswordNotConfiguredError, 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, UnlockTokenRejectedError, UserCancelledError, WalletSelector, WeakPasswordError, WebAuthnNotSupportedError, type WrappedShareMeta, WrongPasswordError, WrongUnlockPasswordError, createDecane, createDecaneConnect, createEthereumProvider, loginWithKingsChatPopup, startEmailAuth, useChainSwitch, useDecane, useEthereumProvider, useSendTransaction, useSignMessage, useSignTypedData, useSocialAuth, useSocialBalance, useSocialWallet, useWalletSelector, validateUnlockPassword, verifyEmailCode };
|
|
1618
|
+
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, InvalidAccessTokenError, InvalidApiKeyError, InvalidPinError, InvalidRecoveryFileError, type KingsChatTokens, MIN_PASSWORD_LENGTH, NetworkError, NewDeviceError, OriginNotAllowedError, type PortableBackup, PromptPasswordNotConfiguredError, 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, UnlockTokenRejectedError, UserCancelledError, WalletSelector, WeakPasswordError, WebAuthnNotSupportedError, type WrappedShareMeta, WrongPasswordError, WrongUnlockPasswordError, createDecane, createDecaneConnect, createEthereumProvider, loginWithKingsChatPopup, startEmailAuth, useChainSwitch, useDecane, useEthereumProvider, useSendTransaction, useSignMessage, useSignTypedData, useSocialAuth, useSocialBalance, useSocialWallet, useWalletSelector, validateUnlockPassword, verifyEmailCode };
|
package/dist/index.d.ts
CHANGED
|
@@ -358,6 +358,19 @@ interface DecaneConnect {
|
|
|
358
358
|
connectWithToken(token: string, opts?: {
|
|
359
359
|
providerId?: string;
|
|
360
360
|
}): Promise<ConnectResult>;
|
|
361
|
+
/**
|
|
362
|
+
* Adopt a Decane access token another app of the same project handed over
|
|
363
|
+
* (in a URL, say): signed in at once, unlocked on the first signature.
|
|
364
|
+
*
|
|
365
|
+
* The token is the one every API call carries as a Bearer. The backend
|
|
366
|
+
* judges it — a revoked or foreign token is refused — and the session lasts
|
|
367
|
+
* as long as the token does, at most two hours; when it lapses the client
|
|
368
|
+
* emits `session-expired` and reads as signed out. No enclave session is
|
|
369
|
+
* opened: the first `unlock()` (or any signing call) provisions or unwraps
|
|
370
|
+
* the device share as an ordinary returning sign-in would, and with
|
|
371
|
+
* `deferDeviceProtection` prompts for nothing.
|
|
372
|
+
*/
|
|
373
|
+
connectWithAccessToken(token: string): Promise<ConnectResult>;
|
|
361
374
|
verifyEmailCode(email: string, code: string): Promise<ConnectResult>;
|
|
362
375
|
/**
|
|
363
376
|
* Send a 6-digit sign-in code by SMS (delivered via Termii).
|
|
@@ -1130,6 +1143,9 @@ declare class PromptPasswordNotConfiguredError extends DecaneConnectError {
|
|
|
1130
1143
|
declare class WrongUnlockPasswordError extends DecaneConnectError {
|
|
1131
1144
|
constructor();
|
|
1132
1145
|
}
|
|
1146
|
+
declare class InvalidAccessTokenError extends DecaneConnectError {
|
|
1147
|
+
constructor(reason: string);
|
|
1148
|
+
}
|
|
1133
1149
|
declare class UnlockTokenRejectedError extends DecaneConnectError {
|
|
1134
1150
|
constructor();
|
|
1135
1151
|
}
|
|
@@ -1423,6 +1439,7 @@ declare function useSocialAuth(): {
|
|
|
1423
1439
|
signInWithToken: (token: string, opts?: {
|
|
1424
1440
|
providerId?: string;
|
|
1425
1441
|
}) => Promise<void>;
|
|
1442
|
+
signInWithAccessToken: (token: string) => Promise<void>;
|
|
1426
1443
|
signInWithCustomAuth: (() => Promise<void>) | undefined;
|
|
1427
1444
|
signInWithPasskey: () => Promise<void>;
|
|
1428
1445
|
unlock: () => Promise<void>;
|
|
@@ -1598,4 +1615,4 @@ declare class WeakPasswordError extends Error {
|
|
|
1598
1615
|
*/
|
|
1599
1616
|
declare function validateUnlockPassword(password: string): void;
|
|
1600
1617
|
|
|
1601
|
-
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, MIN_PASSWORD_LENGTH, NetworkError, NewDeviceError, OriginNotAllowedError, type PortableBackup, PromptPasswordNotConfiguredError, 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, UnlockTokenRejectedError, UserCancelledError, WalletSelector, WeakPasswordError, WebAuthnNotSupportedError, type WrappedShareMeta, WrongPasswordError, WrongUnlockPasswordError, createDecane, createDecaneConnect, createEthereumProvider, loginWithKingsChatPopup, startEmailAuth, useChainSwitch, useDecane, useEthereumProvider, useSendTransaction, useSignMessage, useSignTypedData, useSocialAuth, useSocialBalance, useSocialWallet, useWalletSelector, validateUnlockPassword, verifyEmailCode };
|
|
1618
|
+
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, InvalidAccessTokenError, InvalidApiKeyError, InvalidPinError, InvalidRecoveryFileError, type KingsChatTokens, MIN_PASSWORD_LENGTH, NetworkError, NewDeviceError, OriginNotAllowedError, type PortableBackup, PromptPasswordNotConfiguredError, 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, UnlockTokenRejectedError, UserCancelledError, WalletSelector, WeakPasswordError, WebAuthnNotSupportedError, type WrappedShareMeta, WrongPasswordError, WrongUnlockPasswordError, createDecane, createDecaneConnect, createEthereumProvider, loginWithKingsChatPopup, startEmailAuth, useChainSwitch, useDecane, useEthereumProvider, useSendTransaction, useSignMessage, useSignTypedData, useSocialAuth, useSocialBalance, useSocialWallet, useWalletSelector, validateUnlockPassword, verifyEmailCode };
|
package/dist/index.js
CHANGED
|
@@ -15,6 +15,7 @@ __export(errors_exports, {
|
|
|
15
15
|
CallSequenceError: () => CallSequenceError,
|
|
16
16
|
DecaneConnectError: () => DecaneConnectError,
|
|
17
17
|
ExportNotAuthorizedError: () => ExportNotAuthorizedError,
|
|
18
|
+
InvalidAccessTokenError: () => InvalidAccessTokenError,
|
|
18
19
|
InvalidApiKeyError: () => InvalidApiKeyError,
|
|
19
20
|
InvalidPinError: () => InvalidPinError,
|
|
20
21
|
InvalidRecoveryFileError: () => InvalidRecoveryFileError,
|
|
@@ -37,7 +38,7 @@ __export(errors_exports, {
|
|
|
37
38
|
WrongPasswordError: () => WrongPasswordError,
|
|
38
39
|
WrongUnlockPasswordError: () => WrongUnlockPasswordError
|
|
39
40
|
});
|
|
40
|
-
var DecaneConnectError, InvalidApiKeyError, OriginNotAllowedError, SessionExpiredError, UnlockRequiredError, ReconnectRequiredError, UserCancelledError, WebAuthnNotSupportedError, InvalidPinError, CallSequenceError, NetworkError, ShareCorruptedError, ProvisioningTimeoutError, NewDeviceError, StaleDeviceShareError, PromptPinNotConfiguredError, PromptPasswordNotConfiguredError, WrongUnlockPasswordError, UnlockTokenRejectedError, AttestationError, RecoveryFailedError, InvalidRecoveryFileError, WrongPasswordError, RecoveryWalletMismatchError, ExportNotAuthorizedError;
|
|
41
|
+
var DecaneConnectError, InvalidApiKeyError, OriginNotAllowedError, SessionExpiredError, UnlockRequiredError, ReconnectRequiredError, UserCancelledError, WebAuthnNotSupportedError, InvalidPinError, CallSequenceError, NetworkError, ShareCorruptedError, ProvisioningTimeoutError, NewDeviceError, StaleDeviceShareError, PromptPinNotConfiguredError, PromptPasswordNotConfiguredError, WrongUnlockPasswordError, InvalidAccessTokenError, UnlockTokenRejectedError, AttestationError, RecoveryFailedError, InvalidRecoveryFileError, WrongPasswordError, RecoveryWalletMismatchError, ExportNotAuthorizedError;
|
|
41
42
|
var init_errors = __esm({
|
|
42
43
|
"src/social/errors.ts"() {
|
|
43
44
|
"use strict";
|
|
@@ -142,6 +143,11 @@ var init_errors = __esm({
|
|
|
142
143
|
super("WRONG_UNLOCK_PASSWORD", "That password did not unlock this device");
|
|
143
144
|
}
|
|
144
145
|
};
|
|
146
|
+
InvalidAccessTokenError = class extends DecaneConnectError {
|
|
147
|
+
constructor(reason) {
|
|
148
|
+
super("INVALID_ACCESS_TOKEN", `That access token cannot open a session: ${reason}`);
|
|
149
|
+
}
|
|
150
|
+
};
|
|
145
151
|
UnlockTokenRejectedError = class extends DecaneConnectError {
|
|
146
152
|
constructor() {
|
|
147
153
|
super("UNLOCK_TOKEN_REJECTED", "This device's unlock token is no longer valid \u2014 sign in normally to re-enable password unlock");
|
|
@@ -2273,6 +2279,20 @@ function b64ToBytes(b644) {
|
|
|
2273
2279
|
return Uint8Array.from(atob(b644), (c) => c.charCodeAt(0));
|
|
2274
2280
|
}
|
|
2275
2281
|
|
|
2282
|
+
// src/social/accessToken.ts
|
|
2283
|
+
function decodeAccessToken(token) {
|
|
2284
|
+
try {
|
|
2285
|
+
const payload = token.split(".")[1];
|
|
2286
|
+
if (!payload) return null;
|
|
2287
|
+
const json = JSON.parse(atob(payload.replace(/-/g, "+").replace(/_/g, "/")));
|
|
2288
|
+
if (typeof json.uid !== "string" || json.uid === "") return null;
|
|
2289
|
+
if (typeof json.exp !== "number" || !Number.isFinite(json.exp)) return null;
|
|
2290
|
+
return { userId: json.uid, expiresAt: json.exp * 1e3 };
|
|
2291
|
+
} catch {
|
|
2292
|
+
return null;
|
|
2293
|
+
}
|
|
2294
|
+
}
|
|
2295
|
+
|
|
2276
2296
|
// src/social/storage.ts
|
|
2277
2297
|
import { openDB } from "idb";
|
|
2278
2298
|
var DB_NAME = "decane-connect-kit";
|
|
@@ -3128,7 +3148,9 @@ function loginWithKingsChatPopup(opts) {
|
|
|
3128
3148
|
}
|
|
3129
3149
|
|
|
3130
3150
|
// src/social/signers/evm.ts
|
|
3151
|
+
init_errors();
|
|
3131
3152
|
import { keccak256, Transaction, resolveProperties } from "ethers";
|
|
3153
|
+
var DECODE = (bytes) => new TextDecoder().decode(bytes);
|
|
3132
3154
|
async function signEvmTransaction(tee, chain, tx, jwt) {
|
|
3133
3155
|
const resolved = await resolveProperties(tx);
|
|
3134
3156
|
const unsigned = Transaction.from(resolved).unsignedSerialized;
|
|
@@ -3137,7 +3159,44 @@ async function signEvmTransaction(tee, chain, tx, jwt) {
|
|
|
3137
3159
|
return tee.sign({ chain, kind: "transaction", payload, txHash }, jwt);
|
|
3138
3160
|
}
|
|
3139
3161
|
async function signEvmMessage(tee, chain, message, jwt) {
|
|
3140
|
-
return tee.sign({ chain, kind: "message", payload: message }, jwt);
|
|
3162
|
+
return tee.sign({ chain, kind: "message", payload: messageAsString(message) }, jwt);
|
|
3163
|
+
}
|
|
3164
|
+
function messageAsString(message) {
|
|
3165
|
+
if (typeof message === "string") return message;
|
|
3166
|
+
if (!isValidUtf8(message)) {
|
|
3167
|
+
throw new CallSequenceError(
|
|
3168
|
+
"signMessage: the message bytes are not valid UTF-8. The signer hashes text; pass a string, or UTF-8 bytes."
|
|
3169
|
+
);
|
|
3170
|
+
}
|
|
3171
|
+
return DECODE(message);
|
|
3172
|
+
}
|
|
3173
|
+
function isValidUtf8(b) {
|
|
3174
|
+
let i = 0;
|
|
3175
|
+
while (i < b.length) {
|
|
3176
|
+
const c = b[i];
|
|
3177
|
+
let n = 0;
|
|
3178
|
+
if (c < 128) n = 0;
|
|
3179
|
+
else if (c >= 194 && c <= 223) n = 1;
|
|
3180
|
+
else if (c >= 224 && c <= 239) n = 2;
|
|
3181
|
+
else if (c >= 240 && c <= 244) n = 3;
|
|
3182
|
+
else return false;
|
|
3183
|
+
for (let k = 1; k <= n; k++) {
|
|
3184
|
+
const t = b[i + k];
|
|
3185
|
+
if (t === void 0 || (t & 192) !== 128) return false;
|
|
3186
|
+
}
|
|
3187
|
+
if (n === 2) {
|
|
3188
|
+
const c1 = b[i + 1];
|
|
3189
|
+
if (c === 224 && c1 < 160) return false;
|
|
3190
|
+
if (c === 237 && c1 >= 160) return false;
|
|
3191
|
+
}
|
|
3192
|
+
if (n === 3) {
|
|
3193
|
+
const c1 = b[i + 1];
|
|
3194
|
+
if (c === 240 && c1 < 144) return false;
|
|
3195
|
+
if (c === 244 && c1 >= 144) return false;
|
|
3196
|
+
}
|
|
3197
|
+
i += n + 1;
|
|
3198
|
+
}
|
|
3199
|
+
return true;
|
|
3141
3200
|
}
|
|
3142
3201
|
async function signEvmAuthorization(tee, chainId, address, nonce, jwt) {
|
|
3143
3202
|
const serialized = await tee.sign(
|
|
@@ -3667,8 +3726,10 @@ async function createDecaneConnect(config) {
|
|
|
3667
3726
|
const durationMs = (config.sessionDurationMinutes ?? DEFAULT_SESSION_MINUTES) * 6e4;
|
|
3668
3727
|
const rpId = config.rpId ?? (typeof window !== "undefined" ? window.location.hostname : "localhost");
|
|
3669
3728
|
const rpName = config.rpName ?? "Decane Connect";
|
|
3670
|
-
const PERSIST_KEY = makePersistKey(config.
|
|
3671
|
-
const LAST_USER_KEY = makeLastUserKey(config.
|
|
3729
|
+
const PERSIST_KEY = makePersistKey(config.appId);
|
|
3730
|
+
const LAST_USER_KEY = makeLastUserKey(config.appId);
|
|
3731
|
+
const LEGACY_PERSIST_KEY = makePersistKey(config.apiKey);
|
|
3732
|
+
const LEGACY_LAST_USER_KEY = makeLastUserKey(config.apiKey);
|
|
3672
3733
|
const teeUrl = config.teeUrl ?? DEFAULT_TEE_URL;
|
|
3673
3734
|
const events = new EventEmitter();
|
|
3674
3735
|
const api = new ApiClient(baseUrl, config.apiKey, config.appId);
|
|
@@ -3681,7 +3742,14 @@ async function createDecaneConnect(config) {
|
|
|
3681
3742
|
);
|
|
3682
3743
|
let auth = null;
|
|
3683
3744
|
let persisted = loadPersisted(PERSIST_KEY);
|
|
3684
|
-
|
|
3745
|
+
if (!persisted && LEGACY_PERSIST_KEY !== PERSIST_KEY) {
|
|
3746
|
+
persisted = loadPersisted(LEGACY_PERSIST_KEY);
|
|
3747
|
+
if (persisted) {
|
|
3748
|
+
savePersisted(PERSIST_KEY, persisted);
|
|
3749
|
+
clearPersisted(LEGACY_PERSIST_KEY);
|
|
3750
|
+
}
|
|
3751
|
+
}
|
|
3752
|
+
let lastUserId = loadLastUser(LAST_USER_KEY) ?? (LEGACY_LAST_USER_KEY !== LAST_USER_KEY ? loadLastUser(LEGACY_LAST_USER_KEY) : null);
|
|
3685
3753
|
let ethProvider = null;
|
|
3686
3754
|
const persistSession = config.persistSession !== false;
|
|
3687
3755
|
const deferDeviceProtection = config.deferDeviceProtection === true;
|
|
@@ -3744,12 +3812,13 @@ async function createDecaneConnect(config) {
|
|
|
3744
3812
|
})
|
|
3745
3813
|
]).finally(() => clearTimeout(timer));
|
|
3746
3814
|
}
|
|
3747
|
-
const SESSION_KEY = sessionPersistKey(config.
|
|
3815
|
+
const SESSION_KEY = sessionPersistKey(config.appId);
|
|
3816
|
+
const LEGACY_SESSION_KEY = sessionPersistKey(config.apiKey);
|
|
3748
3817
|
function persistLiveSession() {
|
|
3749
|
-
if (!persistSession) return;
|
|
3818
|
+
if (!persistSession || !auth) return;
|
|
3750
3819
|
const handle = session.getHandle();
|
|
3751
|
-
const expiresAt = session.expiresAtTimestamp();
|
|
3752
|
-
if (!
|
|
3820
|
+
const expiresAt = handle ? session.expiresAtTimestamp() : decodeAccessToken(auth.jwt)?.expiresAt ?? null;
|
|
3821
|
+
if (!expiresAt) return;
|
|
3753
3822
|
saveSession(SESSION_KEY, {
|
|
3754
3823
|
handle,
|
|
3755
3824
|
jwt: auth.jwt,
|
|
@@ -3761,11 +3830,23 @@ async function createDecaneConnect(config) {
|
|
|
3761
3830
|
function dropLiveSession() {
|
|
3762
3831
|
clearSessionPersist(SESSION_KEY);
|
|
3763
3832
|
}
|
|
3833
|
+
let accessTokenExpiry = null;
|
|
3834
|
+
function scheduleAccessTokenExpiry(jwt, expiresAt) {
|
|
3835
|
+
if (accessTokenExpiry) clearTimeout(accessTokenExpiry);
|
|
3836
|
+
accessTokenExpiry = setTimeout(() => {
|
|
3837
|
+
accessTokenExpiry = null;
|
|
3838
|
+
if (auth?.jwt !== jwt || session.isActive()) return;
|
|
3839
|
+
auth = null;
|
|
3840
|
+
dropLiveSession();
|
|
3841
|
+
events.emit("session-expired");
|
|
3842
|
+
}, Math.max(0, expiresAt - Date.now()));
|
|
3843
|
+
}
|
|
3764
3844
|
if (persistSession) {
|
|
3765
|
-
const saved = loadSession(SESSION_KEY);
|
|
3766
|
-
if (saved
|
|
3845
|
+
const saved = loadSession(SESSION_KEY) ?? (LEGACY_SESSION_KEY !== SESSION_KEY ? loadSession(LEGACY_SESSION_KEY) : null);
|
|
3846
|
+
if (saved && saved.expiresAt > Date.now() + 5e3) {
|
|
3767
3847
|
try {
|
|
3768
|
-
session.resume(saved.handle, saved.addresses, saved.expiresAt);
|
|
3848
|
+
if (saved.handle) session.resume(saved.handle, saved.addresses, saved.expiresAt);
|
|
3849
|
+
else scheduleAccessTokenExpiry(saved.jwt, saved.expiresAt);
|
|
3769
3850
|
auth = { jwt: saved.jwt, userId: saved.userId, addresses: saved.addresses };
|
|
3770
3851
|
persisted = { userId: saved.userId, addresses: saved.addresses };
|
|
3771
3852
|
} catch {
|
|
@@ -3774,6 +3855,7 @@ async function createDecaneConnect(config) {
|
|
|
3774
3855
|
} else if (saved) {
|
|
3775
3856
|
dropLiveSession();
|
|
3776
3857
|
}
|
|
3858
|
+
if (LEGACY_SESSION_KEY !== SESSION_KEY) clearSessionPersist(LEGACY_SESSION_KEY);
|
|
3777
3859
|
}
|
|
3778
3860
|
events.on("session-expired", () => dropLiveSession());
|
|
3779
3861
|
async function passwordSetup() {
|
|
@@ -4491,6 +4573,27 @@ async function createDecaneConnect(config) {
|
|
|
4491
4573
|
const result = await api.authExternal(token, opts?.providerId);
|
|
4492
4574
|
return handleAuthResult(result);
|
|
4493
4575
|
},
|
|
4576
|
+
async connectWithAccessToken(token) {
|
|
4577
|
+
const claims = decodeAccessToken(token);
|
|
4578
|
+
if (!claims) throw new InvalidAccessTokenError("not a Decane access token");
|
|
4579
|
+
if (claims.expiresAt <= Date.now() + 5e3) throw new InvalidAccessTokenError("it has expired");
|
|
4580
|
+
const raw = await api.getAddresses(token);
|
|
4581
|
+
if (!raw.evm || !raw.solana) throw new InvalidAccessTokenError("this account holds no wallet yet");
|
|
4582
|
+
const addresses = { evm: raw.evm, solana: raw.solana, tron: raw.tron ?? evmToTronAddress2(raw.evm) };
|
|
4583
|
+
if (session.isActive()) session.end();
|
|
4584
|
+
auth = { jwt: token, userId: claims.userId, addresses };
|
|
4585
|
+
persisted = { userId: claims.userId, addresses };
|
|
4586
|
+
savePersisted(PERSIST_KEY, persisted);
|
|
4587
|
+
events.emit("connected");
|
|
4588
|
+
persistLiveSession();
|
|
4589
|
+
scheduleAccessTokenExpiry(token, claims.expiresAt);
|
|
4590
|
+
const stored = await storage.getShare(claims.userId);
|
|
4591
|
+
return {
|
|
4592
|
+
addresses,
|
|
4593
|
+
isNewUser: false,
|
|
4594
|
+
...stored?.profile ? { profile: stored.profile } : {}
|
|
4595
|
+
};
|
|
4596
|
+
},
|
|
4494
4597
|
async connectWithEmail(email) {
|
|
4495
4598
|
await startEmailAuth(api, email);
|
|
4496
4599
|
return { codeRequired: true };
|
|
@@ -4737,8 +4840,7 @@ async function createDecaneConnect(config) {
|
|
|
4737
4840
|
return bufferToB64u(sig);
|
|
4738
4841
|
}
|
|
4739
4842
|
if (req.chain.startsWith("tron:")) {
|
|
4740
|
-
|
|
4741
|
-
return tee.sign({ chain: req.chain, kind: "message", payload: msg }, auth?.jwt);
|
|
4843
|
+
return tee.sign({ chain: req.chain, kind: "message", payload: messageAsString(req.message) }, auth?.jwt);
|
|
4742
4844
|
}
|
|
4743
4845
|
throw new CallSequenceError(`Unsupported chain: ${req.chain}`);
|
|
4744
4846
|
},
|
|
@@ -7483,6 +7585,18 @@ function DecaneKit({ config, children }) {
|
|
|
7483
7585
|
throw e;
|
|
7484
7586
|
}
|
|
7485
7587
|
}, [clearPhase]);
|
|
7588
|
+
const connectWithAccessToken = useCallback3(async (token) => {
|
|
7589
|
+
const sdk = socialRef.current;
|
|
7590
|
+
if (!sdk) throw new Error("Social sign-in not configured");
|
|
7591
|
+
try {
|
|
7592
|
+
const result = await sdk.connectWithAccessToken(token);
|
|
7593
|
+
applyResult(result);
|
|
7594
|
+
setSelectorOpen(false);
|
|
7595
|
+
} catch (e) {
|
|
7596
|
+
clearPhase();
|
|
7597
|
+
throw e;
|
|
7598
|
+
}
|
|
7599
|
+
}, [clearPhase]);
|
|
7486
7600
|
const customAuthConfig = config?.social?.customAuth;
|
|
7487
7601
|
const connectWithCustomAuth = useCallback3(async () => {
|
|
7488
7602
|
if (!customAuthConfig) throw new Error("Custom auth not configured");
|
|
@@ -7675,6 +7789,7 @@ function DecaneKit({ config, children }) {
|
|
|
7675
7789
|
connectWithPhone,
|
|
7676
7790
|
verifyPhoneCode: verifyPhoneCode2,
|
|
7677
7791
|
connectWithToken,
|
|
7792
|
+
connectWithAccessToken,
|
|
7678
7793
|
customAuthLabel: customAuthConfig?.label,
|
|
7679
7794
|
connectWithCustomAuth: customAuthConfig ? connectWithCustomAuth : void 0,
|
|
7680
7795
|
socialUnlock,
|
|
@@ -7790,6 +7905,7 @@ function useSocialAuth() {
|
|
|
7790
7905
|
connectWithPhone,
|
|
7791
7906
|
verifyPhoneCode: verifyPhoneCode2,
|
|
7792
7907
|
connectWithToken,
|
|
7908
|
+
connectWithAccessToken,
|
|
7793
7909
|
customAuthLabel,
|
|
7794
7910
|
connectWithCustomAuth,
|
|
7795
7911
|
signInWithPasskey: ctxSignInWithPasskey,
|
|
@@ -7898,6 +8014,18 @@ function useSocialAuth() {
|
|
|
7898
8014
|
setTokenLoading(false);
|
|
7899
8015
|
}
|
|
7900
8016
|
}, [connectWithToken]);
|
|
8017
|
+
const signInWithAccessToken = useCallback4(async (token) => {
|
|
8018
|
+
setTokenLoading(true);
|
|
8019
|
+
setError(null);
|
|
8020
|
+
try {
|
|
8021
|
+
await connectWithAccessToken(token);
|
|
8022
|
+
} catch (e) {
|
|
8023
|
+
setError(e.message);
|
|
8024
|
+
throw e;
|
|
8025
|
+
} finally {
|
|
8026
|
+
setTokenLoading(false);
|
|
8027
|
+
}
|
|
8028
|
+
}, [connectWithAccessToken]);
|
|
7901
8029
|
const signInWithCustomAuth = useCallback4(async () => {
|
|
7902
8030
|
if (!connectWithCustomAuth) throw new Error("Custom auth not configured");
|
|
7903
8031
|
setCustomLoading(true);
|
|
@@ -7980,6 +8108,7 @@ function useSocialAuth() {
|
|
|
7980
8108
|
sendPhoneCode,
|
|
7981
8109
|
confirmPhoneCode,
|
|
7982
8110
|
signInWithToken,
|
|
8111
|
+
signInWithAccessToken,
|
|
7983
8112
|
signInWithCustomAuth: connectWithCustomAuth ? signInWithCustomAuth : void 0,
|
|
7984
8113
|
signInWithPasskey,
|
|
7985
8114
|
unlock,
|
|
@@ -8528,6 +8657,7 @@ export {
|
|
|
8528
8657
|
DecaneMark,
|
|
8529
8658
|
DecaneWordmark,
|
|
8530
8659
|
ExportNotAuthorizedError,
|
|
8660
|
+
InvalidAccessTokenError,
|
|
8531
8661
|
InvalidApiKeyError,
|
|
8532
8662
|
InvalidPinError,
|
|
8533
8663
|
InvalidRecoveryFileError,
|