@yeying-community/web3-bs 1.0.7 → 1.0.10
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/README.md +29 -0
- package/dist/auth/provider.d.ts +7 -1
- package/dist/auth/types.d.ts +17 -0
- package/dist/storage/webdav.d.ts +39 -0
- package/dist/web3-bs.esm.js +240 -9
- package/dist/web3-bs.esm.js.map +1 -1
- package/dist/web3-bs.umd.js +245 -8
- package/dist/web3-bs.umd.js.map +1 -1
- package/package.json +2 -2
package/dist/web3-bs.umd.js
CHANGED
|
@@ -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
|
-
|
|
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
|
|
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 =
|
|
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 =
|
|
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
|
-
|
|
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,24 @@
|
|
|
133
281
|
}
|
|
134
282
|
async function requestAccounts(options = {}) {
|
|
135
283
|
const provider = options.provider || (await requireProvider());
|
|
136
|
-
const
|
|
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
|
-
|
|
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
|
+
}
|
|
140
302
|
}
|
|
141
303
|
async function getAccounts(provider) {
|
|
142
304
|
const p = provider || (await requireProvider());
|
|
@@ -1441,6 +1603,9 @@
|
|
|
1441
1603
|
const suffix = path.startsWith('/') ? path : `/${path}`;
|
|
1442
1604
|
return `${base}${suffix}`;
|
|
1443
1605
|
}
|
|
1606
|
+
function isRecord(value) {
|
|
1607
|
+
return typeof value === 'object' && value !== null;
|
|
1608
|
+
}
|
|
1444
1609
|
function resolveAuthHeader(auth, token) {
|
|
1445
1610
|
if (auth?.type === 'bearer') {
|
|
1446
1611
|
return `Bearer ${auth.token}`;
|
|
@@ -1629,6 +1794,72 @@
|
|
|
1629
1794
|
}
|
|
1630
1795
|
return await res.json();
|
|
1631
1796
|
}
|
|
1797
|
+
async requestApiJson(method, apiPath, body, options) {
|
|
1798
|
+
const headers = this.buildHeaders({
|
|
1799
|
+
auth: options?.auth,
|
|
1800
|
+
token: options?.token,
|
|
1801
|
+
contentType: body === undefined ? undefined : 'application/json',
|
|
1802
|
+
});
|
|
1803
|
+
const response = await this.fetcher(joinUrl(this.baseUrl, apiPath), {
|
|
1804
|
+
method,
|
|
1805
|
+
headers,
|
|
1806
|
+
body: body === undefined ? undefined : JSON.stringify(body),
|
|
1807
|
+
credentials: this.credentials,
|
|
1808
|
+
signal: options?.signal,
|
|
1809
|
+
});
|
|
1810
|
+
if (!response.ok) {
|
|
1811
|
+
throw new Error(`WebDAV ${method} ${apiPath} failed: ${response.status} ${response.statusText}`);
|
|
1812
|
+
}
|
|
1813
|
+
return await response.json();
|
|
1814
|
+
}
|
|
1815
|
+
getShareAccessUrl(token, fileName) {
|
|
1816
|
+
const normalizedToken = encodeURIComponent(String(token || '').trim());
|
|
1817
|
+
if (!normalizedToken) {
|
|
1818
|
+
throw new Error('Share token is required');
|
|
1819
|
+
}
|
|
1820
|
+
const encodedFileName = String(fileName || '').trim()
|
|
1821
|
+
? `/${encodeURIComponent(String(fileName || '').trim())}`
|
|
1822
|
+
: '';
|
|
1823
|
+
return joinUrl(this.baseUrl, `/api/v1/public/share/${normalizedToken}${encodedFileName}`);
|
|
1824
|
+
}
|
|
1825
|
+
async createShareLink(options) {
|
|
1826
|
+
const normalizedPath = String(options.path || '').trim();
|
|
1827
|
+
if (!normalizedPath) {
|
|
1828
|
+
throw new Error('Share path is required');
|
|
1829
|
+
}
|
|
1830
|
+
const payload = await this.requestApiJson('POST', '/api/v1/public/share/create', {
|
|
1831
|
+
path: normalizedPath,
|
|
1832
|
+
expiresIn: options.expiresIn,
|
|
1833
|
+
expiresValue: options.expiresValue,
|
|
1834
|
+
expiresUnit: options.expiresUnit,
|
|
1835
|
+
}, options);
|
|
1836
|
+
if (!isRecord(payload)) {
|
|
1837
|
+
throw new Error('WebDAV share create response is invalid');
|
|
1838
|
+
}
|
|
1839
|
+
return payload;
|
|
1840
|
+
}
|
|
1841
|
+
async listShareLinks(options = {}) {
|
|
1842
|
+
const payload = await this.requestApiJson('GET', '/api/v1/public/share/list', undefined, options);
|
|
1843
|
+
if (!isRecord(payload)) {
|
|
1844
|
+
return [];
|
|
1845
|
+
}
|
|
1846
|
+
const items = payload.items;
|
|
1847
|
+
if (!Array.isArray(items)) {
|
|
1848
|
+
return [];
|
|
1849
|
+
}
|
|
1850
|
+
return items.filter(isRecord);
|
|
1851
|
+
}
|
|
1852
|
+
async revokeShareLink(token, options = {}) {
|
|
1853
|
+
const normalizedToken = String(token || '').trim();
|
|
1854
|
+
if (!normalizedToken) {
|
|
1855
|
+
throw new Error('Share token is required');
|
|
1856
|
+
}
|
|
1857
|
+
const payload = await this.requestApiJson('POST', '/api/v1/public/share/revoke', { token: normalizedToken }, options);
|
|
1858
|
+
if (!isRecord(payload)) {
|
|
1859
|
+
return {};
|
|
1860
|
+
}
|
|
1861
|
+
return payload;
|
|
1862
|
+
}
|
|
1632
1863
|
}
|
|
1633
1864
|
function createWebDavClient(options) {
|
|
1634
1865
|
return new WebDavClient(options);
|
|
@@ -1945,6 +2176,7 @@
|
|
|
1945
2176
|
exports.authCentralUcanFetch = authCentralUcanFetch;
|
|
1946
2177
|
exports.authFetch = authFetch;
|
|
1947
2178
|
exports.authUcanFetch = authUcanFetch;
|
|
2179
|
+
exports.classifyWalletError = classifyWalletError;
|
|
1948
2180
|
exports.clearAccessToken = clearAccessToken;
|
|
1949
2181
|
exports.clearCentralSessionToken = clearCentralSessionToken;
|
|
1950
2182
|
exports.clearUcanSession = clearUcanSession;
|
|
@@ -1970,8 +2202,12 @@
|
|
|
1970
2202
|
exports.getProvider = getProvider;
|
|
1971
2203
|
exports.getStoredUcanRoot = getStoredUcanRoot;
|
|
1972
2204
|
exports.getUcanSession = getUcanSession;
|
|
2205
|
+
exports.getWalletErrorCode = getWalletErrorCode;
|
|
2206
|
+
exports.getWalletErrorMessage = getWalletErrorMessage;
|
|
1973
2207
|
exports.initDappSession = initDappSession;
|
|
1974
2208
|
exports.initWebDavStorage = initWebDavStorage;
|
|
2209
|
+
exports.isUserRejectedWalletAction = isUserRejectedWalletAction;
|
|
2210
|
+
exports.isWalletReconnectError = isWalletReconnectError;
|
|
1975
2211
|
exports.isYeYingProvider = isYeYingProvider;
|
|
1976
2212
|
exports.issueCentralUcan = issueCentralUcan;
|
|
1977
2213
|
exports.loginWithChallenge = loginWithChallenge;
|
|
@@ -1989,6 +2225,7 @@
|
|
|
1989
2225
|
exports.signMessage = signMessage;
|
|
1990
2226
|
exports.storeUcanRoot = storeUcanRoot;
|
|
1991
2227
|
exports.watchAccounts = watchAccounts;
|
|
2228
|
+
exports.watchProvider = watchProvider;
|
|
1992
2229
|
|
|
1993
2230
|
}));
|
|
1994
2231
|
//# sourceMappingURL=web3-bs.umd.js.map
|