@pooflabs/web 0.0.68 → 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.
@@ -10777,7 +10777,10 @@ function handleServerMessage(connection, message) {
10777
10777
  }
10778
10778
  function notifyCallbacks(subscription, data) {
10779
10779
  var _a;
10780
- for (const callback of subscription.callbacks) {
10780
+ // Snapshot the callbacks array so that unsubscriptions during
10781
+ // notification don't cause callbacks to be skipped.
10782
+ const callbacks = subscription.callbacks.slice();
10783
+ for (const callback of callbacks) {
10781
10784
  try {
10782
10785
  (_a = callback.onData) === null || _a === void 0 ? void 0 : _a.call(callback, data);
10783
10786
  }
@@ -13563,7 +13566,7 @@ async function loadDependencies() {
13563
13566
  const [reactModule, reactDomModule, phantomModule] = await Promise.all([
13564
13567
  import('react'),
13565
13568
  import('react-dom/client'),
13566
- Promise.resolve().then(function () { return require('./index-ChGj4uuO.js'); })
13569
+ Promise.resolve().then(function () { return require('./index-BRZ4-fcO.js'); })
13567
13570
  ]);
13568
13571
  // Extract default export from ESM module namespace
13569
13572
  // Dynamic import() returns { default: Module, ...exports }, not the module directly
@@ -13675,9 +13678,15 @@ class PhantomWalletProvider {
13675
13678
  this.containerElement.setAttribute('data-phantom-provider', 'true');
13676
13679
  // Keep Phantom UI above host overlays while avoiding global click-capture.
13677
13680
  this.containerElement.style.position = 'fixed';
13678
- this.containerElement.style.inset = '0';
13679
13681
  this.containerElement.style.zIndex = '2147483647';
13680
- this.containerElement.style.pointerEvents = 'none';
13682
+ if (this.config.enablePrivyFallback) {
13683
+ // Full-viewport overlay for custom modal; pointer-events: none lets
13684
+ // clicks pass through to page except where the modal sets 'auto'
13685
+ this.containerElement.style.inset = '0';
13686
+ this.containerElement.style.pointerEvents = 'none';
13687
+ }
13688
+ // When Privy fallback is off, the container just hosts PhantomProvider
13689
+ // without covering the viewport or blocking pointer events
13681
13690
  document.body.appendChild(this.containerElement);
13682
13691
  const that = this;
13683
13692
  const { PhantomProvider: ReactPhantomProvider, usePhantom, useConnect, useDisconnect, useModal, useSolana, useDiscoveredWallets, AddressType, darkTheme, lightTheme } = phantomReactSdk;
@@ -34897,6 +34906,508 @@ class OffchainAuthProvider {
34897
34906
  }
34898
34907
  }
34899
34908
 
34909
+ /**
34910
+ * Detects whether the current environment is a mobile browser capable of
34911
+ * Mobile Wallet Adapter (MWA) communication.
34912
+ *
34913
+ * Returns true on Android browsers (Chrome, etc.) where MWA intents work,
34914
+ * or inside a Seeker/Saga in-app browser context.
34915
+ */
34916
+ function isMobileWalletAvailable() {
34917
+ if (typeof window === 'undefined' || typeof navigator === 'undefined')
34918
+ return false;
34919
+ const ua = navigator.userAgent || '';
34920
+ // Android browser — MWA uses Android intents
34921
+ const isAndroid = /Android/i.test(ua);
34922
+ // In-app browser inside a wallet app on Seeker/Saga
34923
+ const isWalletInAppBrowser = /SolanaWallet/i.test(ua) || /SeedVault/i.test(ua);
34924
+ return isAndroid || isWalletInAppBrowser;
34925
+ }
34926
+ // Dynamically imported MWA module
34927
+ let mwaModule = null;
34928
+ let mwaLoadPromise = null;
34929
+ async function loadMwaModule() {
34930
+ if (mwaModule)
34931
+ return;
34932
+ if (typeof window === 'undefined')
34933
+ return;
34934
+ if (mwaLoadPromise)
34935
+ return mwaLoadPromise;
34936
+ mwaLoadPromise = (async () => {
34937
+ try {
34938
+ mwaModule = await import('@solana-mobile/wallet-adapter-mobile');
34939
+ }
34940
+ catch (e) {
34941
+ console.warn('[SolanaMobileWallet] @solana-mobile/wallet-adapter-mobile not installed. Install it to enable Seeker wallet support.');
34942
+ throw new Error('Missing @solana-mobile/wallet-adapter-mobile dependency');
34943
+ }
34944
+ })();
34945
+ return mwaLoadPromise;
34946
+ }
34947
+ /**
34948
+ * Registers Mobile Wallet Adapter as a wallet-standard wallet so it appears
34949
+ * in wallet selection UIs and can be discovered by other wallet-standard consumers.
34950
+ *
34951
+ * Call this once at app startup (in a browser-only / non-SSR context).
34952
+ *
34953
+ * @param config - App identity and optional remote host authority for desktop QR code support
34954
+ */
34955
+ async function registerMobileWalletAdapter(config) {
34956
+ var _a;
34957
+ if (typeof window === 'undefined')
34958
+ return;
34959
+ try {
34960
+ const walletStandardMobile = await import('@solana-mobile/wallet-standard-mobile');
34961
+ const registerMwa = walletStandardMobile.registerMwa || ((_a = walletStandardMobile.default) === null || _a === void 0 ? void 0 : _a.registerMwa);
34962
+ if (!registerMwa) {
34963
+ console.warn('[SolanaMobileWallet] registerMwa not found in @solana-mobile/wallet-standard-mobile');
34964
+ return;
34965
+ }
34966
+ const options = {};
34967
+ if (config === null || config === void 0 ? void 0 : config.appIdentity) {
34968
+ options.appIdentity = config.appIdentity;
34969
+ }
34970
+ if (config === null || config === void 0 ? void 0 : config.chains) {
34971
+ options.chains = config.chains;
34972
+ }
34973
+ if (config === null || config === void 0 ? void 0 : config.remoteHostAuthority) {
34974
+ options.remoteHostAuthority = config.remoteHostAuthority;
34975
+ }
34976
+ // Use the library's default helpers if available
34977
+ if (walletStandardMobile.createDefaultAuthorizationCache) {
34978
+ options.authorizationCache = walletStandardMobile.createDefaultAuthorizationCache();
34979
+ }
34980
+ if (walletStandardMobile.createDefaultChainSelector) {
34981
+ options.chainSelector = walletStandardMobile.createDefaultChainSelector();
34982
+ }
34983
+ if (walletStandardMobile.createDefaultWalletNotFoundHandler) {
34984
+ options.onWalletNotFound = walletStandardMobile.createDefaultWalletNotFoundHandler();
34985
+ }
34986
+ registerMwa(options);
34987
+ }
34988
+ catch (e) {
34989
+ // @solana-mobile/wallet-standard-mobile is an optional dependency
34990
+ // Silently skip if not installed — the provider still works via
34991
+ // @solana-mobile/wallet-adapter-mobile directly
34992
+ console.debug('[SolanaMobileWallet] @solana-mobile/wallet-standard-mobile not available, skipping wallet-standard registration');
34993
+ }
34994
+ }
34995
+ /**
34996
+ * SolanaMobileWalletProvider implements the AuthProvider interface using the
34997
+ * Solana Mobile Wallet Adapter (MWA) protocol.
34998
+ *
34999
+ * This enables TaroBase dApps to work with any MWA-compliant wallet on Solana
35000
+ * mobile devices (Seeker, Saga) — including the native Seed Vault Wallet,
35001
+ * Phantom, Solflare, and any other wallet that implements the MWA protocol.
35002
+ *
35003
+ * The MWA protocol communicates with wallet apps via Android intents (on mobile)
35004
+ * or WebSocket relay (on desktop via QR code), eliminating the need to integrate
35005
+ * with each wallet individually.
35006
+ */
35007
+ class SolanaMobileWalletProvider {
35008
+ constructor(networkUrl = null, config = {}) {
35009
+ this.mwaAdapter = null;
35010
+ this.authorizedPublicKey = null;
35011
+ this.networkUrl = networkUrl;
35012
+ this.config = config;
35013
+ if (typeof window === 'undefined') {
35014
+ throw new Error('SolanaMobileWalletProvider can only be instantiated in a browser environment');
35015
+ }
35016
+ if (SolanaMobileWalletProvider.instance) {
35017
+ return SolanaMobileWalletProvider.instance;
35018
+ }
35019
+ SolanaMobileWalletProvider.instance = this;
35020
+ }
35021
+ static getInstance(networkUrl, config) {
35022
+ if (!SolanaMobileWalletProvider.instance) {
35023
+ new SolanaMobileWalletProvider(networkUrl, config);
35024
+ }
35025
+ return SolanaMobileWalletProvider.instance;
35026
+ }
35027
+ async ensureAdapter() {
35028
+ var _a;
35029
+ if ((_a = this.mwaAdapter) === null || _a === void 0 ? void 0 : _a.connected)
35030
+ return this.mwaAdapter;
35031
+ await loadMwaModule();
35032
+ const { SolanaMobileWalletAdapter, createDefaultAddressSelector, createDefaultAuthorizationResultCache } = mwaModule;
35033
+ if (!this.mwaAdapter) {
35034
+ const cluster = this.config.cluster || 'mainnet-beta';
35035
+ this.mwaAdapter = new SolanaMobileWalletAdapter({
35036
+ addressSelector: createDefaultAddressSelector(),
35037
+ appIdentity: this.config.appIdentity || {
35038
+ name: 'TaroBase App',
35039
+ uri: typeof window !== 'undefined' ? window.location.origin : undefined,
35040
+ },
35041
+ authorizationResultCache: createDefaultAuthorizationResultCache(),
35042
+ cluster,
35043
+ });
35044
+ }
35045
+ return this.mwaAdapter;
35046
+ }
35047
+ async login() {
35048
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j;
35049
+ setAuthLoading(true);
35050
+ try {
35051
+ const adapter = await this.ensureAdapter();
35052
+ // Connect triggers the MWA authorization flow — this opens the wallet app
35053
+ // via Android intent and asks the user to authorize this dApp
35054
+ await adapter.connect();
35055
+ 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));
35056
+ if (!publicKey) {
35057
+ throw new Error('No public key returned from wallet');
35058
+ }
35059
+ this.authorizedPublicKey = publicKey;
35060
+ // Check if we already have a valid session
35061
+ const existingSession = await WebSessionManager.getSession();
35062
+ if (existingSession && existingSession.address === publicKey) {
35063
+ const user = { provider: this, address: publicKey };
35064
+ setCurrentUser(user);
35065
+ return user;
35066
+ }
35067
+ // Create new session with signature
35068
+ const nonce = await genAuthNonce();
35069
+ const messageText = await genSolanaMessage(publicKey, nonce);
35070
+ // MWA signMessage expects Uint8Array
35071
+ const messageBytes = new TextEncoder().encode(messageText);
35072
+ const signatureBytes = await adapter.signMessage(messageBytes);
35073
+ const signature = bufferExports.Buffer.from(signatureBytes).toString('base64');
35074
+ const createSessionResult = await createSessionWithSignature(publicKey, messageText, signature);
35075
+ await WebSessionManager.storeSession(publicKey, createSessionResult.accessToken, createSessionResult.idToken, createSessionResult.refreshToken);
35076
+ // Mark auth method
35077
+ try {
35078
+ localStorage.setItem('tarobase_last_auth_method', 'mobile-wallet-adapter');
35079
+ }
35080
+ catch (_k) { }
35081
+ const user = { provider: this, address: publicKey };
35082
+ setCurrentUser(user);
35083
+ return user;
35084
+ }
35085
+ catch (error) {
35086
+ const isUserRejection = (error === null || error === void 0 ? void 0 : error.code) === 4001 ||
35087
+ ((_e = error === null || error === void 0 ? void 0 : error.message) === null || _e === void 0 ? void 0 : _e.toLowerCase().includes('user rejected')) ||
35088
+ ((_f = error === null || error === void 0 ? void 0 : error.message) === null || _f === void 0 ? void 0 : _f.toLowerCase().includes('user denied')) ||
35089
+ ((_g = error === null || error === void 0 ? void 0 : error.message) === null || _g === void 0 ? void 0 : _g.toLowerCase().includes('user cancelled')) ||
35090
+ ((_h = error === null || error === void 0 ? void 0 : error.message) === null || _h === void 0 ? void 0 : _h.toLowerCase().includes('user canceled')) ||
35091
+ ((_j = error === null || error === void 0 ? void 0 : error.message) === null || _j === void 0 ? void 0 : _j.toLowerCase().includes('user declined'));
35092
+ if (!isUserRejection) {
35093
+ console.error('[SolanaMobileWallet] Login failed:', error);
35094
+ }
35095
+ throw error;
35096
+ }
35097
+ finally {
35098
+ setAuthLoading(false);
35099
+ }
35100
+ }
35101
+ async restoreSession() {
35102
+ const session = await WebSessionManager.getSession();
35103
+ if (session) {
35104
+ this.authorizedPublicKey = session.address;
35105
+ return { provider: this, address: session.address };
35106
+ }
35107
+ return null;
35108
+ }
35109
+ async logout() {
35110
+ var _a;
35111
+ try {
35112
+ if ((_a = this.mwaAdapter) === null || _a === void 0 ? void 0 : _a.connected) {
35113
+ await this.mwaAdapter.disconnect();
35114
+ }
35115
+ }
35116
+ catch (error) {
35117
+ console.error('[SolanaMobileWallet] Disconnect error:', error);
35118
+ }
35119
+ this.authorizedPublicKey = null;
35120
+ WebSessionManager.clearSession();
35121
+ setCurrentUser(null);
35122
+ }
35123
+ async signMessage(message) {
35124
+ var _a, _b;
35125
+ const adapter = await this.ensureAdapter();
35126
+ if (!adapter.connected) {
35127
+ await adapter.connect();
35128
+ }
35129
+ try {
35130
+ const messageBytes = new TextEncoder().encode(message);
35131
+ const signatureBytes = await adapter.signMessage(messageBytes);
35132
+ return bufferExports.Buffer.from(signatureBytes).toString('base64');
35133
+ }
35134
+ catch (error) {
35135
+ 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'))) {
35136
+ await this.logout();
35137
+ throw new Error('Wallet connection lost. Please reconnect.');
35138
+ }
35139
+ throw new Error(`Failed to sign message: ${error.message}`);
35140
+ }
35141
+ }
35142
+ async signTransaction(transaction) {
35143
+ var _a, _b;
35144
+ const adapter = await this.ensureAdapter();
35145
+ if (!adapter.connected) {
35146
+ await adapter.connect();
35147
+ }
35148
+ // Ensure blockhash is set
35149
+ const isLegacyTransaction = 'recentBlockhash' in transaction && !('message' in transaction && 'staticAccountKeys' in transaction.message);
35150
+ if (isLegacyTransaction) {
35151
+ const legacyTx = transaction;
35152
+ if (!legacyTx.recentBlockhash) {
35153
+ const rpcUrl = this.getRpcUrl();
35154
+ const connection = new web3_js.Connection(rpcUrl, 'confirmed');
35155
+ const { blockhash, lastValidBlockHeight } = await connection.getLatestBlockhash('confirmed');
35156
+ legacyTx.recentBlockhash = blockhash;
35157
+ legacyTx.lastValidBlockHeight = lastValidBlockHeight;
35158
+ }
35159
+ if (!legacyTx.feePayer && adapter.publicKey) {
35160
+ legacyTx.feePayer = adapter.publicKey;
35161
+ }
35162
+ }
35163
+ else {
35164
+ const versionedTx = transaction;
35165
+ if (!versionedTx.message.recentBlockhash) {
35166
+ const rpcUrl = this.getRpcUrl();
35167
+ const connection = new web3_js.Connection(rpcUrl, 'confirmed');
35168
+ const { blockhash } = await connection.getLatestBlockhash('confirmed');
35169
+ versionedTx.message.recentBlockhash = blockhash;
35170
+ }
35171
+ }
35172
+ try {
35173
+ const signed = await adapter.signTransaction(transaction);
35174
+ return signed;
35175
+ }
35176
+ catch (error) {
35177
+ 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'))) {
35178
+ await this.logout();
35179
+ throw new Error('Wallet connection lost. Please reconnect.');
35180
+ }
35181
+ throw new Error(`Failed to sign transaction: ${error.message}`);
35182
+ }
35183
+ }
35184
+ async signAndSubmitTransaction(transaction, feePayer) {
35185
+ var _a, _b, _c, _d, _e, _f;
35186
+ const adapter = await this.ensureAdapter();
35187
+ if (!adapter.connected) {
35188
+ await adapter.connect();
35189
+ }
35190
+ const rpcUrl = this.getRpcUrl();
35191
+ const connection = new web3_js.Connection(rpcUrl, 'confirmed');
35192
+ const isSurfnet = rpcUrl === SURFNET_RPC_URL;
35193
+ try {
35194
+ const { blockhash, lastValidBlockHeight } = await connection.getLatestBlockhash('confirmed');
35195
+ const isLegacyTransaction = 'recentBlockhash' in transaction && !('message' in transaction && 'staticAccountKeys' in transaction.message);
35196
+ if (isLegacyTransaction) {
35197
+ const legacyTx = transaction;
35198
+ legacyTx.recentBlockhash = blockhash;
35199
+ legacyTx.lastValidBlockHeight = lastValidBlockHeight;
35200
+ if (!legacyTx.feePayer) {
35201
+ if (feePayer) {
35202
+ legacyTx.feePayer = feePayer;
35203
+ }
35204
+ else if (adapter.publicKey) {
35205
+ legacyTx.feePayer = adapter.publicKey;
35206
+ }
35207
+ }
35208
+ }
35209
+ else {
35210
+ const versionedTx = transaction;
35211
+ versionedTx.message.recentBlockhash = blockhash;
35212
+ }
35213
+ // On surfnet, sign then submit manually
35214
+ if (isSurfnet) {
35215
+ const signedTx = await adapter.signTransaction(transaction);
35216
+ const signature = await connection.sendRawTransaction(signedTx.serialize(), {
35217
+ preflightCommitment: 'confirmed'
35218
+ });
35219
+ const confirmation = await connection.confirmTransaction({
35220
+ signature,
35221
+ blockhash,
35222
+ lastValidBlockHeight,
35223
+ }, 'confirmed');
35224
+ if (confirmation.value.err) {
35225
+ throw new Error(`Transaction failed: ${confirmation.value.err.toString()}`);
35226
+ }
35227
+ return signature;
35228
+ }
35229
+ // MWA supports signAndSendTransaction natively — this lets the wallet
35230
+ // app submit the transaction directly, which is more reliable on mobile
35231
+ if (adapter.sendTransaction) {
35232
+ const signature = await adapter.sendTransaction(transaction, connection, {
35233
+ preflightCommitment: 'confirmed',
35234
+ });
35235
+ await confirmAndCheckTransaction(connection, signature);
35236
+ return signature;
35237
+ }
35238
+ // Fallback: sign then submit
35239
+ const signedTx = await adapter.signTransaction(transaction);
35240
+ const signature = await connection.sendRawTransaction(signedTx.serialize(), {
35241
+ preflightCommitment: 'confirmed'
35242
+ });
35243
+ await confirmAndCheckTransaction(connection, signature);
35244
+ return signature;
35245
+ }
35246
+ catch (error) {
35247
+ 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'))) {
35248
+ await this.logout();
35249
+ throw new Error('Wallet connection lost. Please reconnect.');
35250
+ }
35251
+ const isUserRejection = (error === null || error === void 0 ? void 0 : error.code) === 4001 ||
35252
+ ((_c = error === null || error === void 0 ? void 0 : error.message) === null || _c === void 0 ? void 0 : _c.toLowerCase().includes('user rejected')) ||
35253
+ ((_d = error === null || error === void 0 ? void 0 : error.message) === null || _d === void 0 ? void 0 : _d.toLowerCase().includes('user denied')) ||
35254
+ ((_e = error === null || error === void 0 ? void 0 : error.message) === null || _e === void 0 ? void 0 : _e.toLowerCase().includes('user cancelled')) ||
35255
+ ((_f = error === null || error === void 0 ? void 0 : error.message) === null || _f === void 0 ? void 0 : _f.toLowerCase().includes('user canceled'));
35256
+ if (!isUserRejection) {
35257
+ console.error('[SolanaMobileWallet] Transaction failed:', error);
35258
+ }
35259
+ throw new Error(`Failed to execute transaction: ${error.message}`);
35260
+ }
35261
+ }
35262
+ async runTransaction(_evmTransactionData, solTransactionData, options) {
35263
+ var _a, _b, _c, _d, _e, _f, _g, _h;
35264
+ if (!solTransactionData) {
35265
+ throw new Error('Solana transaction data is required for mobile wallet');
35266
+ }
35267
+ const adapter = await this.ensureAdapter();
35268
+ if (!adapter.connected) {
35269
+ await this.login();
35270
+ }
35271
+ const rpcUrl = this.getRpcUrl(solTransactionData.network);
35272
+ const connection = new web3_js.Connection(rpcUrl, 'confirmed');
35273
+ const isSurfnet = rpcUrl === SURFNET_RPC_URL;
35274
+ try {
35275
+ const publicKey = adapter.publicKey;
35276
+ if (!publicKey) {
35277
+ throw new Error('No wallet connected');
35278
+ }
35279
+ const remainingAccounts = convertRemainingAccounts(solTransactionData.txArgs[0].remainingAccounts);
35280
+ let app_id = solTransactionData.appId;
35281
+ if (typeof window !== 'undefined' && window.CUSTOM_TAROBASE_APP_ID_HEADER) {
35282
+ app_id = window.CUSTOM_TAROBASE_APP_ID_HEADER;
35283
+ }
35284
+ if (!app_id) {
35285
+ throw new Error('App ID is required');
35286
+ }
35287
+ // Create wallet adapter interface for Anchor
35288
+ const walletAdapter = {
35289
+ publicKey,
35290
+ signTransaction: async (tx) => {
35291
+ return await adapter.signTransaction(tx);
35292
+ },
35293
+ signAllTransactions: async (txs) => {
35294
+ return await adapter.signAllTransactions(txs);
35295
+ }
35296
+ };
35297
+ const anchorProvider = new anchor__namespace.AnchorProvider(connection, walletAdapter, anchor__namespace.AnchorProvider.defaultOptions());
35298
+ const finalDeduped = [];
35299
+ for (const acc of remainingAccounts) {
35300
+ const existing = finalDeduped.find((d) => d.pubkey.equals(acc.pubkey));
35301
+ if (existing) {
35302
+ existing.isSigner = existing.isSigner || acc.isSigner;
35303
+ existing.isWritable = existing.isWritable || acc.isWritable;
35304
+ }
35305
+ else {
35306
+ finalDeduped.push(acc);
35307
+ }
35308
+ }
35309
+ const { tx } = await buildSetDocumentsTransaction(connection, solTransactionData.txArgs[0].idl, anchorProvider, publicKey, {
35310
+ app_id,
35311
+ documents: solTransactionData.txArgs[0].setDocumentData,
35312
+ delete_paths: solTransactionData.txArgs[0].deletePaths,
35313
+ txData: solTransactionData.txArgs[0].txData
35314
+ }, finalDeduped, solTransactionData.lutKey, solTransactionData.preInstructions, false);
35315
+ if ((options === null || options === void 0 ? void 0 : options.shouldSubmitTx) === false) {
35316
+ const signedTx = await walletAdapter.signTransaction(tx);
35317
+ return {
35318
+ signedTransaction: signedTx,
35319
+ blockNumber: 0,
35320
+ gasUsed: '0',
35321
+ data: ''
35322
+ };
35323
+ }
35324
+ // On surfnet, sign + submit manually
35325
+ if (isSurfnet) {
35326
+ const signedTx = await walletAdapter.signTransaction(tx);
35327
+ const { blockhash, lastValidBlockHeight } = await connection.getLatestBlockhash('confirmed');
35328
+ const signature = await connection.sendRawTransaction(signedTx.serialize(), {
35329
+ preflightCommitment: 'confirmed'
35330
+ });
35331
+ const confirmation = await connection.confirmTransaction({
35332
+ signature,
35333
+ blockhash,
35334
+ lastValidBlockHeight,
35335
+ }, 'confirmed');
35336
+ if (confirmation.value.err) {
35337
+ throw new Error(`Transaction failed: ${confirmation.value.err.toString()}`);
35338
+ }
35339
+ const txInfo = await connection.getParsedTransaction(signature, {
35340
+ maxSupportedTransactionVersion: 0,
35341
+ commitment: 'confirmed'
35342
+ });
35343
+ return {
35344
+ transactionSignature: signature,
35345
+ blockNumber: (txInfo === null || txInfo === void 0 ? void 0 : txInfo.slot) || 0,
35346
+ gasUsed: ((_a = txInfo === null || txInfo === void 0 ? void 0 : txInfo.meta) === null || _a === void 0 ? void 0 : _a.fee.toString()) || '0',
35347
+ data: txInfo === null || txInfo === void 0 ? void 0 : txInfo.meta,
35348
+ };
35349
+ }
35350
+ // Use MWA's sendTransaction for mobile-optimized submission
35351
+ let signature;
35352
+ if (adapter.sendTransaction) {
35353
+ signature = await adapter.sendTransaction(tx, connection, {
35354
+ preflightCommitment: 'confirmed',
35355
+ });
35356
+ }
35357
+ else {
35358
+ const signedTx = await walletAdapter.signTransaction(tx);
35359
+ signature = await connection.sendRawTransaction(signedTx.serialize(), {
35360
+ preflightCommitment: 'confirmed'
35361
+ });
35362
+ }
35363
+ const txInfo = await confirmAndCheckTransaction(connection, signature);
35364
+ return {
35365
+ transactionSignature: signature,
35366
+ blockNumber: (txInfo === null || txInfo === void 0 ? void 0 : txInfo.slot) || 0,
35367
+ gasUsed: ((_b = txInfo === null || txInfo === void 0 ? void 0 : txInfo.meta) === null || _b === void 0 ? void 0 : _b.fee.toString()) || '0',
35368
+ data: txInfo === null || txInfo === void 0 ? void 0 : txInfo.meta,
35369
+ };
35370
+ }
35371
+ catch (error) {
35372
+ 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'))) {
35373
+ await this.logout();
35374
+ throw new Error('Wallet connection lost. Please reconnect.');
35375
+ }
35376
+ const isUserRejection = (error === null || error === void 0 ? void 0 : error.code) === 4001 ||
35377
+ ((_e = error === null || error === void 0 ? void 0 : error.message) === null || _e === void 0 ? void 0 : _e.toLowerCase().includes('user rejected')) ||
35378
+ ((_f = error === null || error === void 0 ? void 0 : error.message) === null || _f === void 0 ? void 0 : _f.toLowerCase().includes('user denied')) ||
35379
+ ((_g = error === null || error === void 0 ? void 0 : error.message) === null || _g === void 0 ? void 0 : _g.toLowerCase().includes('user cancelled')) ||
35380
+ ((_h = error === null || error === void 0 ? void 0 : error.message) === null || _h === void 0 ? void 0 : _h.toLowerCase().includes('user canceled'));
35381
+ if (!isUserRejection) {
35382
+ console.error('[SolanaMobileWallet] Transaction failed:', error);
35383
+ }
35384
+ throw new Error(`Failed to execute transaction: ${error.message}`);
35385
+ }
35386
+ }
35387
+ async getNativeMethods() {
35388
+ return this.mwaAdapter;
35389
+ }
35390
+ /* ----------------------------------------------------------- *
35391
+ * Private Helpers
35392
+ * ----------------------------------------------------------- */
35393
+ getRpcUrl(network) {
35394
+ if (this.networkUrl) {
35395
+ return this.networkUrl;
35396
+ }
35397
+ if (network === 'solana_devnet') {
35398
+ return SOLANA_DEVNET_RPC_URL;
35399
+ }
35400
+ else if (network === 'solana_mainnet') {
35401
+ return SOLANA_MAINNET_RPC_URL;
35402
+ }
35403
+ else if (network === 'surfnet') {
35404
+ return SURFNET_RPC_URL;
35405
+ }
35406
+ return SOLANA_MAINNET_RPC_URL;
35407
+ }
35408
+ }
35409
+ SolanaMobileWalletProvider.instance = null;
35410
+
34900
35411
  let currentAuthProvider = null;
