Skip to content

Commit 1cf5be2

Browse files
authored
Merge pull request #18 from Odrin/feat/provider-refactor
feat: provider refactor
2 parents d6a2210 + 1fd7671 commit 1cf5be2

File tree

3 files changed

+222
-144
lines changed

3 files changed

+222
-144
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "everscale-inpage-provider",
3-
"version": "0.3.66",
3+
"version": "0.4.0",
44
"description": "Web3-like interface to the Everscale blockchain",
55
"repository": "https://github.com/broxus/everscale-inpage-provider",
66
"main": "dist/index.js",

src/adapters.ts

Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
import type { Provider } from './index';
2+
3+
declare global {
4+
interface Window {
5+
__ever: Provider | undefined;
6+
__sparx: Provider | undefined;
7+
__hasEverscaleProvider: boolean | undefined;
8+
}
9+
}
10+
11+
const isBrowser = typeof window !== 'undefined' && typeof window.document !== 'undefined';
12+
const ensurePageLoaded = !isBrowser || document.readyState === 'complete'
13+
? Promise.resolve()
14+
: new Promise<void>(resolve => window.addEventListener('load', () => resolve()));
15+
16+
/**
17+
* Interface representing a provider adapter.
18+
* This interface defines the methods required to interact with a provider.
19+
* @category Provider
20+
*/
21+
export interface ProviderAdapter {
22+
/**
23+
* Retrieves the provider instance.
24+
*/
25+
getProvider(): Promise<Provider | undefined> | Provider | undefined;
26+
27+
/**
28+
* Checks if a provider is available.
29+
*/
30+
hasProvider(): Promise<boolean> | boolean;
31+
}
32+
33+
/**
34+
* @category Provider
35+
*/
36+
export function hasEverscaleProvider(): Promise<boolean> {
37+
if (!isBrowser) return Promise.resolve(false);
38+
return ensurePageLoaded.then(() => window.__hasEverscaleProvider === true);
39+
}
40+
41+
/**
42+
* A static implementation of the `ProviderAdapter` interface that wraps a given provider instance or a promise that resolves to a provider.
43+
* This adapter always indicates the presence of a provider.
44+
* @category Provider
45+
* @implements {ProviderAdapter}
46+
*/
47+
export class StaticProviderAdapter implements ProviderAdapter {
48+
private readonly _provider: Promise<Provider> | Provider;
49+
50+
constructor(provider: Promise<Provider> | Provider) {
51+
this._provider = provider;
52+
}
53+
54+
public getProvider(): Promise<Provider> | Provider {
55+
return this._provider;
56+
}
57+
58+
public hasProvider(): boolean {
59+
return true;
60+
}
61+
}
62+
63+
/**
64+
* An implementation of the `ProviderAdapter` interface that wraps Ever Wallet provider.
65+
* @category Provider
66+
* @implements {ProviderAdapter}
67+
*/
68+
export class EverscaleProviderAdapter implements ProviderAdapter {
69+
public async getProvider(): Promise<Provider | undefined> {
70+
if (!(await this.hasProvider())) return;
71+
72+
return new Promise<Provider | undefined>((resolve) => {
73+
if (window.__ever) {
74+
resolve(window.__ever);
75+
} else {
76+
window.addEventListener(
77+
'ever#initialized',
78+
_ => resolve(window.__ever),
79+
{ once: true },
80+
);
81+
}
82+
});
83+
}
84+
85+
public hasProvider(): Promise<boolean> {
86+
return hasEverscaleProvider();
87+
}
88+
}
89+
90+
/**
91+
* An implementation of the `ProviderAdapter` interface that wraps Sparx provider.
92+
* @category Provider
93+
* @implements {ProviderAdapter}
94+
*/
95+
export class SparxProviderAdapter implements ProviderAdapter {
96+
public async getProvider(): Promise<Provider | undefined> {
97+
if (!(await this.hasProvider())) return;
98+
99+
return new Promise<Provider | undefined>((resolve) => {
100+
if (window.__sparx) {
101+
resolve(window.__sparx);
102+
} else {
103+
window.addEventListener(
104+
'sparx#initialized',
105+
_ => resolve(window.__sparx),
106+
{ once: true },
107+
);
108+
}
109+
});
110+
}
111+
112+
public hasProvider(): Promise<boolean> {
113+
return hasEverscaleProvider();
114+
}
115+
}
116+
117+
118+
/**
119+
* The `FallbackProviderAdapter` class implements the `ProviderAdapter` interface
120+
* and provides a mechanism to use multiple provider adapters in a fallback manner.
121+
* It attempts to use the primary adapter first, and if it fails, it falls back to
122+
* the subsequent adapters in the order they were provided.
123+
*
124+
* @category Provider
125+
* @implements {ProviderAdapter}
126+
*/
127+
export class FallbackProviderAdapter implements ProviderAdapter {
128+
private readonly _adapters: [ProviderAdapter, ...ProviderAdapter[]];
129+
130+
constructor(adapter: ProviderAdapter, ...fallbacks: ProviderAdapter[]) {
131+
this._adapters = [adapter, ...fallbacks];
132+
}
133+
134+
public async getProvider(): Promise<Provider | undefined> {
135+
for (const adapter of this._adapters) {
136+
const provider = await adapter.getProvider();
137+
if (provider) return provider;
138+
}
139+
140+
return undefined;
141+
}
142+
143+
public async hasProvider(): Promise<boolean> {
144+
for (const adapter of this._adapters) {
145+
if (await adapter.hasProvider()) return true;
146+
}
147+
return false;
148+
}
149+
}
150+
151+
export function isProviderAdapter(value: any): value is ProviderAdapter {
152+
return !!value && 'getProvider' in value && 'hasProvider' in value;
153+
}

0 commit comments

Comments
 (0)