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.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.apiKey);
3671
- const LAST_USER_KEY = makeLastUserKey(config.apiKey);
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
- let lastUserId = loadLastUser(LAST_USER_KEY);
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.apiKey);
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 (!handle || !auth || !expiresAt) return;
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?.handle && saved.expiresAt > Date.now() + 5e3) {
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
- const msg = typeof req.message === "string" ? req.message : new TextDecoder().decode(req.message);
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,