UNPKG

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