@polkadot/extension-dapp 0.44.8 → 0.45.1

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/bundle.js CHANGED
@@ -1,237 +1,232 @@
1
- // Copyright 2019-2023 @polkadot/extension-dapp authors & contributors
2
- // SPDX-License-Identifier: Apache-2.0
3
-
4
1
  import { isPromise, objectSpread, u8aEq } from '@polkadot/util';
5
2
  import { decodeAddress, encodeAddress } from '@polkadot/util-crypto';
6
- import { documentReadyPromise } from "./util.js";
7
-
8
- // expose utility functions
9
- export { packageInfo } from "./packageInfo.js";
10
- export { unwrapBytes, wrapBytes } from "./wrapBytes.js";
11
-
12
- // just a helper (otherwise we cast all-over, so shorter and more readable)
3
+ import { documentReadyPromise } from './util.js';
4
+ export { packageInfo } from './packageInfo.js';
5
+ export { unwrapBytes, wrapBytes } from './wrapBytes.js';
13
6
  const win = window;
14
-
15
- // don't clobber the existing object, but ensure non-undefined
16
7
  win.injectedWeb3 = win.injectedWeb3 || {};
17
-
18
- // true when anything has been injected and is available
8
+ let isWeb3Injected = web3IsInjected();
9
+ let web3EnablePromise = null;
10
+ export { isWeb3Injected, web3EnablePromise };
11
+ /** @internal true when anything has been injected and is available */
19
12
  function web3IsInjected() {
20
- return Object.values(win.injectedWeb3).filter(({
21
- connect,
22
- enable
23
- }) => !!(connect || enable)).length !== 0;
13
+ return Object
14
+ .values(win.injectedWeb3)
15
+ .filter(({ connect, enable }) => !!(connect || enable))
16
+ .length !== 0;
24
17
  }
25
-
26
- // helper to throw a consistent error when not enabled
18
+ /** @internal throw a consistent error when not extensions have not been enabled */
27
19
  function throwError(method) {
28
- throw new Error(`${method}: web3Enable(originName) needs to be called before ${method}`);
20
+ throw new Error(`${method}: web3Enable(originName) needs to be called before ${method}`);
29
21
  }
30
-
31
- // internal helper to map from Array<InjectedAccount> -> Array<InjectedAccountWithMeta>
22
+ /** @internal map from Array<InjectedAccount> to Array<InjectedAccountWithMeta> */
32
23
  function mapAccounts(source, list, ss58Format) {
33
- return list.map(({
34
- address,
35
- genesisHash,
36
- name,
37
- type
38
- }) => ({
39
- address: address.length === 42 ? address : encodeAddress(decodeAddress(address), ss58Format),
40
- meta: {
41
- genesisHash,
42
- name,
43
- source
44
- },
45
- type
46
- }));
24
+ return list.map(({ address, genesisHash, name, type }) => ({
25
+ address: address.length === 42
26
+ ? address
27
+ : encodeAddress(decodeAddress(address), ss58Format),
28
+ meta: { genesisHash, name, source },
29
+ type
30
+ }));
47
31
  }
48
-
49
- // internal helper to filter accounts
32
+ /** @internal filter accounts based on genesisHash and type of account */
50
33
  function filterAccounts(list, genesisHash, type) {
51
- return list.filter(a => (!a.type || !type || type.includes(a.type)) && (!a.genesisHash || !genesisHash || a.genesisHash === genesisHash));
34
+ return list.filter((a) => (!a.type || !type || type.includes(a.type)) &&
35
+ (!a.genesisHash || !genesisHash || a.genesisHash === genesisHash));
52
36
  }
