@iamgame/wallet-sdk 0.1.1 → 0.1.3

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 CHANGED
@@ -80,6 +80,23 @@ var SolvenClient = class {
80
80
  this.opts.storage.set(session);
81
81
  return session;
82
82
  }
83
+ /** Email + OTP: send a one-time code to the address. */
84
+ async initiateEmail(email) {
85
+ return this.publicCall(
86
+ "POST",
87
+ "/auth/email/initiate",
88
+ { email }
89
+ );
90
+ }
91
+ /** Email + OTP: exchange the code for a session. */
92
+ async verifyEmail(email, code) {
93
+ const session = await this.publicCall("POST", "/auth/email/verify", {
94
+ email,
95
+ code
96
+ });
97
+ this.opts.storage.set(session);
98
+ return session;
99
+ }
83
100
  async refreshSession() {
84
101
  const current = this.opts.storage.get();
85
102
  if (!current) return null;
@@ -353,6 +370,20 @@ function useSolvenAuth() {
353
370
  const session2 = await client.verifyTelegram({ initData });
354
371
  setSession(session2);
355
372
  }, [client, setSession]);
373
+ const requestEmailOtp = react.useCallback(
374
+ async (email) => {
375
+ const { expiresAt } = await client.initiateEmail(email);
376
+ return { expiresAt };
377
+ },
378
+ [client]
379
+ );
380
+ const connectEmail = react.useCallback(
381
+ async (email, code) => {
382
+ const session2 = await client.verifyEmail(email, code);
383
+ setSession(session2);
384
+ },
385
+ [client, setSession]
386
+ );
356
387
  const logout = react.useCallback(async () => {
357
388
  await client.logout();
358
389
  setSession(null);
@@ -360,8 +391,11 @@ function useSolvenAuth() {
360
391
  return {
361
392
  user: session?.user ?? null,
362
393
  status,
394
+ accessToken: session?.accessToken ?? null,
363
395
  connectExternal,
364
396
  connectTelegram,
397
+ requestEmailOtp,
398
+ connectEmail,
365
399
  logout
366
400
  };
367
401
  }
@@ -553,9 +587,13 @@ var defaultTheme = {
553
587
  fontFamily: 'system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif'
554
588
  };
555
589
  function SolvenLoginContent(props) {
556
- const { connectExternal, connectTelegram, status, user } = useSolvenAuth();
590
+ const { connectExternal, connectTelegram, requestEmailOtp, connectEmail, status, user } = useSolvenAuth();
557
591
  const [busy, setBusy] = react.useState(null);
558
592
  const [error, setError] = react.useState(null);
593
+ const [email, setEmail] = react.useState("");
594
+ const [otp, setOtp] = react.useState("");
595
+ const [otpSent, setOtpSent] = react.useState(false);
596
+ const showEmail = props.showEmail ?? true;
559
597
  const theme = react.useMemo(
560
598
  () => ({ ...defaultTheme, ...props.theme ?? {} }),
561
599
  [props.theme]
@@ -622,6 +660,31 @@ function SolvenLoginContent(props) {
622
660
  setBusy(null);
623
661
  }
624
662
  };
663
+ const handleSendOtp = async () => {
664
+ setBusy("email");
665
+ setError(null);
666
+ try {
667
+ await requestEmailOtp(email.trim());
668
+ setOtpSent(true);
669
+ } catch (e) {
670
+ setError(e instanceof Error ? e.message : "Couldn't send the code");
671
+ } finally {
672
+ setBusy(null);
673
+ }
674
+ };
675
+ const handleVerifyOtp = async () => {
676
+ setBusy("email");
677
+ setError(null);
678
+ try {
679
+ await connectEmail(email.trim(), otp.trim());
680
+ props.onSignIn?.();
681
+ props.onCloseAfterSignIn?.();
682
+ } catch (e) {
683
+ setError(e instanceof Error ? e.message : "Couldn't verify the code");
684
+ } finally {
685
+ setBusy(null);
686
+ }
687
+ };
625
688
  const buttonBase = {
626
689
  width: "100%",
627
690
  padding: "0.75rem 0.875rem",
@@ -707,6 +770,135 @@ function SolvenLoginContent(props) {
707
770
  w.id
708
771
  );
709
772
  }) }),
