1
- import { assertArgument } from "../utils/index.js" ;
1
+
2
+ import { assertArgument , makeError } from "../utils/index.js" ;
2
3
3
4
import { JsonRpcApiPollingProvider } from "./provider-jsonrpc.js" ;
4
5
@@ -93,10 +94,13 @@ export interface BrowserDiscoverOptions {
93
94
* environments or to hijack where a provider comes from.
94
95
*/
95
96
window ?: any ;
96
- }
97
97
98
- // @TODO : Future, provide some sort of filter mechansm callback along
99
- // with exposing the following types
98
+ /**
99
+ * Explicitly choose which provider to used once scanning is complete.
100
+ */
101
+ filter ?: ( found : Array < Eip6963ProviderInfo > ) => null | BrowserProvider |
102
+ Eip6963ProviderInfo ;
103
+ }
100
104
101
105
102
106
/**
@@ -242,11 +246,16 @@ export class BrowserProvider extends JsonRpcApiPollingProvider {
242
246
return new BrowserProvider ( context . ethereum ) ;
243
247
}
244
248
249
+ if ( ! ( "addEventListener" in context && "dispatchEvent" in context
250
+ && "removeEventListener" in context ) ) {
251
+ return null ;
252
+ }
253
+
245
254
const timeout = options . timeout ? options . timeout : 300 ;
246
255
if ( timeout === 0 ) { return null ; }
247
256
248
- return await ( new Promise ( ( resolve ) => {
249
- let found : Array < any > = [ ] ;
257
+ return await ( new Promise ( ( resolve , reject ) => {
258
+ let found : Array < Eip6963ProviderDetail > = [ ] ;
250
259
251
260
const addProvider = ( event : Eip6963Announcement ) => {
252
261
found . push ( event . detail ) ;
@@ -255,14 +264,61 @@ export class BrowserProvider extends JsonRpcApiPollingProvider {
255
264
256
265
const finalize = ( ) => {
257
266
clearTimeout ( timer ) ;
267
+
258
268
if ( found . length ) {
259
- const { provider, info } = found [ 0 ] ;
260
- resolve ( new BrowserProvider ( provider , undefined , {
261
- providerInfo : info
262
- } ) ) ;
269
+
270
+ // If filtering is provided:
271
+ if ( options && options . filter ) {
272
+
273
+ // Call filter, with a copies of found provider infos
274
+ const filtered = options . filter ( found . map ( i =>
275
+ Object . assign ( { } , ( i . info ) ) ) ) ;
276
+
277
+ if ( filtered == null ) {
278
+ // No provider selected
279
+ resolve ( null ) ;
280
+
281
+ } else if ( filtered instanceof BrowserProvider ) {
282
+ // Custom provider created
283
+ resolve ( filtered ) ;
284
+
285
+ } else {
286
+ // Find the matching provider
287
+ let match : null | Eip6963ProviderDetail = null ;
288
+ if ( filtered . uuid ) {
289
+ const matches = found . filter ( f =>
290
+ ( filtered . uuid === f . info . uuid ) ) ;
291
+ // @TODO : What should happen if multiple values
292
+ // for the same UUID?
293
+ match = matches [ 0 ] ;
294
+ }
295
+
296
+ if ( match ) {
297
+ const { provider, info } = match ;
298
+ resolve ( new BrowserProvider ( provider , undefined , {
299
+ providerInfo : info
300
+ } ) ) ;
301
+ } else {
302
+ reject ( makeError ( "filter returned unknown info" , "UNSUPPORTED_OPERATION" , {
303
+ value : filtered
304
+ } ) ) ;
305
+ }
306
+ }
307
+
308
+ } else {
309
+
310
+ // Pick the first found provider
311
+ const { provider, info } = found [ 0 ] ;
312
+ resolve ( new BrowserProvider ( provider , undefined , {
313
+ providerInfo : info
314
+ } ) ) ;
315
+ }
316
+
263
317
} else {
318
+ // Nothing found
264
319
resolve ( null ) ;
265
320
}
321
+
266
322
context . removeEventListener ( < any > "eip6963:announceProvider" ,
267
323
addProvider ) ;
268
324
} ;
0 commit comments