@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,7 +1,7 @@
1
1
  'use strict';
2
2
 
3
- var index = require('./index-D-Wbwevj.js');
4
- var index_native = require('./index.native-7hiNiSyC.js');
3
+ var index = require('./index-CvNX4W0l.js');
4
+ var index_native = require('./index.native-FMbSnE7i.js');
5
5
  var web3_js = require('@solana/web3.js');
6
6
  var anchor = require('@coral-xyz/anchor');
7
7
  require('axios');
@@ -26,6 +26,14 @@ function _interopNamespaceDefault(e) {
26
26
 
27
27
  var anchor__namespace = /*#__PURE__*/_interopNamespaceDefault(anchor);
28
28
 
29
+ /**
30
+ * Storage key for persisting the MWA auth_token across cold starts.
31
+ * Holds JSON `{ token: string, address: string }`. Cleared by
32
+ * `logout()`. Hydrated by the constructor on native so cold-start
33
+ * doesn't force the user back into Phantom's approval flow when the
34
+ * underlying wallet authorization is still valid.
35
+ */
36
+ const MWA_AUTH_TOKEN_STORAGE_KEY = 'tarobase_mwa_auth_token';
29
37
  const ED25519_SIGNATURE_LENGTH = 64;
30
38
  const STORED_AUTH_METHOD_KEY = 'tarobase_last_auth_method';
31
39
  const MWA_AUTH_METHOD = 'mobile-wallet-adapter';
@@ -141,13 +149,13 @@ async function withMwaAssociationRetry(fn) {
141
149
  * next tap is a new activation (a real retry). A timer-based retry would
142
150
  * just hit the same Chrome block. Cap at 3 attempts before giving up.
143
151
  */
144
- async function awaitSignInGestureAndSign(theme, signFn) {
152
+ async function awaitSignInGestureAndSign(theme, signFn, noResultError = 'MWA returned no signature') {
145
153
  if (typeof document === 'undefined' || typeof window === 'undefined') {
146
154
  // SSR / non-browser: skip the gesture, just call (the activation
147
155
  // model doesn't apply outside the browser).
148
156
  const results = await signFn();
149
157
  if (!results || results.length === 0)
150
- throw new Error('MWA returned no signature');
158
+ throw new Error(noResultError);
151
159
  return results[0];
152
160
  }
153
161
  return new Promise((resolve, reject) => {
@@ -339,7 +347,7 @@ async function awaitSignInGestureAndSign(theme, signFn) {
339
347
  // launchAssociation(). Do not `await` before calling.
340
348
  signFn().then((results) => {
341
349
  if (!results || results.length === 0) {
342
- finishReject(new Error('MWA returned no signature'));
350
+ finishReject(new Error(noResultError));
343
351
  return;
344
352
  }
345
353
  finishResolve(results[0]);
@@ -367,6 +375,31 @@ async function awaitSignInGestureAndSign(theme, signFn) {
367
375
  });
368
376
  });
369
377
  }
378
+ /**
379
+ * Sign through the gesture modal ONLY when transient user activation has
380
+ * already decayed. Fast transactions still hold the activation from the
381
+ * user's tap, so the `solana-wallet:` navigation succeeds directly with no
382
+ * modal (preserves prior UX — no extra tap). Slow transactions — e.g. a swap
383
+ * whose server-side build exceeds Chrome's ~5s activation window — have lost
384
+ * it, so we fall back to awaitSignInGestureAndSign to mint a fresh activation
385
+ * via a "Sign in" tap. Returns the first result (same shape as the bare
386
+ * wallet-standard feature call and as awaitSignInGestureAndSign).
387
+ */
388
+ async function signWithFreshActivation(theme, signFn, noResultError = 'MWA returned no signature') {
389
+ var _a;
390
+ const activationLive = typeof navigator !== 'undefined' &&
391
+ ((_a = navigator.userActivation) === null || _a === void 0 ? void 0 : _a.isActive) === true;
392
+ if (activationLive) {
393
+ // Live gesture: invoke synchronously (no await before signFn) so the
394
+ // activation propagates to the protocol's location.assign navigation.
395
+ const results = await signFn();
396
+ if (!results || results.length === 0)
397
+ throw new Error(noResultError);
398
+ return results[0];
399
+ }
400
+ // Activation gone: surface the modal so the user's tap mints a fresh one.
401
+ return awaitSignInGestureAndSign(theme, signFn, noResultError);
402
+ }
370
403
  /**
371
404
  * Normalize a chain string to a wallet-standard Solana chain identifier.
372
405
  *
@@ -527,19 +560,66 @@ class SolanaMobileWalletProvider {
527
560
  constructor(networkUrl = null, config = {}) {
528
561
  /** LocalSolanaMobileWalletAdapterWallet, lazy-constructed in ensureWallet(). */
529
562
  this.wallet = null;
563
+ /**
564
+ * Cached MWA auth_token returned by `wallet.authorize()`. Reused by
565
+ * subsequent native transact() calls (signMessage / signTransaction)
566
+ * so the user doesn't get the wallet-pick popup on every operation.
567
+ * Persisted to platform storage and hydrated by the constructor on
568
+ * native; cleared by logout() and on `ERROR_REAUTHORIZE`.
569
+ */
570
+ this.nativeAuthToken = null;
571
+ /** Cached public key string for the connected MWA wallet (native). */
572
+ this.nativeAddress = null;
530
573
  this.networkUrl = networkUrl;
531
574
  this.config = config;
532
- if (typeof window === 'undefined') {
575
+ // Allow construction in true React Native environments: getPlatform().hasDOM
576
+ // is false there even though `typeof window === 'object'` (RN exposes a
577
+ // partial window global). Web/PWA paths still keep their original guard:
578
+ // they need real window+document for wallet-standard-mobile's deep-link
579
+ // mechanism, so missing-window in those builds remains a fail-fast.
580
+ const hasDOM = index_native.getPlatform().hasDOM;
581
+ if (!hasDOM && typeof window === 'undefined') {
582
+ throw new Error('SolanaMobileWalletProvider can only be instantiated in a browser or React Native environment');
583
+ }
584
+ if (hasDOM && typeof window === 'undefined') {
533
585
  throw new Error('SolanaMobileWalletProvider can only be instantiated in a browser environment');
534
586
  }
535
587
  if (SolanaMobileWalletProvider.instance) {
536
588
  return SolanaMobileWalletProvider.instance;
537
589
  }
590
+ // `appIdentity.uri` is what Phantom Android (and other MWA wallets)
591
+ // display in their approval modal. On web/PWA this is the page
592
+ // origin; on native there's no `window.location`, so fall back to
593
+ // a stable identifier the user can recognize. Apps can override
594
+ // entirely via `config.appIdentity.uri`.
595
+ const fallbackUri = hasDOM
596
+ ? index_native.getPlatform().getLocationOrigin()
597
+ : 'tarobase://app';
538
598
  this.appIdentity = config.appIdentity || {
539
599
  name: 'TaroBase App',
540
- uri: index_native.getPlatform().getLocationOrigin(),
600
+ uri: fallbackUri,
541
601
  };
542
602
  this.cluster = config.cluster || 'mainnet-beta';
603
+ // Hydrate cached MWA auth_token from storage on native so we can
604
+ // skip the wallet-pick popup after a cold-start when the underlying
605
+ // wallet authorization is still valid. Sync storage call per the
606
+ // PlatformAdapter contract; safe to swallow read errors (a fresh
607
+ // login() just re-authorizes).
608
+ if (!hasDOM) {
609
+ try {
610
+ const raw = index_native.getPlatform().storage.getItem(MWA_AUTH_TOKEN_STORAGE_KEY);
611
+ if (raw) {
612
+ const parsed = JSON.parse(raw);
613
+ if (typeof parsed.token === 'string' && typeof parsed.address === 'string') {
614
+ this.nativeAuthToken = parsed.token;
615
+ this.nativeAddress = parsed.address;
616
+ }
617
+ }
618
+ }
619
+ catch (_a) {
620
+ // Corrupt or unreadable cache — ignore. login() will re-auth.
621
+ }
622
+ }
543
623
  SolanaMobileWalletProvider.instance = this;
544
624
  }
545
625
  static getInstance(networkUrl, config) {
@@ -552,7 +632,7 @@ class SolanaMobileWalletProvider {
552
632
  async ensureWallet() {
553
633
  if (this.wallet)
554
634
  return this.wallet;
555
- const mod = await Promise.resolve().then(function () { return require('./index.browser-CbawPvh6.js'); });
635
+ const mod = await Promise.resolve().then(function () { return require('./index.browser-BCr9Sc8V.js'); });
556
636
  const chain = mapChainToWalletStandard(this.cluster);
557
637
  this.wallet = new mod.LocalSolanaMobileWalletAdapterWallet({
558
638
  appIdentity: this.appIdentity,
@@ -602,6 +682,134 @@ class SolanaMobileWalletProvider {
602
682
  getChain() {
603
683
  return mapChainToWalletStandard(this.cluster);
604
684
  }
685
+ /**
686
+ * Dynamically import and unwrap `transact` from the MWA web3js
687
+ * package. The package is externalized in rollup.config.js so this
688
+ * resolves to `lib/cjs/index.native.js` (TurboModule-backed) on
689
+ * Metro and `lib/esm/index.browser.js` (WebSocket) on webpack/vite
690
+ * per their respective platform conditions. Handles Metro's CJS-to-
691
+ * ESM interop variance (`mod.transact` vs `mod.default?.transact`).
692
+ */
693
+ async loadTransact() {
694
+ var _a;
695
+ const mod = await import('@solana-mobile/mobile-wallet-adapter-protocol-web3js');
696
+ const t = mod.transact || ((_a = mod.default) === null || _a === void 0 ? void 0 : _a.transact);
697
+ if (typeof t !== 'function') {
698
+ throw new Error('MWA transact API not available on this platform');
699
+ }
700
+ return t;
701
+ }
702
+ /**
703
+ * Cache and persist a fresh MWA auth_token + address. Called from
704
+ * `_loginNative` after a successful authorize. Storage failures are
705
+ * non-fatal (next cold-start re-auths).
706
+ */
707
+ persistNativeAuth(token, address) {
708
+ this.nativeAuthToken = token;
709
+ this.nativeAddress = address;
710
+ try {
711
+ index_native.getPlatform().storage.setItem(MWA_AUTH_TOKEN_STORAGE_KEY, JSON.stringify({ token, address }));
712
+ }
713
+ catch (_a) {
714
+ // non-fatal — token still in-memory for this process
715
+ }
716
+ }
717
+ /** Clear cached + persisted native auth state. */
718
+ clearNativeAuth() {
719
+ this.nativeAuthToken = null;
720
+ this.nativeAddress = null;
721
+ try {
722
+ index_native.getPlatform().storage.removeItem(MWA_AUTH_TOKEN_STORAGE_KEY);
723
+ }
724
+ catch (_a) {
725
+ // ignore
726
+ }
727
+ }
728
+ /**
729
+ * Classify an MWA-native error as a user cancellation. User-cancel
730
+ * shouldn't surface as a red console.error; callers can swallow or
731
+ * show a softer message. MWA spec codes plus the same substring
732
+ * checks the web path uses to catch wallet-specific phrasing.
733
+ */
734
+ isNativeUserCancel(err) {
735
+ var _a;
736
+ if (!err)
737
+ return false;
738
+ const code = err.code;
739
+ if (code === 'ERROR_NOT_SIGNED')
740
+ return true;
741
+ const msg = String((_a = err.message) !== null && _a !== void 0 ? _a : '').toLowerCase();
742
+ return /user (rejected|denied|cancelled|canceled|declined)/.test(msg);
743
+ }
744
+ /**
745
+ * Native MWA login via @solana-mobile/mobile-wallet-adapter-protocol-web3js.
746
+ * Used in true React Native (Expo) environments where wallet-standard-mobile's
747
+ * web universal-link path doesn't apply. Does authorize + signMessage in a
748
+ * single transact() roundtrip — intent-based MWA doesn't need the two-popup
749
+ * dance the web path uses (no Chrome activation-loss concern). Persists the
750
+ * resulting auth_token so cold-start can reauthorize without a fresh popup.
751
+ */
752
+ async _loginNative() {
753
+ const transact = await this.loadTransact();
754
+ const existingSession = await index_native.WebSessionManager.getSession();
755
+ const nonce = await index_native.genAuthNonce();
756
+ const result = await transact(async (wallet) => {
757
+ const auth = await wallet.authorize({
758
+ chain: this.getChain(),
759
+ identity: this.appIdentity,
760
+ });
761
+ if (!auth.accounts || auth.accounts.length === 0) {
762
+ throw new Error('MWA returned no accounts');
763
+ }
764
+ const account = auth.accounts[0];
765
+ // account.address is base64-encoded per MWA spec; convert to
766
+ // the base58 form Tarobase + the rest of the SDK use.
767
+ const base58Addr = new web3_js.PublicKey(index.bufferExports.Buffer.from(account.address, 'base64')).toBase58();
768
+ // Reuse session if already valid for this address — skip the
769
+ // signMessages roundtrip entirely.
770
+ if (existingSession && existingSession.address === base58Addr) {
771
+ return {
772
+ base58Addr,
773
+ authToken: auth.auth_token,
774
+ signatureBase64: null,
775
+ };
776
+ }
777
+ const messageText = await index_native.genSolanaMessage(base58Addr, nonce);
778
+ const messageBytes = index_native.getPlatform().textEncode(messageText);
779
+ const signatures = await wallet.signMessages({
780
+ addresses: [account.address],
781
+ payloads: [messageBytes],
782
+ });
783
+ if (!signatures || signatures.length === 0) {
784
+ throw new Error('MWA returned no signature');
785
+ }
786
+ // Per spec, signMessages returns Uint8Array[] of signatures
787
+ // (one per payload), not message+signature concatenations.
788
+ const signatureBase64 = index.bufferExports.Buffer.from(signatures[0]).toString('base64');
789
+ return {
790
+ base58Addr,
791
+ authToken: auth.auth_token,
792
+ signatureBase64,
793
+ messageText,
794
+ };
795
+ });
796
+ this.persistNativeAuth(result.authToken, result.base58Addr);
797
+ // Existing valid session — short-circuit before re-creating server-side.
798
+ if (existingSession && existingSession.address === result.base58Addr) {
799
+ const user = { provider: this, address: result.base58Addr };
800
+ index_native.setCurrentUser(user);
801
+ return user;
802
+ }
803
+ // Create Tarobase session on the server.
804
+ if (!result.signatureBase64 || !result.messageText) {
805
+ throw new Error('MWA login completed without signature');
806
+ }
807
+ const createSessionResult = await index_native.createSessionWithSignature(result.base58Addr, result.messageText, result.signatureBase64);
808
+ await index_native.WebSessionManager.storeSession(result.base58Addr, createSessionResult.accessToken, createSessionResult.idToken, createSessionResult.refreshToken);
809
+ const user = { provider: this, address: result.base58Addr };
810
+ index_native.setCurrentUser(user);
811
+ return user;
812
+ }
605
813
  async login() {
606
814
  var _a, _b, _c, _d, _e;
607
815
  index_native.setAuthLoading(true);
@@ -612,6 +820,13 @@ class SolanaMobileWalletProvider {
612
820
  const prevAuthMethod = readAuthMethod();
613
821
  writeAuthMethod(MWA_AUTH_METHOD);
614
822
  try {
823
+ // True React Native: skip the wallet-standard-mobile path (which
824
+ // requires window.isSecureContext and a real DOM) and use the raw
825
+ // MWA protocol via Android intents.
826
+ if (!index_native.getPlatform().hasDOM) {
827
+ const user = await this._loginNative();
828
+ return user;
829
+ }
615
830
  const wallet = await this.ensureWallet();
616
831
  // Quick-check: wallet may already have authorization (e.g. from a
617
832
  // previous in-page login) and a matching Tarobase session — skip
@@ -713,6 +928,29 @@ class SolanaMobileWalletProvider {
713
928
  return null;
714
929
  }
715
930
  async logout() {
931
+ if (!index_native.getPlatform().hasDOM) {
932
+ // Native path: deauthorize the cached MWA auth_token if we have
933
+ // one (failures non-fatal — the wallet app may have been
934
+ // uninstalled or the token already revoked), then clear local
935
+ // and persisted state.
936
+ const token = this.nativeAuthToken;
937
+ if (token) {
938
+ try {
939
+ const transact = await this.loadTransact();
940
+ await transact(async (wallet) => {
941
+ await wallet.deauthorize({ auth_token: token });
942
+ });
943
+ }
944
+ catch (error) {
945
+ console.warn('[SolanaMobileWallet] Native deauthorize error:', error);
946
+ }
947
+ }
948
+ this.clearNativeAuth();
949
+ index_native.WebSessionManager.clearSession();
950
+ writeAuthMethod(null);
951
+ index_native.setCurrentUser(null);
952
+ return;
953
+ }
716
954
  try {
717
955
  const wallet = await this.ensureWallet();
718
956
  const disconnectFeat = getDisconnectFeature(wallet);
@@ -732,7 +970,42 @@ class SolanaMobileWalletProvider {
732
970
  index_native.setCurrentUser(null);
733
971
  }
734
972
  async signMessage(message) {
735
- var _a, _b;
973
+ var _a, _b, _c;
974
+ // Native: reauthorize with cached auth_token, then signMessages inside
975
+ // the same transact() session. No wallet-pick popup if the auth_token
976
+ // is still valid for the user's wallet.
977
+ if (!index_native.getPlatform().hasDOM) {
978
+ if (!this.nativeAuthToken || !this.nativeAddress) {
979
+ throw new Error('Wallet not connected. Call login() first.');
980
+ }
981
+ const transact = await this.loadTransact();
982
+ const messageBytes = index_native.getPlatform().textEncode(message);
983
+ const addressBase64 = new web3_js.PublicKey(this.nativeAddress).toBuffer().toString('base64');
984
+ const authToken = this.nativeAuthToken;
985
+ try {
986
+ const signature = await transact(async (wallet) => {
987
+ await wallet.reauthorize({ auth_token: authToken, identity: this.appIdentity });
988
+ const sigs = await wallet.signMessages({
989
+ addresses: [addressBase64],
990
+ payloads: [messageBytes],
991
+ });
992
+ if (!sigs || sigs.length === 0)
993
+ throw new Error('MWA returned no signature');
994
+ return sigs[0];
995
+ });
996
+ return index.bufferExports.Buffer.from(signature).toString('base64');
997
+ }
998
+ catch (error) {
999
+ if (this.isNativeUserCancel(error)) {
1000
+ throw new Error('User declined to sign');
1001
+ }
1002
+ if ((error === null || error === void 0 ? void 0 : error.code) === 'ERROR_AUTHORIZATION_FAILED' || (error === null || error === void 0 ? void 0 : error.code) === 'ERROR_REAUTHORIZE') {
1003
+ await this.logout();
1004
+ throw new Error('Wallet connection lost. Please reconnect.');
1005
+ }
1006
+ throw new Error(`Failed to sign message: ${(_a = error === null || error === void 0 ? void 0 : error.message) !== null && _a !== void 0 ? _a : error}`);
1007
+ }
1008
+ }
736
1009
  const account = await this.ensureAuthorized();
737
1010
  const wallet = await this.ensureWallet();
738
1011
  try {
@@ -746,7 +1019,7 @@ class SolanaMobileWalletProvider {
746
1019
  return index.bufferExports.Buffer.from(sigBytes).toString('base64');
747
1020
  }
748
1021
  catch (error) {
749
- 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')) ||
1022
+ 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')) ||
750
1023
  (error === null || error === void 0 ? void 0 : error.code) === 'ERROR_AUTHORIZATION_FAILED') {
751
1024
  await this.logout();
752
1025
  throw new Error('Wallet connection lost. Please reconnect.');
@@ -755,7 +1028,58 @@ class SolanaMobileWalletProvider {
755
1028
  }
756
1029
  }
757
1030
  async signTransaction(transaction) {
758
- var _a, _b;
1031
+ var _a, _b, _c;
1032
+ // Native: fill blockhash/feePayer if missing, then signTransactions
1033
+ // inside a transact() session keyed by the cached auth_token.
1034
+ if (!index_native.getPlatform().hasDOM) {
1035
+ if (!this.nativeAuthToken || !this.nativeAddress) {
1036
+ throw new Error('Wallet not connected. Call login() first.');
1037
+ }
1038
+ const connectedPubkey = new web3_js.PublicKey(this.nativeAddress);
1039
+ const isLegacyTransaction = 'recentBlockhash' in transaction && !('message' in transaction && 'staticAccountKeys' in transaction.message);
1040
+ if (isLegacyTransaction) {
1041
+ const legacyTx = transaction;
1042
+ if (!legacyTx.recentBlockhash) {
1043
+ const conn = new web3_js.Connection(this.getRpcUrl(), 'confirmed');
1044
+ const { blockhash, lastValidBlockHeight } = await conn.getLatestBlockhash('confirmed');
1045
+ legacyTx.recentBlockhash = blockhash;
1046
+ legacyTx.lastValidBlockHeight = lastValidBlockHeight;
1047
+ }
1048
+ if (!legacyTx.feePayer) {
1049
+ legacyTx.feePayer = connectedPubkey;
1050
+ }
1051
+ }
1052
+ else {
1053
+ const versionedTx = transaction;
1054
+ if (!versionedTx.message.recentBlockhash) {
1055
+ const conn = new web3_js.Connection(this.getRpcUrl(), 'confirmed');
1056
+ const { blockhash } = await conn.getLatestBlockhash('confirmed');
1057
+ versionedTx.message.recentBlockhash = blockhash;
1058
+ }
1059
+ }
1060
+ const transact = await this.loadTransact();
1061
+ const authToken = this.nativeAuthToken;
1062
+ try {
1063
+ const signed = await transact(async (wallet) => {
1064
+ await wallet.reauthorize({ auth_token: authToken, identity: this.appIdentity });
1065
+ const results = await wallet.signTransactions({ transactions: [transaction] });
1066
+ if (!results || results.length === 0)
1067
+ throw new Error('MWA returned no signed transaction');
1068
+ return results[0];
1069
+ });
1070
+ return signed;
1071
+ }
1072
+ catch (error) {
1073
+ if (this.isNativeUserCancel(error)) {
1074
+ throw new Error('User declined to sign');
1075
+ }
1076
+ if ((error === null || error === void 0 ? void 0 : error.code) === 'ERROR_AUTHORIZATION_FAILED' || (error === null || error === void 0 ? void 0 : error.code) === 'ERROR_REAUTHORIZE') {
1077
+ await this.logout();
1078
+ throw new Error('Wallet connection lost. Please reconnect.');
1079
+ }
1080
+ throw new Error(`Failed to sign transaction: ${(_a = error === null || error === void 0 ? void 0 : error.message) !== null && _a !== void 0 ? _a : error}`);
1081
+ }
1082
+ }
759
1083
  const account = await this.ensureAuthorized();
760
1084
  const connectedPubkey = new web3_js.PublicKey(account.publicKey);
761
1085
  const wallet = await this.ensureWallet();
@@ -786,15 +1110,14 @@ class SolanaMobileWalletProvider {
786
1110
  try {
787
1111
  const signTxFeat = getSignTransactionFeature(wallet);
788
1112
  const wireBytes = txToWireBytes(transaction);
789
- const results = await signTxFeat.signTransaction({ account, transaction: wireBytes, chain });
790
- if (!results || results.length === 0) {
791
- throw new Error('MWA returned no signed transaction');
792
- }
793
- const { signedTransaction: signedBytes } = results[0];
1113
+ // signTransaction navigates to `solana-wallet:`; only show the
1114
+ // gesture modal if the tap activation has decayed (see runTransaction).
1115
+ const signResult = await signWithFreshActivation(this.config.theme, () => signTxFeat.signTransaction({ account, transaction: wireBytes, chain }), 'MWA returned no signed transaction');
1116
+ const { signedTransaction: signedBytes } = signResult;
794
1117
  return txFromWireBytes(new Uint8Array(signedBytes));
795
1118
  }
796
1119
  catch (error) {
797
- 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')) ||
1120
+ 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')) ||
798
1121
  (error === null || error === void 0 ? void 0 : error.code) === 'ERROR_AUTHORIZATION_FAILED') {
799
1122
  await this.logout();
800
1123
  throw new Error('Wallet connection lost. Please reconnect.');
@@ -803,7 +1126,70 @@ class SolanaMobileWalletProvider {
803
1126
  }
804
1127
  }
805
1128
  async signAndSubmitTransaction(transaction, feePayer) {
806
- var _a, _b, _c, _d, _e, _f;
1129
+ var _a, _b, _c, _d, _e, _f, _g;
1130
+ // Native: signAndSendTransactions inside a transact() session.
1131
+ // The wallet submits to its own RPC; we then await confirmation on
1132
+ // ours. Surfnet (custom RPC) needs manual submission because the
1133
+ // wallet won't route there — we fall back to sign-only + manual send.
1134
+ if (!index_native.getPlatform().hasDOM) {
1135
+ if (!this.nativeAuthToken || !this.nativeAddress) {
1136
+ throw new Error('Wallet not connected. Call login() first.');
1137
+ }
1138
+ const connectedPubkey = new web3_js.PublicKey(this.nativeAddress);
1139
+ const rpcUrl = this.getRpcUrl();
1140
+ const connection = new web3_js.Connection(rpcUrl, 'confirmed');
1141
+ const isSurfnet = rpcUrl === index_native.SURFNET_RPC_URL;
1142
+ const { blockhash, lastValidBlockHeight } = await connection.getLatestBlockhash('confirmed');
1143
+ const isLegacyTransaction = 'recentBlockhash' in transaction && !('message' in transaction && 'staticAccountKeys' in transaction.message);
1144
+ if (isLegacyTransaction) {
1145
+ const legacyTx = transaction;
1146
+ legacyTx.recentBlockhash = blockhash;
1147
+ legacyTx.lastValidBlockHeight = lastValidBlockHeight;
1148
+ if (!legacyTx.feePayer)
1149
+ legacyTx.feePayer = feePayer !== null && feePayer !== void 0 ? feePayer : connectedPubkey;
1150
+ }
1151
+ else {
1152
+ const versionedTx = transaction;
1153
+ versionedTx.message.recentBlockhash = blockhash;
1154
+ }
1155
+ const transact = await this.loadTransact();
1156
+ const authToken = this.nativeAuthToken;
1157
+ try {
1158
+ if (isSurfnet) {
1159
+ // Surfnet: sign only, submit manually to Surfnet RPC
1160
+ // (the wallet would route signAndSend to its own RPC).
1161
+ const signed = await transact(async (wallet) => {
1162
+ await wallet.reauthorize({ auth_token: authToken, identity: this.appIdentity });
1163
+ const results = await wallet.signTransactions({ transactions: [transaction] });
1164
+ if (!results || results.length === 0)
1165
+ throw new Error('MWA returned no signed transaction');
1166
+ return results[0];
1167
+ });
1168
+ const sig = await connection.sendRawTransaction(signed.serialize(), { preflightCommitment: 'confirmed' });
1169
+ await index_native.confirmAndCheckTransaction(connection, sig);
1170
+ return sig;
1171
+ }
1172
+ const sig = await transact(async (wallet) => {
1173
+ await wallet.reauthorize({ auth_token: authToken, identity: this.appIdentity });
1174
+ const results = await wallet.signAndSendTransactions({ transactions: [transaction] });
1175
+ if (!results || results.length === 0)
1176
+ throw new Error('MWA returned no signature');
1177
+ return results[0];
1178
+ });
1179
+ await index_native.confirmAndCheckTransaction(connection, sig);
1180
+ return sig;
1181
+ }
1182
+ catch (error) {
1183
+ if (this.isNativeUserCancel(error)) {
1184
+ throw new Error('User declined to sign');
1185
+ }
1186
+ if ((error === null || error === void 0 ? void 0 : error.code) === 'ERROR_AUTHORIZATION_FAILED' || (error === null || error === void 0 ? void 0 : error.code) === 'ERROR_REAUTHORIZE') {
1187
+ await this.logout();
1188
+ throw new Error('Wallet connection lost. Please reconnect.');
1189
+ }
1190
+ throw new Error(`Failed to sign+submit transaction: ${(_a = error === null || error === void 0 ? void 0 : error.message) !== null && _a !== void 0 ? _a : error}`);
1191
+ }
1192
+ }
807
1193
  const account = await this.ensureAuthorized();
808
1194
  const connectedPubkey = new web3_js.PublicKey(account.publicKey);
809
1195
  const wallet = await this.ensureWallet();
@@ -833,11 +1219,9 @@ class SolanaMobileWalletProvider {
833
1219
  // because the wallet would submit to its own RPC.
834
1220
  const signTxFeat = getSignTransactionFeature(wallet);
835
1221
  const wireBytes = txToWireBytes(transaction);
836
- const results = await signTxFeat.signTransaction({ account, transaction: wireBytes, chain });
837
- if (!results || results.length === 0) {
838
- throw new Error('MWA returned no signed transaction');
839
- }
840
- const { signedTransaction: signedBytes } = results[0];
1222
+ // Gesture modal only if activation decayed (see runTransaction).
1223
+ const signResult = await signWithFreshActivation(this.config.theme, () => signTxFeat.signTransaction({ account, transaction: wireBytes, chain }), 'MWA returned no signed transaction');
1224
+ const { signedTransaction: signedBytes } = signResult;
841
1225
  const signedTx = txFromWireBytes(new Uint8Array(signedBytes));
842
1226
  const signature = await connection.sendRawTransaction(signedTx.serialize(), {
843
1227
  preflightCommitment: 'confirmed',
@@ -853,33 +1237,31 @@ class SolanaMobileWalletProvider {
853
1237
  return signature;
854
1238
  }
855
1239
  // Non-Surfnet: wallet signs and submits to its own RPC.
1240
+ // Gesture modal only if activation decayed (see runTransaction).
856
1241
  const signSendFeat = getSignAndSendTransactionFeature(wallet);
857
1242
  const wireBytes = txToWireBytes(transaction);
858
- const results = await signSendFeat.signAndSendTransaction({
1243
+ const sendResult = await signWithFreshActivation(this.config.theme, () => signSendFeat.signAndSendTransaction({
859
1244
  account,
860
1245
  transaction: wireBytes,
861
1246
  chain,
862
1247
  options: { commitment: 'confirmed' },
863
- });
864
- if (!results || results.length === 0) {
865
- throw new Error('MWA returned no signature');
866
- }
867
- const { signature: sigBytes } = results[0];
1248
+ }));
1249
+ const { signature: sigBytes } = sendResult;
868
1250
  const signature = index_native.base58.encode(sigBytes);
869
1251
  await index_native.confirmAndCheckTransaction(connection, signature);
870
1252
  return signature;
871
1253
  }
872
1254
  catch (error) {
873
- 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')) ||
1255
+ 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')) ||
874
1256
  (error === null || error === void 0 ? void 0 : error.code) === 'ERROR_AUTHORIZATION_FAILED') {
875
1257
  await this.logout();
876
1258
  throw new Error('Wallet connection lost. Please reconnect.');
877
1259
  }
878
1260
  const isUserRejection = (error === null || error === void 0 ? void 0 : error.code) === 4001 ||
879
- ((_c = error === null || error === void 0 ? void 0 : error.message) === null || _c === void 0 ? void 0 : _c.toLowerCase().includes('user rejected')) ||
880
- ((_d = error === null || error === void 0 ? void 0 : error.message) === null || _d === void 0 ? void 0 : _d.toLowerCase().includes('user denied')) ||
881
- ((_e = error === null || error === void 0 ? void 0 : error.message) === null || _e === void 0 ? void 0 : _e.toLowerCase().includes('user cancelled')) ||
882
- ((_f = error === null || error === void 0 ? void 0 : error.message) === null || _f === void 0 ? void 0 : _f.toLowerCase().includes('user canceled'));
1261
+ ((_d = error === null || error === void 0 ? void 0 : error.message) === null || _d === void 0 ? void 0 : _d.toLowerCase().includes('user rejected')) ||
1262
+ ((_e = error === null || error === void 0 ? void 0 : error.message) === null || _e === void 0 ? void 0 : _e.toLowerCase().includes('user denied')) ||
1263
+ ((_f = error === null || error === void 0 ? void 0 : error.message) === null || _f === void 0 ? void 0 : _f.toLowerCase().includes('user cancelled')) ||
1264
+ ((_g = error === null || error === void 0 ? void 0 : error.message) === null || _g === void 0 ? void 0 : _g.toLowerCase().includes('user canceled'));
883
1265
  if (!isUserRejection) {
884
1266
  console.error('[SolanaMobileWallet] Transaction failed:', error);
885
1267
  }
@@ -944,11 +1326,13 @@ class SolanaMobileWalletProvider {
944
1326
  if ((options === null || options === void 0 ? void 0 : options.shouldSubmitTx) === false) {
945
1327
  const signTxFeat = getSignTransactionFeature(wallet);
946
1328
  const wireBytes = txToWireBytes(tx);
947
- const results = await signTxFeat.signTransaction({ account, transaction: wireBytes, chain });
948
- if (!results || results.length === 0) {
1329
+ // signTransaction also navigates to `solana-wallet:`; only
1330
+ // surface the gesture modal if the tap activation has decayed.
1331
+ const signOnlyResult = await signWithFreshActivation(this.config.theme, () => signTxFeat.signTransaction({ account, transaction: wireBytes, chain }), 'MWA returned no signed transaction');
1332
+ if (!signOnlyResult) {
949
1333
  throw new Error('MWA returned no signed transaction');
950
1334
  }
951
- const { signedTransaction: signedBytes } = results[0];
1335
+ const { signedTransaction: signedBytes } = signOnlyResult;
952
1336
  const signedTx = txFromWireBytes(new Uint8Array(signedBytes));
953
1337
  return {
954
1338
  signedTransaction: signedTx,
@@ -961,11 +1345,13 @@ class SolanaMobileWalletProvider {
961
1345
  // Surfnet: sign locally via wallet-standard, submit manually.
962
1346
  const signTxFeat = getSignTransactionFeature(wallet);
963
1347
  const wireBytes = txToWireBytes(tx);
964
- const results = await signTxFeat.signTransaction({ account, transaction: wireBytes, chain });
965
- if (!results || results.length === 0) {
1348
+ // signTransaction also navigates to `solana-wallet:`; only
1349
+ // surface the gesture modal if the tap activation has decayed.
1350
+ const surfnetResult = await signWithFreshActivation(this.config.theme, () => signTxFeat.signTransaction({ account, transaction: wireBytes, chain }), 'MWA returned no signed transaction');
1351
+ if (!surfnetResult) {
966
1352
  throw new Error('MWA returned no signed transaction');
967
1353
  }
968
- const { signedTransaction: signedBytes } = results[0];
1354
+ const { signedTransaction: signedBytes } = surfnetResult;
969
1355
  const signedTx = txFromWireBytes(new Uint8Array(signedBytes));
970
1356
  const { blockhash, lastValidBlockHeight } = await connection.getLatestBlockhash('confirmed');
971
1357
  const signature = await connection.sendRawTransaction(signedTx.serialize(), {
@@ -991,18 +1377,24 @@ class SolanaMobileWalletProvider {
991
1377
  };
992
1378
  }
993
1379
  // Non-Surfnet: wallet signs and submits to its own RPC.
1380
+ // signAndSendTransaction dispatches a `solana-wallet:` navigation
1381
+ // that Chrome blocks without transient user activation. Fast txs
1382
+ // still hold the tap activation and navigate directly; slow ones
1383
+ // (e.g. a swap whose server build exceeds Chrome's ~5s window)
1384
+ // have lost it, so signWithFreshActivation shows the "Sign in"
1385
+ // modal to mint a fresh activation — no modal when not needed.
994
1386
  const signSendFeat = getSignAndSendTransactionFeature(wallet);
995
1387
  const wireBytes = txToWireBytes(tx);
996
- const results = await signSendFeat.signAndSendTransaction({
1388
+ const sendResult = await signWithFreshActivation(this.config.theme, () => signSendFeat.signAndSendTransaction({
997
1389
  account,
998
1390
  transaction: wireBytes,
999
1391
  chain,
1000
1392
  options: { commitment: 'confirmed' },
1001
- });
1002
- if (!results || results.length === 0) {
1393
+ }));
1394
+ if (!sendResult) {
1003
1395
  throw new Error('MWA returned no signature');
1004
1396
  }
1005
- const { signature: sigBytes } = results[0];
1397
+ const { signature: sigBytes } = sendResult;
1006
1398
  const signature = index_native.base58.encode(sigBytes);
1007
1399
  const txInfo = await index_native.confirmAndCheckTransaction(connection, signature);
1008
1400
  return {
@@ -1084,4 +1476,4 @@ class SolanaMobileWalletProvider {
1084
1476
  SolanaMobileWalletProvider.instance = null;
1085
1477
 
1086
1478
  exports.SolanaMobileWalletProvider = SolanaMobileWalletProvider;
1087
- //# sourceMappingURL=solana-mobile-wallet-provider-DwER68Rz.js.map
1479
+ //# sourceMappingURL=solana-mobile-wallet-provider-CAZs-TkL.js.map