decane-connect-kit 2.29.1 → 2.30.0

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
@@ -431,6 +431,31 @@ interface DecaneConnect {
431
431
  connectWithToken(token: string, opts?: {
432
432
  providerId?: string;
433
433
  }): Promise<ConnectResult>;
434
+ /**
435
+ * Attach a login from your own auth system to the account that is signed in
436
+ * now, so that login opens this same wallet from then on. The usual case:
437
+ * someone signed up by email adds a phone number your backend verified, and
438
+ * can then sign in with either. Needs a signed-in session.
439
+ *
440
+ * The token must be fresh (it carries `exp` and `iat`, and was issued in the
441
+ * last ten minutes). A login that already opens a different account throws
442
+ * LoginInUseError: accounts are never merged. Linking one that is already
443
+ * on this account is a no-op (`alreadyLinked: true`). Since 2.30.0.
444
+ */
445
+ linkWithToken(token: string, opts?: {
446
+ providerId?: string;
447
+ }): Promise<{
448
+ alreadyLinked: boolean;
449
+ id?: string;
450
+ }>;
451
+ /** The logins linked to the signed-in account with linkWithToken(). Since 2.30.0. */
452
+ listLinkedLogins(): Promise<LinkedLogin[]>;
453
+ /**
454
+ * Remove a linked login, for "change my number": sign in, unlink the old one,
455
+ * link the new one. The login the account was created with cannot be removed.
456
+ * Since 2.30.0.
457
+ */
458
+ unlinkLogin(id: string): Promise<void>;
434
459
  /**
435
460
  * Adopt a Decane access token another app of the same project handed over
436
461
  * (in a URL, say): signed in at once, unlocked on the first signature.
@@ -700,6 +725,16 @@ interface AuthResult {
700
725
  */
701
726
  providerSubject?: string;
702
727
  }
728
+ /** A login attached to an account with linkWithToken(). */
729
+ interface LinkedLogin {
730
+ id: string;
731
+ providerId: string | null;
732
+ /** The provider's name as set in the dashboard, e.g. "World Street phone". */
733
+ providerName: string | null;
734
+ /** Masked, for display: never the full identifier. */
735
+ identifier: string | null;
736
+ linkedAt: string;
737
+ }
703
738
 
