UNPKG

24.4 kBJavaScriptView Raw
1// Copyright 2017-2022 @polkadot/api authors & contributors
2// SPDX-License-Identifier: Apache-2.0
3import { BehaviorSubject, combineLatest, from, map, of, switchMap, tap, toArray } from 'rxjs';
4import { getAvailableDerives } from '@polkadot/api-derive';
5import { memo, RpcCore } from '@polkadot/rpc-core';
6import { WsProvider } from '@polkadot/rpc-provider';
7import { expandMetadata, TypeRegistry, unwrapStorageType } from '@polkadot/types';
8import { arrayChunk, arrayFlatten, assert, assertReturn, BN, compactStripLength, lazyMethod, lazyMethods, logger, nextTick, objectSpread, u8aToHex } from '@polkadot/util';
9import { createSubmittable } from "../submittable/index.js";
10import { augmentObject } from "../util/augmentObject.js";
11import { decorateDeriveSections } from "../util/decorate.js";
12import { extractStorageArgs } from "../util/validate.js";
13import { Events } from "./Events.js";
14import { findCall, findError } from "./find.js";
15// the max amount of keys/values that we will retrieve at once
16const PAGE_SIZE_K = 1000; // limit aligned with the 1k on the node (trie lookups are heavy)
17
18const PAGE_SIZE_V = 250; // limited since the data may be > 16MB (e.g. misfiring elections)
19
20const PAGE_SIZE_Q = 50; // queue of pending storage queries (mapped together, next tick)
21
22const l = logger('api/init');
23let instanceCounter = 0;
24
25function getAtQueryFn(api, {
26 method,
27 section
28}) {
29 return assertReturn(api.rx.query[section] && api.rx.query[section][method], () => `query.${section}.${method} is not available in this version of the metadata`);
30}
31
32export class Decorate extends Events {
33 #instanceId;
34 #registry;
35 #storageGetQ = [];
36 #storageSubQ = []; // HACK Use BN import so decorateDerive works... yes, wtf.
37
38 __phantom = new BN(0);
39 _consts = {};
40 _errors = {};
41 _events = {};
42 _extrinsicType = 4; // latest extrinsic version
43
44 _isReady = false;
45 _query = {};
46 _rx = {
47 consts: {},
48 query: {},
49 tx: {}
50 };
51
52 /**
53 * @description Create an instance of the class
54 *
55 * @param options Options object to create API instance or a Provider instance
56 *
57 * @example
58 * <BR>
59 *
60 * ```javascript
61 * import Api from '@polkadot/api/promise';
62 *
63 * const api = new Api().isReady();
64 *
65 * api.rpc.subscribeNewHeads((header) => {
66 * console.log(`new block #${header.number.toNumber()}`);
67 * });
68 * ```
69 */
70 constructor(options, type, decorateMethod) {
71 var _options$source;
72
73 super();
74 this.#instanceId = `${++instanceCounter}`;
75 this.#registry = ((_options$source = options.source) === null || _options$source === void 0 ? void 0 : _options$source.registry) || options.registry || new TypeRegistry();
76
77 this._rx.queryAt = (blockHash, knownVersion) => from(this.at(blockHash, knownVersion)).pipe(map(a => a.rx.query));
78
79 this._rx.registry = this.#registry;
80 const thisProvider = options.source ? options.source._rpcCore.provider.clone() : options.provider || new WsProvider();
81 this._decorateMethod = decorateMethod;
82 this._options = options;
83 this._type = type; // The RPC interface decorates the known interfaces on init
84
85 this._rpcCore = new RpcCore(this.#instanceId, this.#registry, thisProvider, this._options.rpc);
86 this._isConnected = new BehaviorSubject(this._rpcCore.provider.isConnected);
87 this._rx.hasSubscriptions = this._rpcCore.provider.hasSubscriptions;
88 }
89
90 /**
91 * @description Return the current used registry
92 */
93 get registry() {
94 return this.#registry;
95 }
96 /**
97 * @description Creates an instance of a type as registered
98 */
99
100
101 createType(type, ...params) {
102 return this.#registry.createType(type, ...params);
103 }
104 /**
105 * @description Register additional user-defined of chain-specific types in the type registry
106 */
107
108
109 registerTypes(types) {
110 types && this.#registry.register(types);
111 }
112 /**
113 * @returns `true` if the API operates with subscriptions
114 */
115
116
117 get hasSubscriptions() {
118 return this._rpcCore.provider.hasSubscriptions;
119 }
120 /**
121 * @returns `true` if the API decorate multi-key queries
122 */
123
124
125 get supportMulti() {
126 return this._rpcCore.provider.hasSubscriptions || !!this._rpcCore.state.queryStorageAt;
127 }
128
129 _emptyDecorated(registry, blockHash) {
130 return {
131 consts: {},
132 errors: {},
133 events: {},
134 query: {},
135 registry,
136 rx: {
137 query: {}
138 },
139 tx: createSubmittable(this._type, this._rx, this._decorateMethod, registry, blockHash)
140 };
141 }
142
143 _createDecorated(registry, fromEmpty, decoratedApi, blockHash) {
144 if (!decoratedApi) {
145 decoratedApi = this._emptyDecorated(registry.registry, blockHash);
146 }
147
148 if (fromEmpty || !registry.decoratedMeta) {
149 registry.decoratedMeta = expandMetadata(registry.registry, registry.metadata);
150 }
151
152 const storage = this._decorateStorage(registry.decoratedMeta, this._decorateMethod, blockHash);
153
154 const storageRx = this._decorateStorage(registry.decoratedMeta, this._rxDecorateMethod, blockHash);
155
156 augmentObject('consts', registry.decoratedMeta.consts, decoratedApi.consts, fromEmpty);
157 augmentObject('errors', registry.decoratedMeta.errors, decoratedApi.errors, fromEmpty);
158 augmentObject('events', registry.decoratedMeta.events, decoratedApi.events, fromEmpty);
159 augmentObject('query', storage, decoratedApi.query, fromEmpty);
160 augmentObject('query', storageRx, decoratedApi.rx.query, fromEmpty);
161
162 decoratedApi.findCall = callIndex => findCall(registry.registry, callIndex);
163
164 decoratedApi.findError = errorIndex => findError(registry.registry, errorIndex);
165
166 decoratedApi.queryMulti = blockHash ? this._decorateMultiAt(decoratedApi, this._decorateMethod, blockHash) : this._decorateMulti(this._decorateMethod);
167 decoratedApi.runtimeVersion = registry.runtimeVersion;
168 return {
169 decoratedApi,
170 decoratedMeta: registry.decoratedMeta
171 };
172 }
173
174 _injectMetadata(registry, fromEmpty = false) {
175 // clear the decoration, we are redoing it here
176 if (fromEmpty || !registry.decoratedApi) {
177 registry.decoratedApi = this._emptyDecorated(registry.registry);
178 }
179
180 const {
181 decoratedApi,
182 decoratedMeta
183 } = this._createDecorated(registry, fromEmpty, registry.decoratedApi);
184
185 this._consts = decoratedApi.consts;
186 this._errors = decoratedApi.errors;
187 this._events = decoratedApi.events;
188 this._query = decoratedApi.query;
189 this._rx.query = decoratedApi.rx.query;
190
191 const tx = this._decorateExtrinsics(decoratedMeta, this._decorateMethod);
192
193 const rxtx = this._decorateExtrinsics(decoratedMeta, this._rxDecorateMethod);
194
195 if (fromEmpty || !this._extrinsics) {
196 this._extrinsics = tx;
197 this._rx.tx = rxtx;
198 } else {
199 augmentObject('tx', tx, this._extrinsics, false);
200 augmentObject(null, rxtx, this._rx.tx, false);
201 }
202
203 augmentObject(null, decoratedMeta.consts, this._rx.consts, fromEmpty);
204 this.emit('decorated');
205 }
206 /**
207 * @deprecated
208 * backwards compatible endpoint for metadata injection, may be removed in the future (However, it is still useful for testing injection)
209 */
210
211
212 injectMetadata(metadata, fromEmpty, registry) {
213 this._injectMetadata({
214 metadata,
215 registry: registry || this.#registry,
216 runtimeVersion: this.#registry.createType('RuntimeVersionPartial')
217 }, fromEmpty);
218 }
219
220 _decorateFunctionMeta(input, output) {
221 output.meta = input.meta;
222 output.method = input.method;
223 output.section = input.section;
224 output.toJSON = input.toJSON;
225
226 if (input.callIndex) {
227 output.callIndex = input.callIndex;
228 }
229
230 return output;
231 } // Filter all RPC methods based on the results of the rpc_methods call. We do this in the following
232 // manner to cater for both old and new:
233 // - when the number of entries are 0, only remove the ones with isOptional (account & contracts)
234 // - when non-zero, remove anything that is not in the array (we don't do this)
235
236
237 _filterRpc(methods, additional) {
238 // add any specific user-base RPCs
239 if (Object.keys(additional).length !== 0) {
240 this._rpcCore.addUserInterfaces(additional); // re-decorate, only adding any new additional interfaces
241
242
243 this._decorateRpc(this._rpcCore, this._decorateMethod, this._rpc);
244
245 this._decorateRpc(this._rpcCore, this._rxDecorateMethod, this._rx.rpc);
246 }
247
248 this._filterRpcMethods(methods);
249 }
250
251 _filterRpcMethods(exposed) {
252 const hasResults = exposed.length !== 0;
253 const allKnown = [...this._rpcCore.mapping.entries()];
254 const allKeys = [];
255
256 for (let i = 0; i < allKnown.length; i++) {
257 const [, {
258 alias,
259 endpoint,
260 method,
261 pubsub,
262 section
263 }] = allKnown[i];
264 allKeys.push(`${section}_${method}`);
265
266 if (pubsub) {
267 allKeys.push(`${section}_${pubsub[1]}`);
268 allKeys.push(`${section}_${pubsub[2]}`);
269 }
270
271 if (alias) {
272 allKeys.push(...alias);
273 }
274
275 if (endpoint) {
276 allKeys.push(endpoint);
277 }
278 }
279
280 const filterKey = k => !allKeys.includes(k);
281
282 const unknown = exposed.filter(filterKey);
283
284 if (unknown.length) {
285 l.warn(`RPC methods not decorated: ${unknown.join(', ')}`);
286 } // loop through all entries we have (populated in decorate) and filter as required
287 // only remove when we have results and method missing, or with no results if optional
288
289
290 for (let i = 0; i < allKnown.length; i++) {
291 const [k, {
292 method,
293 section
294 }] = allKnown[i];
295
296 if (hasResults && !exposed.includes(k) && k !== 'rpc_methods') {
297 if (this._rpc[section]) {
298 delete this._rpc[section][method];
299 delete this._rx.rpc[section][method];
300 }
301 }
302 }
303 }
304
305 _decorateRpc(rpc, decorateMethod, input = {}) {
306 const out = input;
307
308 const decorateFn = (section, method) => {
309 const source = rpc[section][method];
310 const fn = decorateMethod(source, {
311 methodName: method
312 });
313 fn.meta = source.meta;
314 fn.raw = decorateMethod(source.raw, {
315 methodName: method
316 });
317 return fn;
318 };
319
320 for (let s = 0; s < rpc.sections.length; s++) {
321 const section = rpc.sections[s];
322
323 if (!Object.prototype.hasOwnProperty.call(out, section)) {
324 const methods = Object.keys(rpc[section]);
325
326 const decorateInternal = method => decorateFn(section, method);
327
328 for (let m = 0; m < methods.length; m++) {
329 const method = methods[m]; // skip subscriptions where we have a non-subscribe interface
330
331 if (this.hasSubscriptions || !(method.startsWith('subscribe') || method.startsWith('unsubscribe'))) {
332 if (!Object.prototype.hasOwnProperty.call(out, section)) {
333 out[section] = {};
334 }
335
336 lazyMethod(out[section], method, decorateInternal);
337 }
338 }
339 }
340 }
341
342 return out;
343 } // only be called if supportMulti is true
344
345
346 _decorateMulti(decorateMethod) {
347 // eslint-disable-next-line @typescript-eslint/no-unsafe-return
348 return decorateMethod(keys => (this.hasSubscriptions ? this._rpcCore.state.subscribeStorage : this._rpcCore.state.queryStorageAt)(keys.map(args => Array.isArray(args) ? args[0].creator.meta.type.isPlain ? [args[0].creator] : args[0].creator.meta.type.asMap.hashers.length === 1 ? [args[0].creator, args.slice(1)] : [args[0].creator, ...args.slice(1)] : [args.creator])));
349 }
350
351 _decorateMultiAt(atApi, decorateMethod, blockHash) {
352 // eslint-disable-next-line @typescript-eslint/no-unsafe-return
353 return decorateMethod(calls => this._rpcCore.state.queryStorageAt(calls.map(args => {
354 if (Array.isArray(args)) {
355 const {
356 creator
357 } = getAtQueryFn(atApi, args[0].creator);
358 return creator.meta.type.isPlain ? [creator] : creator.meta.type.asMap.hashers.length === 1 ? [creator, args.slice(1)] : [creator, ...args.slice(1)];
359 }
360
361 return [getAtQueryFn(atApi, args.creator).creator];
362 }), blockHash));
363 }
364
365 _decorateExtrinsics({
366 tx
367 }, decorateMethod) {
368 const result = createSubmittable(this._type, this._rx, decorateMethod);
369
370 const lazySection = section => lazyMethods({}, Object.keys(tx[section]), method => this._decorateExtrinsicEntry(tx[section][method], result));
371
372 const sections = Object.keys(tx);
373
374 for (let i = 0; i < sections.length; i++) {
375 lazyMethod(result, sections[i], lazySection);
376 }
377
378 return result;
379 }
380
381 _decorateExtrinsicEntry(method, creator) {
382 const decorated = (...params) => creator(method(...params)); // pass through the `.is`
383
384
385 decorated.is = other => method.is(other); // eslint-disable-next-line @typescript-eslint/no-unsafe-return
386
387
388 return this._decorateFunctionMeta(method, decorated);
389 }
390
391 _decorateStorage({
392 query,
393 registry
394 }, decorateMethod, blockHash) {
395 const result = {};
396
397 const lazySection = section => lazyMethods({}, Object.keys(query[section]), method => blockHash ? this._decorateStorageEntryAt(registry, query[section][method], decorateMethod, blockHash) : this._decorateStorageEntry(query[section][method], decorateMethod));
398
399 const sections = Object.keys(query);
400
401 for (let i = 0; i < sections.length; i++) {
402 lazyMethod(result, sections[i], lazySection);
403 }
404
405 return result;
406 }
407
408 _decorateStorageEntry(creator, decorateMethod) {
409 const getArgs = (args, registry) => extractStorageArgs(registry || this.#registry, creator, args);
410
411 const getQueryAt = blockHash => from(this.at(blockHash)).pipe(map(api => getAtQueryFn(api, creator))); // Disable this where it occurs for each field we are decorating
412
413 /* eslint-disable @typescript-eslint/no-unsafe-member-access,@typescript-eslint/no-unsafe-assignment */
414
415
416 const decorated = this._decorateStorageCall(creator, decorateMethod);
417
418 decorated.creator = creator;
419 decorated.at = decorateMethod((blockHash, ...args) => getQueryAt(blockHash).pipe(switchMap(q => q(...args))));
420 decorated.hash = decorateMethod((...args) => this._rpcCore.state.getStorageHash(getArgs(args)));
421
422 decorated.is = key => key.section === creator.section && key.method === creator.method;
423
424 decorated.key = (...args) => u8aToHex(compactStripLength(creator(...args))[1]);
425
426 decorated.keyPrefix = (...args) => u8aToHex(creator.keyPrefix(...args));
427
428 decorated.range = decorateMethod((range, ...args) => this._decorateStorageRange(decorated, args, range));
429 decorated.size = decorateMethod((...args) => this._rpcCore.state.getStorageSize(getArgs(args)));
430 decorated.sizeAt = decorateMethod((blockHash, ...args) => getQueryAt(blockHash).pipe(switchMap(q => this._rpcCore.state.getStorageSize(getArgs(args, q.creator.meta.registry), blockHash)))); // .keys() & .entries() only available on map types
431
432 if (creator.iterKey && creator.meta.type.isMap) {
433 decorated.entries = decorateMethod(memo(this.#instanceId, (...args) => this._retrieveMapEntries(creator, null, args)));
434 decorated.entriesAt = decorateMethod(memo(this.#instanceId, (blockHash, ...args) => getQueryAt(blockHash).pipe(switchMap(q => this._retrieveMapEntries(q.creator, blockHash, args)))));
435 decorated.entriesPaged = decorateMethod(memo(this.#instanceId, opts => this._retrieveMapEntriesPaged(creator, undefined, opts)));
436 decorated.keys = decorateMethod(memo(this.#instanceId, (...args) => this._retrieveMapKeys(creator, null, args)));
437 decorated.keysAt = decorateMethod(memo(this.#instanceId, (blockHash, ...args) => getQueryAt(blockHash).pipe(switchMap(q => this._retrieveMapKeys(q.creator, blockHash, args)))));
438 decorated.keysPaged = decorateMethod(memo(this.#instanceId, opts => this._retrieveMapKeysPaged(creator, undefined, opts)));
439 }
440
441 if (this.supportMulti && creator.meta.type.isMap) {
442 // When using double map storage function, user need to pass double map key as an array
443 decorated.multi = decorateMethod(args => creator.meta.type.asMap.hashers.length === 1 ? this._retrieveMulti(args.map(a => [creator, [a]])) : this._retrieveMulti(args.map(a => [creator, a])));
444 }
445 /* eslint-enable @typescript-eslint/no-unsafe-member-access,@typescript-eslint/no-unsafe-assignment */
446
447
448 return this._decorateFunctionMeta(creator, decorated);
449 }
450
451 _decorateStorageEntryAt(registry, creator, decorateMethod, blockHash) {
452 const getArgs = args => extractStorageArgs(registry, creator, args); // Disable this where it occurs for each field we are decorating
453
454 /* eslint-disable @typescript-eslint/no-unsafe-member-access,@typescript-eslint/no-unsafe-assignment */
455
456
457 const decorated = decorateMethod((...args) => this._rpcCore.state.getStorage(getArgs(args), blockHash));
458 decorated.creator = creator;
459 decorated.hash = decorateMethod((...args) => this._rpcCore.state.getStorageHash(getArgs(args), blockHash));
460
461 decorated.is = key => key.section === creator.section && key.method === creator.method;
462
463 decorated.key = (...args) => u8aToHex(compactStripLength(creator(creator.meta.type.isPlain ? undefined : args))[1]);
464
465 decorated.keyPrefix = (...keys) => u8aToHex(creator.keyPrefix(...keys));
466
467 decorated.size = decorateMethod((...args) => this._rpcCore.state.getStorageSize(getArgs(args), blockHash)); // .keys() & .entries() only available on map types
468
469 if (creator.iterKey && creator.meta.type.isMap) {
470 decorated.entries = decorateMethod(memo(this.#instanceId, (...args) => this._retrieveMapEntries(creator, blockHash, args)));
471 decorated.entriesPaged = decorateMethod(memo(this.#instanceId, opts => this._retrieveMapEntriesPaged(creator, blockHash, opts)));
472 decorated.keys = decorateMethod(memo(this.#instanceId, (...args) => this._retrieveMapKeys(creator, blockHash, args)));
473 decorated.keysPaged = decorateMethod(memo(this.#instanceId, opts => this._retrieveMapKeysPaged(creator, blockHash, opts)));
474 }
475
476 if (this.supportMulti && creator.meta.type.isMap) {
477 // When using double map storage function, user need to pass double map key as an array
478 decorated.multi = decorateMethod(args => creator.meta.type.asMap.hashers.length === 1 ? this._retrieveMulti(args.map(a => [creator, [a]]), blockHash) : this._retrieveMulti(args.map(a => [creator, a]), blockHash));
479 }
480 /* eslint-enable @typescript-eslint/no-unsafe-member-access,@typescript-eslint/no-unsafe-assignment */
481
482
483 return this._decorateFunctionMeta(creator, decorated);
484 }
485
486 _queueStorage(call, queue) {
487 const query = queue === this.#storageSubQ ? this._rpcCore.state.subscribeStorage : this._rpcCore.state.queryStorageAt;
488 let queueIdx = queue.length - 1;
489 let valueIdx = 0;
490 let valueObs;
491
492 if (queueIdx === -1 || !queue[queueIdx] || queue[queueIdx][1].length === PAGE_SIZE_Q) {
493 queueIdx++;
494 valueObs = from( // Defer to the next tick - this aligns with nextTick in @polkadot/util,
495 // however since we return a value here, we don't re-use what is there
496 Promise.resolve().then(() => {
497 const calls = queue[queueIdx][1];
498 delete queue[queueIdx];
499 return calls;
500 })).pipe(switchMap(calls => query(calls)));
501 queue.push([valueObs, [call]]);
502 } else {
503 valueObs = queue[queueIdx][0];
504 valueIdx = queue[queueIdx][1].length;
505 queue[queueIdx][1].push(call);
506 }
507
508 return valueObs.pipe(map(values => values[valueIdx]));
509 } // Decorate the base storage call. In the case or rxjs or promise-without-callback (await)
510 // we make a subscription, alternatively we push this through a single-shot query
511
512
513 _decorateStorageCall(creator, decorateMethod) {
514 return decorateMethod((...args) => {
515 const call = extractStorageArgs(this.#registry, creator, args);
516
517 if (!this.hasSubscriptions) {
518 return this._rpcCore.state.getStorage(call);
519 }
520
521 return this._queueStorage(call, this.#storageSubQ);
522 }, {
523 methodName: creator.method,
524 overrideNoSub: (...args) => this._queueStorage(extractStorageArgs(this.#registry, creator, args), this.#storageGetQ)
525 });
526 }
527
528 _decorateStorageRange(decorated, args, range) {
529 const outputType = unwrapStorageType(this.#registry, decorated.creator.meta.type, decorated.creator.meta.modifier.isOptional);
530 return this._rpcCore.state.queryStorage([decorated.key(...args)], ...range).pipe(map(result => result.map(([blockHash, [value]]) => [blockHash, this.createType(outputType, value.isSome ? value.unwrap().toHex() : undefined)])));
531 } // retrieve a set of values for a specific set of keys - here we chunk the keys into PAGE_SIZE sizes
532
533
534 _retrieveMulti(keys, blockHash) {
535 if (!keys.length) {
536 return of([]);
537 }
538
539 const query = this.hasSubscriptions && !blockHash ? this._rpcCore.state.subscribeStorage : this._rpcCore.state.queryStorageAt;
540
541 if (keys.length <= PAGE_SIZE_V) {
542 return blockHash ? query(keys, blockHash) : query(keys);
543 }
544
545 return combineLatest(arrayChunk(keys, PAGE_SIZE_V).map(k => blockHash ? query(k, blockHash) : query(k))).pipe(map(arrayFlatten));
546 }
547
548 _retrieveMapKeys({
549 iterKey,
550 meta,
551 method,
552 section
553 }, at, args) {
554 assert(iterKey && meta.type.isMap, 'keys can only be retrieved on maps');
555 const headKey = iterKey(...args).toHex();
556 const startSubject = new BehaviorSubject(headKey);
557 const query = at ? startKey => this._rpcCore.state.getKeysPaged(headKey, PAGE_SIZE_K, startKey, at) : startKey => this._rpcCore.state.getKeysPaged(headKey, PAGE_SIZE_K, startKey);
558
559 const setMeta = key => key.setMeta(meta, section, method);
560
561 return startSubject.pipe(switchMap(query), map(keys => keys.map(setMeta)), tap(keys => nextTick(() => {
562 keys.length === PAGE_SIZE_K ? startSubject.next(keys[PAGE_SIZE_K - 1].toHex()) : startSubject.complete();
563 })), toArray(), // toArray since we want to startSubject to be completed
564 map(arrayFlatten));
565 }
566
567 _retrieveMapKeysPaged({
568 iterKey,
569 meta,
570 method,
571 section
572 }, at, opts) {
573 assert(iterKey && meta.type.isMap, 'keys can only be retrieved on maps');
574
575 const setMeta = key => key.setMeta(meta, section, method);
576
577 const query = at ? headKey => this._rpcCore.state.getKeysPaged(headKey, opts.pageSize, opts.startKey || headKey, at) : headKey => this._rpcCore.state.getKeysPaged(headKey, opts.pageSize, opts.startKey || headKey);
578 return query(iterKey(...opts.args).toHex()).pipe(map(keys => keys.map(setMeta)));
579 }
580
581 _retrieveMapEntries(entry, at, args) {
582 const query = at ? keys => this._rpcCore.state.queryStorageAt(keys, at) : keys => this._rpcCore.state.queryStorageAt(keys);
583 return this._retrieveMapKeys(entry, at, args).pipe(switchMap(keys => keys.length ? combineLatest(arrayChunk(keys, PAGE_SIZE_V).map(query)).pipe(map(valsArr => arrayFlatten(valsArr).map((value, index) => [keys[index], value]))) : of([])));
584 }
585
586 _retrieveMapEntriesPaged(entry, at, opts) {
587 const query = at ? keys => this._rpcCore.state.queryStorageAt(keys, at) : keys => this._rpcCore.state.queryStorageAt(keys);
588 return this._retrieveMapKeysPaged(entry, at, opts).pipe(switchMap(keys => keys.length ? query(keys).pipe(map(valsArr => valsArr.map((value, index) => [keys[index], value]))) : of([])));
589 }
590
591 _decorateDeriveRx(decorateMethod) {
592 var _this$_runtimeVersion, _this$_options$typesB, _this$_options$typesB2, _this$_options$typesB3;
593
594 const specName = (_this$_runtimeVersion = this._runtimeVersion) === null || _this$_runtimeVersion === void 0 ? void 0 : _this$_runtimeVersion.specName.toString(); // Pull in derive from api-derive
595
596 const available = getAvailableDerives(this.#instanceId, this._rx, objectSpread({}, this._options.derives, (_this$_options$typesB = this._options.typesBundle) === null || _this$_options$typesB === void 0 ? void 0 : (_this$_options$typesB2 = _this$_options$typesB.spec) === null || _this$_options$typesB2 === void 0 ? void 0 : (_this$_options$typesB3 = _this$_options$typesB2[specName || '']) === null || _this$_options$typesB3 === void 0 ? void 0 : _this$_options$typesB3.derives));
597 return decorateDeriveSections(decorateMethod, available);
598 }
599
600 _decorateDerive(decorateMethod) {
601 return decorateDeriveSections(decorateMethod, this._rx.derive);
602 }
603 /**
604 * Put the `this.onCall` function of ApiRx here, because it is needed by
605 * `api._rx`.
606 */
607
608
609 _rxDecorateMethod = method => {
610 return method;
611 };
612}
\No newline at end of file