53
-
54
- // have we found a properly constructed window.injectedWeb3
55
- let isWeb3Injected = web3IsInjected();
56
-
57
- // we keep the last promise created around (for queries)
58
- let web3EnablePromise = null;
59
- export { isWeb3Injected, web3EnablePromise };
37
+ /** @internal retrieves all the extensions available on the window */
60
38
  function getWindowExtensions(originName) {
61
- return Promise.all(Object.entries(win.injectedWeb3).map(([nameOrHash, {
62
- connect,
63
- enable,
64
- version
65
- }]) => Promise.resolve().then(() => connect
66
- // new style, returning all info
67
- ? connect(originName) : enable
68
- // previous interface, leakages on name/version
69
- ? enable(originName).then(e => objectSpread({
70
- name: nameOrHash,
71
- version: version || 'unknown'
72
- }, e)) : Promise.reject(new Error('No connect(..) or enable(...) hook found'))).catch(({
73
- message
74
- }) => {
75
- console.error(`Error initializing ${nameOrHash}: ${message}`);
76
- }))).then(exts => exts.filter(e => !!e));
39
+ return Promise
40
+ .all(Object
41
+ .entries(win.injectedWeb3)
42
+ .map(([nameOrHash, { connect, enable, version }]) => Promise
43
+ .resolve()
44
+ .then(() => connect
45
+ // new style, returning all info
46
+ ? connect(originName)
47
+ : enable
48
+ // previous interface, leakages on name/version
49
+ ? enable(originName).then((e) => objectSpread({ name: nameOrHash, version: version || 'unknown' }, e))
50
+ : Promise.reject(new Error('No connect(..) or enable(...) hook found')))
51
+ .catch(({ message }) => {
52
+ console.error(`Error initializing ${nameOrHash}: ${message}`);
53
+ })))
54
+ .then((exts) => exts.filter((e) => !!e));
77
55
  }