773
+ !inTma && showEmail && /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { marginTop: "1rem" }, children: [
774
+ /* @__PURE__ */ jsxRuntime.jsxs(
775
+ "div",
776
+ {
777
+ style: {
778
+ display: "flex",
779
+ alignItems: "center",
780
+ gap: "0.625rem",
781
+ margin: "0.25rem 0 0.875rem",
782
+ color: theme.muted,
783
+ fontSize: "0.8125rem"
784
+ },
785
+ children: [
786
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: { flex: 1, height: 1, background: theme.border } }),
787
+ "or",
788
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: { flex: 1, height: 1, background: theme.border } })
789
+ ]
790
+ }
791
+ ),
792
+ !otpSent ? /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "0.5rem" }, children: [
793
+ /* @__PURE__ */ jsxRuntime.jsx(
794
+ "input",
795
+ {
796
+ type: "email",
797
+ inputMode: "email",
798
+ autoComplete: "email",
799
+ placeholder: "you@email.com",
800
+ value: email,
801
+ onChange: (e) => setEmail(e.target.value),
802
+ style: {
803
+ width: "100%",
804
+ padding: "0.75rem 0.875rem",
805
+ borderRadius: theme.radius,
806
+ border: `1px solid ${theme.border}`,
807
+ background: theme.surface,
808
+ color: theme.foreground,
809
+ fontSize: "0.9375rem",
810
+ outline: "none",
811
+ boxSizing: "border-box"
812
+ }
813
+ }
814
+ ),
815
+ /* @__PURE__ */ jsxRuntime.jsx(
816
+ "button",
817
+ {
818
+ type: "button",
819
+ onClick: handleSendOtp,
820
+ disabled: busy !== null || !email.includes("@"),
821
+ style: {
822
+ ...buttonBase,
823
+ justifyContent: "center",
824
+ background: theme.primary,
825
+ color: "#ffffff",
826
+ border: "none",
827
+ opacity: busy === "email" || !email.includes("@") ? 0.6 : 1
828
+ },
829
+ children: busy === "email" ? "Sending\u2026" : "Email me a code"
830
+ }
831
+ )
832
+ ] }) : /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "0.5rem" }, children: [
833
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { color: theme.muted, fontSize: "0.8125rem" }, children: [
834
+ "Enter the 6-digit code sent to ",
835
+ /* @__PURE__ */ jsxRuntime.jsx("strong", { children: email.trim() }),
836
+ "."
837
+ ] }),
838
+ /* @__PURE__ */ jsxRuntime.jsx(
839
+ "input",
840
+ {
841
+ type: "text",
842
+ inputMode: "numeric",
843
+ autoComplete: "one-time-code",
844
+ maxLength: 6,
845
+ placeholder: "123456",
846
+ value: otp,
847
+ onChange: (e) => setOtp(e.target.value.replace(/\D/g, "")),
848
+ style: {
849
+ width: "100%",
850
+ padding: "0.75rem 0.875rem",
851
+ borderRadius: theme.radius,
852
+ border: `1px solid ${theme.border}`,
853
+ background: theme.surface,
854
+ color: theme.foreground,
855
+ fontSize: "1.125rem",
856
+ letterSpacing: "0.3em",
857
+ textAlign: "center",
858
+ outline: "none",
859
+ boxSizing: "border-box"
860
+ }
861
+ }
862
+ ),
863
+ /* @__PURE__ */ jsxRuntime.jsx(
864
+ "button",
865
+ {
866
+ type: "button",
867
+ onClick: handleVerifyOtp,
868
+ disabled: busy !== null || otp.length !== 6,
869
+ style: {
870
+ ...buttonBase,
871
+ justifyContent: "center",
872
+ background: theme.primary,
873
+ color: "#ffffff",
874
+ border: "none",
875
+ opacity: busy === "email" || otp.length !== 6 ? 0.6 : 1
876
+ },
877
+ children: busy === "email" ? "Verifying\u2026" : "Verify & sign in"
878
+ }
879
+ ),
880
+ /* @__PURE__ */ jsxRuntime.jsx(
881
+ "button",
882
+ {
883
+ type: "button",
884
+ onClick: () => {
885
+ setOtpSent(false);
886
+ setOtp("");
887
+ setError(null);
888
+ },
889
+ style: {
890
+ background: "none",
891
+ border: "none",
892
+ color: theme.muted,
893
+ fontSize: "0.8125rem",
894
+ cursor: "pointer",
895
+ padding: "0.25rem"
896
+ },
897
+ children: "Use a different email"
898
+ }
899
+ )
900
+ ] })
901
+ ] }),
710
902
  error && /* @__PURE__ */ jsxRuntime.jsx(
711
903
  "div",
712
904
  {
package/dist/index.d.cts CHANGED
@@ -1,12 +1,15 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import React$1 from 'react';
3
3
 
4
- type AuthMethod = "siws" | "telegram";
4
+ type AuthMethod = "siws" | "telegram" | "email";
5
5
  interface IUserIdentity {
6
6
  id: string;
7
7
  type: AuthMethod;
8
- /** For SIWS: base58 Solana pubkey. For Telegram: numeric user id as string. */
8
+ /** For SIWS: base58 Solana pubkey. For Telegram: numeric user id as string. For email: the address. */
9
9
  externalId: string;
10
+ /** Provider-specific profile captured at login (e.g. Telegram { username, firstName }).
11
+ * Display/attribution only — null when none was captured. */
12
+ profile?: Record<string, unknown> | null;
10
13
  }
11
14
  interface IUserWallet {
12
15
  /** base58 Solana pubkey */
@@ -156,7 +159,7 @@ interface IWebhookSignatureHeader {
156
159
  signature: string;
157
160
  }
158
161
 
159
- type IAMGameErrorCode = "auth/invalid_signature" | "auth/challenge_expired" | "auth/challenge_already_redeemed" | "auth/invalid_init_data" | "auth/init_data_stale" | "auth/init_data_replayed" | "auth/missing_token" | "auth/invalid_token" | "auth/expired_token" | "wallet/not_found" | "wallet/insufficient_balance" | "wallet/export_blocked" | "wallet/already_exported" | "user/not_found" | "user/suspended" | "compliance/blocked" | "sign/invalid_transaction" | "sign/wallet_archived" | "sign/internal_failure" | "withdrawal/insufficient_balance" | "withdrawal/limit_exceeded" | "ledger/insufficient_balance" | "ledger/session_not_found" | "ledger/session_closed" | "ledger/bet_not_found" | "ledger/bet_rolled_back" | "ledger/currency_mismatch" | "ratelimit/exceeded" | "idempotency/key_in_use" | "validation/bad_request" | "server/internal";
162
+ type IAMGameErrorCode = "auth/invalid_signature" | "auth/challenge_expired" | "auth/challenge_already_redeemed" | "auth/invalid_init_data" | "auth/init_data_stale" | "auth/init_data_replayed" | "auth/missing_token" | "auth/invalid_token" | "auth/expired_token" | "auth/method_not_allowed" | "auth/invalid_otp" | "auth/otp_not_found" | "auth/otp_locked" | "wallet/not_found" | "wallet/insufficient_balance" | "wallet/export_blocked" | "wallet/already_exported" | "user/not_found" | "user/suspended" | "compliance/blocked" | "sign/invalid_transaction" | "sign/wallet_archived" | "sign/internal_failure" | "withdrawal/insufficient_balance" | "withdrawal/limit_exceeded" | "ledger/insufficient_balance" | "ledger/session_not_found" | "ledger/session_closed" | "ledger/bet_not_found" | "ledger/bet_rolled_back" | "ledger/currency_mismatch" | "ratelimit/exceeded" | "idempotency/key_in_use" | "validation/bad_request" | "server/internal";
160
163
  interface IIAMGameErrorEnvelope {
161
164
  code: IAMGameErrorCode;
162
165
  message: string;
@@ -194,6 +197,13 @@ declare class IAMGameClient {
194
197
  requestSiwsChallenge(publicKey: string): Promise<ISiwsChallenge>;
195
198
  verifySiws(req: ISiwsVerifyRequest): Promise<ISession>;
196
199
  verifyTelegram(req: ITelegramVerifyRequest): Promise<ISession>;
200
+ /** Email + OTP: send a one-time code to the address. */
201
+ initiateEmail(email: string): Promise<{
202
+ sent: boolean;
203
+ expiresAt: string;
204
+ }>;
205
+ /** Email + OTP: exchange the code for a session. */
206
+ verifyEmail(email: string, code: string): Promise<ISession>;
197
207
  refreshSession(): Promise<ISession | null>;
198
208
  logout(): Promise<void>;
199
209
  getSession(): ISession | null;
@@ -251,6 +261,19 @@ interface IUseIAMGameAuth {
251
261
  connectExternal: (adapter: IExternalWalletAdapter) => Promise<void>;
252
262
  /** Run the Telegram TMA flow. Reads `window.Telegram.WebApp.initData` and posts to IAMGame. */
253
263
  connectTelegram: () => Promise<void>;
264
+ /**
265
+ * The current session's access token, or null when anonymous. Hand this to YOUR
266
+ * backend, which verifies it server-to-server (POST /v1/sessions/verify with your
267
+ * secret key) and mints its own app session. Never trust it as proof of identity
268
+ * on its own — it must be verified server-side.
269
+ */
270
+ accessToken: string | null;
271
+ /** Email + OTP step 1: email a one-time code to the address. */
272
+ requestEmailOtp: (email: string) => Promise<{
273
+ expiresAt: string;
274
+ }>;
275
+ /** Email + OTP step 2: exchange the code for a session. */
276
+ connectEmail: (email: string, code: string) => Promise<void>;
254
277
  logout: () => Promise<void>;
255
278
  }
256
279
  declare function useIAMGameAuth(): IUseIAMGameAuth;
@@ -307,6 +330,12 @@ interface CommonProps {
307
330
  * no clicks. Defaults to true.
308
331
  */
309
332
  autoTelegram?: boolean;
333
+ /**
334
+ * Show the email + one-time-code login option (web / non-TMA). Defaults to true.
335
+ * The app must also enable `email` in its allowed auth methods, or the send-code
336
+ * call is rejected.
337
+ */
338
+ showEmail?: boolean;
310
339
  }
311
340
  type IAMGameLoginProps = CommonProps;
312
341
  interface IAMGameLoginModalProps extends CommonProps {
package/dist/index.d.ts CHANGED
@@ -1,12 +1,15 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import React$1 from 'react';
3
3
 
4
- type AuthMethod = "siws" | "telegram";
4
+ type AuthMethod = "siws" | "telegram" | "email";
5
5
  interface IUserIdentity {
6
6
  id: string;
7
7
  type: AuthMethod;
8
- /** For SIWS: base58 Solana pubkey. For Telegram: numeric user id as string. */
8
+ /** For SIWS: base58 Solana pubkey. For Telegram: numeric user id as string. For email: the address. */
9
9
  externalId: string;
10
+ /** Provider-specific profile captured at login (e.g. Telegram { username, firstName }).
11
+ * Display/attribution only — null when none was captured. */
12
+ profile?: Record<string, unknown> | null;
10
13
  }
11
14
  interface IUserWallet {
12
15
  /** base58 Solana pubkey */
@@ -156,7 +159,7 @@ interface IWebhookSignatureHeader {
156
159
  signature: string;
157
160
  }
158
161
 
159
- type IAMGameErrorCode = "auth/invalid_signature" | "auth/challenge_expired" | "auth/challenge_already_redeemed" | "auth/invalid_init_data" | "auth/init_data_stale" | "auth/init_data_replayed" | "auth/missing_token" | "auth/invalid_token" | "auth/expired_token" | "wallet/not_found" | "wallet/insufficient_balance" | "wallet/export_blocked" | "wallet/already_exported" | "user/not_found" | "user/suspended" | "compliance/blocked" | "sign/invalid_transaction" | "sign/wallet_archived" | "sign/internal_failure" | "withdrawal/insufficient_balance" | "withdrawal/limit_exceeded" | "ledger/insufficient_balance" | "ledger/session_not_found" | "ledger/session_closed" | "ledger/bet_not_found" | "ledger/bet_rolled_back" | "ledger/currency_mismatch" | "ratelimit/exceeded" | "idempotency/key_in_use" | "validation/bad_request" | "server/internal";
162
+ type IAMGameErrorCode = "auth/invalid_signature" | "auth/challenge_expired" | "auth/challenge_already_redeemed" | "auth/invalid_init_data" | "auth/init_data_stale" | "auth/init_data_replayed" | "auth/missing_token" | "auth/invalid_token" | "auth/expired_token" | "auth/method_not_allowed" | "auth/invalid_otp" | "auth/otp_not_found" | "auth/otp_locked" | "wallet/not_found" | "wallet/insufficient_balance" | "wallet/export_blocked" | "wallet/already_exported" | "user/not_found" | "user/suspended" | "compliance/blocked" | "sign/invalid_transaction" | "sign/wallet_archived" | "sign/internal_failure" | "withdrawal/insufficient_balance" | "withdrawal/limit_exceeded" | "ledger/insufficient_balance" | "ledger/session_not_found" | "ledger/session_closed" | "ledger/bet_not_found" | "ledger/bet_rolled_back" | "ledger/currency_mismatch" | "ratelimit/exceeded" | "idempotency/key_in_use" | "validation/bad_request" | "server/internal";
160
163
  interface IIAMGameErrorEnvelope {
161
164
  code: IAMGameErrorCode;
162
165
  message: string;
@@ -194,6 +197,13 @@ declare class IAMGameClient {
194
197
  requestSiwsChallenge(publicKey: string): Promise<ISiwsChallenge>;
195
198
  verifySiws(req: ISiwsVerifyRequest): Promise<ISession>;
196
199
  verifyTelegram(req: ITelegramVerifyRequest): Promise<ISession>;
200
+ /** Email + OTP: send a one-time code to the address. */
201
+ initiateEmail(email: string): Promise<{
202
+ sent: boolean;
203
+ expiresAt: string;
204
+ }>;
205
+ /** Email + OTP: exchange the code for a session. */
206
+ verifyEmail(email: string, code: string): Promise<ISession>;
197
207
  refreshSession(): Promise<ISession | null>;
198
208
  logout(): Promise<void>;
199
209
  getSession(): ISession | null;
@@ -251,6 +261,19 @@ interface IUseIAMGameAuth {
251
261
  connectExternal: (adapter: IExternalWalletAdapter) => Promise<void>;
252
262
  /** Run the Telegram TMA flow. Reads `window.Telegram.WebApp.initData` and posts to IAMGame. */
253
263
  connectTelegram: () => Promise<void>;
264
+ /**
265
+ * The current session's access token, or null when anonymous. Hand this to YOUR
266
+ * backend, which verifies it server-to-server (POST /v1/sessions/verify with your
267
+ * secret key) and mints its own app session. Never trust it as proof of identity
268
+ * on its own — it must be verified server-side.
269
+ */
270
+ accessToken: string | null;
271
+ /** Email + OTP step 1: email a one-time code to the address. */
272
+ requestEmailOtp: (email: string) => Promise<{
273
+ expiresAt: string;
274
+ }>;
275
+ /** Email + OTP step 2: exchange the code for a session. */
276
+ connectEmail: (email: string, code: string) => Promise<void>;
254
277
  logout: () => Promise<void>;
255
278
  }
256
279
  declare function useIAMGameAuth(): IUseIAMGameAuth;
@@ -307,6 +330,12 @@ interface CommonProps {
307
330
  * no clicks. Defaults to true.
308
331
  */
309
332
  autoTelegram?: boolean;
333
+ /**
334
+ * Show the email + one-time-code login option (web / non-TMA). Defaults to true.
335
+ * The app must also enable `email` in its allowed auth methods, or the send-code
336
+ * call is rejected.
337
+ */
338
+ showEmail?: boolean;
310
339
  }
311
340
  type IAMGameLoginProps = CommonProps;
312
341
  interface IAMGameLoginModalProps extends CommonProps {
package/dist/index.js CHANGED
@@ -78,6 +78,23 @@ var SolvenClient = class {
78
78
  this.opts.storage.set(session);
79
79
  return session;
80
80
  }
81
+ /** Email + OTP: send a one-time code to the address. */
82
+ async initiateEmail(email) {
83
+ return this.publicCall(
84
+ "POST",
85
+ "/auth/email/initiate",
86
+ { email }
87
+ );
88
+ }
89
+ /** Email + OTP: exchange the code for a session. */
90
+ async verifyEmail(email, code) {
91
+ const session = await this.publicCall("POST", "/auth/email/verify", {
92
+ email,
93
+ code
94
+ });
95
+ this.opts.storage.set(session);
96
+ return session;
97
+ }
81
98
  async refreshSession() {
82
99
  const current = this.opts.storage.get();
83
100
  if (!current) return null;
@@ -351,6 +368,20 @@ function useSolvenAuth() {
351
368
  const session2 = await client.verifyTelegram({ initData });
352
369
  setSession(session2);
353
370
  }, [client, setSession]);
371
+ const requestEmailOtp = useCallback(
372
+ async (email) => {
373
+ const { expiresAt } = await client.initiateEmail(email);
374
+ return { expiresAt };
375
+ },
376
+ [client]
377
+ );
378
+ const connectEmail = useCallback(
379
+ async (email, code) => {
380
+ const session2 = await client.verifyEmail(email, code);
381
+ setSession(session2);
382
+ },
383
+ [client, setSession]
384
+ );
354
385
  const logout = useCallback(async () => {
355
386
  await client.logout();
356
387
  setSession(null);
@@ -358,8 +389,11 @@ function useSolvenAuth() {
358
389
  return {
359
390
  user: session?.user ?? null,
360
391
  status,
392
+ accessToken: session?.accessToken ?? null,
361
393
  connectExternal,
362
394
  connectTelegram,
395
+ requestEmailOtp,
396
+ connectEmail,
363
397
  logout
364
398
  };
365
399
  }
@@ -551,9 +585,13 @@ var defaultTheme = {
551
585
  fontFamily: 'system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif'
552
586
  };
553
587
  function SolvenLoginContent(props) {
554
- const { connectExternal, connectTelegram, status, user } = useSolvenAuth();
588
+ const { connectExternal, connectTelegram, requestEmailOtp, connectEmail, status, user } = useSolvenAuth();
555
589
  const [busy, setBusy] = useState(null);
556
590
  const [error, setError] = useState(null);
591
+ const [email, setEmail] = useState("");
592
+ const [otp, setOtp] = useState("");
593
+ const [otpSent, setOtpSent] = useState(false);
594
+ const showEmail = props.showEmail ?? true;
557
595
  const theme = useMemo(
558
596
  () => ({ ...defaultTheme, ...props.theme ?? {} }),
559
597
  [props.theme]
@@ -620,6 +658,31 @@ function SolvenLoginContent(props) {
620
658
  setBusy(null);
621
659
  }
622
660
  };
661
+ const handleSendOtp = async () => {
662
+ setBusy("email");
663
+ setError(null);
664
+ try {
665
+ await requestEmailOtp(email.trim());
666
+ setOtpSent(true);
667
+ } catch (e) {
668
+ setError(e instanceof Error ? e.message : "Couldn't send the code");
669
+ } finally {
670
+ setBusy(null);
671
+ }
672
+ };
673
+ const handleVerifyOtp = async () => {
674
+ setBusy("email");
675
+ setError(null);
676
+ try {
677
+ await connectEmail(email.trim(), otp.trim());
678
+ props.onSignIn?.();
679
+ props.onCloseAfterSignIn?.();
680
+ } catch (e) {
681
+ setError(e instanceof Error ? e.message : "Couldn't verify the code");
682
+ } finally {
683
+ setBusy(null);
684
+ }
685
+ };
623
686
  const buttonBase = {
624
687
  width: "100%",
625
688
  padding: "0.75rem 0.875rem",
@@ -705,6 +768,135 @@ function SolvenLoginContent(props) {
705
768
  w.id
706
769
  );
707
770
  }) }),
771
+ !inTma && showEmail && /* @__PURE__ */ jsxs("div", { style: { marginTop: "1rem" }, children: [
772
+ /* @__PURE__ */ jsxs(
773
+ "div",
774
+ {
775
+ style: {
776
+ display: "flex",
777
+ alignItems: "center",
778
+ gap: "0.625rem",
779
+ margin: "0.25rem 0 0.875rem",
780
+ color: theme.muted,
781
+ fontSize: "0.8125rem"
782
+ },
783
+ children: [
784
+ /* @__PURE__ */ jsx("span", { style: { flex: 1, height: 1, background: theme.border } }),
785
+ "or",
786
+ /* @__PURE__ */ jsx("span", { style: { flex: 1, height: 1, background: theme.border } })
787
+ ]
788
+ }
789
+ ),
790
+ !otpSent ? /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "0.5rem" }, children: [
791
+ /* @__PURE__ */ jsx(
792
+ "input",
793
+ {
794
+ type: "email",
795
+ inputMode: "email",
796
+ autoComplete: "email",
797
+ placeholder: "you@email.com",
798
+ value: email,
799
+ onChange: (e) => setEmail(e.target.value),
800
+ style: {
801
+ width: "100%",
802
+ padding: "0.75rem 0.875rem",
803
+ borderRadius: theme.radius,
804
+ border: `1px solid ${theme.border}`,
805
+ background: theme.surface,
806
+ color: theme.foreground,
807
+ fontSize: "0.9375rem",
808
+ outline: "none",
809
+ boxSizing: "border-box"
810
+ }
811
+ }
812
+ ),
813
+ /* @__PURE__ */ jsx(
814
+ "button",
815
+ {
816
+ type: "button",
817
+ onClick: handleSendOtp,
818
+ disabled: busy !== null || !email.includes("@"),
819
+ style: {
820
+ ...buttonBase,
821
+ justifyContent: "center",
822
+ background: theme.primary,
823
+ color: "#ffffff",
824
+ border: "none",
825
+ opacity: busy === "email" || !email.includes("@") ? 0.6 : 1
826
+ },
827
+ children: busy === "email" ? "Sending\u2026" : "Email me a code"
828
+ }
829
+ )
830
+ ] }) : /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "0.5rem" }, children: [
831
+ /* @__PURE__ */ jsxs("div", { style: { color: theme.muted, fontSize: "0.8125rem" }, children: [
832
+ "Enter the 6-digit code sent to ",
833
+ /* @__PURE__ */ jsx("strong", { children: email.trim() }),
834
+ "."
835
+ ] }),
836
+ /* @__PURE__ */ jsx(
837
+ "input",
838
+ {
839
+ type: "text",
840
+ inputMode: "numeric",
841
+ autoComplete: "one-time-code",
842
+ maxLength: 6,
843
+ placeholder: "123456",
844
+ value: otp,
845
+ onChange: (e) => setOtp(e.target.value.replace(/\D/g, "")),
846
+ style: {
847
+ width: "100%",
848
+ padding: "0.75rem 0.875rem",
849
+ borderRadius: theme.radius,
850
+ border: `1px solid ${theme.border}`,
851
+ background: theme.surface,
852
+ color: theme.foreground,
853
+ fontSize: "1.125rem",
854
+ letterSpacing: "0.3em",
855
+ textAlign: "center",
856
+ outline: "none",
857
+ boxSizing: "border-box"
858
+ }
859
+ }
860
+ ),
861
+ /* @__PURE__ */ jsx(
862
+ "button",
863
+ {
864
+ type: "button",
865
+ onClick: handleVerifyOtp,
866
+ disabled: busy !== null || otp.length !== 6,
867
+ style: {
868
+ ...buttonBase,
869
+ justifyContent: "center",
870
+ background: theme.primary,
871
+ color: "#ffffff",
872
+ border: "none",
873
+ opacity: busy === "email" || otp.length !== 6 ? 0.6 : 1
874
+ },
875
+ children: busy === "email" ? "Verifying\u2026" : "Verify & sign in"
876
+ }
877
+ ),
878
+ /* @__PURE__ */ jsx(
879
+ "button",
880
+ {
881
+ type: "button",
882
+ onClick: () => {
883
+ setOtpSent(false);
884
+ setOtp("");
885
+ setError(null);
886
+ },
887
+ style: {
888
+ background: "none",
889
+ border: "none",
890
+ color: theme.muted,
891
+ fontSize: "0.8125rem",
892
+ cursor: "pointer",
893
+ padding: "0.25rem"
894
+ },
895
+ children: "Use a different email"
896
+ }
897
+ )
898
+ ] })
899
+ ] }),
708
900
  error && /* @__PURE__ */ jsx(
709
901
  "div",
710
902
  {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@iamgame/wallet-sdk",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "description": "IAMGame Wallet browser SDK — Telegram & Solana wallet auth, balances, server-side signing, and key export. Drop-in React provider for game frontends.",
5
5
  "license": "MIT",
6
6
  "homepage": "https://wallet.iamgame.com",