Internal adjustments (part 6) (#4138)
* Internal adjustments (part 6) * Additional
This commit is contained in:
@@ -322,7 +322,11 @@ export abstract class Decorate<ApiType extends ApiTypes> extends Events {
|
||||
protected _filterRpcMethods (exposed: string[]): void {
|
||||
const hasResults = exposed.length !== 0;
|
||||
const allKnown = [...this._rpcCore.mapping.entries()];
|
||||
const allKeys = allKnown.reduce((allKeys: string[], [, { alias, endpoint, method, pubsub, section }]): string[] => {
|
||||
const allKeys: string[] = [];
|
||||
|
||||
for (let i = 0; i < allKnown.length; i++) {
|
||||
const [, { alias, endpoint, method, pubsub, section }] = allKnown[i];
|
||||
|
||||
allKeys.push(`${section}_${method}`);
|
||||
|
||||
if (pubsub) {
|
||||
@@ -337,11 +341,10 @@ export abstract class Decorate<ApiType extends ApiTypes> extends Events {
|
||||
if (endpoint) {
|
||||
allKeys.push(endpoint);
|
||||
}
|
||||
}
|
||||
|
||||
return allKeys;
|
||||
}, []);
|
||||
const unknown = exposed.filter((k) => !allKeys.includes(k));
|
||||
const deletion = allKnown.filter(([k]) => hasResults && !exposed.includes(k) && k !== 'rpc_methods');
|
||||
const filterKey = (k: string) => !allKeys.includes(k);
|
||||
const unknown = exposed.filter(filterKey);
|
||||
|
||||
if (unknown.length) {
|
||||
l.warn(`RPC methods not decorated: ${unknown.join(', ')}`);
|
||||
@@ -349,19 +352,26 @@ export abstract class Decorate<ApiType extends ApiTypes> extends Events {
|
||||
|
||||
// loop through all entries we have (populated in decorate) and filter as required
|
||||
// only remove when we have results and method missing, or with no results if optional
|
||||
deletion.forEach(([, { method, section }]): void => {
|
||||
delete (this._rpc as Record<string, Record<string, unknown>>)[section][method];
|
||||
delete (this._rx.rpc as Record<string, Record<string, unknown>>)[section][method];
|
||||
});
|
||||
for (let i = 0; i < allKnown.length; i++) {
|
||||
const [k, { method, section }] = allKnown[i];
|
||||
|
||||
if (hasResults && !exposed.includes(k) && k !== 'rpc_methods') {
|
||||
delete (this._rpc as Record<string, Record<string, unknown>>)[section][method];
|
||||
delete (this._rx.rpc as Record<string, Record<string, unknown>>)[section][method];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected _decorateRpc<ApiType extends ApiTypes> (rpc: RpcCore & RpcInterface, decorateMethod: DecorateMethod<ApiType>, input: Partial<DecoratedRpc<ApiType, RpcInterface>> = {}): DecoratedRpc<ApiType, RpcInterface> {
|
||||
return rpc.sections.reduce((out, _sectionName): DecoratedRpc<ApiType, RpcInterface> => {
|
||||
const sectionName = _sectionName as keyof DecoratedRpc<ApiType, RpcInterface>;
|
||||
const out = input as DecoratedRpc<ApiType, RpcInterface>;
|
||||
|
||||
for (let s = 0; s < rpc.sections.length; s++) {
|
||||
const sectionName = rpc.sections[s] as keyof DecoratedRpc<ApiType, RpcInterface>;
|
||||
|
||||
if (!(out as Record<string, unknown>)[sectionName]) {
|
||||
// out and section here are horrors to get right from a typing perspective :(
|
||||
(out as Record<string, unknown>)[sectionName] = Object.entries(rpc[sectionName]).reduce((section, [methodName, method]): DecoratedRpcSection<ApiType, RpcInterface[typeof sectionName]> => {
|
||||
const section = {} as DecoratedRpcSection<ApiType, RpcInterface[typeof sectionName]>;
|
||||
|
||||
for (const [methodName, method] of Object.entries(rpc[sectionName])) {
|
||||
// skip subscriptions where we have a non-subscribe interface
|
||||
if (this.hasSubscriptions || !(methodName.startsWith('subscribe') || methodName.startsWith('unsubscribe'))) {
|
||||
(section as Record<string, unknown>)[methodName] = decorateMethod(method, { methodName }) as unknown;
|
||||
@@ -370,13 +380,13 @@ export abstract class Decorate<ApiType extends ApiTypes> extends Events {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
||||
(section as Record<string, { meta: unknown }>)[methodName].meta = method.meta;
|
||||
}
|
||||
}
|
||||
|
||||
return section;
|
||||
}, {} as DecoratedRpcSection<ApiType, RpcInterface[typeof sectionName]>);
|
||||
(out as Record<string, unknown>)[sectionName] = section;
|
||||
}
|
||||
}
|
||||
|
||||
return out;
|
||||
}, input as DecoratedRpc<ApiType, RpcInterface>);
|
||||
return out;
|
||||
}
|
||||
|
||||
// only be called if supportMulti is true
|
||||
@@ -417,17 +427,19 @@ export abstract class Decorate<ApiType extends ApiTypes> extends Events {
|
||||
}
|
||||
|
||||
protected _decorateExtrinsics<ApiType extends ApiTypes> ({ tx }: DecoratedMeta, decorateMethod: DecorateMethod<ApiType>): SubmittableExtrinsics<ApiType> {
|
||||
const creator = createSubmittable(this._type, this._rx, decorateMethod);
|
||||
const creator = createSubmittable(this._type, this._rx, decorateMethod) as SubmittableExtrinsics<ApiType>;
|
||||
|
||||
return Object.entries(tx).reduce((out, [name, section]): SubmittableExtrinsics<ApiType> => {
|
||||
out[name] = Object.entries(section).reduce((out, [name, method]): SubmittableModuleExtrinsics<ApiType> => {
|
||||
out[name] = this._decorateExtrinsicEntry(method, creator);
|
||||
for (const [name, section] of Object.entries(tx)) {
|
||||
const methods: SubmittableModuleExtrinsics<ApiType> = {};
|
||||
|
||||
return out;
|
||||
}, {} as SubmittableModuleExtrinsics<ApiType>);
|
||||
for (const [name, method] of Object.entries(section)) {
|
||||
methods[name] = this._decorateExtrinsicEntry(method, creator);
|
||||
}
|
||||
|
||||
return out;
|
||||
}, creator as SubmittableExtrinsics<ApiType>);
|
||||
creator[name] = methods;
|
||||
}
|
||||
|
||||
return creator;
|
||||
}
|
||||
|
||||
private _decorateExtrinsicEntry<ApiType extends ApiTypes> (method: CallFunction, creator: (value: Call | Uint8Array | string) => SubmittableExtrinsic<ApiType>): SubmittableExtrinsicFunction<ApiType> {
|
||||
@@ -443,27 +455,35 @@ export abstract class Decorate<ApiType extends ApiTypes> extends Events {
|
||||
}
|
||||
|
||||
protected _decorateStorage<ApiType extends ApiTypes> ({ query }: DecoratedMeta, decorateMethod: DecorateMethod<ApiType>): QueryableStorage<ApiType> {
|
||||
return Object.entries(query).reduce((out, [name, section]): QueryableStorage<ApiType> => {
|
||||
out[name] = Object.entries(section).reduce((out, [name, method]): QueryableModuleStorage<ApiType> => {
|
||||
out[name] = this._decorateStorageEntry(method, decorateMethod);
|
||||
const result = {} as QueryableStorage<ApiType>;
|
||||
|
||||
return out;
|
||||
}, {} as QueryableModuleStorage<ApiType>);
|
||||
for (const [name, section] of Object.entries(query)) {
|
||||
const methods: QueryableModuleStorage<ApiType> = {};
|
||||
|
||||
return out;
|
||||
}, {} as QueryableStorage<ApiType>);
|
||||
for (const [name, method] of Object.entries(section)) {
|
||||
methods[name] = this._decorateStorageEntry(method, decorateMethod);
|
||||
}
|
||||
|
||||
result[name] = methods;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
protected _decorateStorageAt<ApiType extends ApiTypes> ({ query, registry }: DecoratedMeta, decorateMethod: DecorateMethod<ApiType>, blockHash: Uint8Array): QueryableStorageAt<ApiType> {
|
||||
return Object.entries(query).reduce((out, [name, section]): QueryableStorageAt<ApiType> => {
|
||||
out[name] = Object.entries(section).reduce((out, [name, method]): QueryableModuleStorageAt<ApiType> => {
|
||||
out[name] = this._decorateStorageEntryAt(registry, method, decorateMethod, blockHash);
|
||||
const result = {} as QueryableStorageAt<ApiType>;
|
||||
|
||||
return out;
|
||||
}, {} as QueryableModuleStorageAt<ApiType>);
|
||||
for (const [name, section] of Object.entries(query)) {
|
||||
const methods: QueryableModuleStorageAt<ApiType> = {};
|
||||
|
||||
return out;
|
||||
}, {} as QueryableStorageAt<ApiType>);
|
||||
for (const [name, method] of Object.entries(section)) {
|
||||
methods[name] = this._decorateStorageEntryAt(registry, method, decorateMethod, blockHash);
|
||||
}
|
||||
|
||||
result[name] = methods;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private _decorateStorageEntry<ApiType extends ApiTypes> (creator: StorageEntry, decorateMethod: DecorateMethod<ApiType>): QueryableStorageEntry<ApiType> {
|
||||
@@ -652,10 +672,11 @@ export abstract class Decorate<ApiType extends ApiTypes> extends Events {
|
||||
const queryCall = at
|
||||
? (startKey: string) => this._rpcCore.state.getKeysPaged(headKey, PAGE_SIZE_K, startKey, at)
|
||||
: (startKey: string) => this._rpcCore.state.getKeysPaged(headKey, PAGE_SIZE_K, startKey);
|
||||
const setMeta = (key: StorageKey) => key.setMeta(meta, section, method);
|
||||
|
||||
return startSubject.pipe(
|
||||
switchMap(queryCall),
|
||||
map((keys) => keys.map((key) => key.setMeta(meta, section, method))),
|
||||
map((keys) => keys.map(setMeta)),
|
||||
tap((keys): void => {
|
||||
setTimeout((): void => {
|
||||
keys.length === PAGE_SIZE_K
|
||||
@@ -672,9 +693,10 @@ export abstract class Decorate<ApiType extends ApiTypes> extends Events {
|
||||
assert(iterKey && meta.type.isMap, 'keys can only be retrieved on maps');
|
||||
|
||||
const headKey = iterKey(...opts.args).toHex();
|
||||
const setMeta = (key: StorageKey) => key.setMeta(meta, section, method);
|
||||
|
||||
return this._rpcCore.state.getKeysPaged(headKey, opts.pageSize, opts.startKey || headKey).pipe(
|
||||
map((keys) => keys.map((key) => key.setMeta(meta, section, method)))
|
||||
map((keys) => keys.map(setMeta))
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -23,6 +23,10 @@ const KEEPALIVE_INTERVAL = 10000;
|
||||
|
||||
const l = logger('api/init');
|
||||
|
||||
function textToString (t: Text): string {
|
||||
return t.toString();
|
||||
}
|
||||
|
||||
export abstract class Init<ApiType extends ApiTypes> extends Decorate<ApiType> {
|
||||
#healthTimer: NodeJS.Timeout | null = null;
|
||||
|
||||
@@ -242,17 +246,21 @@ export abstract class Init<ApiType extends ApiTypes> extends Decorate<ApiType> {
|
||||
this._runtimeChain = source.runtimeChain;
|
||||
this._runtimeVersion = source.runtimeVersion;
|
||||
|
||||
const methods: string[] = [];
|
||||
|
||||
// manually build a list of all available methods in this RPC, we are
|
||||
// going to filter on it to align the cloned RPC without making a call
|
||||
Object.keys(source.rpc).forEach((section): void => {
|
||||
Object.keys((source.rpc as Record<string, Record<string, unknown>>)[section]).forEach((method): void => {
|
||||
methods.push(`${section}_${method}`);
|
||||
});
|
||||
});
|
||||
const sections = Object.keys(source.rpc);
|
||||
const rpcs: string[] = [];
|
||||
|
||||
this._filterRpc(methods, getSpecRpc(this.registry, source.runtimeChain, source.runtimeVersion.specName));
|
||||
for (let s = 0; s < sections.length; s++) {
|
||||
const section = sections[s];
|
||||
const methods = Object.keys((source.rpc as Record<string, Record<string, unknown>>)[section]);
|
||||
|
||||
for (let m = 0; m < methods.length; m++) {
|
||||
rpcs.push(`${section}_${methods[m]}`);
|
||||
}
|
||||
}
|
||||
|
||||
this._filterRpc(rpcs, getSpecRpc(this.registry, source.runtimeChain, source.runtimeVersion.specName));
|
||||
|
||||
return [source.genesisHash, source.runtimeMetadata];
|
||||
}
|
||||
@@ -335,7 +343,7 @@ export abstract class Init<ApiType extends ApiTypes> extends Decorate<ApiType> {
|
||||
|
||||
// initializes the registry & RPC
|
||||
this._initRegistry(this.registry, chain, runtimeVersion, metadata, chainProps);
|
||||
this._filterRpc(rpcMethods.methods.map((t) => t.toString()), getSpecRpc(this.registry, chain, runtimeVersion.specName));
|
||||
this._filterRpc(rpcMethods.methods.map(textToString), getSpecRpc(this.registry, chain, runtimeVersion.specName));
|
||||
this._subscribeUpdates();
|
||||
|
||||
// setup the initial registry, when we have none
|
||||
|
||||
@@ -26,16 +26,17 @@ function warn (prefix: string, type: 'calls' | 'modules', [added, removed]: Stri
|
||||
}
|
||||
}
|
||||
|
||||
function extractKeys (src: Record<string, Record<string, any>>, dst: Record<string, Record<string, any>>): StringsStrings {
|
||||
return [Object.keys(src), Object.keys(dst)];
|
||||
function findSectionExcludes (a: string[], b: string[]): string[] {
|
||||
return a.filter((s) => !b.includes(s));
|
||||
}
|
||||
|
||||
function findSectionExcludes (a: string[], b: string[]): string[] {
|
||||
return a.filter((section) => !b.includes(section));
|
||||
function findSectionIncludes (a: string[], b: string[]): string[] {
|
||||
return a.filter((s) => b.includes(s));
|
||||
}
|
||||
|
||||
function extractSections (src: Record<string, Record<string, any>>, dst: Record<string, Record<string, any>>): StringsStrings {
|
||||
const [srcSections, dstSections] = extractKeys(src, dst);
|
||||
const srcSections = Object.keys(src);
|
||||
const dstSections = Object.keys(dst);
|
||||
|
||||
return [
|
||||
findSectionExcludes(srcSections, dstSections),
|
||||
@@ -45,20 +46,22 @@ function extractSections (src: Record<string, Record<string, any>>, dst: Record<
|
||||
|
||||
function findMethodExcludes (src: Record<string, Record<string, any>>, dst: Record<string, Record<string, any>>): string[] {
|
||||
const srcSections = Object.keys(src);
|
||||
const dstSections = Object.keys(dst);
|
||||
const dstSections = findSectionIncludes(Object.keys(dst), srcSections);
|
||||
const excludes: string[] = [];
|
||||
|
||||
return dstSections
|
||||
.filter((section) => srcSections.includes(section))
|
||||
.reduce((rmMethods: string[], section): string[] => {
|
||||
const srcMethods = Object.keys(src[section]);
|
||||
for (let s = 0; s < dstSections.length; s++) {
|
||||
const section = dstSections[s];
|
||||
const srcMethods = Object.keys(src[section]);
|
||||
const dstMethods = Object.keys(dst[section]);
|
||||
|
||||
return rmMethods.concat(
|
||||
...Object
|
||||
.keys(dst[section])
|
||||
.filter((method) => !srcMethods.includes(method))
|
||||
.map((method) => `${section}.${method}`)
|
||||
);
|
||||
}, []);
|
||||
excludes.push(
|
||||
...dstMethods
|
||||
.filter((m) => !srcMethods.includes(m))
|
||||
.map((m) => `${section}.${m}`)
|
||||
);
|
||||
}
|
||||
|
||||
return excludes;
|
||||
}
|
||||
|
||||
function extractMethods (src: Record<string, Record<string, any>>, dst: Record<string, Record<string, any>>): StringsStrings {
|
||||
@@ -75,9 +78,11 @@ function extractMethods (src: Record<string, Record<string, any>>, dst: Record<s
|
||||
*/
|
||||
export function augmentObject (prefix: string | null, src: Record<string, Record<string, unknown>>, dst: Record<string, Record<string, unknown>>, fromEmpty = false): Record<string, Record<string, any>> {
|
||||
if (fromEmpty) {
|
||||
Object.keys(dst).forEach((key): void => {
|
||||
delete dst[key];
|
||||
});
|
||||
const dstKeys = Object.keys(dst);
|
||||
|
||||
for (let k = 0; k < dstKeys.length; k++) {
|
||||
delete dst[dstKeys[k]];
|
||||
}
|
||||
}
|
||||
|
||||
if (prefix && Object.keys(dst).length) {
|
||||
@@ -85,22 +90,26 @@ export function augmentObject (prefix: string | null, src: Record<string, Record
|
||||
warn(prefix, 'calls', extractMethods(src, dst));
|
||||
}
|
||||
|
||||
return Object
|
||||
.keys(src)
|
||||
.reduce((newSection, sectionName): Record<string, Record<string, unknown>> => {
|
||||
const section = src[sectionName];
|
||||
const srcKeys = Object.keys(src);
|
||||
|
||||
newSection[sectionName] = Object
|
||||
.keys(section)
|
||||
.reduce((result, methodName): Record<string, unknown> => {
|
||||
// TODO When it does match, check the actual details and warn when there are differences
|
||||
if (!result[methodName]) {
|
||||
result[methodName] = section[methodName];
|
||||
}
|
||||
for (let s = 0; s < srcKeys.length; s++) {
|
||||
const section = srcKeys[s];
|
||||
|
||||
return result;
|
||||
}, dst[sectionName] || {});
|
||||
if (!dst[section]) {
|
||||
dst[section] = {};
|
||||
}
|
||||
|
||||
return newSection;
|
||||
}, dst);
|
||||
const methods = Object.keys(src[section]);
|
||||
|
||||
for (let m = 0; m < methods.length; m++) {
|
||||
const method = methods[m];
|
||||
|
||||
// TODO When it does match, check the actual details and warn when there are differences
|
||||
if (!dst[section][method]) {
|
||||
dst[section][method] = src[section][method];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return dst;
|
||||
}
|
||||
|
||||
@@ -6,10 +6,16 @@ import type { ApiTypes, DecorateMethod, MethodResult } from '../types';
|
||||
|
||||
// Most generic typings for `api.derive.*.*`
|
||||
type AnyDerive = Record<string, Record<string, AnyFunction>>;
|
||||
|
||||
// Exact typings for a particular section `api.derive.section.*`
|
||||
type DeriveSection<ApiType extends ApiTypes, Section extends Record<string, AnyFunction>> = { [MethodName in keyof Section]: MethodResult<ApiType, Section[MethodName]> };
|
||||
type DeriveSection<ApiType extends ApiTypes, Section extends Record<string, AnyFunction>> = {
|
||||
[MethodName in keyof Section]: MethodResult<ApiType, Section[MethodName]>
|
||||
};
|
||||
|
||||
// Exact typings for all sections `api.derive.*.*`
|
||||
export type DeriveAllSections<ApiType extends ApiTypes, AllSections extends AnyDerive> = { [SectionName in keyof AllSections]: DeriveSection<ApiType, AllSections[SectionName]> };
|
||||
export type DeriveAllSections<ApiType extends ApiTypes, AllSections extends AnyDerive> = {
|
||||
[SectionName in keyof AllSections]: DeriveSection<ApiType, AllSections[SectionName]>
|
||||
};
|
||||
|
||||
// A technically unsafe version of Object.keys(obj) that assumes that
|
||||
// obj only has known properties of T
|
||||
@@ -21,38 +27,27 @@ function keys<T extends Record<string, unknown>> (obj: T): (keyof T)[] {
|
||||
* This is a methods decorator which keeps all type information.
|
||||
*/
|
||||
function decorateMethods<ApiType extends ApiTypes, Section extends Record<string, AnyFunction>> (section: Section, decorateMethod: DecorateMethod<ApiType>): DeriveSection<ApiType, Section> {
|
||||
return keys(section).reduce(
|
||||
<MethodName extends keyof Section>(
|
||||
acc: DeriveSection<ApiType, Section>,
|
||||
methodName: MethodName
|
||||
): DeriveSection<ApiType, Section> => {
|
||||
const method = section[methodName];
|
||||
const result = {} as DeriveSection<ApiType, Section>;
|
||||
const names = keys(section);
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
||||
acc[methodName] = decorateMethod(method) as MethodResult<ApiType, Section[MethodName]>;
|
||||
for (let k = 0; k < names.length; k++) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
||||
result[names[k]] = decorateMethod(section[names[k]]);
|
||||
}
|
||||
|
||||
return acc;
|
||||
},
|
||||
{} as DeriveSection<ApiType, Section>
|
||||
);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* This is a section decorator which keeps all type information.
|
||||
*/
|
||||
export function decorateSections<ApiType extends ApiTypes, AllSections extends AnyDerive> (
|
||||
allSections: AllSections,
|
||||
decorateMethod: DecorateMethod<ApiType>
|
||||
): DeriveAllSections<ApiType, AllSections> {
|
||||
return keys(allSections).reduce(
|
||||
<MethodName extends keyof AllSections>(
|
||||
acc: DeriveAllSections<ApiType, AllSections>,
|
||||
sectionName: MethodName
|
||||
): DeriveAllSections<ApiType, AllSections> => {
|
||||
acc[sectionName] = decorateMethods(allSections[sectionName], decorateMethod);
|
||||
export function decorateSections<ApiType extends ApiTypes, AllSections extends AnyDerive> (allSections: AllSections, decorateMethod: DecorateMethod<ApiType>): DeriveAllSections<ApiType, AllSections> {
|
||||
const result = {} as DeriveAllSections<ApiType, AllSections>;
|
||||
const names = keys(allSections);
|
||||
|
||||
return acc;
|
||||
},
|
||||
{} as DeriveAllSections<ApiType, AllSections>
|
||||
);
|
||||
for (let k = 0; k < names.length; k++) {
|
||||
result[names[k]] = decorateMethods(allSections[names[k]], decorateMethod);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user