@pooflabs/web 0.0.86 → 0.0.88

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.
Files changed (65) hide show
  1. package/dist/auth/providers/solana-mobile-wallet-provider.d.ts +43 -0
  2. package/dist/{index-DK28JaJm.esm.js → index-BfsQaxom.esm.js} +3054 -301
  3. package/dist/index-BfsQaxom.esm.js.map +1 -0
  4. package/dist/{index-BQUfNEiY.esm.js → index-CJRFnq6O.esm.js} +476 -103
  5. package/dist/index-CJRFnq6O.esm.js.map +1 -0
  6. package/dist/{index-BHkED2YI.js → index-CTtGbOzo.js} +3054 -300
  7. package/dist/index-CTtGbOzo.js.map +1 -0
  8. package/dist/{index-D-Wbwevj.js → index-CvNX4W0l.js} +2 -2
  9. package/dist/index-CvNX4W0l.js.map +1 -0
  10. package/dist/{index-DUn32Hkh.js → index-DBYgqO9f.js} +3055 -301
  11. package/dist/index-DBYgqO9f.js.map +1 -0
  12. package/dist/index-DpiO7Cpe.esm.js +6 -0
  13. package/dist/index-DpiO7Cpe.esm.js.map +1 -0
  14. package/dist/{index-hEc5_KoM.js → index-Lm0k5Hwv.js} +477 -102
  15. package/dist/index-Lm0k5Hwv.js.map +1 -0
  16. package/dist/{index-Cfp30Jm_.esm.js → index-MF_M5V0O.esm.js} +3055 -300
  17. package/dist/index-MF_M5V0O.esm.js.map +1 -0
  18. package/dist/{index.browser-CbawPvh6.js → index.browser-BCr9Sc8V.js} +506 -1876
  19. package/dist/index.browser-BCr9Sc8V.js.map +1 -0
  20. package/dist/{index.browser-DD8pg_L2.js → index.browser-BxKN5pIs.js} +1223 -2565
  21. package/dist/index.browser-BxKN5pIs.js.map +1 -0
  22. package/dist/{index.browser-DQqKPfDA.esm.js → index.browser-CGZvkfTO.esm.js} +506 -1876
  23. package/dist/index.browser-CGZvkfTO.esm.js.map +1 -0
  24. package/dist/{index.browser-C9gHoUen.esm.js → index.browser-CMijwVwX.esm.js} +1223 -2565
  25. package/dist/index.browser-CMijwVwX.esm.js.map +1 -0
  26. package/dist/index.esm.js +1 -1
  27. package/dist/index.js +1 -1
  28. package/dist/{index.native-7hiNiSyC.js → index.native-FMbSnE7i.js} +44 -61
  29. package/dist/index.native-FMbSnE7i.js.map +1 -0
  30. package/dist/{index.native-BItnSD47.esm.js → index.native-GyqT8Dn5.esm.js} +43 -62
  31. package/dist/index.native-GyqT8Dn5.esm.js.map +1 -0
  32. package/dist/index.native.esm.js +1 -1
  33. package/dist/index.native.js +1 -1
  34. package/dist/{phantom-wallet-provider-CjvLq_2_.js → phantom-wallet-provider-4_DBhDbx.js} +4 -4
  35. package/dist/{phantom-wallet-provider-CjvLq_2_.js.map → phantom-wallet-provider-4_DBhDbx.js.map} +1 -1
  36. package/dist/{phantom-wallet-provider-DE3vit2Z.esm.js → phantom-wallet-provider-BFSfBW0w.esm.js} +4 -4
  37. package/dist/{phantom-wallet-provider-DE3vit2Z.esm.js.map → phantom-wallet-provider-BFSfBW0w.esm.js.map} +1 -1
  38. package/dist/{privy-wallet-provider-DFZaQPss.js → privy-wallet-provider-DRss_Hua.js} +3 -3
  39. package/dist/privy-wallet-provider-DRss_Hua.js.map +1 -0
  40. package/dist/{privy-wallet-provider-ip2pqo_U.esm.js → privy-wallet-provider-Dl0feuCb.esm.js} +3 -3
  41. package/dist/privy-wallet-provider-Dl0feuCb.esm.js.map +1 -0
  42. package/dist/{solana-mobile-wallet-provider-D7BbSpez.esm.js → solana-mobile-wallet-provider-C5mN8Dxh.esm.js} +437 -45
  43. package/dist/solana-mobile-wallet-provider-C5mN8Dxh.esm.js.map +1 -0
  44. package/dist/{solana-mobile-wallet-provider-DwER68Rz.js → solana-mobile-wallet-provider-CAZs-TkL.js} +437 -45
  45. package/dist/solana-mobile-wallet-provider-CAZs-TkL.js.map +1 -0
  46. package/package.json +1 -1
  47. package/dist/index-BHkED2YI.js.map +0 -1
  48. package/dist/index-BQUfNEiY.esm.js.map +0 -1
  49. package/dist/index-Cfp30Jm_.esm.js.map +0 -1
  50. package/dist/index-D-Wbwevj.js.map +0 -1
  51. package/dist/index-DK28JaJm.esm.js.map +0 -1
  52. package/dist/index-DKyWaxCB.esm.js +0 -6
  53. package/dist/index-DKyWaxCB.esm.js.map +0 -1
  54. package/dist/index-DUn32Hkh.js.map +0 -1
  55. package/dist/index-hEc5_KoM.js.map +0 -1
  56. package/dist/index.browser-C9gHoUen.esm.js.map +0 -1
  57. package/dist/index.browser-CbawPvh6.js.map +0 -1
  58. package/dist/index.browser-DD8pg_L2.js.map +0 -1
  59. package/dist/index.browser-DQqKPfDA.esm.js.map +0 -1
  60. package/dist/index.native-7hiNiSyC.js.map +0 -1
  61. package/dist/index.native-BItnSD47.esm.js.map +0 -1
  62. package/dist/privy-wallet-provider-DFZaQPss.js.map +0 -1
  63. package/dist/privy-wallet-provider-ip2pqo_U.esm.js.map +0 -1
  64. package/dist/solana-mobile-wallet-provider-D7BbSpez.esm.js.map +0 -1
  65. package/dist/solana-mobile-wallet-provider-DwER68Rz.js.map +0 -1
