@yeying-community/web3-bs 1.0.8 → 1.0.11

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.
@@ -7,10 +7,46 @@
7
7
  const YEYING_RDNS = 'io.github.yeying';
8
8
  const DEFAULT_TIMEOUT = 1000;
9
9
  const DEFAULT_ACCOUNT_STORAGE_KEY = 'yeying:last_account';
10
+ const DEFAULT_PROVIDER_POLL_INTERVAL = 100;
11
+ const DEFAULT_PROVIDER_MAX_POLLS = 20;
12
+ const requestAccountsInFlight = new WeakMap();
13
+ function isProvider(value) {
14
+ return !!value && typeof value.request === 'function';
15
+ }
10
16
  function getWindowEthereum() {
11
17
  if (typeof window === 'undefined')
12
18
  return null;
13
- return window.ethereum || null;
19
+ const ethereum = window.ethereum;
20
+ return isProvider(ethereum) ? ethereum : null;
21
+ }
22
+ function getWindowProviderCandidates() {
23
+ if (typeof window === 'undefined')
24
+ return [];
25
+ const source = window;
26
+ const candidates = [];
27
+ const addProvider = (provider) => {
28
+ if (isProvider(provider) && !candidates.includes(provider)) {
29
+ candidates.push(provider);
30
+ }
31
+ };
32
+ for (const name of [
33
+ 'ethereum',
34
+ 'yeeying',
35
+ 'yeying',
36
+ 'coinbaseWallet',
37
+ 'bitkeep',
38
+ 'tokenpocket',
39
+ '__YEYING_PROVIDER__',
40
+ ]) {
41
+ addProvider(source[name]);
42
+ }
43
+ const ethereum = getWindowEthereum();
44
+ if (Array.isArray(ethereum?.providers)) {
45
+ for (const provider of ethereum.providers) {
46
+ addProvider(provider);
47
+ }
48
+ }
49
+ return candidates;
14
50
  }
15
51
  function readStoredAccount(storageKey) {
16
52
  if (typeof localStorage === 'undefined')
@@ -54,7 +90,7 @@
54
90
  }
55
91
  function selectBestProvider(candidates, preferYeYing) {
56
92
  if (candidates.length === 0)
57
- return null;
93
+ return selectBestWindowProvider(preferYeYing);
58
94
  if (preferYeYing) {
59
95
  const yeying = candidates.find(c => isYeYingProvider(c.provider, c.info));
60
96
  if (yeying)
@@ -62,10 +98,21 @@
62
98
  }
63
99
  return candidates[0].provider;
64
100
  }
101
+ function selectBestWindowProvider(preferYeYing) {
102
+ const candidates = getWindowProviderCandidates();
103
+ if (candidates.length === 0)
104
+ return null;
105
+ if (preferYeYing) {
106
+ const yeying = candidates.find(provider => isYeYingProvider(provider));
107
+ if (yeying)
108
+ return yeying;
109
+ }
110
+ return candidates[0];
111
+ }
65
112
  async function getProvider(options = {}) {
66
113
  const preferYeYing = options.preferYeYing !== false;
67
114
  const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT;
68
- const windowProvider = getWindowEthereum();
115
+ const windowProvider = selectBestWindowProvider(preferYeYing);
69
116
  if (preferYeYing && isYeYingProvider(windowProvider)) {
70
117
  return windowProvider;
71
118
  }
@@ -98,7 +145,7 @@
98
145
  }
99
146
  };
100
147
  const onEthereumInitialized = () => {
101
- const injected = getWindowEthereum();
148
+ const injected = selectBestWindowProvider(preferYeYing);
102
149
  if (preferYeYing && isYeYingProvider(injected)) {
103
150
  safeResolve(injected);
104
151
  }
@@ -110,7 +157,7 @@
110
157
  return;
111
158
  const best = selectBestProvider(discovered, preferYeYing) ||
112
159
  windowProvider ||
113
- getWindowEthereum();
160
+ selectBestWindowProvider(preferYeYing);
114
161
  safeResolve(best || null);
115
162
  }, timeoutMs);
116
163
  try {
@@ -124,6 +171,107 @@
124
171
  }
125
172
  });
126
173
  }
