@pezkuwi/rpc-core 16.5.5 → 16.5.6
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/LICENSE +201 -0
- package/{build/bundle.d.ts → bundle.d.ts} +1 -1
- package/bundle.js +411 -0
- package/cjs/bundle.d.ts +91 -0
- package/cjs/bundle.js +417 -0
- package/cjs/index.js +5 -0
- package/cjs/package.json +3 -0
- package/cjs/packageDetect.js +7 -0
- package/cjs/packageInfo.js +4 -0
- package/cjs/types/base.js +2 -0
- package/cjs/types/index.js +5 -0
- package/cjs/types/jsonrpc.js +2 -0
- package/cjs/util/drr.js +31 -0
- package/cjs/util/index.js +6 -0
- package/cjs/util/memo.js +18 -0
- package/cjs/util/refCountDelay.js +40 -0
- package/index.d.ts +2 -0
- package/index.js +2 -0
- package/package.json +186 -12
- package/packageDetect.d.ts +1 -0
- package/{src/packageDetect.ts → packageDetect.js} +0 -8
- package/packageInfo.d.ts +6 -0
- package/packageInfo.js +1 -0
- package/types/base.d.ts +22 -0
- package/types/base.js +1 -0
- package/types/index.d.ts +2 -0
- package/types/index.js +2 -0
- package/types/jsonrpc.d.ts +2 -0
- package/types/jsonrpc.js +1 -0
- package/util/drr.d.ts +15 -0
- package/util/drr.js +28 -0
- package/util/index.d.ts +3 -0
- package/util/index.js +3 -0
- package/util/memo.d.ts +6 -0
- package/util/memo.js +15 -0
- package/util/refCountDelay.d.ts +3 -0
- package/util/refCountDelay.js +37 -0
- package/src/bundle.ts +0 -535
- package/src/cached.spec.ts +0 -129
- package/src/checkTypes.manual.ts +0 -4
- package/src/index.spec.ts +0 -55
- package/src/index.ts +0 -6
- package/src/methodSend.spec.ts +0 -75
- package/src/mod.ts +0 -4
- package/src/packageInfo.ts +0 -6
- package/src/replay.spec.ts +0 -73
- package/src/types/base.ts +0 -28
- package/src/types/index.ts +0 -8
- package/src/types/jsonrpc.ts +0 -7
- package/src/util/drr.spec.ts +0 -50
- package/src/util/drr.ts +0 -52
- package/src/util/index.ts +0 -6
- package/src/util/memo.ts +0 -36
- package/src/util/refCountDelay.ts +0 -45
- package/tsconfig.build.json +0 -17
- package/tsconfig.build.tsbuildinfo +0 -1
- package/tsconfig.spec.json +0 -20
- /package/{build → cjs}/index.d.ts +0 -0
- /package/{build → cjs}/packageDetect.d.ts +0 -0
- /package/{build → cjs}/packageInfo.d.ts +0 -0
- /package/{build → cjs}/types/base.d.ts +0 -0
- /package/{build → cjs}/types/index.d.ts +0 -0
- /package/{build → cjs}/types/jsonrpc.d.ts +0 -0
- /package/{build → cjs}/util/drr.d.ts +0 -0
- /package/{build → cjs}/util/index.d.ts +0 -0
- /package/{build → cjs}/util/memo.d.ts +0 -0
- /package/{build → cjs}/util/refCountDelay.d.ts +0 -0
package/cjs/bundle.d.ts
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import type { ProviderInterface } from '@pezkuwi/rpc-provider/types';
|
|
2
|
+
import type { AnyNumber, DefinitionRpc, DefinitionRpcExt, DefinitionRpcSub, Registry } from '@pezkuwi/types/types';
|
|
3
|
+
import type { RpcCoreStats } from './types/index.js';
|
|
4
|
+
export { packageInfo } from './packageInfo.js';
|
|
5
|
+
export * from './util/index.js';
|
|
6
|
+
interface Options {
|
|
7
|
+
isPedantic?: boolean;
|
|
8
|
+
provider: ProviderInterface;
|
|
9
|
+
/**
|
|
10
|
+
* Custom size of the rpc LRUCache capacity. Defaults to `RPC_CORE_DEFAULT_CAPACITY` (1024 * 10 * 10)
|
|
11
|
+
*/
|
|
12
|
+
rpcCacheCapacity?: number;
|
|
13
|
+
ttl?: number | null;
|
|
14
|
+
userRpc?: Record<string, Record<string, DefinitionRpc | DefinitionRpcSub>>;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* @name Rpc
|
|
18
|
+
* @summary The API may use a HTTP or WebSockets provider.
|
|
19
|
+
* @description It allows for querying a Pezkuwi Client Node.
|
|
20
|
+
* WebSockets provider is recommended since HTTP provider only supports basic querying.
|
|
21
|
+
*
|
|
22
|
+
* ```mermaid
|
|
23
|
+
* graph LR;
|
|
24
|
+
* A[Api] --> |WebSockets| B[WsProvider];
|
|
25
|
+
* B --> |endpoint| C[ws://127.0.0.1:9944]
|
|
26
|
+
* ```
|
|
27
|
+
*
|
|
28
|
+
* @example
|
|
29
|
+
* <BR>
|
|
30
|
+
*
|
|
31
|
+
* ```javascript
|
|
32
|
+
* import Rpc from '@pezkuwi/rpc-core';
|
|
33
|
+
* import { WsProvider } from '@pezkuwi/rpc-provider/ws';
|
|
34
|
+
*
|
|
35
|
+
* const provider = new WsProvider('ws://127.0.0.1:9944');
|
|
36
|
+
* const rpc = new Rpc(provider);
|
|
37
|
+
* ```
|
|
38
|
+
*/
|
|
39
|
+
export declare class RpcCore {
|
|
40
|
+
#private;
|
|
41
|
+
readonly mapping: Map<string, DefinitionRpcExt>;
|
|
42
|
+
readonly provider: ProviderInterface;
|
|
43
|
+
readonly sections: string[];
|
|
44
|
+
/**
|
|
45
|
+
* @constructor
|
|
46
|
+
* Default constructor for the core RPC handler
|
|
47
|
+
* @param {Registry} registry Type Registry
|
|
48
|
+
* @param {ProviderInterface} options.provider An API provider using any of the supported providers (HTTP, SC or WebSocket)
|
|
49
|
+
* @param {number} [options.rpcCacheCapacity] Custom size of the rpc LRUCache capacity. Defaults to `RPC_CORE_DEFAULT_CAPACITY` (1024 * 10 * 10)
|
|
50
|
+
*/
|
|
51
|
+
constructor(instanceId: string, registry: Registry, { isPedantic, provider, rpcCacheCapacity, ttl, userRpc }: Options);
|
|
52
|
+
/**
|
|
53
|
+
* @description Returns the connected status of a provider
|
|
54
|
+
*/
|
|
55
|
+
get isConnected(): boolean;
|
|
56
|
+
/**
|
|
57
|
+
* @description Manually connect from the attached provider
|
|
58
|
+
*/
|
|
59
|
+
connect(): Promise<void>;
|
|
60
|
+
/**
|
|
61
|
+
* @description Manually disconnect from the attached provider
|
|
62
|
+
*/
|
|
63
|
+
disconnect(): Promise<void>;
|
|
64
|
+
/**
|
|
65
|
+
* @description Returns the underlying core stats, including those from teh provider
|
|
66
|
+
*/
|
|
67
|
+
get stats(): RpcCoreStats | undefined;
|
|
68
|
+
/**
|
|
69
|
+
* @description Sets a registry swap (typically from Api)
|
|
70
|
+
*/
|
|
71
|
+
setRegistrySwap(registrySwap: (blockHash: Uint8Array) => Promise<{
|
|
72
|
+
registry: Registry;
|
|
73
|
+
}>): void;
|
|
74
|
+
/**
|
|
75
|
+
* @description Sets a function to resolve block hash from block number
|
|
76
|
+
*/
|
|
77
|
+
setResolveBlockHash(resolveBlockHash: (blockNumber: AnyNumber) => Promise<Uint8Array>): void;
|
|
78
|
+
addUserInterfaces(userRpc: Record<string, Record<string, DefinitionRpc | DefinitionRpcSub>>): void;
|
|
79
|
+
private _memomize;
|
|
80
|
+
private _formatResult;
|
|
81
|
+
private _createMethodSend;
|
|
82
|
+
private _createSubscriber;
|
|
83
|
+
private _createMethodSubscribe;
|
|
84
|
+
private _formatParams;
|
|
85
|
+
private _formatOutput;
|
|
86
|
+
private _formatStorageData;
|
|
87
|
+
private _formatStorageSet;
|
|
88
|
+
private _formatStorageSetEntry;
|
|
89
|
+
private _setToCache;
|
|
90
|
+
private _newType;
|
|
91
|
+
}
|
package/cjs/bundle.js
ADDED
|
@@ -0,0 +1,417 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.RpcCore = exports.packageInfo = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const rxjs_1 = require("rxjs");
|
|
6
|
+
const rpc_provider_1 = require("@pezkuwi/rpc-provider");
|
|
7
|
+
const types_1 = require("@pezkuwi/types");
|
|
8
|
+
const util_1 = require("@pezkuwi/types/util");
|
|
9
|
+
const util_2 = require("@pezkuwi/util");
|
|
10
|
+
const index_js_1 = require("./util/index.js");
|
|
11
|
+
var packageInfo_js_1 = require("./packageInfo.js");
|
|
12
|
+
Object.defineProperty(exports, "packageInfo", { enumerable: true, get: function () { return packageInfo_js_1.packageInfo; } });
|
|
13
|
+
tslib_1.__exportStar(require("./util/index.js"), exports);
|
|
14
|
+
const l = (0, util_2.logger)('rpc-core');
|
|
15
|
+
const EMPTY_META = {
|
|
16
|
+
fallback: undefined,
|
|
17
|
+
modifier: { isOptional: true },
|
|
18
|
+
type: {
|
|
19
|
+
asMap: { linked: { isTrue: false } },
|
|
20
|
+
isMap: false
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
const RPC_CORE_DEFAULT_CAPACITY = 1024 * 10 * 10;
|
|
24
|
+
/** @internal */
|
|
25
|
+
function logErrorMessage(method, { noErrorLog, params, type }, error) {
|
|
26
|
+
if (noErrorLog) {
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
l.error(`${method}(${params.map(({ isOptional, name, type }) => `${name}${isOptional ? '?' : ''}: ${type}`).join(', ')}): ${type}:: ${error.message}`);
|
|
30
|
+
}
|
|
31
|
+
function isTreatAsHex(key) {
|
|
32
|
+
// :code is problematic - it does not have the length attached, which is
|
|
33
|
+
// unlike all other storage entries where it is indeed properly encoded
|
|
34
|
+
return ['0x3a636f6465'].includes(key.toHex());
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* @name Rpc
|
|
38
|
+
* @summary The API may use a HTTP or WebSockets provider.
|
|
39
|
+
* @description It allows for querying a Pezkuwi Client Node.
|
|
40
|
+
* WebSockets provider is recommended since HTTP provider only supports basic querying.
|
|
41
|
+
*
|
|
42
|
+
* ```mermaid
|
|
43
|
+
* graph LR;
|
|
44
|
+
* A[Api] --> |WebSockets| B[WsProvider];
|
|
45
|
+
* B --> |endpoint| C[ws://127.0.0.1:9944]
|
|
46
|
+
* ```
|
|
47
|
+
*
|
|
48
|
+
* @example
|
|
49
|
+
* <BR>
|
|
50
|
+
*
|
|
51
|
+
* ```javascript
|
|
52
|
+
* import Rpc from '@pezkuwi/rpc-core';
|
|
53
|
+
* import { WsProvider } from '@pezkuwi/rpc-provider/ws';
|
|
54
|
+
*
|
|
55
|
+
* const provider = new WsProvider('ws://127.0.0.1:9944');
|
|
56
|
+
* const rpc = new Rpc(provider);
|
|
57
|
+
* ```
|
|
58
|
+
*/
|
|
59
|
+
class RpcCore {
|
|
60
|
+
#instanceId;
|
|
61
|
+
#isPedantic;
|
|
62
|
+
#registryDefault;
|
|
63
|
+
#storageCache;
|
|
64
|
+
#storageCacheHits = 0;
|
|
65
|
+
#getBlockRegistry;
|
|
66
|
+
#getBlockHash;
|
|
67
|
+
mapping = new Map();
|
|
68
|
+
provider;
|
|
69
|
+
sections = [];
|
|
70
|
+
/**
|
|
71
|
+
* @constructor
|
|
72
|
+
* Default constructor for the core RPC handler
|
|
73
|
+
* @param {Registry} registry Type Registry
|
|
74
|
+
* @param {ProviderInterface} options.provider An API provider using any of the supported providers (HTTP, SC or WebSocket)
|
|
75
|
+
* @param {number} [options.rpcCacheCapacity] Custom size of the rpc LRUCache capacity. Defaults to `RPC_CORE_DEFAULT_CAPACITY` (1024 * 10 * 10)
|
|
76
|
+
*/
|
|
77
|
+
constructor(instanceId, registry, { isPedantic = true, provider, rpcCacheCapacity, ttl, userRpc = {} }) {
|
|
78
|
+
if (!provider || !(0, util_2.isFunction)(provider.send)) {
|
|
79
|
+
throw new Error('Expected Provider to API create');
|
|
80
|
+
}
|
|
81
|
+
this.#instanceId = instanceId;
|
|
82
|
+
this.#isPedantic = isPedantic;
|
|
83
|
+
this.#registryDefault = registry;
|
|
84
|
+
this.provider = provider;
|
|
85
|
+
const sectionNames = Object.keys(types_1.rpcDefinitions);
|
|
86
|
+
// these are the base keys (i.e. part of jsonrpc)
|
|
87
|
+
this.sections.push(...sectionNames);
|
|
88
|
+
this.#storageCache = new rpc_provider_1.LRUCache(rpcCacheCapacity || RPC_CORE_DEFAULT_CAPACITY, ttl);
|
|
89
|
+
// decorate all interfaces, defined and user on this instance
|
|
90
|
+
this.addUserInterfaces(userRpc);
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* @description Returns the connected status of a provider
|
|
94
|
+
*/
|
|
95
|
+
get isConnected() {
|
|
96
|
+
return this.provider.isConnected;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* @description Manually connect from the attached provider
|
|
100
|
+
*/
|
|
101
|
+
connect() {
|
|
102
|
+
return this.provider.connect();
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* @description Manually disconnect from the attached provider
|
|
106
|
+
*/
|
|
107
|
+
async disconnect() {
|
|
108
|
+
return this.provider.disconnect();
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* @description Returns the underlying core stats, including those from teh provider
|
|
112
|
+
*/
|
|
113
|
+
get stats() {
|
|
114
|
+
const stats = this.provider.stats;
|
|
115
|
+
return stats
|
|
116
|
+
? {
|
|
117
|
+
...stats,
|
|
118
|
+
core: {
|
|
119
|
+
cacheHits: this.#storageCacheHits,
|
|
120
|
+
cacheSize: this.#storageCache.length
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
: undefined;
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* @description Sets a registry swap (typically from Api)
|
|
127
|
+
*/
|
|
128
|
+
setRegistrySwap(registrySwap) {
|
|
129
|
+
this.#getBlockRegistry = (0, util_2.memoize)(registrySwap, {
|
|
130
|
+
getInstanceId: () => this.#instanceId
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* @description Sets a function to resolve block hash from block number
|
|
135
|
+
*/
|
|
136
|
+
setResolveBlockHash(resolveBlockHash) {
|
|
137
|
+
this.#getBlockHash = (0, util_2.memoize)(resolveBlockHash, {
|
|
138
|
+
getInstanceId: () => this.#instanceId
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
addUserInterfaces(userRpc) {
|
|
142
|
+
// add any extra user-defined sections
|
|
143
|
+
this.sections.push(...Object.keys(userRpc).filter((k) => !this.sections.includes(k)));
|
|
144
|
+
for (let s = 0, scount = this.sections.length; s < scount; s++) {
|
|
145
|
+
const section = this.sections[s];
|
|
146
|
+
const defs = (0, util_2.objectSpread)({}, types_1.rpcDefinitions[section], userRpc[section]);
|
|
147
|
+
const methods = Object.keys(defs);
|
|
148
|
+
for (let m = 0, mcount = methods.length; m < mcount; m++) {
|
|
149
|
+
const method = methods[m];
|
|
150
|
+
const def = defs[method];
|
|
151
|
+
const jsonrpc = def.endpoint || `${section}_${method}`;
|
|
152
|
+
if (!this.mapping.has(jsonrpc)) {
|
|
153
|
+
const isSubscription = !!def.pubsub;
|
|
154
|
+
if (!this[section]) {
|
|
155
|
+
this[section] = {};
|
|
156
|
+
}
|
|
157
|
+
this.mapping.set(jsonrpc, (0, util_2.objectSpread)({}, def, { isSubscription, jsonrpc, method, section }));
|
|
158
|
+
(0, util_2.lazyMethod)(this[section], method, () => isSubscription
|
|
159
|
+
? this._createMethodSubscribe(section, method, def)
|
|
160
|
+
: this._createMethodSend(section, method, def));
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
_memomize(creator, def) {
|
|
166
|
+
const memoOpts = { getInstanceId: () => this.#instanceId };
|
|
167
|
+
const memoized = (0, util_2.memoize)(creator(true), memoOpts);
|
|
168
|
+
memoized.raw = (0, util_2.memoize)(creator(false), memoOpts);
|
|
169
|
+
memoized.meta = def;
|
|
170
|
+
return memoized;
|
|
171
|
+
}
|
|
172
|
+
_formatResult(isScale, registry, blockHash, method, def, params, result) {
|
|
173
|
+
return isScale
|
|
174
|
+
? this._formatOutput(registry, blockHash, method, def, params, result)
|
|
175
|
+
: result;
|
|
176
|
+
}
|
|
177
|
+
_createMethodSend(section, method, def) {
|
|
178
|
+
const rpcName = def.endpoint || `${section}_${method}`;
|
|
179
|
+
const hashIndex = def.params.findIndex(({ isHistoric }) => isHistoric);
|
|
180
|
+
let memoized = null;
|
|
181
|
+
// execute the RPC call, doing a registry swap for historic as applicable
|
|
182
|
+
const callWithRegistry = async (isScale, values) => {
|
|
183
|
+
const blockId = hashIndex === -1
|
|
184
|
+
? null
|
|
185
|
+
: values[hashIndex];
|
|
186
|
+
const blockHash = blockId && def.params[hashIndex].type === 'BlockNumber'
|
|
187
|
+
? await this.#getBlockHash?.(blockId)
|
|
188
|
+
: blockId;
|
|
189
|
+
const { registry } = isScale && blockHash && this.#getBlockRegistry
|
|
190
|
+
? await this.#getBlockRegistry((0, util_2.u8aToU8a)(blockHash))
|
|
191
|
+
: { registry: this.#registryDefault };
|
|
192
|
+
const params = this._formatParams(registry, null, def, values);
|
|
193
|
+
// only cache .at(<blockHash>) queries, e.g. where valid blockHash was supplied
|
|
194
|
+
const result = await this.provider.send(rpcName, params.map((p) => p.toJSON()), !!blockHash);
|
|
195
|
+
return this._formatResult(isScale, registry, blockHash, method, def, params, result);
|
|
196
|
+
};
|
|
197
|
+
const creator = (isScale) => (...values) => {
|
|
198
|
+
const isDelayed = isScale && hashIndex !== -1 && !!values[hashIndex];
|
|
199
|
+
return new rxjs_1.Observable((observer) => {
|
|
200
|
+
callWithRegistry(isScale, values)
|
|
201
|
+
.then((value) => {
|
|
202
|
+
observer.next(value);
|
|
203
|
+
observer.complete();
|
|
204
|
+
})
|
|
205
|
+
.catch((error) => {
|
|
206
|
+
logErrorMessage(method, def, error);
|
|
207
|
+
observer.error(error);
|
|
208
|
+
observer.complete();
|
|
209
|
+
});
|
|
210
|
+
return () => {
|
|
211
|
+
// delete old results from cache
|
|
212
|
+
if (isScale) {
|
|
213
|
+
memoized?.unmemoize(...values);
|
|
214
|
+
}
|
|
215
|
+
else {
|
|
216
|
+
memoized?.raw.unmemoize(...values);
|
|
217
|
+
}
|
|
218
|
+
};
|
|
219
|
+
}).pipe(
|
|
220
|
+
// eslint-disable-next-line deprecation/deprecation
|
|
221
|
+
(0, rxjs_1.publishReplay)(1), // create a Replay(1)
|
|
222
|
+
isDelayed
|
|
223
|
+
? (0, index_js_1.refCountDelay)() // Unsubscribe after delay
|
|
224
|
+
// eslint-disable-next-line deprecation/deprecation
|
|
225
|
+
: (0, rxjs_1.refCount)());
|
|
226
|
+
};
|
|
227
|
+
memoized = this._memomize(creator, def);
|
|
228
|
+
return memoized;
|
|
229
|
+
}
|
|
230
|
+
// create a subscriptor, it subscribes once and resolves with the id as subscribe
|
|
231
|
+
_createSubscriber({ paramsJson, subName, subType, update }, errorHandler) {
|
|
232
|
+
return new Promise((resolve, reject) => {
|
|
233
|
+
this.provider
|
|
234
|
+
.subscribe(subType, subName, paramsJson, update)
|
|
235
|
+
.then(resolve)
|
|
236
|
+
.catch((error) => {
|
|
237
|
+
errorHandler(error);
|
|
238
|
+
reject(error);
|
|
239
|
+
});
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
_createMethodSubscribe(section, method, def) {
|
|
243
|
+
const [updateType, subMethod, unsubMethod] = def.pubsub;
|
|
244
|
+
const subName = `${section}_${subMethod}`;
|
|
245
|
+
const unsubName = `${section}_${unsubMethod}`;
|
|
246
|
+
const subType = `${section}_${updateType}`;
|
|
247
|
+
let memoized = null;
|
|
248
|
+
const creator = (isScale) => (...values) => {
|
|
249
|
+
return new rxjs_1.Observable((observer) => {
|
|
250
|
+
// Have at least an empty promise, as used in the unsubscribe
|
|
251
|
+
let subscriptionPromise = Promise.resolve(null);
|
|
252
|
+
const registry = this.#registryDefault;
|
|
253
|
+
const errorHandler = (error) => {
|
|
254
|
+
logErrorMessage(method, def, error);
|
|
255
|
+
observer.error(error);
|
|
256
|
+
};
|
|
257
|
+
try {
|
|
258
|
+
const params = this._formatParams(registry, null, def, values);
|
|
259
|
+
const update = (error, result) => {
|
|
260
|
+
if (error) {
|
|
261
|
+
logErrorMessage(method, def, error);
|
|
262
|
+
return;
|
|
263
|
+
}
|
|
264
|
+
try {
|
|
265
|
+
observer.next(this._formatResult(isScale, registry, null, method, def, params, result));
|
|
266
|
+
}
|
|
267
|
+
catch (error) {
|
|
268
|
+
observer.error(error);
|
|
269
|
+
}
|
|
270
|
+
};
|
|
271
|
+
subscriptionPromise = this._createSubscriber({ paramsJson: params.map((p) => p.toJSON()), subName, subType, update }, errorHandler);
|
|
272
|
+
}
|
|
273
|
+
catch (error) {
|
|
274
|
+
errorHandler(error);
|
|
275
|
+
}
|
|
276
|
+
// Teardown logic
|
|
277
|
+
return () => {
|
|
278
|
+
// Delete from cache, so old results don't hang around
|
|
279
|
+
if (isScale) {
|
|
280
|
+
memoized?.unmemoize(...values);
|
|
281
|
+
}
|
|
282
|
+
else {
|
|
283
|
+
memoized?.raw.unmemoize(...values);
|
|
284
|
+
}
|
|
285
|
+
// Unsubscribe from provider
|
|
286
|
+
subscriptionPromise
|
|
287
|
+
.then((subscriptionId) => (0, util_2.isNull)(subscriptionId)
|
|
288
|
+
? Promise.resolve(false)
|
|
289
|
+
: this.provider.unsubscribe(subType, unsubName, subscriptionId))
|
|
290
|
+
.catch((error) => logErrorMessage(method, def, error));
|
|
291
|
+
};
|
|
292
|
+
}).pipe((0, index_js_1.drr)());
|
|
293
|
+
};
|
|
294
|
+
memoized = this._memomize(creator, def);
|
|
295
|
+
return memoized;
|
|
296
|
+
}
|
|
297
|
+
_formatParams(registry, blockHash, def, inputs) {
|
|
298
|
+
const count = inputs.length;
|
|
299
|
+
const reqCount = def.params.filter(({ isOptional }) => !isOptional).length;
|
|
300
|
+
if (count < reqCount || count > def.params.length) {
|
|
301
|
+
throw new Error(`Expected ${def.params.length} parameters${reqCount === def.params.length ? '' : ` (${def.params.length - reqCount} optional)`}, ${count} found instead`);
|
|
302
|
+
}
|
|
303
|
+
const params = new Array(count);
|
|
304
|
+
for (let i = 0; i < count; i++) {
|
|
305
|
+
params[i] = registry.createTypeUnsafe(def.params[i].type, [inputs[i]], { blockHash });
|
|
306
|
+
}
|
|
307
|
+
return params;
|
|
308
|
+
}
|
|
309
|
+
_formatOutput(registry, blockHash, method, rpc, params, result) {
|
|
310
|
+
if (rpc.type === 'StorageData') {
|
|
311
|
+
const key = params[0];
|
|
312
|
+
return this._formatStorageData(registry, blockHash, key, result);
|
|
313
|
+
}
|
|
314
|
+
else if (rpc.type === 'StorageChangeSet') {
|
|
315
|
+
const keys = params[0];
|
|
316
|
+
return keys
|
|
317
|
+
? this._formatStorageSet(registry, result.block, keys, result.changes)
|
|
318
|
+
: registry.createType('StorageChangeSet', result);
|
|
319
|
+
}
|
|
320
|
+
else if (rpc.type === 'Vec<StorageChangeSet>') {
|
|
321
|
+
const jsonSet = result;
|
|
322
|
+
const count = jsonSet.length;
|
|
323
|
+
const mapped = new Array(count);
|
|
324
|
+
for (let i = 0; i < count; i++) {
|
|
325
|
+
const { block, changes } = jsonSet[i];
|
|
326
|
+
mapped[i] = [
|
|
327
|
+
registry.createType('BlockHash', block),
|
|
328
|
+
this._formatStorageSet(registry, block, params[0], changes)
|
|
329
|
+
];
|
|
330
|
+
}
|
|
331
|
+
// we only query at a specific block, not a range - flatten
|
|
332
|
+
return method === 'queryStorageAt'
|
|
333
|
+
? mapped[0][1]
|
|
334
|
+
: mapped;
|
|
335
|
+
}
|
|
336
|
+
return registry.createTypeUnsafe(rpc.type, [result], { blockHash });
|
|
337
|
+
}
|
|
338
|
+
_formatStorageData(registry, blockHash, key, value) {
|
|
339
|
+
const isEmpty = (0, util_2.isNull)(value);
|
|
340
|
+
// we convert to Uint8Array since it maps to the raw encoding, all
|
|
341
|
+
// data will be correctly encoded (incl. numbers, excl. :code)
|
|
342
|
+
const input = isEmpty
|
|
343
|
+
? null
|
|
344
|
+
: isTreatAsHex(key)
|
|
345
|
+
? value
|
|
346
|
+
: (0, util_2.u8aToU8a)(value);
|
|
347
|
+
return this._newType(registry, blockHash, key, input, isEmpty);
|
|
348
|
+
}
|
|
349
|
+
_formatStorageSet(registry, blockHash, keys, changes) {
|
|
350
|
+
// For StorageChangeSet, the changes has the [key, value] mappings
|
|
351
|
+
const count = keys.length;
|
|
352
|
+
const withCache = count !== 1;
|
|
353
|
+
const values = new Array(count);
|
|
354
|
+
// multiple return values (via state.storage subscription), decode the
|
|
355
|
+
// values one at a time, all based on the supplied query types
|
|
356
|
+
for (let i = 0; i < count; i++) {
|
|
357
|
+
values[i] = this._formatStorageSetEntry(registry, blockHash, keys[i], changes, withCache, i);
|
|
358
|
+
}
|
|
359
|
+
return values;
|
|
360
|
+
}
|
|
361
|
+
_formatStorageSetEntry(registry, blockHash, key, changes, withCache, entryIndex) {
|
|
362
|
+
const hexKey = key.toHex();
|
|
363
|
+
const found = changes.find(([key]) => key === hexKey);
|
|
364
|
+
const isNotFound = (0, util_2.isUndefined)(found);
|
|
365
|
+
// if we don't find the value, this is our fallback
|
|
366
|
+
// - in the case of an array of values, fill the hole from the cache
|
|
367
|
+
// - if a single result value, don't fill - it is not an update hole
|
|
368
|
+
// - fallback to an empty option in all cases
|
|
369
|
+
if (isNotFound && withCache) {
|
|
370
|
+
const cached = this.#storageCache.get(hexKey);
|
|
371
|
+
if (cached) {
|
|
372
|
+
this.#storageCacheHits++;
|
|
373
|
+
return cached;
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
const value = isNotFound
|
|
377
|
+
? null
|
|
378
|
+
: found[1];
|
|
379
|
+
const isEmpty = (0, util_2.isNull)(value);
|
|
380
|
+
const input = isEmpty || isTreatAsHex(key)
|
|
381
|
+
? value
|
|
382
|
+
: (0, util_2.u8aToU8a)(value);
|
|
383
|
+
const codec = this._newType(registry, blockHash, key, input, isEmpty, entryIndex);
|
|
384
|
+
this._setToCache(hexKey, codec);
|
|
385
|
+
return codec;
|
|
386
|
+
}
|
|
387
|
+
_setToCache(key, value) {
|
|
388
|
+
this.#storageCache.set(key, value);
|
|
389
|
+
}
|
|
390
|
+
_newType(registry, blockHash, key, input, isEmpty, entryIndex = -1) {
|
|
391
|
+
// single return value (via state.getStorage), decode the value based on the
|
|
392
|
+
// outputType that we have specified. Fallback to Raw on nothing
|
|
393
|
+
const type = key.meta ? registry.createLookupType((0, util_1.unwrapStorageSi)(key.meta.type)) : (key.outputType || 'Raw');
|
|
394
|
+
const meta = key.meta || EMPTY_META;
|
|
395
|
+
const entryNum = entryIndex === -1
|
|
396
|
+
? ''
|
|
397
|
+
: ` entry ${entryIndex}:`;
|
|
398
|
+
try {
|
|
399
|
+
return registry.createTypeUnsafe(type, [
|
|
400
|
+
isEmpty
|
|
401
|
+
? meta.fallback
|
|
402
|
+
// For old-style Linkage, we add an empty linkage at the end
|
|
403
|
+
? type.includes('Linkage<')
|
|
404
|
+
? (0, util_2.u8aConcat)((0, util_2.hexToU8a)(meta.fallback.toHex()), new Uint8Array(2))
|
|
405
|
+
: (0, util_2.hexToU8a)(meta.fallback.toHex())
|
|
406
|
+
: undefined
|
|
407
|
+
: meta.modifier.isOptional
|
|
408
|
+
? registry.createTypeUnsafe(type, [input], { blockHash, isPedantic: this.#isPedantic })
|
|
409
|
+
: input
|
|
410
|
+
], { blockHash, isFallback: isEmpty && !!meta.fallback, isOptional: meta.modifier.isOptional, isPedantic: this.#isPedantic && !meta.modifier.isOptional });
|
|
411
|
+
}
|
|
412
|
+
catch (error) {
|
|
413
|
+
throw new Error(`Unable to decode storage ${key.section || 'unknown'}.${key.method || 'unknown'}:${entryNum}: ${error.message}`);
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
exports.RpcCore = RpcCore;
|
package/cjs/index.js
ADDED
package/cjs/package.json
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const packageInfo_1 = require("@pezkuwi/rpc-provider/cjs/packageInfo");
|
|
4
|
+
const packageInfo_2 = require("@pezkuwi/types/cjs/packageInfo");
|
|
5
|
+
const util_1 = require("@pezkuwi/util");
|
|
6
|
+
const packageInfo_js_1 = require("./packageInfo.js");
|
|
7
|
+
(0, util_1.detectPackage)(packageInfo_js_1.packageInfo, null, [packageInfo_1.packageInfo, packageInfo_2.packageInfo]);
|
package/cjs/util/drr.js
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.drr = drr;
|
|
4
|
+
const rxjs_1 = require("rxjs");
|
|
5
|
+
const util_1 = require("@pezkuwi/util");
|
|
6
|
+
const refCountDelay_js_1 = require("./refCountDelay.js");
|
|
7
|
+
function CMP(a, b) {
|
|
8
|
+
return (0, util_1.stringify)({ t: a }) === (0, util_1.stringify)({ t: b });
|
|
9
|
+
}
|
|
10
|
+
function ERR(error) {
|
|
11
|
+
throw error;
|
|
12
|
+
}
|
|
13
|
+
function NOOP() {
|
|
14
|
+
// empty
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Shorthand for distinctUntilChanged(), publishReplay(1) and refCount().
|
|
18
|
+
*
|
|
19
|
+
* @ignore
|
|
20
|
+
* @internal
|
|
21
|
+
*/
|
|
22
|
+
function drr({ delay, skipChange = false, skipTimeout = false } = {}) {
|
|
23
|
+
return (source$) => source$.pipe((0, rxjs_1.catchError)(ERR), skipChange
|
|
24
|
+
? (0, rxjs_1.tap)(NOOP)
|
|
25
|
+
: (0, rxjs_1.distinctUntilChanged)(CMP),
|
|
26
|
+
// eslint-disable-next-line deprecation/deprecation
|
|
27
|
+
(0, rxjs_1.publishReplay)(1), skipTimeout
|
|
28
|
+
// eslint-disable-next-line deprecation/deprecation
|
|
29
|
+
? (0, rxjs_1.refCount)()
|
|
30
|
+
: (0, refCountDelay_js_1.refCountDelay)(delay));
|
|
31
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const tslib_1 = require("tslib");
|
|
4
|
+
tslib_1.__exportStar(require("./drr.js"), exports);
|
|
5
|
+
tslib_1.__exportStar(require("./memo.js"), exports);
|
|
6
|
+
tslib_1.__exportStar(require("./refCountDelay.js"), exports);
|
package/cjs/util/memo.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.memo = memo;
|
|
4
|
+
const rxjs_1 = require("rxjs");
|
|
5
|
+
const util_1 = require("@pezkuwi/util");
|
|
6
|
+
const drr_js_1 = require("./drr.js");
|
|
7
|
+
/** @internal */
|
|
8
|
+
function memo(instanceId, inner) {
|
|
9
|
+
const options = { getInstanceId: () => instanceId };
|
|
10
|
+
const cached = (0, util_1.memoize)((...params) => new rxjs_1.Observable((observer) => {
|
|
11
|
+
const subscription = inner(...params).subscribe(observer);
|
|
12
|
+
return () => {
|
|
13
|
+
cached.unmemoize(...params);
|
|
14
|
+
subscription.unsubscribe();
|
|
15
|
+
};
|
|
16
|
+
}).pipe((0, drr_js_1.drr)()), options);
|
|
17
|
+
return cached;
|
|
18
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.refCountDelay = refCountDelay;
|
|
4
|
+
const rxjs_1 = require("rxjs");
|
|
5
|
+
/** @internal */
|
|
6
|
+
function refCountDelay(delay = 1750) {
|
|
7
|
+
return (source) => {
|
|
8
|
+
// state: 0 = disconnected, 1 = disconnecting, 2 = connecting, 3 = connected
|
|
9
|
+
let [state, refCount, connection, scheduler] = [0, 0, rxjs_1.Subscription.EMPTY, rxjs_1.Subscription.EMPTY];
|
|
10
|
+
return new rxjs_1.Observable((ob) => {
|
|
11
|
+
source.subscribe(ob);
|
|
12
|
+
if (refCount++ === 0) {
|
|
13
|
+
if (state === 1) {
|
|
14
|
+
scheduler.unsubscribe();
|
|
15
|
+
}
|
|
16
|
+
else {
|
|
17
|
+
// eslint-disable-next-line deprecation/deprecation
|
|
18
|
+
connection = source.connect();
|
|
19
|
+
}
|
|
20
|
+
state = 3;
|
|
21
|
+
}
|
|
22
|
+
return () => {
|
|
23
|
+
if (--refCount === 0) {
|
|
24
|
+
if (state === 2) {
|
|
25
|
+
state = 0;
|
|
26
|
+
scheduler.unsubscribe();
|
|
27
|
+
}
|
|
28
|
+
else {
|
|
29
|
+
// state === 3
|
|
30
|
+
state = 1;
|
|
31
|
+
scheduler = rxjs_1.asapScheduler.schedule(() => {
|
|
32
|
+
state = 0;
|
|
33
|
+
connection.unsubscribe();
|
|
34
|
+
}, delay);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
});
|
|
39
|
+
};
|
|
40
|
+
}
|
package/index.d.ts
ADDED
package/index.js
ADDED