@pooflabs/web 0.0.67 → 0.0.69-rc.1

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.
@@ -10600,8 +10600,6 @@ async function getOrCreateConnection(appId, isServer) {
10600
10600
  isConnected: false,
10601
10601
  appId,
10602
10602
  tokenRefreshTimer: null,
10603
- lastMessageAt: Date.now(),
10604
- keepaliveTimer: null,
10605
10603
  consecutiveAuthFailures: 0,
10606
10604
  };
10607
10605
  connections.set(appId, connection);
@@ -10653,7 +10651,6 @@ async function getOrCreateConnection(appId, isServer) {
10653
10651
  ws.addEventListener('open', () => {
10654
10652
  connection.isConnecting = false;
10655
10653
  connection.isConnected = true;
10656
- connection.lastMessageAt = Date.now();
10657
10654
  connection.consecutiveAuthFailures = 0;
10658
10655
  // Schedule periodic token freshness checks
10659
10656
  scheduleTokenRefresh(connection, isServer);
@@ -10662,25 +10659,9 @@ async function getOrCreateConnection(appId, isServer) {
10662
10659
  sub.lastData = undefined;
10663
10660
  sendSubscribe(connection, sub);
10664
10661
  }
10665
- // Start keepalive detection — if no messages for 90s, force reconnect
10666
- if (connection.keepaliveTimer) {
10667
- clearInterval(connection.keepaliveTimer);
10668
- }
10669
- connection.keepaliveTimer = setInterval(() => {
10670
- var _a;
10671
- if (Date.now() - connection.lastMessageAt > 90000) {
10672
- console.warn('[WS v2] No messages received for 90s, forcing reconnect');
10673
- if (connection.keepaliveTimer) {
10674
- clearInterval(connection.keepaliveTimer);
10675
- connection.keepaliveTimer = null;
10676
- }
10677
- (_a = connection.ws) === null || _a === void 0 ? void 0 : _a.reconnect();
10678
- }
10679
- }, 30000);
10680
10662
  });
10681
10663
  // Handle incoming messages
10682
10664
  ws.addEventListener('message', (event) => {
10683
- connection.lastMessageAt = Date.now();
10684
10665
  try {
10685
10666
  const message = JSON.parse(event.data);
10686
10667
  handleServerMessage(connection, message);
@@ -10704,10 +10685,6 @@ async function getOrCreateConnection(appId, isServer) {
10704
10685
  clearInterval(connection.tokenRefreshTimer);
10705
10686
  connection.tokenRefreshTimer = null;
10706
10687
  }
10707
- if (connection.keepaliveTimer) {
10708
- clearInterval(connection.keepaliveTimer);
10709
- connection.keepaliveTimer = null;
10710
- }
10711
10688
  });
10712
10689
  return connection;
10713
10690
  }
@@ -10780,7 +10757,10 @@ function handleServerMessage(connection, message) {
10780
10757
  }
10781
10758
  function notifyCallbacks(subscription, data) {
10782
10759
  var _a;
10783
- for (const callback of subscription.callbacks) {
10760
+ // Snapshot the callbacks array so that unsubscriptions during
10761
+ // notification don't cause callbacks to be skipped.
10762
+ const callbacks = subscription.callbacks.slice();
10763
+ for (const callback of callbacks) {
10784
10764
  try {
10785
10765
  (_a = callback.onData) === null || _a === void 0 ? void 0 : _a.call(callback, data);
10786
10766
  }
@@ -10965,10 +10945,6 @@ async function closeAllSubscriptionsV2() {
10965
10945
  clearInterval(connection.tokenRefreshTimer);
10966
10946
  connection.tokenRefreshTimer = null;
10967
10947
  }
10968
- if (connection.keepaliveTimer) {
10969
- clearInterval(connection.keepaliveTimer);
10970
- connection.keepaliveTimer = null;
10971
- }
10972
10948
  if (connection.ws) {
10973
10949
  const ws = connection.ws;
10974
10950
  connection.ws = null;
@@ -13570,7 +13546,7 @@ async function loadDependencies() {
13570
13546
  const [reactModule, reactDomModule, phantomModule] = await Promise.all([
13571
13547
  import('react'),
13572
13548
  import('react-dom/client'),
13573
- import('./index-DzfODeEO.esm.js')
13549
+ import('./index-DnHUGqjI.esm.js')
13574
13550
  ]);
13575
13551
  // Extract default export from ESM module namespace
13576
13552
  // Dynamic import() returns { default: Module, ...exports }, not the module directly
@@ -13682,9 +13658,15 @@ class PhantomWalletProvider {
13682
13658
  this.containerElement.setAttribute('data-phantom-provider', 'true');
13683
13659
  // Keep Phantom UI above host overlays while avoiding global click-capture.
13684
13660
  this.containerElement.style.position = 'fixed';
13685
- this.containerElement.style.inset = '0';
13686
13661
  this.containerElement.style.zIndex = '2147483647';
13687
- this.containerElement.style.pointerEvents = 'none';
13662
+ if (this.config.enablePrivyFallback) {
13663
+ // Full-viewport overlay for custom modal; pointer-events: none lets
13664
+ // clicks pass through to page except where the modal sets 'auto'
13665
+ this.containerElement.style.inset = '0';
13666
+ this.containerElement.style.pointerEvents = 'none';
13667
+ }
13668
+ // When Privy fallback is off, the container just hosts PhantomProvider
13669
+ // without covering the viewport or blocking pointer events
13688
13670
  document.body.appendChild(this.containerElement);
13689
13671
  const that = this;
13690
13672
  const { PhantomProvider: ReactPhantomProvider, usePhantom, useConnect, useDisconnect, useModal, useSolana, useDiscoveredWallets, AddressType, darkTheme, lightTheme } = phantomReactSdk;
@@ -34904,6 +34886,508 @@ class OffchainAuthProvider {
34904
34886
  }
34905
34887
  }
34906
34888
 
34889
+ /**
34890
+ * Detects whether the current environment is a mobile browser capable of
34891
+ * Mobile Wallet Adapter (MWA) communication.
34892
+ *
34893
+ * Returns true on Android browsers (Chrome, etc.) where MWA intents work,
34894
+ * or inside a Seeker/Saga in-app browser context.
34895
+ */
34896
+ function isMobileWalletAvailable() {
34897
+ if (typeof window === 'undefined' || typeof navigator === 'undefined')
34898
+ return false;
34899
+ const ua = navigator.userAgent || '';
34900
+ // Android browser — MWA uses Android intents
34901
+ const isAndroid = /Android/i.test(ua);
34902
+ // In-app browser inside a wallet app on Seeker/Saga
34903
+ const isWalletInAppBrowser = /SolanaWallet/i.test(ua) || /SeedVault/i.test(ua);
34904
+ return isAndroid || isWalletInAppBrowser;
34905
+ }
34906
+ // Dynamically imported MWA module
34907
+ let mwaModule = null;
34908
+ let mwaLoadPromise = null;
34909
+ async function loadMwaModule() {
34910
+ if (mwaModule)
34911
+ return;
34912
+ if (typeof window === 'undefined')
34913
+ return;
34914
+ if (mwaLoadPromise)
34915
+ return mwaLoadPromise;
34916
+ mwaLoadPromise = (async () => {
34917
+ try {
34918
+ mwaModule = await import('@solana-mobile/wallet-adapter-mobile');
34919
+ }
34920
+ catch (e) {
34921
+ console.warn('[SolanaMobileWallet] @solana-mobile/wallet-adapter-mobile not installed. Install it to enable Seeker wallet support.');
34922
+ throw new Error('Missing @solana-mobile/wallet-adapter-mobile dependency');
34923
+ }
34924
+ })();
34925
+ return mwaLoadPromise;
34926
+ }
34927
+ /**
34928
+ * Registers Mobile Wallet Adapter as a wallet-standard wallet so it appears
34929
+ * in wallet selection UIs and can be discovered by other wallet-standard consumers.
34930
+ *
34931
+ * Call this once at app startup (in a browser-only / non-SSR context).
34932
+ *
34933
+ * @param config - App identity and optional remote host authority for desktop QR code support
34934
+ */
34935
+ async function registerMobileWalletAdapter(config) {
34936
+ var _a;
34937
+ if (typeof window === 'undefined')
34938
+ return;
34939
+ try {
34940
+ const walletStandardMobile = await import('@solana-mobile/wallet-standard-mobile');
34941
+ const registerMwa = walletStandardMobile.registerMwa || ((_a = walletStandardMobile.default) === null || _a === void 0 ? void 0 : _a.registerMwa);
34942
+ if (!registerMwa) {
34943
+ console.warn('[SolanaMobileWallet] registerMwa not found in @solana-mobile/wallet-standard-mobile');
34944
+ return;
34945
+ }
34946
+ const options = {};
34947
+ if (config === null || config === void 0 ? void 0 : config.appIdentity) {
34948
+ options.appIdentity = config.appIdentity;
34949
+ }
34950
+ if (config === null || config === void 0 ? void 0 : config.chains) {
34951
+ options.chains = config.chains;
34952
+ }
34953
+ if (config === null || config === void 0 ? void 0 : config.remoteHostAuthority) {
34954
+ options.remoteHostAuthority = config.remoteHostAuthority;
34955
+ }
34956
+ // Use the library's default helpers if available
34957
+ if (walletStandardMobile.createDefaultAuthorizationCache) {
34958
+ options.authorizationCache = walletStandardMobile.createDefaultAuthorizationCache();
34959
+ }
34960
+ if (walletStandardMobile.createDefaultChainSelector) {
34961
+ options.chainSelector = walletStandardMobile.createDefaultChainSelector();
34962
+ }
34963
+ if (walletStandardMobile.createDefaultWalletNotFoundHandler) {
34964
+ options.onWalletNotFound = walletStandardMobile.createDefaultWalletNotFoundHandler();
34965
+ }
34966
+ registerMwa(options);
34967
+ }
34968
+ catch (e) {
34969
+ // @solana-mobile/wallet-standard-mobile is an optional dependency
34970
+ // Silently skip if not installed — the provider still works via
34971
+ // @solana-mobile/wallet-adapter-mobile directly
34972
+ console.debug('[SolanaMobileWallet] @solana-mobile/wallet-standard-mobile not available, skipping wallet-standard registration');
34973
+ }
34974
+ }
34975
+ /**
34976
+ * SolanaMobileWalletProvider implements the AuthProvider interface using the
34977
+ * Solana Mobile Wallet Adapter (MWA) protocol.
34978
+ *
34979
+ * This enables TaroBase dApps to work with any MWA-compliant wallet on Solana
34980
+ * mobile devices (Seeker, Saga) — including the native Seed Vault Wallet,
34981
+ * Phantom, Solflare, and any other wallet that implements the MWA protocol.
34982
+ *
34983
+ * The MWA protocol communicates with wallet apps via Android intents (on mobile)
34984
+ * or WebSocket relay (on desktop via QR code), eliminating the need to integrate
34985
+ * with each wallet individually.
34986
+ */
34987
+ class SolanaMobileWalletProvider {
34988
+ constructor(networkUrl = null, config = {}) {
34989
+ this.mwaAdapter = null;
34990
+ this.authorizedPublicKey = null;
34991
+ this.networkUrl = networkUrl;
34992
+ this.config = config;
34993
+ if (typeof window === 'undefined') {
34994
+ throw new Error('SolanaMobileWalletProvider can only be instantiated in a browser environment');
34995
+ }
34996
+ if (SolanaMobileWalletProvider.instance) {
34997
+ return SolanaMobileWalletProvider.instance;
34998
+ }
34999
+ SolanaMobileWalletProvider.instance = this;
35000
+ }
35001
+ static getInstance(networkUrl, config) {
35002
+ if (!SolanaMobileWalletProvider.instance) {
35003
+ new SolanaMobileWalletProvider(networkUrl, config);
35004
+ }
35005
+ return SolanaMobileWalletProvider.instance;
35006
+ }
35007
+ async ensureAdapter() {
35008
+ var _a;
35009
+ if ((_a = this.mwaAdapter) === null || _a === void 0 ? void 0 : _a.connected)
35010
+ return this.mwaAdapter;
35011
+ await loadMwaModule();
35012
+ const { SolanaMobileWalletAdapter, createDefaultAddressSelector, createDefaultAuthorizationResultCache } = mwaModule;
35013
+ if (!this.mwaAdapter) {
35014
+ const cluster = this.config.cluster || 'mainnet-beta';
35015
+ this.mwaAdapter = new SolanaMobileWalletAdapter({
35016
+ addressSelector: createDefaultAddressSelector(),
35017
+ appIdentity: this.config.appIdentity || {
35018
+ name: 'TaroBase App',
35019
+ uri: typeof window !== 'undefined' ? window.location.origin : undefined,
35020
+ },
35021
+ authorizationResultCache: createDefaultAuthorizationResultCache(),
35022
+ cluster,
35023
+ });
35024
+ }
35025
+ return this.mwaAdapter;
35026
+ }
35027
+ async login() {
35028
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j;
35029
+ setAuthLoading(true);
35030
+ try {
35031
+ const adapter = await this.ensureAdapter();
35032
+ // Connect triggers the MWA authorization flow — this opens the wallet app
35033
+ // via Android intent and asks the user to authorize this dApp
35034
+ await adapter.connect();
35035
+ const publicKey = ((_b = (_a = adapter.publicKey) === null || _a === void 0 ? void 0 : _a.toBase58) === null || _b === void 0 ? void 0 : _b.call(_a)) || ((_d = (_c = adapter.publicKey) === null || _c === void 0 ? void 0 : _c.toString) === null || _d === void 0 ? void 0 : _d.call(_c));
35036
+ if (!publicKey) {
35037
+ throw new Error('No public key returned from wallet');
35038
+ }
35039
+ this.authorizedPublicKey = publicKey;
35040
+ // Check if we already have a valid session
35041
+ const existingSession = await WebSessionManager.getSession();
35042
+ if (existingSession && existingSession.address === publicKey) {
35043
+ const user = { provider: this, address: publicKey };
35044
+ setCurrentUser(user);
35045
+ return user;
35046
+ }
35047
+ // Create new session with signature
35048
+ const nonce = await genAuthNonce();
35049
+ const messageText = await genSolanaMessage(publicKey, nonce);
35050
+ // MWA signMessage expects Uint8Array
35051
+ const messageBytes = new TextEncoder().encode(messageText);
35052
+ const signatureBytes = await adapter.signMessage(messageBytes);
35053
+ const signature = bufferExports.Buffer.from(signatureBytes).toString('base64');
35054
+ const createSessionResult = await createSessionWithSignature(publicKey, messageText, signature);
35055
+ await WebSessionManager.storeSession(publicKey, createSessionResult.accessToken, createSessionResult.idToken, createSessionResult.refreshToken);
35056
+ // Mark auth method
35057
+ try {
35058
+ localStorage.setItem('tarobase_last_auth_method', 'mobile-wallet-adapter');
35059
+ }
35060
+ catch (_k) { }
35061
+ const user = { provider: this, address: publicKey };
35062
+ setCurrentUser(user);
35063
+ return user;
35064
+ }
35065
+ catch (error) {
35066
+ const isUserRejection = (error === null || error === void 0 ? void 0 : error.code) === 4001 ||
35067
+ ((_e = error === null || error === void 0 ? void 0 : error.message) === null || _e === void 0 ? void 0 : _e.toLowerCase().includes('user rejected')) ||
35068
+ ((_f = error === null || error === void 0 ? void 0 : error.message) === null || _f === void 0 ? void 0 : _f.toLowerCase().includes('user denied')) ||
35069
+ ((_g = error === null || error === void 0 ? void 0 : error.message) === null || _g === void 0 ? void 0 : _g.toLowerCase().includes('user cancelled')) ||
35070
+ ((_h = error === null || error === void 0 ? void 0 : error.message) === null || _h === void 0 ? void 0 : _h.toLowerCase().includes('user canceled')) ||
35071
+ ((_j = error === null || error === void 0 ? void 0 : error.message) === null || _j === void 0 ? void 0 : _j.toLowerCase().includes('user declined'));
35072
+ if (!isUserRejection) {
35073
+ console.error('[SolanaMobileWallet] Login failed:', error);
35074
+ }
35075
+ throw error;
35076
+ }
35077
+ finally {
35078
+ setAuthLoading(false);
35079
+ }
35080
+ }
35081
+ async restoreSession() {
35082
+ const session = await WebSessionManager.getSession();
35083
+ if (session) {
35084
+ this.authorizedPublicKey = session.address;
35085
+ return { provider: this, address: session.address };
35086
+ }
35087
+ return null;
35088
+ }
35089
+ async logout() {
35090
+ var _a;
35091
+ try {
35092
+ if ((_a = this.mwaAdapter) === null || _a === void 0 ? void 0 : _a.connected) {
35093
+ await this.mwaAdapter.disconnect();
35094
+ }
35095
+ }
35096
+ catch (error) {
35097
+ console.error('[SolanaMobileWallet] Disconnect error:', error);
35098
+ }
35099
+ this.authorizedPublicKey = null;
35100
+ WebSessionManager.clearSession();
35101
+ setCurrentUser(null);
35102
+ }
35103
+ async signMessage(message) {
35104
+ var _a, _b;
35105
+ const adapter = await this.ensureAdapter();
35106
+ if (!adapter.connected) {
35107
+ await adapter.connect();
35108
+ }
35109
+ try {
35110
+ const messageBytes = new TextEncoder().encode(message);
35111
+ const signatureBytes = await adapter.signMessage(messageBytes);
35112
+ return bufferExports.Buffer.from(signatureBytes).toString('base64');
35113
+ }
35114
+ catch (error) {
35115
+ 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'))) {
35116
+ await this.logout();
35117
+ throw new Error('Wallet connection lost. Please reconnect.');
35118
+ }
35119
+ throw new Error(`Failed to sign message: ${error.message}`);
35120
+ }
35121
+ }
35122
+ async signTransaction(transaction) {
35123
+ var _a, _b;
35124
+ const adapter = await this.ensureAdapter();
35125
+ if (!adapter.connected) {
35126
+ await adapter.connect();
35127
+ }
35128
+ // Ensure blockhash is set
35129
+ const isLegacyTransaction = 'recentBlockhash' in transaction && !('message' in transaction && 'staticAccountKeys' in transaction.message);
35130
+ if (isLegacyTransaction) {
35131
+ const legacyTx = transaction;
35132
+ if (!legacyTx.recentBlockhash) {
35133
+ const rpcUrl = this.getRpcUrl();
35134
+ const connection = new Connection(rpcUrl, 'confirmed');
35135
+ const { blockhash, lastValidBlockHeight } = await connection.getLatestBlockhash('confirmed');
35136
+ legacyTx.recentBlockhash = blockhash;
35137
+ legacyTx.lastValidBlockHeight = lastValidBlockHeight;
35138
+ }
35139
+ if (!legacyTx.feePayer && adapter.publicKey) {
35140
+ legacyTx.feePayer = adapter.publicKey;
35141
+ }
35142
+ }
35143
+ else {
35144
+ const versionedTx = transaction;
35145
+ if (!versionedTx.message.recentBlockhash) {
35146
+ const rpcUrl = this.getRpcUrl();
35147
+ const connection = new Connection(rpcUrl, 'confirmed');
35148
+ const { blockhash } = await connection.getLatestBlockhash('confirmed');
35149
+ versionedTx.message.recentBlockhash = blockhash;
35150
+ }
35151
+ }
35152
+ try {
35153
+ const signed = await adapter.signTransaction(transaction);
35154
+ return signed;
35155
+ }
35156
+ catch (error) {
35157
+ 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'))) {
35158
+ await this.logout();
35159
+ throw new Error('Wallet connection lost. Please reconnect.');
35160
+ }
35161
+ throw new Error(`Failed to sign transaction: ${error.message}`);
35162
+ }
35163
+ }
35164
+ async signAndSubmitTransaction(transaction, feePayer) {
35165
+ var _a, _b, _c, _d, _e, _f;
35166
+ const adapter = await this.ensureAdapter();
35167
+ if (!adapter.connected) {
35168
+ await adapter.connect();
35169
+ }
35170
+ const rpcUrl = this.getRpcUrl();
35171
+ const connection = new Connection(rpcUrl, 'confirmed');
35172
+ const isSurfnet = rpcUrl === SURFNET_RPC_URL;
35173
+ try {
35174
+ const { blockhash, lastValidBlockHeight } = await connection.getLatestBlockhash('confirmed');
35175
+ const isLegacyTransaction = 'recentBlockhash' in transaction && !('message' in transaction && 'staticAccountKeys' in transaction.message);
35176
+ if (isLegacyTransaction) {
35177
+ const legacyTx = transaction;
35178
+ legacyTx.recentBlockhash = blockhash;
35179
+ legacyTx.lastValidBlockHeight = lastValidBlockHeight;
35180
+ if (!legacyTx.feePayer) {
35181
+ if (feePayer) {
35182
+ legacyTx.feePayer = feePayer;
35183
+ }
35184
+ else if (adapter.publicKey) {
35185
+ legacyTx.feePayer = adapter.publicKey;
35186
+ }
35187
+ }
35188
+ }
35189
+ else {
35190
+ const versionedTx = transaction;
35191
+ versionedTx.message.recentBlockhash = blockhash;
35192
+ }
35193
+ // On surfnet, sign then submit manually
35194
+ if (isSurfnet) {
35195
+ const signedTx = await adapter.signTransaction(transaction);
35196
+ const signature = await connection.sendRawTransaction(signedTx.serialize(), {
35197
+ preflightCommitment: 'confirmed'
35198
+ });
35199
+ const confirmation = await connection.confirmTransaction({
35200
+ signature,
35201
+ blockhash,
35202
+ lastValidBlockHeight,
35203
+ }, 'confirmed');
35204
+ if (confirmation.value.err) {
35205
+ throw new Error(`Transaction failed: ${confirmation.value.err.toString()}`);
35206
+ }
35207
+ return signature;
35208
+ }
35209
+ // MWA supports signAndSendTransaction natively — this lets the wallet
35210
+ // app submit the transaction directly, which is more reliable on mobile
35211
+ if (adapter.sendTransaction) {
35212
+ const signature = await adapter.sendTransaction(transaction, connection, {
35213
+ preflightCommitment: 'confirmed',
35214
+ });
35215
+ await confirmAndCheckTransaction(connection, signature);
35216
+ return signature;
35217
+ }
35218
+ // Fallback: sign then submit
35219
+ const signedTx = await adapter.signTransaction(transaction);
35220
+ const signature = await connection.sendRawTransaction(signedTx.serialize(), {
35221
+ preflightCommitment: 'confirmed'
35222
+ });
35223
+ await confirmAndCheckTransaction(connection, signature);
35224
+ return signature;
35225
+ }
35226
+ catch (error) {
35227
+ 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'))) {
35228
+ await this.logout();
35229
+ throw new Error('Wallet connection lost. Please reconnect.');
35230
+ }
35231
+ const isUserRejection = (error === null || error === void 0 ? void 0 : error.code) === 4001 ||
35232
+ ((_c = error === null || error === void 0 ? void 0 : error.message) === null || _c === void 0 ? void 0 : _c.toLowerCase().includes('user rejected')) ||
35233
+ ((_d = error === null || error === void 0 ? void 0 : error.message) === null || _d === void 0 ? void 0 : _d.toLowerCase().includes('user denied')) ||
35234
+ ((_e = error === null || error === void 0 ? void 0 : error.message) === null || _e === void 0 ? void 0 : _e.toLowerCase().includes('user cancelled')) ||
35235
+ ((_f = error === null || error === void 0 ? void 0 : error.message) === null || _f === void 0 ? void 0 : _f.toLowerCase().includes('user canceled'));
35236
+ if (!isUserRejection) {
35237
+ console.error('[SolanaMobileWallet] Transaction failed:', error);
35238
+ }
35239
+ throw new Error(`Failed to execute transaction: ${error.message}`);
35240
+ }
35241
+ }
35242
+ async runTransaction(_evmTransactionData, solTransactionData, options) {
35243
+ var _a, _b, _c, _d, _e, _f, _g, _h;
35244
+ if (!solTransactionData) {
35245
+ throw new Error('Solana transaction data is required for mobile wallet');
35246
+ }
35247
+ const adapter = await this.ensureAdapter();
35248
+ if (!adapter.connected) {
35249
+ await this.login();
35250
+ }
35251
+ const rpcUrl = this.getRpcUrl(solTransactionData.network);
35252
+ const connection = new Connection(rpcUrl, 'confirmed');
35253
+ const isSurfnet = rpcUrl === SURFNET_RPC_URL;
35254
+ try {
35255
+ const publicKey = adapter.publicKey;
35256
+ if (!publicKey) {
35257
+ throw new Error('No wallet connected');
35258
+ }
35259
+ const remainingAccounts = convertRemainingAccounts(solTransactionData.txArgs[0].remainingAccounts);
35260
+ let app_id = solTransactionData.appId;
35261
+ if (typeof window !== 'undefined' && window.CUSTOM_TAROBASE_APP_ID_HEADER) {
35262
+ app_id = window.CUSTOM_TAROBASE_APP_ID_HEADER;
35263
+ }
35264
+ if (!app_id) {
35265
+ throw new Error('App ID is required');
35266
+ }
35267
+ // Create wallet adapter interface for Anchor
35268
+ const walletAdapter = {
35269
+ publicKey,
35270
+ signTransaction: async (tx) => {
35271
+ return await adapter.signTransaction(tx);
35272
+ },
35273
+ signAllTransactions: async (txs) => {
35274
+ return await adapter.signAllTransactions(txs);
35275
+ }
35276
+ };
35277
+ const anchorProvider = new anchor.AnchorProvider(connection, walletAdapter, anchor.AnchorProvider.defaultOptions());
35278
+ const finalDeduped = [];
35279
+ for (const acc of remainingAccounts) {
35280
+ const existing = finalDeduped.find((d) => d.pubkey.equals(acc.pubkey));
35281
+ if (existing) {
35282
+ existing.isSigner = existing.isSigner || acc.isSigner;
35283
+ existing.isWritable = existing.isWritable || acc.isWritable;
35284
+ }
35285
+ else {
35286
+ finalDeduped.push(acc);
35287
+ }
35288
+ }
35289
+ const { tx } = await buildSetDocumentsTransaction(connection, solTransactionData.txArgs[0].idl, anchorProvider, publicKey, {
35290
+ app_id,
35291
+ documents: solTransactionData.txArgs[0].setDocumentData,
35292
+ delete_paths: solTransactionData.txArgs[0].deletePaths,
35293
+ txData: solTransactionData.txArgs[0].txData
35294
+ }, finalDeduped, solTransactionData.lutKey, solTransactionData.preInstructions, false);
35295
+ if ((options === null || options === void 0 ? void 0 : options.shouldSubmitTx) === false) {
35296
+ const signedTx = await walletAdapter.signTransaction(tx);
35297
+ return {
35298
+ signedTransaction: signedTx,
35299
+ blockNumber: 0,
35300
+ gasUsed: '0',
35301
+ data: ''
35302
+ };
35303
+ }
35304
+ // On surfnet, sign + submit manually
35305
+ if (isSurfnet) {
35306
+ const signedTx = await walletAdapter.signTransaction(tx);
35307
+ const { blockhash, lastValidBlockHeight } = await connection.getLatestBlockhash('confirmed');
35308
+ const signature = await connection.sendRawTransaction(signedTx.serialize(), {
35309
+ preflightCommitment: 'confirmed'
35310
+ });
35311
+ const confirmation = await connection.confirmTransaction({
35312
+ signature,
35313
+ blockhash,
35314
+ lastValidBlockHeight,
35315
+ }, 'confirmed');
35316
+ if (confirmation.value.err) {
35317
+ throw new Error(`Transaction failed: ${confirmation.value.err.toString()}`);
35318
+ }
35319
+ const txInfo = await connection.getParsedTransaction(signature, {
35320
+ maxSupportedTransactionVersion: 0,
35321
+ commitment: 'confirmed'
35322
+ });
35323
+ return {
35324
+ transactionSignature: signature,
35325
+ blockNumber: (txInfo === null || txInfo === void 0 ? void 0 : txInfo.slot) || 0,
35326
+ gasUsed: ((_a = txInfo === null || txInfo === void 0 ? void 0 : txInfo.meta) === null || _a === void 0 ? void 0 : _a.fee.toString()) || '0',
35327
+ data: txInfo === null || txInfo === void 0 ? void 0 : txInfo.meta,
35328
+ };
35329
+ }
35330
+ // Use MWA's sendTransaction for mobile-optimized submission
35331
+ let signature;
35332
+ if (adapter.sendTransaction) {
35333
+ signature = await adapter.sendTransaction(tx, connection, {
35334
+ preflightCommitment: 'confirmed',
35335
+ });
35336
+ }
35337
+ else {
35338
+ const signedTx = await walletAdapter.signTransaction(tx);
35339
+ signature = await connection.sendRawTransaction(signedTx.serialize(), {
35340
+ preflightCommitment: 'confirmed'
35341
+ });
35342
+ }
35343
+ const txInfo = await confirmAndCheckTransaction(connection, signature);
35344
+ return {
35345
+ transactionSignature: signature,
35346
+ blockNumber: (txInfo === null || txInfo === void 0 ? void 0 : txInfo.slot) || 0,
35347
+ gasUsed: ((_b = txInfo === null || txInfo === void 0 ? void 0 : txInfo.meta) === null || _b === void 0 ? void 0 : _b.fee.toString()) || '0',
35348
+ data: txInfo === null || txInfo === void 0 ? void 0 : txInfo.meta,
35349
+ };
35350
+ }
35351
+ catch (error) {
35352
+ if (((_c = error === null || error === void 0 ? void 0 : error.message) === null || _c === void 0 ? void 0 : _c.includes('not connected')) || ((_d = error === null || error === void 0 ? void 0 : error.message) === null || _d === void 0 ? void 0 : _d.includes('not authorized'))) {
35353
+ await this.logout();
35354
+ throw new Error('Wallet connection lost. Please reconnect.');
35355
+ }
35356
+ const isUserRejection = (error === null || error === void 0 ? void 0 : error.code) === 4001 ||
35357
+ ((_e = error === null || error === void 0 ? void 0 : error.message) === null || _e === void 0 ? void 0 : _e.toLowerCase().includes('user rejected')) ||
35358
+ ((_f = error === null || error === void 0 ? void 0 : error.message) === null || _f === void 0 ? void 0 : _f.toLowerCase().includes('user denied')) ||
35359
+ ((_g = error === null || error === void 0 ? void 0 : error.message) === null || _g === void 0 ? void 0 : _g.toLowerCase().includes('user cancelled')) ||
35360
+ ((_h = error === null || error === void 0 ? void 0 : error.message) === null || _h === void 0 ? void 0 : _h.toLowerCase().includes('user canceled'));
35361
+ if (!isUserRejection) {
35362
+ console.error('[SolanaMobileWallet] Transaction failed:', error);
35363
+ }
35364
+ throw new Error(`Failed to execute transaction: ${error.message}`);
35365
+ }
35366
+ }
35367
+ async getNativeMethods() {
35368
+ return this.mwaAdapter;
35369
+ }
35370
+ /* ----------------------------------------------------------- *
35371
+ * Private Helpers
35372
+ * ----------------------------------------------------------- */
35373
+ getRpcUrl(network) {
35374
+ if (this.networkUrl) {
35375
+ return this.networkUrl;
35376
+ }
35377
+ if (network === 'solana_devnet') {
35378
+ return SOLANA_DEVNET_RPC_URL;
35379
+ }
35380
+ else if (network === 'solana_mainnet') {
35381
+ return SOLANA_MAINNET_RPC_URL;
35382
+ }
35383
+ else if (network === 'surfnet') {
35384
+ return SURFNET_RPC_URL;
35385
+ }
35386
+ return SOLANA_MAINNET_RPC_URL;
35387
+ }
35388
+ }
35389
+ SolanaMobileWalletProvider.instance = null;
35390
+
34907
35391
  let currentAuthProvider = null;
34908
35392
  let currentAuthMethod = null;
34909
35393
  let initConfig = null;
@@ -34977,7 +35461,7 @@ const SOLANA_DEVNET_RPC_URL = "https://idelle-8nxsep-fast-devnet.helius-rpc.com"
34977
35461
  const SOLANA_MAINNET_RPC_URL = "https://celestia-cegncv-fast-mainnet.helius-rpc.com";
34978
35462
  const SURFNET_RPC_URL = "https://surfpool.fly.dev";
34979
35463
  async function getAuthProvider(config) {
34980
- var _a, _b, _c, _d;
35464
+ var _a, _b, _c, _d, _e, _f;
34981
35465
  if (currentAuthProvider) {
34982
35466
  return currentAuthProvider;
34983
35467
  }
@@ -34992,7 +35476,7 @@ async function getAuthProvider(config) {
34992
35476
  return currentAuthProvider;
34993
35477
  }
34994
35478
  // If the user previously logged in with a specific method, use that instead
34995
- const validAuthMethods = ['privy', 'phantom', 'wallet', 'rainbowkit', 'coinbase-smart-wallet', 'onboard', 'none'];
35479
+ const validAuthMethods = ['privy', 'phantom', 'wallet', 'rainbowkit', 'coinbase-smart-wallet', 'onboard', 'mobile-wallet-adapter', 'none'];
34996
35480
  const storedMethod = getStoredAuthMethod();
34997
35481
  const authMethod = (storedMethod && validAuthMethods.includes(storedMethod))
34998
35482
  ? storedMethod
@@ -35001,7 +35485,25 @@ async function getAuthProvider(config) {
35001
35485
  // Invalid stored value — clear it
35002
35486
  setStoredAuthMethod(null);
35003
35487
  }
35004
- const rpcUrl = (_a = config.rpcUrl) !== null && _a !== void 0 ? _a : null;
35488
+ // --- Register MWA as a wallet-standard wallet on mobile ---
35489
+ // On Android (TWA via Bubblewrap, Chrome, or mobile browser), register the
35490
+ // Mobile Wallet Adapter so it appears in wallet discovery (e.g. Phantom's
35491
+ // useDiscoveredWallets, or any wallet-standard consumer). This makes Seed
35492
+ // Vault, Solflare, and other MWA wallets show up alongside injected wallets
35493
+ // in the existing Phantom/Privy modals — without overriding the configured
35494
+ // authMethod. Email login, deeplinks, and all other flows stay intact.
35495
+ //
35496
+ // Only authMethod: 'mobile-wallet-adapter' (explicit opt-in) bypasses
35497
+ // Phantom/Privy entirely and uses MWA as the sole provider.
35498
+ if (isMobileWalletAvailable()) {
35499
+ registerMobileWalletAdapter({
35500
+ appIdentity: (_b = (_a = config.mobileWalletConfig) === null || _a === void 0 ? void 0 : _a.appIdentity) !== null && _b !== void 0 ? _b : {
35501
+ name: config.name || undefined,
35502
+ uri: typeof window !== 'undefined' ? window.location.origin : undefined,
35503
+ },
35504
+ }).catch(() => { });
35505
+ }
35506
+ const rpcUrl = (_c = config.rpcUrl) !== null && _c !== void 0 ? _c : null;
35005
35507
  currentAuthMethod = authMethod;
35006
35508
  switch (authMethod) {
35007
35509
  case "wallet":
@@ -35011,15 +35513,18 @@ async function getAuthProvider(config) {
35011
35513
  console.warn("Rainbow Kit auth is not yet supported.");
35012
35514
  break;
35013
35515
  case "privy":
35014
- currentAuthProvider = new PrivyWalletProvider((_b = config.name) !== null && _b !== void 0 ? _b : null, (_c = config.logoUrl) !== null && _c !== void 0 ? _c : null, config.privyConfig, rpcUrl);
35516
+ currentAuthProvider = new PrivyWalletProvider((_d = config.name) !== null && _d !== void 0 ? _d : null, (_e = config.logoUrl) !== null && _e !== void 0 ? _e : null, config.privyConfig, rpcUrl);
35015
35517
  break;
35016
35518
  case "phantom":
35017
35519
  currentAuthProvider = new PhantomWalletProvider(rpcUrl, config.phantomConfig);
35018
- if ((_d = config.phantomConfig) === null || _d === void 0 ? void 0 : _d.enablePrivyFallback) {
35520
+ if ((_f = config.phantomConfig) === null || _f === void 0 ? void 0 : _f.enablePrivyFallback) {
35019
35521
  currentAuthProvider.onSwitchToPrivy =
35020
35522
  () => hotSwapToPrivyProvider(config);
35021
35523
  }
35022
35524
  break;
35525
+ case "mobile-wallet-adapter":
35526
+ currentAuthProvider = new SolanaMobileWalletProvider(rpcUrl, config.mobileWalletConfig);
35527
+ break;
35023
35528
  case "onboard":
35024
35529
  console.warn("Onboard auth is not yet supported.");
35025
35530
  break;
@@ -35235,5 +35740,5 @@ async function getIdToken() {
35235
35740
  return getIdToken$1(false);
35236
35741
  }
35237
35742
 
35238
- export { useAuth as A, getIdToken as B, PrivyWalletProvider as C, DEFAULT_TEST_ADDRESS as D, EventEmitter3 as E, buildSetDocumentsTransaction as F, clearCache as G, closeAllSubscriptions as H, convertRemainingAccounts as I, createSessionWithPrivy as J, createSessionWithSignature as K, genAuthNonce as L, MockAuthProvider as M, genSolanaMessage as N, OffchainAuthProvider as O, PhantomWalletProvider as P, getCachedData as Q, reconnectWithNewAuth as R, ServerSessionManager as S, refreshSession as T, signSessionCreateMessage as U, WebSessionManager as W, bs58 as a, bufferExports as b, onAuthLoadingChanged as c, getAuthLoading as d, logout as e, getConfig as f, getCurrentUser as g, getAuthProvider as h, init as i, get$2 as j, setMany as k, login as l, setFile as m, getFiles as n, onAuthStateChanged as o, runQueryMany as p, runExpression as q, runQuery as r, set$1 as s, runExpressionMany as t, signMessage as u, signTransaction as v, signAndSubmitTransaction as w, count as x, aggregate as y, subscribe as z };
35239
- //# sourceMappingURL=index-BJkKyW8U.esm.js.map
35743
+ export { useAuth as A, getIdToken as B, PrivyWalletProvider as C, DEFAULT_TEST_ADDRESS as D, EventEmitter3 as E, isMobileWalletAvailable as F, registerMobileWalletAdapter as G, ServerSessionManager as H, buildSetDocumentsTransaction as I, clearCache as J, closeAllSubscriptions as K, convertRemainingAccounts as L, MockAuthProvider as M, createSessionWithPrivy as N, OffchainAuthProvider as O, PhantomWalletProvider as P, createSessionWithSignature as Q, genAuthNonce as R, SolanaMobileWalletProvider as S, genSolanaMessage as T, getCachedData as U, reconnectWithNewAuth as V, WebSessionManager as W, refreshSession as X, signSessionCreateMessage as Y, bs58 as a, bufferExports as b, onAuthLoadingChanged as c, getAuthLoading as d, logout as e, getConfig as f, getCurrentUser as g, getAuthProvider as h, init as i, get$2 as j, setMany as k, login as l, setFile as m, getFiles as n, onAuthStateChanged as o, runQueryMany as p, runExpression as q, runQuery as r, set$1 as s, runExpressionMany as t, signMessage as u, signTransaction as v, signAndSubmitTransaction as w, count as x, aggregate as y, subscribe as z };
35744
+ //# sourceMappingURL=index-DUIdAaPc.esm.js.map