From 81be70e15b7585edd82d9cadecaf3f0e2b226e61 Mon Sep 17 00:00:00 2001 From: Jaco Date: Wed, 7 Jul 2021 12:35:30 +0300 Subject: [PATCH] Introduce bundle exports (#3742) * Introduce bundle exports * Move memo * Cleanup imports * Move DoNotConstruct --- packages/api-contract/src/base/Code.spec.ts | 6 +- packages/api-contract/src/bundle.ts | 7 + packages/api-contract/src/index.ts | 5 +- .../api-contract/src/promise/Blueprint.ts | 5 +- packages/api-contract/src/promise/Code.ts | 4 +- packages/api-contract/src/promise/Contract.ts | 5 +- packages/api-contract/src/rx/Blueprint.ts | 5 +- packages/api-contract/src/rx/Code.ts | 4 +- packages/api-contract/src/rx/Contract.ts | 5 +- packages/api-derive/src/bounties/bounties.ts | 5 +- packages/api-derive/src/bundle.ts | 116 +++++ packages/api-derive/src/index.ts | 114 +---- packages/api-derive/src/util/index.ts | 3 +- packages/api/src/base/Decorate.ts | 3 +- packages/api/src/bundle.ts | 10 + packages/api/src/index.ts | 8 +- packages/api/test/typesBundleDerive.spec.ts | 2 +- packages/metadata/src/bundle.ts | 6 + packages/metadata/src/index.ts | 4 +- packages/rpc-core/src/bundle.ts | 464 ++++++++++++++++++ packages/rpc-core/src/index.ts | 461 +---------------- packages/rpc-core/src/util/index.ts | 1 + .../{api-derive => rpc-core}/src/util/memo.ts | 6 +- packages/rpc-provider/src/bundle.ts | 6 + packages/rpc-provider/src/index.ts | 4 +- packages/typegen/src/bundle.ts | 5 + packages/typegen/src/index.ts | 3 +- packages/types-known/src/bundle.ts | 130 +++++ packages/types-known/src/index.ts | 128 +---- packages/types/src/bundle.ts | 8 + packages/types/src/classes.ts | 6 - .../DoNotConstruct.spec.ts | 0 packages/types/src/codec/DoNotConstruct.ts | 82 ++++ packages/types/src/codec/index.ts | 1 + packages/types/src/create/createClass.ts | 3 +- packages/types/src/create/registry.spec.ts | 4 +- packages/types/src/create/registry.ts | 2 +- packages/types/src/index.ts | 5 +- .../types/src/primitive/DoNotConstruct.ts | 27 - packages/types/src/primitive/StorageKey.ts | 2 +- packages/types/src/primitive/index.ts | 1 - 41 files changed, 874 insertions(+), 792 deletions(-) create mode 100644 packages/api-contract/src/bundle.ts create mode 100644 packages/api-derive/src/bundle.ts create mode 100644 packages/api/src/bundle.ts create mode 100644 packages/metadata/src/bundle.ts create mode 100644 packages/rpc-core/src/bundle.ts rename packages/{api-derive => rpc-core}/src/util/memo.ts (91%) create mode 100644 packages/rpc-provider/src/bundle.ts create mode 100644 packages/typegen/src/bundle.ts create mode 100644 packages/types-known/src/bundle.ts create mode 100644 packages/types/src/bundle.ts delete mode 100644 packages/types/src/classes.ts rename packages/types/src/{primitive => codec}/DoNotConstruct.spec.ts (100%) create mode 100644 packages/types/src/codec/DoNotConstruct.ts delete mode 100644 packages/types/src/primitive/DoNotConstruct.ts diff --git a/packages/api-contract/src/base/Code.spec.ts b/packages/api-contract/src/base/Code.spec.ts index 178cccb092..f3b8785b3d 100644 --- a/packages/api-contract/src/base/Code.spec.ts +++ b/packages/api-contract/src/base/Code.spec.ts @@ -4,7 +4,7 @@ import fs from 'fs'; import path from 'path'; -import { decorateMethod } from '@polkadot/api/promise'; +import { decorateMethodPromise } from '@polkadot/api'; import contractFlipper from '../../test/contracts/ink/flipper.contract.json'; import abiFlipper from '../../test/contracts/ink/flipper.json'; @@ -16,13 +16,13 @@ const wasmFlipper = fs.readFileSync(path.join(__dirname, '../../test/contracts/i describe('Code', (): void => { it('can construct with an individual ABI/WASM combo', (): void => { expect( - () => new Code(mockApi, abiFlipper, wasmFlipper, decorateMethod) + () => new Code(mockApi, abiFlipper, wasmFlipper, decorateMethodPromise) ).not.toThrow(); }); it('can construct with an .contract ABI', (): void => { expect( - () => new Code(mockApi, contractFlipper, null, decorateMethod) + () => new Code(mockApi, contractFlipper, null, decorateMethodPromise) ).not.toThrow(); }); }); diff --git a/packages/api-contract/src/bundle.ts b/packages/api-contract/src/bundle.ts new file mode 100644 index 0000000000..716351d80f --- /dev/null +++ b/packages/api-contract/src/bundle.ts @@ -0,0 +1,7 @@ +// Copyright 2017-2021 @polkadot/api-contract authors & contributors +// SPDX-License-Identifier: Apache-2.0 + +export { Abi } from './Abi'; +export { packageInfo } from './packageInfo'; +export { Blueprint as BlueprintPromise, Code as CodePromise, Contract as ContractPromise } from './promise'; +export { Blueprint as BlueprintRx, Code as CodeRx, Contract as ContractRx } from './rx'; diff --git a/packages/api-contract/src/index.ts b/packages/api-contract/src/index.ts index 51974d88d3..b718d85e20 100644 --- a/packages/api-contract/src/index.ts +++ b/packages/api-contract/src/index.ts @@ -3,7 +3,4 @@ import './detectPackage'; -export { Abi } from './Abi'; -export { packageInfo } from './packageInfo'; -export { Blueprint as BlueprintPromise, Code as CodePromise, Contract as ContractPromise } from './promise'; -export { Blueprint as BlueprintRx, Code as CodeRx, Contract as ContractRx } from './rx'; +export * from './bundle'; diff --git a/packages/api-contract/src/promise/Blueprint.ts b/packages/api-contract/src/promise/Blueprint.ts index 31e1c7ccde..e5fa972e4c 100644 --- a/packages/api-contract/src/promise/Blueprint.ts +++ b/packages/api-contract/src/promise/Blueprint.ts @@ -4,14 +4,13 @@ import type { Hash } from '@polkadot/types/interfaces'; import type { AnyJson } from '@polkadot/types/types'; -import { ApiPromise } from '@polkadot/api'; -import { decorateMethod } from '@polkadot/api/promise'; +import { ApiPromise, decorateMethodPromise } from '@polkadot/api'; import { Abi } from '../Abi'; import { Blueprint as BaseBlueprint } from '../base'; export class Blueprint extends BaseBlueprint<'promise'> { constructor (api: ApiPromise, abi: AnyJson | Abi, codeHash: string | Hash) { - super(api, abi, codeHash, decorateMethod); + super(api, abi, codeHash, decorateMethodPromise); } } diff --git a/packages/api-contract/src/promise/Code.ts b/packages/api-contract/src/promise/Code.ts index f8e7020970..f8c00b372a 100644 --- a/packages/api-contract/src/promise/Code.ts +++ b/packages/api-contract/src/promise/Code.ts @@ -4,13 +4,13 @@ import type { ApiPromise } from '@polkadot/api'; import type { AnyJson } from '@polkadot/types/types'; -import { decorateMethod } from '@polkadot/api/promise'; +import { decorateMethodPromise } from '@polkadot/api'; import { Abi } from '../Abi'; import { Code as BaseCode } from '../base'; export class Code extends BaseCode<'promise'> { constructor (api: ApiPromise, abi: AnyJson | Abi, wasm: Uint8Array | string | Buffer | null | undefined) { - super(api, abi, wasm, decorateMethod); + super(api, abi, wasm, decorateMethodPromise); } } diff --git a/packages/api-contract/src/promise/Contract.ts b/packages/api-contract/src/promise/Contract.ts index 3e1510da35..999b114771 100644 --- a/packages/api-contract/src/promise/Contract.ts +++ b/packages/api-contract/src/promise/Contract.ts @@ -4,14 +4,13 @@ import type { AccountId } from '@polkadot/types/interfaces'; import type { AnyJson } from '@polkadot/types/types'; -import { ApiPromise } from '@polkadot/api'; -import { decorateMethod } from '@polkadot/api/promise'; +import { ApiPromise, decorateMethodPromise } from '@polkadot/api'; import { Abi } from '../Abi'; import { Contract as BaseContract } from '../base'; export class Contract extends BaseContract<'promise'> { constructor (api: ApiPromise, abi: AnyJson | Abi, address: string | AccountId) { - super(api, abi, address, decorateMethod); + super(api, abi, address, decorateMethodPromise); } } diff --git a/packages/api-contract/src/rx/Blueprint.ts b/packages/api-contract/src/rx/Blueprint.ts index 3802c96c93..9670f31f6a 100644 --- a/packages/api-contract/src/rx/Blueprint.ts +++ b/packages/api-contract/src/rx/Blueprint.ts @@ -4,14 +4,13 @@ import type { Hash } from '@polkadot/types/interfaces'; import type { AnyJson } from '@polkadot/types/types'; -import { ApiRx } from '@polkadot/api'; -import { decorateMethod } from '@polkadot/api/rx'; +import { ApiRx, decorateMethodRx } from '@polkadot/api'; import { Abi } from '../Abi'; import { Blueprint as BaseBlueprint } from '../base'; export class Blueprint extends BaseBlueprint<'rxjs'> { constructor (api: ApiRx, abi: AnyJson | Abi, codeHash: string | Hash) { - super(api, abi, codeHash, decorateMethod); + super(api, abi, codeHash, decorateMethodRx); } } diff --git a/packages/api-contract/src/rx/Code.ts b/packages/api-contract/src/rx/Code.ts index 84a99566ed..5670f219e3 100644 --- a/packages/api-contract/src/rx/Code.ts +++ b/packages/api-contract/src/rx/Code.ts @@ -4,13 +4,13 @@ import type { ApiRx } from '@polkadot/api'; import type { AnyJson } from '@polkadot/types/types'; -import { decorateMethod } from '@polkadot/api/rx'; +import { decorateMethodRx } from '@polkadot/api'; import { Abi } from '../Abi'; import { Code as BaseCode } from '../base'; export class Code extends BaseCode<'rxjs'> { constructor (api: ApiRx, abi: AnyJson | Abi, wasm: Uint8Array | string | Buffer | null | undefined) { - super(api, abi, wasm, decorateMethod); + super(api, abi, wasm, decorateMethodRx); } } diff --git a/packages/api-contract/src/rx/Contract.ts b/packages/api-contract/src/rx/Contract.ts index d27c72b64c..81d0b2e198 100644 --- a/packages/api-contract/src/rx/Contract.ts +++ b/packages/api-contract/src/rx/Contract.ts @@ -4,14 +4,13 @@ import type { AccountId } from '@polkadot/types/interfaces'; import type { AnyJson } from '@polkadot/types/types'; -import { ApiRx } from '@polkadot/api'; -import { decorateMethod } from '@polkadot/api/rx'; +import { ApiRx, decorateMethodRx } from '@polkadot/api'; import { Abi } from '../Abi'; import { Contract as BaseContract } from '../base'; export class Contract extends BaseContract<'rxjs'> { constructor (api: ApiRx, abi: AnyJson | Abi, address: string | AccountId) { - super(api, abi, address, decorateMethod); + super(api, abi, address, decorateMethodRx); } } diff --git a/packages/api-derive/src/bounties/bounties.ts b/packages/api-derive/src/bounties/bounties.ts index 658d6aaa12..96635b4b8f 100644 --- a/packages/api-derive/src/bounties/bounties.ts +++ b/packages/api-derive/src/bounties/bounties.ts @@ -3,14 +3,13 @@ import type { Observable } from 'rxjs'; import type { ApiInterfaceRx } from '@polkadot/api/types'; -import type { DeriveBounties, DeriveCollectiveProposal } from '@polkadot/api-derive/types'; import type { Bytes, Option } from '@polkadot/types'; import type { Bounty, BountyIndex, ProposalIndex } from '@polkadot/types/interfaces'; +import type { DeriveBounties, DeriveCollectiveProposal } from '../types'; import { combineLatest, map, of, switchMap } from 'rxjs'; -import { memo } from '@polkadot/api-derive/util'; - +import { memo } from '../util'; import { filterBountiesProposals } from './helpers/filterBountyProposals'; type Result = [Option[], Option[], BountyIndex[], DeriveCollectiveProposal[]]; diff --git a/packages/api-derive/src/bundle.ts b/packages/api-derive/src/bundle.ts new file mode 100644 index 0000000000..406fcfe0f7 --- /dev/null +++ b/packages/api-derive/src/bundle.ts @@ -0,0 +1,116 @@ +// Copyright 2017-2021 @polkadot/api-derive authors & contributors +// SPDX-License-Identifier: Apache-2.0 + +import type { Observable } from 'rxjs'; +import type { ApiInterfaceRx } from '@polkadot/api/types'; +import type { AnyFunction } from '@polkadot/types/types'; + +import * as accounts from './accounts'; +import * as balances from './balances'; +import * as bounties from './bounties'; +import * as chain from './chain'; +import * as contracts from './contracts'; +import * as council from './council'; +import * as democracy from './democracy'; +import * as elections from './elections'; +import * as imOnline from './imOnline'; +import * as membership from './membership'; +import * as parachains from './parachains'; +import * as session from './session'; +import * as society from './society'; +import * as staking from './staking'; +import * as technicalCommittee from './technicalCommittee'; +import * as treasury from './treasury'; +import * as tx from './tx'; + +export { packageInfo } from './packageInfo'; +export * from './type'; + +interface Avail { + instances: string[]; + withDetect?: boolean; +} + +export const derive = { accounts, balances, bounties, chain, contracts, council, democracy, elections, imOnline, membership, parachains, session, society, staking, technicalCommittee, treasury, tx }; + +type DeriveSection
= { + [Method in keyof Section]: Section[Method] extends AnyFunction + ? ReturnType // ReturnType will be the inner function, i.e. without (api) argument + : never; +}; +type DeriveAllSections = { + [Section in keyof AllSections]: DeriveSection +}; + +export type DeriveCustom = Record (...args: any[]) => Observable>>; + +export type ExactDerive = DeriveAllSections; + +// Enable derive only if some of these modules are available +const deriveAvail: Record = { + contracts: { instances: ['contracts'] }, + council: { instances: ['council'], withDetect: true }, + democracy: { instances: ['democracy'] }, + elections: { instances: ['phragmenElection', 'electionsPhragmen', 'elections', 'council'], withDetect: true }, + imOnline: { instances: ['imOnline'] }, + membership: { instances: ['membership'] }, + parachains: { instances: ['parachains', 'registrar'] }, + session: { instances: ['session'] }, + society: { instances: ['society'] }, + staking: { instances: ['staking'] }, + technicalCommittee: { instances: ['technicalCommittee'], withDetect: true }, + treasury: { instances: ['treasury'] } +}; + +/** + * Returns an object that will inject `api` into all the functions inside + * `allSections`, and keep the object architecture of `allSections`. + */ +/** @internal */ +function injectFunctions (instanceId: string, api: ApiInterfaceRx, allSections: AllSections): DeriveAllSections { + const queryKeys = Object.keys(api.query); + const specName = api.runtimeVersion.specName.toString(); + + return Object + .keys(allSections) + .filter((sectionName) => + !deriveAvail[sectionName] || + deriveAvail[sectionName].instances.some((q) => queryKeys.includes(q)) || + ( + deriveAvail[sectionName].withDetect && + deriveAvail[sectionName].instances.some((q) => + (api.registry.getModuleInstances(specName, q) || []).some((q) => queryKeys.includes(q)) + ) + ) + ) + .reduce((deriveAcc, sectionName): DeriveAllSections => { + const section = allSections[sectionName as keyof AllSections]; + + deriveAcc[sectionName as keyof AllSections] = Object + .keys(section) + .reduce((sectionAcc, _methodName): DeriveSection => { + const methodName = _methodName as keyof typeof section; + // Not sure what to do here, casting as any. Though the final types are good + // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment,@typescript-eslint/no-unsafe-call + const method = (section[methodName] as any)(instanceId, api); + + // idem + // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment,@typescript-eslint/no-unsafe-member-access + (sectionAcc as any)[methodName] = method; + + return sectionAcc; + }, {} as DeriveSection); + + return deriveAcc; + }, {} as DeriveAllSections); +} + +// FIXME The return type of this function should be {...ExactDerive, ...DeriveCustom} +// For now we just drop the custom derive typings +/** @internal */ +export function decorateDerive (instanceId: string, api: ApiInterfaceRx, custom: DeriveCustom = {}): ExactDerive { + return { + ...injectFunctions(instanceId, api, derive), + ...injectFunctions(instanceId, api, custom) + }; +} diff --git a/packages/api-derive/src/index.ts b/packages/api-derive/src/index.ts index d39658366c..b59cc69832 100644 --- a/packages/api-derive/src/index.ts +++ b/packages/api-derive/src/index.ts @@ -3,116 +3,4 @@ import './detectPackage'; -import type { Observable } from 'rxjs'; -import type { ApiInterfaceRx } from '@polkadot/api/types'; -import type { AnyFunction } from '@polkadot/types/types'; - -import * as accounts from './accounts'; -import * as balances from './balances'; -import * as bounties from './bounties'; -import * as chain from './chain'; -import * as contracts from './contracts'; -import * as council from './council'; -import * as democracy from './democracy'; -import * as elections from './elections'; -import * as imOnline from './imOnline'; -import * as membership from './membership'; -import * as parachains from './parachains'; -import * as session from './session'; -import * as society from './society'; -import * as staking from './staking'; -import * as technicalCommittee from './technicalCommittee'; -import * as treasury from './treasury'; -import * as tx from './tx'; - -export { packageInfo } from './packageInfo'; -export * from './type'; - -interface Avail { - instances: string[]; - withDetect?: boolean; -} - -export const derive = { accounts, balances, bounties, chain, contracts, council, democracy, elections, imOnline, membership, parachains, session, society, staking, technicalCommittee, treasury, tx }; - -type DeriveSection
= { - [Method in keyof Section]: Section[Method] extends AnyFunction - ? ReturnType // ReturnType will be the inner function, i.e. without (api) argument - : never; -}; -type DeriveAllSections = { - [Section in keyof AllSections]: DeriveSection -}; - -export type DeriveCustom = Record (...args: any[]) => Observable>>; - -export type ExactDerive = DeriveAllSections; - -// Enable derive only if some of these modules are available -const deriveAvail: Record = { - contracts: { instances: ['contracts'] }, - council: { instances: ['council'], withDetect: true }, - democracy: { instances: ['democracy'] }, - elections: { instances: ['phragmenElection', 'electionsPhragmen', 'elections', 'council'], withDetect: true }, - imOnline: { instances: ['imOnline'] }, - membership: { instances: ['membership'] }, - parachains: { instances: ['parachains', 'registrar'] }, - session: { instances: ['session'] }, - society: { instances: ['society'] }, - staking: { instances: ['staking'] }, - technicalCommittee: { instances: ['technicalCommittee'], withDetect: true }, - treasury: { instances: ['treasury'] } -}; - -/** - * Returns an object that will inject `api` into all the functions inside - * `allSections`, and keep the object architecture of `allSections`. - */ -/** @internal */ -function injectFunctions (instanceId: string, api: ApiInterfaceRx, allSections: AllSections): DeriveAllSections { - const queryKeys = Object.keys(api.query); - const specName = api.runtimeVersion.specName.toString(); - - return Object - .keys(allSections) - .filter((sectionName) => - !deriveAvail[sectionName] || - deriveAvail[sectionName].instances.some((q) => queryKeys.includes(q)) || - ( - deriveAvail[sectionName].withDetect && - deriveAvail[sectionName].instances.some((q) => - (api.registry.getModuleInstances(specName, q) || []).some((q) => queryKeys.includes(q)) - ) - ) - ) - .reduce((deriveAcc, sectionName): DeriveAllSections => { - const section = allSections[sectionName as keyof AllSections]; - - deriveAcc[sectionName as keyof AllSections] = Object - .keys(section) - .reduce((sectionAcc, _methodName): DeriveSection => { - const methodName = _methodName as keyof typeof section; - // Not sure what to do here, casting as any. Though the final types are good - // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment,@typescript-eslint/no-unsafe-call - const method = (section[methodName] as any)(instanceId, api); - - // idem - // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment,@typescript-eslint/no-unsafe-member-access - (sectionAcc as any)[methodName] = method; - - return sectionAcc; - }, {} as DeriveSection); - - return deriveAcc; - }, {} as DeriveAllSections); -} - -// FIXME The return type of this function should be {...ExactDerive, ...DeriveCustom} -// For now we just drop the custom derive typings -/** @internal */ -export function decorateDerive (instanceId: string, api: ApiInterfaceRx, custom: DeriveCustom = {}): ExactDerive { - return { - ...injectFunctions(instanceId, api, derive), - ...injectFunctions(instanceId, api, custom) - }; -} +export * from './bundle'; diff --git a/packages/api-derive/src/util/index.ts b/packages/api-derive/src/util/index.ts index e1333c83aa..21ffe00155 100644 --- a/packages/api-derive/src/util/index.ts +++ b/packages/api-derive/src/util/index.ts @@ -1,9 +1,8 @@ // Copyright 2017-2021 @polkadot/api-derive authors & contributors // SPDX-License-Identifier: Apache-2.0 -export { drr } from '@polkadot/rpc-core/util'; +export { drr, memo } from '@polkadot/rpc-core'; export * from './approvalFlagsToBools'; export * from './cache'; export * from './cacheImpl'; -export * from './memo'; diff --git a/packages/api/src/base/Decorate.ts b/packages/api/src/base/Decorate.ts index 207607508d..d055490bf9 100644 --- a/packages/api/src/base/Decorate.ts +++ b/packages/api/src/base/Decorate.ts @@ -15,9 +15,8 @@ import type { VersionedRegistry } from './types'; import { BehaviorSubject, combineLatest, map, of, switchMap, tap, toArray } from 'rxjs'; import { decorateDerive, ExactDerive } from '@polkadot/api-derive'; -import { memo } from '@polkadot/api-derive/util'; import { expandMetadata, Metadata } from '@polkadot/metadata'; -import { RpcCore } from '@polkadot/rpc-core'; +import { memo, RpcCore } from '@polkadot/rpc-core'; import { WsProvider } from '@polkadot/rpc-provider'; import { TypeRegistry } from '@polkadot/types/create'; import { DEFAULT_VERSION as EXTRINSIC_DEFAULT_VERSION } from '@polkadot/types/extrinsic/constants'; diff --git a/packages/api/src/bundle.ts b/packages/api/src/bundle.ts new file mode 100644 index 0000000000..3731044461 --- /dev/null +++ b/packages/api/src/bundle.ts @@ -0,0 +1,10 @@ +// Copyright 2017-2021 @polkadot/api authors & contributors +// SPDX-License-Identifier: Apache-2.0 + +export { Keyring } from '@polkadot/keyring'; +export { WsProvider, HttpProvider } from '@polkadot/rpc-provider'; + +export { packageInfo } from './packageInfo'; +export { ApiPromise, decorateMethod as decorateMethodPromise } from './promise'; +export { SubmittableResult } from './submittable'; +export { ApiRx, decorateMethod as decorateMethodRx } from './rx'; diff --git a/packages/api/src/index.ts b/packages/api/src/index.ts index c49984c342..86d6fe405b 100644 --- a/packages/api/src/index.ts +++ b/packages/api/src/index.ts @@ -3,10 +3,4 @@ import './detectPackage'; -export { Keyring } from '@polkadot/keyring'; -export { WsProvider } from '@polkadot/rpc-provider/ws'; - -export { packageInfo } from './packageInfo'; -export { ApiPromise } from './promise'; -export { SubmittableResult } from './submittable'; -export { ApiRx } from './rx'; +export * from './bundle'; diff --git a/packages/api/test/typesBundleDerive.spec.ts b/packages/api/test/typesBundleDerive.spec.ts index 4007e6b370..56791f8137 100644 --- a/packages/api/test/typesBundleDerive.spec.ts +++ b/packages/api/test/typesBundleDerive.spec.ts @@ -11,7 +11,7 @@ import { jest } from '@jest/globals'; import { combineLatest, map, of, switchMap } from 'rxjs'; import { ApiPromise, WsProvider } from '@polkadot/api'; -import { memo } from '@polkadot/api-derive/util/memo'; +import { memo } from '@polkadot/rpc-core'; interface VestingInfo extends Struct { readonly locked: Balance; diff --git a/packages/metadata/src/bundle.ts b/packages/metadata/src/bundle.ts new file mode 100644 index 0000000000..1fe88bd05e --- /dev/null +++ b/packages/metadata/src/bundle.ts @@ -0,0 +1,6 @@ +// Copyright 2017-2021 @polkadot/metadata authors & contributors +// SPDX-License-Identifier: Apache-2.0 + +export { Metadata } from './Metadata'; +export { decorateConstants, decorateExtrinsics, decorateStorage, expandMetadata } from './decorate'; +export { packageInfo } from './packageInfo'; diff --git a/packages/metadata/src/index.ts b/packages/metadata/src/index.ts index 20b2f6e2cd..efdaef6093 100644 --- a/packages/metadata/src/index.ts +++ b/packages/metadata/src/index.ts @@ -3,6 +3,4 @@ import './detectPackage'; -export { Metadata } from './Metadata'; -export { decorateConstants, decorateExtrinsics, decorateStorage, expandMetadata } from './decorate'; -export { packageInfo } from './packageInfo'; +export * from './bundle'; diff --git a/packages/rpc-core/src/bundle.ts b/packages/rpc-core/src/bundle.ts new file mode 100644 index 0000000000..34ea41cb1f --- /dev/null +++ b/packages/rpc-core/src/bundle.ts @@ -0,0 +1,464 @@ +// Copyright 2017-2021 @polkadot/rpc-core authors & contributors +// SPDX-License-Identifier: Apache-2.0 + +import type { Observer } from 'rxjs'; +import type { ProviderInterface, ProviderInterfaceCallback } from '@polkadot/rpc-provider/types'; +import type { StorageKey, Vec } from '@polkadot/types'; +import type { Hash } from '@polkadot/types/interfaces'; +import type { AnyJson, Codec, DefinitionRpc, DefinitionRpcExt, DefinitionRpcSub, Registry } from '@polkadot/types/types'; +import type { Memoized } from '@polkadot/util/types'; +import type { RpcInterface, RpcInterfaceMethod } from './types'; + +import { Observable, publishReplay, refCount } from 'rxjs'; + +import { Option } from '@polkadot/types'; +import { createClass, createTypeUnsafe } from '@polkadot/types/create'; +import jsonrpc from '@polkadot/types/interfaces/jsonrpc'; +import { assert, hexToU8a, isFunction, isNull, isUndefined, logger, memoize, u8aToU8a } from '@polkadot/util'; + +import { drr, refCountDelay } from './util'; + +export { packageInfo } from './packageInfo'; +export * from './util'; + +interface StorageChangeSetJSON { + block: string; + changes: [string, string | null][]; +} + +type OutputType = 'json' | 'raw' | 'scale'; + +const l = logger('rpc-core'); + +const EMPTY_META = { + fallback: undefined, + modifier: { isOptional: true }, + type: { + asMap: { linked: { isTrue: false } }, + isMap: false + } +}; + +// utility method to create a nicely-formatted error +/** @internal */ +function logErrorMessage (method: string, { params, type }: DefinitionRpc, error: Error): void { + const inputs = params.map(({ isOptional, name, type }): string => + `${name}${isOptional ? '?' : ''}: ${type}` + ).join(', '); + + l.error(`${method}(${inputs}): ${type}:: ${error.message}`); +} + +function isTreatAsHex (key: StorageKey): boolean { + // :code is problematic - it does not have the length attached, which is + // unlike all other storage entries where it is indeed properly encoded + return ['0x3a636f6465'].includes(key.toHex()); +} + +/** + * @name Rpc + * @summary The API may use a HTTP or WebSockets provider. + * @description It allows for querying a Polkadot Client Node. + * WebSockets provider is recommended since HTTP provider only supports basic querying. + * + * ```mermaid + * graph LR; + * A[Api] --> |WebSockets| B[WsProvider]; + * B --> |endpoint| C[ws://127.0.0.1:9944] + * ``` + * + * @example + *
+ * + * ```javascript + * import Rpc from '@polkadot/rpc-core'; + * import { WsProvider } from '@polkadot/rpc-provider/ws'; + * + * const provider = new WsProvider('ws://127.0.0.1:9944'); + * const rpc = new Rpc(provider); + * ``` + */ +export class RpcCore { + #instanceId: string; + + #registryDefault: Registry; + + #getBlockRegistry?: (blockHash: Uint8Array) => Promise<{ registry: Registry }>; + + readonly #storageCache = new Map(); + + public readonly mapping = new Map(); + + public readonly provider: ProviderInterface; + + public readonly sections: string[] = []; + + /** + * @constructor + * Default constructor for the Api Object + * @param {ProviderInterface} provider An API provider using HTTP or WebSocket + */ + constructor (instanceId: string, registry: Registry, provider: ProviderInterface, userRpc: Record> = {}) { + // eslint-disable-next-line @typescript-eslint/unbound-method + assert(provider && isFunction(provider.send), 'Expected Provider to API create'); + + this.#instanceId = instanceId; + this.#registryDefault = registry; + this.provider = provider; + + const sectionNames = Object.keys(jsonrpc); + + // these are the base keys (i.e. part of jsonrpc) + this.sections.push(...sectionNames); + + // decorate all interfaces, defined and user on this instance + this.addUserInterfaces(userRpc); + } + + /** + * @description Returns the connected status of a provider + */ + public get isConnected (): boolean { + return this.provider.isConnected; + } + + /** + * @description Manually connect from the attached provider + */ + public connect (): Promise { + return this.provider.connect(); + } + + /** + * @description Manually disconnect from the attached provider + */ + public disconnect (): Promise { + return this.provider.disconnect(); + } + + /** + * @description Sets a registry swap (typically from Api) + */ + public setRegistrySwap (registrySwap: (blockHash: Uint8Array) => Promise<{ registry: Registry }>): void { + this.#getBlockRegistry = memoize(registrySwap, { + getInstanceId: () => this.#instanceId + }); + } + + public addUserInterfaces
(userRpc: Record>): void { + // add any extra user-defined sections + this.sections.push(...Object.keys(userRpc).filter((key) => !this.sections.includes(key))); + + // decorate the sections with base and user methods + this.sections.forEach((sectionName): void => { + (this as Record)[sectionName as Section] ||= {}; + + const section = (this as Record)[sectionName as Section] as Record; + + Object + .entries({ + ...this._createInterface(sectionName, jsonrpc[sectionName as 'babe'] || {}), + ...this._createInterface(sectionName, userRpc[sectionName] || {}) + }) + .forEach(([key, value]): void => { + section[key] ||= value; + }); + }); + } + + private _createInterface
(section: string, methods: Record): RpcInterface[Section] { + return Object + .entries(methods) + .filter(([method, { endpoint }]) => !this.mapping.has(endpoint || `${section}_${method}`)) + .reduce((exposed, [method, { endpoint }]): RpcInterface[Section] => { + const def = methods[method]; + const isSubscription = !!(def as DefinitionRpcSub).pubsub; + const jsonrpc = endpoint || `${section}_${method}`; + + this.mapping.set(jsonrpc, { ...def, isSubscription, jsonrpc, method, section }); + + (exposed as Record)[method] = isSubscription + ? this._createMethodSubscribe(section, method, def as DefinitionRpcSub) + : this._createMethodSend(section, method, def); + + return exposed; + }, {} as RpcInterface[Section]); + } + + private _memomize (creator: (outputAs: OutputType) => (...values: unknown[]) => Observable, def: DefinitionRpc): Memoized { + const memoized = memoize(creator('scale') as RpcInterfaceMethod, { + getInstanceId: () => this.#instanceId + }); + + memoized.json = creator('json'); + memoized.raw = creator('raw'); + memoized.meta = def; + + return memoized; + } + + private _createMethodSend (section: string, method: string, def: DefinitionRpc): RpcInterfaceMethod { + const rpcName = def.endpoint || `${section}_${method}`; + const hashIndex = def.params.findIndex(({ isHistoric }) => isHistoric); + let memoized: null | Memoized = null; + + // execute the RPC call, doing a registry swap for historic as applicable + const callWithRegistry = async (outputAs: OutputType, values: unknown[]): Promise => { + const blockHash = hashIndex === -1 + ? null + : values[hashIndex] as (Uint8Array | string | null | undefined); + const { registry } = outputAs === 'scale' && blockHash && this.#getBlockRegistry + ? await this.#getBlockRegistry(u8aToU8a(blockHash)) + : { registry: this.#registryDefault }; + const params = this._formatInputs(registry, null, def, values); + const data = await this.provider.send(rpcName, params.map((param) => param.toJSON())); + + return outputAs === 'scale' + ? this._formatOutput(registry, blockHash, method, def, params, data) as unknown as T + : registry.createType(outputAs === 'raw' ? 'Raw' : 'Json', data) as unknown as T; + }; + + const creator = (outputAs: OutputType) => (...values: unknown[]): Observable => { + const isDelayed = outputAs === 'scale' && hashIndex !== -1 && !!values[hashIndex]; + + return new Observable((observer: Observer): VoidCallback => { + callWithRegistry(outputAs, values) + .then((value): void => { + observer.next(value); + observer.complete(); + }) + .catch((error): void => { + logErrorMessage(method, def, error); + + observer.error(error); + observer.complete(); + }); + + return (): void => { + // delete old results from cache + memoized?.unmemoize(...values); + }; + }).pipe( + publishReplay(1), // create a Replay(1) + isDelayed + ? refCountDelay() // Unsubscribe after delay + : refCount() + ); + }; + + memoized = this._memomize(creator, def); + + return memoized; + } + + // create a subscriptor, it subscribes once and resolves with the id as subscribe + private _createSubscriber ({ paramsJson, subName, subType, update }: { subType: string; subName: string; paramsJson: AnyJson[]; update: ProviderInterfaceCallback }, errorHandler: (error: Error) => void): Promise { + return new Promise((resolve, reject): void => { + this.provider + .subscribe(subType, subName, paramsJson, update) + .then(resolve) + .catch((error): void => { + errorHandler(error); + reject(error); + }); + }); + } + + private _createMethodSubscribe (section: string, method: string, def: DefinitionRpcSub): RpcInterfaceMethod { + const [updateType, subMethod, unsubMethod] = def.pubsub; + const subName = `${section}_${subMethod}`; + const unsubName = `${section}_${unsubMethod}`; + const subType = `${section}_${updateType}`; + let memoized: null | Memoized = null; + + const creator = (outputAs: OutputType) => (...values: unknown[]): Observable => { + return new Observable((observer: Observer): VoidCallback => { + // Have at least an empty promise, as used in the unsubscribe + let subscriptionPromise: Promise = Promise.resolve(null); + const registry = this.#registryDefault; + + const errorHandler = (error: Error): void => { + logErrorMessage(method, def, error); + + observer.error(error); + }; + + try { + const params = this._formatInputs(registry, null, def, values); + const paramsJson = params.map((param): AnyJson => param.toJSON()); + + const update = (error?: Error | null, result?: T): void => { + if (error) { + logErrorMessage(method, def, error); + + return; + } + + try { + observer.next( + outputAs === 'scale' + ? this._formatOutput(registry, null, method, def, params, result) as unknown as T + : registry.createType(outputAs === 'raw' ? 'Raw' : 'Json', result) as unknown as T + ); + } catch (error) { + observer.error(error); + } + }; + + subscriptionPromise = this._createSubscriber({ paramsJson, subName, subType, update }, errorHandler); + } catch (error) { + errorHandler(error); + } + + // Teardown logic + return (): void => { + // Delete from cache, so old results don't hang around + memoized?.unmemoize(...values); + + // Unsubscribe from provider + subscriptionPromise + .then((subscriptionId): Promise => + isNull(subscriptionId) + ? Promise.resolve(false) + : this.provider.unsubscribe(subType, unsubName, subscriptionId) + ) + .catch((error: Error) => logErrorMessage(method, def, error)); + }; + }).pipe(drr()); + }; + + memoized = this._memomize(creator, def); + + return memoized; + } + + private _formatInputs (registry: Registry, blockHash: Uint8Array | string | null | undefined, def: DefinitionRpc, inputs: unknown[]): Codec[] { + const reqArgCount = def.params.filter(({ isOptional }) => !isOptional).length; + const optText = reqArgCount === def.params.length + ? '' + : ` (${def.params.length - reqArgCount} optional)`; + + assert(inputs.length >= reqArgCount && inputs.length <= def.params.length, () => `Expected ${def.params.length} parameters${optText}, ${inputs.length} found instead`); + + return inputs.map((input, index): Codec => + createTypeUnsafe(registry, def.params[index].type, [input], { blockHash }) + ); + } + + private _formatOutput (registry: Registry, blockHash: Uint8Array | string | null | undefined, method: string, rpc: DefinitionRpc, params: Codec[], result?: unknown): Codec | Codec[] { + if (rpc.type === 'StorageData') { + const key = params[0] as StorageKey; + + return this._formatStorageData(registry, blockHash, key, result as string); + } else if (rpc.type === 'StorageChangeSet') { + const keys = params[0] as Vec; + + return keys + ? this._formatStorageSet(registry, (result as StorageChangeSetJSON).block, keys, (result as StorageChangeSetJSON).changes) + : registry.createType('StorageChangeSet', result); + } else if (rpc.type === 'Vec') { + const mapped = (result as StorageChangeSetJSON[]).map(({ block, changes }): [Hash, Codec[]] => [ + registry.createType('Hash', block), + this._formatStorageSet(registry, block, params[0] as Vec, changes) + ]); + + // we only query at a specific block, not a range - flatten + return method === 'queryStorageAt' + ? mapped[0][1] + : mapped as unknown as Codec[]; + } + + return createTypeUnsafe(registry, rpc.type, [result], { blockHash }); + } + + private _formatStorageData (registry: Registry, blockHash: Uint8Array | string | null | undefined, key: StorageKey, value: string | null): Codec { + const isEmpty = isNull(value); + + // we convert to Uint8Array since it maps to the raw encoding, all + // data will be correctly encoded (incl. numbers, excl. :code) + const input = isEmpty + ? null + : isTreatAsHex(key) + ? value + : u8aToU8a(value); + + return this._newType(registry, blockHash, key, input, isEmpty); + } + + private _formatStorageSet (registry: Registry, blockHash: string, keys: Vec, changes: [string, string | null][]): Codec[] { + // For StorageChangeSet, the changes has the [key, value] mappings + const withCache = keys.length !== 1; + + // multiple return values (via state.storage subscription), decode the values + // one at a time, all based on the query types. Three values can be returned - + // - Codec - There is a valid value, non-empty + // - null - The storage key is empty + return keys.reduce((results: Codec[], key: StorageKey, index): Codec[] => { + results.push(this._formatStorageSetEntry(registry, blockHash, key, changes, withCache, index)); + + return results; + }, []); + } + + private _formatStorageSetEntry (registry: Registry, blockHash: string, key: StorageKey, changes: [string, string | null][], witCache: boolean, entryIndex: number): Codec { + const hexKey = key.toHex(); + const found = changes.find(([key]) => key === hexKey); + + // if we don't find the value, this is our fallback + // - in the case of an array of values, fill the hole from the cache + // - if a single result value, don't fill - it is not an update hole + // - fallback to an empty option in all cases + const value = isUndefined(found) + ? (witCache && this.#storageCache.get(hexKey)) || null + : found[1]; + const isEmpty = isNull(value); + const input = isEmpty || isTreatAsHex(key) + ? value + : u8aToU8a(value); + + // store the retrieved result - the only issue with this cache is that there is no + // clearing of it, so very long running processes (not just a couple of hours, longer) + // will increase memory beyond what is allowed. + this.#storageCache.set(hexKey, value); + + return this._newType(registry, blockHash, key, input, isEmpty, entryIndex); + } + + private _newType (registry: Registry, blockHash: Uint8Array | string | null | undefined, key: StorageKey, input: string | Uint8Array | null, isEmpty: boolean, entryIndex = -1): Codec { + // single return value (via state.getStorage), decode the value based on the + // outputType that we have specified. Fallback to Raw on nothing + const type = key.outputType || 'Raw'; + const meta = key.meta || EMPTY_META; + const entryNum = entryIndex === -1 + ? '' + : ` entry ${entryIndex}:`; + + try { + if (meta.modifier.isOptional) { + let inner = null; + + if (!isEmpty) { + inner = createTypeUnsafe(registry, type, [input], { blockHash, isPedantic: true }); + } + + const option = new Option(registry, createClass(registry, type), inner); + + if (blockHash) { + option.createdAtHash = registry.createType('Hash', blockHash); + } + + return option; + } + + return createTypeUnsafe(registry, type, [ + isEmpty + ? meta.fallback + ? hexToU8a(meta.fallback.toHex()) + : undefined + : input + ], { blockHash, isPedantic: true }); + } catch (error) { + throw new Error(`Unable to decode storage ${key.section || 'unknown'}.${key.method || 'unknown'}:${entryNum}: ${(error as Error).message}`); + } + } +} diff --git a/packages/rpc-core/src/index.ts b/packages/rpc-core/src/index.ts index ab7e33ef50..8d0d606e16 100644 --- a/packages/rpc-core/src/index.ts +++ b/packages/rpc-core/src/index.ts @@ -3,463 +3,4 @@ import './detectPackage'; -import type { Observer } from 'rxjs'; -import type { ProviderInterface, ProviderInterfaceCallback } from '@polkadot/rpc-provider/types'; -import type { StorageKey, Vec } from '@polkadot/types'; -import type { Hash } from '@polkadot/types/interfaces'; -import type { AnyJson, Codec, DefinitionRpc, DefinitionRpcExt, DefinitionRpcSub, Registry } from '@polkadot/types/types'; -import type { Memoized } from '@polkadot/util/types'; -import type { RpcInterface, RpcInterfaceMethod } from './types'; - -import { Observable, publishReplay, refCount } from 'rxjs'; - -import { Option } from '@polkadot/types'; -import { createClass, createTypeUnsafe } from '@polkadot/types/create'; -import jsonrpc from '@polkadot/types/interfaces/jsonrpc'; -import { assert, hexToU8a, isFunction, isNull, isUndefined, logger, memoize, u8aToU8a } from '@polkadot/util'; - -import { drr, refCountDelay } from './util'; - -export { packageInfo } from './packageInfo'; - -interface StorageChangeSetJSON { - block: string; - changes: [string, string | null][]; -} - -type OutputType = 'json' | 'raw' | 'scale'; - -const l = logger('rpc-core'); - -const EMPTY_META = { - fallback: undefined, - modifier: { isOptional: true }, - type: { - asMap: { linked: { isTrue: false } }, - isMap: false - } -}; - -// utility method to create a nicely-formatted error -/** @internal */ -function logErrorMessage (method: string, { params, type }: DefinitionRpc, error: Error): void { - const inputs = params.map(({ isOptional, name, type }): string => - `${name}${isOptional ? '?' : ''}: ${type}` - ).join(', '); - - l.error(`${method}(${inputs}): ${type}:: ${error.message}`); -} - -function isTreatAsHex (key: StorageKey): boolean { - // :code is problematic - it does not have the length attached, which is - // unlike all other storage entries where it is indeed properly encoded - return ['0x3a636f6465'].includes(key.toHex()); -} - -/** - * @name Rpc - * @summary The API may use a HTTP or WebSockets provider. - * @description It allows for querying a Polkadot Client Node. - * WebSockets provider is recommended since HTTP provider only supports basic querying. - * - * ```mermaid - * graph LR; - * A[Api] --> |WebSockets| B[WsProvider]; - * B --> |endpoint| C[ws://127.0.0.1:9944] - * ``` - * - * @example - *
- * - * ```javascript - * import Rpc from '@polkadot/rpc-core'; - * import { WsProvider } from '@polkadot/rpc-provider/ws'; - * - * const provider = new WsProvider('ws://127.0.0.1:9944'); - * const rpc = new Rpc(provider); - * ``` - */ -export class RpcCore { - #instanceId: string; - - #registryDefault: Registry; - - #getBlockRegistry?: (blockHash: Uint8Array) => Promise<{ registry: Registry }>; - - readonly #storageCache = new Map(); - - public readonly mapping = new Map(); - - public readonly provider: ProviderInterface; - - public readonly sections: string[] = []; - - /** - * @constructor - * Default constructor for the Api Object - * @param {ProviderInterface} provider An API provider using HTTP or WebSocket - */ - constructor (instanceId: string, registry: Registry, provider: ProviderInterface, userRpc: Record> = {}) { - // eslint-disable-next-line @typescript-eslint/unbound-method - assert(provider && isFunction(provider.send), 'Expected Provider to API create'); - - this.#instanceId = instanceId; - this.#registryDefault = registry; - this.provider = provider; - - const sectionNames = Object.keys(jsonrpc); - - // these are the base keys (i.e. part of jsonrpc) - this.sections.push(...sectionNames); - - // decorate all interfaces, defined and user on this instance - this.addUserInterfaces(userRpc); - } - - /** - * @description Returns the connected status of a provider - */ - public get isConnected (): boolean { - return this.provider.isConnected; - } - - /** - * @description Manually connect from the attached provider - */ - public connect (): Promise { - return this.provider.connect(); - } - - /** - * @description Manually disconnect from the attached provider - */ - public disconnect (): Promise { - return this.provider.disconnect(); - } - - /** - * @description Sets a registry swap (typically from Api) - */ - public setRegistrySwap (registrySwap: (blockHash: Uint8Array) => Promise<{ registry: Registry }>): void { - this.#getBlockRegistry = memoize(registrySwap, { - getInstanceId: () => this.#instanceId - }); - } - - public addUserInterfaces
(userRpc: Record>): void { - // add any extra user-defined sections - this.sections.push(...Object.keys(userRpc).filter((key) => !this.sections.includes(key))); - - // decorate the sections with base and user methods - this.sections.forEach((sectionName): void => { - (this as Record)[sectionName as Section] ||= {}; - - const section = (this as Record)[sectionName as Section] as Record; - - Object - .entries({ - ...this._createInterface(sectionName, jsonrpc[sectionName as 'babe'] || {}), - ...this._createInterface(sectionName, userRpc[sectionName] || {}) - }) - .forEach(([key, value]): void => { - section[key] ||= value; - }); - }); - } - - private _createInterface
(section: string, methods: Record): RpcInterface[Section] { - return Object - .entries(methods) - .filter(([method, { endpoint }]) => !this.mapping.has(endpoint || `${section}_${method}`)) - .reduce((exposed, [method, { endpoint }]): RpcInterface[Section] => { - const def = methods[method]; - const isSubscription = !!(def as DefinitionRpcSub).pubsub; - const jsonrpc = endpoint || `${section}_${method}`; - - this.mapping.set(jsonrpc, { ...def, isSubscription, jsonrpc, method, section }); - - (exposed as Record)[method] = isSubscription - ? this._createMethodSubscribe(section, method, def as DefinitionRpcSub) - : this._createMethodSend(section, method, def); - - return exposed; - }, {} as RpcInterface[Section]); - } - - private _memomize (creator: (outputAs: OutputType) => (...values: unknown[]) => Observable, def: DefinitionRpc): Memoized { - const memoized = memoize(creator('scale') as RpcInterfaceMethod, { - getInstanceId: () => this.#instanceId - }); - - memoized.json = creator('json'); - memoized.raw = creator('raw'); - memoized.meta = def; - - return memoized; - } - - private _createMethodSend (section: string, method: string, def: DefinitionRpc): RpcInterfaceMethod { - const rpcName = def.endpoint || `${section}_${method}`; - const hashIndex = def.params.findIndex(({ isHistoric }) => isHistoric); - let memoized: null | Memoized = null; - - // execute the RPC call, doing a registry swap for historic as applicable - const callWithRegistry = async (outputAs: OutputType, values: unknown[]): Promise => { - const blockHash = hashIndex === -1 - ? null - : values[hashIndex] as (Uint8Array | string | null | undefined); - const { registry } = outputAs === 'scale' && blockHash && this.#getBlockRegistry - ? await this.#getBlockRegistry(u8aToU8a(blockHash)) - : { registry: this.#registryDefault }; - const params = this._formatInputs(registry, null, def, values); - const data = await this.provider.send(rpcName, params.map((param) => param.toJSON())); - - return outputAs === 'scale' - ? this._formatOutput(registry, blockHash, method, def, params, data) as unknown as T - : registry.createType(outputAs === 'raw' ? 'Raw' : 'Json', data) as unknown as T; - }; - - const creator = (outputAs: OutputType) => (...values: unknown[]): Observable => { - const isDelayed = outputAs === 'scale' && hashIndex !== -1 && !!values[hashIndex]; - - return new Observable((observer: Observer): VoidCallback => { - callWithRegistry(outputAs, values) - .then((value): void => { - observer.next(value); - observer.complete(); - }) - .catch((error): void => { - logErrorMessage(method, def, error); - - observer.error(error); - observer.complete(); - }); - - return (): void => { - // delete old results from cache - memoized?.unmemoize(...values); - }; - }).pipe( - publishReplay(1), // create a Replay(1) - isDelayed - ? refCountDelay() // Unsubscribe after delay - : refCount() - ); - }; - - memoized = this._memomize(creator, def); - - return memoized; - } - - // create a subscriptor, it subscribes once and resolves with the id as subscribe - private _createSubscriber ({ paramsJson, subName, subType, update }: { subType: string; subName: string; paramsJson: AnyJson[]; update: ProviderInterfaceCallback }, errorHandler: (error: Error) => void): Promise { - return new Promise((resolve, reject): void => { - this.provider - .subscribe(subType, subName, paramsJson, update) - .then(resolve) - .catch((error): void => { - errorHandler(error); - reject(error); - }); - }); - } - - private _createMethodSubscribe (section: string, method: string, def: DefinitionRpcSub): RpcInterfaceMethod { - const [updateType, subMethod, unsubMethod] = def.pubsub; - const subName = `${section}_${subMethod}`; - const unsubName = `${section}_${unsubMethod}`; - const subType = `${section}_${updateType}`; - let memoized: null | Memoized = null; - - const creator = (outputAs: OutputType) => (...values: unknown[]): Observable => { - return new Observable((observer: Observer): VoidCallback => { - // Have at least an empty promise, as used in the unsubscribe - let subscriptionPromise: Promise = Promise.resolve(null); - const registry = this.#registryDefault; - - const errorHandler = (error: Error): void => { - logErrorMessage(method, def, error); - - observer.error(error); - }; - - try { - const params = this._formatInputs(registry, null, def, values); - const paramsJson = params.map((param): AnyJson => param.toJSON()); - - const update = (error?: Error | null, result?: T): void => { - if (error) { - logErrorMessage(method, def, error); - - return; - } - - try { - observer.next( - outputAs === 'scale' - ? this._formatOutput(registry, null, method, def, params, result) as unknown as T - : registry.createType(outputAs === 'raw' ? 'Raw' : 'Json', result) as unknown as T - ); - } catch (error) { - observer.error(error); - } - }; - - subscriptionPromise = this._createSubscriber({ paramsJson, subName, subType, update }, errorHandler); - } catch (error) { - errorHandler(error); - } - - // Teardown logic - return (): void => { - // Delete from cache, so old results don't hang around - memoized?.unmemoize(...values); - - // Unsubscribe from provider - subscriptionPromise - .then((subscriptionId): Promise => - isNull(subscriptionId) - ? Promise.resolve(false) - : this.provider.unsubscribe(subType, unsubName, subscriptionId) - ) - .catch((error: Error) => logErrorMessage(method, def, error)); - }; - }).pipe(drr()); - }; - - memoized = this._memomize(creator, def); - - return memoized; - } - - private _formatInputs (registry: Registry, blockHash: Uint8Array | string | null | undefined, def: DefinitionRpc, inputs: unknown[]): Codec[] { - const reqArgCount = def.params.filter(({ isOptional }) => !isOptional).length; - const optText = reqArgCount === def.params.length - ? '' - : ` (${def.params.length - reqArgCount} optional)`; - - assert(inputs.length >= reqArgCount && inputs.length <= def.params.length, () => `Expected ${def.params.length} parameters${optText}, ${inputs.length} found instead`); - - return inputs.map((input, index): Codec => - createTypeUnsafe(registry, def.params[index].type, [input], { blockHash }) - ); - } - - private _formatOutput (registry: Registry, blockHash: Uint8Array | string | null | undefined, method: string, rpc: DefinitionRpc, params: Codec[], result?: unknown): Codec | Codec[] { - if (rpc.type === 'StorageData') { - const key = params[0] as StorageKey; - - return this._formatStorageData(registry, blockHash, key, result as string); - } else if (rpc.type === 'StorageChangeSet') { - const keys = params[0] as Vec; - - return keys - ? this._formatStorageSet(registry, (result as StorageChangeSetJSON).block, keys, (result as StorageChangeSetJSON).changes) - : registry.createType('StorageChangeSet', result); - } else if (rpc.type === 'Vec') { - const mapped = (result as StorageChangeSetJSON[]).map(({ block, changes }): [Hash, Codec[]] => [ - registry.createType('Hash', block), - this._formatStorageSet(registry, block, params[0] as Vec, changes) - ]); - - // we only query at a specific block, not a range - flatten - return method === 'queryStorageAt' - ? mapped[0][1] - : mapped as unknown as Codec[]; - } - - return createTypeUnsafe(registry, rpc.type, [result], { blockHash }); - } - - private _formatStorageData (registry: Registry, blockHash: Uint8Array | string | null | undefined, key: StorageKey, value: string | null): Codec { - const isEmpty = isNull(value); - - // we convert to Uint8Array since it maps to the raw encoding, all - // data will be correctly encoded (incl. numbers, excl. :code) - const input = isEmpty - ? null - : isTreatAsHex(key) - ? value - : u8aToU8a(value); - - return this._newType(registry, blockHash, key, input, isEmpty); - } - - private _formatStorageSet (registry: Registry, blockHash: string, keys: Vec, changes: [string, string | null][]): Codec[] { - // For StorageChangeSet, the changes has the [key, value] mappings - const withCache = keys.length !== 1; - - // multiple return values (via state.storage subscription), decode the values - // one at a time, all based on the query types. Three values can be returned - - // - Codec - There is a valid value, non-empty - // - null - The storage key is empty - return keys.reduce((results: Codec[], key: StorageKey, index): Codec[] => { - results.push(this._formatStorageSetEntry(registry, blockHash, key, changes, withCache, index)); - - return results; - }, []); - } - - private _formatStorageSetEntry (registry: Registry, blockHash: string, key: StorageKey, changes: [string, string | null][], witCache: boolean, entryIndex: number): Codec { - const hexKey = key.toHex(); - const found = changes.find(([key]) => key === hexKey); - - // if we don't find the value, this is our fallback - // - in the case of an array of values, fill the hole from the cache - // - if a single result value, don't fill - it is not an update hole - // - fallback to an empty option in all cases - const value = isUndefined(found) - ? (witCache && this.#storageCache.get(hexKey)) || null - : found[1]; - const isEmpty = isNull(value); - const input = isEmpty || isTreatAsHex(key) - ? value - : u8aToU8a(value); - - // store the retrieved result - the only issue with this cache is that there is no - // clearing of it, so very long running processes (not just a couple of hours, longer) - // will increase memory beyond what is allowed. - this.#storageCache.set(hexKey, value); - - return this._newType(registry, blockHash, key, input, isEmpty, entryIndex); - } - - private _newType (registry: Registry, blockHash: Uint8Array | string | null | undefined, key: StorageKey, input: string | Uint8Array | null, isEmpty: boolean, entryIndex = -1): Codec { - // single return value (via state.getStorage), decode the value based on the - // outputType that we have specified. Fallback to Raw on nothing - const type = key.outputType || 'Raw'; - const meta = key.meta || EMPTY_META; - const entryNum = entryIndex === -1 - ? '' - : ` entry ${entryIndex}:`; - - try { - if (meta.modifier.isOptional) { - let inner = null; - - if (!isEmpty) { - inner = createTypeUnsafe(registry, type, [input], { blockHash, isPedantic: true }); - } - - const option = new Option(registry, createClass(registry, type), inner); - - if (blockHash) { - option.createdAtHash = registry.createType('Hash', blockHash); - } - - return option; - } - - return createTypeUnsafe(registry, type, [ - isEmpty - ? meta.fallback - ? hexToU8a(meta.fallback.toHex()) - : undefined - : input - ], { blockHash, isPedantic: true }); - } catch (error) { - throw new Error(`Unable to decode storage ${key.section || 'unknown'}.${key.method || 'unknown'}:${entryNum}: ${(error as Error).message}`); - } - } -} +export * from './bundle'; diff --git a/packages/rpc-core/src/util/index.ts b/packages/rpc-core/src/util/index.ts index 703b4ce579..acd420ad49 100644 --- a/packages/rpc-core/src/util/index.ts +++ b/packages/rpc-core/src/util/index.ts @@ -2,4 +2,5 @@ // SPDX-License-Identifier: Apache-2.0 export * from './drr'; +export * from './memo'; export * from './refCountDelay'; diff --git a/packages/api-derive/src/util/memo.ts b/packages/rpc-core/src/util/memo.ts similarity index 91% rename from packages/api-derive/src/util/memo.ts rename to packages/rpc-core/src/util/memo.ts index 68b98838b0..1afcb0f555 100644 --- a/packages/api-derive/src/util/memo.ts +++ b/packages/rpc-core/src/util/memo.ts @@ -6,9 +6,10 @@ import type { Memoized } from '@polkadot/util/types'; import { Observable } from 'rxjs'; -import { drr } from '@polkadot/rpc-core/util'; import { memoize } from '@polkadot/util'; +import { drr } from './drr'; + type ObsFn = (...params: any[]) => Observable; // Wraps a derive, doing 2 things to optimize calls - @@ -16,6 +17,7 @@ type ObsFn = (...params: any[]) => Observable; // 2. wraps the observable in a drr() (which includes an unsub delay) /** @internal */ export function memo (instanceId: string, inner: ObsFn): Memoized> { + const options = { getInstanceId: () => instanceId }; const cached = memoize( (...params: any[]): Observable => new Observable((observer: Observer): TeardownLogic => { @@ -26,7 +28,7 @@ export function memo (instanceId: string, inner: ObsFn): Memoized instanceId } + options ); return cached; diff --git a/packages/rpc-provider/src/bundle.ts b/packages/rpc-provider/src/bundle.ts new file mode 100644 index 0000000000..6b2a1ec3a5 --- /dev/null +++ b/packages/rpc-provider/src/bundle.ts @@ -0,0 +1,6 @@ +// Copyright 2017-2021 @polkadot/rpc-provider authors & contributors +// SPDX-License-Identifier: Apache-2.0 + +export { HttpProvider } from './http'; +export { packageInfo } from './packageInfo'; +export { WsProvider } from './ws'; diff --git a/packages/rpc-provider/src/index.ts b/packages/rpc-provider/src/index.ts index f2d749a170..6d0520637c 100644 --- a/packages/rpc-provider/src/index.ts +++ b/packages/rpc-provider/src/index.ts @@ -3,6 +3,4 @@ import './detectPackage'; -export { HttpProvider } from './http'; -export { packageInfo } from './packageInfo'; -export { WsProvider } from './ws'; +export * from './bundle'; diff --git a/packages/typegen/src/bundle.ts b/packages/typegen/src/bundle.ts new file mode 100644 index 0000000000..79018d21d2 --- /dev/null +++ b/packages/typegen/src/bundle.ts @@ -0,0 +1,5 @@ +// Copyright 2017-2021 @polkadot/typegen authors & contributors +// SPDX-License-Identifier: Apache-2.0 + +export { packageInfo } from './packageInfo'; +export { formatType } from './util/formatting'; diff --git a/packages/typegen/src/index.ts b/packages/typegen/src/index.ts index 0b14cd7fe1..1e6bd5cf52 100644 --- a/packages/typegen/src/index.ts +++ b/packages/typegen/src/index.ts @@ -3,5 +3,4 @@ import './detectPackage'; -export { packageInfo } from './packageInfo'; -export { formatType } from './util/formatting'; +export * from './bundle'; diff --git a/packages/types-known/src/bundle.ts b/packages/types-known/src/bundle.ts new file mode 100644 index 0000000000..ed54cfd5c8 --- /dev/null +++ b/packages/types-known/src/bundle.ts @@ -0,0 +1,130 @@ +// Copyright 2017-2021 @polkadot/types-known authors & contributors +// SPDX-License-Identifier: Apache-2.0 + +import type { Text } from '@polkadot/types'; +import type { ExtDef } from '@polkadot/types/extrinsic/signedExtensions/types'; +import type { Hash } from '@polkadot/types/interfaces'; +import type { ChainUpgradeVersion, CodecHasher, DefinitionRpc, DefinitionRpcSub, OverrideModuleType, OverrideVersionedType, Registry, RegistryTypes } from '@polkadot/types/types'; +import type { BN } from '@polkadot/util'; + +import { bnToBn, isUndefined } from '@polkadot/util'; + +import typesChain from './chain'; +import typesModules from './modules'; +import typesSpec from './spec'; +import upgrades from './upgrades'; + +export { packageInfo } from './packageInfo'; + +// flatten a VersionedType[] into a Record +/** @internal */ +function filterVersions (versions: OverrideVersionedType[] = [], specVersion: number): RegistryTypes { + return versions + .filter(({ minmax: [min, max] }) => + (isUndefined(min) || specVersion >= min) && + (isUndefined(max) || specVersion <= max) + ) + .reduce((result: RegistryTypes, { types }): RegistryTypes => ({ + ...result, + ...types + }), {}); +} + +/** + * @description Get types for specific modules (metadata override) + */ +export function getModuleTypes ({ knownTypes }: Registry, section: string): OverrideModuleType { + return { + ...(typesModules[section] || {}), + ...(knownTypes.typesAlias?.[section] || {}) + }; +} + +/** + * @description Based on the chain and runtimeVersion, get the applicable signed extensions (ready for registration) + */ +export function getSpecExtensions ({ knownTypes }: Registry, chainName: Text | string, specName: Text | string): ExtDef { + const _chainName = chainName.toString(); + const _specName = specName.toString(); + + return { + ...(knownTypes.typesBundle?.spec?.[_specName]?.signedExtensions || {}), + ...(knownTypes.typesBundle?.chain?.[_chainName]?.signedExtensions || {}) + }; +} + +/** + * @description Based on the chain and runtimeVersion, get the applicable types (ready for registration) + */ +export function getSpecTypes ({ knownTypes }: Registry, chainName: Text | string, specName: Text | string, specVersion: BigInt | BN | number): RegistryTypes { + const _chainName = chainName.toString(); + const _specName = specName.toString(); + const _specVersion = bnToBn(specVersion).toNumber(); + + // The order here is always, based on - + // - spec then chain + // - typesBundle takes higher precedence + // - types is the final catch-all override + return { + ...filterVersions(typesSpec[_specName], _specVersion), + ...filterVersions(typesChain[_chainName], _specVersion), + ...filterVersions(knownTypes.typesBundle?.spec?.[_specName]?.types, _specVersion), + ...filterVersions(knownTypes.typesBundle?.chain?.[_chainName]?.types, _specVersion), + ...(knownTypes.typesSpec?.[_specName] || {}), + ...(knownTypes.typesChain?.[_chainName] || {}), + ...(knownTypes.types || {}) + }; +} + +export function getSpecHasher ({ knownTypes }: Registry, chainName: Text | string, specName: Text | string): CodecHasher | null { + const _chainName = chainName.toString(); + const _specName = specName.toString(); + + return knownTypes.hasher || knownTypes.typesBundle?.chain?.[_chainName]?.hasher || knownTypes.typesBundle?.spec?.[_specName]?.hasher || null; +} + +/** + * @description Based on the chain and runtimeVersion, get the applicable rpc definitions (ready for registration) + */ +export function getSpecRpc ({ knownTypes }: Registry, chainName: Text | string, specName: Text | string): Record> { + const _chainName = chainName.toString(); + const _specName = specName.toString(); + + return { + ...(knownTypes.typesBundle?.spec?.[_specName]?.rpc || {}), + ...(knownTypes.typesBundle?.chain?.[_chainName]?.rpc || {}) + }; +} + +/** + * @description Based on the chain and runtimeVersion, get the applicable alias definitions (ready for registration) + */ +export function getSpecAlias ({ knownTypes }: Registry, chainName: Text | string, specName: Text | string): Record { + const _chainName = chainName.toString(); + const _specName = specName.toString(); + + // as per versions, first spec, then chain then finally non-versioned + return { + ...(knownTypes.typesBundle?.spec?.[_specName]?.alias || {}), + ...(knownTypes.typesBundle?.chain?.[_chainName]?.alias || {}), + ...(knownTypes.typesAlias || {}) + }; +} + +/** + * @description Returns a version record for known chains where upgrades are being tracked + */ +export function getUpgradeVersion (genesisHash: Hash, blockNumber: BN): [ChainUpgradeVersion | undefined, ChainUpgradeVersion | undefined] { + const known = upgrades.find((u) => genesisHash.eq(u.genesisHash)); + + return known + ? [ + known.versions.reduce((last: ChainUpgradeVersion | undefined, version): ChainUpgradeVersion | undefined => { + return blockNumber.gt(version.blockNumber) + ? version + : last; + }, undefined), + known.versions.find((version) => blockNumber.lte(version.blockNumber)) + ] + : [undefined, undefined]; +} diff --git a/packages/types-known/src/index.ts b/packages/types-known/src/index.ts index ce6f750287..f2a7044671 100644 --- a/packages/types-known/src/index.ts +++ b/packages/types-known/src/index.ts @@ -3,130 +3,4 @@ import './detectPackage'; -import type { Text } from '@polkadot/types'; -import type { ExtDef } from '@polkadot/types/extrinsic/signedExtensions/types'; -import type { Hash } from '@polkadot/types/interfaces'; -import type { ChainUpgradeVersion, CodecHasher, DefinitionRpc, DefinitionRpcSub, OverrideModuleType, OverrideVersionedType, Registry, RegistryTypes } from '@polkadot/types/types'; -import type { BN } from '@polkadot/util'; - -import { bnToBn, isUndefined } from '@polkadot/util'; - -import typesChain from './chain'; -import typesModules from './modules'; -import typesSpec from './spec'; -import upgrades from './upgrades'; - -export { packageInfo } from './packageInfo'; - -// flatten a VersionedType[] into a Record -/** @internal */ -function filterVersions (versions: OverrideVersionedType[] = [], specVersion: number): RegistryTypes { - return versions - .filter(({ minmax: [min, max] }) => - (isUndefined(min) || specVersion >= min) && - (isUndefined(max) || specVersion <= max) - ) - .reduce((result: RegistryTypes, { types }): RegistryTypes => ({ - ...result, - ...types - }), {}); -} - -/** - * @description Get types for specific modules (metadata override) - */ -export function getModuleTypes ({ knownTypes }: Registry, section: string): OverrideModuleType { - return { - ...(typesModules[section] || {}), - ...(knownTypes.typesAlias?.[section] || {}) - }; -} - -/** - * @description Based on the chain and runtimeVersion, get the applicable signed extensions (ready for registration) - */ -export function getSpecExtensions ({ knownTypes }: Registry, chainName: Text | string, specName: Text | string): ExtDef { - const _chainName = chainName.toString(); - const _specName = specName.toString(); - - return { - ...(knownTypes.typesBundle?.spec?.[_specName]?.signedExtensions || {}), - ...(knownTypes.typesBundle?.chain?.[_chainName]?.signedExtensions || {}) - }; -} - -/** - * @description Based on the chain and runtimeVersion, get the applicable types (ready for registration) - */ -export function getSpecTypes ({ knownTypes }: Registry, chainName: Text | string, specName: Text | string, specVersion: BigInt | BN | number): RegistryTypes { - const _chainName = chainName.toString(); - const _specName = specName.toString(); - const _specVersion = bnToBn(specVersion).toNumber(); - - // The order here is always, based on - - // - spec then chain - // - typesBundle takes higher precedence - // - types is the final catch-all override - return { - ...filterVersions(typesSpec[_specName], _specVersion), - ...filterVersions(typesChain[_chainName], _specVersion), - ...filterVersions(knownTypes.typesBundle?.spec?.[_specName]?.types, _specVersion), - ...filterVersions(knownTypes.typesBundle?.chain?.[_chainName]?.types, _specVersion), - ...(knownTypes.typesSpec?.[_specName] || {}), - ...(knownTypes.typesChain?.[_chainName] || {}), - ...(knownTypes.types || {}) - }; -} - -export function getSpecHasher ({ knownTypes }: Registry, chainName: Text | string, specName: Text | string): CodecHasher | null { - const _chainName = chainName.toString(); - const _specName = specName.toString(); - - return knownTypes.hasher || knownTypes.typesBundle?.chain?.[_chainName]?.hasher || knownTypes.typesBundle?.spec?.[_specName]?.hasher || null; -} - -/** - * @description Based on the chain and runtimeVersion, get the applicable rpc definitions (ready for registration) - */ -export function getSpecRpc ({ knownTypes }: Registry, chainName: Text | string, specName: Text | string): Record> { - const _chainName = chainName.toString(); - const _specName = specName.toString(); - - return { - ...(knownTypes.typesBundle?.spec?.[_specName]?.rpc || {}), - ...(knownTypes.typesBundle?.chain?.[_chainName]?.rpc || {}) - }; -} - -/** - * @description Based on the chain and runtimeVersion, get the applicable alias definitions (ready for registration) - */ -export function getSpecAlias ({ knownTypes }: Registry, chainName: Text | string, specName: Text | string): Record { - const _chainName = chainName.toString(); - const _specName = specName.toString(); - - // as per versions, first spec, then chain then finally non-versioned - return { - ...(knownTypes.typesBundle?.spec?.[_specName]?.alias || {}), - ...(knownTypes.typesBundle?.chain?.[_chainName]?.alias || {}), - ...(knownTypes.typesAlias || {}) - }; -} - -/** - * @description Returns a version record for known chains where upgrades are being tracked - */ -export function getUpgradeVersion (genesisHash: Hash, blockNumber: BN): [ChainUpgradeVersion | undefined, ChainUpgradeVersion | undefined] { - const known = upgrades.find((u) => genesisHash.eq(u.genesisHash)); - - return known - ? [ - known.versions.reduce((last: ChainUpgradeVersion | undefined, version): ChainUpgradeVersion | undefined => { - return blockNumber.gt(version.blockNumber) - ? version - : last; - }, undefined), - known.versions.find((version) => blockNumber.lte(version.blockNumber)) - ] - : [undefined, undefined]; -} +export * from './bundle'; diff --git a/packages/types/src/bundle.ts b/packages/types/src/bundle.ts new file mode 100644 index 0000000000..28705c53e0 --- /dev/null +++ b/packages/types/src/bundle.ts @@ -0,0 +1,8 @@ +// Copyright 2017-2021 @polkadot/types authors & contributors +// SPDX-License-Identifier: Apache-2.0 + +export * from './codec'; +export * from './create'; +export * from './index.types'; +export { packageInfo } from './packageInfo'; +export { TypeDefInfo } from './types'; diff --git a/packages/types/src/classes.ts b/packages/types/src/classes.ts deleted file mode 100644 index f96e5cfd4f..0000000000 --- a/packages/types/src/classes.ts +++ /dev/null @@ -1,6 +0,0 @@ -// Copyright 2017-2021 @polkadot/types authors & contributors -// SPDX-License-Identifier: Apache-2.0 - -import * as Classes from './index.types'; - -export type CodecTypes = keyof typeof Classes; diff --git a/packages/types/src/primitive/DoNotConstruct.spec.ts b/packages/types/src/codec/DoNotConstruct.spec.ts similarity index 100% rename from packages/types/src/primitive/DoNotConstruct.spec.ts rename to packages/types/src/codec/DoNotConstruct.spec.ts diff --git a/packages/types/src/codec/DoNotConstruct.ts b/packages/types/src/codec/DoNotConstruct.ts new file mode 100644 index 0000000000..6de6249d79 --- /dev/null +++ b/packages/types/src/codec/DoNotConstruct.ts @@ -0,0 +1,82 @@ +// Copyright 2017-2021 @polkadot/types authors & contributors +// SPDX-License-Identifier: Apache-2.0 + +import type { CodecHash, Hash } from '../interfaces/runtime'; +import type { AnyJson, Codec, Constructor, Registry } from '../types'; + +/** + * @name DoNotConstruct + * @description + * An unknown type that fails on construction with the type info + */ +export class DoNotConstruct implements Codec { + public readonly registry: Registry; + + public createdAtHash?: Hash; + + #neverError: Error; + + constructor (registry: Registry, typeName = 'DoNotConstruct') { + this.registry = registry; + this.#neverError = new Error(`Cannot construct unknown type ${typeName}`); + + throw this.#neverError; + } + + public static with (typeName?: string): Constructor { + return class extends DoNotConstruct { + constructor (registry: Registry) { + super(registry, typeName); + } + }; + } + + /** + * @description The length of the value when encoded as a Uint8Array + */ + public get encodedLength (): number { + throw this.#neverError; + } + + /** + * @description returns a hash of the contents + */ + public get hash (): CodecHash { + throw this.#neverError; + } + + /** + * @description Checks if the value is an empty value (always true) + */ + public get isEmpty (): boolean { + throw this.#neverError; + } + + eq (): boolean { + throw this.#neverError; + } + + toHex (): string { + throw this.#neverError; + } + + toHuman (): AnyJson { + throw this.#neverError; + } + + toJSON (): AnyJson { + throw this.#neverError; + } + + toRawType (): string { + throw this.#neverError; + } + + toString (): string { + throw this.#neverError; + } + + toU8a (): Uint8Array { + throw this.#neverError; + } +} diff --git a/packages/types/src/codec/index.ts b/packages/types/src/codec/index.ts index c6207d497e..6bdab0f57b 100644 --- a/packages/types/src/codec/index.ts +++ b/packages/types/src/codec/index.ts @@ -11,6 +11,7 @@ export { BTreeMap } from './BTreeMap'; export { BTreeSet } from './BTreeSet'; export { Compact } from './Compact'; // export { CodecDate, CodecDate as Date } from './Date'; +export { DoNotConstruct } from './DoNotConstruct'; export { Enum } from './Enum'; export { HashMap } from './HashMap'; export { Int } from './Int'; diff --git a/packages/types/src/create/createClass.ts b/packages/types/src/create/createClass.ts index 5a8801b638..2911e64634 100644 --- a/packages/types/src/create/createClass.ts +++ b/packages/types/src/create/createClass.ts @@ -7,8 +7,7 @@ import type { FromReg, TypeDef } from './types'; import { assert, isNumber, isUndefined, stringify } from '@polkadot/util'; -import { BTreeMap, BTreeSet, CodecSet, Compact, Enum, HashMap, Int, Option, Result, Struct, Tuple, U8aFixed, UInt, Vec, VecFixed } from '../codec'; -import { DoNotConstruct } from '../primitive'; +import { BTreeMap, BTreeSet, CodecSet, Compact, DoNotConstruct, Enum, HashMap, Int, Option, Result, Struct, Tuple, U8aFixed, UInt, Vec, VecFixed } from '../codec'; import { getTypeDef } from './getTypeDef'; import { TypeDefInfo } from './types'; diff --git a/packages/types/src/create/registry.spec.ts b/packages/types/src/create/registry.spec.ts index 826ed1b381..8ea275db12 100644 --- a/packages/types/src/create/registry.spec.ts +++ b/packages/types/src/create/registry.spec.ts @@ -8,8 +8,8 @@ import type { Codec, Constructor } from '../types'; import { isChildClass, u8aToU8a } from '@polkadot/util'; import { keccakAsU8a } from '@polkadot/util-crypto'; -import { Struct } from '../codec'; -import { DoNotConstruct, Text, U32 } from '../primitive'; +import { DoNotConstruct, Struct } from '../codec'; +import { Text, U32 } from '../primitive'; import { TypeRegistry } from '.'; describe('TypeRegistry', (): void => { diff --git a/packages/types/src/create/registry.ts b/packages/types/src/create/registry.ts index 6fad8909a4..90883a2cdd 100644 --- a/packages/types/src/create/registry.ts +++ b/packages/types/src/create/registry.ts @@ -13,13 +13,13 @@ import { Metadata } from '@polkadot/metadata/Metadata'; import { assert, assertReturn, BN_ZERO, formatBalance, isFunction, isString, isU8a, logger, stringCamelCase, stringify, u8aToHex } from '@polkadot/util'; import { blake2AsU8a } from '@polkadot/util-crypto'; +import { DoNotConstruct } from '../codec/DoNotConstruct'; import { Json } from '../codec/Json'; import { Raw } from '../codec/Raw'; import { expandExtensionTypes, fallbackExtensions, findUnknownExtensions } from '../extrinsic/signedExtensions'; import { GenericEventData } from '../generic/Event'; import * as baseTypes from '../index.types'; import * as definitions from '../interfaces/definitions'; -import { DoNotConstruct } from '../primitive/DoNotConstruct'; import { createClass, getTypeClass } from './createClass'; import { createType } from './createType'; import { getTypeDef } from './getTypeDef'; diff --git a/packages/types/src/index.ts b/packages/types/src/index.ts index f27968cd91..f2d45c6b0b 100644 --- a/packages/types/src/index.ts +++ b/packages/types/src/index.ts @@ -3,7 +3,4 @@ import './detectPackage'; -export * from './codec'; -export * from './create'; -export * from './index.types'; -export { packageInfo } from './packageInfo'; +export * from './bundle'; diff --git a/packages/types/src/primitive/DoNotConstruct.ts b/packages/types/src/primitive/DoNotConstruct.ts deleted file mode 100644 index a2c240bc7a..0000000000 --- a/packages/types/src/primitive/DoNotConstruct.ts +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright 2017-2021 @polkadot/types authors & contributors -// SPDX-License-Identifier: Apache-2.0 - -import type { Constructor, Registry } from '../types'; - -import { Null } from './Null'; - -/** - * @name DoNotConstruct - * @description - * An unknown type that fails on construction with the type info - */ -export class DoNotConstruct extends Null { - constructor (registry: Registry, typeName = 'DoNotConstruct') { - super(registry); - - throw new Error(`Cannot construct unknown type ${typeName}`); - } - - public static with (typeName?: string): Constructor { - return class extends DoNotConstruct { - constructor (registry: Registry) { - super(registry, typeName); - } - }; - } -} diff --git a/packages/types/src/primitive/StorageKey.ts b/packages/types/src/primitive/StorageKey.ts index 34bde2954a..6a8fc41118 100644 --- a/packages/types/src/primitive/StorageKey.ts +++ b/packages/types/src/primitive/StorageKey.ts @@ -2,12 +2,12 @@ // SPDX-License-Identifier: Apache-2.0 import type { StorageEntryMetadataLatest, StorageEntryTypeLatest, StorageHasher } from '../interfaces/metadata'; +import type { AllHashers } from '../interfaces/metadata/definitions'; import type { AnyJson, AnyTuple, AnyU8a, Codec, InterfaceTypes, IStorageKey, Registry } from '../types'; import type { StorageEntry } from './types'; import { assert, isFunction, isString, isU8a } from '@polkadot/util'; -import { AllHashers } from '../interfaces/metadata/definitions'; import { Bytes } from './Bytes'; interface Decoded { diff --git a/packages/types/src/primitive/index.ts b/packages/types/src/primitive/index.ts index 015cbf95b4..b8b2d29da5 100644 --- a/packages/types/src/primitive/index.ts +++ b/packages/types/src/primitive/index.ts @@ -8,7 +8,6 @@ export { BitVec } from './BitVec'; export { bool, bool as Bool } from './Bool'; export { Bytes } from './Bytes'; export { Data } from './Data'; -export { DoNotConstruct } from './DoNotConstruct'; export { i8, i8 as I8 } from './I8'; export { i16, i16 as I16 } from './I16'; export { i32, i32 as I32 } from './I32';