@@ -1,10 +1,18 @@
1
- import { b as bufferExports } from './index-DKyWaxCB.esm.js';
2
- import { g as getPlatform, k as setAuthLoading, W as WebSessionManager, s as setCurrentUser, l as genAuthNonce, m as genSolanaMessage, n as createSessionWithSignature, d as base58, e as confirmAndCheckTransaction, c as convertRemainingAccounts, b as buildSetDocumentsTransaction, a as SOLANA_DEVNET_RPC_URL, S as SOLANA_MAINNET_RPC_URL, h as SURFNET_RPC_URL } from './index.native-BItnSD47.esm.js';
1
+ import { b as bufferExports } from './index-DpiO7Cpe.esm.js';
2
+ import { g as getPlatform, W as WebSessionManager, m as genAuthNonce, n as genSolanaMessage, s as setCurrentUser, o as createSessionWithSignature, l as setAuthLoading, e as confirmAndCheckTransaction, d as base58, c as convertRemainingAccounts, b as buildSetDocumentsTransaction, a as SOLANA_DEVNET_RPC_URL, S as SOLANA_MAINNET_RPC_URL, h as SURFNET_RPC_URL } from './index.native-GyqT8Dn5.esm.js';
3
3
  import { PublicKey, Connection, VersionedTransaction, VersionedMessage, Transaction } from '@solana/web3.js';
4
4
  import * as anchor from '@coral-xyz/anchor';
5
5
  import 'axios';
6
6
  import 'react';
7
7
 
8
+ /**
9
+ * Storage key for persisting the MWA auth_token across cold starts.
10
+ * Holds JSON `{ token: string, address: string }`. Cleared by
11
+ * `logout()`. Hydrated by the constructor on native so cold-start
12
+ * doesn't force the user back into Phantom's approval flow when the
13
+ * underlying wallet authorization is still valid.
14
+ */
15
+ const MWA_AUTH_TOKEN_STORAGE_KEY = 'tarobase_mwa_auth_token';
8
16
  const ED25519_SIGNATURE_LENGTH = 64;
9
17
  const STORED_AUTH_METHOD_KEY = 'tarobase_last_auth_method';
10
18
  const MWA_AUTH_METHOD = 'mobile-wallet-adapter';
