Rebrand: polkadot → pezkuwi, substrate → bizinikiwi, kusama → dicle

This commit is contained in:
Kurdistan Tech Ministry committed 2026-01-07 02:29:40 +03:00
commit d5f038faea
1383 files changed
+1088018

No files matched your search

@@ -0,0 +1,54 @@
// Copyright 2017-2025 @pezkuwi/api authors & contributors
// SPDX-License-Identifier: Apache-2.0
/// <reference types="@pezkuwi/dev-test/globals.d.ts" />
import { augmentObject } from './augmentObject.js';
describe('augmentObject', (): void => {
let spy: ReturnType<typeof jest.spyOn>;
beforeEach((): void => {
spy = jest.spyOn(console, 'warn');
});
afterEach((): void => {
spy.mockRestore();
});
it('logs added/removed sections and methods', (): void => {
augmentObject(
'test',
{ bar: { b: 1 }, foo: { d: 1, f: 1 }, new: { z: 1 } },
{ bar: { a: 1, c: 1 }, baz: { a: 1 }, foo: { c: 1, f: 1 } }
);
expect(spy).toHaveBeenCalledWith(
expect.anything(),
expect.stringMatching(/API\/AUGMENT/),
'api.test: Found 1 added and 1 removed modules:\n\t added: new\n\tremoved: baz'
);
expect(spy).toHaveBeenCalledWith(
expect.anything(),
expect.stringMatching(/API\/AUGMENT/),
'api.test: Found 2 added and 3 removed calls:\n\t added: bar.b, foo.d\n\tremoved: bar.a, bar.c, foo.c'
);
});
it('copies sections to the dest', (): void => {
const src = { bar: { b: 1 }, foo: { a: 1 } };
expect(augmentObject('test', src, {})).toEqual(src);
});
it('adds fields to existing sections', (): void => {
const src = { bar: { b: 1 }, foo: { a: 1 } };
const dst = { baz: { c: 1 }, foo: { b: 2 } };
expect(augmentObject('test', src, dst)).toEqual({
bar: { b: 1 },
baz: { c: 1 },
foo: { a: 1, b: 2 }
});
});
});
+112
View File
@@ -0,0 +1,112 @@
// Copyright 2017-2025 @pezkuwi/api authors & contributors
// SPDX-License-Identifier: Apache-2.0
import { lazyMethods, logger, objectClear } from '@pezkuwi/util';
type Sections <T> = Record<string, Methods<T>>;
type Methods <T> = Record<string, T>;
type StringsStrings = [string[], string[]];
const l = logger('api/augment');
function logLength (type: 'added' | 'removed', values: string[], and: string[] = []): string {
return values.length
? ` ${values.length} ${type}${and.length ? ' and' : ''}`
: '';
}
function logValues (type: 'added' | 'removed', values: string[]): string {
return values.length
? `\n\t${type.padStart(7)}: ${values.sort().join(', ')}`
: '';
}
// log details to console
function warn (prefix: string, type: 'calls' | 'modules', [added, removed]: StringsStrings): void {
if (added.length || removed.length) {
l.warn(`api.${prefix}: Found${logLength('added', added, removed)}${logLength('removed', removed)} ${type}:${logValues('added', added)}${logValues('removed', removed)}`);
}
}
function findSectionExcludes (a: string[], b: string[]): string[] {
return a.filter((s) => !b.includes(s));
}
function findSectionIncludes (a: string[], b: string[]): string[] {
return a.filter((s) => b.includes(s));
}
function extractSections <T> (src: Sections<T>, dst: Sections<T>): StringsStrings {
const srcSections = Object.keys(src);
const dstSections = Object.keys(dst);
return [
findSectionExcludes(srcSections, dstSections),
findSectionExcludes(dstSections, srcSections)
];
}
function findMethodExcludes <T> (src: Sections<T>, dst: Sections<T>): string[] {
const srcSections = Object.keys(src);
const dstSections = findSectionIncludes(Object.keys(dst), srcSections);
const excludes: string[] = [];
for (let s = 0, scount = dstSections.length; s < scount; s++) {
const section = dstSections[s];
const srcMethods = Object.keys(src[section]);
const dstMethods = Object.keys(dst[section]);
for (let d = 0, mcount = dstMethods.length; d < mcount; d++) {
const method = dstMethods[d];
if (!srcMethods.includes(method)) {
excludes.push(`${section}.${method}`);
}
}
}
return excludes;
}
function extractMethods <T> (src: Sections<T>, dst: Sections<T>): StringsStrings {
return [
findMethodExcludes(dst, src),
findMethodExcludes(src, dst)
];
}
/**
* @description Takes a decorated api section (e.g. api.tx) and augment it with the details. It does not override what is
* already available, but rather just adds new missing items into the result object.
* @internal
*/
export function augmentObject <T> (prefix: string | null, src: Sections<T>, dst: Sections<T>, fromEmpty = false): Sections<T> {
fromEmpty && objectClear(dst);
// NOTE: This part is slightly problematic since it will get the
// values for at least all the sections and the names of the methods
// (Since methods won't be decorated before lazy, this _may_ be ok)
if (prefix && Object.keys(dst).length) {
warn(prefix, 'modules', extractSections(src, dst));
warn(prefix, 'calls', extractMethods(src, dst));
}
const sections = Object.keys(src);
for (let i = 0, count = sections.length; i < count; i++) {
const section = sections[i];
const methods = src[section];
// We don't set here with a lazy interface, we decorate based
// on the top-level structure (this bypasses adding lazy onto lazy)
if (!dst[section]) {
dst[section] = {};
}
lazyMethods(dst[section], Object.keys(methods), (m: string) => methods[m]);
}
return dst;
}
+43
View File
@@ -0,0 +1,43 @@
// Copyright 2017-2025 @pezkuwi/api authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { ExactDerive } from '@pezkuwi/api-derive';
import type { AnyFunction } from '@pezkuwi/types/types';
import type { ApiTypes, DecorateMethod, MethodResult } from '../types/index.js';
import { lazyDeriveSection } from '@pezkuwi/api-derive';
type AnyDeriveSection = Record<string, AnyFunction>;
// Most generic typings for `api.derive.*.*`
type AnyDerive = Record<string, AnyDeriveSection>;
// Exact typings for a particular section `api.derive.section.*`
type DeriveSection<ApiType extends ApiTypes, Section extends AnyDeriveSection> = {
[M in keyof Section]: MethodResult<ApiType, Section[M]>
};
// Exact typings for all sections `api.derive.*.*`
export type AllDerives<ApiType extends ApiTypes> = {
[S in keyof ExactDerive]: DeriveSection<ApiType, ExactDerive[S]>
};
/**
* This is a section decorator which keeps all type information.
*/
export function decorateDeriveSections<ApiType extends ApiTypes> (decorateMethod: DecorateMethod<ApiType>, derives: AnyDerive): AllDerives<ApiType> {
const getKeys = (s: string) =>
Object.keys(derives[s]);
const creator = (s: string, m: string) =>
decorateMethod(derives[s][m]) as AnyFunction;
const result: AnyDerive = {};
const names = Object.keys(derives);
for (let i = 0, count = names.length; i < count; i++) {
lazyDeriveSection(result, names[i], getKeys, creator);
}
return result as AllDerives<ApiType>;
}
+34
View File
@@ -0,0 +1,34 @@
// Copyright 2017-2025 @pezkuwi/api authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { BlockNumber, EventRecord, ExtrinsicStatus, H256, SignedBlock } from '@pezkuwi/types/interfaces';
import { isCompact } from '@pezkuwi/util';
import { l } from './logging.js';
export function filterEvents (txHash: H256, { block: { extrinsics, header } }: SignedBlock, allEvents: EventRecord[], status: ExtrinsicStatus): { events?: EventRecord[], txIndex?: number, blockNumber?: BlockNumber } {
// extrinsics to hashes
for (const [txIndex, x] of extrinsics.entries()) {
if (x.hash.eq(txHash)) {
return {
blockNumber: isCompact<BlockNumber>(header.number) ? header.number.unwrap() : header.number,
events: allEvents.filter(({ phase }) =>
phase.isApplyExtrinsic &&
phase.asApplyExtrinsic.eqn(txIndex)
),
txIndex
};
}
}
// if we do get the block after finalized, it _should_ be there
// only warn on filtering with isInBlock (finalization finalizes after)
if (status.isInBlock) {
const allHashes = extrinsics.map((x) => x.hash.toHex());
l.warn(`block ${header.hash.toHex()}: Unable to find extrinsic ${txHash.toHex()} inside ${allHashes.join(', ')}`);
}
return {};
}
+10
View File
@@ -0,0 +1,10 @@
// Copyright 2017-2025 @pezkuwi/api authors & contributors
// SPDX-License-Identifier: Apache-2.0
// all named
export { filterEvents } from './filterEvents.js';
export { isKeyringPair } from './isKeyringPair.js';
export { l } from './logging.js';
// all starred
export * from './decorate.js';
+11
View File
@@ -0,0 +1,11 @@
// Copyright 2017-2025 @pezkuwi/api authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { AccountId, Address } from '@pezkuwi/types/interfaces';
import type { IKeyringPair } from '@pezkuwi/types/types';
import { isFunction } from '@pezkuwi/util';
export function isKeyringPair (account: string | IKeyringPair | AccountId | Address): account is IKeyringPair {
return isFunction((account as IKeyringPair).sign);
}
+6
View File
@@ -0,0 +1,6 @@
// Copyright 2017-2025 @pezkuwi/api authors & contributors
// SPDX-License-Identifier: Apache-2.0
import { logger } from '@pezkuwi/util';
export const l = /*#__PURE__*/ logger('api/util');
+72
View File
@@ -0,0 +1,72 @@
// Copyright 2017-2025 @pezkuwi/api authors & contributors
// SPDX-License-Identifier: Apache-2.0
/// <reference types="@pezkuwi/dev-test/globals.d.ts" />
import { decorateStorage, Metadata, TypeRegistry } from '@pezkuwi/types';
import metaStatic from '@pezkuwi/types-support/metadata/static-bizinikiwi';
import { extractStorageArgs } from './validate.js';
describe('extractStorageArgs', (): void => {
const registry = new TypeRegistry();
const metadata = new Metadata(registry, metaStatic);
registry.setMetadata(metadata);
const storage = decorateStorage(registry, metadata.asLatest, metadata.version);
it('validates no-arg plain', (): void => {
expect(
extractStorageArgs(registry, storage['timestamp']['now'], [])
).toEqual([storage['timestamp']['now'], []]);
});
it('validates no-arg plain (with undefined, undefined)', (): void => {
expect(
extractStorageArgs(registry, storage['timestamp']['now'], [undefined, undefined])
).toEqual([storage['timestamp']['now'], []]);
});
it('validates no-arg plain (failing when there are args)', (): void => {
expect(
() => extractStorageArgs(registry, storage['timestamp']['now'], [123, 456])
).toThrow('timestamp.now() does not take any arguments, 2 found');
});
it('validates map, 1 arg', (): void => {
expect(
extractStorageArgs(registry, storage['staking']['payee'], ['abc'])
).toEqual([storage['staking']['payee'], ['abc']]);
});
it('validates map, 1 arg (failing with no args)', (): void => {
expect(
() => extractStorageArgs(registry, storage['staking']['payee'], [])
).toThrow('staking.payee(AccountId32) is a map, requiring 1 arguments, 0 found');
});
it('validates map, 1 arg (failing with more args)', (): void => {
expect(
() => extractStorageArgs(registry, storage['staking']['payee'], ['abc', 'def'])
).toThrow('staking.payee(AccountId32) is a map, requiring 1 arguments, 2 found');
});
it('validates doublemap, 2 args', (): void => {
expect(
extractStorageArgs(registry, storage['staking']['erasStakers'], [1, '0x1234'])
).toEqual([storage['staking']['erasStakers'], [1, '0x1234']]);
});
it('validates doublemap, 2 args (failing with no args)', (): void => {
expect(
() => extractStorageArgs(registry, storage['staking']['erasStakers'], [])
).toThrow('staking.erasStakers(u32, AccountId32) is a map, requiring 2 arguments, 0 found');
});
it('validates doublemap, 2 args (failing with 1 arg)', (): void => {
expect(
() => extractStorageArgs(registry, storage['staking']['erasStakers'], [123])
).toThrow('staking.erasStakers(u32, AccountId32) is a map, requiring 2 arguments, 1 found');
});
});
+36
View File
@@ -0,0 +1,36 @@
// Copyright 2017-2025 @pezkuwi/api authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { SiLookupTypeId } from '@pezkuwi/types/interfaces';
import type { StorageEntry } from '@pezkuwi/types/primitive/types';
import type { Registry } from '@pezkuwi/types/types';
import { isUndefined } from '@pezkuwi/util';
function sig ({ lookup }: Registry, { method, section }: StorageEntry, args: SiLookupTypeId[]): string {
return `${section}.${method}(${args.map((a) => lookup.getTypeDef(a).type).join(', ')})`;
}
// sets up the arguments in the form of [creator, args] ready to be used in a storage
// call. Additionally, it verifies that the correct number of arguments have been passed
export function extractStorageArgs (registry: Registry, creator: StorageEntry, _args: unknown[]): [StorageEntry, unknown[]] {
const args = _args.filter((a) => !isUndefined(a));
if (creator.meta.type.isPlain) {
if (args.length !== 0) {
throw new Error(`${sig(registry, creator, [])} does not take any arguments, ${args.length} found`);
}
} else {
const { hashers, key } = creator.meta.type.asMap;
const keys = hashers.length === 1
? [key]
: registry.lookup.getSiType(key).def.asTuple.map((t) => t);
if (args.length !== keys.length) {
throw new Error(`${sig(registry, creator, keys)} is a map, requiring ${keys.length} arguments, ${args.length} found`);
}
}
// pass as tuple
return [creator, args];
}