decane-connect-kit 2.19.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.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
@@ -755,7 +780,7 @@ interface DecaneProvider {
755
780
  type ConnectMode = "all" | "social" | "wallets" | "evm" | "solana" | "tron" | "evm+social" | "solana+social" | "tron+social" | "evm+tron" | "evm+tron+social";
756
781
  interface SocialConfig {
757
782
  apiKey: string;
758
- authMethods?: ("google" | "email" | "phone" | "kingschat")[];
783
+ authMethods?: ("google" | "email" | "phone" | "kingschat" | "x")[];
759
784
  /**
760
785
  * Scopes requested from KingsChat. Defaults to `['send_chat_message']`, which
761
786
  * is what KingsChat's own SDK asks for and is enough to establish identity.
@@ -1159,9 +1184,10 @@ interface WalletSelectorProps {
1159
1184
  theme?: "light" | "dark" | "auto";
1160
1185
  networks?: "evm" | "solana" | "tron" | "bitcoin" | "all";
1161
1186
  mode?: ConnectMode;
1162
- socialAuthMethods?: ("google" | "email" | "phone" | "kingschat")[];
1187
+ socialAuthMethods?: ("google" | "email" | "phone" | "kingschat" | "x")[];
1163
1188
  onGoogleSignIn?: () => Promise<void>;
1164
1189
  onKingsChatSignIn?: () => Promise<void>;
1190
+ onXSignIn?: () => Promise<void>;
1165
1191
  onEmailStart?: (email: string) => Promise<{
1166
1192
  codeRequired: true;
1167
1193
  }>;
@@ -1179,7 +1205,7 @@ interface WalletSelectorProps {
1179
1205
  passkeyAddress?: string | null;
1180
1206
  onPasskeySignIn?: () => Promise<unknown>;
1181
1207
  }
1182
- 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;
1183
1209
 
1184
1210
  type Theme = "light" | "dark" | "auto";
1185
1211
  interface SocialAuthState {
@@ -1243,6 +1269,7 @@ interface SocialWalletModalProps {
1243
1269
  onDisconnect: () => Promise<void>;
1244
1270
  onGoogleSignIn: () => Promise<void>;
1245
1271
  onKingsChatSignIn?: () => Promise<void>;
1272
+ onXSignIn?: () => Promise<void>;
1246
1273
  onEmailStart: (email: string) => Promise<{
1247
1274
  codeRequired: true;
1248
1275
  }>;
@@ -1251,7 +1278,7 @@ interface SocialWalletModalProps {
1251
1278
  codeRequired: true;
1252
1279
  }>;
1253
1280
  onPhoneVerify?: (phone: string, code: string) => Promise<void>;
1254
- authMethods?: Array<"google" | "email" | "phone" | "kingschat">;
1281
+ authMethods?: Array<"google" | "email" | "phone" | "kingschat" | "x">;
1255
1282
  customAuthLabel?: string;
1256
1283
  onCustomAuthSignIn?: () => Promise<void>;
1257
1284
  canUsePasskey?: boolean;
@@ -1300,6 +1327,7 @@ declare function useSocialAuth(): {
1300
1327
  needsReconnect: boolean;
1301
1328
  googleLoading: boolean;
1302
1329
  kingschatLoading: boolean;
1330
+ xLoading: boolean;
1303
1331
  emailLoading: boolean;
1304
1332
  phoneLoading: boolean;
1305
1333
  tokenLoading: boolean;
@@ -1309,6 +1337,7 @@ declare function useSocialAuth(): {
1309
1337
  clearError: () => void;
1310
1338
  signInWithGoogle: () => Promise<void>;
1311
1339
  signInWithKingsChat: () => Promise<void>;
1340
+ signInWithX: () => Promise<void>;
1312
1341
  sendEmailCode: (email: string) => Promise<{
1313
1342
  codeRequired: true;
1314
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
@@ -755,7 +780,7 @@ interface DecaneProvider {
755
780
  type ConnectMode = "all" | "social" | "wallets" | "evm" | "solana" | "tron" | "evm+social" | "solana+social" | "tron+social" | "evm+tron" | "evm+tron+social";
756
781
  interface SocialConfig {
757
782
  apiKey: string;
758
- authMethods?: ("google" | "email" | "phone" | "kingschat")[];
783
+ authMethods?: ("google" | "email" | "phone" | "kingschat" | "x")[];
759
784
  /**
760
785
  * Scopes requested from KingsChat. Defaults to `['send_chat_message']`, which
761
786
  * is what KingsChat's own SDK asks for and is enough to establish identity.
@@ -1159,9 +1184,10 @@ interface WalletSelectorProps {
1159
1184
  theme?: "light" | "dark" | "auto";
1160
1185
  networks?: "evm" | "solana" | "tron" | "bitcoin" | "all";
1161
1186
  mode?: ConnectMode;
1162
- socialAuthMethods?: ("google" | "email" | "phone" | "kingschat")[];
1187
+ socialAuthMethods?: ("google" | "email" | "phone" | "kingschat" | "x")[];
1163
1188
  onGoogleSignIn?: () => Promise<void>;
1164
1189
  onKingsChatSignIn?: () => Promise<void>;
1190
+ onXSignIn?: () => Promise<void>;
1165
1191
  onEmailStart?: (email: string) => Promise<{
1166
1192
  codeRequired: true;
1167
1193
  }>;
@@ -1179,7 +1205,7 @@ interface WalletSelectorProps {
1179
1205
  passkeyAddress?: string | null;
1180
1206
  onPasskeySignIn?: () => Promise<unknown>;
1181
1207
  }
1182
- 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;
1183
1209
 
1184
1210
  type Theme = "light" | "dark" | "auto";
1185
1211
  interface SocialAuthState {
@@ -1243,6 +1269,7 @@ interface SocialWalletModalProps {
1243
1269
  onDisconnect: () => Promise<void>;
1244
1270
  onGoogleSignIn: () => Promise<void>;
1245
1271
  onKingsChatSignIn?: () => Promise<void>;
1272
+ onXSignIn?: () => Promise<void>;
1246
1273
  onEmailStart: (email: string) => Promise<{
1247
1274
  codeRequired: true;
1248
1275
  }>;
@@ -1251,7 +1278,7 @@ interface SocialWalletModalProps {
1251
1278
  codeRequired: true;
1252
1279
  }>;
1253
1280
  onPhoneVerify?: (phone: string, code: string) => Promise<void>;
1254
- authMethods?: Array<"google" | "email" | "phone" | "kingschat">;
1281
+ authMethods?: Array<"google" | "email" | "phone" | "kingschat" | "x">;
1255
1282
  customAuthLabel?: string;
1256
1283
  onCustomAuthSignIn?: () => Promise<void>;
1257
1284
  canUsePasskey?: boolean;
@@ -1300,6 +1327,7 @@ declare function useSocialAuth(): {
1300
1327
  needsReconnect: boolean;
1301
1328
  googleLoading: boolean;
1302
1329
  kingschatLoading: boolean;
1330
+ xLoading: boolean;
1303
1331
  emailLoading: boolean;
1304
1332
  phoneLoading: boolean;
1305
1333
  tokenLoading: boolean;
@@ -1309,6 +1337,7 @@ declare function useSocialAuth(): {
1309
1337
  clearError: () => void;
1310
1338
  signInWithGoogle: () => Promise<void>;
1311
1339
  signInWithKingsChat: () => Promise<void>;
1340
+ signInWithX: () => Promise<void>;
1312
1341
  sendEmailCode: (email: string) => Promise<{
1313
1342
  codeRequired: true;
1314
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
@@ -4296,6 +4335,21 @@ async function createDecaneConnect(config) {
4296
4335
  ...stored.profile ? { profile: stored.profile } : {}
4297
4336
  };
4298
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
+ }
4299
4353
  async function handleAuthResult(result) {
4300
4354
  let addresses;
4301
4355
  if (!result.hasShare) {
@@ -4342,39 +4396,33 @@ async function createDecaneConnect(config) {
4342
4396
  throw new CallSequenceError(`Unknown auth method: ${method}`);
4343
4397
  },
4344
4398
  async connectWithGoogle() {
4345
- const params = new URLSearchParams(window.location.search);
4346
- const decaneJwt = params.get("decane_jwt");
4347
- const decaneError = params.get("decane_error");
4348
- if (decaneError) {
4349
- window.history.replaceState({}, "", window.location.pathname);
4350
- throw new CallSequenceError(`Google sign-in failed: ${decaneError}`);
4351
- }
4352
- if (decaneJwt) {
4353
- const name = params.get("decane_name");
4354
- const email = params.get("decane_email");
4355
- const picture = params.get("decane_picture");
4356
- const profile = {
4357
- ...name ? { name } : {},
4358
- ...email ? { email } : {},
4359
- ...picture ? { picture } : {}
4360
- };
4361
- const result = {
4362
- jwt: decaneJwt,
4363
- userId: params.get("decane_user_id") ?? "",
4364
- isNewUser: params.get("decane_is_new_user") === "true",
4365
- hasShare: params.get("decane_has_share") === "true",
4366
- // Omitted entirely when Google released nothing, so callers can test
4367
- // `result.profile` rather than an object that is always present but
4368
- // sometimes empty.
4369
- ...Object.keys(profile).length ? { profile } : {}
4370
- };
4371
- window.history.replaceState({}, "", window.location.pathname);
4372
- 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");
4373
4417
  }
4374
- const { url } = await api.getGoogleInitUrl();
4375
- window.location.href = url;
4376
- return new Promise(() => {
4377
- });
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());
4378
4426
  },
4379
4427
  async connectWithGoogleToken(idToken) {
4380
4428
  if (!idToken) throw new CallSequenceError("connectWithGoogleToken requires an ID token");
@@ -5198,6 +5246,20 @@ function ChainIconStack({ support, size = 16 }) {
5198
5246
  /* @__PURE__ */ React.createElement(ChainCircleIcon, { chain, size })
5199
5247
  )));