78
-
79
- // enables all the providers found on the injected window interface
80
- export function web3Enable(originName, compatInits = []) {
81
- if (!originName) {
82
- throw new Error('You must pass a name for your app to the web3Enable function');
83
- }
84
- const initCompat = compatInits.length ? Promise.all(compatInits.map(c => c().catch(() => false))) : Promise.resolve([true]);
85
- web3EnablePromise = documentReadyPromise(() => initCompat.then(() => getWindowExtensions(originName).then(values => values.map(e => {
86
- // if we don't have an accounts subscriber, add a single-shot version
87
- if (!e.accounts.subscribe) {
88
- e.accounts.subscribe = cb => {
89
- e.accounts.get().then(cb).catch(console.error);
90
- return () => {
91
- // no ubsubscribe needed, this is a single-shot
92
- };
93
- };
56
+ /** @internal Ensure the enable promise is resolved and filter by extensions */
57
+ async function filterEnable(caller, extensions) {
58
+ if (!web3EnablePromise) {
59
+ return throwError(caller);
94
60
  }
95
- return e;
96
- })).catch(() => []).then(values => {
97
- const names = values.map(({
98
- name,
99
- version
100
- }) => `${name}/${version}`);
101
- isWeb3Injected = web3IsInjected();
102
- console.info(`web3Enable: Enabled ${values.length} extension${values.length !== 1 ? 's' : ''}: ${names.join(', ')}`);
103
- return values;
104
- })));
105
- return web3EnablePromise;
61
+ const sources = await web3EnablePromise;
62
+ return sources.filter(({ name }) => !extensions ||
63
+ extensions.includes(name));
106
64
  }
107
-
108
- // retrieve all the accounts across all providers
109
- export async function web3Accounts({
110
- accountType,
111
- extensions,
112
- genesisHash,
113
- ss58Format
114
- } = {}) {
115
- if (!web3EnablePromise) {
116
- return throwError('web3Accounts');
117
- }
118
- const accounts = [];
119
- const sources = await web3EnablePromise;
120
- const retrieved = await Promise.all(sources.filter(({
121
- name: source
122
- }) => !extensions || extensions.includes(source)).map(async ({
123
- accounts,
124
- name: source
125
- }) => {
126
- try {
127
- const list = await accounts.get();
128
- return mapAccounts(source, filterAccounts(list, genesisHash, accountType), ss58Format);
129
- } catch (error) {
130
- // cannot handle this one
131
- return [];
65
+ /**
66
+ * @summary Enables all the providers found on the injected window interface
67
+ * @description
68
+ * Enables all injected extensions that has been found on the page. This
69
+ * should be called before making use of any other web3* functions.
70
+ */
71
+ export function web3Enable(originName, compatInits = []) {
72
+ if (!originName) {
73
+ throw new Error('You must pass a name for your app to the web3Enable function');
132
74
  }
133
- }));
134
- retrieved.forEach(result => {
135
- accounts.push(...result);
136
- });
137
- console.info(`web3Accounts: Found ${accounts.length} address${accounts.length !== 1 ? 'es' : ''}`);
138
- return accounts;
75
+ const initCompat = compatInits.length
76
+ ? Promise.all(compatInits.map((c) => c().catch(() => false)))
77
+ : Promise.resolve([true]);
78
+ web3EnablePromise = documentReadyPromise(() => initCompat.then(() => getWindowExtensions(originName)
79
+ .then((values) => values.map((e) => {
80
+ // if we don't have an accounts subscriber, add a single-shot version
81
+ if (!e.accounts.subscribe) {
82
+ e.accounts.subscribe = (cb) => {
83
+ e.accounts
84
+ .get()
85
+ .then(cb)
86
+ .catch(console.error);
87
+ return () => {
88
+ // no ubsubscribe needed, this is a single-shot
89
+ };
90
+ };
91
+ }
92
+ return e;
93
+ }))
94
+ .catch(() => [])
95
+ .then((values) => {
96
+ const names = values.map(({ name, version }) => `${name}/${version}`);
97
+ isWeb3Injected = web3IsInjected();
98
+ console.info(`web3Enable: Enabled ${values.length} extension${values.length !== 1 ? 's' : ''}: ${names.join(', ')}`);
99
+ return values;
100
+ })));
101
+ return web3EnablePromise;
139
102
  }
140
- export async function web3AccountsSubscribe(cb, {
141
- accountType,
142
- extensions,
143
- genesisHash,
144
- ss58Format
145
- } = {}) {
146
- if (!web3EnablePromise) {
147
- return throwError('web3AccountsSubscribe');
148
- }
149
- const accounts = {};
150
- const triggerUpdate = () => cb(Object.entries(accounts).reduce((result, [source, list]) => {
151
- result.push(...mapAccounts(source, filterAccounts(list, genesisHash, accountType), ss58Format));
152
- return result;
153
- }, []));
154
- const sources = await web3EnablePromise;
155
- const unsubs = sources.filter(({
156
- name: source
157
- }) => !extensions || extensions.includes(source)).map(({
158
- accounts: {
159
- subscribe
160
- },
161
- name: source
162
- }) => subscribe(result => {
163
- accounts[source] = result;
164
- try {
165
- const result = triggerUpdate();
166
- if (result && isPromise(result)) {
167
- result.catch(console.error);
168
- }
169
- } catch (error) {
170
- console.error(error);
171
- }
172
- }));
173
- return () => {
174
- unsubs.forEach(unsub => {
175
- unsub();
103
+ /**
104
+ * @summary Retrieves all the accounts across all providers
105
+ * @description
106
+ * This returns the full list of account available (accross all extensions) to
107
+ * the page. Filtereing options are available of a per-extension, per type and
108
+ * per-genesisHash basis. Optionally the accounts can be encoded with the provided
109
+ * ss58Format
110
+ */
111
+ export async function web3Accounts({ accountType, extensions, genesisHash, ss58Format } = {}) {
112
+ const accounts = [];
113
+ const sources = await filterEnable('web3Accounts', extensions);
114
+ const retrieved = await Promise.all(sources.map(async ({ accounts, name: source }) => {
115
+ try {
116
+ const list = await accounts.get();
117
+ return mapAccounts(source, filterAccounts(list, genesisHash, accountType), ss58Format);
118
+ }
119
+ catch (error) {
120
+ // cannot handle this one
121
+ return [];
122
+ }
123
+ }));
124
+ retrieved.forEach((result) => {
125
+ accounts.push(...result);
176
126
  });
177
- };
127
+ console.info(`web3Accounts: Found ${accounts.length} address${accounts.length !== 1 ? 'es' : ''}`);
128
+ return accounts;
178
129
  }
179
-
180
- // find a specific provider based on the name
130
+ /**
131
+ * @summary Subscribes to all the accounts across all providers
132
+ * @description
133
+ * This is the subscription version of the web3Accounts interface with
134
+ * updates as to when new accounts do become available. The list of filtering
135
+ * options are the same as for the web3Accounts interface.
136
+ */
137
+ export async function web3AccountsSubscribe(cb, { accountType, extensions, genesisHash, ss58Format } = {}) {
138
+ const sources = await filterEnable('web3AccountsSubscribe', extensions);
139
+ const accounts = {};
140
+ const triggerUpdate = () => cb(Object
141
+ .entries(accounts)
142
+ .reduce((result, [source, list]) => {
143
+ result.push(...mapAccounts(source, filterAccounts(list, genesisHash, accountType), ss58Format));
144
+ return result;
145
+ }, []));
146
+ const unsubs = sources.map(({ accounts: { subscribe }, name: source }) => subscribe((result) => {
147
+ accounts[source] = result;
148
+ try {
149
+ const result = triggerUpdate();
150
+ if (result && isPromise(result)) {
151
+ result.catch(console.error);
152
+ }
153
+ }
154
+ catch (error) {
155
+ console.error(error);
156
+ }
157
+ }));
158
+ return () => {
159
+ unsubs.forEach((unsub) => {
160
+ unsub();
161
+ });
162
+ };
163
+ }
164
+ /**
165
+ * @summary Finds a specific provider based on the name
166
+ * @description
167
+ * This retrieves a specific source (extension) based on the name. In most
168
+ * cases it should not be needed to call it directly (e.g. it is used internally
169
+ * by calls such as web3FromAddress) but would allow operation on a specific
170
+ * known extension.
171
+ */
181
172
  export async function web3FromSource(source) {
182
- if (!web3EnablePromise) {
183
- return throwError('web3FromSource');
184
- }
185
- const sources = await web3EnablePromise;
186
- const found = source && sources.find(({
187
- name
188
- }) => name === source);
189
- if (!found) {
190
- throw new Error(`web3FromSource: Unable to find an injected ${source}`);
191
- }
192
- return found;
173
+ if (!web3EnablePromise) {
174
+ return throwError('web3FromSource');
175
+ }
176
+ const sources = await web3EnablePromise;
177
+ const found = source && sources.find(({ name }) => name === source);
178
+ if (!found) {
179
+ throw new Error(`web3FromSource: Unable to find an injected ${source}`);
180
+ }
181
+ return found;
193
182
  }
194
-
195
- // find a specific provider based on an address
183
+ /**
184
+ * @summary Find a specific provider that provides a specific address
185
+ * @description
186
+ * Based on an address, return the provider that has makes this address
187
+ * available to the page.
188
+ */
196
189
  export async function web3FromAddress(address) {
197
- if (!web3EnablePromise) {
198
- return throwError('web3FromAddress');
199
- }
200
- const accounts = await web3Accounts();
201
- let found;
202
- if (address) {
203
- const accountU8a = decodeAddress(address);
204
- found = accounts.find(account => u8aEq(decodeAddress(account.address), accountU8a));
205
- }
206
- if (!found) {
207
- throw new Error(`web3FromAddress: Unable to find injected ${address}`);
208
- }
209
- return web3FromSource(found.meta.source);
190
+ if (!web3EnablePromise) {
191
+ return throwError('web3FromAddress');
192
+ }
193
+ const accounts = await web3Accounts();
194
+ let found;
195
+ if (address) {
196
+ const accountU8a = decodeAddress(address);
197
+ found = accounts.find((account) => u8aEq(decodeAddress(account.address), accountU8a));
198
+ }
199
+ if (!found) {
200
+ throw new Error(`web3FromAddress: Unable to find injected ${address}`);
201
+ }
202
+ return web3FromSource(found.meta.source);
210
203
  }
211
-
212
- // retrieve all providers exposed by one source
204
+ /**
205
+ * @summary List all providers exposed by one source
206
+ * @description
207
+ * For extensions that supply RPC providers, this call would return the list
208
+ * of RPC providers that any extension may supply.
209
+ */
213
210
  export async function web3ListRpcProviders(source) {
214
- const {
215
- provider
216
- } = await web3FromSource(source);
217
- if (!provider) {
218
- console.warn(`Extension ${source} does not expose any provider`);
219
- return null;
220
- }
221
- return provider.listProviders();
211
+ const { provider } = await web3FromSource(source);
212
+ if (!provider) {
213
+ console.warn(`Extension ${source} does not expose any provider`);
214
+ return null;
215
+ }
216
+ return provider.listProviders();
222
217
  }
223
-
224
- // retrieve all providers exposed by one source
218
+ /**
219
+ * @summary Start an RPC provider provider by a specific source
220
+ * @description
221
+ * For extensions that supply RPC providers, this call would return an
222
+ * enabled provider (initialized with the specific key) from the
223
+ * specified extension source.
224
+ */
225
225
  export async function web3UseRpcProvider(source, key) {
226
- const {
227
- provider
228
- } = await web3FromSource(source);
229
- if (!provider) {
230
- throw new Error(`Extension ${source} does not expose any provider`);
231
- }
232
- const meta = await provider.startProvider(key);
233
- return {
234
- meta,
235
- provider
236
- };
226
+ const { provider } = await web3FromSource(source);
227
+ if (!provider) {
228
+ throw new Error(`Extension ${source} does not expose any provider`);
229
+ }
230
+ const meta = await provider.startProvider(key);
231
+ return { meta, provider };
237
232
  }