decane-connect-kit 2.4.0 → 2.6.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
@@ -76,7 +76,12 @@ interface DecaneProvider {
76
76
  type ConnectMode = "all" | "social" | "wallets" | "evm" | "solana" | "tron" | "evm+social" | "solana+social" | "tron+social" | "evm+tron" | "evm+tron+social";
77
77
  interface SocialConfig {
78
78
  apiKey: string;
79
- authMethods?: ("google" | "email")[];
79
+ authMethods?: ("google" | "email" | "kingschat")[];
80
+ /**
81
+ * Scopes requested from KingsChat. Defaults to `['send_chat_message']`, which
82
+ * is what KingsChat's own SDK asks for and is enough to establish identity.
83
+ */
84
+ kingsChatScopes?: string[];
80
85
  promptPin?: () => Promise<string>;
81
86
  apiBaseUrl?: string;
82
87
  chains?: string[];
@@ -170,6 +175,23 @@ declare class ApiClient {
170
175
  getGoogleInitUrl(): Promise<{
171
176
  url: string;
172
177
  }>;
178
+ /**
179
+ * Exchange a Google ID token the app already holds for a Decane session.
180
+ * Resolves to the SAME identity as the redirect flow, so one Google account
181
+ * means one wallet across web and mobile.
182
+ */
183
+ authGoogleToken(idToken: string): Promise<AuthResult>;
184
+ /** The project's KingsChat clientId, so the dApp never has to hardcode it. */
185
+ getKingsChatConfig(): Promise<{
186
+ clientId: string;
187
+ authorizationUrl: string;
188
+ }>;
189
+ /**
190
+ * Exchange a KingsChat access token for a Decane session. The backend spends
191
+ * the token against KingsChat's own API to establish the identity — it is
192
+ * never trusted on its face, and never stored.
193
+ */
194
+ authKingsChat(accessToken: string): Promise<AuthResult>;
173
195
  authEmailStart(email: string): Promise<void>;
174
196
  authEmailVerify(email: string, code: string): Promise<AuthResult>;
175
197
  getAddresses(jwt: string): Promise<{
@@ -185,6 +207,16 @@ declare class ApiClient {
185
207
  solanaAddress: string;
186
208
  tronAddress: string;
187
209
  }): Promise<void>;
210
+ recordTransaction(jwt: string, tx: {
211
+ chain: string;
212
+ txHash?: string;
213
+ to?: string;
214
+ value?: string;
215
+ kind?: string;
216
+ status?: string;
217
+ metadata?: Record<string, unknown>;
218
+ }): Promise<TransactionRecord>;
219
+ getTransactions(jwt: string, limit?: number): Promise<TransactionRecord[]>;
188
220
  getWebAuthnRegisterOptions(jwt: string, rpId: string, rpName: string): Promise<_simplewebauthn_browser.PublicKeyCredentialCreationOptionsJSON>;
189
221
  postWebAuthnRegister(jwt: string, response: _simplewebauthn_browser.RegistrationResponseJSON, origin: string): Promise<void>;
190
222
  /**
@@ -336,7 +368,15 @@ interface DecaneConnectConfig {
336
368
  appId: string;
337
369
  apiKey: string;
338
370
  chains: Chain[];
339
- authMethods: Array<'google' | 'email'>;
371
+ authMethods: Array<'google' | 'email' | 'kingschat'>;
372
+ /**
373
+ * Scopes requested from KingsChat at sign-in. Defaults to
374
+ * `['send_chat_message']`, which is what KingsChat's own SDK asks for and is
375
+ * enough to establish identity. Widen only if the app actually calls
376
+ * KingsChat APIs on the user's behalf — the consent screen lists every scope,
377
+ * so asking for more than you use costs conversions.
378
+ */
379
+ kingsChatScopes?: string[];
340
380
  apiBaseUrl?: string;
341
381
  sessionDurationMinutes?: number;
342
382
  promptPin?: () => Promise<string>;
@@ -402,6 +442,48 @@ interface DecaneConnectConfig {
402
442
  }>;
403
443
  /** Recovery stage callbacks, for dApp UI. */
404
444
  onRecoveryProgress?: (event: RecoveryProgress) => void;
445
+ /**
446
+ * Let the enclave hand a device a working share on the strength of a valid
447
+ * login alone — no synced passkey, no recovery file, nothing for the user to
448
+ * keep. Default TRUE, because a wallet a person cannot re-enter after
449
+ * clearing their browser is worse than useless to them.
450
+ *
451
+ * The trade, stated plainly: enrolling stores a second Shamir share sealed to
452
+ * the enclave, so the enclave can reconstruct a wallet by itself. It is sealed
453
+ * with a key derived inside the TEE, so your backend and its database still
454
+ * cannot — but a malicious enclave image, or anyone able to mint JWTs, could.
455
+ *
456
+ * Set false to keep the stricter property that no single party can
457
+ * reconstruct. Users then need a synced passkey or their recovery file on
458
+ * every new device, and losing both means losing the wallet.
459
+ */
460
+ serverAssistedRecovery?: boolean;
461
+ /**
462
+ * Rotate the whole share set whenever a NEW device recovers via passkey sync
463
+ * (Flow A) — the "every device holds a distinct share" model.
464
+ *
465
+ * Default false, which preserves the historical behaviour: every device
466
+ * synced to the same passkey caches the byte-identical wrapped share, so a
467
+ * device that is later lost keeps a share that stays valid until someone
468
+ * explicitly calls rotateShares(). There is no way to revoke one device
469
+ * without revoking all of them.
470
+ *
471
+ * With this on, joining a new device re-splits the master and issues that
472
+ * device its own share, which invalidates every other device's cached copy
473
+ * at the same instant. That is what makes per-device revocation possible,
474
+ * and it has three consequences worth accepting deliberately:
475
+ *
476
+ * - **Other devices are logged out, not just the lost one.** Each surviving
477
+ * device hits StaleDeviceShareError on its next unlock, clears its share,
478
+ * and silently re-recovers through Flow A (one passkey prompt). Expected,
479
+ * but it means a shared-family-device setup re-prompts more often.
480
+ * - **The user's recovery FILE dies too.** Rotation issues a new recovery
481
+ * share, so `onRecoveryRotated` MUST be configured to capture it —
482
+ * enabling this without that callback throws at connect time rather than
483
+ * stranding the user with a dead file.
484
+ * - **Adding a device costs a TEE round trip.** Recovery is slower.
485
+ */
486
+ rotateOnNewDeviceRecovery?: boolean;
405
487
  }
406
488
  interface ConnectResult {
407
489
  addresses: {
@@ -411,6 +493,29 @@ interface ConnectResult {
411
493
  };
412
494
  isNewUser: boolean;
413
495
  }
496
+ /** A recorded on-chain transaction in the user's history. */
497
+ interface TransactionRecord {
498
+ id: string;
499
+ chain: string;
500
+ kind: string;
501
+ txHash: string | null;
502
+ to: string | null;
503
+ value: string | null;
504
+ status: 'submitted' | 'confirmed' | 'failed' | string;
505
+ metadata: Record<string, unknown> | null;
506
+ createdAt: string;
507
+ updatedAt?: string;
508
+ }
509
+ /** What the dApp passes to record a transaction it broadcast. */
510
+ interface RecordTransactionInput {
511
+ chain: string;
512
+ txHash?: string;
513
+ to?: string;
514
+ value?: string;
515
+ kind?: string;
516
+ status?: string;
517
+ metadata?: Record<string, unknown>;
518
+ }
414
519
  interface SignMessageRequest {
415
520
  chain: Chain;
416
521
  message: string | Uint8Array;
@@ -434,6 +539,30 @@ type SdkEvent = 'connected' | 'disconnected' | 'session-expired' | 'session-star
434
539
  interface DecaneConnect {
435
540
  connect(): Promise<ConnectResult>;
436
541
  connectWithGoogle(): Promise<ConnectResult>;
542
+ /**
543
+ * Sign in with a Google ID token the app already obtained — native Google
544
+ * Sign-In on mobile, or Google Identity Services on the web.
545
+ *
546
+ * Resolves to the SAME wallet as connectWithGoogle(): both end at the
547
+ * backend's Google identity, so a user who signs in on your website and then
548
+ * on your app lands on one wallet, not two.
549
+ */
550
+ connectWithGoogleToken(idToken: string): Promise<ConnectResult>;
551
+ /**
552
+ * Sign in with KingsChat.
553
+ *
554
+ * Opens KingsChat's consent screen in a popup, so this MUST be called
555
+ * directly from a click handler — a popup opened after an await is blocked by
556
+ * every browser. The resulting access token is exchanged server-side for a
557
+ * Decane session; it is never treated as one on its own.
558
+ */
559
+ connectWithKingsChat(): Promise<ConnectResult>;
560
+ /**
561
+ * Sign in with a KingsChat access token the app already holds — from
562
+ * kingschat-web-sdk, a native SDK, or any other flow. Use when you want to
563
+ * own the consent step yourself; connectWithKingsChat() is the turnkey path.
564
+ */
565
+ connectWithKingsChatToken(accessToken: string): Promise<ConnectResult>;
437
566
  connectWithEmail(email: string): Promise<{
438
567
  codeRequired: true;
439
568
  }>;
@@ -521,6 +650,15 @@ interface DecaneConnect {
521
650
  * the transaction's `signature` array and broadcast via TronWeb / a full node.
522
651
  */
523
652
  signTronTransaction(rawDataHex: string): Promise<string>;
653
+ /**
654
+ * Record a transaction this wallet broadcast, so it appears in the user's
655
+ * history (and the developer dashboard). EVM `sendTransaction` records itself
656
+ * automatically; call this for Solana/Tron transactions your dApp broadcasts,
657
+ * or to attach a `confirmed`/`failed` status update to an existing hash.
658
+ */
659
+ recordTransaction(tx: RecordTransactionInput): Promise<TransactionRecord>;
660
+ /** The user's transaction history, most recent first. Requires a live session. */
661
+ getTransactionHistory(limit?: number): Promise<TransactionRecord[]>;
524
662
  disconnect(): Promise<void>;
525
663
  getAddresses(): {
526
664
  evm?: string;
@@ -598,6 +736,24 @@ declare function startEmailAuth(api: ApiClient, email: string): Promise<void>;
598
736
  */
599
737
  declare function verifyEmailCode(api: ApiClient, email: string, code: string): Promise<AuthResult>;
600
738
 
739
+ interface KingsChatTokens {
740
+ accessToken: string;
741
+ refreshToken?: string;
742
+ expiresInMillis?: number;
743
+ }
744
+ /**
745
+ * Open the KingsChat consent popup and resolve with the tokens it returns.
746
+ *
747
+ * Must be called synchronously from a user gesture (a click handler) — popup
748
+ * blockers reject a window.open that happens after an await, which is why the
749
+ * clientId is fetched by the caller *before* this runs.
750
+ */
751
+ declare function loginWithKingsChatPopup(opts: {
752
+ clientId: string;
753
+ scopes?: string[];
754
+ timeoutMs?: number;
755
+ }): Promise<KingsChatTokens>;
756
+
601
757
  declare class DecaneConnectError extends Error {
602
758
  code: string;
603
759
  retryable: boolean;
@@ -652,6 +808,21 @@ declare class ShareCorruptedError extends DecaneConnectError {
652
808
  declare class NewDeviceError extends DecaneConnectError {
653
809
  constructor();
654
810
  }
811
+ /**
812
+ * The device share this device just used no longer reconstructs the account's
813
+ * real key — almost always because another device recovered via passkey sync
814
+ * since and rotated the whole share set (see rotateOnNewDeviceRecovery in
815
+ * DecaneConnectConfig), silently invalidating every other device's cached
816
+ * copy. Thrown instead of signing: two mismatched shares from different
817
+ * share-set versions still combine to *something*, just not the user's real
818
+ * key, so continuing would risk operating on a wrong (though not
819
+ * attacker-chosen) address. The stale local share is cleared by the caller
820
+ * before this propagates, so the next connect() naturally falls through to
821
+ * recovery instead of repeating the same failure.
822
+ */
823
+ declare class StaleDeviceShareError extends DecaneConnectError {
824
+ constructor();
825
+ }
655
826
  declare class PromptPinNotConfiguredError extends DecaneConnectError {
656
827
  constructor();
657
828
  }
@@ -770,8 +941,9 @@ interface WalletSelectorProps {
770
941
  theme?: "light" | "dark" | "auto";
771
942
  networks?: "evm" | "solana" | "tron" | "bitcoin" | "all";
772
943
  mode?: ConnectMode;
773
- socialAuthMethods?: ("google" | "email")[];
944
+ socialAuthMethods?: ("google" | "email" | "kingschat")[];
774
945
  onGoogleSignIn?: () => Promise<void>;
946
+ onKingsChatSignIn?: () => Promise<void>;
775
947
  onEmailStart?: (email: string) => Promise<{
776
948
  codeRequired: true;
777
949
  }>;
@@ -785,7 +957,7 @@ interface WalletSelectorProps {
785
957
  passkeyAddress?: string | null;
786
958
  onPasskeySignIn?: () => Promise<unknown>;
787
959
  }
788
- declare function WalletSelector({ provider, open, onClose, onConnect, theme, networks, mode, socialAuthMethods, onGoogleSignIn, onEmailStart, onEmailVerify, customAuthLabel, onCustomAuthSignIn, canUsePasskey, passkeyAddress, onPasskeySignIn, }: WalletSelectorProps): React.ReactPortal | null;
960
+ declare function WalletSelector({ provider, open, onClose, onConnect, theme, networks, mode, socialAuthMethods, onGoogleSignIn, onKingsChatSignIn, onEmailStart, onEmailVerify, customAuthLabel, onCustomAuthSignIn, canUsePasskey, passkeyAddress, onPasskeySignIn, }: WalletSelectorProps): React.ReactPortal | null;
789
961
 
790
962
  type Theme = "light" | "dark" | "auto";
791
963
  interface SocialAuthState {
@@ -834,11 +1006,12 @@ interface SocialWalletModalProps {
834
1006
  onUnlock: () => Promise<void>;
835
1007
  onDisconnect: () => Promise<void>;
836
1008
  onGoogleSignIn: () => Promise<void>;
1009
+ onKingsChatSignIn?: () => Promise<void>;
837
1010
  onEmailStart: (email: string) => Promise<{
838
1011
  codeRequired: true;
839
1012
  }>;
840
1013
  onEmailVerify: (email: string, code: string) => Promise<void>;
841
- authMethods?: Array<"google" | "email">;
1014
+ authMethods?: Array<"google" | "email" | "kingschat">;
842
1015
  customAuthLabel?: string;
843
1016
  onCustomAuthSignIn?: () => Promise<void>;
844
1017
  canUsePasskey?: boolean;
@@ -855,7 +1028,7 @@ interface SocialWalletModalProps {
855
1028
  rpcUrls?: Record<string, string>;
856
1029
  chains?: string[];
857
1030
  }
858
- declare function SocialWalletModal({ open, onClose, theme, socialAuth, onUnlock, onDisconnect, onGoogleSignIn, onEmailStart, onEmailVerify, authMethods, customAuthLabel, onCustomAuthSignIn, canUsePasskey, passkeyAddress, onPasskeySignIn, onRotateShares, onExportPortableBackup, rpcUrls, chains, }: SocialWalletModalProps): React.ReactPortal | null;
1031
+ declare function SocialWalletModal({ open, onClose, theme, socialAuth, onUnlock, onDisconnect, onGoogleSignIn, onKingsChatSignIn, onEmailStart, onEmailVerify, authMethods, customAuthLabel, onCustomAuthSignIn, canUsePasskey, passkeyAddress, onPasskeySignIn, onRotateShares, onExportPortableBackup, rpcUrls, chains, }: SocialWalletModalProps): React.ReactPortal | null;
859
1032
 
860
1033
  declare function DecaneMark({ size, muted }: {
861
1034
  size?: number;
@@ -933,6 +1106,8 @@ declare function useSocialWallet(): {
933
1106
  }) => Promise<string>;
934
1107
  signSolanaTransaction: (tx: Uint8Array) => Promise<Uint8Array<ArrayBufferLike>>;
935
1108
  signTronTransaction: (rawDataHex: string) => Promise<string>;
1109
+ recordTransaction: (tx: RecordTransactionInput) => Promise<TransactionRecord>;
1110
+ getTransactionHistory: (limit?: number) => Promise<TransactionRecord[]>;
936
1111
  signTypedData: (req: {
937
1112
  chain: string;
938
1113
  domain: Record<string, unknown>;
@@ -1051,4 +1226,4 @@ declare function useSignTypedData(): {
1051
1226
  reset: () => void;
1052
1227
  };
1053
1228
 
1054
- export { type ActiveSession, AttestationError, 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, NetworkError, NewDeviceError, OriginNotAllowedError, type PortableBackup, PromptPinNotConfiguredError, ReconnectRequiredError, RecoveryFailedError, type RecoveryProgress, type RecoveryShareFile, RecoveryWalletMismatchError, type SdkEvent, type SendTransactionRequest, SessionExpiredError, ShareCorruptedError, type SignMessageRequest, type SignTypedDataRequest, type SignedAuthorization, type SocialAuthState, type SocialConfig, SocialWalletModal, type Theme, type TxParams, type UnifiedWalletAccount, UnlockRequiredError, UserCancelledError, WalletSelector, WebAuthnNotSupportedError, type WrappedShareMeta, WrongPasswordError, createDecane, createDecaneConnect, createEthereumProvider, startEmailAuth, useChainSwitch, useDecane, useEthereumProvider, useSendTransaction, useSignMessage, useSignTypedData, useSocialAuth, useSocialBalance, useSocialWallet, useWalletSelector, verifyEmailCode };
1229
+ export { type ActiveSession, AttestationError, 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 };
package/dist/index.d.ts CHANGED
@@ -76,7 +76,12 @@ interface DecaneProvider {
76
76
  type ConnectMode = "all" | "social" | "wallets" | "evm" | "solana" | "tron" | "evm+social" | "solana+social" | "tron+social" | "evm+tron" | "evm+tron+social";
77
77
  interface SocialConfig {
78
78
  apiKey: string;
79
- authMethods?: ("google" | "email")[];
79
+ authMethods?: ("google" | "email" | "kingschat")[];
80
+ /**
81
+ * Scopes requested from KingsChat. Defaults to `['send_chat_message']`, which
82
+ * is what KingsChat's own SDK asks for and is enough to establish identity.
83
+ */
84
+ kingsChatScopes?: string[];
80
85
  promptPin?: () => Promise<string>;
81
86
  apiBaseUrl?: string;
82
87
  chains?: string[];
@@ -170,6 +175,23 @@ declare class ApiClient {
170
175
  getGoogleInitUrl(): Promise<{
171
176
  url: string;
172
177
  }>;
178
+ /**
179
+ * Exchange a Google ID token the app already holds for a Decane session.
180
+ * Resolves to the SAME identity as the redirect flow, so one Google account
181
+ * means one wallet across web and mobile.
182
+ */
183
+ authGoogleToken(idToken: string): Promise<AuthResult>;
184
+ /** The project's KingsChat clientId, so the dApp never has to hardcode it. */
185
+ getKingsChatConfig(): Promise<{
186
+ clientId: string;
187
+ authorizationUrl: string;
188
+ }>;
189
+ /**
190
+ * Exchange a KingsChat access token for a Decane session. The backend spends
191
+ * the token against KingsChat's own API to establish the identity — it is
192
+ * never trusted on its face, and never stored.
193
+ */
194
+ authKingsChat(accessToken: string): Promise<AuthResult>;
173
195
  authEmailStart(email: string): Promise<void>;
174
196
  authEmailVerify(email: string, code: string): Promise<AuthResult>;
175
197
  getAddresses(jwt: string): Promise<{
@@ -185,6 +207,16 @@ declare class ApiClient {
185
207
  solanaAddress: string;
186
208
  tronAddress: string;
187
209
  }): Promise<void>;
210
+ recordTransaction(jwt: string, tx: {
211
+ chain: string;
212
+ txHash?: string;
213
+ to?: string;
214
+ value?: string;
215
+ kind?: string;
216
+ status?: string;
217
+ metadata?: Record<string, unknown>;
218
+ }): Promise<TransactionRecord>;
219
+ getTransactions(jwt: string, limit?: number): Promise<TransactionRecord[]>;
188
220
  getWebAuthnRegisterOptions(jwt: string, rpId: string, rpName: string): Promise<_simplewebauthn_browser.PublicKeyCredentialCreationOptionsJSON>;
189
221
  postWebAuthnRegister(jwt: string, response: _simplewebauthn_browser.RegistrationResponseJSON, origin: string): Promise<void>;
190
222
  /**
@@ -336,7 +368,15 @@ interface DecaneConnectConfig {
336
368
  appId: string;
337
369
  apiKey: string;
338
370
  chains: Chain[];
339
- authMethods: Array<'google' | 'email'>;
371
+ authMethods: Array<'google' | 'email' | 'kingschat'>;
372
+ /**
373
+ * Scopes requested from KingsChat at sign-in. Defaults to
374
+ * `['send_chat_message']`, which is what KingsChat's own SDK asks for and is
375
+ * enough to establish identity. Widen only if the app actually calls
376
+ * KingsChat APIs on the user's behalf — the consent screen lists every scope,
377
+ * so asking for more than you use costs conversions.
378
+ */
379
+ kingsChatScopes?: string[];
340
380
  apiBaseUrl?: string;
341
381
  sessionDurationMinutes?: number;
342
382
  promptPin?: () => Promise<string>;
@@ -402,6 +442,48 @@ interface DecaneConnectConfig {
402
442
  }>;
403
443
  /** Recovery stage callbacks, for dApp UI. */
404
444
  onRecoveryProgress?: (event: RecoveryProgress) => void;
445
+ /**
446
+ * Let the enclave hand a device a working share on the strength of a valid
447
+ * login alone — no synced passkey, no recovery file, nothing for the user to
448
+ * keep. Default TRUE, because a wallet a person cannot re-enter after
449
+ * clearing their browser is worse than useless to them.
450
+ *
451
+ * The trade, stated plainly: enrolling stores a second Shamir share sealed to
452
+ * the enclave, so the enclave can reconstruct a wallet by itself. It is sealed
453
+ * with a key derived inside the TEE, so your backend and its database still
454
+ * cannot — but a malicious enclave image, or anyone able to mint JWTs, could.
455
+ *
456
+ * Set false to keep the stricter property that no single party can
457
+ * reconstruct. Users then need a synced passkey or their recovery file on
458
+ * every new device, and losing both means losing the wallet.
459
+ */
460
+ serverAssistedRecovery?: boolean;
461
+ /**
462
+ * Rotate the whole share set whenever a NEW device recovers via passkey sync
463
+ * (Flow A) — the "every device holds a distinct share" model.
464
+ *
465
+ * Default false, which preserves the historical behaviour: every device
466
+ * synced to the same passkey caches the byte-identical wrapped share, so a
467
+ * device that is later lost keeps a share that stays valid until someone
468
+ * explicitly calls rotateShares(). There is no way to revoke one device
469
+ * without revoking all of them.
470
+ *
471
+ * With this on, joining a new device re-splits the master and issues that
472
+ * device its own share, which invalidates every other device's cached copy
473
+ * at the same instant. That is what makes per-device revocation possible,
474
+ * and it has three consequences worth accepting deliberately:
475
+ *
476
+ * - **Other devices are logged out, not just the lost one.** Each surviving
477
+ * device hits StaleDeviceShareError on its next unlock, clears its share,
478
+ * and silently re-recovers through Flow A (one passkey prompt). Expected,
479
+ * but it means a shared-family-device setup re-prompts more often.
480
+ * - **The user's recovery FILE dies too.** Rotation issues a new recovery
481
+ * share, so `onRecoveryRotated` MUST be configured to capture it —
482
+ * enabling this without that callback throws at connect time rather than
483
+ * stranding the user with a dead file.
484
+ * - **Adding a device costs a TEE round trip.** Recovery is slower.
485
+ */
486
+ rotateOnNewDeviceRecovery?: boolean;
405
487
  }
406
488
  interface ConnectResult {
407
489
  addresses: {
@@ -411,6 +493,29 @@ interface ConnectResult {
411
493
  };
412
494
  isNewUser: boolean;
413
495
  }
496
+ /** A recorded on-chain transaction in the user's history. */
497
+ interface TransactionRecord {
498
+ id: string;
499
+ chain: string;
500
+ kind: string;
501
+ txHash: string | null;
502
+ to: string | null;
503
+ value: string | null;
504
+ status: 'submitted' | 'confirmed' | 'failed' | string;
505
+ metadata: Record<string, unknown> | null;
506
+ createdAt: string;
507
+ updatedAt?: string;
508
+ }
509
+ /** What the dApp passes to record a transaction it broadcast. */
510
+ interface RecordTransactionInput {
511
+ chain: string;
512
+ txHash?: string;
513
+ to?: string;
514
+ value?: string;
515
+ kind?: string;
516
+ status?: string;
517
+ metadata?: Record<string, unknown>;
518
+ }
414
519
  interface SignMessageRequest {
415
520
  chain: Chain;
416
521
  message: string | Uint8Array;
@@ -434,6 +539,30 @@ type SdkEvent = 'connected' | 'disconnected' | 'session-expired' | 'session-star
434
539
  interface DecaneConnect {
435
540
  connect(): Promise<ConnectResult>;
436
541
  connectWithGoogle(): Promise<ConnectResult>;
542
+ /**
543
+ * Sign in with a Google ID token the app already obtained — native Google
544
+ * Sign-In on mobile, or Google Identity Services on the web.
545
+ *
546
+ * Resolves to the SAME wallet as connectWithGoogle(): both end at the
547
+ * backend's Google identity, so a user who signs in on your website and then
548
+ * on your app lands on one wallet, not two.
549
+ */
550
+ connectWithGoogleToken(idToken: string): Promise<ConnectResult>;
551
+ /**
552
+ * Sign in with KingsChat.
553
+ *
554
+ * Opens KingsChat's consent screen in a popup, so this MUST be called
555
+ * directly from a click handler — a popup opened after an await is blocked by
556
+ * every browser. The resulting access token is exchanged server-side for a
557
+ * Decane session; it is never treated as one on its own.
558
+ */
559
+ connectWithKingsChat(): Promise<ConnectResult>;
560
+ /**
561
+ * Sign in with a KingsChat access token the app already holds — from
562
+ * kingschat-web-sdk, a native SDK, or any other flow. Use when you want to
563
+ * own the consent step yourself; connectWithKingsChat() is the turnkey path.
564
+ */
565
+ connectWithKingsChatToken(accessToken: string): Promise<ConnectResult>;
437
566
  connectWithEmail(email: string): Promise<{
438
567
  codeRequired: true;
439
568
  }>;
@@ -521,6 +650,15 @@ interface DecaneConnect {
521
650
  * the transaction's `signature` array and broadcast via TronWeb / a full node.
522
651
  */
523
652
  signTronTransaction(rawDataHex: string): Promise<string>;
653
+ /**
654
+ * Record a transaction this wallet broadcast, so it appears in the user's
655
+ * history (and the developer dashboard). EVM `sendTransaction` records itself
656
+ * automatically; call this for Solana/Tron transactions your dApp broadcasts,
657
+ * or to attach a `confirmed`/`failed` status update to an existing hash.
658
+ */
659
+ recordTransaction(tx: RecordTransactionInput): Promise<TransactionRecord>;
660
+ /** The user's transaction history, most recent first. Requires a live session. */
661
+ getTransactionHistory(limit?: number): Promise<TransactionRecord[]>;
524
662
  disconnect(): Promise<void>;
525
663
  getAddresses(): {
526
664
  evm?: string;
@@ -598,6 +736,24 @@ declare function startEmailAuth(api: ApiClient, email: string): Promise<void>;
598
736
  */
599
737
  declare function verifyEmailCode(api: ApiClient, email: string, code: string): Promise<AuthResult>;
600
738
 
739
+ interface KingsChatTokens {
740
+ accessToken: string;
741
+ refreshToken?: string;
742
+ expiresInMillis?: number;
743
+ }
744
+ /**
745
+ * Open the KingsChat consent popup and resolve with the tokens it returns.
746
+ *
747
+ * Must be called synchronously from a user gesture (a click handler) — popup
748
+ * blockers reject a window.open that happens after an await, which is why the
749
+ * clientId is fetched by the caller *before* this runs.
750
+ */
751
+ declare function loginWithKingsChatPopup(opts: {
752
+ clientId: string;
753
+ scopes?: string[];
754
+ timeoutMs?: number;
755
+ }): Promise<KingsChatTokens>;
756
+
601
757
  declare class DecaneConnectError extends Error {
602
758
  code: string;
603
759
  retryable: boolean;
@@ -652,6 +808,21 @@ declare class ShareCorruptedError extends DecaneConnectError {
652
808
  declare class NewDeviceError extends DecaneConnectError {
653
809
  constructor();
654
810
  }
811
+ /**
812
+ * The device share this device just used no longer reconstructs the account's
813
+ * real key — almost always because another device recovered via passkey sync
814
+ * since and rotated the whole share set (see rotateOnNewDeviceRecovery in
815
+ * DecaneConnectConfig), silently invalidating every other device's cached
816
+ * copy. Thrown instead of signing: two mismatched shares from different
817
+ * share-set versions still combine to *something*, just not the user's real
818
+ * key, so continuing would risk operating on a wrong (though not
819
+ * attacker-chosen) address. The stale local share is cleared by the caller
820
+ * before this propagates, so the next connect() naturally falls through to
821
+ * recovery instead of repeating the same failure.
822
+ */
823
+ declare class StaleDeviceShareError extends DecaneConnectError {
824
+ constructor();
825
+ }
655
826
  declare class PromptPinNotConfiguredError extends DecaneConnectError {
656
827
  constructor();
657
828
  }
@@ -770,8 +941,9 @@ interface WalletSelectorProps {
770
941
  theme?: "light" | "dark" | "auto";
771
942
  networks?: "evm" | "solana" | "tron" | "bitcoin" | "all";
772
943
  mode?: ConnectMode;
773
- socialAuthMethods?: ("google" | "email")[];
944
+ socialAuthMethods?: ("google" | "email" | "kingschat")[];
774
945
  onGoogleSignIn?: () => Promise<void>;
946
+ onKingsChatSignIn?: () => Promise<void>;
775
947
  onEmailStart?: (email: string) => Promise<{
776
948
  codeRequired: true;
777
949
  }>;
@@ -785,7 +957,7 @@ interface WalletSelectorProps {
785
957
  passkeyAddress?: string | null;
786
958
  onPasskeySignIn?: () => Promise<unknown>;
787
959
  }
788
- declare function WalletSelector({ provider, open, onClose, onConnect, theme, networks, mode, socialAuthMethods, onGoogleSignIn, onEmailStart, onEmailVerify, customAuthLabel, onCustomAuthSignIn, canUsePasskey, passkeyAddress, onPasskeySignIn, }: WalletSelectorProps): React.ReactPortal | null;
960
+ declare function WalletSelector({ provider, open, onClose, onConnect, theme, networks, mode, socialAuthMethods, onGoogleSignIn, onKingsChatSignIn, onEmailStart, onEmailVerify, customAuthLabel, onCustomAuthSignIn, canUsePasskey, passkeyAddress, onPasskeySignIn, }: WalletSelectorProps): React.ReactPortal | null;
789
961
 
790
962
  type Theme = "light" | "dark" | "auto";
791
963
  interface SocialAuthState {
@@ -834,11 +1006,12 @@ interface SocialWalletModalProps {
834
1006
  onUnlock: () => Promise<void>;
835
1007
  onDisconnect: () => Promise<void>;
836
1008
  onGoogleSignIn: () => Promise<void>;
1009
+ onKingsChatSignIn?: () => Promise<void>;
837
1010
  onEmailStart: (email: string) => Promise<{
838
1011
  codeRequired: true;
839
1012
  }>;
840
1013
  onEmailVerify: (email: string, code: string) => Promise<void>;
841
- authMethods?: Array<"google" | "email">;
1014
+ authMethods?: Array<"google" | "email" | "kingschat">;
842
1015
  customAuthLabel?: string;
843
1016
  onCustomAuthSignIn?: () => Promise<void>;
844
1017
  canUsePasskey?: boolean;
@@ -855,7 +1028,7 @@ interface SocialWalletModalProps {
855
1028
  rpcUrls?: Record<string, string>;
856
1029
  chains?: string[];
857
1030
  }
858
- declare function SocialWalletModal({ open, onClose, theme, socialAuth, onUnlock, onDisconnect, onGoogleSignIn, onEmailStart, onEmailVerify, authMethods, customAuthLabel, onCustomAuthSignIn, canUsePasskey, passkeyAddress, onPasskeySignIn, onRotateShares, onExportPortableBackup, rpcUrls, chains, }: SocialWalletModalProps): React.ReactPortal | null;
1031
+ declare function SocialWalletModal({ open, onClose, theme, socialAuth, onUnlock, onDisconnect, onGoogleSignIn, onKingsChatSignIn, onEmailStart, onEmailVerify, authMethods, customAuthLabel, onCustomAuthSignIn, canUsePasskey, passkeyAddress, onPasskeySignIn, onRotateShares, onExportPortableBackup, rpcUrls, chains, }: SocialWalletModalProps): React.ReactPortal | null;
859
1032
 
860
1033
  declare function DecaneMark({ size, muted }: {
861
1034
  size?: number;
@@ -933,6 +1106,8 @@ declare function useSocialWallet(): {
933
1106
  }) => Promise<string>;
934
1107
  signSolanaTransaction: (tx: Uint8Array) => Promise<Uint8Array<ArrayBufferLike>>;
935
1108
  signTronTransaction: (rawDataHex: string) => Promise<string>;
1109
+ recordTransaction: (tx: RecordTransactionInput) => Promise<TransactionRecord>;
1110
+ getTransactionHistory: (limit?: number) => Promise<TransactionRecord[]>;
936
1111
  signTypedData: (req: {
937
1112
  chain: string;
938
1113
  domain: Record<string, unknown>;
@@ -1051,4 +1226,4 @@ declare function useSignTypedData(): {
1051
1226
  reset: () => void;
1052
1227
  };
1053
1228
 
1054
- export { type ActiveSession, AttestationError, 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, NetworkError, NewDeviceError, OriginNotAllowedError, type PortableBackup, PromptPinNotConfiguredError, ReconnectRequiredError, RecoveryFailedError, type RecoveryProgress, type RecoveryShareFile, RecoveryWalletMismatchError, type SdkEvent, type SendTransactionRequest, SessionExpiredError, ShareCorruptedError, type SignMessageRequest, type SignTypedDataRequest, type SignedAuthorization, type SocialAuthState, type SocialConfig, SocialWalletModal, type Theme, type TxParams, type UnifiedWalletAccount, UnlockRequiredError, UserCancelledError, WalletSelector, WebAuthnNotSupportedError, type WrappedShareMeta, WrongPasswordError, createDecane, createDecaneConnect, createEthereumProvider, startEmailAuth, useChainSwitch, useDecane, useEthereumProvider, useSendTransaction, useSignMessage, useSignTypedData, useSocialAuth, useSocialBalance, useSocialWallet, useWalletSelector, verifyEmailCode };
1229
+ export { type ActiveSession, AttestationError, 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 };