174
+ function watchProvider(handler, options = {}) {
175
+ if (typeof window === 'undefined') {
176
+ handler({ provider: null, present: false });
177
+ return () => { };
178
+ }
179
+ const preferYeYing = options.preferYeYing !== false;
180
+ const pollIntervalMs = options.pollIntervalMs ?? DEFAULT_PROVIDER_POLL_INTERVAL;
181
+ const maxPolls = options.maxPolls ?? DEFAULT_PROVIDER_MAX_POLLS;
182
+ let stopped = false;
183
+ let lastProvider;
184
+ let pollCount = 0;
185
+ let pollTimer = null;
186
+ const emit = () => {
187
+ if (stopped)
188
+ return;
189
+ const provider = selectBestWindowProvider(preferYeYing);
190
+ if (provider === lastProvider)
191
+ return;
192
+ lastProvider = provider;
193
+ handler({ provider, present: !!provider });
194
+ };
195
+ const poll = () => {
196
+ if (stopped)
197
+ return;
198
+ emit();
199
+ pollCount += 1;
200
+ if (lastProvider || pollCount >= maxPolls)
201
+ return;
202
+ pollTimer = setTimeout(poll, pollIntervalMs);
203
+ };
204
+ const handleProviderReady = () => {
205
+ emit();
206
+ };
207
+ window.addEventListener('ethereum#initialized', handleProviderReady);
208
+ window.addEventListener('eip6963:announceProvider', handleProviderReady);
209
+ try {
210
+ window.dispatchEvent(new Event('eip6963:requestProvider'));
211
+ }
212
+ catch {
213
+ // Ignore unsupported event dispatch environments.
214
+ }
215
+ poll();
216
+ return () => {
217
+ stopped = true;
218
+ if (pollTimer) {
219
+ clearTimeout(pollTimer);
220
+ }
221
+ window.removeEventListener('ethereum#initialized', handleProviderReady);
222
+ window.removeEventListener('eip6963:announceProvider', handleProviderReady);
223
+ };
224
+ }
225
+ function getWalletErrorMessage(error) {
226
+ if (!error)
227
+ return '';
228
+ if (typeof error === 'string')
229
+ return error;
230
+ if (error instanceof Error)
231
+ return error.message || String(error);
232
+ const message = error.message;
233
+ if (typeof message === 'string')
234
+ return message;
235
+ return String(error);
236
+ }
237
+ function getWalletErrorCode(error) {
238
+ const code = Number(error?.code);
239
+ if (!Number.isNaN(code))
240
+ return code;
241
+ const causeCode = Number(error?.cause?.code);
242
+ if (!Number.isNaN(causeCode))
243
+ return causeCode;
244
+ return null;
245
+ }
246
+ function classifyWalletError(error) {
247
+ const code = getWalletErrorCode(error);
248
+ const message = getWalletErrorMessage(error);
249
+ const lowerMessage = message.toLowerCase();
250
+ if (code === 4001 || lowerMessage.includes('user rejected')) {
251
+ return { type: 'userRejected', code, message };
252
+ }
253
+ if (code === 4900 ||
254
+ lowerMessage.includes('disconnected') ||
255
+ lowerMessage.includes('reconnect') ||
256
+ lowerMessage.includes('not connected')) {
257
+ return { type: 'disconnected', code, message };
258
+ }
259
+ if (lowerMessage.includes('timeout')) {
260
+ return { type: 'timeout', code, message };
261
+ }
262
+ if (lowerMessage.includes('no injected wallet provider') ||
263
+ lowerMessage.includes('未检测到钱包')) {
264
+ return { type: 'notFound', code, message };
265
+ }
266
+ return { type: 'unknown', code, message };
267
+ }
268
+ function isUserRejectedWalletAction(error) {
269
+ return classifyWalletError(error).type === 'userRejected';
270
+ }
271
+ function isWalletReconnectError(error) {
272
+ const type = classifyWalletError(error).type;
273
+ return type === 'disconnected' || type === 'timeout';
274
+ }
127
275
  async function requireProvider(options = {}) {
128
276
  const provider = await getProvider(options);
129
277
  if (!provider) {
@@ -133,10 +281,43 @@
133
281
  }
134
282
  async function requestAccounts(options = {}) {
135
283
  const provider = options.provider || (await requireProvider());
136
- const accounts = (await provider.request({
284
+ const dedupe = options.dedupe !== false;
285
+ if (dedupe) {
286
+ const pending = requestAccountsInFlight.get(provider);
287
+ if (pending)
288
+ return pending;
289
+ }
290
+ const request = provider.request({
137
291
  method: 'eth_requestAccounts',
138
- }));
139
- return Array.isArray(accounts) ? accounts : [];
292
+ }).then(accounts => (Array.isArray(accounts) ? accounts : []));
293
+ if (!dedupe)
294
+ return request;
295
+ requestAccountsInFlight.set(provider, request);
296
+ try {
297
+ return await request;
298
+ }
299
+ finally {
300
+ requestAccountsInFlight.delete(provider);
301
+ }
302
+ }
303
+ async function focusPendingApproval(provider) {
304
+ const p = provider || (await requireProvider());
305
+ const result = await p.request({
306
+ method: 'wallet_focusPendingApproval',
307
+ });
308
+ if (!result || typeof result !== 'object') {
309
+ return { focused: false, type: null };
310
+ }
311
+ const payload = result;
312
+ return {
313
+ focused: Boolean(payload.focused),
314
+ type: typeof payload.type === 'string' ? payload.type : null,
315
+ requestId: typeof payload.requestId === 'string' ? payload.requestId : null,
316
+ origin: typeof payload.origin === 'string' ? payload.origin : '',
317
+ tabId: typeof payload.tabId === 'number' && Number.isFinite(payload.tabId)
318
+ ? payload.tabId
319
+ : null,
320
+ };
140
321
  }
141
322
  async function getAccounts(provider) {
142
323
  const p = provider || (await requireProvider());
@@ -2014,6 +2195,7 @@
2014
2195
  exports.authCentralUcanFetch = authCentralUcanFetch;
2015
2196
  exports.authFetch = authFetch;
2016
2197
  exports.authUcanFetch = authUcanFetch;
2198
+ exports.classifyWalletError = classifyWalletError;
2017
2199
  exports.clearAccessToken = clearAccessToken;
2018
2200
  exports.clearCentralSessionToken = clearCentralSessionToken;
2019
2201
  exports.clearUcanSession = clearUcanSession;
@@ -2026,6 +2208,7 @@
2026
2208
  exports.createWebDavClient = createWebDavClient;
2027
2209
  exports.deriveAppIdFromHost = deriveAppIdFromHost;
2028
2210
  exports.deriveAppIdFromLocation = deriveAppIdFromLocation;
2211
+ exports.focusPendingApproval = focusPendingApproval;
2029
2212
  exports.getAccessToken = getAccessToken;
2030
2213
  exports.getAccounts = getAccounts;
2031
2214
  exports.getBalance = getBalance;
@@ -2039,8 +2222,12 @@
2039
2222
  exports.getProvider = getProvider;
2040
2223
  exports.getStoredUcanRoot = getStoredUcanRoot;
2041
2224
  exports.getUcanSession = getUcanSession;
2225
+ exports.getWalletErrorCode = getWalletErrorCode;
2226
+ exports.getWalletErrorMessage = getWalletErrorMessage;
2042
2227
  exports.initDappSession = initDappSession;
2043
2228
  exports.initWebDavStorage = initWebDavStorage;
2229
+ exports.isUserRejectedWalletAction = isUserRejectedWalletAction;
2230
+ exports.isWalletReconnectError = isWalletReconnectError;
2044
2231
  exports.isYeYingProvider = isYeYingProvider;
2045
2232
  exports.issueCentralUcan = issueCentralUcan;
2046
2233
  exports.loginWithChallenge = loginWithChallenge;
@@ -2058,6 +2245,7 @@
2058
2245
  exports.signMessage = signMessage;
2059
2246
  exports.storeUcanRoot = storeUcanRoot;
2060
2247
  exports.watchAccounts = watchAccounts;
2248
+ exports.watchProvider = watchProvider;
2061
2249
 
2062
2250
  }));
2063
2251
  //# sourceMappingURL=web3-bs.umd.js.map