UNPKG

6.52 kBJavaScriptView Raw
1import { noop, objectSpread } from '@polkadot/util';
2import { ApiBase } from '../base/index.js';
3import { Combinator } from './Combinator.js';
4import { promiseTracker, toPromiseMethod } from './decorateMethod.js';
5/**
6 * # @polkadot/api/promise
7 *
8 * ## Overview
9 *
10 * @name ApiPromise
11 * @description
12 * ApiPromise is a standard JavaScript wrapper around the RPC and interfaces on the Polkadot network. As a full Promise-based, all interface calls return Promises, including the static `.create(...)`. Subscription calls utilise `(value) => {}` callbacks to pass through the latest values.
13 *
14 * The API is well suited to real-time applications where either the single-shot state is needed or use is to be made of the subscription-based features of Polkadot (and Substrate) clients.
15 *
16 * @see [[ApiRx]]
17 *
18 * ## Usage
19 *
20 * Making rpc calls -
21 * <BR>
22 *
23 * ```javascript
24 * import ApiPromise from '@polkadot/api/promise';
25 *
26 * // initialise via static create
27 * const api = await ApiPromise.create();
28 *
29 * // make a subscription to the network head
30 * api.rpc.chain.subscribeNewHeads((header) => {
31 * console.log(`Chain is at #${header.number}`);
32 * });
33 * ```
34 * <BR>
35 *
36 * Subscribing to chain state -
37 * <BR>
38 *
39 * ```javascript
40 * import { ApiPromise, WsProvider } from '@polkadot/api';
41 *
42 * // initialise a provider with a specific endpoint
43 * const provider = new WsProvider('wss://example.com:9944')
44 *
45 * // initialise via isReady & new with specific provider
46 * const api = await new ApiPromise({ provider }).isReady;
47 *
48 * // retrieve the block target time
49 * const blockPeriod = await api.query.timestamp.blockPeriod().toNumber();
50 * let last = 0;
51 *
52 * // subscribe to the current block timestamp, updates automatically (callback provided)
53 * api.query.timestamp.now((timestamp) => {
54 * const elapsed = last
55 * ? `, ${timestamp.toNumber() - last}s since last`
56 * : '';
57 *
58 * last = timestamp.toNumber();
59 * console.log(`timestamp ${timestamp}${elapsed} (${blockPeriod}s target)`);
60 * });
61 * ```
62 * <BR>
63 *
64 * Submitting a transaction -
65 * <BR>
66 *
67 * ```javascript
68 * import ApiPromise from '@polkadot/api/promise';
69 *
70 * ApiPromise.create().then((api) => {
71 * const [nonce] = await api.query.system.account(keyring.alice.address);
72 *
73 * api.tx.balances
74 * // create transfer
75 * transfer(keyring.bob.address, 12345)
76 * // sign the transcation
77 * .sign(keyring.alice, { nonce })
78 * // send the transaction (optional status callback)
79 * .send((status) => {
80 * console.log(`current status ${status.type}`);
81 * })
82 * // retrieve the submitted extrinsic hash
83 * .then((hash) => {
84 * console.log(`submitted with hash ${hash}`);
85 * });
86 * });
87 * ```
88 */
89export class ApiPromise extends ApiBase {
90 __internal__isReadyPromise;
91 __internal__isReadyOrErrorPromise;
92 /**
93 * @description Creates an instance of the ApiPromise class
94 * @param options Options to create an instance. This can be either [[ApiOptions]] or
95 * an [[WsProvider]].
96 * @example
97 * <BR>
98 *
99 * ```javascript
100 * import Api from '@polkadot/api/promise';
101 *
102 * new Api().isReady.then((api) => {
103 * api.rpc.subscribeNewHeads((header) => {
104 * console.log(`new block #${header.number.toNumber()}`);
105 * });
106 * });
107 * ```
108 */
109 constructor(options) {
110 super(options, 'promise', toPromiseMethod);
111 this.__internal__isReadyPromise = new Promise((resolve) => {
112 super.once('ready', () => resolve(this));
113 });
114 this.__internal__isReadyOrErrorPromise = new Promise((resolve, reject) => {
115 const tracker = promiseTracker(resolve, reject);
116 super.once('ready', () => tracker.resolve(this));
117 super.once('error', (error) => tracker.reject(error));
118 });
119 }
120 /**
121 * @description Creates an ApiPromise instance using the supplied provider. Returns an Promise containing the actual Api instance.
122 * @param options options that is passed to the class contructor. Can be either [[ApiOptions]] or a
123 * provider (see the constructor arguments)
124 * @example
125 * <BR>
126 *
127 * ```javascript
128 * import Api from '@polkadot/api/promise';
129 *
130 * Api.create().then(async (api) => {
131 * const timestamp = await api.query.timestamp.now();
132 *
133 * console.log(`lastest block timestamp ${timestamp}`);
134 * });
135 * ```
136 */
137 static create(options) {
138 const instance = new ApiPromise(options);
139 if (options && options.throwOnConnect) {
140 return instance.isReadyOrError;
141 }
142 // Swallow any rejections on isReadyOrError
143 // (in Node 15.x this creates issues, when not being looked at)
144 instance.isReadyOrError.catch(noop);
145 return instance.isReady;
146 }
147 /**
148 * @description Promise that resolves the first time we are connected and loaded
149 */
150 get isReady() {
151 return this.__internal__isReadyPromise;
152 }
153 /**
154 * @description Promise that resolves if we can connect, or reject if there is an error
155 */
156 get isReadyOrError() {
157 return this.__internal__isReadyOrErrorPromise;
158 }
159 /**
160 * @description Returns a clone of this ApiPromise instance (new underlying provider connection)
161 */
162 clone() {
163 return new ApiPromise(objectSpread({}, this._options, { source: this }));
164 }
165 /**
166 * @description Creates a combinator that can be used to combine the latest results from multiple subscriptions
167 * @param fns An array of function to combine, each in the form of `(cb: (value: void)) => void`
168 * @param callback A callback that will return an Array of all the values this combinator has been applied to
169 * @example
170 * <BR>
171 *
172 * ```javascript
173 * const address = '5DTestUPts3kjeXSTMyerHihn1uwMfLj8vU8sqF7qYrFacT7';
174 *
175 * // combines values from balance & nonce as it updates
176 * api.combineLatest([
177 * api.rpc.chain.subscribeNewHeads,
178 * (cb) => api.query.system.account(address, cb)
179 * ], ([head, [balance, nonce]]) => {
180 * console.log(`#${head.number}: You have ${balance.free} units, with ${nonce} transactions sent`);
181 * });
182 * ```
183 */
184 // eslint-disable-next-line @typescript-eslint/require-await
185 async combineLatest(fns, callback) {
186 const combinator = new Combinator(fns, callback);
187 return () => {
188 combinator.unsubscribe();
189 };
190 }
191}