34901
35412
  let currentAuthMethod = null;
34902
35413
  let initConfig = null;
@@ -34970,7 +35481,7 @@ const SOLANA_DEVNET_RPC_URL = "https://idelle-8nxsep-fast-devnet.helius-rpc.com"
34970
35481
  const SOLANA_MAINNET_RPC_URL = "https://celestia-cegncv-fast-mainnet.helius-rpc.com";
34971
35482
  const SURFNET_RPC_URL = "https://surfpool.fly.dev";
34972
35483
  async function getAuthProvider(config) {
34973
- var _a, _b, _c, _d;
35484
+ var _a, _b, _c, _d, _e, _f;
34974
35485
  if (currentAuthProvider) {
34975
35486
  return currentAuthProvider;
34976
35487
  }
@@ -34985,7 +35496,7 @@ async function getAuthProvider(config) {
34985
35496
  return currentAuthProvider;
34986
35497
  }
34987
35498
  // If the user previously logged in with a specific method, use that instead
34988
- const validAuthMethods = ['privy', 'phantom', 'wallet', 'rainbowkit', 'coinbase-smart-wallet', 'onboard', 'none'];
35499
+ const validAuthMethods = ['privy', 'phantom', 'wallet', 'rainbowkit', 'coinbase-smart-wallet', 'onboard', 'mobile-wallet-adapter', 'none'];
34989
35500
  const storedMethod = getStoredAuthMethod();
34990
35501
  const authMethod = (storedMethod && validAuthMethods.includes(storedMethod))
34991
35502
  ? storedMethod
@@ -34994,7 +35505,25 @@ async function getAuthProvider(config) {
34994
35505
  // Invalid stored value — clear it
34995
35506
  setStoredAuthMethod(null);
34996
35507
  }
34997
- const rpcUrl = (_a = config.rpcUrl) !== null && _a !== void 0 ? _a : null;
35508
+ // --- Register MWA as a wallet-standard wallet on mobile ---
35509
+ // On Android (TWA via Bubblewrap, Chrome, or mobile browser), register the
35510
+ // Mobile Wallet Adapter so it appears in wallet discovery (e.g. Phantom's
35511
+ // useDiscoveredWallets, or any wallet-standard consumer). This makes Seed
35512
+ // Vault, Solflare, and other MWA wallets show up alongside injected wallets
35513
+ // in the existing Phantom/Privy modals — without overriding the configured
35514
+ // authMethod. Email login, deeplinks, and all other flows stay intact.
35515
+ //
35516
+ // Only authMethod: 'mobile-wallet-adapter' (explicit opt-in) bypasses
35517
+ // Phantom/Privy entirely and uses MWA as the sole provider.
35518
+ if (isMobileWalletAvailable()) {
35519
+ registerMobileWalletAdapter({
35520
+ appIdentity: (_b = (_a = config.mobileWalletConfig) === null || _a === void 0 ? void 0 : _a.appIdentity) !== null && _b !== void 0 ? _b : {
35521
+ name: config.name || undefined,
35522
+ uri: typeof window !== 'undefined' ? window.location.origin : undefined,
35523
+ },
35524
+ }).catch(() => { });
35525
+ }
35526
+ const rpcUrl = (_c = config.rpcUrl) !== null && _c !== void 0 ? _c : null;
34998
35527
  currentAuthMethod = authMethod;
34999
35528
  switch (authMethod) {
35000
35529
  case "wallet":
@@ -35004,15 +35533,18 @@ async function getAuthProvider(config) {
35004
35533
  console.warn("Rainbow Kit auth is not yet supported.");
35005
35534
  break;
35006
35535
  case "privy":
35007
- currentAuthProvider = new PrivyWalletProvider((_b = config.name) !== null && _b !== void 0 ? _b : null, (_c = config.logoUrl) !== null && _c !== void 0 ? _c : null, config.privyConfig, rpcUrl);
35536
+ currentAuthProvider = new PrivyWalletProvider((_d = config.name) !== null && _d !== void 0 ? _d : null, (_e = config.logoUrl) !== null && _e !== void 0 ? _e : null, config.privyConfig, rpcUrl);
35008
35537
  break;
35009
35538
  case "phantom":
35010
35539
  currentAuthProvider = new PhantomWalletProvider(rpcUrl, config.phantomConfig);
35011
- if ((_d = config.phantomConfig) === null || _d === void 0 ? void 0 : _d.enablePrivyFallback) {
35540
+ if ((_f = config.phantomConfig) === null || _f === void 0 ? void 0 : _f.enablePrivyFallback) {
35012
35541
  currentAuthProvider.onSwitchToPrivy =
35013
35542
  () => hotSwapToPrivyProvider(config);
35014
35543
  }
35015
35544
  break;
35545
+ case "mobile-wallet-adapter":
35546
+ currentAuthProvider = new SolanaMobileWalletProvider(rpcUrl, config.mobileWalletConfig);
35547
+ break;
35016
35548
  case "onboard":
35017
35549
  console.warn("Onboard auth is not yet supported.");
35018
35550
  break;
@@ -35235,6 +35767,7 @@ exports.OffchainAuthProvider = OffchainAuthProvider;
35235
35767
  exports.PhantomWalletProvider = PhantomWalletProvider;
35236
35768
  exports.PrivyWalletProvider = PrivyWalletProvider;
35237
35769
  exports.ServerSessionManager = ServerSessionManager;
35770
+ exports.SolanaMobileWalletProvider = SolanaMobileWalletProvider;
35238
35771
  exports.WebSessionManager = WebSessionManager;
35239
35772
  exports.aggregate = aggregate;
35240
35773
  exports.bs58 = bs58;
@@ -35257,12 +35790,14 @@ exports.getCurrentUser = getCurrentUser;
35257
35790
  exports.getFiles = getFiles;
35258
35791
  exports.getIdToken = getIdToken;
35259
35792
  exports.init = init;
35793
+ exports.isMobileWalletAvailable = isMobileWalletAvailable;
35260
35794
  exports.login = login;
35261
35795
  exports.logout = logout;
35262
35796
  exports.onAuthLoadingChanged = onAuthLoadingChanged;
35263
35797
  exports.onAuthStateChanged = onAuthStateChanged;
35264
35798
  exports.reconnectWithNewAuth = reconnectWithNewAuth;
35265
35799
  exports.refreshSession = refreshSession;
35800
+ exports.registerMobileWalletAdapter = registerMobileWalletAdapter;
35266
35801
  exports.runExpression = runExpression;
35267
35802
  exports.runExpressionMany = runExpressionMany;
35268
35803
  exports.runQuery = runQuery;
@@ -35276,4 +35811,4 @@ exports.signSessionCreateMessage = signSessionCreateMessage;
35276
35811
  exports.signTransaction = signTransaction;
35277
35812
  exports.subscribe = subscribe;
35278
35813
  exports.useAuth = useAuth;
35279
- //# sourceMappingURL=index-YzZ1QavD.js.map
35814
+ //# sourceMappingURL=index-C4TkISTV.js.map