decane-connect-kit 2.18.0 → 2.20.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.cjs +216 -36
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +40 -6
- package/dist/index.d.ts +40 -6
- package/dist/index.js +216 -36
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -92,7 +92,7 @@ interface DecaneConnectConfig {
|
|
|
92
92
|
appId: string;
|
|
93
93
|
apiKey: string;
|
|
94
94
|
chains: Chain[];
|
|
95
|
-
authMethods: Array<'google' | 'email' | 'phone' | 'kingschat'>;
|
|
95
|
+
authMethods: Array<'google' | 'email' | 'phone' | 'kingschat' | 'x'>;
|
|
96
96
|
/**
|
|
97
97
|
* Scopes requested from KingsChat at sign-in. Defaults to
|
|
98
98
|
* `['send_chat_message']`, which is what KingsChat's own SDK asks for and is
|
|
@@ -303,6 +303,23 @@ interface DecaneConnect {
|
|
|
303
303
|
* Decane session; it is never treated as one on its own.
|
|
304
304
|
*/
|
|
305
305
|
connectWithKingsChat(): Promise<ConnectResult>;
|
|
306
|
+
/**
|
|
307
|
+
* Sign in with X (Twitter).
|
|
308
|
+
*
|
|
309
|
+
* A redirect, like Google and unlike KingsChat's popup: calling it navigates
|
|
310
|
+
* away, and the promise never resolves. Call it again on the page X returns
|
|
311
|
+
* to and it finishes the sign-in from the URL instead of starting a new one.
|
|
312
|
+
*
|
|
313
|
+
* X releases no email address, so `result.profile` carries a name and a
|
|
314
|
+
* picture and nothing else. Anything that needs an address must ask the user
|
|
315
|
+
* for one.
|
|
316
|
+
*/
|
|
317
|
+
connectWithX(): Promise<ConnectResult>;
|
|
318
|
+
/**
|
|
319
|
+
* Finish a redirect sign-in already present in the URL, whichever provider
|
|
320
|
+
* started it. Throws when there is nothing to finish — it never starts one.
|
|
321
|
+
*/
|
|
322
|
+
completeRedirectSignIn(): Promise<ConnectResult>;
|
|
306
323
|
/**
|
|
307
324
|
* Sign in with a KingsChat access token the app already holds — from
|
|
308
325
|
* kingschat-web-sdk, a native SDK, or any other flow. Use when you want to
|
|
@@ -548,6 +565,14 @@ declare class ApiClient {
|
|
|
548
565
|
getGoogleInitUrl(): Promise<{
|
|
549
566
|
url: string;
|
|
550
567
|
}>;
|
|
568
|
+
/**
|
|
569
|
+
* The X consent URL. Same contract as Google's: the backend holds the client
|
|
570
|
+
* secret and the PKCE verifier, and answers 503 X_NOT_CONFIGURED when the
|
|
571
|
+
* deployment has no X credentials.
|
|
572
|
+
*/
|
|
573
|
+
getXInitUrl(): Promise<{
|
|
574
|
+
url: string;
|
|
575
|
+
}>;
|
|
551
576
|
/**
|
|
552
577
|
* Exchange a Google ID token the app already holds for a Decane session.
|
|
553
578
|
* Resolves to the SAME identity as the redirect flow, so one Google account
|
|
@@ -592,7 +617,12 @@ declare class ApiClient {
|
|
|
592
617
|
metadata?: Record<string, unknown>;
|
|
593
618
|
}): Promise<TransactionRecord>;
|
|
594
619
|
getTransactions(jwt: string, limit?: number): Promise<TransactionRecord[]>;
|
|
595
|
-
|
|
620
|
+
/**
|
|
621
|
+
* `label` is what the user's password manager will show for this passkey.
|
|
622
|
+
* Without one they see the account's opaque id. Sent, used, and forgotten —
|
|
623
|
+
* the backend echoes it into the options and stores nothing.
|
|
624
|
+
*/
|
|
625
|
+
getWebAuthnRegisterOptions(jwt: string, rpId: string, rpName: string, label?: string): Promise<_simplewebauthn_browser.PublicKeyCredentialCreationOptionsJSON>;
|
|
596
626
|
postWebAuthnRegister(jwt: string, response: _simplewebauthn_browser.RegistrationResponseJSON, origin: string): Promise<void>;
|
|
597
627
|
/**
|
|
598
628
|
* Exchange a token from the developer's own auth system for a Decane
|
|
@@ -750,7 +780,7 @@ interface DecaneProvider {
|
|
|
750
780
|
type ConnectMode = "all" | "social" | "wallets" | "evm" | "solana" | "tron" | "evm+social" | "solana+social" | "tron+social" | "evm+tron" | "evm+tron+social";
|
|
751
781
|
interface SocialConfig {
|
|
752
782
|
apiKey: string;
|
|
753
|
-
authMethods?: ("google" | "email" | "phone" | "kingschat")[];
|
|
783
|
+
authMethods?: ("google" | "email" | "phone" | "kingschat" | "x")[];
|
|
754
784
|
/**
|
|
755
785
|
* Scopes requested from KingsChat. Defaults to `['send_chat_message']`, which
|
|
756
786
|
* is what KingsChat's own SDK asks for and is enough to establish identity.
|
|
@@ -1154,9 +1184,10 @@ interface WalletSelectorProps {
|
|
|
1154
1184
|
theme?: "light" | "dark" | "auto";
|
|
1155
1185
|
networks?: "evm" | "solana" | "tron" | "bitcoin" | "all";
|
|
1156
1186
|
mode?: ConnectMode;
|
|
1157
|
-
socialAuthMethods?: ("google" | "email" | "phone" | "kingschat")[];
|
|
1187
|
+
socialAuthMethods?: ("google" | "email" | "phone" | "kingschat" | "x")[];
|
|
1158
1188
|
onGoogleSignIn?: () => Promise<void>;
|
|
1159
1189
|
onKingsChatSignIn?: () => Promise<void>;
|
|
1190
|
+
onXSignIn?: () => Promise<void>;
|
|
1160
1191
|
onEmailStart?: (email: string) => Promise<{
|
|
1161
1192
|
codeRequired: true;
|
|
1162
1193
|
}>;
|
|
@@ -1174,7 +1205,7 @@ interface WalletSelectorProps {
|
|
|
1174
1205
|
passkeyAddress?: string | null;
|
|
1175
1206
|
onPasskeySignIn?: () => Promise<unknown>;
|
|
1176
1207
|
}
|
|
1177
|
-
declare function WalletSelector({ provider, open, onClose, onConnect, theme, networks, mode, socialAuthMethods, onGoogleSignIn, onKingsChatSignIn, onEmailStart, onEmailVerify, onPhoneStart, onPhoneVerify, customAuthLabel, onCustomAuthSignIn, canUsePasskey, passkeyAddress, onPasskeySignIn, }: WalletSelectorProps): React.ReactPortal | null;
|
|
1208
|
+
declare function WalletSelector({ provider, open, onClose, onConnect, theme, networks, mode, socialAuthMethods, onGoogleSignIn, onKingsChatSignIn, onXSignIn, onEmailStart, onEmailVerify, onPhoneStart, onPhoneVerify, customAuthLabel, onCustomAuthSignIn, canUsePasskey, passkeyAddress, onPasskeySignIn, }: WalletSelectorProps): React.ReactPortal | null;
|
|
1178
1209
|
|
|
1179
1210
|
type Theme = "light" | "dark" | "auto";
|
|
1180
1211
|
interface SocialAuthState {
|
|
@@ -1238,6 +1269,7 @@ interface SocialWalletModalProps {
|
|
|
1238
1269
|
onDisconnect: () => Promise<void>;
|
|
1239
1270
|
onGoogleSignIn: () => Promise<void>;
|
|
1240
1271
|
onKingsChatSignIn?: () => Promise<void>;
|
|
1272
|
+
onXSignIn?: () => Promise<void>;
|
|
1241
1273
|
onEmailStart: (email: string) => Promise<{
|
|
1242
1274
|
codeRequired: true;
|
|
1243
1275
|
}>;
|
|
@@ -1246,7 +1278,7 @@ interface SocialWalletModalProps {
|
|
|
1246
1278
|
codeRequired: true;
|
|
1247
1279
|
}>;
|
|
1248
1280
|
onPhoneVerify?: (phone: string, code: string) => Promise<void>;
|
|
1249
|
-
authMethods?: Array<"google" | "email" | "phone" | "kingschat">;
|
|
1281
|
+
authMethods?: Array<"google" | "email" | "phone" | "kingschat" | "x">;
|
|
1250
1282
|
customAuthLabel?: string;
|
|
1251
1283
|
onCustomAuthSignIn?: () => Promise<void>;
|
|
1252
1284
|
canUsePasskey?: boolean;
|
|
@@ -1295,6 +1327,7 @@ declare function useSocialAuth(): {
|
|
|
1295
1327
|
needsReconnect: boolean;
|
|
1296
1328
|
googleLoading: boolean;
|
|
1297
1329
|
kingschatLoading: boolean;
|
|
1330
|
+
xLoading: boolean;
|
|
1298
1331
|
emailLoading: boolean;
|
|
1299
1332
|
phoneLoading: boolean;
|
|
1300
1333
|
tokenLoading: boolean;
|
|
@@ -1304,6 +1337,7 @@ declare function useSocialAuth(): {
|
|
|
1304
1337
|
clearError: () => void;
|
|
1305
1338
|
signInWithGoogle: () => Promise<void>;
|
|
1306
1339
|
signInWithKingsChat: () => Promise<void>;
|
|
1340
|
+
signInWithX: () => Promise<void>;
|
|
1307
1341
|
sendEmailCode: (email: string) => Promise<{
|
|
1308
1342
|
codeRequired: true;
|
|
1309
1343
|
}>;
|
package/dist/index.d.ts
CHANGED
|
@@ -92,7 +92,7 @@ interface DecaneConnectConfig {
|
|
|
92
92
|
appId: string;
|
|
93
93
|
apiKey: string;
|
|
94
94
|
chains: Chain[];
|
|
95
|
-
authMethods: Array<'google' | 'email' | 'phone' | 'kingschat'>;
|
|
95
|
+
authMethods: Array<'google' | 'email' | 'phone' | 'kingschat' | 'x'>;
|
|
96
96
|
/**
|
|
97
97
|
* Scopes requested from KingsChat at sign-in. Defaults to
|
|
98
98
|
* `['send_chat_message']`, which is what KingsChat's own SDK asks for and is
|
|
@@ -303,6 +303,23 @@ interface DecaneConnect {
|
|
|
303
303
|
* Decane session; it is never treated as one on its own.
|
|
304
304
|
*/
|
|
305
305
|
connectWithKingsChat(): Promise<ConnectResult>;
|
|
306
|
+
/**
|
|
307
|
+
* Sign in with X (Twitter).
|
|
308
|
+
*
|
|
309
|
+
* A redirect, like Google and unlike KingsChat's popup: calling it navigates
|
|
310
|
+
* away, and the promise never resolves. Call it again on the page X returns
|
|
311
|
+
* to and it finishes the sign-in from the URL instead of starting a new one.
|
|
312
|
+
*
|
|
313
|
+
* X releases no email address, so `result.profile` carries a name and a
|
|
314
|
+
* picture and nothing else. Anything that needs an address must ask the user
|
|
315
|
+
* for one.
|
|
316
|
+
*/
|
|
317
|
+
connectWithX(): Promise<ConnectResult>;
|
|
318
|
+
/**
|
|
319
|
+
* Finish a redirect sign-in already present in the URL, whichever provider
|
|
320
|
+
* started it. Throws when there is nothing to finish — it never starts one.
|
|
321
|
+
*/
|
|
322
|
+
completeRedirectSignIn(): Promise<ConnectResult>;
|
|
306
323
|
/**
|
|
307
324
|
* Sign in with a KingsChat access token the app already holds — from
|
|
308
325
|
* kingschat-web-sdk, a native SDK, or any other flow. Use when you want to
|
|
@@ -548,6 +565,14 @@ declare class ApiClient {
|
|
|
548
565
|
getGoogleInitUrl(): Promise<{
|
|
549
566
|
url: string;
|
|
550
567
|
}>;
|
|
568
|
+
/**
|
|
569
|
+
* The X consent URL. Same contract as Google's: the backend holds the client
|
|
570
|
+
* secret and the PKCE verifier, and answers 503 X_NOT_CONFIGURED when the
|
|
571
|
+
* deployment has no X credentials.
|
|
572
|
+
*/
|
|
573
|
+
getXInitUrl(): Promise<{
|
|
574
|
+
url: string;
|
|
575
|
+
}>;
|
|
551
576
|
/**
|
|
552
577
|
* Exchange a Google ID token the app already holds for a Decane session.
|
|
553
578
|
* Resolves to the SAME identity as the redirect flow, so one Google account
|
|
@@ -592,7 +617,12 @@ declare class ApiClient {
|
|
|
592
617
|
metadata?: Record<string, unknown>;
|
|
593
618
|
}): Promise<TransactionRecord>;
|
|
594
619
|
getTransactions(jwt: string, limit?: number): Promise<TransactionRecord[]>;
|
|
595
|
-
|
|
620
|
+
/**
|
|
621
|
+
* `label` is what the user's password manager will show for this passkey.
|
|
622
|
+
* Without one they see the account's opaque id. Sent, used, and forgotten —
|
|
623
|
+
* the backend echoes it into the options and stores nothing.
|
|
624
|
+
*/
|
|
625
|
+
getWebAuthnRegisterOptions(jwt: string, rpId: string, rpName: string, label?: string): Promise<_simplewebauthn_browser.PublicKeyCredentialCreationOptionsJSON>;
|
|
596
626
|
postWebAuthnRegister(jwt: string, response: _simplewebauthn_browser.RegistrationResponseJSON, origin: string): Promise<void>;
|
|
597
627
|
/**
|
|
598
628
|
* Exchange a token from the developer's own auth system for a Decane
|
|
@@ -750,7 +780,7 @@ interface DecaneProvider {
|
|
|
750
780
|
type ConnectMode = "all" | "social" | "wallets" | "evm" | "solana" | "tron" | "evm+social" | "solana+social" | "tron+social" | "evm+tron" | "evm+tron+social";
|
|
751
781
|
interface SocialConfig {
|
|
752
782
|
apiKey: string;
|
|
753
|
-
authMethods?: ("google" | "email" | "phone" | "kingschat")[];
|
|
783
|
+
authMethods?: ("google" | "email" | "phone" | "kingschat" | "x")[];
|
|
754
784
|
/**
|
|
755
785
|
* Scopes requested from KingsChat. Defaults to `['send_chat_message']`, which
|
|
756
786
|
* is what KingsChat's own SDK asks for and is enough to establish identity.
|
|
@@ -1154,9 +1184,10 @@ interface WalletSelectorProps {
|
|
|
1154
1184
|
theme?: "light" | "dark" | "auto";
|
|
1155
1185
|
networks?: "evm" | "solana" | "tron" | "bitcoin" | "all";
|
|
1156
1186
|
mode?: ConnectMode;
|
|
1157
|
-
socialAuthMethods?: ("google" | "email" | "phone" | "kingschat")[];
|
|
1187
|
+
socialAuthMethods?: ("google" | "email" | "phone" | "kingschat" | "x")[];
|
|
1158
1188
|
onGoogleSignIn?: () => Promise<void>;
|
|
1159
1189
|
onKingsChatSignIn?: () => Promise<void>;
|
|
1190
|
+
onXSignIn?: () => Promise<void>;
|
|
1160
1191
|
onEmailStart?: (email: string) => Promise<{
|
|
1161
1192
|
codeRequired: true;
|
|
1162
1193
|
}>;
|
|
@@ -1174,7 +1205,7 @@ interface WalletSelectorProps {
|
|
|
1174
1205
|
passkeyAddress?: string | null;
|
|
1175
1206
|
onPasskeySignIn?: () => Promise<unknown>;
|
|
1176
1207
|
}
|
|
1177
|
-
declare function WalletSelector({ provider, open, onClose, onConnect, theme, networks, mode, socialAuthMethods, onGoogleSignIn, onKingsChatSignIn, onEmailStart, onEmailVerify, onPhoneStart, onPhoneVerify, customAuthLabel, onCustomAuthSignIn, canUsePasskey, passkeyAddress, onPasskeySignIn, }: WalletSelectorProps): React.ReactPortal | null;
|
|
1208
|
+
declare function WalletSelector({ provider, open, onClose, onConnect, theme, networks, mode, socialAuthMethods, onGoogleSignIn, onKingsChatSignIn, onXSignIn, onEmailStart, onEmailVerify, onPhoneStart, onPhoneVerify, customAuthLabel, onCustomAuthSignIn, canUsePasskey, passkeyAddress, onPasskeySignIn, }: WalletSelectorProps): React.ReactPortal | null;
|
|
1178
1209
|
|
|
1179
1210
|
type Theme = "light" | "dark" | "auto";
|
|
1180
1211
|
interface SocialAuthState {
|
|
@@ -1238,6 +1269,7 @@ interface SocialWalletModalProps {
|
|
|
1238
1269
|
onDisconnect: () => Promise<void>;
|
|
1239
1270
|
onGoogleSignIn: () => Promise<void>;
|
|
1240
1271
|
onKingsChatSignIn?: () => Promise<void>;
|
|
1272
|
+
onXSignIn?: () => Promise<void>;
|
|
1241
1273
|
onEmailStart: (email: string) => Promise<{
|
|
1242
1274
|
codeRequired: true;
|
|
1243
1275
|
}>;
|
|
@@ -1246,7 +1278,7 @@ interface SocialWalletModalProps {
|
|
|
1246
1278
|
codeRequired: true;
|
|
1247
1279
|
}>;
|
|
1248
1280
|
onPhoneVerify?: (phone: string, code: string) => Promise<void>;
|
|
1249
|
-
authMethods?: Array<"google" | "email" | "phone" | "kingschat">;
|
|
1281
|
+
authMethods?: Array<"google" | "email" | "phone" | "kingschat" | "x">;
|
|
1250
1282
|
customAuthLabel?: string;
|
|
1251
1283
|
onCustomAuthSignIn?: () => Promise<void>;
|
|
1252
1284
|
canUsePasskey?: boolean;
|
|
@@ -1295,6 +1327,7 @@ declare function useSocialAuth(): {
|
|
|
1295
1327
|
needsReconnect: boolean;
|
|
1296
1328
|
googleLoading: boolean;
|
|
1297
1329
|
kingschatLoading: boolean;
|
|
1330
|
+
xLoading: boolean;
|
|
1298
1331
|
emailLoading: boolean;
|
|
1299
1332
|
phoneLoading: boolean;
|
|
1300
1333
|
tokenLoading: boolean;
|
|
@@ -1304,6 +1337,7 @@ declare function useSocialAuth(): {
|
|
|
1304
1337
|
clearError: () => void;
|
|
1305
1338
|
signInWithGoogle: () => Promise<void>;
|
|
1306
1339
|
signInWithKingsChat: () => Promise<void>;
|
|
1340
|
+
signInWithX: () => Promise<void>;
|
|
1307
1341
|
sendEmailCode: (email: string) => Promise<{
|
|
1308
1342
|
codeRequired: true;
|
|
1309
1343
|
}>;
|
package/dist/index.js
CHANGED
|
@@ -1946,6 +1946,37 @@ var EventEmitter = class {
|
|
|
1946
1946
|
}
|
|
1947
1947
|
};
|
|
1948
1948
|
|
|
1949
|
+
// src/social/auth/redirectResult.ts
|
|
1950
|
+
function readRedirectOutcome(search) {
|
|
1951
|
+
const params = new URLSearchParams(search);
|
|
1952
|
+
const error = params.get("decane_error");
|
|
1953
|
+
if (error) return { kind: "error", error };
|
|
1954
|
+
const jwt = params.get("decane_jwt");
|
|
1955
|
+
if (!jwt) return { kind: "none" };
|
|
1956
|
+
const name = params.get("decane_name");
|
|
1957
|
+
const email = params.get("decane_email");
|
|
1958
|
+
const picture = params.get("decane_picture");
|
|
1959
|
+
const profile = {
|
|
1960
|
+
...name ? { name } : {},
|
|
1961
|
+
...email ? { email } : {},
|
|
1962
|
+
...picture ? { picture } : {}
|
|
1963
|
+
};
|
|
1964
|
+
return {
|
|
1965
|
+
kind: "result",
|
|
1966
|
+
result: {
|
|
1967
|
+
jwt,
|
|
1968
|
+
userId: params.get("decane_user_id") ?? "",
|
|
1969
|
+
isNewUser: params.get("decane_is_new_user") === "true",
|
|
1970
|
+
hasShare: params.get("decane_has_share") === "true",
|
|
1971
|
+
// Omitted entirely when the provider released nothing, so callers can
|
|
1972
|
+
// test `result.profile` rather than an object that is always present but
|
|
1973
|
+
// sometimes empty. X never sends an email, so this is the normal case
|
|
1974
|
+
// there rather than an edge one.
|
|
1975
|
+
...Object.keys(profile).length ? { profile } : {}
|
|
1976
|
+
}
|
|
1977
|
+
};
|
|
1978
|
+
}
|
|
1979
|
+
|
|
1949
1980
|
// src/social/api.ts
|
|
1950
1981
|
init_errors();
|
|
1951
1982
|
var ERROR_MAP = {
|
|
@@ -1997,6 +2028,14 @@ var ApiClient = class {
|
|
|
1997
2028
|
async getGoogleInitUrl() {
|
|
1998
2029
|
return this._request("/auth/google/init", { method: "GET" });
|
|
1999
2030
|
}
|
|
2031
|
+
/**
|
|
2032
|
+
* The X consent URL. Same contract as Google's: the backend holds the client
|
|
2033
|
+
* secret and the PKCE verifier, and answers 503 X_NOT_CONFIGURED when the
|
|
2034
|
+
* deployment has no X credentials.
|
|
2035
|
+
*/
|
|
2036
|
+
async getXInitUrl() {
|
|
2037
|
+
return this._request("/auth/x/init", { method: "GET" });
|
|
2038
|
+
}
|
|
2000
2039
|
/**
|
|
2001
2040
|
* Exchange a Google ID token the app already holds for a Decane session.
|
|
2002
2041
|
* Resolves to the SAME identity as the redirect flow, so one Google account
|
|
@@ -2085,8 +2124,14 @@ var ApiClient = class {
|
|
|
2085
2124
|
return body.transactions;
|
|
2086
2125
|
}
|
|
2087
2126
|
// ── WebAuthn registration (additive to the PRF-only passkey flow) ─────────
|
|
2088
|
-
|
|
2089
|
-
|
|
2127
|
+
/**
|
|
2128
|
+
* `label` is what the user's password manager will show for this passkey.
|
|
2129
|
+
* Without one they see the account's opaque id. Sent, used, and forgotten —
|
|
2130
|
+
* the backend echoes it into the options and stores nothing.
|
|
2131
|
+
*/
|
|
2132
|
+
async getWebAuthnRegisterOptions(jwt, rpId, rpName, label) {
|
|
2133
|
+
const query = `rpId=${encodeURIComponent(rpId)}&rpName=${encodeURIComponent(rpName)}` + (label ? `&label=${encodeURIComponent(label)}` : "");
|
|
2134
|
+
return this._request(`/webauthn/register-options?${query}`, {
|
|
2090
2135
|
headers: { Authorization: `Bearer ${jwt}` }
|
|
2091
2136
|
});
|
|
2092
2137
|
}
|
|
@@ -2970,7 +3015,12 @@ function bufFromBytes(u) {
|
|
|
2970
3015
|
return u.buffer.slice(u.byteOffset, u.byteOffset + u.byteLength);
|
|
2971
3016
|
}
|
|
2972
3017
|
async function registerWebAuthnCredential(opts) {
|
|
2973
|
-
const baseOptions = await opts.api.getWebAuthnRegisterOptions(
|
|
3018
|
+
const baseOptions = await opts.api.getWebAuthnRegisterOptions(
|
|
3019
|
+
opts.jwt,
|
|
3020
|
+
opts.rpId,
|
|
3021
|
+
opts.rpName,
|
|
3022
|
+
opts.label
|
|
3023
|
+
);
|
|
2974
3024
|
if (opts.allowDuplicate) delete baseOptions.excludeCredentials;
|
|
2975
3025
|
const optionsJSON = {
|
|
2976
3026
|
...baseOptions,
|
|
@@ -3776,12 +3826,14 @@ async function createDecaneConnect(config) {
|
|
|
3776
3826
|
let credentialId;
|
|
3777
3827
|
let prfOutput;
|
|
3778
3828
|
try {
|
|
3829
|
+
const label = (await storage.getShare(userId))?.profile?.email;
|
|
3779
3830
|
({ credentialId, prfOutput } = await registerWebAuthnCredential({
|
|
3780
3831
|
api,
|
|
3781
3832
|
jwt,
|
|
3782
3833
|
rpId,
|
|
3783
3834
|
rpName,
|
|
3784
3835
|
prfSalt,
|
|
3836
|
+
...label ? { label } : {},
|
|
3785
3837
|
...opts.allowDuplicate ? { allowDuplicate: true } : {}
|
|
3786
3838
|
}));
|
|
3787
3839
|
} catch (e) {
|
|
@@ -4283,6 +4335,21 @@ async function createDecaneConnect(config) {
|
|
|
4283
4335
|
...stored.profile ? { profile: stored.profile } : {}
|
|
4284
4336
|
};
|
|
4285
4337
|
}
|
|
4338
|
+
async function connectViaRedirect(label, getInitUrl) {
|
|
4339
|
+
const outcome = readRedirectOutcome(window.location.search);
|
|
4340
|
+
if (outcome.kind === "error") {
|
|
4341
|
+
window.history.replaceState({}, "", window.location.pathname);
|
|
4342
|
+
throw new CallSequenceError(`${label} sign-in failed: ${outcome.error}`);
|
|
4343
|
+
}
|
|
4344
|
+
if (outcome.kind === "result") {
|
|
4345
|
+
window.history.replaceState({}, "", window.location.pathname);
|
|
4346
|
+
return handleAuthResult(outcome.result);
|
|
4347
|
+
}
|
|
4348
|
+
const { url } = await getInitUrl();
|
|
4349
|
+
window.location.href = url;
|
|
4350
|
+
return new Promise(() => {
|
|
4351
|
+
});
|
|
4352
|
+
}
|
|
4286
4353
|
async function handleAuthResult(result) {
|
|
4287
4354
|
let addresses;
|
|
4288
4355
|
if (!result.hasShare) {
|
|
@@ -4329,39 +4396,33 @@ async function createDecaneConnect(config) {
|
|
|
4329
4396
|
throw new CallSequenceError(`Unknown auth method: ${method}`);
|
|
4330
4397
|
},
|
|
4331
4398
|
async connectWithGoogle() {
|
|
4332
|
-
|
|
4333
|
-
|
|
4334
|
-
|
|
4335
|
-
|
|
4336
|
-
|
|
4337
|
-
|
|
4338
|
-
|
|
4339
|
-
|
|
4340
|
-
|
|
4341
|
-
|
|
4342
|
-
|
|
4343
|
-
|
|
4344
|
-
|
|
4345
|
-
|
|
4346
|
-
|
|
4347
|
-
|
|
4348
|
-
|
|
4349
|
-
|
|
4350
|
-
userId: params.get("decane_user_id") ?? "",
|
|
4351
|
-
isNewUser: params.get("decane_is_new_user") === "true",
|
|
4352
|
-
hasShare: params.get("decane_has_share") === "true",
|
|
4353
|
-
// Omitted entirely when Google released nothing, so callers can test
|
|
4354
|
-
// `result.profile` rather than an object that is always present but
|
|
4355
|
-
// sometimes empty.
|
|
4356
|
-
...Object.keys(profile).length ? { profile } : {}
|
|
4357
|
-
};
|
|
4358
|
-
window.history.replaceState({}, "", window.location.pathname);
|
|
4359
|
-
return handleAuthResult(result);
|
|
4399
|
+
return connectViaRedirect("Google", () => api.getGoogleInitUrl());
|
|
4400
|
+
},
|
|
4401
|
+
/**
|
|
4402
|
+
* Finish a redirect sign-in that is already sitting in the URL, whichever
|
|
4403
|
+
* provider started it.
|
|
4404
|
+
*
|
|
4405
|
+
* Google and X bounce back with the same decane_* params, so the page that
|
|
4406
|
+
* receives them cannot tell which one ran — and should not have to. Calling
|
|
4407
|
+
* connectWithGoogle() here would work by accident and then report an X
|
|
4408
|
+
* failure as "Google sign-in failed".
|
|
4409
|
+
*
|
|
4410
|
+
* Throws if there is nothing to finish: unlike the connectWith* methods,
|
|
4411
|
+
* this never starts a flow.
|
|
4412
|
+
*/
|
|
4413
|
+
async completeRedirectSignIn() {
|
|
4414
|
+
const outcome = readRedirectOutcome(window.location.search);
|
|
4415
|
+
if (outcome.kind === "none") {
|
|
4416
|
+
throw new CallSequenceError("No sign-in result in the URL to complete");
|
|
4360
4417
|
}
|
|
4361
|
-
|
|
4362
|
-
|
|
4363
|
-
|
|
4364
|
-
}
|
|
4418
|
+
window.history.replaceState({}, "", window.location.pathname);
|
|
4419
|
+
if (outcome.kind === "error") {
|
|
4420
|
+
throw new CallSequenceError(`Sign-in failed: ${outcome.error}`);
|
|
4421
|
+
}
|
|
4422
|
+
return handleAuthResult(outcome.result);
|
|
4423
|
+
},
|
|
4424
|
+
async connectWithX() {
|
|
4425
|
+
return connectViaRedirect("X", () => api.getXInitUrl());
|
|
4365
4426
|
},
|
|
4366
4427
|
async connectWithGoogleToken(idToken) {
|
|
4367
4428
|
if (!idToken) throw new CallSequenceError("connectWithGoogleToken requires an ID token");
|
|
@@ -5185,6 +5246,20 @@ function ChainIconStack({ support, size = 16 }) {
|
|
|
5185
5246
|
/* @__PURE__ */ React.createElement(ChainCircleIcon, { chain, size })
|
|
5186
5247
|
)));
|
|
5187
5248
|
}
|
|
5249
|
+
function XLogo({ size = 14 }) {
|
|
5250
|
+
return /* @__PURE__ */ React.createElement(
|
|
5251
|
+
"svg",
|
|
5252
|
+
{
|
|
5253
|
+
width: size,
|
|
5254
|
+
height: size,
|
|
5255
|
+
viewBox: "0 0 24 24",
|
|
5256
|
+
fill: "currentColor",
|
|
5257
|
+
"aria-hidden": "true",
|
|
5258
|
+
focusable: "false"
|
|
5259
|
+
},
|
|
5260
|
+
/* @__PURE__ */ React.createElement("path", { d: "M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z" })
|
|
5261
|
+
);
|
|
5262
|
+
}
|
|
5188
5263
|
|
|
5189
5264
|
// src/ui/WalletSelector.tsx
|
|
5190
5265
|
var FONT_URL = "https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@400;500;600;700;800&display=swap";
|
|
@@ -5326,6 +5401,7 @@ function WalletSelector({
|
|
|
5326
5401
|
socialAuthMethods = ["google", "email"],
|
|
5327
5402
|
onGoogleSignIn,
|
|
5328
5403
|
onKingsChatSignIn,
|
|
5404
|
+
onXSignIn,
|
|
5329
5405
|
onEmailStart,
|
|
5330
5406
|
onEmailVerify,
|
|
5331
5407
|
onPhoneStart,
|
|
@@ -5420,6 +5496,17 @@ function WalletSelector({
|
|
|
5420
5496
|
setSocialLoad(false);
|
|
5421
5497
|
}
|
|
5422
5498
|
}
|
|
5499
|
+
async function handleXClick() {
|
|
5500
|
+
if (!onXSignIn) return;
|
|
5501
|
+
setSocialLoad(true);
|
|
5502
|
+
setSocialErr("");
|
|
5503
|
+
try {
|
|
5504
|
+
await onXSignIn();
|
|
5505
|
+
} catch (e) {
|
|
5506
|
+
setSocialErr(e.message);
|
|
5507
|
+
setSocialLoad(false);
|
|
5508
|
+
}
|
|
5509
|
+
}
|
|
5423
5510
|
async function handleCustomAuthClick() {
|
|
5424
5511
|
if (!onCustomAuthSignIn) return;
|
|
5425
5512
|
setSocialLoad(true);
|
|
@@ -5901,6 +5988,38 @@ function WalletSelector({
|
|
|
5901
5988
|
},
|
|
5902
5989
|
/* @__PURE__ */ React2.createElement("svg", { width: "18", height: "18", viewBox: "0 0 18 18", fill: "none", "aria-hidden": "true" }, /* @__PURE__ */ React2.createElement("circle", { cx: "9", cy: "9", r: "9", fill: "var(--dc-accent)" }), /* @__PURE__ */ React2.createElement("path", { d: "M5.5 4.5h1.9v3.6l3.1-3.6h2.3l-3.3 3.8 3.5 5.2h-2.3l-2.5-3.8-.8.9v2.9H5.5V4.5z", fill: "var(--dc-accent-text)" })),
|
|
5903
5990
|
socialLoad ? "Waiting for KingsChat\u2026" : "Continue with KingsChat"
|
|
5991
|
+
), !passkeyFirst && socialAuthMethods.includes("x") && onXSignIn && /* @__PURE__ */ React2.createElement(
|
|
5992
|
+
"button",
|
|
5993
|
+
{
|
|
5994
|
+
onClick: handleXClick,
|
|
5995
|
+
disabled: socialLoad,
|
|
5996
|
+
style: {
|
|
5997
|
+
display: "flex",
|
|
5998
|
+
alignItems: "center",
|
|
5999
|
+
justifyContent: "center",
|
|
6000
|
+
gap: 10,
|
|
6001
|
+
width: "100%",
|
|
6002
|
+
padding: "11px 16px",
|
|
6003
|
+
background: "var(--dc-surface)",
|
|
6004
|
+
border: "1px solid var(--dc-border)",
|
|
6005
|
+
borderRadius: 10,
|
|
6006
|
+
cursor: socialLoad ? "not-allowed" : "pointer",
|
|
6007
|
+
fontSize: 14,
|
|
6008
|
+
fontWeight: 600,
|
|
6009
|
+
color: "var(--dc-text)",
|
|
6010
|
+
fontFamily: "inherit",
|
|
6011
|
+
transition: "border-color 0.12s, background 0.12s",
|
|
6012
|
+
opacity: socialLoad ? 0.6 : 1
|
|
6013
|
+
},
|
|
6014
|
+
onMouseEnter: (e) => {
|
|
6015
|
+
if (!socialLoad) e.currentTarget.style.borderColor = "var(--dc-border-accent)";
|
|
6016
|
+
},
|
|
6017
|
+
onMouseLeave: (e) => {
|
|
6018
|
+
e.currentTarget.style.borderColor = "var(--dc-border)";
|
|
6019
|
+
}
|
|
6020
|
+
},
|
|
6021
|
+
/* @__PURE__ */ React2.createElement(XLogo, { size: 16 }),
|
|
6022
|
+
socialLoad ? "Redirecting\u2026" : "Continue with X"
|
|
5904
6023
|
), !passkeyFirst && socialAuthMethods.includes("google") && socialAuthMethods.includes("email") && /* @__PURE__ */ React2.createElement("div", { style: { display: "flex", alignItems: "center", gap: 10 } }, /* @__PURE__ */ React2.createElement("div", { style: { flex: 1, height: 1, background: "var(--dc-border)" } }), /* @__PURE__ */ React2.createElement("span", { style: { fontSize: 11, color: "var(--dc-text-muted)", whiteSpace: "nowrap" } }, "or continue with email"), /* @__PURE__ */ React2.createElement("div", { style: { flex: 1, height: 1, background: "var(--dc-border)" } })), !passkeyFirst && socialAuthMethods.includes("email") && (emailStep === "input" ? /* @__PURE__ */ React2.createElement("form", { onSubmit: handleEmailStart, style: { display: "flex", flexDirection: "column", gap: 8 } }, /* @__PURE__ */ React2.createElement(
|
|
5905
6024
|
"input",
|
|
5906
6025
|
{
|
|
@@ -6268,6 +6387,7 @@ function AddressRow({
|
|
|
6268
6387
|
function SignInView({
|
|
6269
6388
|
onGoogleSignIn,
|
|
6270
6389
|
onKingsChatSignIn,
|
|
6390
|
+
onXSignIn,
|
|
6271
6391
|
onEmailStart,
|
|
6272
6392
|
onEmailVerify,
|
|
6273
6393
|
onPhoneStart,
|
|
@@ -6282,6 +6402,7 @@ function SignInView({
|
|
|
6282
6402
|
}) {
|
|
6283
6403
|
const [googleLoading, setGoogleLoading] = useState2(false);
|
|
6284
6404
|
const [kingsChatLoading, setKingsChatLoading] = useState2(false);
|
|
6405
|
+
const [xLoading, setXLoading] = useState2(false);
|
|
6285
6406
|
const [email, setEmail] = useState2("");
|
|
6286
6407
|
const [code, setCode] = useState2("");
|
|
6287
6408
|
const [emailSent, setEmailSent] = useState2(false);
|
|
@@ -6332,6 +6453,17 @@ function SignInView({
|
|
|
6332
6453
|
setKingsChatLoading(false);
|
|
6333
6454
|
}
|
|
6334
6455
|
}
|
|
6456
|
+
async function handleX() {
|
|
6457
|
+
if (!onXSignIn) return;
|
|
6458
|
+
setError("");
|
|
6459
|
+
setXLoading(true);
|
|
6460
|
+
try {
|
|
6461
|
+
await onXSignIn();
|
|
6462
|
+
} catch (e) {
|
|
6463
|
+
setError(e.message);
|
|
6464
|
+
setXLoading(false);
|
|
6465
|
+
}
|
|
6466
|
+
}
|
|
6335
6467
|
async function handleEmailStart(e) {
|
|
6336
6468
|
e.preventDefault();
|
|
6337
6469
|
setError("");
|
|
@@ -6490,6 +6622,32 @@ function SignInView({
|
|
|
6490
6622
|
}
|
|
6491
6623
|
},
|
|
6492
6624
|
kingsChatLoading ? "Waiting for KingsChat\u2026" : "Continue with KingsChat"
|
|
6625
|
+
), !passkeyFirst && authMethods.includes("x") && onXSignIn && /* @__PURE__ */ React3.createElement(
|
|
6626
|
+
"button",
|
|
6627
|
+
{
|
|
6628
|
+
onClick: handleX,
|
|
6629
|
+
disabled: xLoading,
|
|
6630
|
+
style: {
|
|
6631
|
+
width: "100%",
|
|
6632
|
+
padding: "10px 0",
|
|
6633
|
+
marginBottom: 10,
|
|
6634
|
+
background: "var(--dc-surface)",
|
|
6635
|
+
color: "var(--dc-text)",
|
|
6636
|
+
border: "1px solid var(--dc-border)",
|
|
6637
|
+
borderRadius: 10,
|
|
6638
|
+
fontSize: 13,
|
|
6639
|
+
fontWeight: 700,
|
|
6640
|
+
cursor: xLoading ? "not-allowed" : "pointer",
|
|
6641
|
+
opacity: xLoading ? 0.7 : 1,
|
|
6642
|
+
fontFamily: "inherit",
|
|
6643
|
+
display: "flex",
|
|
6644
|
+
alignItems: "center",
|
|
6645
|
+
justifyContent: "center",
|
|
6646
|
+
gap: 8
|
|
6647
|
+
}
|
|
6648
|
+
},
|
|
6649
|
+
/* @__PURE__ */ React3.createElement(XLogo, null),
|
|
6650
|
+
xLoading ? "Redirecting\u2026" : "Continue with X"
|
|
6493
6651
|
), !passkeyFirst && authMethods.includes("email") && /* @__PURE__ */ React3.createElement(React3.Fragment, null, authMethods.includes("google") && /* @__PURE__ */ React3.createElement("div", { style: { textAlign: "center", color: "var(--dc-text-muted)", fontSize: 12, margin: "10px 0" } }, "\u2014 or \u2014"), !emailSent ? /* @__PURE__ */ React3.createElement("form", { onSubmit: handleEmailStart, style: { display: "flex", gap: 8 } }, /* @__PURE__ */ React3.createElement(
|
|
6494
6652
|
"input",
|
|
6495
6653
|
{
|
|
@@ -7152,7 +7310,7 @@ function DecaneKit({ config, children }) {
|
|
|
7152
7310
|
});
|
|
7153
7311
|
const params = new URLSearchParams(window.location.search);
|
|
7154
7312
|
if (params.has("decane_jwt") || params.has("decane_error")) {
|
|
7155
|
-
sdk.
|
|
7313
|
+
sdk.completeRedirectSignIn().then(applyResult).catch((e) => {
|
|
7156
7314
|
setSocialAuth((p) => p.phase ? { ...p, phase: null } : p);
|
|
7157
7315
|
console.error(e);
|
|
7158
7316
|
});
|
|
@@ -7193,6 +7351,11 @@ function DecaneKit({ config, children }) {
|
|
|
7193
7351
|
if (!sdk) throw new Error("Social sign-in not configured");
|
|
7194
7352
|
await sdk.connectWithGoogle();
|
|
7195
7353
|
}, []);
|
|
7354
|
+
const connectWithX = useCallback3(async () => {
|
|
7355
|
+
const sdk = socialRef.current;
|
|
7356
|
+
if (!sdk) throw new Error("Social sign-in not configured");
|
|
7357
|
+
await sdk.connectWithX();
|
|
7358
|
+
}, []);
|
|
7196
7359
|
const connectWithKingsChat = useCallback3(async () => {
|
|
7197
7360
|
const sdk = socialRef.current;
|
|
7198
7361
|
if (!sdk) throw new Error("Social sign-in not configured");
|
|
@@ -7413,6 +7576,7 @@ function DecaneKit({ config, children }) {
|
|
|
7413
7576
|
signInWithPasskey,
|
|
7414
7577
|
connectWithGoogle,
|
|
7415
7578
|
connectWithKingsChat,
|
|
7579
|
+
connectWithX,
|
|
7416
7580
|
connectWithEmail,
|
|
7417
7581
|
verifyEmailCode: verifyEmailCode2,
|
|
7418
7582
|
connectWithPhone,
|
|
@@ -7464,6 +7628,7 @@ function DecaneKit({ config, children }) {
|
|
|
7464
7628
|
socialAuthMethods: config?.social?.authMethods ?? ["google", "email"],
|
|
7465
7629
|
onGoogleSignIn: connectWithGoogle,
|
|
7466
7630
|
onKingsChatSignIn: connectWithKingsChat,
|
|
7631
|
+
onXSignIn: connectWithX,
|
|
7467
7632
|
onEmailStart: connectWithEmail,
|
|
7468
7633
|
onEmailVerify: verifyEmailCode2,
|
|
7469
7634
|
onPhoneStart: connectWithPhone,
|
|
@@ -7488,6 +7653,7 @@ function DecaneKit({ config, children }) {
|
|
|
7488
7653
|
onCustomAuthSignIn: customAuthConfig ? connectWithCustomAuth : void 0,
|
|
7489
7654
|
onGoogleSignIn: connectWithGoogle,
|
|
7490
7655
|
onKingsChatSignIn: connectWithKingsChat,
|
|
7656
|
+
onXSignIn: connectWithX,
|
|
7491
7657
|
onEmailStart: connectWithEmail,
|
|
7492
7658
|
onEmailVerify: verifyEmailCode2,
|
|
7493
7659
|
onPhoneStart: connectWithPhone,
|
|
@@ -7522,6 +7688,7 @@ function useSocialAuth() {
|
|
|
7522
7688
|
socialAuth,
|
|
7523
7689
|
connectWithGoogle,
|
|
7524
7690
|
connectWithKingsChat,
|
|
7691
|
+
connectWithX,
|
|
7525
7692
|
connectWithEmail,
|
|
7526
7693
|
verifyEmailCode: verifyEmailCode2,
|
|
7527
7694
|
connectWithPhone,
|
|
@@ -7535,6 +7702,7 @@ function useSocialAuth() {
|
|
|
7535
7702
|
} = useDecaneContext();
|
|
7536
7703
|
const [googleLoading, setGoogleLoading] = useState4(false);
|
|
7537
7704
|
const [kingschatLoading, setKingschatLoading] = useState4(false);
|
|
7705
|
+
const [xLoading, setXLoading] = useState4(false);
|
|
7538
7706
|
const [emailLoading, setEmailLoading] = useState4(false);
|
|
7539
7707
|
const [phoneLoading, setPhoneLoading] = useState4(false);
|
|
7540
7708
|
const [tokenLoading, setTokenLoading] = useState4(false);
|
|
@@ -7550,6 +7718,16 @@ function useSocialAuth() {
|
|
|
7550
7718
|
setGoogleLoading(false);
|
|
7551
7719
|
}
|
|
7552
7720
|
}, [connectWithGoogle]);
|
|
7721
|
+
const signInWithX = useCallback4(async () => {
|
|
7722
|
+
setXLoading(true);
|
|
7723
|
+
setError(null);
|
|
7724
|
+
try {
|
|
7725
|
+
await connectWithX();
|
|
7726
|
+
} catch (e) {
|
|
7727
|
+
setError(e.message);
|
|
7728
|
+
setXLoading(false);
|
|
7729
|
+
}
|
|
7730
|
+
}, [connectWithX]);
|
|
7553
7731
|
const signInWithKingsChat = useCallback4(async () => {
|
|
7554
7732
|
setKingschatLoading(true);
|
|
7555
7733
|
setError(null);
|
|
@@ -7687,6 +7865,7 @@ function useSocialAuth() {
|
|
|
7687
7865
|
needsReconnect: socialAuth.needsReconnect,
|
|
7688
7866
|
googleLoading,
|
|
7689
7867
|
kingschatLoading,
|
|
7868
|
+
xLoading,
|
|
7690
7869
|
emailLoading,
|
|
7691
7870
|
phoneLoading,
|
|
7692
7871
|
tokenLoading,
|
|
@@ -7696,6 +7875,7 @@ function useSocialAuth() {
|
|
|
7696
7875
|
clearError: () => setError(null),
|
|
7697
7876
|
signInWithGoogle,
|
|
7698
7877
|
signInWithKingsChat,
|
|
7878
|
+
signInWithX,
|
|
7699
7879
|
sendEmailCode,
|
|
7700
7880
|
confirmEmailCode,
|
|
7701
7881
|
sendPhoneCode,
|