@pooflabs/web 0.0.85-rc1 → 0.0.85-rc3
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.
- package/dist/auth/providers/solana-mobile-wallet-provider.d.ts +5 -0
- package/dist/{index-DlyeWzMk.js → index-B5qYY4YM.js} +2 -2
- package/dist/index-B5qYY4YM.js.map +1 -0
- package/dist/{index-Buu8v-Oe.esm.js → index-BE-VWSJT.esm.js} +2 -2
- package/dist/{index-Buu8v-Oe.esm.js.map → index-BE-VWSJT.esm.js.map} +1 -1
- package/dist/{index-BoWQVxMI.js → index-BaKs3A8s.js} +2 -2
- package/dist/{index-BoWQVxMI.js.map → index-BaKs3A8s.js.map} +1 -1
- package/dist/{index-C2p1Cldz.js → index-BzeiIIwF.js} +3 -3
- package/dist/{index-C2p1Cldz.js.map → index-BzeiIIwF.js.map} +1 -1
- package/dist/{index-ZKzq5QT_.esm.js → index-C4AnWFs_.esm.js} +421 -13
- package/dist/{index-ZKzq5QT_.esm.js.map → index-C4AnWFs_.esm.js.map} +1 -1
- package/dist/index-TzHXEf3-.esm.js +6 -0
- package/dist/index-TzHXEf3-.esm.js.map +1 -0
- package/dist/{index-R7cvXys2.js → index-bEXLwE7_.js} +421 -13
- package/dist/{index-R7cvXys2.js.map → index-bEXLwE7_.js.map} +1 -1
- package/dist/{index-4TKz3Mn_.esm.js → index-dqqR5q7b.esm.js} +3 -3
- package/dist/{index-4TKz3Mn_.esm.js.map → index-dqqR5q7b.esm.js.map} +1 -1
- package/dist/{index.browser-BQSN-6X2.js → index.browser-CN6obNQM.js} +2 -118
- package/dist/{index.browser-BQSN-6X2.js.map → index.browser-CN6obNQM.js.map} +1 -1
- package/dist/{index.browser-DZCNegue.js → index.browser-CZIJCtms.js} +2 -2
- package/dist/{index.browser-DZCNegue.js.map → index.browser-CZIJCtms.js.map} +1 -1
- package/dist/{index.browser-tPepE5fo.esm.js → index.browser-D8ttddP4.esm.js} +3 -117
- package/dist/{index.browser-tPepE5fo.esm.js.map → index.browser-D8ttddP4.esm.js.map} +1 -1
- package/dist/{index.browser-zfGYm0ST.esm.js → index.browser-DQIwLToJ.esm.js} +2 -2
- package/dist/{index.browser-zfGYm0ST.esm.js.map → index.browser-DQIwLToJ.esm.js.map} +1 -1
- package/dist/index.esm.js +1 -1
- package/dist/index.js +1 -1
- package/dist/{index.native-BPQqeP6_.esm.js → index.native-DLziTime.esm.js} +4 -4
- package/dist/{index.native-BPQqeP6_.esm.js.map → index.native-DLziTime.esm.js.map} +1 -1
- package/dist/{index.native-BGaUOX9f.js → index.native-pG1NTZ0f.js} +4 -4
- package/dist/{index.native-BGaUOX9f.js.map → index.native-pG1NTZ0f.js.map} +1 -1
- package/dist/index.native.esm.js +1 -1
- package/dist/index.native.js +1 -1
- package/dist/{phantom-wallet-provider-DheGhOp4.esm.js → phantom-wallet-provider-CP6NXRwG.esm.js} +4 -4
- package/dist/{phantom-wallet-provider-DheGhOp4.esm.js.map → phantom-wallet-provider-CP6NXRwG.esm.js.map} +1 -1
- package/dist/{phantom-wallet-provider-MFcwrRpJ.js → phantom-wallet-provider-zBp7-uEw.js} +4 -4
- package/dist/{phantom-wallet-provider-MFcwrRpJ.js.map → phantom-wallet-provider-zBp7-uEw.js.map} +1 -1
- package/dist/{privy-wallet-provider-D15Au3j8.esm.js → privy-wallet-provider-CGYvf3-r.esm.js} +3 -3
- package/dist/{privy-wallet-provider-D15Au3j8.esm.js.map → privy-wallet-provider-CGYvf3-r.esm.js.map} +1 -1
- package/dist/{privy-wallet-provider-CFw6o7O5.js → privy-wallet-provider-CoyW5Gdg.js} +3 -3
- package/dist/{privy-wallet-provider-CFw6o7O5.js.map → privy-wallet-provider-CoyW5Gdg.js.map} +1 -1
- package/dist/{solana-mobile-wallet-provider-ChHh-U_p.esm.js → solana-mobile-wallet-provider-B8rHfsPN.esm.js} +414 -9
- package/dist/solana-mobile-wallet-provider-B8rHfsPN.esm.js.map +1 -0
- package/dist/{solana-mobile-wallet-provider-BM9wdF0m.js → solana-mobile-wallet-provider-CN-D_H4l.js} +414 -9
- package/dist/solana-mobile-wallet-provider-CN-D_H4l.js.map +1 -0
- package/package.json +1 -1
- package/dist/index-COF6zNCs.esm.js +0 -6
- package/dist/index-COF6zNCs.esm.js.map +0 -1
- package/dist/index-DlyeWzMk.js.map +0 -1
- package/dist/solana-mobile-wallet-provider-BM9wdF0m.js.map +0 -1
- package/dist/solana-mobile-wallet-provider-ChHh-U_p.esm.js.map +0 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { b as bufferExports } from './index-
|
|
2
|
-
import { g as getPlatform, k as setAuthLoading, W as WebSessionManager, s as setCurrentUser, l as genAuthNonce, m as genSolanaMessage, n as createSessionWithSignature, d as base58, e as confirmAndCheckTransaction, c as convertRemainingAccounts, b as buildSetDocumentsTransaction, a as SOLANA_DEVNET_RPC_URL, S as SOLANA_MAINNET_RPC_URL, h as SURFNET_RPC_URL } from './index.native-
|
|
1
|
+
import { b as bufferExports } from './index-TzHXEf3-.esm.js';
|
|
2
|
+
import { g as getPlatform, k as setAuthLoading, W as WebSessionManager, s as setCurrentUser, l as genAuthNonce, m as genSolanaMessage, n as createSessionWithSignature, d as base58, e as confirmAndCheckTransaction, c as convertRemainingAccounts, b as buildSetDocumentsTransaction, a as SOLANA_DEVNET_RPC_URL, S as SOLANA_MAINNET_RPC_URL, h as SURFNET_RPC_URL } from './index.native-DLziTime.esm.js';
|
|
3
3
|
import { PublicKey, Connection, VersionedTransaction, VersionedMessage, Transaction } from '@solana/web3.js';
|
|
4
4
|
import * as anchor from '@coral-xyz/anchor';
|
|
5
5
|
import 'axios';
|
|
@@ -8,6 +8,381 @@ import 'react';
|
|
|
8
8
|
const ED25519_SIGNATURE_LENGTH = 64;
|
|
9
9
|
const STORED_AUTH_METHOD_KEY = 'tarobase_last_auth_method';
|
|
10
10
|
const MWA_AUTH_METHOD = 'mobile-wallet-adapter';
|
|
11
|
+
function findMwaError(e, maxDepth = 5) {
|
|
12
|
+
var _a;
|
|
13
|
+
let cur = e;
|
|
14
|
+
let depth = 0;
|
|
15
|
+
while (cur && depth < maxDepth) {
|
|
16
|
+
if ((cur === null || cur === void 0 ? void 0 : cur.name) === 'SolanaMobileWalletAdapterError' && typeof (cur === null || cur === void 0 ? void 0 : cur.code) === 'string') {
|
|
17
|
+
return { code: cur.code, message: String((_a = cur.message) !== null && _a !== void 0 ? _a : '') };
|
|
18
|
+
}
|
|
19
|
+
cur = cur === null || cur === void 0 ? void 0 : cur.cause;
|
|
20
|
+
depth++;
|
|
21
|
+
}
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Returns the matched MwaErrorInfo when the error is from an association
|
|
26
|
+
* failure that an automatic retry can recover from (i.e. the wallet exists
|
|
27
|
+
* on-device but the dApp's protocol session didn't complete in time). Returns
|
|
28
|
+
* null for non-retryable errors (user cancel, unknown wallet errors, etc.).
|
|
29
|
+
*
|
|
30
|
+
* Specifically:
|
|
31
|
+
* - ERROR_WALLET_NOT_FOUND: thrown from the protocol's startScenario when
|
|
32
|
+
* it gave up waiting for a wallet to respond. On Seeker this races the
|
|
33
|
+
* first-time-consent UI on the very first authorize.
|
|
34
|
+
* - ERROR_SESSION_TIMEOUT: similar — the protocol's session-establishment
|
|
35
|
+
* timer expired.
|
|
36
|
+
* - ERROR_ASSOCIATION_CANCELLED: shared by user-cancel ("Wallet connection
|
|
37
|
+
* cancelled by user") AND the 30s wallet-standard WALLET_ASSOCIATION_TIMEOUT
|
|
38
|
+
* ("Wallet connection timed out"). Discriminate by message — never retry
|
|
39
|
+
* a user cancel.
|
|
40
|
+
*/
|
|
41
|
+
function isMwaAssociationRetryable(e) {
|
|
42
|
+
const info = findMwaError(e);
|
|
43
|
+
if (!info)
|
|
44
|
+
return null;
|
|
45
|
+
if (info.code === 'ERROR_WALLET_NOT_FOUND')
|
|
46
|
+
return info;
|
|
47
|
+
if (info.code === 'ERROR_SESSION_TIMEOUT')
|
|
48
|
+
return info;
|
|
49
|
+
if (info.code === 'ERROR_ASSOCIATION_CANCELLED' && /timed out/i.test(info.message))
|
|
50
|
+
return info;
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Single-retry wrapper for MWA association failures. Used ONLY for login's
|
|
55
|
+
* `standard:connect` and `solana:signMessage` calls — never for
|
|
56
|
+
* `signAndSendTransaction`/`runTransaction` because retry on a path that
|
|
57
|
+
* may have already submitted a tx can double-send.
|
|
58
|
+
*
|
|
59
|
+
* The retry exists for one specific scenario: on first-time MWA usage from a
|
|
60
|
+
* given origin on Seeker, the protocol's session-establishment timer races
|
|
61
|
+
* Seeker's first-time consent UI. The user reads the consent sheet, taps
|
|
62
|
+
* Connect — but by then the protocol has given up and thrown
|
|
63
|
+
* ERROR_WALLET_NOT_FOUND. The consent itself IS persisted on Seeker though,
|
|
64
|
+
* so a second attempt skips the consent sheet, jumps straight to
|
|
65
|
+
* Verify/Approve, and completes inside the timeout.
|
|
66
|
+
*/
|
|
67
|
+
async function withMwaAssociationRetry(label, fn) {
|
|
68
|
+
const t0 = Date.now();
|
|
69
|
+
console.log(`[MWA-DEBUG] ${label} attempt=1 start`);
|
|
70
|
+
try {
|
|
71
|
+
const result = await fn();
|
|
72
|
+
console.log(`[MWA-DEBUG] ${label} attempt=1 ok (${Date.now() - t0}ms)`);
|
|
73
|
+
return result;
|
|
74
|
+
}
|
|
75
|
+
catch (e) {
|
|
76
|
+
const info = findMwaError(e);
|
|
77
|
+
console.log(`[MWA-DEBUG] ${label} attempt=1 err (${Date.now() - t0}ms)`, {
|
|
78
|
+
outer: { name: e === null || e === void 0 ? void 0 : e.name, message: e === null || e === void 0 ? void 0 : e.message },
|
|
79
|
+
mwa: info,
|
|
80
|
+
});
|
|
81
|
+
const retryable = isMwaAssociationRetryable(e);
|
|
82
|
+
if (!retryable)
|
|
83
|
+
throw e;
|
|
84
|
+
// Seeker's consent sheet is a bottom-sheet overlay — Chrome doesn't
|
|
85
|
+
// reliably flip document.visibilityState to 'hidden' while it's open,
|
|
86
|
+
// so visibility-based waits fire too early. Use a fixed delay long
|
|
87
|
+
// enough for Seeker to dismiss its sheet and the OS to release intent
|
|
88
|
+
// state. 2.5s is empirically safe; tune from device traces if needed.
|
|
89
|
+
console.log(`[MWA-DEBUG] ${label} retryable (${retryable.code}); waiting 2500ms before retry`);
|
|
90
|
+
await new Promise(r => setTimeout(r, 2500));
|
|
91
|
+
const t1 = Date.now();
|
|
92
|
+
console.log(`[MWA-DEBUG] ${label} attempt=2 start`);
|
|
93
|
+
try {
|
|
94
|
+
const result = await fn();
|
|
95
|
+
console.log(`[MWA-DEBUG] ${label} attempt=2 ok (${Date.now() - t1}ms)`);
|
|
96
|
+
return result;
|
|
97
|
+
}
|
|
98
|
+
catch (e2) {
|
|
99
|
+
const info2 = findMwaError(e2);
|
|
100
|
+
console.log(`[MWA-DEBUG] ${label} attempt=2 err (${Date.now() - t1}ms)`, {
|
|
101
|
+
outer: { name: e2 === null || e2 === void 0 ? void 0 : e2.name, message: e2 === null || e2 === void 0 ? void 0 : e2.message },
|
|
102
|
+
mwa: info2,
|
|
103
|
+
});
|
|
104
|
+
// Only mask the error with the clean Seeker message when the
|
|
105
|
+
// second failure is also an association-flavored error. If it's
|
|
106
|
+
// a user cancel, wallet rejection, or unknown error, rethrow
|
|
107
|
+
// the original so the host app surfaces the real cause.
|
|
108
|
+
if (isMwaAssociationRetryable(e2)) {
|
|
109
|
+
throw new Error("Couldn't connect to your Seeker wallet. Please try again.");
|
|
110
|
+
}
|
|
111
|
+
throw e2;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* User-gesture-mediated wallet-standard sign helper.
|
|
117
|
+
*
|
|
118
|
+
* Why this exists: login flows that go through wallet-standard call two
|
|
119
|
+
* separate transacts (standard:connect, then solana:signMessage). Each
|
|
120
|
+
* transact dispatches its own `solana-wallet:` Android intent navigation
|
|
121
|
+
* via `window.location.assign(associationUrl)` (see
|
|
122
|
+
* @solana-mobile/mobile-wallet-adapter-protocol/lib/cjs/index.browser.js
|
|
123
|
+
* `launchAssociation()` at line 459). Chrome requires **transient user
|
|
124
|
+
* activation** for each custom-scheme navigation. The first transact
|
|
125
|
+
* consumes the activation from the user's "Continue to Allow" tap on the
|
|
126
|
+
* LNA modal; by the time the second transact (signMessage) runs as a JS
|
|
127
|
+
* continuation, the activation has decayed, Chrome blocks the navigation,
|
|
128
|
+
* no `blur` event fires, the protocol's `getDetectionPromise` (3000ms
|
|
129
|
+
* timeout, line 433) rejects, and we get `ERROR_WALLET_NOT_FOUND`.
|
|
130
|
+
*
|
|
131
|
+
* Fix: show a Tarobase-controlled modal between the two transacts. When the
|
|
132
|
+
* user taps the modal's "Sign in" button, that tap IS a fresh user
|
|
133
|
+
* activation. We invoke the sign function directly inside the click handler
|
|
134
|
+
* — no `await` between the tap and the call — so the activation propagates
|
|
135
|
+
* to the protocol's `location.assign`.
|
|
136
|
+
*
|
|
137
|
+
* Failure recovery is also user-gesture driven: if the sign function fails
|
|
138
|
+
* with a retryable association error, we re-enable the button so the user's
|
|
139
|
+
* next tap is a new activation (a real retry). A timer-based retry would
|
|
140
|
+
* just hit the same Chrome block. Cap at 3 attempts before giving up.
|
|
141
|
+
*/
|
|
142
|
+
async function awaitSignInGestureAndSign(label, theme, signFn) {
|
|
143
|
+
if (typeof document === 'undefined' || typeof window === 'undefined') {
|
|
144
|
+
// SSR / non-browser: skip the gesture, just call (the activation
|
|
145
|
+
// model doesn't apply outside the browser).
|
|
146
|
+
const results = await signFn();
|
|
147
|
+
if (!results || results.length === 0)
|
|
148
|
+
throw new Error('MWA returned no signature');
|
|
149
|
+
return results[0];
|
|
150
|
+
}
|
|
151
|
+
return new Promise((resolve, reject) => {
|
|
152
|
+
const isDark = theme === 'dark'
|
|
153
|
+
|| (theme == null
|
|
154
|
+
&& typeof window.matchMedia === 'function'
|
|
155
|
+
&& window.matchMedia('(prefers-color-scheme: dark)').matches);
|
|
156
|
+
// Palette
|
|
157
|
+
const overlayBg = 'rgba(0, 0, 0, 0.62)';
|
|
158
|
+
const cardBg = isDark ? '#1a1a1f' : '#ffffff';
|
|
159
|
+
const titleColor = isDark ? '#ffffff' : '#0a0a0a';
|
|
160
|
+
const subtitleColor = isDark ? '#a1a1aa' : '#52525b';
|
|
161
|
+
const btnBg = isDark ? '#ffffff' : '#0a0a0a';
|
|
162
|
+
const btnText = isDark ? '#0a0a0a' : '#ffffff';
|
|
163
|
+
const btnDisabledBg = isDark ? '#3f3f46' : '#d4d4d8';
|
|
164
|
+
const btnDisabledText = isDark ? '#71717a' : '#71717a';
|
|
165
|
+
const errorColor = isDark ? '#fca5a5' : '#dc2626';
|
|
166
|
+
const closeColor = isDark ? '#71717a' : '#a1a1aa';
|
|
167
|
+
const fontStack = '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif';
|
|
168
|
+
const overlay = document.createElement('div');
|
|
169
|
+
overlay.setAttribute('data-tarobase-mwa-gesture', 'true');
|
|
170
|
+
overlay.style.cssText = [
|
|
171
|
+
'position: fixed',
|
|
172
|
+
'inset: 0',
|
|
173
|
+
'z-index: 2147483646',
|
|
174
|
+
`background: ${overlayBg}`,
|
|
175
|
+
'display: flex',
|
|
176
|
+
'align-items: center',
|
|
177
|
+
'justify-content: center',
|
|
178
|
+
'padding: 20px',
|
|
179
|
+
'box-sizing: border-box',
|
|
180
|
+
`font-family: ${fontStack}`,
|
|
181
|
+
].join('; ');
|
|
182
|
+
const card = document.createElement('div');
|
|
183
|
+
card.style.cssText = [
|
|
184
|
+
`background: ${cardBg}`,
|
|
185
|
+
'border-radius: 20px',
|
|
186
|
+
'padding: 28px 24px 24px',
|
|
187
|
+
'max-width: 340px',
|
|
188
|
+
'width: 100%',
|
|
189
|
+
'box-shadow: 0 20px 50px rgba(0, 0, 0, 0.28)',
|
|
190
|
+
'position: relative',
|
|
191
|
+
'box-sizing: border-box',
|
|
192
|
+
].join('; ');
|
|
193
|
+
const closeBtn = document.createElement('button');
|
|
194
|
+
closeBtn.setAttribute('aria-label', 'Close');
|
|
195
|
+
closeBtn.innerHTML = '×';
|
|
196
|
+
closeBtn.style.cssText = [
|
|
197
|
+
'position: absolute',
|
|
198
|
+
'top: 12px',
|
|
199
|
+
'right: 12px',
|
|
200
|
+
'background: transparent',
|
|
201
|
+
'border: none',
|
|
202
|
+
`color: ${closeColor}`,
|
|
203
|
+
'font-size: 24px',
|
|
204
|
+
'line-height: 1',
|
|
205
|
+
'cursor: pointer',
|
|
206
|
+
'padding: 6px 10px',
|
|
207
|
+
'border-radius: 8px',
|
|
208
|
+
].join('; ');
|
|
209
|
+
const title = document.createElement('div');
|
|
210
|
+
title.textContent = 'Almost there';
|
|
211
|
+
title.style.cssText = [
|
|
212
|
+
`color: ${titleColor}`,
|
|
213
|
+
'font-size: 20px',
|
|
214
|
+
'font-weight: 600',
|
|
215
|
+
'margin-bottom: 6px',
|
|
216
|
+
'text-align: center',
|
|
217
|
+
].join('; ');
|
|
218
|
+
const subtitle = document.createElement('div');
|
|
219
|
+
subtitle.textContent = 'Tap to sign in with your wallet';
|
|
220
|
+
subtitle.style.cssText = [
|
|
221
|
+
`color: ${subtitleColor}`,
|
|
222
|
+
'font-size: 14px',
|
|
223
|
+
'line-height: 1.4',
|
|
224
|
+
'margin-bottom: 22px',
|
|
225
|
+
'text-align: center',
|
|
226
|
+
].join('; ');
|
|
227
|
+
const errorRow = document.createElement('div');
|
|
228
|
+
errorRow.style.cssText = [
|
|
229
|
+
`color: ${errorColor}`,
|
|
230
|
+
'font-size: 13px',
|
|
231
|
+
'line-height: 1.4',
|
|
232
|
+
'margin-bottom: 14px',
|
|
233
|
+
'text-align: center',
|
|
234
|
+
'min-height: 0',
|
|
235
|
+
'transition: min-height 100ms ease',
|
|
236
|
+
].join('; ');
|
|
237
|
+
const button = document.createElement('button');
|
|
238
|
+
button.textContent = 'Sign in';
|
|
239
|
+
const setButtonEnabledStyle = () => {
|
|
240
|
+
button.style.cssText = [
|
|
241
|
+
`background: ${btnBg}`,
|
|
242
|
+
`color: ${btnText}`,
|
|
243
|
+
'border: none',
|
|
244
|
+
'border-radius: 14px',
|
|
245
|
+
'padding: 14px 20px',
|
|
246
|
+
'font-size: 16px',
|
|
247
|
+
'font-weight: 600',
|
|
248
|
+
'width: 100%',
|
|
249
|
+
'cursor: pointer',
|
|
250
|
+
'-webkit-tap-highlight-color: transparent',
|
|
251
|
+
'box-sizing: border-box',
|
|
252
|
+
`font-family: ${fontStack}`,
|
|
253
|
+
].join('; ');
|
|
254
|
+
};
|
|
255
|
+
const setButtonDisabledStyle = () => {
|
|
256
|
+
button.style.cssText = [
|
|
257
|
+
`background: ${btnDisabledBg}`,
|
|
258
|
+
`color: ${btnDisabledText}`,
|
|
259
|
+
'border: none',
|
|
260
|
+
'border-radius: 14px',
|
|
261
|
+
'padding: 14px 20px',
|
|
262
|
+
'font-size: 16px',
|
|
263
|
+
'font-weight: 600',
|
|
264
|
+
'width: 100%',
|
|
265
|
+
'cursor: default',
|
|
266
|
+
'-webkit-tap-highlight-color: transparent',
|
|
267
|
+
'box-sizing: border-box',
|
|
268
|
+
`font-family: ${fontStack}`,
|
|
269
|
+
].join('; ');
|
|
270
|
+
};
|
|
271
|
+
setButtonEnabledStyle();
|
|
272
|
+
card.appendChild(closeBtn);
|
|
273
|
+
card.appendChild(title);
|
|
274
|
+
card.appendChild(subtitle);
|
|
275
|
+
card.appendChild(errorRow);
|
|
276
|
+
card.appendChild(button);
|
|
277
|
+
overlay.appendChild(card);
|
|
278
|
+
document.body.appendChild(overlay);
|
|
279
|
+
let settled = false;
|
|
280
|
+
let attemptCount = 0;
|
|
281
|
+
const MAX_ATTEMPTS = 3;
|
|
282
|
+
const cleanup = () => {
|
|
283
|
+
try {
|
|
284
|
+
overlay.remove();
|
|
285
|
+
}
|
|
286
|
+
catch ( /* ignore */_a) { /* ignore */ }
|
|
287
|
+
document.removeEventListener('keydown', onKeydown);
|
|
288
|
+
};
|
|
289
|
+
const finishResolve = (value) => {
|
|
290
|
+
if (settled)
|
|
291
|
+
return;
|
|
292
|
+
settled = true;
|
|
293
|
+
cleanup();
|
|
294
|
+
resolve(value);
|
|
295
|
+
};
|
|
296
|
+
const finishReject = (err) => {
|
|
297
|
+
if (settled)
|
|
298
|
+
return;
|
|
299
|
+
settled = true;
|
|
300
|
+
cleanup();
|
|
301
|
+
reject(err);
|
|
302
|
+
};
|
|
303
|
+
const handleCancel = () => {
|
|
304
|
+
// Phrasing matches login()'s isUserRejection substring check so
|
|
305
|
+
// the existing catch suppresses error-log noise.
|
|
306
|
+
finishReject(new Error('User cancelled wallet sign in'));
|
|
307
|
+
};
|
|
308
|
+
closeBtn.addEventListener('click', () => {
|
|
309
|
+
console.log(`[MWA-DEBUG] ${label} gesture: close clicked`);
|
|
310
|
+
handleCancel();
|
|
311
|
+
});
|
|
312
|
+
overlay.addEventListener('click', (e) => {
|
|
313
|
+
if (e.target === overlay) {
|
|
314
|
+
console.log(`[MWA-DEBUG] ${label} gesture: overlay clicked (cancel)`);
|
|
315
|
+
handleCancel();
|
|
316
|
+
}
|
|
317
|
+
});
|
|
318
|
+
const onKeydown = (e) => {
|
|
319
|
+
if (e.key === 'Escape') {
|
|
320
|
+
console.log(`[MWA-DEBUG] ${label} gesture: Escape pressed (cancel)`);
|
|
321
|
+
handleCancel();
|
|
322
|
+
}
|
|
323
|
+
};
|
|
324
|
+
document.addEventListener('keydown', onKeydown);
|
|
325
|
+
button.addEventListener('click', () => {
|
|
326
|
+
if (settled)
|
|
327
|
+
return;
|
|
328
|
+
attemptCount++;
|
|
329
|
+
const attempt = attemptCount;
|
|
330
|
+
console.log(`[MWA-DEBUG] ${label} gesture: button click attempt=${attempt}`);
|
|
331
|
+
// Disable to prevent double-clicks while the wallet popup is up.
|
|
332
|
+
button.disabled = true;
|
|
333
|
+
setButtonDisabledStyle();
|
|
334
|
+
const originalText = 'Sign in';
|
|
335
|
+
button.textContent = 'Signing in…';
|
|
336
|
+
errorRow.textContent = '';
|
|
337
|
+
errorRow.style.minHeight = '0';
|
|
338
|
+
// CRITICAL: invoke signFn() synchronously inside the click handler
|
|
339
|
+
// so Chrome's transient user activation propagates to the
|
|
340
|
+
// protocol's window.location.assign(associationUrl) inside
|
|
341
|
+
// launchAssociation(). Do not `await` before calling.
|
|
342
|
+
const t0 = Date.now();
|
|
343
|
+
console.log(`[MWA-DEBUG] ${label} gesture: signMessage start (attempt=${attempt})`);
|
|
344
|
+
signFn().then((results) => {
|
|
345
|
+
const elapsed = Date.now() - t0;
|
|
346
|
+
if (!results || results.length === 0) {
|
|
347
|
+
console.log(`[MWA-DEBUG] ${label} gesture: signMessage returned empty (attempt=${attempt}, ${elapsed}ms)`);
|
|
348
|
+
finishReject(new Error('MWA returned no signature'));
|
|
349
|
+
return;
|
|
350
|
+
}
|
|
351
|
+
console.log(`[MWA-DEBUG] ${label} gesture: signMessage ok (attempt=${attempt}, ${elapsed}ms)`);
|
|
352
|
+
finishResolve(results[0]);
|
|
353
|
+
}).catch((err) => {
|
|
354
|
+
const elapsed = Date.now() - t0;
|
|
355
|
+
const info = findMwaError(err);
|
|
356
|
+
console.log(`[MWA-DEBUG] ${label} gesture: signMessage err (attempt=${attempt}, ${elapsed}ms)`, {
|
|
357
|
+
outer: { name: err === null || err === void 0 ? void 0 : err.name, message: err === null || err === void 0 ? void 0 : err.message },
|
|
358
|
+
mwa: info,
|
|
359
|
+
});
|
|
360
|
+
const retryable = isMwaAssociationRetryable(err);
|
|
361
|
+
if (retryable && attempt < MAX_ATTEMPTS) {
|
|
362
|
+
// Re-enable the button so the user's next tap provides a
|
|
363
|
+
// fresh user activation. Show inline error text.
|
|
364
|
+
console.log(`[MWA-DEBUG] ${label} gesture: retryable (${retryable.code}); awaiting user tap to retry (attempt ${attempt}/${MAX_ATTEMPTS})`);
|
|
365
|
+
button.disabled = false;
|
|
366
|
+
setButtonEnabledStyle();
|
|
367
|
+
button.textContent = originalText;
|
|
368
|
+
errorRow.textContent = "Couldn't connect — tap to try again";
|
|
369
|
+
errorRow.style.minHeight = '20px';
|
|
370
|
+
return;
|
|
371
|
+
}
|
|
372
|
+
if (retryable) {
|
|
373
|
+
// Hit the attempt cap with a still-retryable failure.
|
|
374
|
+
console.log(`[MWA-DEBUG] ${label} gesture: retryable but attempt cap reached (${attempt})`);
|
|
375
|
+
finishReject(new Error("Couldn't connect to your Seeker wallet. Please try again."));
|
|
376
|
+
return;
|
|
377
|
+
}
|
|
378
|
+
// Non-retryable error (user cancel inside Seeker, wallet
|
|
379
|
+
// rejected sign, unknown error, etc.) — surface as-is.
|
|
380
|
+
finishReject(err);
|
|
381
|
+
});
|
|
382
|
+
});
|
|
383
|
+
console.log(`[MWA-DEBUG] ${label} gesture: modal shown`);
|
|
384
|
+
});
|
|
385
|
+
}
|
|
11
386
|
/**
|
|
12
387
|
* Normalize a chain string to a wallet-standard Solana chain identifier.
|
|
13
388
|
*
|
|
@@ -193,14 +568,22 @@ class SolanaMobileWalletProvider {
|
|
|
193
568
|
async ensureWallet() {
|
|
194
569
|
if (this.wallet)
|
|
195
570
|
return this.wallet;
|
|
196
|
-
const mod = await import('./index.browser-
|
|
571
|
+
const mod = await import('./index.browser-D8ttddP4.esm.js');
|
|
197
572
|
const chain = mapChainToWalletStandard(this.cluster);
|
|
198
573
|
this.wallet = new mod.LocalSolanaMobileWalletAdapterWallet({
|
|
199
574
|
appIdentity: this.appIdentity,
|
|
200
575
|
authorizationCache: mod.createDefaultAuthorizationCache(),
|
|
201
576
|
chains: [chain],
|
|
202
577
|
chainSelector: mod.createDefaultChainSelector(),
|
|
203
|
-
|
|
578
|
+
// Suppress the default "We can't find a wallet" modal — that
|
|
579
|
+
// modal is misleading when ERROR_WALLET_NOT_FOUND fires during
|
|
580
|
+
// a first-time-consent race on Seeker (the wallet IS installed,
|
|
581
|
+
// the protocol just gave up before the user finished consenting).
|
|
582
|
+
// login()'s withMwaAssociationRetry handles this case; on second
|
|
583
|
+
// failure it surfaces a clean error message to the host app.
|
|
584
|
+
onWalletNotFound: async () => {
|
|
585
|
+
console.warn('[MWA-DEBUG] ensureWallet onWalletNotFound (suppressed)');
|
|
586
|
+
},
|
|
204
587
|
});
|
|
205
588
|
return this.wallet;
|
|
206
589
|
}
|
|
@@ -265,8 +648,15 @@ class SolanaMobileWalletProvider {
|
|
|
265
648
|
// is where wallet-standard's checkLocalNetworkAccessPermission()
|
|
266
649
|
// fires the three-stage LNA UX (info modal → permission prompt →
|
|
267
650
|
// success modal) before opening the localhost WebSocket.
|
|
651
|
+
//
|
|
652
|
+
// Wrap with single-retry: on a Seeker origin's first MWA usage,
|
|
653
|
+
// the protocol's session-establishment timer often races Seeker's
|
|
654
|
+
// first-time consent UI and throws ERROR_WALLET_NOT_FOUND before
|
|
655
|
+
// the user finishes tapping. The retry hits Seeker's cached
|
|
656
|
+
// consent on the second pass and completes quickly. See
|
|
657
|
+
// withMwaAssociationRetry for details.
|
|
268
658
|
const connectFeat = getConnectFeature(wallet);
|
|
269
|
-
const { accounts } = await connectFeat.connect();
|
|
659
|
+
const { accounts } = await withMwaAssociationRetry('login:connect', () => connectFeat.connect());
|
|
270
660
|
if (!accounts || accounts.length === 0) {
|
|
271
661
|
throw new Error('MWA returned no accounts');
|
|
272
662
|
}
|
|
@@ -281,14 +671,29 @@ class SolanaMobileWalletProvider {
|
|
|
281
671
|
return user;
|
|
282
672
|
}
|
|
283
673
|
// Wallet popup #2: sign the Tarobase nonce message.
|
|
674
|
+
//
|
|
675
|
+
// We cannot call signMessageFeat.signMessage() directly here:
|
|
676
|
+
// it would run as a JS continuation from the connect() resolve,
|
|
677
|
+
// with no fresh Chrome transient user activation. The wallet-
|
|
678
|
+
// standard sign path internally dispatches a new solana-wallet:
|
|
679
|
+
// Android intent via window.location.assign() (see
|
|
680
|
+
// @solana-mobile/mobile-wallet-adapter-protocol launchAssociation
|
|
681
|
+
// at lib/cjs/index.browser.js:459). Chrome blocks the assign
|
|
682
|
+
// without activation, the blur event never fires, and the
|
|
683
|
+
// protocol's 3-second getDetectionPromise rejects with
|
|
684
|
+
// ERROR_WALLET_NOT_FOUND.
|
|
685
|
+
//
|
|
686
|
+
// Insert a Tarobase modal: the user's tap on "Sign in" provides a
|
|
687
|
+
// fresh activation, and signMessage is invoked synchronously
|
|
688
|
+
// inside the click handler so the activation propagates.
|
|
284
689
|
const messageText = await genSolanaMessage(base58Addr, nonce);
|
|
285
690
|
const messageBytes = getPlatform().textEncode(messageText);
|
|
286
691
|
const signMessageFeat = getSignMessageFeature(wallet);
|
|
287
|
-
const
|
|
288
|
-
if (!
|
|
692
|
+
const signResult = await awaitSignInGestureAndSign('login:signMessage', this.config.theme, () => signMessageFeat.signMessage({ account, message: messageBytes }));
|
|
693
|
+
if (!signResult) {
|
|
289
694
|
throw new Error('MWA returned no signature');
|
|
290
695
|
}
|
|
291
|
-
const { signature: sigBytes } =
|
|
696
|
+
const { signature: sigBytes } = signResult;
|
|
292
697
|
const signatureBase64 = bufferExports.Buffer.from(sigBytes).toString('base64');
|
|
293
698
|
// Create Tarobase session on the server.
|
|
294
699
|
const createSessionResult = await createSessionWithSignature(base58Addr, messageText, signatureBase64);
|
|
@@ -695,4 +1100,4 @@ class SolanaMobileWalletProvider {
|
|
|
695
1100
|
SolanaMobileWalletProvider.instance = null;
|
|
696
1101
|
|
|
697
1102
|
export { SolanaMobileWalletProvider };
|
|
698
|
-
//# sourceMappingURL=solana-mobile-wallet-provider-
|
|
1103
|
+
//# sourceMappingURL=solana-mobile-wallet-provider-B8rHfsPN.esm.js.map
|