@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
@@ -4,6 +4,21 @@ import * as anchor from '@coral-xyz/anchor';
4
4
  import { Program } from '@coral-xyz/anchor';
5
5
  import * as React$2 from 'react';
6
6
 
7
+ function _mergeNamespaces(n, m) {
8
+ m.forEach(function (e) {
9
+ e && typeof e !== 'string' && !Array.isArray(e) && Object.keys(e).forEach(function (k) {
10
+ if (k !== 'default' && !(k in n)) {
11
+ var d = Object.getOwnPropertyDescriptor(e, k);
12
+ Object.defineProperty(n, k, d.get ? d : {
13
+ enumerable: true,
14
+ get: function () { return e[k]; }
15
+ });
16
+ }
17
+ });
18
+ });
19
+ return Object.freeze(n);
20
+ }
21
+
7
22
  function getDefaultExportFromCjs$1 (x) {
8
23
  return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
9
24
  }
@@ -6749,28 +6764,6 @@ class WebSessionManager {
6749
6764
  static async storeSession(address, accessToken, idToken, refreshToken) {
6750
6765
  if (typeof window === "undefined")
6751
6766
  return;
6752
- // JWT-wallet binding: refuse to store a session whose idToken is bound
6753
- // to a different wallet than `address`. Prevents races that would otherwise
6754
- // leave localStorage with mismatched address/token state.
6755
- try {
6756
- const payloadB64 = idToken.split(".")[1];
6757
- if (payloadB64) {
6758
- const payload = JSON.parse(this.decodeBase64Url(payloadB64));
6759
- const tokenWallet = payload["custom:walletAddress"];
6760
- if (tokenWallet && tokenWallet !== address) {
6761
- throw new Error(`[WebSessionManager] Refusing to store session: address (${address}) does not match idToken custom:walletAddress (${tokenWallet})`);
6762
- }
6763
- if (!tokenWallet) {
6764
- console.warn("[WebSessionManager] storeSession: idToken has no custom:walletAddress claim — writing without validation");
6765
- }
6766
- }
6767
- }
6768
- catch (err) {
6769
- if (typeof (err === null || err === void 0 ? void 0 : err.message) === "string" && err.message.includes("Refusing to store session")) {
6770
- throw err;
6771
- }
6772
- console.warn("[WebSessionManager] storeSession: failed to decode idToken for validation:", err);
6773
- }
6774
6767
  const config = await getConfig();
6775
6768
  const currentAppId = config.appId;
6776
6769
  localStorage.setItem(this.TAROBASE_SESSION_STORAGE_KEY, JSON.stringify({
@@ -9469,11 +9462,11 @@ function requireSrc$1 () {
9469
9462
  }
9470
9463
 
9471
9464
  var bs58$1;
9472
- var hasRequiredBs58;
9465
+ var hasRequiredBs58$1;
9473
9466
 
9474
- function requireBs58 () {
9475
- if (hasRequiredBs58) return bs58$1;
9476
- hasRequiredBs58 = 1;
9467
+ function requireBs58$1 () {
9468
+ if (hasRequiredBs58$1) return bs58$1;
9469
+ hasRequiredBs58$1 = 1;
9477
9470
  var basex = requireSrc$1();
9478
9471
  var ALPHABET = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz';
9479
9472
 
@@ -9481,8 +9474,8 @@ function requireBs58 () {
9481
9474
  return bs58$1;
9482
9475
  }
9483
9476
 
9484
- var bs58Exports = requireBs58();
9485
- var bs58 = /*@__PURE__*/getDefaultExportFromCjs(bs58Exports);
9477
+ var bs58Exports$1 = requireBs58$1();
9478
+ var bs58$2 = /*@__PURE__*/getDefaultExportFromCjs(bs58Exports$1);
9486
9479
 
9487
9480
  // ─────────────────────────────────────────────────────────────
9488
9481
  // Local implementation of getSimulationComputeUnits
@@ -9744,7 +9737,7 @@ function loadKeypairFromEnv() {
9744
9737
  try {
9745
9738
  const secretKey = secret.trim().startsWith("[")
9746
9739
  ? Uint8Array.from(JSON.parse(secret))
9747
- : bs58.decode(secret.trim());
9740
+ : bs58$2.decode(secret.trim());
9748
9741
  return Keypair.fromSecretKey(secretKey);
9749
9742
  }
9750
9743
  catch (err) {
@@ -11689,28 +11682,6 @@ class ReactNativeSessionManager {
11689
11682
  /* STORE */
11690
11683
  /* ------------------------------------------------------------------ */
11691
11684
  static async storeSession(address, accessToken, idToken, refreshToken) {
11692
- // JWT-wallet binding: refuse to store a session whose idToken is bound
11693
- // to a different wallet than `address`. Prevents races that would otherwise
11694
- // leave storage with mismatched address/token state.
11695
- try {
11696
- const payloadB64 = idToken.split(".")[1];
11697
- if (payloadB64) {
11698
- const payload = JSON.parse(this.decodeBase64Url(payloadB64));
11699
- const tokenWallet = payload["custom:walletAddress"];
11700
- if (tokenWallet && tokenWallet !== address) {
11701
- throw new Error(`[ReactNativeSessionManager] Refusing to store session: address (${address}) does not match idToken custom:walletAddress (${tokenWallet})`);
11702
- }
11703
- if (!tokenWallet) {
11704
- console.warn("[ReactNativeSessionManager] storeSession: idToken has no custom:walletAddress claim — writing without validation");
11705
- }
11706
- }
11707
- }
11708
- catch (err) {
11709
- if (typeof (err === null || err === void 0 ? void 0 : err.message) === "string" && err.message.includes("Refusing to store session")) {
11710
- throw err;
11711
- }
11712
- console.warn("[ReactNativeSessionManager] storeSession: failed to decode idToken for validation:", err);
11713
- }
11714
11685
  const config = await getConfig();
11715
11686
  const currentAppId = config.appId;
11716
11687
  this.getStorage().setItem(this.TAROBASE_SESSION_STORAGE_KEY, JSON.stringify({
@@ -15709,7 +15680,7 @@ async function loadDependencies() {
15709
15680
  const [reactModule, reactDomModule, phantomModule] = await Promise.all([
15710
15681
  import('react'),
15711
15682
  import('react-dom/client'),
15712
- import('./index-Cfp30Jm_.esm.js')
15683
+ import('./index-BfsQaxom.esm.js')
15713
15684
  ]);
15714
15685
  // Extract default export from ESM module namespace
15715
15686
  // Dynamic import() returns { default: Module, ...exports }, not the module directly
@@ -20367,16 +20338,26 @@ function requireSrc () {
20367
20338
  return src;
20368
20339
  }
20369
20340
 
20370
- var srcExports = requireSrc();
20371
- var basex = /*@__PURE__*/getDefaultExportFromCjs$1(srcExports);
20341
+ var bs58;
20342
+ var hasRequiredBs58;
20372
20343
 
20373
- var ALPHABET = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz';
20374
- var base58 = basex(ALPHABET);
20344
+ function requireBs58 () {
20345
+ if (hasRequiredBs58) return bs58;
20346
+ hasRequiredBs58 = 1;
20347
+ var basex = requireSrc();
20348
+ var ALPHABET = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz';
20349
+
20350
+ bs58 = basex(ALPHABET);
20351
+ return bs58;
20352
+ }
20353
+
20354
+ var bs58Exports = requireBs58();
20355
+ var base58 = /*@__PURE__*/getDefaultExportFromCjs$1(bs58Exports);
20375
20356
 
20376
- var index = /*#__PURE__*/Object.freeze({
20357
+ var index = /*#__PURE__*/_mergeNamespaces({
20377
20358
  __proto__: null,
20378
20359
  default: base58
20379
- });
20360
+ }, [bs58Exports]);
20380
20361
 
20381
20362
  const SURFNET_RPC_URL$1 = "https://surfpool.fly.dev";
20382
20363
  let React;
@@ -21265,6 +21246,14 @@ var privyWalletProvider = /*#__PURE__*/Object.freeze({
21265
21246
  PrivyWalletProvider: PrivyWalletProvider
21266
21247
  });
21267
21248
 
21249
+ /**
21250
+ * Storage key for persisting the MWA auth_token across cold starts.
21251
+ * Holds JSON `{ token: string, address: string }`. Cleared by
21252
+ * `logout()`. Hydrated by the constructor on native so cold-start
21253
+ * doesn't force the user back into Phantom's approval flow when the
21254
+ * underlying wallet authorization is still valid.
21255
+ */
21256
+ const MWA_AUTH_TOKEN_STORAGE_KEY = 'tarobase_mwa_auth_token';
21268
21257
  /**
21269
21258
  * Detects whether the current environment is a mobile browser capable of
21270
21259
  * Mobile Wallet Adapter (MWA) communication.
@@ -21392,13 +21381,13 @@ async function withMwaAssociationRetry(fn) {
21392
21381
  * next tap is a new activation (a real retry). A timer-based retry would
21393
21382
  * just hit the same Chrome block. Cap at 3 attempts before giving up.
21394
21383
  */
21395
- async function awaitSignInGestureAndSign(theme, signFn) {
21384
+ async function awaitSignInGestureAndSign(theme, signFn, noResultError = 'MWA returned no signature') {
21396
21385
  if (typeof document === 'undefined' || typeof window === 'undefined') {
21397
21386
  // SSR / non-browser: skip the gesture, just call (the activation
21398
21387
  // model doesn't apply outside the browser).
21399
21388
  const results = await signFn();
21400
21389
  if (!results || results.length === 0)
21401
- throw new Error('MWA returned no signature');
21390
+ throw new Error(noResultError);
21402
21391
  return results[0];
21403
21392
  }
21404
21393
  return new Promise((resolve, reject) => {
@@ -21590,7 +21579,7 @@ async function awaitSignInGestureAndSign(theme, signFn) {
21590
21579
  // launchAssociation(). Do not `await` before calling.
21591
21580
  signFn().then((results) => {
21592
21581
  if (!results || results.length === 0) {
21593
- finishReject(new Error('MWA returned no signature'));
21582
+ finishReject(new Error(noResultError));
21594
21583
  return;
21595
21584
  }
21596
21585
  finishResolve(results[0]);
@@ -21618,6 +21607,31 @@ async function awaitSignInGestureAndSign(theme, signFn) {
21618
21607
  });
21619
21608
  });
21620
21609
  }
21610
+ /**
21611
+ * Sign through the gesture modal ONLY when transient user activation has
21612
+ * already decayed. Fast transactions still hold the activation from the
21613
+ * user's tap, so the `solana-wallet:` navigation succeeds directly with no
21614
+ * modal (preserves prior UX — no extra tap). Slow transactions — e.g. a swap
21615
+ * whose server-side build exceeds Chrome's ~5s activation window — have lost
21616
+ * it, so we fall back to awaitSignInGestureAndSign to mint a fresh activation
21617
+ * via a "Sign in" tap. Returns the first result (same shape as the bare
21618
+ * wallet-standard feature call and as awaitSignInGestureAndSign).
21619
+ */
21620
+ async function signWithFreshActivation(theme, signFn, noResultError = 'MWA returned no signature') {
21621
+ var _a;
21622
+ const activationLive = typeof navigator !== 'undefined' &&
21623
+ ((_a = navigator.userActivation) === null || _a === void 0 ? void 0 : _a.isActive) === true;
21624
+ if (activationLive) {
21625
+ // Live gesture: invoke synchronously (no await before signFn) so the
21626
+ // activation propagates to the protocol's location.assign navigation.
21627
+ const results = await signFn();
21628
+ if (!results || results.length === 0)
21629
+ throw new Error(noResultError);
21630
+ return results[0];
21631
+ }
21632
+ // Activation gone: surface the modal so the user's tap mints a fresh one.
21633
+ return awaitSignInGestureAndSign(theme, signFn, noResultError);
21634
+ }
21621
21635
  /**
21622
21636
  * Normalize a chain string to a wallet-standard Solana chain identifier.
21623
21637
  *
@@ -21759,7 +21773,7 @@ async function registerMobileWalletAdapter(config) {
21759
21773
  if (typeof window === 'undefined')
21760
21774
  return;
21761
21775
  try {
21762
- const walletStandardMobile = await import('./index.browser-C9gHoUen.esm.js');
21776
+ const walletStandardMobile = await import('./index.browser-CMijwVwX.esm.js');
21763
21777
  const registerMwa = walletStandardMobile.registerMwa || ((_a = walletStandardMobile.default) === null || _a === void 0 ? void 0 : _a.registerMwa);
21764
21778
  if (!registerMwa) {
21765
21779
  console.warn('[SolanaMobileWallet] registerMwa not found in @solana-mobile/wallet-standard-mobile');
@@ -21826,19 +21840,66 @@ class SolanaMobileWalletProvider {
21826
21840
  constructor(networkUrl = null, config = {}) {
21827
21841
  /** LocalSolanaMobileWalletAdapterWallet, lazy-constructed in ensureWallet(). */
21828
21842
  this.wallet = null;
21843
+ /**
21844
+ * Cached MWA auth_token returned by `wallet.authorize()`. Reused by
21845
+ * subsequent native transact() calls (signMessage / signTransaction)
21846
+ * so the user doesn't get the wallet-pick popup on every operation.
21847
+ * Persisted to platform storage and hydrated by the constructor on
21848
+ * native; cleared by logout() and on `ERROR_REAUTHORIZE`.
21849
+ */
21850
+ this.nativeAuthToken = null;
21851
+ /** Cached public key string for the connected MWA wallet (native). */
21852
+ this.nativeAddress = null;
21829
21853
  this.networkUrl = networkUrl;
21830
21854
  this.config = config;
21831
- if (typeof window === 'undefined') {
21855
+ // Allow construction in true React Native environments: getPlatform().hasDOM
21856
+ // is false there even though `typeof window === 'object'` (RN exposes a
21857
+ // partial window global). Web/PWA paths still keep their original guard:
21858
+ // they need real window+document for wallet-standard-mobile's deep-link
21859
+ // mechanism, so missing-window in those builds remains a fail-fast.
21860
+ const hasDOM = getPlatform().hasDOM;
21861
+ if (!hasDOM && typeof window === 'undefined') {
21862
+ throw new Error('SolanaMobileWalletProvider can only be instantiated in a browser or React Native environment');
21863
+ }
21864
+ if (hasDOM && typeof window === 'undefined') {
21832
21865
  throw new Error('SolanaMobileWalletProvider can only be instantiated in a browser environment');
21833
21866
  }
21834
21867
  if (SolanaMobileWalletProvider.instance) {
21835
21868
  return SolanaMobileWalletProvider.instance;
21836
21869
  }
21870
+ // `appIdentity.uri` is what Phantom Android (and other MWA wallets)
21871
+ // display in their approval modal. On web/PWA this is the page
21872
+ // origin; on native there's no `window.location`, so fall back to
21873
+ // a stable identifier the user can recognize. Apps can override
21874
+ // entirely via `config.appIdentity.uri`.
21875
+ const fallbackUri = hasDOM
21876
+ ? getPlatform().getLocationOrigin()
21877
+ : 'tarobase://app';
21837
21878
  this.appIdentity = config.appIdentity || {
21838
21879
  name: 'TaroBase App',
21839
- uri: getPlatform().getLocationOrigin(),
21880
+ uri: fallbackUri,
21840
21881
  };
21841
21882
  this.cluster = config.cluster || 'mainnet-beta';
21883
+ // Hydrate cached MWA auth_token from storage on native so we can
21884
+ // skip the wallet-pick popup after a cold-start when the underlying
21885
+ // wallet authorization is still valid. Sync storage call per the
21886
+ // PlatformAdapter contract; safe to swallow read errors (a fresh
21887
+ // login() just re-authorizes).
21888
+ if (!hasDOM) {
21889
+ try {
21890
+ const raw = getPlatform().storage.getItem(MWA_AUTH_TOKEN_STORAGE_KEY);
21891
+ if (raw) {
21892
+ const parsed = JSON.parse(raw);
21893
+ if (typeof parsed.token === 'string' && typeof parsed.address === 'string') {
21894
+ this.nativeAuthToken = parsed.token;
21895
+ this.nativeAddress = parsed.address;
21896
+ }
21897
+ }
21898
+ }
21899
+ catch (_a) {
21900
+ // Corrupt or unreadable cache — ignore. login() will re-auth.
21901
+ }
21902
+ }
21842
21903
  SolanaMobileWalletProvider.instance = this;
21843
21904
  }
21844
21905
  static getInstance(networkUrl, config) {
@@ -21851,7 +21912,7 @@ class SolanaMobileWalletProvider {
21851
21912
  async ensureWallet() {
21852
21913
  if (this.wallet)
21853
21914
  return this.wallet;
21854
- const mod = await import('./index.browser-C9gHoUen.esm.js');
21915
+ const mod = await import('./index.browser-CMijwVwX.esm.js');
21855
21916
  const chain = mapChainToWalletStandard(this.cluster);
21856
21917
  this.wallet = new mod.LocalSolanaMobileWalletAdapterWallet({
21857
21918
  appIdentity: this.appIdentity,
@@ -21901,6 +21962,134 @@ class SolanaMobileWalletProvider {
21901
21962
  getChain() {
21902
21963
  return mapChainToWalletStandard(this.cluster);
21903
21964
  }
21965
+ /**
21966
+ * Dynamically import and unwrap `transact` from the MWA web3js
21967
+ * package. The package is externalized in rollup.config.js so this
21968
+ * resolves to `lib/cjs/index.native.js` (TurboModule-backed) on
21969
+ * Metro and `lib/esm/index.browser.js` (WebSocket) on webpack/vite
21970
+ * per their respective platform conditions. Handles Metro's CJS-to-
21971
+ * ESM interop variance (`mod.transact` vs `mod.default?.transact`).
21972
+ */
21973
+ async loadTransact() {
21974
+ var _a;
21975
+ const mod = await import('@solana-mobile/mobile-wallet-adapter-protocol-web3js');
21976
+ const t = mod.transact || ((_a = mod.default) === null || _a === void 0 ? void 0 : _a.transact);
21977
+ if (typeof t !== 'function') {
21978
+ throw new Error('MWA transact API not available on this platform');
21979
+ }
21980
+ return t;
21981
+ }
21982
+ /**
21983
+ * Cache and persist a fresh MWA auth_token + address. Called from
21984
+ * `_loginNative` after a successful authorize. Storage failures are
21985
+ * non-fatal (next cold-start re-auths).
21986
+ */
21987
+ persistNativeAuth(token, address) {
21988
+ this.nativeAuthToken = token;
21989
+ this.nativeAddress = address;
21990
+ try {
21991
+ getPlatform().storage.setItem(MWA_AUTH_TOKEN_STORAGE_KEY, JSON.stringify({ token, address }));
21992
+ }
21993
+ catch (_a) {
21994
+ // non-fatal — token still in-memory for this process
21995
+ }
21996
+ }
21997
+ /** Clear cached + persisted native auth state. */
21998
+ clearNativeAuth() {
21999
+ this.nativeAuthToken = null;
22000
+ this.nativeAddress = null;
22001
+ try {
22002
+ getPlatform().storage.removeItem(MWA_AUTH_TOKEN_STORAGE_KEY);
22003
+ }
22004
+ catch (_a) {
22005
+ // ignore
22006
+ }
22007
+ }
22008
+ /**
22009
+ * Classify an MWA-native error as a user cancellation. User-cancel
22010
+ * shouldn't surface as a red console.error; callers can swallow or
22011
+ * show a softer message. MWA spec codes plus the same substring
22012
+ * checks the web path uses to catch wallet-specific phrasing.
22013
+ */
22014
+ isNativeUserCancel(err) {
22015
+ var _a;
22016
+ if (!err)
22017
+ return false;
22018
+ const code = err.code;
22019
+ if (code === 'ERROR_NOT_SIGNED')
22020
+ return true;
22021
+ const msg = String((_a = err.message) !== null && _a !== void 0 ? _a : '').toLowerCase();
22022
+ return /user (rejected|denied|cancelled|canceled|declined)/.test(msg);
22023
+ }
22024
+ /**
22025
+ * Native MWA login via @solana-mobile/mobile-wallet-adapter-protocol-web3js.
22026
+ * Used in true React Native (Expo) environments where wallet-standard-mobile's
22027
+ * web universal-link path doesn't apply. Does authorize + signMessage in a
22028
+ * single transact() roundtrip — intent-based MWA doesn't need the two-popup
22029
+ * dance the web path uses (no Chrome activation-loss concern). Persists the
22030
+ * resulting auth_token so cold-start can reauthorize without a fresh popup.
22031
+ */
22032
+ async _loginNative() {
22033
+ const transact = await this.loadTransact();
22034
+ const existingSession = await WebSessionManager.getSession();
22035
+ const nonce = await genAuthNonce();
22036
+ const result = await transact(async (wallet) => {
22037
+ const auth = await wallet.authorize({
22038
+ chain: this.getChain(),
22039
+ identity: this.appIdentity,
22040
+ });
22041
+ if (!auth.accounts || auth.accounts.length === 0) {
22042
+ throw new Error('MWA returned no accounts');
22043
+ }
22044
+ const account = auth.accounts[0];
22045
+ // account.address is base64-encoded per MWA spec; convert to
22046
+ // the base58 form Tarobase + the rest of the SDK use.
22047
+ const base58Addr = new PublicKey(bufferExports.Buffer.from(account.address, 'base64')).toBase58();
22048
+ // Reuse session if already valid for this address — skip the
22049
+ // signMessages roundtrip entirely.
22050
+ if (existingSession && existingSession.address === base58Addr) {
22051
+ return {
22052
+ base58Addr,
22053
+ authToken: auth.auth_token,
22054
+ signatureBase64: null,
22055
+ };
22056
+ }
22057
+ const messageText = await genSolanaMessage(base58Addr, nonce);
22058
+ const messageBytes = getPlatform().textEncode(messageText);
22059
+ const signatures = await wallet.signMessages({
22060
+ addresses: [account.address],
22061
+ payloads: [messageBytes],
22062
+ });
22063
+ if (!signatures || signatures.length === 0) {
22064
+ throw new Error('MWA returned no signature');
22065
+ }
22066
+ // Per spec, signMessages returns Uint8Array[] of signatures
22067
+ // (one per payload), not message+signature concatenations.
22068
+ const signatureBase64 = bufferExports.Buffer.from(signatures[0]).toString('base64');
22069
+ return {
22070
+ base58Addr,
22071
+ authToken: auth.auth_token,
22072
+ signatureBase64,
22073
+ messageText,
22074
+ };
22075
+ });
22076
+ this.persistNativeAuth(result.authToken, result.base58Addr);
22077
+ // Existing valid session — short-circuit before re-creating server-side.
22078
+ if (existingSession && existingSession.address === result.base58Addr) {
22079
+ const user = { provider: this, address: result.base58Addr };
22080
+ setCurrentUser(user);
22081
+ return user;
22082
+ }
22083
+ // Create Tarobase session on the server.
22084
+ if (!result.signatureBase64 || !result.messageText) {
22085
+ throw new Error('MWA login completed without signature');
22086
+ }
22087
+ const createSessionResult = await createSessionWithSignature(result.base58Addr, result.messageText, result.signatureBase64);
22088
+ await WebSessionManager.storeSession(result.base58Addr, createSessionResult.accessToken, createSessionResult.idToken, createSessionResult.refreshToken);
22089
+ const user = { provider: this, address: result.base58Addr };
22090
+ setCurrentUser(user);
22091
+ return user;
22092
+ }
21904
22093
  async login() {
21905
22094
  var _a, _b, _c, _d, _e;
21906
22095
  setAuthLoading(true);
@@ -21911,6 +22100,13 @@ class SolanaMobileWalletProvider {
21911
22100
  const prevAuthMethod = readAuthMethod();
21912
22101
  writeAuthMethod(MWA_AUTH_METHOD);
21913
22102
  try {
22103
+ // True React Native: skip the wallet-standard-mobile path (which
22104
+ // requires window.isSecureContext and a real DOM) and use the raw
22105
+ // MWA protocol via Android intents.
22106
+ if (!getPlatform().hasDOM) {
22107
+ const user = await this._loginNative();
22108
+ return user;
22109
+ }
21914
22110
  const wallet = await this.ensureWallet();
21915
22111
  // Quick-check: wallet may already have authorization (e.g. from a
21916
22112
  // previous in-page login) and a matching Tarobase session — skip
@@ -22012,6 +22208,29 @@ class SolanaMobileWalletProvider {
22012
22208
  return null;
22013
22209
  }
22014
22210
  async logout() {
22211
+ if (!getPlatform().hasDOM) {
22212
+ // Native path: deauthorize the cached MWA auth_token if we have
22213
+ // one (failures non-fatal — the wallet app may have been
22214
+ // uninstalled or the token already revoked), then clear local
22215
+ // and persisted state.
22216
+ const token = this.nativeAuthToken;
22217
+ if (token) {
22218
+ try {
22219
+ const transact = await this.loadTransact();
22220
+ await transact(async (wallet) => {
22221
+ await wallet.deauthorize({ auth_token: token });
22222
+ });
22223
+ }
22224
+ catch (error) {
22225
+ console.warn('[SolanaMobileWallet] Native deauthorize error:', error);
22226
+ }
22227
+ }
22228
+ this.clearNativeAuth();
22229
+ WebSessionManager.clearSession();
22230
+ writeAuthMethod(null);
22231
+ setCurrentUser(null);
22232
+ return;
22233
+ }
22015
22234
  try {
22016
22235
  const wallet = await this.ensureWallet();
22017
22236
  const disconnectFeat = getDisconnectFeature(wallet);
@@ -22031,7 +22250,42 @@ class SolanaMobileWalletProvider {
22031
22250
  setCurrentUser(null);
22032
22251
  }
22033
22252
  async signMessage(message) {
22034
- var _a, _b;
22253
+ var _a, _b, _c;
22254
+ // Native: reauthorize with cached auth_token, then signMessages inside
22255
+ // the same transact() session. No wallet-pick popup if the auth_token
22256
+ // is still valid for the user's wallet.
22257
+ if (!getPlatform().hasDOM) {
22258
+ if (!this.nativeAuthToken || !this.nativeAddress) {
22259
+ throw new Error('Wallet not connected. Call login() first.');
22260
+ }
22261
+ const transact = await this.loadTransact();
22262
+ const messageBytes = getPlatform().textEncode(message);
22263
+ const addressBase64 = new PublicKey(this.nativeAddress).toBuffer().toString('base64');
22264
+ const authToken = this.nativeAuthToken;
22265
+ try {
22266
+ const signature = await transact(async (wallet) => {
22267
+ await wallet.reauthorize({ auth_token: authToken, identity: this.appIdentity });
22268
+ const sigs = await wallet.signMessages({
22269
+ addresses: [addressBase64],
22270
+ payloads: [messageBytes],
22271
+ });
22272
+ if (!sigs || sigs.length === 0)
22273
+ throw new Error('MWA returned no signature');
22274
+ return sigs[0];
22275
+ });
22276
+ return bufferExports.Buffer.from(signature).toString('base64');
22277
+ }
22278
+ catch (error) {
22279
+ if (this.isNativeUserCancel(error)) {
22280
+ throw new Error('User declined to sign');
22281
+ }
22282
+ if ((error === null || error === void 0 ? void 0 : error.code) === 'ERROR_AUTHORIZATION_FAILED' || (error === null || error === void 0 ? void 0 : error.code) === 'ERROR_REAUTHORIZE') {
22283
+ await this.logout();
22284
+ throw new Error('Wallet connection lost. Please reconnect.');
22285
+ }
22286
+ throw new Error(`Failed to sign message: ${(_a = error === null || error === void 0 ? void 0 : error.message) !== null && _a !== void 0 ? _a : error}`);
22287
+ }
22288
+ }
22035
22289
  const account = await this.ensureAuthorized();
22036
22290
  const wallet = await this.ensureWallet();
22037
22291
  try {
@@ -22045,7 +22299,7 @@ class SolanaMobileWalletProvider {
22045
22299
  return bufferExports.Buffer.from(sigBytes).toString('base64');
22046
22300
  }
22047
22301
  catch (error) {
22048
- 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')) ||
22302
+ 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')) ||
22049
22303
  (error === null || error === void 0 ? void 0 : error.code) === 'ERROR_AUTHORIZATION_FAILED') {
22050
22304
  await this.logout();
22051
22305
  throw new Error('Wallet connection lost. Please reconnect.');
@@ -22054,7 +22308,58 @@ class SolanaMobileWalletProvider {
22054
22308
  }
22055
22309
  }
22056
22310
  async signTransaction(transaction) {
22057
- var _a, _b;
22311
+ var _a, _b, _c;
22312
+ // Native: fill blockhash/feePayer if missing, then signTransactions
22313
+ // inside a transact() session keyed by the cached auth_token.
22314
+ if (!getPlatform().hasDOM) {
22315
+ if (!this.nativeAuthToken || !this.nativeAddress) {
22316
+ throw new Error('Wallet not connected. Call login() first.');
22317
+ }
22318
+ const connectedPubkey = new PublicKey(this.nativeAddress);
22319
+ const isLegacyTransaction = 'recentBlockhash' in transaction && !('message' in transaction && 'staticAccountKeys' in transaction.message);
22320
+ if (isLegacyTransaction) {
22321
+ const legacyTx = transaction;
22322
+ if (!legacyTx.recentBlockhash) {
22323
+ const conn = new Connection(this.getRpcUrl(), 'confirmed');
22324
+ const { blockhash, lastValidBlockHeight } = await conn.getLatestBlockhash('confirmed');
22325
+ legacyTx.recentBlockhash = blockhash;
22326
+ legacyTx.lastValidBlockHeight = lastValidBlockHeight;
22327
+ }
22328
+ if (!legacyTx.feePayer) {
22329
+ legacyTx.feePayer = connectedPubkey;
22330
+ }
22331
+ }
22332
+ else {
22333
+ const versionedTx = transaction;
22334
+ if (!versionedTx.message.recentBlockhash) {
22335
+ const conn = new Connection(this.getRpcUrl(), 'confirmed');
22336
+ const { blockhash } = await conn.getLatestBlockhash('confirmed');
22337
+ versionedTx.message.recentBlockhash = blockhash;
22338
+ }
22339
+ }
22340
+ const transact = await this.loadTransact();
22341
+ const authToken = this.nativeAuthToken;
22342
+ try {
22343
+ const signed = await transact(async (wallet) => {
22344
+ await wallet.reauthorize({ auth_token: authToken, identity: this.appIdentity });
22345
+ const results = await wallet.signTransactions({ transactions: [transaction] });
22346
+ if (!results || results.length === 0)
22347
+ throw new Error('MWA returned no signed transaction');
22348
+ return results[0];
22349
+ });
22350
+ return signed;
22351
+ }
22352
+ catch (error) {
22353
+ if (this.isNativeUserCancel(error)) {
22354
+ throw new Error('User declined to sign');
22355
+ }
22356
+ if ((error === null || error === void 0 ? void 0 : error.code) === 'ERROR_AUTHORIZATION_FAILED' || (error === null || error === void 0 ? void 0 : error.code) === 'ERROR_REAUTHORIZE') {
22357
+ await this.logout();
22358
+ throw new Error('Wallet connection lost. Please reconnect.');
22359
+ }
22360
+ throw new Error(`Failed to sign transaction: ${(_a = error === null || error === void 0 ? void 0 : error.message) !== null && _a !== void 0 ? _a : error}`);
22361
+ }
22362
+ }
22058
22363
  const account = await this.ensureAuthorized();
22059
22364
  const connectedPubkey = new PublicKey(account.publicKey);
22060
22365
  const wallet = await this.ensureWallet();
@@ -22085,15 +22390,14 @@ class SolanaMobileWalletProvider {
22085
22390
  try {
22086
22391
  const signTxFeat = getSignTransactionFeature(wallet);
22087
22392
  const wireBytes = txToWireBytes(transaction);
22088
- const results = await signTxFeat.signTransaction({ account, transaction: wireBytes, chain });
22089
- if (!results || results.length === 0) {
22090
- throw new Error('MWA returned no signed transaction');
22091
- }
22092
- const { signedTransaction: signedBytes } = results[0];
22393
+ // signTransaction navigates to `solana-wallet:`; only show the
22394
+ // gesture modal if the tap activation has decayed (see runTransaction).
22395
+ const signResult = await signWithFreshActivation(this.config.theme, () => signTxFeat.signTransaction({ account, transaction: wireBytes, chain }), 'MWA returned no signed transaction');
22396
+ const { signedTransaction: signedBytes } = signResult;
22093
22397
  return txFromWireBytes(new Uint8Array(signedBytes));
22094
22398
  }
22095
22399
  catch (error) {
22096
- 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')) ||
22400
+ 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')) ||
22097
22401
  (error === null || error === void 0 ? void 0 : error.code) === 'ERROR_AUTHORIZATION_FAILED') {
22098
22402
  await this.logout();
22099
22403
  throw new Error('Wallet connection lost. Please reconnect.');
@@ -22102,7 +22406,70 @@ class SolanaMobileWalletProvider {
22102
22406
  }
22103
22407
  }
22104
22408
  async signAndSubmitTransaction(transaction, feePayer) {
22105
- var _a, _b, _c, _d, _e, _f;
22409
+ var _a, _b, _c, _d, _e, _f, _g;
22410
+ // Native: signAndSendTransactions inside a transact() session.
22411
+ // The wallet submits to its own RPC; we then await confirmation on
22412
+ // ours. Surfnet (custom RPC) needs manual submission because the
22413
+ // wallet won't route there — we fall back to sign-only + manual send.
22414
+ if (!getPlatform().hasDOM) {
22415
+ if (!this.nativeAuthToken || !this.nativeAddress) {
22416
+ throw new Error('Wallet not connected. Call login() first.');
22417
+ }
22418
+ const connectedPubkey = new PublicKey(this.nativeAddress);
22419
+ const rpcUrl = this.getRpcUrl();
22420
+ const connection = new Connection(rpcUrl, 'confirmed');
22421
+ const isSurfnet = rpcUrl === SURFNET_RPC_URL$2;
22422
+ const { blockhash, lastValidBlockHeight } = await connection.getLatestBlockhash('confirmed');
22423
+ const isLegacyTransaction = 'recentBlockhash' in transaction && !('message' in transaction && 'staticAccountKeys' in transaction.message);
22424
+ if (isLegacyTransaction) {
22425
+ const legacyTx = transaction;
22426
+ legacyTx.recentBlockhash = blockhash;
22427
+ legacyTx.lastValidBlockHeight = lastValidBlockHeight;
22428
+ if (!legacyTx.feePayer)
22429
+ legacyTx.feePayer = feePayer !== null && feePayer !== void 0 ? feePayer : connectedPubkey;
22430
+ }
22431
+ else {
22432
+ const versionedTx = transaction;
22433
+ versionedTx.message.recentBlockhash = blockhash;
22434
+ }
22435
+ const transact = await this.loadTransact();
22436
+ const authToken = this.nativeAuthToken;
22437
+ try {
22438
+ if (isSurfnet) {
22439
+ // Surfnet: sign only, submit manually to Surfnet RPC
22440
+ // (the wallet would route signAndSend to its own RPC).
22441
+ const signed = await transact(async (wallet) => {
22442
+ await wallet.reauthorize({ auth_token: authToken, identity: this.appIdentity });
22443
+ const results = await wallet.signTransactions({ transactions: [transaction] });
22444
+ if (!results || results.length === 0)
22445
+ throw new Error('MWA returned no signed transaction');
22446
+ return results[0];
22447
+ });
22448
+ const sig = await connection.sendRawTransaction(signed.serialize(), { preflightCommitment: 'confirmed' });
22449
+ await confirmAndCheckTransaction(connection, sig);
22450
+ return sig;
22451
+ }
22452
+ const sig = await transact(async (wallet) => {
22453
+ await wallet.reauthorize({ auth_token: authToken, identity: this.appIdentity });
22454
+ const results = await wallet.signAndSendTransactions({ transactions: [transaction] });
22455
+ if (!results || results.length === 0)
22456
+ throw new Error('MWA returned no signature');
22457
+ return results[0];
22458
+ });
22459
+ await confirmAndCheckTransaction(connection, sig);
22460
+ return sig;
22461
+ }
22462
+ catch (error) {
22463
+ if (this.isNativeUserCancel(error)) {
22464
+ throw new Error('User declined to sign');
22465
+ }
22466
+ if ((error === null || error === void 0 ? void 0 : error.code) === 'ERROR_AUTHORIZATION_FAILED' || (error === null || error === void 0 ? void 0 : error.code) === 'ERROR_REAUTHORIZE') {
22467
+ await this.logout();
22468
+ throw new Error('Wallet connection lost. Please reconnect.');
22469
+ }
22470
+ throw new Error(`Failed to sign+submit transaction: ${(_a = error === null || error === void 0 ? void 0 : error.message) !== null && _a !== void 0 ? _a : error}`);
22471
+ }
22472
+ }
22106
22473
  const account = await this.ensureAuthorized();
22107
22474
  const connectedPubkey = new PublicKey(account.publicKey);
22108
22475
  const wallet = await this.ensureWallet();
@@ -22132,11 +22499,9 @@ class SolanaMobileWalletProvider {
22132
22499
  // because the wallet would submit to its own RPC.
22133
22500
  const signTxFeat = getSignTransactionFeature(wallet);
22134
22501
  const wireBytes = txToWireBytes(transaction);
22135
- const results = await signTxFeat.signTransaction({ account, transaction: wireBytes, chain });
22136
- if (!results || results.length === 0) {
22137
- throw new Error('MWA returned no signed transaction');
22138
- }
22139
- const { signedTransaction: signedBytes } = results[0];
22502
+ // Gesture modal only if activation decayed (see runTransaction).
22503
+ const signResult = await signWithFreshActivation(this.config.theme, () => signTxFeat.signTransaction({ account, transaction: wireBytes, chain }), 'MWA returned no signed transaction');
22504
+ const { signedTransaction: signedBytes } = signResult;
22140
22505
  const signedTx = txFromWireBytes(new Uint8Array(signedBytes));
22141
22506
  const signature = await connection.sendRawTransaction(signedTx.serialize(), {
22142
22507
  preflightCommitment: 'confirmed',
@@ -22152,33 +22517,31 @@ class SolanaMobileWalletProvider {
22152
22517
  return signature;
22153
22518
  }
22154
22519
  // Non-Surfnet: wallet signs and submits to its own RPC.
22520
+ // Gesture modal only if activation decayed (see runTransaction).
22155
22521
  const signSendFeat = getSignAndSendTransactionFeature(wallet);
22156
22522
  const wireBytes = txToWireBytes(transaction);
22157
- const results = await signSendFeat.signAndSendTransaction({
22523
+ const sendResult = await signWithFreshActivation(this.config.theme, () => signSendFeat.signAndSendTransaction({
22158
22524
  account,
22159
22525
  transaction: wireBytes,
22160
22526
  chain,
22161
22527
  options: { commitment: 'confirmed' },
22162
- });
22163
- if (!results || results.length === 0) {
22164
- throw new Error('MWA returned no signature');
22165
- }
22166
- const { signature: sigBytes } = results[0];
22528
+ }));
22529
+ const { signature: sigBytes } = sendResult;
22167
22530
  const signature = base58.encode(sigBytes);
22168
22531
  await confirmAndCheckTransaction(connection, signature);
22169
22532
  return signature;
22170
22533
  }
22171
22534
  catch (error) {
22172
- 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')) ||
22535
+ 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')) ||
22173
22536
  (error === null || error === void 0 ? void 0 : error.code) === 'ERROR_AUTHORIZATION_FAILED') {
22174
22537
  await this.logout();
22175
22538
  throw new Error('Wallet connection lost. Please reconnect.');
22176
22539
  }
22177
22540
  const isUserRejection = (error === null || error === void 0 ? void 0 : error.code) === 4001 ||
22178
- ((_c = error === null || error === void 0 ? void 0 : error.message) === null || _c === void 0 ? void 0 : _c.toLowerCase().includes('user rejected')) ||
22179
- ((_d = error === null || error === void 0 ? void 0 : error.message) === null || _d === void 0 ? void 0 : _d.toLowerCase().includes('user denied')) ||
22180
- ((_e = error === null || error === void 0 ? void 0 : error.message) === null || _e === void 0 ? void 0 : _e.toLowerCase().includes('user cancelled')) ||
22181
- ((_f = error === null || error === void 0 ? void 0 : error.message) === null || _f === void 0 ? void 0 : _f.toLowerCase().includes('user canceled'));
22541
+ ((_d = error === null || error === void 0 ? void 0 : error.message) === null || _d === void 0 ? void 0 : _d.toLowerCase().includes('user rejected')) ||
22542
+ ((_e = error === null || error === void 0 ? void 0 : error.message) === null || _e === void 0 ? void 0 : _e.toLowerCase().includes('user denied')) ||
22543
+ ((_f = error === null || error === void 0 ? void 0 : error.message) === null || _f === void 0 ? void 0 : _f.toLowerCase().includes('user cancelled')) ||
22544
+ ((_g = error === null || error === void 0 ? void 0 : error.message) === null || _g === void 0 ? void 0 : _g.toLowerCase().includes('user canceled'));
22182
22545
  if (!isUserRejection) {
22183
22546
  console.error('[SolanaMobileWallet] Transaction failed:', error);
22184
22547
  }
@@ -22243,11 +22606,13 @@ class SolanaMobileWalletProvider {
22243
22606
  if ((options === null || options === void 0 ? void 0 : options.shouldSubmitTx) === false) {
22244
22607
  const signTxFeat = getSignTransactionFeature(wallet);
22245
22608
  const wireBytes = txToWireBytes(tx);
22246
- const results = await signTxFeat.signTransaction({ account, transaction: wireBytes, chain });
22247
- if (!results || results.length === 0) {
22609
+ // signTransaction also navigates to `solana-wallet:`; only
22610
+ // surface the gesture modal if the tap activation has decayed.
22611
+ const signOnlyResult = await signWithFreshActivation(this.config.theme, () => signTxFeat.signTransaction({ account, transaction: wireBytes, chain }), 'MWA returned no signed transaction');
22612
+ if (!signOnlyResult) {
22248
22613
  throw new Error('MWA returned no signed transaction');
22249
22614
  }
22250
- const { signedTransaction: signedBytes } = results[0];
22615
+ const { signedTransaction: signedBytes } = signOnlyResult;
22251
22616
  const signedTx = txFromWireBytes(new Uint8Array(signedBytes));
22252
22617
  return {
22253
22618
  signedTransaction: signedTx,
@@ -22260,11 +22625,13 @@ class SolanaMobileWalletProvider {
22260
22625
  // Surfnet: sign locally via wallet-standard, submit manually.
22261
22626
  const signTxFeat = getSignTransactionFeature(wallet);
22262
22627
  const wireBytes = txToWireBytes(tx);
22263
- const results = await signTxFeat.signTransaction({ account, transaction: wireBytes, chain });
22264
- if (!results || results.length === 0) {
22628
+ // signTransaction also navigates to `solana-wallet:`; only
22629
+ // surface the gesture modal if the tap activation has decayed.
22630
+ const surfnetResult = await signWithFreshActivation(this.config.theme, () => signTxFeat.signTransaction({ account, transaction: wireBytes, chain }), 'MWA returned no signed transaction');
22631
+ if (!surfnetResult) {
22265
22632
  throw new Error('MWA returned no signed transaction');
22266
22633
  }
22267
- const { signedTransaction: signedBytes } = results[0];
22634
+ const { signedTransaction: signedBytes } = surfnetResult;
22268
22635
  const signedTx = txFromWireBytes(new Uint8Array(signedBytes));
22269
22636
  const { blockhash, lastValidBlockHeight } = await connection.getLatestBlockhash('confirmed');
22270
22637
  const signature = await connection.sendRawTransaction(signedTx.serialize(), {
@@ -22290,18 +22657,24 @@ class SolanaMobileWalletProvider {
22290
22657
  };
22291
22658
  }
22292
22659
  // Non-Surfnet: wallet signs and submits to its own RPC.
22660
+ // signAndSendTransaction dispatches a `solana-wallet:` navigation
22661
+ // that Chrome blocks without transient user activation. Fast txs
22662
+ // still hold the tap activation and navigate directly; slow ones
22663
+ // (e.g. a swap whose server build exceeds Chrome's ~5s window)
22664
+ // have lost it, so signWithFreshActivation shows the "Sign in"
22665
+ // modal to mint a fresh activation — no modal when not needed.
22293
22666
  const signSendFeat = getSignAndSendTransactionFeature(wallet);
22294
22667
  const wireBytes = txToWireBytes(tx);
22295
- const results = await signSendFeat.signAndSendTransaction({
22668
+ const sendResult = await signWithFreshActivation(this.config.theme, () => signSendFeat.signAndSendTransaction({
22296
22669
  account,
22297
22670
  transaction: wireBytes,
22298
22671
  chain,
22299
22672
  options: { commitment: 'confirmed' },
22300
- });
22301
- if (!results || results.length === 0) {
22673
+ }));
22674
+ if (!sendResult) {
22302
22675
  throw new Error('MWA returned no signature');
22303
22676
  }
22304
- const { signature: sigBytes } = results[0];
22677
+ const { signature: sigBytes } = sendResult;
22305
22678
  const signature = base58.encode(sigBytes);
22306
22679
  const txInfo = await confirmAndCheckTransaction(connection, signature);
22307
22680
  return {
@@ -22728,5 +23101,5 @@ class PrivyExpoProvider {
22728
23101
  }
22729
23102
  }
22730
23103
 
22731
- export { getCachedData as $, subscribe as A, useAuth as B, deserializeTransaction as C, getIdToken as D, setPlatform as E, getPlatform as F, PrivyWalletProvider as G, DEFAULT_TEST_ADDRESS as H, isMobileWalletAvailable as I, registerMobileWalletAdapter as J, PrivyExpoProvider as K, InsufficientBalanceError as L, MockAuthProvider as M, ServerSessionManager as N, OffchainAuthProvider as O, PhantomWalletProvider as P, buildSetDocumentsTransaction as Q, ReactNativeSessionManager as R, SolanaMobileWalletProvider as S, clearCache as T, closeAllSubscriptions as U, convertRemainingAccounts as V, WebSessionManager as W, createSessionWithPrivy as X, createSessionWithSignature as Y, genAuthNonce as Z, genSolanaMessage as _, base58 as a, getMany as a0, reconnectWithNewAuth as a1, refreshSession as a2, signSessionCreateMessage as a3, bufferExports as b, getCurrentUser as c, onAuthLoadingChanged as d, getAuthLoading as e, logout as f, getDefaultExportFromCjs$1 as g, getConfig as h, init as i, getAuthProvider as j, get as k, login as l, setMany as m, setFile as n, onAuthStateChanged as o, getFiles as p, runQueryMany as q, runQuery as r, set as s, runExpression as t, runExpressionMany as u, signMessage as v, signTransaction as w, signAndSubmitTransaction as x, count as y, aggregate as z };
22732
- //# sourceMappingURL=index-BQUfNEiY.esm.js.map
23104
+ export { genAuthNonce as $, count as A, aggregate as B, subscribe as C, useAuth as D, deserializeTransaction as E, getIdToken as F, setPlatform as G, getPlatform as H, PrivyWalletProvider as I, DEFAULT_TEST_ADDRESS as J, isMobileWalletAvailable as K, registerMobileWalletAdapter as L, MockAuthProvider as M, PrivyExpoProvider as N, OffchainAuthProvider as O, PhantomWalletProvider as P, InsufficientBalanceError as Q, ReactNativeSessionManager as R, SolanaMobileWalletProvider as S, ServerSessionManager as T, buildSetDocumentsTransaction as U, clearCache as V, WebSessionManager as W, closeAllSubscriptions as X, convertRemainingAccounts as Y, createSessionWithPrivy as Z, createSessionWithSignature as _, base58 as a, genSolanaMessage as a0, getCachedData as a1, getMany as a2, reconnectWithNewAuth as a3, refreshSession as a4, signSessionCreateMessage as a5, bufferExports as b, commonjsRequire as c, getCurrentUser as d, onAuthLoadingChanged as e, getAuthLoading as f, getDefaultExportFromCjs$1 as g, logout as h, init as i, getConfig as j, getAuthProvider as k, login as l, get as m, setMany as n, onAuthStateChanged as o, setFile as p, getFiles as q, require$$0 as r, set as s, runQuery as t, runQueryMany as u, runExpression as v, runExpressionMany as w, signMessage as x, signTransaction as y, signAndSubmitTransaction as z };
23105
+ //# sourceMappingURL=index-CJRFnq6O.esm.js.map