@pezkuwi/rpc-core 16.5.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,55 @@
1
+ // Copyright 2017-2025 @polkadot/rpc-core authors & contributors
2
+ // SPDX-License-Identifier: Apache-2.0
3
+
4
+ /// <reference types="@pezkuwi/dev-test/globals.d.ts" />
5
+
6
+ import type { ProviderInterface } from '@pezkuwi/rpc-provider/types';
7
+
8
+ import { MockProvider } from '@pezkuwi/rpc-provider/mock';
9
+ import { TypeRegistry } from '@pezkuwi/types/create';
10
+ import { isFunction } from '@pezkuwi/util';
11
+
12
+ import { RpcCore } from './index.js';
13
+
14
+ describe('Api', (): void => {
15
+ const registry = new TypeRegistry();
16
+
17
+ it('requires a provider with a send method', (): void => {
18
+ expect(
19
+ () => new RpcCore('234', registry, { provider: {} as unknown as ProviderInterface })
20
+ ).toThrow(/Expected Provider/);
21
+ });
22
+
23
+ it('allows for the definition of user RPCs', async () => {
24
+ const provider = new MockProvider(registry);
25
+ const rpc = new RpcCore('567', registry, {
26
+ provider,
27
+ userRpc: {
28
+ testing: {
29
+ foo: {
30
+ description: 'foo',
31
+ params: [{ name: 'bar', type: 'u32' }],
32
+ type: 'Balance'
33
+ }
34
+ }
35
+ }
36
+ });
37
+
38
+ expect(isFunction((rpc as unknown as { testing: { foo: boolean } }).testing.foo)).toBe(true);
39
+ expect(rpc.sections.includes('testing')).toBe(true);
40
+ expect(rpc.mapping.get('testing_foo')).toEqual({
41
+ description: 'foo',
42
+ isSubscription: false,
43
+ jsonrpc: 'testing_foo',
44
+ method: 'foo',
45
+ params: [{
46
+ name: 'bar',
47
+ type: 'u32'
48
+ }],
49
+ section: 'testing',
50
+ type: 'Balance'
51
+ });
52
+
53
+ await provider.disconnect();
54
+ });
55
+ });
package/src/index.ts ADDED
@@ -0,0 +1,6 @@
1
+ // Copyright 2017-2025 @polkadot/rpc-core authors & contributors
2
+ // SPDX-License-Identifier: Apache-2.0
3
+
4
+ import './packageDetect.js';
5
+
6
+ export * from './bundle.js';
@@ -0,0 +1,75 @@
1
+ // Copyright 2017-2025 @polkadot/rpc-core authors & contributors
2
+ // SPDX-License-Identifier: Apache-2.0
3
+
4
+ /// <reference types="@pezkuwi/dev-test/globals.d.ts" />
5
+
6
+ import type { ProviderInterface } from '@pezkuwi/rpc-provider/types';
7
+ import type { DefinitionRpc } from '@pezkuwi/types/types';
8
+
9
+ import { TypeRegistry } from '@pezkuwi/types/create';
10
+
11
+ import { RpcCore } from './index.js';
12
+
13
+ describe('methodSend', (): void => {
14
+ const registry = new TypeRegistry();
15
+ let rpc: RpcCore;
16
+ let methods: { blah: DefinitionRpc; bleh: DefinitionRpc };
17
+ let provider: ProviderInterface;
18
+
19
+ beforeEach((): void => {
20
+ methods = {
21
+ blah: {
22
+ description: 'test',
23
+ params: [
24
+ { name: 'foo', type: 'Bytes' }
25
+ ],
26
+ type: 'Bytes'
27
+ },
28
+ bleh: {
29
+ description: 'test',
30
+ params: [],
31
+ type: 'Bytes'
32
+ }
33
+ };
34
+
35
+ provider = {
36
+ send: jest.fn((_method: string, params: unknown[]): Promise<unknown> =>
37
+ Promise.resolve(params[0])
38
+ )
39
+ } as unknown as ProviderInterface;
40
+
41
+ rpc = new RpcCore('987', registry, { provider });
42
+ });
43
+
44
+ it('checks for mismatched parameters', async (): Promise<void> => {
45
+ // private method
46
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment,@typescript-eslint/no-unsafe-call,@typescript-eslint/no-unsafe-member-access
47
+ const method = (rpc as any)._createMethodSend('test', 'bleh', methods.bleh);
48
+
49
+ await new Promise<boolean>((resolve) => {
50
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-call,@typescript-eslint/no-unsafe-member-access
51
+ method(1).subscribe(
52
+ (): void => undefined,
53
+ (error: Error): void => {
54
+ expect(error.message).toMatch(/parameters, 1 found instead/);
55
+ resolve(true);
56
+ });
57
+ });
58
+ });
59
+
60
+ it('calls the provider with the correct parameters', async (): Promise<void> => {
61
+ // private method
62
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment,@typescript-eslint/no-unsafe-call,@typescript-eslint/no-unsafe-member-access
63
+ const method = (rpc as any)._createMethodSend('test', 'blah', methods.blah);
64
+
65
+ await new Promise<boolean>((resolve) => {
66
+ // Args are length-prefixed, because it's a Bytes
67
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-call,@typescript-eslint/no-unsafe-member-access
68
+ method(new Uint8Array([2 << 2, 0x12, 0x34])).subscribe((): void => {
69
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
70
+ expect(provider.send).toHaveBeenCalledWith('test_blah', ['0x1234'], false);
71
+ resolve(true);
72
+ });
73
+ });
74
+ });
75
+ });
package/src/mod.ts ADDED
@@ -0,0 +1,4 @@
1
+ // Copyright 2017-2025 @polkadot/rpc-core authors & contributors
2
+ // SPDX-License-Identifier: Apache-2.0
3
+
4
+ export * from './index.js';
@@ -0,0 +1,13 @@
1
+ // Copyright 2017-2025 @polkadot/rpc-core authors & contributors
2
+ // SPDX-License-Identifier: Apache-2.0
3
+
4
+ // Do not edit, auto-generated by @polkadot/dev
5
+ // (packageInfo imports will be kept as-is, user-editable)
6
+
7
+ import { packageInfo as providerInfo } from '@pezkuwi/rpc-provider/packageInfo';
8
+ import { packageInfo as typesInfo } from '@pezkuwi/types/packageInfo';
9
+ import { detectPackage } from '@pezkuwi/util';
10
+
11
+ import { packageInfo } from './packageInfo.js';
12
+
13
+ detectPackage(packageInfo, null, [providerInfo, typesInfo]);
@@ -0,0 +1,6 @@
1
+ // Copyright 2017-2025 @polkadot/rpc-core authors & contributors
2
+ // SPDX-License-Identifier: Apache-2.0
3
+
4
+ // Do not edit, auto-generated by @polkadot/dev
5
+
6
+ export const packageInfo = { name: '@pezkuwi/rpc-core', path: 'auto', type: 'auto', version: '16.5.5' };
@@ -0,0 +1,73 @@
1
+ // Copyright 2017-2025 @polkadot/rpc-core authors & contributors
2
+ // SPDX-License-Identifier: Apache-2.0
3
+
4
+ /// <reference types="@pezkuwi/dev-test/globals.d.ts" />
5
+
6
+ import type { RpcInterface } from './types/index.js';
7
+
8
+ import { MockProvider } from '@pezkuwi/rpc-provider/mock';
9
+ import { TypeRegistry } from '@pezkuwi/types/create';
10
+
11
+ import { RpcCore } from './index.js';
12
+
13
+ describe('replay', (): void => {
14
+ const registry = new TypeRegistry();
15
+ let rpc: RpcCore & RpcInterface;
16
+ let provider: MockProvider;
17
+
18
+ beforeEach((): void => {
19
+ provider = new MockProvider(registry);
20
+ rpc = new RpcCore('653', registry, { provider }) as (RpcCore & RpcInterface);
21
+ });
22
+
23
+ afterEach(async () => {
24
+ await provider.disconnect();
25
+ });
26
+
27
+ it('returns the observable value', async (): Promise<void> => {
28
+ await new Promise<boolean>((resolve) => {
29
+ rpc.system.chain().subscribe((value?: { toString: () => string }): void => {
30
+ if (value) {
31
+ // eslint-disable-next-line jest/no-conditional-expect
32
+ expect(value.toString()).toEqual('mockChain'); // Defined in MockProvider
33
+ resolve(true);
34
+ }
35
+ });
36
+ });
37
+ });
38
+
39
+ it('replay(1) works as expected', async (): Promise<void> => {
40
+ const observable = rpc.system.chain();
41
+ let a: any;
42
+
43
+ observable.subscribe((value?: unknown): void => {
44
+ a = value;
45
+ });
46
+
47
+ await new Promise<boolean>((resolve) => {
48
+ setTimeout((): void => {
49
+ // Subscribe again to the same observable, it should fire value immediately
50
+ observable.subscribe((value: any): void => {
51
+ expect(value).toEqual(a);
52
+ resolve(true);
53
+ });
54
+ }, 1000);
55
+ });
56
+ });
57
+
58
+ it('unsubscribes as required', async (): Promise<void> => {
59
+ rpc.provider.unsubscribe = jest.fn();
60
+
61
+ await new Promise<boolean>((resolve) => {
62
+ const subscription = rpc.chain.subscribeNewHeads().subscribe((): void => {
63
+ subscription.unsubscribe();
64
+
65
+ // There's a promise inside .unsubscribe(), wait a bit (> 2s)
66
+ setTimeout((): void => {
67
+ expect(rpc.provider.unsubscribe).toHaveBeenCalled();
68
+ resolve(true);
69
+ }, 3500);
70
+ });
71
+ });
72
+ });
73
+ });
@@ -0,0 +1,28 @@
1
+ // Copyright 2017-2025 @polkadot/rpc-core authors & contributors
2
+ // SPDX-License-Identifier: Apache-2.0
3
+
4
+ import type { Observable } from 'rxjs';
5
+ import type { ProviderInterface } from '@pezkuwi/rpc-provider/types';
6
+ import type { AnyFunction, Codec, DefinitionRpc } from '@pezkuwi/types/types';
7
+
8
+ export interface RpcInterfaceMethod {
9
+ <T extends Codec> (...params: unknown[]): Observable<T>;
10
+ raw (...params: unknown[]): Observable<unknown>;
11
+ meta: DefinitionRpc;
12
+ }
13
+
14
+ export type AugmentedRpc<F extends AnyFunction> = F & {
15
+ raw: <T> (...params: Parameters<F>) => Observable<T>;
16
+ meta: DefinitionRpc;
17
+ };
18
+
19
+ /** Stats from the rpc-core layer, including the provider stats */
20
+ export interface RpcCoreStats extends NonNullable<ProviderInterface['stats']> {
21
+ /** Internal stats for the rpc-core layer */
22
+ core: {
23
+ /** The number of values retrieved from the core cache */
24
+ cacheHits: number;
25
+ /** The number of entries in the core cache */
26
+ cacheSize: number;
27
+ }
28
+ }
@@ -0,0 +1,8 @@
1
+ // Copyright 2017-2025 @polkadot/rpc-core authors & contributors
2
+ // SPDX-License-Identifier: Apache-2.0
3
+
4
+ // augmented, do an augmentation export
5
+ export * from '@pezkuwi/rpc-core/types/jsonrpc';
6
+
7
+ // normal exports
8
+ export * from './base.js';
@@ -0,0 +1,7 @@
1
+ // Copyright 2017-2025 @polkadot/rpc-core authors & contributors
2
+ // SPDX-License-Identifier: Apache-2.0
3
+
4
+ // eslint-disable-next-line @typescript-eslint/no-empty-interface
5
+ export interface RpcInterface {
6
+ // augmented
7
+ }
@@ -0,0 +1,50 @@
1
+ // Copyright 2017-2025 @polkadot/api-derive authors & contributors
2
+ // SPDX-License-Identifier: Apache-2.0
3
+
4
+ /// <reference types="@pezkuwi/dev-test/globals.d.ts" />
5
+
6
+ import { of, timer } from 'rxjs';
7
+
8
+ import { drr } from './index.js';
9
+
10
+ describe('drr', (): void => {
11
+ it('should not fire twice the same value', async (): Promise<void> => {
12
+ let count = 0;
13
+ const sub = of(1, 1).pipe(drr({ delay: 500 })).subscribe((): void => {
14
+ ++count;
15
+ });
16
+
17
+ await new Promise<boolean>((resolve) => {
18
+ setTimeout((): void => {
19
+ expect(count).toBe(1);
20
+ sub.unsubscribe();
21
+
22
+ setTimeout(() => {
23
+ resolve(true);
24
+ }, 2000);
25
+ }, 50);
26
+ });
27
+ });
28
+
29
+ it('should be a ReplaySubject(1)', async (): Promise<void> => {
30
+ const obs = timer(0, 100).pipe(drr({ delay: 500 })); // Starts at 0, increments every 100ms
31
+ const sub = obs.subscribe(); // Fire the observable
32
+
33
+ await new Promise<boolean>((resolve) => {
34
+ // Subscribe another time after some time, i.e. after the observable has fired
35
+ setTimeout((): void => {
36
+ const sub = obs.subscribe((value): void => {
37
+ expect(value > 1).toBe(true);
38
+
39
+ setTimeout(() => {
40
+ resolve(true);
41
+ }, 2000);
42
+ });
43
+
44
+ sub.unsubscribe();
45
+ }, 500);
46
+
47
+ sub.unsubscribe();
48
+ });
49
+ });
50
+ });
@@ -0,0 +1,52 @@
1
+ // Copyright 2017-2025 @polkadot/rpc-core authors & contributors
2
+ // SPDX-License-Identifier: Apache-2.0
3
+
4
+ import type { Observable } from 'rxjs';
5
+
6
+ import { catchError, distinctUntilChanged, publishReplay, refCount, tap } from 'rxjs';
7
+
8
+ import { stringify } from '@pezkuwi/util';
9
+
10
+ import { refCountDelay } from './refCountDelay.js';
11
+
12
+ export type DrrResult = <T> (source$: Observable<T>) => Observable<T>;
13
+
14
+ interface Options {
15
+ delay?: number;
16
+ skipChange?: boolean;
17
+ skipTimeout?: boolean;
18
+ }
19
+
20
+ function CMP (a: unknown, b: unknown): boolean {
21
+ return stringify({ t: a }) === stringify({ t: b });
22
+ }
23
+
24
+ function ERR (error: Error): Observable<never> {
25
+ throw error;
26
+ }
27
+
28
+ function NOOP (): void {
29
+ // empty
30
+ }
31
+
32
+ /**
33
+ * Shorthand for distinctUntilChanged(), publishReplay(1) and refCount().
34
+ *
35
+ * @ignore
36
+ * @internal
37
+ */
38
+ export function drr ({ delay, skipChange = false, skipTimeout = false }: Options = {}): DrrResult {
39
+ return <T> (source$: Observable<T>): Observable<T> =>
40
+ source$.pipe(
41
+ catchError(ERR),
42
+ skipChange
43
+ ? tap(NOOP)
44
+ : distinctUntilChanged<T>(CMP),
45
+ // eslint-disable-next-line deprecation/deprecation
46
+ publishReplay(1),
47
+ skipTimeout
48
+ // eslint-disable-next-line deprecation/deprecation
49
+ ? refCount()
50
+ : refCountDelay(delay)
51
+ );
52
+ }
@@ -0,0 +1,6 @@
1
+ // Copyright 2017-2025 @polkadot/rpc-core authors & contributors
2
+ // SPDX-License-Identifier: Apache-2.0
3
+
4
+ export * from './drr.js';
5
+ export * from './memo.js';
6
+ export * from './refCountDelay.js';
@@ -0,0 +1,36 @@
1
+ // Copyright 2017-2025 @polkadot/api-derive authors & contributors
2
+ // SPDX-License-Identifier: Apache-2.0
3
+
4
+ import type { Observer, TeardownLogic } from 'rxjs';
5
+ import type { Memoized } from '@pezkuwi/util/types';
6
+
7
+ import { Observable } from 'rxjs';
8
+
9
+ import { memoize } from '@pezkuwi/util';
10
+
11
+ import { drr } from './drr.js';
12
+
13
+ type ObsFn <T> = (...params: unknown[]) => Observable<T>;
14
+
15
+ // Wraps a derive, doing 2 things to optimize calls -
16
+ // 1. creates a memo of the inner fn -> Observable, removing when unsubscribed
17
+ // 2. wraps the observable in a drr() (which includes an unsub delay)
18
+ /** @internal */
19
+ // eslint-disable-next-line @typescript-eslint/ban-types
20
+ export function memo <T> (instanceId: string, inner: Function): Memoized<ObsFn<T>> {
21
+ const options = { getInstanceId: () => instanceId };
22
+ const cached = memoize(
23
+ (...params: unknown[]): Observable<T> =>
24
+ new Observable((observer: Observer<T>): TeardownLogic => {
25
+ const subscription = (inner as ObsFn<T>)(...params).subscribe(observer);
26
+
27
+ return (): void => {
28
+ cached.unmemoize(...params);
29
+ subscription.unsubscribe();
30
+ };
31
+ }).pipe(drr()),
32
+ options
33
+ );
34
+
35
+ return cached;
36
+ }
@@ -0,0 +1,45 @@
1
+ // Copyright 2017-2025 @polkadot/rpc-core authors & contributors
2
+ // SPDX-License-Identifier: Apache-2.0
3
+
4
+ import type { ConnectableObservable, MonoTypeOperatorFunction, TeardownLogic } from 'rxjs';
5
+
6
+ import { asapScheduler, Observable, Subscription } from 'rxjs';
7
+
8
+ /** @internal */
9
+ export function refCountDelay <T> (delay = 1750): MonoTypeOperatorFunction<T> {
10
+ return (source: Observable<T>): Observable<T> => {
11
+ // state: 0 = disconnected, 1 = disconnecting, 2 = connecting, 3 = connected
12
+ let [state, refCount, connection, scheduler] = [0, 0, Subscription.EMPTY, Subscription.EMPTY];
13
+
14
+ return new Observable((ob): TeardownLogic => {
15
+ source.subscribe(ob);
16
+
17
+ if (refCount++ === 0) {
18
+ if (state === 1) {
19
+ scheduler.unsubscribe();
20
+ } else {
21
+ // eslint-disable-next-line deprecation/deprecation
22
+ connection = (source as ConnectableObservable<T>).connect();
23
+ }
24
+
25
+ state = 3;
26
+ }
27
+
28
+ return (): void => {
29
+ if (--refCount === 0) {
30
+ if (state === 2) {
31
+ state = 0;
32
+ scheduler.unsubscribe();
33
+ } else {
34
+ // state === 3
35
+ state = 1;
36
+ scheduler = asapScheduler.schedule((): void => {
37
+ state = 0;
38
+ connection.unsubscribe();
39
+ }, delay);
40
+ }
41
+ }
42
+ };
43
+ });
44
+ };
45
+ }
@@ -0,0 +1,17 @@
1
+ {
2
+ "extends": "../../tsconfig.base.json",
3
+ "compilerOptions": {
4
+ "baseUrl": "..",
5
+ "outDir": "./build",
6
+ "rootDir": "./src"
7
+ },
8
+ "exclude": [
9
+ "**/checkTypes.manual.ts",
10
+ "**/mod.ts",
11
+ "**/*.spec.ts"
12
+ ],
13
+ "references": [
14
+ { "path": "../rpc-provider/tsconfig.build.json" },
15
+ { "path": "../types/tsconfig.build.json" }
16
+ ]
17
+ }