@@ -120,13 +128,13 @@ async function withMwaAssociationRetry(fn) {
120
128
  * next tap is a new activation (a real retry). A timer-based retry would
121
129
  * just hit the same Chrome block. Cap at 3 attempts before giving up.
122
130
  */
123
- async function awaitSignInGestureAndSign(theme, signFn) {
131
+ async function awaitSignInGestureAndSign(theme, signFn, noResultError = 'MWA returned no signature') {
124
132
  if (typeof document === 'undefined' || typeof window === 'undefined') {
125
133
  // SSR / non-browser: skip the gesture, just call (the activation
126
134
  // model doesn't apply outside the browser).
127
135
  const results = await signFn();
128
136
  if (!results || results.length === 0)
129
- throw new Error('MWA returned no signature');
137
+ throw new Error(noResultError);
130
138
  return results[0];
131
139
  }
132
140
  return new Promise((resolve, reject) => {
@@ -318,7 +326,7 @@ async function awaitSignInGestureAndSign(theme, signFn) {
318
326
  // launchAssociation(). Do not `await` before calling.
319
327
  signFn().then((results) => {
320
328
  if (!results || results.length === 0) {
321
- finishReject(new Error('MWA returned no signature'));
329
+ finishReject(new Error(noResultError));
322
330
  return;
323
331
  }
324
332
  finishResolve(results[0]);
@@ -346,6 +354,31 @@ async function awaitSignInGestureAndSign(theme, signFn) {
346
354
  });
347
355
  });
348
356
  }
357
+ /**
358
+ * Sign through the gesture modal ONLY when transient user activation has
359
+ * already decayed. Fast transactions still hold the activation from the
360
+ * user's tap, so the `solana-wallet:` navigation succeeds directly with no
361
+ * modal (preserves prior UX — no extra tap). Slow transactions — e.g. a swap
362
+ * whose server-side build exceeds Chrome's ~5s activation window — have lost
363
+ * it, so we fall back to awaitSignInGestureAndSign to mint a fresh activation
364
+ * via a "Sign in" tap. Returns the first result (same shape as the bare
365
+ * wallet-standard feature call and as awaitSignInGestureAndSign).
366
+ */
367
+ async function signWithFreshActivation(theme, signFn, noResultError = 'MWA returned no signature') {
368
+ var _a;
369
+ const activationLive = typeof navigator !== 'undefined' &&
370
+ ((_a = navigator.userActivation) === null || _a === void 0 ? void 0 : _a.isActive) === true;
371
+ if (activationLive) {
372
+ // Live gesture: invoke synchronously (no await before signFn) so the
373
+ // activation propagates to the protocol's location.assign navigation.
374
+ const results = await signFn();
375
+ if (!results || results.length === 0)
376
+ throw new Error(noResultError);
377
+ return results[0];
378
+ }
379
+ // Activation gone: surface the modal so the user's tap mints a fresh one.
380
+ return awaitSignInGestureAndSign(theme, signFn, noResultError);
381
+ }
349
382
  /**
350
383
  * Normalize a chain string to a wallet-standard Solana chain identifier.
351
384
  *
@@ -506,19 +539,66 @@ class SolanaMobileWalletProvider {
506
539
  constructor(networkUrl = null, config = {}) {
507
540
  /** LocalSolanaMobileWalletAdapterWallet, lazy-constructed in ensureWallet(). */
508
541
  this.wallet = null;
542
+ /**
543
+ * Cached MWA auth_token returned by `wallet.authorize()`. Reused by
544
+ * subsequent native transact() calls (signMessage / signTransaction)
545
+ * so the user doesn't get the wallet-pick popup on every operation.
546
+ * Persisted to platform storage and hydrated by the constructor on
547
+ * native; cleared by logout() and on `ERROR_REAUTHORIZE`.
548
+ */
549
+ this.nativeAuthToken = null;
550
+ /** Cached public key string for the connected MWA wallet (native). */
551
+ this.nativeAddress = null;
509
552
  this.networkUrl = networkUrl;
510
553
  this.config = config;
511
- if (typeof window === 'undefined') {
554
+ // Allow construction in true React Native environments: getPlatform().hasDOM
555
+ // is false there even though `typeof window === 'object'` (RN exposes a
556
+ // partial window global). Web/PWA paths still keep their original guard:
557
+ // they need real window+document for wallet-standard-mobile's deep-link
558
+ // mechanism, so missing-window in those builds remains a fail-fast.
559
+ const hasDOM = getPlatform().hasDOM;
560
+ if (!hasDOM && typeof window === 'undefined') {
561
+ throw new Error('SolanaMobileWalletProvider can only be instantiated in a browser or React Native environment');
562
+ }
563
+ if (hasDOM && typeof window === 'undefined') {
512
564
  throw new Error('SolanaMobileWalletProvider can only be instantiated in a browser environment');
513
565
  }
514
566
  if (SolanaMobileWalletProvider.instance) {
515
567
  return SolanaMobileWalletProvider.instance;
516
568
  }
569
+ // `appIdentity.uri` is what Phantom Android (and other MWA wallets)
570
+ // display in their approval modal. On web/PWA this is the page
571
+ // origin; on native there's no `window.location`, so fall back to
572
+ // a stable identifier the user can recognize. Apps can override
573
+ // entirely via `config.appIdentity.uri`.
574
+ const fallbackUri = hasDOM
575
+ ? getPlatform().getLocationOrigin()
576
+ : 'tarobase://app';
517
577
  this.appIdentity = config.appIdentity || {
518
578
  name: 'TaroBase App',
519
- uri: getPlatform().getLocationOrigin(),
579
+ uri: fallbackUri,
520
580
  };
521
581
  this.cluster = config.cluster || 'mainnet-beta';
582
+ // Hydrate cached MWA auth_token from storage on native so we can
583
+ // skip the wallet-pick popup after a cold-start when the underlying
584
+ // wallet authorization is still valid. Sync storage call per the
585
+ // PlatformAdapter contract; safe to swallow read errors (a fresh
586
+ // login() just re-authorizes).
587
+ if (!hasDOM) {
588
+ try {
589
+ const raw = getPlatform().storage.getItem(MWA_AUTH_TOKEN_STORAGE_KEY);
590
+ if (raw) {
591
+ const parsed = JSON.parse(raw);
592
+ if (typeof parsed.token === 'string' && typeof parsed.address === 'string') {
593
+ this.nativeAuthToken = parsed.token;
594
+ this.nativeAddress = parsed.address;
595
+ }
596
+ }
597
+ }
598
+ catch (_a) {
599
+ // Corrupt or unreadable cache — ignore. login() will re-auth.
600
+ }
601
+ }
522
602
  SolanaMobileWalletProvider.instance = this;
523
603
  }
524
604
  static getInstance(networkUrl, config) {
@@ -531,7 +611,7 @@ class SolanaMobileWalletProvider {
531
611
  async ensureWallet() {
532
612
  if (this.wallet)
533
613
  return this.wallet;
534
- const mod = await import('./index.browser-DQqKPfDA.esm.js');
614
+ const mod = await import('./index.browser-CGZvkfTO.esm.js');
535
615
  const chain = mapChainToWalletStandard(this.cluster);
536
616
  this.wallet = new mod.LocalSolanaMobileWalletAdapterWallet({
537
617
  appIdentity: this.appIdentity,
@@ -581,6 +661,134 @@ class SolanaMobileWalletProvider {
581
661
  getChain() {
582
662
  return mapChainToWalletStandard(this.cluster);
583
663
  }
664
+ /**
665
+ * Dynamically import and unwrap `transact` from the MWA web3js
666
+ * package. The package is externalized in rollup.config.js so this
667
+ * resolves to `lib/cjs/index.native.js` (TurboModule-backed) on
668
+ * Metro and `lib/esm/index.browser.js` (WebSocket) on webpack/vite
669
+ * per their respective platform conditions. Handles Metro's CJS-to-
670
+ * ESM interop variance (`mod.transact` vs `mod.default?.transact`).
671
+ */
672
+ async loadTransact() {
673
+ var _a;
674
+ const mod = await import('@solana-mobile/mobile-wallet-adapter-protocol-web3js');
675
+ const t = mod.transact || ((_a = mod.default) === null || _a === void 0 ? void 0 : _a.transact);
676
+ if (typeof t !== 'function') {
677
+ throw new Error('MWA transact API not available on this platform');
678
+ }
679
+ return t;
680
+ }
681
+ /**
682
+ * Cache and persist a fresh MWA auth_token + address. Called from
683
+ * `_loginNative` after a successful authorize. Storage failures are
684
+ * non-fatal (next cold-start re-auths).
685
+ */
686
+ persistNativeAuth(token, address) {
687
+ this.nativeAuthToken = token;
688
+ this.nativeAddress = address;
689
+ try {
690
+ getPlatform().storage.setItem(MWA_AUTH_TOKEN_STORAGE_KEY, JSON.stringify({ token, address }));
691
+ }
692
+ catch (_a) {
693
+ // non-fatal — token still in-memory for this process
694
+ }
695
+ }
696
+ /** Clear cached + persisted native auth state. */
697
+ clearNativeAuth() {
698
+ this.nativeAuthToken = null;
699
+ this.nativeAddress = null;
700
+ try {
701
+ getPlatform().storage.removeItem(MWA_AUTH_TOKEN_STORAGE_KEY);
702
+ }
703
+ catch (_a) {
704
+ // ignore
705
+ }
706
+ }
707
+ /**
708
+ * Classify an MWA-native error as a user cancellation. User-cancel
709
+ * shouldn't surface as a red console.error; callers can swallow or
710
+ * show a softer message. MWA spec codes plus the same substring
711
+ * checks the web path uses to catch wallet-specific phrasing.
712
+ */
713
+ isNativeUserCancel(err) {
714
+ var _a;
715
+ if (!err)
716
+ return false;
717
+ const code = err.code;
718
+ if (code === 'ERROR_NOT_SIGNED')
719
+ return true;
720
+ const msg = String((_a = err.message) !== null && _a !== void 0 ? _a : '').toLowerCase();
721
+ return /user (rejected|denied|cancelled|canceled|declined)/.test(msg);
722
+ }
723
+ /**
724
+ * Native MWA login via @solana-mobile/mobile-wallet-adapter-protocol-web3js.
725
+ * Used in true React Native (Expo) environments where wallet-standard-mobile's
726
+ * web universal-link path doesn't apply. Does authorize + signMessage in a
727
+ * single transact() roundtrip — intent-based MWA doesn't need the two-popup
728
+ * dance the web path uses (no Chrome activation-loss concern). Persists the
729
+ * resulting auth_token so cold-start can reauthorize without a fresh popup.
730
+ */
731
+ async _loginNative() {
732
+ const transact = await this.loadTransact();
733
+ const existingSession = await WebSessionManager.getSession();
734
+ const nonce = await genAuthNonce();
735
+ const result = await transact(async (wallet) => {
736
+ const auth = await wallet.authorize({
737
+ chain: this.getChain(),
738
+ identity: this.appIdentity,
739
+ });
740
+ if (!auth.accounts || auth.accounts.length === 0) {
741
+ throw new Error('MWA returned no accounts');
742
+ }
743
+ const account = auth.accounts[0];
744
+ // account.address is base64-encoded per MWA spec; convert to
745
+ // the base58 form Tarobase + the rest of the SDK use.
746
+ const base58Addr = new PublicKey(bufferExports.Buffer.from(account.address, 'base64')).toBase58();
747
+ // Reuse session if already valid for this address — skip the
748
+ // signMessages roundtrip entirely.
749
+ if (existingSession && existingSession.address === base58Addr) {
750
+ return {
751
+ base58Addr,
752
+ authToken: auth.auth_token,
753
+ signatureBase64: null,
754
+ };
755
+ }
756
+ const messageText = await genSolanaMessage(base58Addr, nonce);
757
+ const messageBytes = getPlatform().textEncode(messageText);
758
+ const signatures = await wallet.signMessages({
759
+ addresses: [account.address],
760
+ payloads: [messageBytes],
761
+ });
762
+ if (!signatures || signatures.length === 0) {
763
+ throw new Error('MWA returned no signature');
764
+ }
765
+ // Per spec, signMessages returns Uint8Array[] of signatures
766
+ // (one per payload), not message+signature concatenations.
767
+ const signatureBase64 = bufferExports.Buffer.from(signatures[0]).toString('base64');
768
+ return {
769
+ base58Addr,
770
+ authToken: auth.auth_token,
771
+ signatureBase64,
772
+ messageText,
773
+ };
774
+ });
775
+ this.persistNativeAuth(result.authToken, result.base58Addr);
776
+ // Existing valid session — short-circuit before re-creating server-side.
777
+ if (existingSession && existingSession.address === result.base58Addr) {
778
+ const user = { provider: this, address: result.base58Addr };
779
+ setCurrentUser(user);
780
+ return user;
781
+ }
782
+ // Create Tarobase session on the server.
783
+ if (!result.signatureBase64 || !result.messageText) {
784
+ throw new Error('MWA login completed without signature');
785
+ }
786
+ const createSessionResult = await createSessionWithSignature(result.base58Addr, result.messageText, result.signatureBase64);
787
+ await WebSessionManager.storeSession(result.base58Addr, createSessionResult.accessToken, createSessionResult.idToken, createSessionResult.refreshToken);
788
+ const user = { provider: this, address: result.base58Addr };
789
+ setCurrentUser(user);
790
+ return user;
791
+ }
584
792
  async login() {
585
793
  var _a, _b, _c, _d, _e;
586
794
  setAuthLoading(true);
@@ -591,6 +799,13 @@ class SolanaMobileWalletProvider {
591
799
  const prevAuthMethod = readAuthMethod();
592
800
  writeAuthMethod(MWA_AUTH_METHOD);
593
801
  try {
802
+ // True React Native: skip the wallet-standard-mobile path (which
803
+ // requires window.isSecureContext and a real DOM) and use the raw
804
+ // MWA protocol via Android intents.
805
+ if (!getPlatform().hasDOM) {
806
+ const user = await this._loginNative();
807
+ return user;
808
+ }
594
809
  const wallet = await this.ensureWallet();
595
810
  // Quick-check: wallet may already have authorization (e.g. from a
596
811
  // previous in-page login) and a matching Tarobase session — skip
@@ -692,6 +907,29 @@ class SolanaMobileWalletProvider {
692
907
  return null;
693
908
  }
694
909
  async logout() {
910
+ if (!getPlatform().hasDOM) {
911
+ // Native path: deauthorize the cached MWA auth_token if we have
912
+ // one (failures non-fatal — the wallet app may have been
913
+ // uninstalled or the token already revoked), then clear local
914
+ // and persisted state.
915
+ const token = this.nativeAuthToken;
916
+ if (token) {
917
+ try {
918
+ const transact = await this.loadTransact();
919
+ await transact(async (wallet) => {
920
+ await wallet.deauthorize({ auth_token: token });
921
+ });
922
+ }
923
+ catch (error) {
924
+ console.warn('[SolanaMobileWallet] Native deauthorize error:', error);
925
+ }
926
+ }
927
+ this.clearNativeAuth();
928
+ WebSessionManager.clearSession();
929
+ writeAuthMethod(null);
930
+ setCurrentUser(null);
931
+ return;
932
+ }
695
933
  try {
696
934
  const wallet = await this.ensureWallet();
697
935
  const disconnectFeat = getDisconnectFeature(wallet);
@@ -711,7 +949,42 @@ class SolanaMobileWalletProvider {
711
949
  setCurrentUser(null);
712
950
  }
713
951
  async signMessage(message) {
714
- var _a, _b;
952
+ var _a, _b, _c;
953
+ // Native: reauthorize with cached auth_token, then signMessages inside
954
+ // the same transact() session. No wallet-pick popup if the auth_token
955
+ // is still valid for the user's wallet.
956
+ if (!getPlatform().hasDOM) {
957
+ if (!this.nativeAuthToken || !this.nativeAddress) {
958
+ throw new Error('Wallet not connected. Call login() first.');
959
+ }
960
+ const transact = await this.loadTransact();
961
+ const messageBytes = getPlatform().textEncode(message);
962
+ const addressBase64 = new PublicKey(this.nativeAddress).toBuffer().toString('base64');
963
+ const authToken = this.nativeAuthToken;
964
+ try {
965
+ const signature = await transact(async (wallet) => {
966
+ await wallet.reauthorize({ auth_token: authToken, identity: this.appIdentity });
967
+ const sigs = await wallet.signMessages({
968
+ addresses: [addressBase64],
969
+ payloads: [messageBytes],
970
+ });
971
+ if (!sigs || sigs.length === 0)
972
+ throw new Error('MWA returned no signature');
973
+ return sigs[0];
974
+ });
975
+ return bufferExports.Buffer.from(signature).toString('base64');
976
+ }
977
+ catch (error) {
978
+ if (this.isNativeUserCancel(error)) {
979
+ throw new Error('User declined to sign');
980
+ }
981
+ if ((error === null || error === void 0 ? void 0 : error.code) === 'ERROR_AUTHORIZATION_FAILED' || (error === null || error === void 0 ? void 0 : error.code) === 'ERROR_REAUTHORIZE') {
982
+ await this.logout();
983
+ throw new Error('Wallet connection lost. Please reconnect.');
984
+ }
985
+ throw new Error(`Failed to sign message: ${(_a = error === null || error === void 0 ? void 0 : error.message) !== null && _a !== void 0 ? _a : error}`);
986
+ }
987
+ }
715
988
  const account = await this.ensureAuthorized();
716
989
  const wallet = await this.ensureWallet();
717
990
  try {
@@ -725,7 +998,7 @@ class SolanaMobileWalletProvider {
725
998
  return bufferExports.Buffer.from(sigBytes).toString('base64');
726
999
  }
727
1000
  catch (error) {
728
- if (((_a = error === null || error === void 0 ? void 0 : error.message) === null || _a === void 0 ? void 0 : _a.includes('not connected')) || ((_b = error === null || error === void 0 ? void 0 : error.message) === null || _b === void 0 ? void 0 : _b.includes('not authorized')) ||
1001
+ if (((_b = error === null || error === void 0 ? void 0 : error.message) === null || _b === void 0 ? void 0 : _b.includes('not connected')) || ((_c = error === null || error === void 0 ? void 0 : error.message) === null || _c === void 0 ? void 0 : _c.includes('not authorized')) ||
729
1002
  (error === null || error === void 0 ? void 0 : error.code) === 'ERROR_AUTHORIZATION_FAILED') {
730
1003
  await this.logout();
731
1004
  throw new Error('Wallet connection lost. Please reconnect.');
@@ -734,7 +1007,58 @@ class SolanaMobileWalletProvider {
734
1007
  }
735
1008
  }
736
1009
  async signTransaction(transaction) {
737
- var _a, _b;
1010
+ var _a, _b, _c;
1011
+ // Native: fill blockhash/feePayer if missing, then signTransactions
1012
+ // inside a transact() session keyed by the cached auth_token.
1013
+ if (!getPlatform().hasDOM) {
1014
+ if (!this.nativeAuthToken || !this.nativeAddress) {
1015
+ throw new Error('Wallet not connected. Call login() first.');
1016
+ }
1017
+ const connectedPubkey = new PublicKey(this.nativeAddress);
1018
+ const isLegacyTransaction = 'recentBlockhash' in transaction && !('message' in transaction && 'staticAccountKeys' in transaction.message);
1019
+ if (isLegacyTransaction) {
1020
+ const legacyTx = transaction;
1021
+ if (!legacyTx.recentBlockhash) {
1022
+ const conn = new Connection(this.getRpcUrl(), 'confirmed');
1023
+ const { blockhash, lastValidBlockHeight } = await conn.getLatestBlockhash('confirmed');
1024
+ legacyTx.recentBlockhash = blockhash;
1025
+ legacyTx.lastValidBlockHeight = lastValidBlockHeight;
1026
+ }
1027
+ if (!legacyTx.feePayer) {
1028
+ legacyTx.feePayer = connectedPubkey;
1029
+ }
1030
+ }
1031
+ else {
1032
+ const versionedTx = transaction;
1033
+ if (!versionedTx.message.recentBlockhash) {
1034
+ const conn = new Connection(this.getRpcUrl(), 'confirmed');
1035
+ const { blockhash } = await conn.getLatestBlockhash('confirmed');
1036
+ versionedTx.message.recentBlockhash = blockhash;
1037
+ }
1038
+ }
1039
+ const transact = await this.loadTransact();
1040
+ const authToken = this.nativeAuthToken;
1041
+ try {
1042
+ const signed = await transact(async (wallet) => {
1043
+ await wallet.reauthorize({ auth_token: authToken, identity: this.appIdentity });
1044
+ const results = await wallet.signTransactions({ transactions: [transaction] });
1045
+ if (!results || results.length === 0)
1046
+ throw new Error('MWA returned no signed transaction');
1047
+ return results[0];
1048
+ });
1049
+ return signed;
1050
+ }
1051
+ catch (error) {
1052
+ if (this.isNativeUserCancel(error)) {
1053
+ throw new Error('User declined to sign');
1054
+ }
1055
+ if ((error === null || error === void 0 ? void 0 : error.code) === 'ERROR_AUTHORIZATION_FAILED' || (error === null || error === void 0 ? void 0 : error.code) === 'ERROR_REAUTHORIZE') {
1056
+ await this.logout();
1057
+ throw new Error('Wallet connection lost. Please reconnect.');
1058
+ }
1059
+ throw new Error(`Failed to sign transaction: ${(_a = error === null || error === void 0 ? void 0 : error.message) !== null && _a !== void 0 ? _a : error}`);
1060
+ }
1061
+ }
738
1062
  const account = await this.ensureAuthorized();
739
1063
  const connectedPubkey = new PublicKey(account.publicKey);
740
1064
  const wallet = await this.ensureWallet();
@@ -765,15 +1089,14 @@ class SolanaMobileWalletProvider {
765
1089
  try {
766
1090
  const signTxFeat = getSignTransactionFeature(wallet);
767
1091
  const wireBytes = txToWireBytes(transaction);
768
- const results = await signTxFeat.signTransaction({ account, transaction: wireBytes, chain });
769
- if (!results || results.length === 0) {
770
- throw new Error('MWA returned no signed transaction');
771
- }
772
- const { signedTransaction: signedBytes } = results[0];
1092
+ // signTransaction navigates to `solana-wallet:`; only show the
1093
+ // gesture modal if the tap activation has decayed (see runTransaction).
1094
+ const signResult = await signWithFreshActivation(this.config.theme, () => signTxFeat.signTransaction({ account, transaction: wireBytes, chain }), 'MWA returned no signed transaction');
1095
+ const { signedTransaction: signedBytes } = signResult;
773
1096
  return txFromWireBytes(new Uint8Array(signedBytes));
774
1097
  }
775
1098
  catch (error) {
776
- if (((_a = error === null || error === void 0 ? void 0 : error.message) === null || _a === void 0 ? void 0 : _a.includes('not connected')) || ((_b = error === null || error === void 0 ? void 0 : error.message) === null || _b === void 0 ? void 0 : _b.includes('not authorized')) ||
1099
+ if (((_b = error === null || error === void 0 ? void 0 : error.message) === null || _b === void 0 ? void 0 : _b.includes('not connected')) || ((_c = error === null || error === void 0 ? void 0 : error.message) === null || _c === void 0 ? void 0 : _c.includes('not authorized')) ||
777
1100
  (error === null || error === void 0 ? void 0 : error.code) === 'ERROR_AUTHORIZATION_FAILED') {
778
1101
  await this.logout();
779
1102
  throw new Error('Wallet connection lost. Please reconnect.');
@@ -782,7 +1105,70 @@ class SolanaMobileWalletProvider {
782
1105
  }
783
1106
  }
784
1107
  async signAndSubmitTransaction(transaction, feePayer) {
785
- var _a, _b, _c, _d, _e, _f;
1108
+ var _a, _b, _c, _d, _e, _f, _g;
1109
+ // Native: signAndSendTransactions inside a transact() session.
1110
+ // The wallet submits to its own RPC; we then await confirmation on
1111
+ // ours. Surfnet (custom RPC) needs manual submission because the
1112
+ // wallet won't route there — we fall back to sign-only + manual send.
1113
+ if (!getPlatform().hasDOM) {
1114
+ if (!this.nativeAuthToken || !this.nativeAddress) {
1115
+ throw new Error('Wallet not connected. Call login() first.');
1116
+ }
1117
+ const connectedPubkey = new PublicKey(this.nativeAddress);
1118
+ const rpcUrl = this.getRpcUrl();
1119
+ const connection = new Connection(rpcUrl, 'confirmed');
1120
+ const isSurfnet = rpcUrl === SURFNET_RPC_URL;
1121
+ const { blockhash, lastValidBlockHeight } = await connection.getLatestBlockhash('confirmed');
1122
+ const isLegacyTransaction = 'recentBlockhash' in transaction && !('message' in transaction && 'staticAccountKeys' in transaction.message);
1123
+ if (isLegacyTransaction) {
1124
+ const legacyTx = transaction;
1125
+ legacyTx.recentBlockhash = blockhash;
1126
+ legacyTx.lastValidBlockHeight = lastValidBlockHeight;
1127
+ if (!legacyTx.feePayer)
1128
+ legacyTx.feePayer = feePayer !== null && feePayer !== void 0 ? feePayer : connectedPubkey;
1129
+ }
1130
+ else {
1131
+ const versionedTx = transaction;
1132
+ versionedTx.message.recentBlockhash = blockhash;
1133
+ }
1134
+ const transact = await this.loadTransact();
1135
+ const authToken = this.nativeAuthToken;
1136
+ try {
1137
+ if (isSurfnet) {
1138
+ // Surfnet: sign only, submit manually to Surfnet RPC
1139
+ // (the wallet would route signAndSend to its own RPC).
1140
+ const signed = await transact(async (wallet) => {
1141
+ await wallet.reauthorize({ auth_token: authToken, identity: this.appIdentity });
1142
+ const results = await wallet.signTransactions({ transactions: [transaction] });
1143
+ if (!results || results.length === 0)
1144
+ throw new Error('MWA returned no signed transaction');
1145
+ return results[0];
1146
+ });
1147
+ const sig = await connection.sendRawTransaction(signed.serialize(), { preflightCommitment: 'confirmed' });
1148
+ await confirmAndCheckTransaction(connection, sig);
1149
+ return sig;
1150
+ }
1151
+ const sig = await transact(async (wallet) => {
1152
+ await wallet.reauthorize({ auth_token: authToken, identity: this.appIdentity });
1153
+ const results = await wallet.signAndSendTransactions({ transactions: [transaction] });
1154
+ if (!results || results.length === 0)
1155
+ throw new Error('MWA returned no signature');
1156
+ return results[0];
1157
+ });
1158
+ await confirmAndCheckTransaction(connection, sig);
1159
+ return sig;
1160
+ }
1161
+ catch (error) {
1162
+ if (this.isNativeUserCancel(error)) {
1163
+ throw new Error('User declined to sign');
1164
+ }
1165
+ if ((error === null || error === void 0 ? void 0 : error.code) === 'ERROR_AUTHORIZATION_FAILED' || (error === null || error === void 0 ? void 0 : error.code) === 'ERROR_REAUTHORIZE') {
1166
+ await this.logout();
1167
+ throw new Error('Wallet connection lost. Please reconnect.');
1168
+ }
1169
+ throw new Error(`Failed to sign+submit transaction: ${(_a = error === null || error === void 0 ? void 0 : error.message) !== null && _a !== void 0 ? _a : error}`);
1170
+ }
1171
+ }
786
1172
  const account = await this.ensureAuthorized();
787
1173
  const connectedPubkey = new PublicKey(account.publicKey);
788
1174
  const wallet = await this.ensureWallet();
@@ -812,11 +1198,9 @@ class SolanaMobileWalletProvider {
812
1198
  // because the wallet would submit to its own RPC.
813
1199
  const signTxFeat = getSignTransactionFeature(wallet);
814
1200
  const wireBytes = txToWireBytes(transaction);
815
- const results = await signTxFeat.signTransaction({ account, transaction: wireBytes, chain });
816
- if (!results || results.length === 0) {
817
- throw new Error('MWA returned no signed transaction');
818
- }
819
- const { signedTransaction: signedBytes } = results[0];
1201
+ // Gesture modal only if activation decayed (see runTransaction).
1202
+ const signResult = await signWithFreshActivation(this.config.theme, () => signTxFeat.signTransaction({ account, transaction: wireBytes, chain }), 'MWA returned no signed transaction');
1203
+ const { signedTransaction: signedBytes } = signResult;
820
1204
  const signedTx = txFromWireBytes(new Uint8Array(signedBytes));
821
1205
  const signature = await connection.sendRawTransaction(signedTx.serialize(), {
822
1206
  preflightCommitment: 'confirmed',
@@ -832,33 +1216,31 @@ class SolanaMobileWalletProvider {
832
1216
  return signature;
833
1217
  }
834
1218
  // Non-Surfnet: wallet signs and submits to its own RPC.
1219
+ // Gesture modal only if activation decayed (see runTransaction).
835
1220
  const signSendFeat = getSignAndSendTransactionFeature(wallet);
836
1221
  const wireBytes = txToWireBytes(transaction);
837
- const results = await signSendFeat.signAndSendTransaction({
1222
+ const sendResult = await signWithFreshActivation(this.config.theme, () => signSendFeat.signAndSendTransaction({
838
1223
  account,
839
1224
  transaction: wireBytes,
840
1225
  chain,
841
1226
  options: { commitment: 'confirmed' },
842
- });
843
- if (!results || results.length === 0) {
844
- throw new Error('MWA returned no signature');
845
- }
846
- const { signature: sigBytes } = results[0];
1227
+ }));
1228
+ const { signature: sigBytes } = sendResult;
847
1229
  const signature = base58.encode(sigBytes);
848
1230
  await confirmAndCheckTransaction(connection, signature);
849
1231
  return signature;
850
1232
  }
851
1233
  catch (error) {
852
- if (((_a = error === null || error === void 0 ? void 0 : error.message) === null || _a === void 0 ? void 0 : _a.includes('not connected')) || ((_b = error === null || error === void 0 ? void 0 : error.message) === null || _b === void 0 ? void 0 : _b.includes('not authorized')) ||
1234
+ if (((_b = error === null || error === void 0 ? void 0 : error.message) === null || _b === void 0 ? void 0 : _b.includes('not connected')) || ((_c = error === null || error === void 0 ? void 0 : error.message) === null || _c === void 0 ? void 0 : _c.includes('not authorized')) ||
853
1235
  (error === null || error === void 0 ? void 0 : error.code) === 'ERROR_AUTHORIZATION_FAILED') {
854
1236
  await this.logout();
855
1237
  throw new Error('Wallet connection lost. Please reconnect.');
856
1238
  }
857
1239
  const isUserRejection = (error === null || error === void 0 ? void 0 : error.code) === 4001 ||
858
- ((_c = error === null || error === void 0 ? void 0 : error.message) === null || _c === void 0 ? void 0 : _c.toLowerCase().includes('user rejected')) ||
859
- ((_d = error === null || error === void 0 ? void 0 : error.message) === null || _d === void 0 ? void 0 : _d.toLowerCase().includes('user denied')) ||
860
- ((_e = error === null || error === void 0 ? void 0 : error.message) === null || _e === void 0 ? void 0 : _e.toLowerCase().includes('user cancelled')) ||
861
- ((_f = error === null || error === void 0 ? void 0 : error.message) === null || _f === void 0 ? void 0 : _f.toLowerCase().includes('user canceled'));
1240
+ ((_d = error === null || error === void 0 ? void 0 : error.message) === null || _d === void 0 ? void 0 : _d.toLowerCase().includes('user rejected')) ||
1241
+ ((_e = error === null || error === void 0 ? void 0 : error.message) === null || _e === void 0 ? void 0 : _e.toLowerCase().includes('user denied')) ||
1242
+ ((_f = error === null || error === void 0 ? void 0 : error.message) === null || _f === void 0 ? void 0 : _f.toLowerCase().includes('user cancelled')) ||
1243
+ ((_g = error === null || error === void 0 ? void 0 : error.message) === null || _g === void 0 ? void 0 : _g.toLowerCase().includes('user canceled'));
862
1244
  if (!isUserRejection) {
863
1245
  console.error('[SolanaMobileWallet] Transaction failed:', error);
864
1246
  }
@@ -923,11 +1305,13 @@ class SolanaMobileWalletProvider {
923
1305
  if ((options === null || options === void 0 ? void 0 : options.shouldSubmitTx) === false) {
924
1306
  const signTxFeat = getSignTransactionFeature(wallet);
925
1307
  const wireBytes = txToWireBytes(tx);
926
- const results = await signTxFeat.signTransaction({ account, transaction: wireBytes, chain });
927
- if (!results || results.length === 0) {
1308
+ // signTransaction also navigates to `solana-wallet:`; only
1309
+ // surface the gesture modal if the tap activation has decayed.
1310
+ const signOnlyResult = await signWithFreshActivation(this.config.theme, () => signTxFeat.signTransaction({ account, transaction: wireBytes, chain }), 'MWA returned no signed transaction');
1311
+ if (!signOnlyResult) {
928
1312
  throw new Error('MWA returned no signed transaction');
929
1313
  }
930
- const { signedTransaction: signedBytes } = results[0];
1314
+ const { signedTransaction: signedBytes } = signOnlyResult;
931
1315
  const signedTx = txFromWireBytes(new Uint8Array(signedBytes));
932
1316
  return {
933
1317
  signedTransaction: signedTx,
@@ -940,11 +1324,13 @@ class SolanaMobileWalletProvider {
940
1324
  // Surfnet: sign locally via wallet-standard, submit manually.
941
1325
  const signTxFeat = getSignTransactionFeature(wallet);
942
1326
  const wireBytes = txToWireBytes(tx);
943
- const results = await signTxFeat.signTransaction({ account, transaction: wireBytes, chain });
944
- if (!results || results.length === 0) {
1327
+ // signTransaction also navigates to `solana-wallet:`; only
1328
+ // surface the gesture modal if the tap activation has decayed.
1329
+ const surfnetResult = await signWithFreshActivation(this.config.theme, () => signTxFeat.signTransaction({ account, transaction: wireBytes, chain }), 'MWA returned no signed transaction');
1330
+ if (!surfnetResult) {
945
1331
  throw new Error('MWA returned no signed transaction');
946
1332
  }
947
- const { signedTransaction: signedBytes } = results[0];
1333
+ const { signedTransaction: signedBytes } = surfnetResult;
948
1334
  const signedTx = txFromWireBytes(new Uint8Array(signedBytes));
949
1335
  const { blockhash, lastValidBlockHeight } = await connection.getLatestBlockhash('confirmed');
950
1336
  const signature = await connection.sendRawTransaction(signedTx.serialize(), {
@@ -970,18 +1356,24 @@ class SolanaMobileWalletProvider {
970
1356
  };
971
1357
  }
972
1358
  // Non-Surfnet: wallet signs and submits to its own RPC.
1359
+ // signAndSendTransaction dispatches a `solana-wallet:` navigation
1360
+ // that Chrome blocks without transient user activation. Fast txs
1361
+ // still hold the tap activation and navigate directly; slow ones
1362
+ // (e.g. a swap whose server build exceeds Chrome's ~5s window)
1363
+ // have lost it, so signWithFreshActivation shows the "Sign in"
1364
+ // modal to mint a fresh activation — no modal when not needed.
973
1365
  const signSendFeat = getSignAndSendTransactionFeature(wallet);
974
1366
  const wireBytes = txToWireBytes(tx);
975
- const results = await signSendFeat.signAndSendTransaction({
1367
+ const sendResult = await signWithFreshActivation(this.config.theme, () => signSendFeat.signAndSendTransaction({
976
1368
  account,
977
1369
  transaction: wireBytes,
978
1370
  chain,
979
1371
  options: { commitment: 'confirmed' },
980
- });
981
- if (!results || results.length === 0) {
1372
+ }));
1373
+ if (!sendResult) {
982
1374
  throw new Error('MWA returned no signature');
983
1375
  }
984
- const { signature: sigBytes } = results[0];
1376
+ const { signature: sigBytes } = sendResult;
985
1377
  const signature = base58.encode(sigBytes);
986
1378
  const txInfo = await confirmAndCheckTransaction(connection, signature);
987
1379
  return {
@@ -1063,4 +1455,4 @@ class SolanaMobileWalletProvider {
1063
1455
  SolanaMobileWalletProvider.instance = null;
1064
1456
 
1065
1457
  export { SolanaMobileWalletProvider };
1066
- //# sourceMappingURL=solana-mobile-wallet-provider-D7BbSpez.esm.js.map
1458
+ //# sourceMappingURL=solana-mobile-wallet-provider-C5mN8Dxh.esm.js.map