704
739
  declare class ApiClient {
705
740
  private readonly baseUrl;
@@ -782,6 +817,16 @@ declare class ApiClient {
782
817
  * provider configured.
783
818
  */
784
819
  authExternal(token: string, providerId?: string): Promise<AuthResult>;
820
+ /** Attach a login from the project's own provider to the signed-in account. */
821
+ linkExternal(jwt: string, token: string, providerId?: string): Promise<{
822
+ linked: true;
823
+ alreadyLinked: boolean;
824
+ id?: string;
825
+ }>;
826
+ listLinkedLogins(jwt: string): Promise<{
827
+ logins: LinkedLogin[];
828
+ }>;
829
+ unlinkLogin(jwt: string, id: string): Promise<void>;
785
830
  /**
786
831
  * Returns null when this user has no server-registered passkey, which is the
787
832
  * expected answer for wallets created before passkey sign-in existed or for
@@ -1004,6 +1049,13 @@ interface SocialConfig {
1004
1049
  * read from one tab to the whole origin.
1005
1050
  */
1006
1051
  resumeSessionAcrossTabs?: boolean;
1052
+ /**
1053
+ * How long a wallet session lasts, in minutes. Default 480 (8 hours). The
1054
+ * session is still capped by the access token's expiry and the signer's own
1055
+ * limit, whichever comes first. It is also how long a saved session survives
1056
+ * a reload, so a shorter value signs people out on refresh sooner.
1057
+ */
1058
+ sessionDurationMinutes?: number;
1007
1059
  /**
1008
1060
  * Offer to save a recovery-share file at signup. **Default false** since
1009
1061
  * 2.7.4 — opt in explicitly with `true`.
@@ -1285,6 +1337,14 @@ declare class ExportNotAuthorizedError extends DecaneConnectError {
1285
1337
  * The client discards what it generated and provisions instead; nothing for
1286
1338
  * the caller to do, which is why this never reaches them.
1287
1339
  */
1340
+ /**
1341
+ * linkWithToken(): that login already opens a different account (someone signed
1342
+ * up with that phone number on its own, say). Decane never merges two accounts,
1343
+ * because each is its own key and its own addresses, so it was not linked.
1344
+ */
1345
+ declare class LoginInUseError extends DecaneConnectError {
1346
+ constructor(message?: string);
1347
+ }
1288
1348
  declare class WalletExistsError extends DecaneConnectError {
1289
1349
  constructor();
1290
1350
  }
@@ -1590,6 +1650,14 @@ declare function useSocialAuth(): {
1590
1650
  providerId?: string;
1591
1651
  }) => Promise<void>;
1592
1652
  signInWithAccessToken: (token: string) => Promise<void>;
1653
+ linkWithToken: (token: string, opts?: {
1654
+ providerId?: string;
1655
+ }) => Promise<{
1656
+ alreadyLinked: boolean;
1657
+ id?: string;
1658
+ }>;
1659
+ listLinkedLogins: () => Promise<LinkedLogin[]>;
1660
+ unlinkLogin: (id: string) => Promise<void>;
1593
1661
  signInWithCustomAuth: (() => Promise<void>) | undefined;
1594
1662
  signInWithPasskey: () => Promise<void>;
1595
1663
  unlock: () => Promise<void>;
@@ -1765,4 +1833,4 @@ declare class WeakPasswordError extends Error {
1765
1833
  */
1766
1834
  declare function validateUnlockPassword(password: string): void;
1767
1835
 
1768
- 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, EnclaveHttpError, type EthereumProviderOptions, ExportNotAuthorizedError, InvalidAccessTokenError, InvalidApiKeyError, InvalidPinError, InvalidRecoveryFileError, type KingsChatTokens, MIN_PASSWORD_LENGTH, NetworkError, NewDeviceError, OriginNotAllowedError, type PortableBackup, PromptPasswordNotConfiguredError, PromptPinNotConfiguredError, ProvisioningRateLimitedError, 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, WalletEnrolmentError, WalletExistsError, WalletSelector, WeakPasswordError, WebAuthnNotSupportedError, type WrappedShareMeta, WrongPasswordError, WrongUnlockPasswordError, createDecane, createDecaneConnect, createEthereumProvider, loginWithKingsChatPopup, startEmailAuth, useChainSwitch, useDecane, useEthereumProvider, useSendTransaction, useSignMessage, useSignTypedData, useSocialAuth, useSocialBalance, useSocialWallet, useWalletSelector, validateUnlockPassword, verifyEmailCode };
1836
+ 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, EnclaveHttpError, type EthereumProviderOptions, ExportNotAuthorizedError, InvalidAccessTokenError, InvalidApiKeyError, InvalidPinError, InvalidRecoveryFileError, type KingsChatTokens, type LinkedLogin, LoginInUseError, MIN_PASSWORD_LENGTH, NetworkError, NewDeviceError, OriginNotAllowedError, type PortableBackup, PromptPasswordNotConfiguredError, PromptPinNotConfiguredError, ProvisioningRateLimitedError, 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, WalletEnrolmentError, WalletExistsError, 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
@@ -431,6 +431,31 @@ interface DecaneConnect {
431
431
  connectWithToken(token: string, opts?: {
432
432
  providerId?: string;
433
433
  }): Promise<ConnectResult>;
434
+ /**
435
+ * Attach a login from your own auth system to the account that is signed in
436
+ * now, so that login opens this same wallet from then on. The usual case:
437
+ * someone signed up by email adds a phone number your backend verified, and
438
+ * can then sign in with either. Needs a signed-in session.
439
+ *
440
+ * The token must be fresh (it carries `exp` and `iat`, and was issued in the
441
+ * last ten minutes). A login that already opens a different account throws
442
+ * LoginInUseError: accounts are never merged. Linking one that is already
443
+ * on this account is a no-op (`alreadyLinked: true`). Since 2.30.0.
444
+ */
445
+ linkWithToken(token: string, opts?: {
446
+ providerId?: string;
447
+ }): Promise<{
448
+ alreadyLinked: boolean;
449
+ id?: string;
450
+ }>;
451
+ /** The logins linked to the signed-in account with linkWithToken(). Since 2.30.0. */
452
+ listLinkedLogins(): Promise<LinkedLogin[]>;
453
+ /**
454
+ * Remove a linked login, for "change my number": sign in, unlink the old one,
455
+ * link the new one. The login the account was created with cannot be removed.
456
+ * Since 2.30.0.
457
+ */
458
+ unlinkLogin(id: string): Promise<void>;
434
459
  /**
435
460
  * Adopt a Decane access token another app of the same project handed over
436
461
  * (in a URL, say): signed in at once, unlocked on the first signature.
@@ -700,6 +725,16 @@ interface AuthResult {
700
725
  */
701
726
  providerSubject?: string;
702
727
  }
728
+ /** A login attached to an account with linkWithToken(). */
729
+ interface LinkedLogin {
730
+ id: string;
731
+ providerId: string | null;
732
+ /** The provider's name as set in the dashboard, e.g. "World Street phone". */
733
+ providerName: string | null;
734
+ /** Masked, for display: never the full identifier. */
735
+ identifier: string | null;
736
+ linkedAt: string;
737
+ }
703
738
 
704
739
  declare class ApiClient {
705
740
  private readonly baseUrl;
@@ -782,6 +817,16 @@ declare class ApiClient {
782
817
  * provider configured.
783
818
  */
784
819
  authExternal(token: string, providerId?: string): Promise<AuthResult>;
820
+ /** Attach a login from the project's own provider to the signed-in account. */
821
+ linkExternal(jwt: string, token: string, providerId?: string): Promise<{
822
+ linked: true;
823
+ alreadyLinked: boolean;
824
+ id?: string;
825
+ }>;
826
+ listLinkedLogins(jwt: string): Promise<{
827
+ logins: LinkedLogin[];
828
+ }>;
829
+ unlinkLogin(jwt: string, id: string): Promise<void>;
785
830
  /**
786
831
  * Returns null when this user has no server-registered passkey, which is the
787
832
  * expected answer for wallets created before passkey sign-in existed or for
@@ -1004,6 +1049,13 @@ interface SocialConfig {
1004
1049
  * read from one tab to the whole origin.
1005
1050
  */
1006
1051
  resumeSessionAcrossTabs?: boolean;
1052
+ /**
1053
+ * How long a wallet session lasts, in minutes. Default 480 (8 hours). The
1054
+ * session is still capped by the access token's expiry and the signer's own
1055
+ * limit, whichever comes first. It is also how long a saved session survives
1056
+ * a reload, so a shorter value signs people out on refresh sooner.
1057
+ */
1058
+ sessionDurationMinutes?: number;
1007
1059
  /**
1008
1060
  * Offer to save a recovery-share file at signup. **Default false** since
1009
1061
  * 2.7.4 — opt in explicitly with `true`.
@@ -1285,6 +1337,14 @@ declare class ExportNotAuthorizedError extends DecaneConnectError {
1285
1337
  * The client discards what it generated and provisions instead; nothing for
1286
1338
  * the caller to do, which is why this never reaches them.
1287
1339
  */
1340
+ /**
1341
+ * linkWithToken(): that login already opens a different account (someone signed
1342
+ * up with that phone number on its own, say). Decane never merges two accounts,
1343
+ * because each is its own key and its own addresses, so it was not linked.
1344
+ */
1345
+ declare class LoginInUseError extends DecaneConnectError {
1346
+ constructor(message?: string);
1347
+ }
1288
1348
  declare class WalletExistsError extends DecaneConnectError {
1289
1349
  constructor();
1290
1350
  }
@@ -1590,6 +1650,14 @@ declare function useSocialAuth(): {
1590
1650
  providerId?: string;
1591
1651
  }) => Promise<void>;
1592
1652
  signInWithAccessToken: (token: string) => Promise<void>;
1653
+ linkWithToken: (token: string, opts?: {
1654
+ providerId?: string;
1655
+ }) => Promise<{
1656
+ alreadyLinked: boolean;
1657
+ id?: string;
1658
+ }>;
1659
+ listLinkedLogins: () => Promise<LinkedLogin[]>;
1660
+ unlinkLogin: (id: string) => Promise<void>;
1593
1661
  signInWithCustomAuth: (() => Promise<void>) | undefined;
1594
1662
  signInWithPasskey: () => Promise<void>;
1595
1663
  unlock: () => Promise<void>;
@@ -1765,4 +1833,4 @@ declare class WeakPasswordError extends Error {
1765
1833
  */
1766
1834
  declare function validateUnlockPassword(password: string): void;
1767
1835
 
1768
- 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, EnclaveHttpError, type EthereumProviderOptions, ExportNotAuthorizedError, InvalidAccessTokenError, InvalidApiKeyError, InvalidPinError, InvalidRecoveryFileError, type KingsChatTokens, MIN_PASSWORD_LENGTH, NetworkError, NewDeviceError, OriginNotAllowedError, type PortableBackup, PromptPasswordNotConfiguredError, PromptPinNotConfiguredError, ProvisioningRateLimitedError, 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, WalletEnrolmentError, WalletExistsError, WalletSelector, WeakPasswordError, WebAuthnNotSupportedError, type WrappedShareMeta, WrongPasswordError, WrongUnlockPasswordError, createDecane, createDecaneConnect, createEthereumProvider, loginWithKingsChatPopup, startEmailAuth, useChainSwitch, useDecane, useEthereumProvider, useSendTransaction, useSignMessage, useSignTypedData, useSocialAuth, useSocialBalance, useSocialWallet, useWalletSelector, validateUnlockPassword, verifyEmailCode };
1836
+ 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, EnclaveHttpError, type EthereumProviderOptions, ExportNotAuthorizedError, InvalidAccessTokenError, InvalidApiKeyError, InvalidPinError, InvalidRecoveryFileError, type KingsChatTokens, type LinkedLogin, LoginInUseError, MIN_PASSWORD_LENGTH, NetworkError, NewDeviceError, OriginNotAllowedError, type PortableBackup, PromptPasswordNotConfiguredError, PromptPinNotConfiguredError, ProvisioningRateLimitedError, 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, WalletEnrolmentError, WalletExistsError, 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
@@ -20,6 +20,7 @@ __export(errors_exports, {
20
20
  InvalidApiKeyError: () => InvalidApiKeyError,
21
21
  InvalidPinError: () => InvalidPinError,
22
22
  InvalidRecoveryFileError: () => InvalidRecoveryFileError,
23
+ LoginInUseError: () => LoginInUseError,
23
24
  NetworkError: () => NetworkError,
24
25
  NewDeviceError: () => NewDeviceError,
25
26
  OriginNotAllowedError: () => OriginNotAllowedError,
@@ -42,7 +43,7 @@ __export(errors_exports, {
42
43
  WrongPasswordError: () => WrongPasswordError,
43
44
  WrongUnlockPasswordError: () => WrongUnlockPasswordError
44
45
  });
45
- 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, WalletExistsError, WalletEnrolmentError, ProvisioningRateLimitedError, EnclaveHttpError;
46
+ 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, LoginInUseError, WalletExistsError, WalletEnrolmentError, ProvisioningRateLimitedError, EnclaveHttpError;
46
47
  var init_errors = __esm({
47
48
  "src/social/errors.ts"() {
48
49
  "use strict";
@@ -191,6 +192,11 @@ var init_errors = __esm({
191
192
  super("EXPORT_NOT_AUTHORIZED", "Export requires a fresh security check", true);
192
193
  }
193
194
  };
195
+ LoginInUseError = class extends DecaneConnectError {
196
+ constructor(message = "That login already opens another account. It was not linked.") {
197
+ super("LOGIN_IN_USE", message);
198
+ }
199
+ };
194
200
  WalletExistsError = class extends DecaneConnectError {
195
201
  constructor() {
196
202
  super("WALLET_EXISTS", "This account already has a wallet; opening it instead.", true);
@@ -2031,7 +2037,9 @@ var ERROR_MAP = {
2031
2037
  // generic failure message.
2032
2038
  UNAUTHORIZED: ReconnectRequiredError,
2033
2039
  // A restorable wallet already exists: the client provisions instead of creating.
2034
- WALLET_EXISTS: WalletExistsError
2040
+ WALLET_EXISTS: WalletExistsError,
2041
+ // linkWithToken(): the login already opens another account.
2042
+ LOGIN_IN_USE: LoginInUseError
2035
2043
  };
2036
2044
  var REQUEST_TIMEOUT_MS = 3e4;
2037
2045
  var ApiClient = class {
@@ -2200,6 +2208,23 @@ var ApiClient = class {
2200
2208
  body: JSON.stringify(providerId ? { token, providerId } : { token })
2201
2209
  });
2202
2210
  }
2211
+ /** Attach a login from the project's own provider to the signed-in account. */
2212
+ async linkExternal(jwt, token, providerId) {
2213
+ return this._request("/auth/link/external", {
2214
+ method: "POST",
2215
+ headers: { Authorization: `Bearer ${jwt}` },
2216
+ body: JSON.stringify(providerId ? { token, providerId } : { token })
2217
+ });
2218
+ }
2219
+ async listLinkedLogins(jwt) {
2220
+ return this._request("/auth/link/external", { method: "GET", headers: { Authorization: `Bearer ${jwt}` } });
2221
+ }
2222
+ async unlinkLogin(jwt, id) {
2223
+ await this._request(`/auth/link/external/${encodeURIComponent(id)}`, {
2224
+ method: "DELETE",
2225
+ headers: { Authorization: `Bearer ${jwt}` }
2226
+ });
2227
+ }
2203
2228
  /**
2204
2229
  * Returns null when this user has no server-registered passkey, which is the
2205
2230
  * expected answer for wallets created before passkey sign-in existed or for
@@ -3828,7 +3853,7 @@ async function buildPortableBackup(deviceShare, recoveryShare, password, address
3828
3853
  // src/social/client.ts
3829
3854
  var DEFAULT_API_BASE = "https://backend.decane.app";
3830
3855
  var DEFAULT_TEE_URL = "https://4405742df08d19abc549a05ade2a7154d98bd87f-8443.dstack-pha-prod9.phala.network";
3831
- var DEFAULT_SESSION_MINUTES = 120;
3856
+ var DEFAULT_SESSION_MINUTES = 480;
3832
3857
  function makePersistKey(apiKey) {
3833
3858
  return `decane:social:${apiKey.slice(0, 20)}`;
3834
3859
  }
@@ -4872,6 +4897,20 @@ async function createDecaneConnect(config) {
4872
4897
  const result = await api.authExternal(token, opts?.providerId);
4873
4898
  return handleAuthResult(result);
4874
4899
  },
4900
+ async linkWithToken(token, opts) {
4901
+ if (!token) throw new CallSequenceError("linkWithToken requires a token");
4902
+ if (!auth) throw new ReconnectRequiredError();
4903
+ const result = await api.linkExternal(auth.jwt, token, opts?.providerId);
4904
+ return result.id ? { alreadyLinked: result.alreadyLinked, id: result.id } : { alreadyLinked: result.alreadyLinked };
4905
+ },
4906
+ async listLinkedLogins() {
4907
+ if (!auth) throw new ReconnectRequiredError();
4908
+ return (await api.listLinkedLogins(auth.jwt)).logins;
4909
+ },
4910
+ async unlinkLogin(id) {
4911
+ if (!auth) throw new ReconnectRequiredError();
4912
+ await api.unlinkLogin(auth.jwt, id);
4913
+ },
4875
4914
  async connectWithAccessToken(token) {
4876
4915
  const claims = decodeAccessToken(token);
4877
4916
  if (!claims) throw new InvalidAccessTokenError("not a Decane access token");
@@ -6812,6 +6851,7 @@ function DecaneKit({ config, children }) {
6812
6851
  protection,
6813
6852
  deferDeviceProtection,
6814
6853
  resumeSessionAcrossTabs,
6854
+ sessionDurationMinutes,
6815
6855
  // Recovery callbacks. Forwarding these is what makes recovery
6816
6856
  // configurable at all from <DecaneKit>; before, they were silently
6817
6857
  // dropped and the headless client was constructed without them.
@@ -6835,6 +6875,7 @@ function DecaneKit({ config, children }) {
6835
6875
  protection,
6836
6876
  deferDeviceProtection,
6837
6877
  resumeSessionAcrossTabs,
6878
+ sessionDurationMinutes,
6838
6879
  offerRecoveryAtSignup,
6839
6880
  onRecoveryShareOffer,
6840
6881
  onRecoveryFileReady,
@@ -6958,6 +6999,21 @@ function DecaneKit({ config, children }) {
6958
6999
  throw e;
6959
7000
  }
6960
7001
  }, [clearPhase]);
7002
+ const linkWithToken = useCallback3(async (token, opts) => {
7003
+ const sdk = socialRef.current;
7004
+ if (!sdk) throw new Error("Social sign-in not configured");
7005
+ return sdk.linkWithToken(token, opts);
7006
+ }, []);
7007
+ const listLinkedLogins = useCallback3(async () => {
7008
+ const sdk = socialRef.current;
7009
+ if (!sdk) throw new Error("Social sign-in not configured");
7010
+ return sdk.listLinkedLogins();
7011
+ }, []);
7012
+ const unlinkLogin = useCallback3(async (id) => {
7013
+ const sdk = socialRef.current;
7014
+ if (!sdk) throw new Error("Social sign-in not configured");
7015
+ await sdk.unlinkLogin(id);
7016
+ }, []);
6961
7017
  const connectWithToken = useCallback3(async (token, opts) => {
6962
7018
  const sdk = socialRef.current;
6963
7019
  if (!sdk) throw new Error("Social sign-in not configured");
@@ -7175,6 +7231,9 @@ function DecaneKit({ config, children }) {
7175
7231
  verifyPhoneCode: verifyPhoneCode2,
7176
7232
  connectWithToken,
7177
7233
  connectWithAccessToken,
7234
+ linkWithToken,
7235
+ listLinkedLogins,
7236
+ unlinkLogin,
7178
7237
  customAuthLabel: customAuthConfig?.label,
7179
7238
  connectWithCustomAuth: customAuthConfig ? connectWithCustomAuth : void 0,
7180
7239
  socialUnlock,
@@ -7291,6 +7350,9 @@ function useSocialAuth() {
7291
7350
  verifyPhoneCode: verifyPhoneCode2,
7292
7351
  connectWithToken,
7293
7352
  connectWithAccessToken,
7353
+ linkWithToken,
7354
+ listLinkedLogins,
7355
+ unlinkLogin,
7294
7356
  customAuthLabel,
7295
7357
  connectWithCustomAuth,
7296
7358
  signInWithPasskey: ctxSignInWithPasskey,
@@ -7494,6 +7556,11 @@ function useSocialAuth() {
7494
7556
  confirmPhoneCode,
7495
7557
  signInWithToken,
7496
7558
  signInWithAccessToken,
7559
+ // Linked logins: while signed in, attach a login from your own auth (a
7560
+ // phone number your backend verified, say) so it opens this same wallet.
7561
+ linkWithToken,
7562
+ listLinkedLogins,
7563
+ unlinkLogin,
7497
7564
  signInWithCustomAuth: connectWithCustomAuth ? signInWithCustomAuth : void 0,
7498
7565
  signInWithPasskey,
7499
7566
  unlock,
@@ -8047,6 +8114,7 @@ export {
8047
8114
  InvalidApiKeyError,
8048
8115
  InvalidPinError,
8049
8116
  InvalidRecoveryFileError,
8117
+ LoginInUseError,
8050
8118
  MIN_PASSWORD_LENGTH,
8051
8119
  NetworkError,
8052
8120
  NewDeviceError,