5200
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
+ }
5201
5263
 
5202
5264
  // src/ui/WalletSelector.tsx
5203
5265
  var FONT_URL = "https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@400;500;600;700;800&display=swap";
@@ -5339,6 +5401,7 @@ function WalletSelector({
5339
5401
  socialAuthMethods = ["google", "email"],
5340
5402
  onGoogleSignIn,
5341
5403
  onKingsChatSignIn,
5404
+ onXSignIn,
5342
5405
  onEmailStart,
5343
5406
  onEmailVerify,
5344
5407
  onPhoneStart,
@@ -5433,6 +5496,17 @@ function WalletSelector({
5433
5496
  setSocialLoad(false);
5434
5497
  }
5435
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
+ }
5436
5510
  async function handleCustomAuthClick() {
5437
5511
  if (!onCustomAuthSignIn) return;
5438
5512
  setSocialLoad(true);
@@ -5914,6 +5988,38 @@ function WalletSelector({
5914
5988
  },
5915
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)" })),
5916
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"
5917
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(
5918
6024
  "input",
5919
6025
  {
@@ -6281,6 +6387,7 @@ function AddressRow({
6281
6387
  function SignInView({
6282
6388
  onGoogleSignIn,
6283
6389
  onKingsChatSignIn,
6390
+ onXSignIn,
6284
6391
  onEmailStart,
6285
6392
  onEmailVerify,
6286
6393
  onPhoneStart,
@@ -6295,6 +6402,7 @@ function SignInView({
6295
6402
  }) {
6296
6403
  const [googleLoading, setGoogleLoading] = useState2(false);
6297
6404
  const [kingsChatLoading, setKingsChatLoading] = useState2(false);
6405
+ const [xLoading, setXLoading] = useState2(false);
6298
6406
  const [email, setEmail] = useState2("");
6299
6407
  const [code, setCode] = useState2("");
6300
6408
  const [emailSent, setEmailSent] = useState2(false);
@@ -6345,6 +6453,17 @@ function SignInView({
6345
6453
  setKingsChatLoading(false);
6346
6454
  }
6347
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
+ }
6348
6467
  async function handleEmailStart(e) {
6349
6468
  e.preventDefault();
6350
6469
  setError("");
@@ -6503,6 +6622,32 @@ function SignInView({
6503
6622
  }
6504
6623
  },
6505
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"
6506
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(
6507
6652
  "input",
6508
6653
  {
@@ -7165,7 +7310,7 @@ function DecaneKit({ config, children }) {
7165
7310
  });
7166
7311
  const params = new URLSearchParams(window.location.search);
7167
7312
  if (params.has("decane_jwt") || params.has("decane_error")) {
7168
- sdk.connectWithGoogle().then(applyResult).catch((e) => {
7313
+ sdk.completeRedirectSignIn().then(applyResult).catch((e) => {
7169
7314
  setSocialAuth((p) => p.phase ? { ...p, phase: null } : p);
7170
7315
  console.error(e);
7171
7316
  });
@@ -7206,6 +7351,11 @@ function DecaneKit({ config, children }) {
7206
7351
  if (!sdk) throw new Error("Social sign-in not configured");
7207
7352
  await sdk.connectWithGoogle();
7208
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
+ }, []);
7209
7359
  const connectWithKingsChat = useCallback3(async () => {
7210
7360
  const sdk = socialRef.current;
7211
7361
  if (!sdk) throw new Error("Social sign-in not configured");
@@ -7426,6 +7576,7 @@ function DecaneKit({ config, children }) {
7426
7576
  signInWithPasskey,
7427
7577
  connectWithGoogle,
7428
7578
  connectWithKingsChat,
7579
+ connectWithX,
7429
7580
  connectWithEmail,
7430
7581
  verifyEmailCode: verifyEmailCode2,
7431
7582
  connectWithPhone,
@@ -7477,6 +7628,7 @@ function DecaneKit({ config, children }) {
7477
7628
  socialAuthMethods: config?.social?.authMethods ?? ["google", "email"],
7478
7629
  onGoogleSignIn: connectWithGoogle,
7479
7630
  onKingsChatSignIn: connectWithKingsChat,
7631
+ onXSignIn: connectWithX,
7480
7632
  onEmailStart: connectWithEmail,
7481
7633
  onEmailVerify: verifyEmailCode2,
7482
7634
  onPhoneStart: connectWithPhone,
@@ -7501,6 +7653,7 @@ function DecaneKit({ config, children }) {
7501
7653
  onCustomAuthSignIn: customAuthConfig ? connectWithCustomAuth : void 0,
7502
7654
  onGoogleSignIn: connectWithGoogle,
7503
7655
  onKingsChatSignIn: connectWithKingsChat,
7656
+ onXSignIn: connectWithX,
7504
7657
  onEmailStart: connectWithEmail,
7505
7658
  onEmailVerify: verifyEmailCode2,
7506
7659
  onPhoneStart: connectWithPhone,
@@ -7535,6 +7688,7 @@ function useSocialAuth() {
7535
7688
  socialAuth,
7536
7689
  connectWithGoogle,
7537
7690
  connectWithKingsChat,
7691
+ connectWithX,
7538
7692
  connectWithEmail,
7539
7693
  verifyEmailCode: verifyEmailCode2,
7540
7694
  connectWithPhone,
@@ -7548,6 +7702,7 @@ function useSocialAuth() {
7548
7702
  } = useDecaneContext();
7549
7703
  const [googleLoading, setGoogleLoading] = useState4(false);
7550
7704
  const [kingschatLoading, setKingschatLoading] = useState4(false);
7705
+ const [xLoading, setXLoading] = useState4(false);
7551
7706
  const [emailLoading, setEmailLoading] = useState4(false);
7552
7707
  const [phoneLoading, setPhoneLoading] = useState4(false);
7553
7708
  const [tokenLoading, setTokenLoading] = useState4(false);
@@ -7563,6 +7718,16 @@ function useSocialAuth() {
7563
7718
  setGoogleLoading(false);
7564
7719
  }
7565
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]);
7566
7731
  const signInWithKingsChat = useCallback4(async () => {
7567
7732
  setKingschatLoading(true);
7568
7733
  setError(null);
@@ -7700,6 +7865,7 @@ function useSocialAuth() {
7700
7865
  needsReconnect: socialAuth.needsReconnect,
7701
7866
  googleLoading,
7702
7867
  kingschatLoading,
7868
+ xLoading,
7703
7869
  emailLoading,
7704
7870
  phoneLoading,
7705
7871
  tokenLoading,
@@ -7709,6 +7875,7 @@ function useSocialAuth() {
7709
7875
  clearError: () => setError(null),
7710
7876
  signInWithGoogle,
7711
7877
  signInWithKingsChat,
7878
+ signInWithX,
7712
7879
  sendEmailCode,
7713
7880
  confirmEmailCode,
7714
7881
  sendPhoneCode,