diff --git a/apps/json-api-front/src/app/app.component.ts b/apps/json-api-front/src/app/app.component.ts index 4f91abb..30f8445 100644 --- a/apps/json-api-front/src/app/app.component.ts +++ b/apps/json-api-front/src/app/app.component.ts @@ -2,8 +2,23 @@ import { Component, inject, OnInit } from '@angular/core'; import { NxWelcomeComponent } from './nx-welcome.component'; import { JsonApiSdkService } from 'json-api-nestjs-sdk'; import { AtomicFactory } from 'json-api-nestjs-sdk/json-api-nestjs-sdk.module'; +import { + JSON_RPC, + RPC_BATCH, + Rpc, +} from '@klerick/nestjs-json-rpc-sdk/json-rpc-sdk.module'; + import { switchMap } from 'rxjs'; +interface TestRpc { + test(a: number, b: number): Promise; + test2(firstArg: string, secondArg: number): Promise; +} + +type RpcMap = { + TestRpc: TestRpc; +}; + @Component({ standalone: true, imports: [NxWelcomeComponent], @@ -14,14 +29,19 @@ import { switchMap } from 'rxjs'; export class AppComponent implements OnInit { private JsonApiSdkService = inject(JsonApiSdkService); private atomicFactory = inject(AtomicFactory); + private rpc = inject>(JSON_RPC); + private rpcBatch = inject(RPC_BATCH); ngOnInit(): void { - // this.JsonApiSdkService.getAll(class Users {}, { - // page: { - // size: 2, - // number: 1, - // }, - // }).subscribe((r) => console.log(r)); + const rpc1 = this.rpc.TestRpc.test(1, 2); + const rpc2 = this.rpc.TestRpc.test2('string', 2); + this.rpcBatch(rpc2, rpc1).subscribe(([r2, r1]) => console.log(r1, r2)); + this.JsonApiSdkService.getAll(class Users {}, { + page: { + size: 2, + number: 1, + }, + }).subscribe((r) => console.log(r)); class Addresses { id = 1; diff --git a/apps/json-api-front/src/app/app.config.ts b/apps/json-api-front/src/app/app.config.ts index fe16eb7..f02b645 100644 --- a/apps/json-api-front/src/app/app.config.ts +++ b/apps/json-api-front/src/app/app.config.ts @@ -1,5 +1,9 @@ import { ApplicationConfig, importProvidersFrom } from '@angular/core'; import { JsonApiAngular } from 'json-api-nestjs-sdk/json-api-nestjs-sdk.module'; +import { + JsonRpcAngular, + TransportType, +} from '@klerick/nestjs-json-rpc-sdk/json-rpc-sdk.module'; export const appConfig: ApplicationConfig = { providers: [ @@ -11,5 +15,12 @@ export const appConfig: ApplicationConfig = { operationUrl: 'operation', }) ), + importProvidersFrom( + JsonRpcAngular.forRoot({ + transport: TransportType.HTTP, + rpcPath: 'rpc', + rpcHost: 'http://localhost:4200', + }) + ), ], }; diff --git a/libs/json-rpc/nestjs-json-rpc-sdk/.eslintrc.json b/libs/json-rpc/nestjs-json-rpc-sdk/.eslintrc.json new file mode 100644 index 0000000..c9748d2 --- /dev/null +++ b/libs/json-rpc/nestjs-json-rpc-sdk/.eslintrc.json @@ -0,0 +1,25 @@ +{ + "extends": ["../../../.eslintrc.base.json"], + "ignorePatterns": ["!**/*"], + "overrides": [ + { + "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], + "rules": {} + }, + { + "files": ["*.ts", "*.tsx"], + "rules": {} + }, + { + "files": ["*.js", "*.jsx"], + "rules": {} + }, + { + "files": ["*.json"], + "parser": "jsonc-eslint-parser", + "rules": { + "@nx/dependency-checks": "error" + } + } + ] +} diff --git a/libs/json-rpc/nestjs-json-rpc-sdk/README.md b/libs/json-rpc/nestjs-json-rpc-sdk/README.md new file mode 100644 index 0000000..0b83b72 --- /dev/null +++ b/libs/json-rpc/nestjs-json-rpc-sdk/README.md @@ -0,0 +1,11 @@ +# nestjs-json-rpc-sdk + +This library was generated with [Nx](https://nx.dev). + +## Building + +Run `nx build nestjs-json-rpc-sdk` to build the library. + +## Running unit tests + +Run `nx test nestjs-json-rpc-sdk` to execute the unit tests via [Jest](https://jestjs.io). diff --git a/libs/json-rpc/nestjs-json-rpc-sdk/jest.config.ts b/libs/json-rpc/nestjs-json-rpc-sdk/jest.config.ts new file mode 100644 index 0000000..3ea00a7 --- /dev/null +++ b/libs/json-rpc/nestjs-json-rpc-sdk/jest.config.ts @@ -0,0 +1,11 @@ +/* eslint-disable */ +export default { + displayName: 'nestjs-json-rpc-sdk', + preset: '../../../jest.preset.js', + testEnvironment: 'node', + transform: { + '^.+\\.[tj]s$': ['ts-jest', { tsconfig: '/tsconfig.spec.json' }], + }, + moduleFileExtensions: ['ts', 'js', 'html'], + coverageDirectory: '../../../coverage/libs/json-rpc/nestjs-json-rpc-sdk', +}; diff --git a/libs/json-rpc/nestjs-json-rpc-sdk/package.json b/libs/json-rpc/nestjs-json-rpc-sdk/package.json new file mode 100644 index 0000000..53bedc3 --- /dev/null +++ b/libs/json-rpc/nestjs-json-rpc-sdk/package.json @@ -0,0 +1,7 @@ +{ + "name": "@klerick/nestjs-json-rpc-sdk", + "version": "0.0.1", + "dependencies": { + "tslib": "^2.3.0" + } +} diff --git a/libs/json-rpc/nestjs-json-rpc-sdk/project.json b/libs/json-rpc/nestjs-json-rpc-sdk/project.json new file mode 100644 index 0000000..dc7adb7 --- /dev/null +++ b/libs/json-rpc/nestjs-json-rpc-sdk/project.json @@ -0,0 +1,23 @@ +{ + "name": "nestjs-json-rpc-sdk", + "$schema": "../../../node_modules/nx/schemas/project-schema.json", + "sourceRoot": "libs/json-rpc/nestjs-json-rpc-sdk/src", + "projectType": "library", + "targets": { + "build": { + "executor": "@nx/js:tsc", + "outputs": ["{options.outputPath}"], + "options": { + "outputPath": "dist/libs/json-rpc/nestjs-json-rpc-sdk", + "main": "libs/json-rpc/nestjs-json-rpc-sdk/src/index.ts", + "tsConfig": "libs/json-rpc/nestjs-json-rpc-sdk/tsconfig.lib.json", + "assets": ["libs/json-rpc/nestjs-json-rpc-sdk/*.md"] + } + }, + "publish": { + "command": "node tools/scripts/publish.mjs nestjs-json-rpc-sdk {args.ver} {args.tag}", + "dependsOn": ["build"] + } + }, + "tags": [] +} diff --git a/libs/json-rpc/nestjs-json-rpc-sdk/src/index.ts b/libs/json-rpc/nestjs-json-rpc-sdk/src/index.ts new file mode 100644 index 0000000..c7e2c77 --- /dev/null +++ b/libs/json-rpc/nestjs-json-rpc-sdk/src/index.ts @@ -0,0 +1 @@ +export * from './lib/nestjs-json-rpc-sdk'; diff --git a/libs/json-rpc/nestjs-json-rpc-sdk/src/json-rpc-sdk.module.ts b/libs/json-rpc/nestjs-json-rpc-sdk/src/json-rpc-sdk.module.ts new file mode 100644 index 0000000..f3d4ea8 --- /dev/null +++ b/libs/json-rpc/nestjs-json-rpc-sdk/src/json-rpc-sdk.module.ts @@ -0,0 +1 @@ +export * from './lib/json-rpc-angular'; diff --git a/libs/json-rpc/nestjs-json-rpc-sdk/src/lib/constans/index.ts b/libs/json-rpc/nestjs-json-rpc-sdk/src/lib/constans/index.ts new file mode 100644 index 0000000..af8cbdd --- /dev/null +++ b/libs/json-rpc/nestjs-json-rpc-sdk/src/lib/constans/index.ts @@ -0,0 +1 @@ +export const JSON_RPC_VERSION = '2.0'; diff --git a/libs/json-rpc/nestjs-json-rpc-sdk/src/lib/factory/axios-transport.factory.ts b/libs/json-rpc/nestjs-json-rpc-sdk/src/lib/factory/axios-transport.factory.ts new file mode 100644 index 0000000..451edb7 --- /dev/null +++ b/libs/json-rpc/nestjs-json-rpc-sdk/src/lib/factory/axios-transport.factory.ts @@ -0,0 +1,34 @@ +import { Axios, AxiosResponse } from 'axios'; +import { Observable } from 'rxjs'; + +import { + HttpAgentFactory, + LoopFunc, + PayloadRpc, + ReturnTransportCall, + RpcResult, +} from '../types'; +import { map } from 'rxjs/operators'; + +export function axiosTransportFactory( + axios: Axios +): HttpAgentFactory { + return (url: string) => (body: PayloadRpc) => { + const controller = new AbortController(); + const signal = controller.signal; + + return new Observable>>((subscriber) => { + axios + .post< + ReturnTransportCall, + AxiosResponse, PayloadRpc>, + PayloadRpc + >(url, body, { signal }) + .then((response) => subscriber.next(response)) + .catch((error: unknown) => subscriber.error(error)) + .finally(() => subscriber.complete()); + + return { unsubscribe: () => controller.abort() }; + }).pipe(map((r) => r.data)); + }; +} diff --git a/libs/json-rpc/nestjs-json-rpc-sdk/src/lib/factory/id-request.spec.ts b/libs/json-rpc/nestjs-json-rpc-sdk/src/lib/factory/id-request.spec.ts new file mode 100644 index 0000000..b1f5597 --- /dev/null +++ b/libs/json-rpc/nestjs-json-rpc-sdk/src/lib/factory/id-request.spec.ts @@ -0,0 +1,9 @@ +import { idRequest } from './id-request'; + +describe('id-request', () => { + it('should be increment', () => { + expect(idRequest()).toBe(1); + expect(idRequest()).toBe(2); + expect(idRequest()).toBe(3); + }); +}); diff --git a/libs/json-rpc/nestjs-json-rpc-sdk/src/lib/factory/id-request.ts b/libs/json-rpc/nestjs-json-rpc-sdk/src/lib/factory/id-request.ts new file mode 100644 index 0000000..c43bbef --- /dev/null +++ b/libs/json-rpc/nestjs-json-rpc-sdk/src/lib/factory/id-request.ts @@ -0,0 +1,2 @@ +let i = 0; +export const idRequest = () => ++i; diff --git a/libs/json-rpc/nestjs-json-rpc-sdk/src/lib/factory/index.ts b/libs/json-rpc/nestjs-json-rpc-sdk/src/lib/factory/index.ts new file mode 100644 index 0000000..da8d773 --- /dev/null +++ b/libs/json-rpc/nestjs-json-rpc-sdk/src/lib/factory/index.ts @@ -0,0 +1,4 @@ +export * from './axios-transport.factory'; +export * from './id-request'; +export * from './rpc.factory'; +export * from './transport.factory'; diff --git a/libs/json-rpc/nestjs-json-rpc-sdk/src/lib/factory/rpc.factory.ts b/libs/json-rpc/nestjs-json-rpc-sdk/src/lib/factory/rpc.factory.ts new file mode 100644 index 0000000..b9006e0 --- /dev/null +++ b/libs/json-rpc/nestjs-json-rpc-sdk/src/lib/factory/rpc.factory.ts @@ -0,0 +1,39 @@ +import { RpcConfig, RpcReturnList, RpcBatch, RpcBatchPromise } from '../types'; +import { transportFactory } from './transport.factory'; +import { RpcBatchFactory, rpcProxy, RpcBatchFactoryPromise } from '../utils'; + +type ResultRpcFactory = { + rpc: RpcReturnList; + rpcBatch: RpcBatch; +}; +type ResultRpcFactoryPromise = { + rpc: RpcReturnList; + rpcForBatch: RpcReturnList; + rpcBatch: RpcBatchPromise; +}; + +export function RpcFactory( + options: RpcConfig, + usePromise: false +): ResultRpcFactory; +export function RpcFactory( + options: RpcConfig, + usePromise: true +): ResultRpcFactoryPromise; +export function RpcFactory( + options: RpcConfig, + usePromise: true | false = false +): ResultRpcFactory | ResultRpcFactoryPromise { + const transport = transportFactory(options); + let rpc: RpcReturnList | RpcReturnList; + let rpcForBatch: RpcReturnList; + + if (usePromise) { + rpc = rpcProxy>(transport, usePromise); + rpcForBatch = rpcProxy>(transport, usePromise); + return { rpc, rpcForBatch, rpcBatch: RpcBatchFactoryPromise(transport) }; + } else { + rpc = rpcProxy>(transport, usePromise); + return { rpc, rpcBatch: RpcBatchFactory(transport) }; + } +} diff --git a/libs/json-rpc/nestjs-json-rpc-sdk/src/lib/factory/transport.factory.ts b/libs/json-rpc/nestjs-json-rpc-sdk/src/lib/factory/transport.factory.ts new file mode 100644 index 0000000..c8ef5a7 --- /dev/null +++ b/libs/json-rpc/nestjs-json-rpc-sdk/src/lib/factory/transport.factory.ts @@ -0,0 +1,39 @@ +import { fromFetch } from 'rxjs/fetch'; +import { + RpcConfig, + Transport, + TransportType, + RpcHttpConfig, + LoopFunc, + PayloadRpc, + RpcResult, +} from '../types'; + +function httpTransport( + config: RpcHttpConfig +): Transport { + const url = new URL(config.rpcPath, config.rpcHost).toString(); + if (config.httpAgentFactory) { + return config.httpAgentFactory(url); + } + + return (body: PayloadRpc) => + fromFetch>(url, { + method: 'post', + body: JSON.stringify(body), + selector: (r) => r.json(), + }); +} + +export function transportFactory( + rpcConfig: RpcConfig +): Transport { + switch (rpcConfig.transport) { + case TransportType.HTTP: + return httpTransport(rpcConfig); + case TransportType.WS: + throw new Error('Unknown transport'); + default: + throw new Error('Unknown transport'); + } +} diff --git a/libs/json-rpc/nestjs-json-rpc-sdk/src/lib/json-rpc-angular.ts b/libs/json-rpc/nestjs-json-rpc-sdk/src/lib/json-rpc-angular.ts new file mode 100644 index 0000000..65d202a --- /dev/null +++ b/libs/json-rpc/nestjs-json-rpc-sdk/src/lib/json-rpc-angular.ts @@ -0,0 +1,80 @@ +import { + Component, + inject, + InjectionToken, + ModuleWithProviders, + NgModule, +} from '@angular/core'; +import { HttpClientModule, HttpClient } from '@angular/common/http'; +import { + LoopFunc, + RpcMainHttpConfig, + RpcHttpConfig, + RpcWsConfig, + Transport, + TransportType, + PayloadRpc, + RpcResult, + RpcReturnList, + RpcBatch, +} from './types'; +import { transportFactory } from './factory'; +import { RpcBatchFactory, rpcProxy } from './utils'; + +type Rpc = RpcReturnList; + +export { TransportType, Rpc }; + +export const JSON_RPC_SDK_CONFIG = new InjectionToken( + 'Main config object for sdk' +); + +export const JSON_RPC_SDK_TRANSPORT = new InjectionToken>( + 'Transport for RPC', + { + factory: () => { + const config = inject(JSON_RPC_SDK_CONFIG); + const httpClient = inject(HttpClient); + if (config.transport === TransportType.HTTP) { + (config as unknown as RpcHttpConfig)['httpAgentFactory'] = + (url: string) => (body: PayloadRpc) => { + return httpClient.post>(url, body); + }; + } + return transportFactory(config); + }, + } +); + +export const JSON_RPC = new InjectionToken>( + 'Rpc client', + { + factory: () => + rpcProxy>(inject(JSON_RPC_SDK_TRANSPORT), false), + } +); + +export const RPC_BATCH = new InjectionToken('Rpc client for batch', { + factory: () => RpcBatchFactory(inject(JSON_RPC_SDK_TRANSPORT)), +}); + +export type JsonRpcAngularConfig = RpcMainHttpConfig | RpcWsConfig; + +@NgModule({ + imports: [HttpClientModule], +}) +export class JsonRpcAngular { + static forRoot( + config: JsonRpcAngularConfig + ): ModuleWithProviders { + return { + ngModule: JsonRpcAngular, + providers: [ + { + useValue: config, + provide: JSON_RPC_SDK_CONFIG, + }, + ], + }; + } +} diff --git a/libs/json-rpc/nestjs-json-rpc-sdk/src/lib/nestjs-json-rpc-sdk.spec.ts b/libs/json-rpc/nestjs-json-rpc-sdk/src/lib/nestjs-json-rpc-sdk.spec.ts new file mode 100644 index 0000000..7959f32 --- /dev/null +++ b/libs/json-rpc/nestjs-json-rpc-sdk/src/lib/nestjs-json-rpc-sdk.spec.ts @@ -0,0 +1,7 @@ +import { nestjsJsonRpcSdk } from './nestjs-json-rpc-sdk'; + +describe('nestjsJsonRpcSdk', () => { + it('should work', () => { + expect(nestjsJsonRpcSdk()).toEqual('nestjs-json-rpc-sdk'); + }); +}); diff --git a/libs/json-rpc/nestjs-json-rpc-sdk/src/lib/nestjs-json-rpc-sdk.ts b/libs/json-rpc/nestjs-json-rpc-sdk/src/lib/nestjs-json-rpc-sdk.ts new file mode 100644 index 0000000..4876f67 --- /dev/null +++ b/libs/json-rpc/nestjs-json-rpc-sdk/src/lib/nestjs-json-rpc-sdk.ts @@ -0,0 +1,5 @@ +import { RpcConfig } from './types'; + +export function nestjsJsonRpcSdk(rpcConfig: RpcConfig): string { + return 'nestjs-json-rpc-sdk'; +} diff --git a/libs/json-rpc/nestjs-json-rpc-sdk/src/lib/types/config.ts b/libs/json-rpc/nestjs-json-rpc-sdk/src/lib/types/config.ts new file mode 100644 index 0000000..23e2d56 --- /dev/null +++ b/libs/json-rpc/nestjs-json-rpc-sdk/src/lib/types/config.ts @@ -0,0 +1,43 @@ +import { Observable } from 'rxjs'; +import { Transport } from './rpc'; +import { HttpAgentFactory, LoopFunc } from './utils'; + +export enum TransportType { + HTTP, + WS, +} + +// export type RpcHttpConfig = { +// rpcPath: string; +// rpcHost: string; +// transport: TransportType.HTTP; +// httpAgent?: (data: T) => Promise; +// }; + +// export type HttpConfig = { +// transport: TransportType.HTTP, +// rpcPath: string; +// rpcHost: string; +// httpAgent?: (data: T) => Promise; +// }; + +export type RpcMainHttpConfig = { + transport: TransportType.HTTP; + rpcPath: string; + rpcHost: string; +}; + +export type RpcTransportHttpConfig = { + httpAgentFactory?: HttpAgentFactory>; +}; + +export type RpcHttpConfig = RpcMainHttpConfig & RpcTransportHttpConfig; + +export type RpcWsConfig = { + transport: TransportType.WS; + rpcPath: string; + rpcHost: string; + rpcPort: number; +}; + +export type RpcConfig = RpcHttpConfig | RpcWsConfig; diff --git a/libs/json-rpc/nestjs-json-rpc-sdk/src/lib/types/index.ts b/libs/json-rpc/nestjs-json-rpc-sdk/src/lib/types/index.ts new file mode 100644 index 0000000..4f0e436 --- /dev/null +++ b/libs/json-rpc/nestjs-json-rpc-sdk/src/lib/types/index.ts @@ -0,0 +1,4 @@ +export * from './config'; +export * from './rpc'; +export * from './rpc-error-object'; +export * from './utils'; diff --git a/libs/json-rpc/nestjs-json-rpc-sdk/src/lib/types/rpc-error-object.ts b/libs/json-rpc/nestjs-json-rpc-sdk/src/lib/types/rpc-error-object.ts new file mode 100644 index 0000000..a1c1f30 --- /dev/null +++ b/libs/json-rpc/nestjs-json-rpc-sdk/src/lib/types/rpc-error-object.ts @@ -0,0 +1,40 @@ +import { JsonRpcVersion } from './rpc'; + +export enum ErrorCodeType { + ParseError = 'Parse error', + InvalidRequest = 'Invalid request', + MethodNotFound = 'Method not found', + InvalidParams = 'Invalid params', + InternalError = 'Internal error', + ServerError = 'Server error', +} + +export type RpcErrorObject = { + jsonrpc: JsonRpcVersion; + error: { + message: ErrorCodeType | string; + code: number; + data?: { + title: string; + description: string; + }; + }; + id: null | number; +}; + +export class RpcError extends Error { + data!: { + title: string; + description: string; + }; + code!: number; + id: null | number = null; + constructor(rpcError: RpcErrorObject) { + super(rpcError.error.message); + this.id = rpcError.id; + this.code = rpcError.error.code; + if (rpcError.error.data) { + this.data = rpcError.error.data; + } + } +} diff --git a/libs/json-rpc/nestjs-json-rpc-sdk/src/lib/types/rpc.ts b/libs/json-rpc/nestjs-json-rpc-sdk/src/lib/types/rpc.ts new file mode 100644 index 0000000..f16381a --- /dev/null +++ b/libs/json-rpc/nestjs-json-rpc-sdk/src/lib/types/rpc.ts @@ -0,0 +1,75 @@ +import { Observable } from 'rxjs'; +import { RpcErrorObject } from './rpc-error-object'; +import { LoopFunc, ReturnGenericType } from './utils'; + +export type JsonRpcVersion = '2.0'; + +export type PayloadRpc = { + jsonrpc: JsonRpcVersion; + method: string; + params: Parameters; + id: number; +}; + +export type IdRequest = () => number; + +export type RpcResultObject = { + jsonrpc: JsonRpcVersion; + result: ReturnGenericType; + id: number; +}; + +export type RpcResult = RpcErrorObject | RpcResultObject; + +export type ReturnTransportCall = + | ReturnGenericType + | RpcErrorObject; + +export type Transport = ( + body: PayloadRpc +) => Observable>; + +export type RpcReturnList = { + [K in keyof R]: RpcCallReturnChange; +}; + +export interface WrapperCallRpc extends Observable { + nameSpace: string; + method: string; + arg: P; + id: number; + body: { + jsonrpc: JsonRpcVersion; + method: string; + params: P; + id: number; + }; +} + +type CallFunction = T extends (...args: infer Z) => any + ? ( + ...arg: Z + ) => P extends false + ? WrapperCallRpc, Parameters> + : Promise> + : never; + +export type RpcCallReturnChange = { + [K in keyof R]: R[K] extends LoopFunc ? CallFunction : never; +}; + +export type OutputData = { + [K in keyof T]: T[K] extends WrapperCallRpc + ? O | RpcErrorObject + : never; +}; + +export type RpcBatch = []>( + ...arg: readonly [...A] +) => Observable>; + +export type RpcBatchPromise = < + A extends readonly WrapperCallRpc[] +>( + ...arg: readonly [...A] +) => Promise>; diff --git a/libs/json-rpc/nestjs-json-rpc-sdk/src/lib/types/utils.ts b/libs/json-rpc/nestjs-json-rpc-sdk/src/lib/types/utils.ts new file mode 100644 index 0000000..6a108d0 --- /dev/null +++ b/libs/json-rpc/nestjs-json-rpc-sdk/src/lib/types/utils.ts @@ -0,0 +1,10 @@ +import { Transport } from './rpc'; + +export type LoopFunc = (...args: any) => any; + +export type ReturnGenericType = + ReturnType extends Promise ? U : ReturnType; + +export type HttpAgentFactory = ( + url: string +) => Transport; diff --git a/libs/json-rpc/nestjs-json-rpc-sdk/src/lib/utils/body.spec.ts b/libs/json-rpc/nestjs-json-rpc-sdk/src/lib/utils/body.spec.ts new file mode 100644 index 0000000..2dc4118 --- /dev/null +++ b/libs/json-rpc/nestjs-json-rpc-sdk/src/lib/utils/body.spec.ts @@ -0,0 +1,30 @@ +import { generateBody, generateBodyMethod } from './body'; +import { JSON_RPC_VERSION } from '../constans'; + +describe('body', () => { + it('generateBodyMethod', () => { + const nameSpace = 'nameSpace'; + const method = 'method'; + expect(generateBodyMethod(nameSpace, method)).toBe( + `${nameSpace}.${method}` + ); + }); + + it('generateBody', () => { + const nameSpace = 'nameSpace'; + const method = 'method'; + const params = ['param1', 'param2']; + const id = 1; + const result = generateBody( + generateBodyMethod(nameSpace, method), + params, + id + ); + expect(result).toEqual({ + jsonrpc: JSON_RPC_VERSION, + method: generateBodyMethod(nameSpace, method), + params, + id, + }); + }); +}); diff --git a/libs/json-rpc/nestjs-json-rpc-sdk/src/lib/utils/body.ts b/libs/json-rpc/nestjs-json-rpc-sdk/src/lib/utils/body.ts new file mode 100644 index 0000000..930bea8 --- /dev/null +++ b/libs/json-rpc/nestjs-json-rpc-sdk/src/lib/utils/body.ts @@ -0,0 +1,19 @@ +import { LoopFunc, PayloadRpc } from '../types'; +import { JSON_RPC_VERSION } from '../constans'; + +export function generateBodyMethod(nameSpace: string, method: string): string { + return `${nameSpace}.${method}`; +} + +export function generateBody( + method: string, + params: Parameters, + id: number +): PayloadRpc { + return { + jsonrpc: JSON_RPC_VERSION, + params, + method, + id, + }; +} diff --git a/libs/json-rpc/nestjs-json-rpc-sdk/src/lib/utils/index.ts b/libs/json-rpc/nestjs-json-rpc-sdk/src/lib/utils/index.ts new file mode 100644 index 0000000..3d45935 --- /dev/null +++ b/libs/json-rpc/nestjs-json-rpc-sdk/src/lib/utils/index.ts @@ -0,0 +1,4 @@ +export * from './wrapper-call'; +export * from './rpc-proxy'; +export * from './rpc-batch'; +export * from './body'; diff --git a/libs/json-rpc/nestjs-json-rpc-sdk/src/lib/utils/pipe.ts b/libs/json-rpc/nestjs-json-rpc-sdk/src/lib/utils/pipe.ts new file mode 100644 index 0000000..2caf9ab --- /dev/null +++ b/libs/json-rpc/nestjs-json-rpc-sdk/src/lib/utils/pipe.ts @@ -0,0 +1,40 @@ +import { OperatorFunction, pipe, throwError } from 'rxjs'; +import { map } from 'rxjs/operators'; + +import { + LoopFunc, + ReturnGenericType, + ReturnTransportCall, + RpcError, + RpcResult, +} from '../types'; + +export const mapParseResponse = (r: RpcResult) => { + if ('error' in r) return r; + return r.result; +}; + +export const throwOrReturnError = (returnError = false) => { + return (r: ReturnTransportCall) => { + if (!(typeof r === 'object' && r !== null && 'error' in r)) { + return r; + } + const error = new RpcError(r); + if (!returnError) throw error; + return error; + }; +}; + +export function parseResponse(): OperatorFunction< + RpcResult, + ReturnTransportCall +> { + return pipe(map(mapParseResponse)); +} + +export function throwRpcError(): OperatorFunction< + ReturnTransportCall, + ReturnGenericType +> { + return pipe(map((r) => throwOrReturnError()(r))); +} diff --git a/libs/json-rpc/nestjs-json-rpc-sdk/src/lib/utils/rpc-batch.spec.ts b/libs/json-rpc/nestjs-json-rpc-sdk/src/lib/utils/rpc-batch.spec.ts new file mode 100644 index 0000000..96ef272 --- /dev/null +++ b/libs/json-rpc/nestjs-json-rpc-sdk/src/lib/utils/rpc-batch.spec.ts @@ -0,0 +1,108 @@ +import { RpcBatchFactory, RpcBatchFactoryPromise } from './rpc-batch'; +import { WrapperCall } from './wrapper-call'; +import { RpcError } from '../types'; +import { of } from 'rxjs'; + +describe('rpc-batch', () => { + it('RpcBatchFactory', (done) => { + const transport = jest.fn().mockImplementationOnce((data) => { + expect(data.map((i: any) => i.id)).toEqual([1, 2, 3]); + const errorObj = { + error: { + message: 'ErrroMsg', + code: 1, + }, + id: 3, + }; + return of( + data.map((i: any) => { + if (i.id === 3) { + return errorObj; + } else { + return { + result: i.params, + id: i.id, + }; + } + }) + ); + }); + const rpcBatch = RpcBatchFactory(transport); + const call1 = new WrapperCall( + 'TestSpace', + 'TestMethod', + [1, 2], + transport + ) as any; + const call2 = new WrapperCall( + 'TestSpace1', + 'TestMethod1', + [2], + transport + ) as any; + const call3 = new WrapperCall( + 'TestSpace2', + 'TestMethod2', + [3], + transport + ) as any; + + rpcBatch(call3, call1, call2).subscribe((result) => { + const [r3, r1, r2] = result; + expect(r3).toBeInstanceOf(RpcError); + expect(r2).toEqual(call2.arg); + expect(r1).toEqual(call1.arg); + done(); + }); + }); + + it('RpcBatchFactoryPromise', async () => { + const transport = jest.fn().mockImplementationOnce((data) => { + expect(data.map((i: any) => i.id)).toEqual([1, 2, 3]); + const errorObj = { + error: { + message: 'ErrroMsg', + code: 1, + }, + id: 3, + }; + return of( + data.map((i: any) => { + if (i.id === 3) { + return errorObj; + } else { + return { + result: i.params, + id: i.id, + }; + } + }) + ); + }); + const rpcBatch = RpcBatchFactoryPromise(transport); + const call1 = new WrapperCall( + 'TestSpace', + 'TestMethod', + [1, 2], + transport + ) as any; + const call2 = new WrapperCall( + 'TestSpace1', + 'TestMethod1', + [2], + transport + ) as any; + const call3 = new WrapperCall( + 'TestSpace2', + 'TestMethod2', + [3], + transport + ) as any; + + const [r3, r1, r2] = await rpcBatch(call3, call1, call2); + + expect(r3).toBeInstanceOf(RpcError); + expect(r2).toEqual(call2.arg); + expect(r1).toEqual(call1.arg); + }); +}); diff --git a/libs/json-rpc/nestjs-json-rpc-sdk/src/lib/utils/rpc-batch.ts b/libs/json-rpc/nestjs-json-rpc-sdk/src/lib/utils/rpc-batch.ts new file mode 100644 index 0000000..5e0ec1d --- /dev/null +++ b/libs/json-rpc/nestjs-json-rpc-sdk/src/lib/utils/rpc-batch.ts @@ -0,0 +1,40 @@ +import { + LoopFunc, + RpcBatch, + RpcBatchPromise, + RpcResult, + Transport, +} from '../types'; +import { map } from 'rxjs/operators'; +import { mapParseResponse, throwOrReturnError } from './pipe'; +import { lastValueFrom } from 'rxjs'; + +export function RpcBatchFactory( + transport: Transport +): RpcBatch { + const returnError = throwOrReturnError(true); + return (...arg) => { + const bodyArray = arg.map((i) => i.body); + + const sortMap = bodyArray.reduce((acum, item, currentIndex) => { + acum[item.id] = currentIndex; + return acum; + }, {} as Record); + + bodyArray.sort((a, b) => a.id - b.id); + + return transport(bodyArray as any).pipe( + map((r) => r as unknown as RpcResult[]), + map((r) => r.sort((a, b) => sortMap[a.id || 0] - sortMap[b.id || 0])), + map((r) => r.map(mapParseResponse) as any), + map((r) => r.map(returnError) as any) + ); + }; +} + +export function RpcBatchFactoryPromise( + transport: Transport +): RpcBatchPromise { + const rpcBatch = RpcBatchFactory(transport); + return (...arg) => lastValueFrom(rpcBatch(...arg)); +} diff --git a/libs/json-rpc/nestjs-json-rpc-sdk/src/lib/utils/rpc-proxy.spec.ts b/libs/json-rpc/nestjs-json-rpc-sdk/src/lib/utils/rpc-proxy.spec.ts new file mode 100644 index 0000000..059634c --- /dev/null +++ b/libs/json-rpc/nestjs-json-rpc-sdk/src/lib/utils/rpc-proxy.spec.ts @@ -0,0 +1,48 @@ +import { Observable, of } from 'rxjs'; + +import { rpcProxy } from './rpc-proxy'; +import { LoopFunc, RpcReturnList, Transport } from '../types'; + +interface TestRpc { + test(a: number, b: number): Promise; +} + +type MapRpc = { + TestRpc: TestRpc; +}; + +describe('rpc-proxy', () => { + it('should be return Observable', () => { + const arg: [number, number] = [1, 2]; + const resultRpc = 1; + const transport = jest.fn().mockImplementationOnce((data) => ({ + result: resultRpc, + id: data.id, + })) as Transport; + const usePromise = false; + const rpc = rpcProxy>(transport, usePromise); + expect(rpc).toHaveProperty('TestRpc'); + expect(rpc.TestRpc).toHaveProperty('test'); + const result = rpc.TestRpc.test(...arg); + expect(result).toBeInstanceOf(Observable); + }); + + it('should be return Promise', async () => { + const arg: [number, number] = [1, 2]; + const resultRpc = 1; + const transport = jest.fn().mockImplementationOnce((data) => + of({ + result: resultRpc, + id: data.id, + }) + ) as Transport; + const usePromise = true; + const rpc = rpcProxy>(transport, usePromise); + expect(rpc).toHaveProperty('TestRpc'); + expect(rpc.TestRpc).toHaveProperty('test'); + const result = rpc.TestRpc.test(...arg); + expect(result).toBeInstanceOf(Promise); + const resultRpcCheck = await result; + expect(resultRpcCheck).toBe(resultRpc); + }); +}); diff --git a/libs/json-rpc/nestjs-json-rpc-sdk/src/lib/utils/rpc-proxy.ts b/libs/json-rpc/nestjs-json-rpc-sdk/src/lib/utils/rpc-proxy.ts new file mode 100644 index 0000000..c81c8f2 --- /dev/null +++ b/libs/json-rpc/nestjs-json-rpc-sdk/src/lib/utils/rpc-proxy.ts @@ -0,0 +1,30 @@ +import { lastValueFrom } from 'rxjs'; + +import { LoopFunc, RpcReturnList, Transport } from '../types'; +import { WrapperCall } from './wrapper-call'; + +export const rpcProxy = >( + transport: Transport, + usePromise = false +): T => { + const mockRpcNameSpace = {} as T; + return new Proxy(mockRpcNameSpace, { + get(target, nameSpace: keyof T) { + const mockRpcmethode = {} as T[typeof nameSpace]; + return new Proxy(mockRpcmethode, { + get(target, method: keyof T[typeof nameSpace]) { + return (...arg: Parameters) => { + const wr = new WrapperCall( + String(nameSpace), + String(method), + arg, + transport + ); + if (usePromise) return lastValueFrom(wr); + return wr; + }; + }, + }); + }, + }); +}; diff --git a/libs/json-rpc/nestjs-json-rpc-sdk/src/lib/utils/wrapper-call.spec.ts b/libs/json-rpc/nestjs-json-rpc-sdk/src/lib/utils/wrapper-call.spec.ts new file mode 100644 index 0000000..c258529 --- /dev/null +++ b/libs/json-rpc/nestjs-json-rpc-sdk/src/lib/utils/wrapper-call.spec.ts @@ -0,0 +1,39 @@ +import { WrapperCall } from './wrapper-call'; +import { Transport } from '../types'; +import { of } from 'rxjs'; + +function mockRPC(a: number, b: string): number { + return 1; +} + +describe('wrapper-call', () => { + let nameSpace: string; + let method: string; + let arg: Parameters; + let transport: Transport; + + beforeEach(() => { + nameSpace = 'namespace'; + method = 'method'; + arg = [1, 'test']; + }); + + it('should be init Observable', (done) => { + const result = { result: 'result' }; + transport = jest.fn().mockImplementationOnce((input) => { + return of(result); + }); + expect.assertions(2); + const instWrapperCall = new WrapperCall(nameSpace, method, arg, transport); + instWrapperCall.subscribe({ + next: (r) => { + expect(r).toEqual(result.result); + }, + complete: () => { + expect(transport).toHaveBeenCalledWith(instWrapperCall.body); + done(); + }, + error: (err) => done(err), + }); + }); +}); diff --git a/libs/json-rpc/nestjs-json-rpc-sdk/src/lib/utils/wrapper-call.ts b/libs/json-rpc/nestjs-json-rpc-sdk/src/lib/utils/wrapper-call.ts new file mode 100644 index 0000000..ccfb738 --- /dev/null +++ b/libs/json-rpc/nestjs-json-rpc-sdk/src/lib/utils/wrapper-call.ts @@ -0,0 +1,34 @@ +import { Observable } from 'rxjs'; +import { LoopFunc, PayloadRpc, ReturnTransportCall, Transport } from '../types'; +import { generateBody, generateBodyMethod } from './body'; +import { idRequest } from '../factory/id-request'; +import { parseResponse, throwRpcError } from './pipe'; + +export class WrapperCall extends Observable< + ReturnTransportCall +> { + id: number = idRequest(); + body!: PayloadRpc; + constructor( + private nameSpace: string, + private method: string, + private arg: Parameters, + private transport: Transport + ) { + super((subscriber) => { + const transportSubscribe = this.transport(this.body) + .pipe(parseResponse(), throwRpcError()) + .subscribe({ + next: (r) => subscriber.next(r), + error: (err) => subscriber.error(err), + complete: () => subscriber.complete(), + }); + return { unsubscribe: () => transportSubscribe.unsubscribe() }; + }); + this.body = generateBody( + generateBodyMethod(this.nameSpace, this.method), + this.arg, + this.id + ); + } +} diff --git a/libs/json-rpc/nestjs-json-rpc-sdk/tsconfig.json b/libs/json-rpc/nestjs-json-rpc-sdk/tsconfig.json new file mode 100644 index 0000000..8122543 --- /dev/null +++ b/libs/json-rpc/nestjs-json-rpc-sdk/tsconfig.json @@ -0,0 +1,22 @@ +{ + "extends": "../../../tsconfig.base.json", + "compilerOptions": { + "module": "commonjs", + "forceConsistentCasingInFileNames": true, + "strict": true, + "noImplicitOverride": true, + "noPropertyAccessFromIndexSignature": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true + }, + "files": [], + "include": [], + "references": [ + { + "path": "./tsconfig.lib.json" + }, + { + "path": "./tsconfig.spec.json" + } + ] +} diff --git a/libs/json-rpc/nestjs-json-rpc-sdk/tsconfig.lib.json b/libs/json-rpc/nestjs-json-rpc-sdk/tsconfig.lib.json new file mode 100644 index 0000000..4befa7f --- /dev/null +++ b/libs/json-rpc/nestjs-json-rpc-sdk/tsconfig.lib.json @@ -0,0 +1,10 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../../dist/out-tsc", + "declaration": true, + "types": ["node"] + }, + "include": ["src/**/*.ts"], + "exclude": ["jest.config.ts", "src/**/*.spec.ts", "src/**/*.test.ts"] +} diff --git a/libs/json-rpc/nestjs-json-rpc-sdk/tsconfig.spec.json b/libs/json-rpc/nestjs-json-rpc-sdk/tsconfig.spec.json new file mode 100644 index 0000000..69a251f --- /dev/null +++ b/libs/json-rpc/nestjs-json-rpc-sdk/tsconfig.spec.json @@ -0,0 +1,14 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../../dist/out-tsc", + "module": "commonjs", + "types": ["jest", "node"] + }, + "include": [ + "jest.config.ts", + "src/**/*.test.ts", + "src/**/*.spec.ts", + "src/**/*.d.ts" + ] +} diff --git a/libs/json-rpc/nestjs-json-rpc/project.json b/libs/json-rpc/nestjs-json-rpc/project.json index 219a861..2e8aaea 100644 --- a/libs/json-rpc/nestjs-json-rpc/project.json +++ b/libs/json-rpc/nestjs-json-rpc/project.json @@ -18,6 +18,15 @@ "publish": { "command": "node tools/scripts/publish.mjs nestjs-json-rpc {args.ver} {args.tag}", "dependsOn": ["build"] + }, + "test": { + "executor": "@nx/jest:jest", + "outputs": ["{workspaceRoot}/coverage/{projectRoot}"], + "options": { + "jestConfig": "libs/json-rpc/nestjs-json-rpc/jest.config.ts", + "codeCoverage": true, + "coverageReporters": ["json-summary"] + } } }, "tags": [] diff --git a/libs/json-rpc/nestjs-json-rpc/src/lib/modules/http-transport/controllers/json-rpc.controller.spec.ts b/libs/json-rpc/nestjs-json-rpc/src/lib/modules/http-transport/controllers/json-rpc.controller.spec.ts new file mode 100644 index 0000000..6b9d59e --- /dev/null +++ b/libs/json-rpc/nestjs-json-rpc/src/lib/modules/http-transport/controllers/json-rpc.controller.spec.ts @@ -0,0 +1,42 @@ +import { Test } from '@nestjs/testing'; +import { JsonRpcController } from './json-rpc.controller'; +import { UtilModule } from '../../util/util.module'; +import { HandlerService } from '../../util/service'; + +describe('json-rpc.controller', () => { + let jsonRpcController: JsonRpcController; + let handlerService: HandlerService; + beforeEach(async () => { + const testModuleRef = await Test.createTestingModule({ + imports: [UtilModule], + providers: [JsonRpcController], + }).compile(); + + jsonRpcController = testModuleRef.get(JsonRpcController); + handlerService = testModuleRef.get(HandlerService); + }); + + it('Should be call HandlerService', async () => { + const result = { + jsonrpc: '2.0', + id: 1, + result: 1 as any, + }; + const input = { + jsonrpc: '2.0', + id: 1, + params: [1], + method: { + methodName: 'test', + spaceName: 'test', + }, + }; + const spyHandlerServiceCallHandler = jest + .spyOn(handlerService, 'callHandler') + .mockResolvedValue(result as any); + const resultController = jsonRpcController.handler(input as any); + expect(spyHandlerServiceCallHandler).toHaveBeenCalledWith(input); + expect(spyHandlerServiceCallHandler).toHaveBeenCalledTimes(1); + expect(resultController).resolves.toEqual(result); + }); +}); diff --git a/libs/json-rpc/nestjs-json-rpc/src/lib/modules/http-transport/controllers/json-rpc.controller.ts b/libs/json-rpc/nestjs-json-rpc/src/lib/modules/http-transport/controllers/json-rpc.controller.ts index b9cb28c..1048002 100644 --- a/libs/json-rpc/nestjs-json-rpc/src/lib/modules/http-transport/controllers/json-rpc.controller.ts +++ b/libs/json-rpc/nestjs-json-rpc/src/lib/modules/http-transport/controllers/json-rpc.controller.ts @@ -2,7 +2,7 @@ import { Body, Controller, Inject, Post, UseFilters } from '@nestjs/common'; import { HandlerService } from '../../util/service'; import { InputDataPipe } from '../../util/pipe/input-data.pipe'; import { PayloadRpcData, RpcResult } from '../../../types'; -import { RpcErrorObject } from '../../../types/error-payloade'; +import { RpcErrorObject } from '../../../types'; import { RpcErrorExceptionFilter } from '../filter/rpc-error-exception.filter'; @Controller('/') diff --git a/libs/json-rpc/nestjs-json-rpc/src/lib/modules/http-transport/filter/rpc-error-exception.filter.spec.ts b/libs/json-rpc/nestjs-json-rpc/src/lib/modules/http-transport/filter/rpc-error-exception.filter.spec.ts new file mode 100644 index 0000000..8ddd631 --- /dev/null +++ b/libs/json-rpc/nestjs-json-rpc/src/lib/modules/http-transport/filter/rpc-error-exception.filter.spec.ts @@ -0,0 +1,62 @@ +import { ArgumentsHost } from '@nestjs/common'; + +import { RpcErrorExceptionFilter } from './rpc-error-exception.filter'; +import { + createError, + fromRpcErrorToRpcErrorObject, + RpcError, +} from '../../../utils'; +import { ErrorCodeType } from '../../../types'; + +import * as ts from '@schematics/angular/third_party/github.com/Microsoft/TypeScript/lib/typescript'; +import Response = ts.server.protocol.Response; +import { HttpArgumentsHost } from '@nestjs/common/interfaces'; + +describe('rpc-error-exception.filter', () => { + let argumentsHost: ArgumentsHost; + let response: { + send: (arg: any) => void; + }; + let getResponse: () => typeof response; + + beforeEach(() => { + response = { + send() { + return void 0; + }, + }; + getResponse = () => response; + argumentsHost = { + switchToHttp(): HttpArgumentsHost { + return { + getResponse, + } as any; + }, + } as any; + }); + + it('should catch RpcError and transform it to RpcErrorObject', () => { + const filter = new RpcErrorExceptionFilter(); + const exception = createError( + ErrorCodeType.InvalidRequest, + 'InvalidRequest' + ); + const spySend = jest.spyOn(response, 'send'); + filter.catch(exception, argumentsHost); + expect(spySend).toHaveBeenCalledWith( + fromRpcErrorToRpcErrorObject(exception) + ); + }); + + it('should catch Error and transform it to RpcErrorObject', () => { + const filter = new RpcErrorExceptionFilter(); + const exception = new Error('Test Error'); + const spySend = jest.spyOn(response, 'send'); + filter.catch(exception, argumentsHost); + expect(spySend).toHaveBeenCalledWith( + fromRpcErrorToRpcErrorObject( + createError(ErrorCodeType.ServerError, exception.message) + ) + ); + }); +}); diff --git a/libs/json-rpc/nestjs-json-rpc/src/lib/modules/util/pipe/input-data.pipe.spec.ts b/libs/json-rpc/nestjs-json-rpc/src/lib/modules/util/pipe/input-data.pipe.spec.ts index 5bab2d2..703aa7c 100644 --- a/libs/json-rpc/nestjs-json-rpc/src/lib/modules/util/pipe/input-data.pipe.spec.ts +++ b/libs/json-rpc/nestjs-json-rpc/src/lib/modules/util/pipe/input-data.pipe.spec.ts @@ -2,7 +2,7 @@ import { Test } from '@nestjs/testing'; import { InputDataPipe } from './input-data.pipe'; import { ErrorCodeType, PayloadRpcData } from '../../../types'; import { zodInputDataProvider } from '../../../providers/zod-input-data.provider'; -import { RpcError } from '@klerick/nestjs-json-rpc'; +import { RpcError } from '../../../utils'; import { ErrorCode } from '../../../constants'; describe('input-data.pipe', () => { diff --git a/libs/json-rpc/nestjs-json-rpc/src/lib/modules/util/pipe/input-data.pipe.ts b/libs/json-rpc/nestjs-json-rpc/src/lib/modules/util/pipe/input-data.pipe.ts index 68ff6ea..19baab0 100644 --- a/libs/json-rpc/nestjs-json-rpc/src/lib/modules/util/pipe/input-data.pipe.ts +++ b/libs/json-rpc/nestjs-json-rpc/src/lib/modules/util/pipe/input-data.pipe.ts @@ -1,4 +1,4 @@ -import { Inject, PipeTransform } from '@nestjs/common'; +import { Inject, Injectable, PipeTransform } from '@nestjs/common'; import { ZOD_INPUT_DATA } from '../../../constants'; import { @@ -9,6 +9,7 @@ import { } from '../../../types'; import { createError, RpcError } from '../../../utils'; +@Injectable() export class InputDataPipe implements PipeTransform { diff --git a/libs/json-rpc/nestjs-json-rpc/src/lib/modules/util/util.module.ts b/libs/json-rpc/nestjs-json-rpc/src/lib/modules/util/util.module.ts index 2e1cc5b..235a0fd 100644 --- a/libs/json-rpc/nestjs-json-rpc/src/lib/modules/util/util.module.ts +++ b/libs/json-rpc/nestjs-json-rpc/src/lib/modules/util/util.module.ts @@ -1,10 +1,11 @@ import { Inject, Module, OnApplicationBootstrap } from '@nestjs/common'; +import { ModuleRef } from '@nestjs/core'; import { MAP_HANDLER } from '../../constants'; import { mapHandlerStoreProvider, AsyncIterate } from '../../providers'; import { HandlerService, ExplorerService } from './service'; -import { ModuleRef } from '@nestjs/core'; import { zodInputDataProvider } from '../../providers/zod-input-data.provider'; +import { InputDataPipe } from './pipe/input-data.pipe'; @Module({ controllers: [], @@ -14,8 +15,15 @@ import { zodInputDataProvider } from '../../providers/zod-input-data.provider'; ExplorerService, AsyncIterate, zodInputDataProvider, + InputDataPipe, + ], + exports: [ + mapHandlerStoreProvider, + HandlerService, + AsyncIterate, + zodInputDataProvider, + InputDataPipe, ], - exports: [mapHandlerStoreProvider, HandlerService, AsyncIterate], }) export class UtilModule implements OnApplicationBootstrap { @Inject(MAP_HANDLER) private readonly mapHandler!: Map; diff --git a/package-lock.json b/package-lock.json index 001c055..f4c4990 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3013,7 +3013,7 @@ "version": "0.8.1", "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", - "devOptional": true, + "dev": true, "dependencies": { "@jridgewell/trace-mapping": "0.3.9" }, @@ -3025,7 +3025,7 @@ "version": "0.3.9", "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", - "devOptional": true, + "dev": true, "dependencies": { "@jridgewell/resolve-uri": "^3.0.3", "@jridgewell/sourcemap-codec": "^1.4.10" @@ -4635,7 +4635,7 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", - "devOptional": true, + "dev": true, "engines": { "node": ">=6.0.0" } @@ -4663,7 +4663,7 @@ "version": "1.4.15", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", - "devOptional": true + "dev": true }, "node_modules/@jridgewell/trace-mapping": { "version": "0.3.23", @@ -7319,7 +7319,7 @@ "version": "1.3.107", "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.3.107.tgz", "integrity": "sha512-zKhqDyFcTsyLIYK1iEmavljZnf4CCor5pF52UzLAz4B6Nu/4GLU+2LQVAf+oRHjusG39PTPjd2AlRT3f3QWfsQ==", - "devOptional": true, + "dev": true, "hasInstallScript": true, "dependencies": { "@swc/counter": "^0.1.1", @@ -7360,6 +7360,7 @@ "cpu": [ "arm64" ], + "dev": true, "optional": true, "os": [ "darwin" @@ -7375,6 +7376,7 @@ "cpu": [ "x64" ], + "dev": true, "optional": true, "os": [ "darwin" @@ -7390,6 +7392,7 @@ "cpu": [ "arm" ], + "dev": true, "optional": true, "os": [ "linux" @@ -7405,6 +7408,7 @@ "cpu": [ "arm64" ], + "dev": true, "optional": true, "os": [ "linux" @@ -7420,6 +7424,7 @@ "cpu": [ "arm64" ], + "dev": true, "optional": true, "os": [ "linux" @@ -7435,6 +7440,7 @@ "cpu": [ "x64" ], + "dev": true, "optional": true, "os": [ "linux" @@ -7450,6 +7456,7 @@ "cpu": [ "x64" ], + "dev": true, "optional": true, "os": [ "linux" @@ -7465,6 +7472,7 @@ "cpu": [ "arm64" ], + "dev": true, "optional": true, "os": [ "win32" @@ -7480,6 +7488,7 @@ "cpu": [ "ia32" ], + "dev": true, "optional": true, "os": [ "win32" @@ -7495,6 +7504,7 @@ "cpu": [ "x64" ], + "dev": true, "optional": true, "os": [ "win32" @@ -7507,13 +7517,13 @@ "version": "0.1.3", "resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz", "integrity": "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==", - "devOptional": true + "dev": true }, "node_modules/@swc/helpers": { "version": "0.5.6", "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.6.tgz", "integrity": "sha512-aYX01Ke9hunpoCexYAgQucEpARGQ5w/cqHFrIR+e9gdKb1QWTsVJuTJ2ozQzIAxLyRQe/m+2RqzkyOOGiMKRQA==", - "devOptional": true, + "dev": true, "dependencies": { "tslib": "^2.4.0" } @@ -7522,7 +7532,7 @@ "version": "0.1.5", "resolved": "https://registry.npmjs.org/@swc/types/-/types-0.1.5.tgz", "integrity": "sha512-myfUej5naTBWnqOCc/MdVOLVjXUXtIA+NpDrDBKJtLLg2shUjBu3cZmB/85RyitKc55+lUUyl7oRfLOvkr2hsw==", - "devOptional": true + "dev": true }, "node_modules/@tootallnate/once": { "version": "2.0.0", @@ -7546,25 +7556,25 @@ "version": "1.0.9", "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==", - "devOptional": true + "dev": true }, "node_modules/@tsconfig/node12": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", - "devOptional": true + "dev": true }, "node_modules/@tsconfig/node14": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", - "devOptional": true + "dev": true }, "node_modules/@tsconfig/node16": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", - "devOptional": true + "dev": true }, "node_modules/@tufjs/canonical-json": { "version": "2.0.0", @@ -7820,7 +7830,7 @@ "version": "18.16.20", "resolved": "https://registry.npmjs.org/@types/node/-/node-18.16.20.tgz", "integrity": "sha512-nL54VfDjThdP2UXJXZao5wp76CDiDw4zSRO8d4Tk7UgDqNKGKVEQB0/t3ti63NS+YNNkIQDvwEAF04BO+WYu7Q==", - "devOptional": true + "dev": true }, "node_modules/@types/node-forge": { "version": "1.3.11", @@ -9225,7 +9235,7 @@ "version": "8.11.3", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", - "devOptional": true, + "dev": true, "bin": { "acorn": "bin/acorn" }, @@ -9265,7 +9275,7 @@ "version": "8.3.2", "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.2.tgz", "integrity": "sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A==", - "devOptional": true, + "dev": true, "engines": { "node": ">=0.4.0" } @@ -9488,7 +9498,7 @@ "version": "4.1.3", "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", - "devOptional": true + "dev": true }, "node_modules/argparse": { "version": "2.0.1", @@ -11332,7 +11342,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", - "devOptional": true + "dev": true }, "node_modules/critters": { "version": "0.0.20", @@ -11907,7 +11917,7 @@ "version": "4.0.2", "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "devOptional": true, + "dev": true, "engines": { "node": ">=0.3.1" } @@ -12177,6 +12187,7 @@ "version": "0.1.13", "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", + "dev": true, "optional": true, "dependencies": { "iconv-lite": "^0.6.2" @@ -12186,6 +12197,7 @@ "version": "0.6.3", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, "optional": true, "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" @@ -15107,23 +15119,6 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/jest-circus/node_modules/babel-plugin-macros": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz", - "integrity": "sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==", - "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "@babel/runtime": "^7.12.5", - "cosmiconfig": "^7.0.0", - "resolve": "^1.19.0" - }, - "engines": { - "node": ">=10", - "npm": ">=6" - } - }, "node_modules/jest-circus/node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -15158,24 +15153,6 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, - "node_modules/jest-circus/node_modules/cosmiconfig": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", - "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", - "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "@types/parse-json": "^4.0.0", - "import-fresh": "^3.2.1", - "parse-json": "^5.0.0", - "path-type": "^4.0.0", - "yaml": "^1.10.0" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/jest-circus/node_modules/dedent": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.5.1.tgz", @@ -17525,7 +17502,7 @@ "version": "1.3.6", "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "devOptional": true + "dev": true }, "node_modules/make-fetch-happen": { "version": "13.0.0", @@ -18883,27 +18860,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/openapi3-ts": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/openapi3-ts/-/openapi3-ts-4.2.2.tgz", - "integrity": "sha512-+9g4actZKeb3czfi9gVQ4Br2Ju3KwhCAQJBNaKgye5KggqcBLIhFHH+nIkcm0BUX00TrAJl6dH4JWgM4G4JWrw==", - "peer": true, - "dependencies": { - "yaml": "^2.3.4" - } - }, - "node_modules/openapi3-ts/node_modules/yaml": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.4.1.tgz", - "integrity": "sha512-pIXzoImaqmfOrL7teGUBt/T7ZDnyeGBWyXQBvOVhLkWLN37GXv8NMLK406UY6dS51JfcQHsmcW5cJ441bHg6Lg==", - "peer": true, - "bin": { - "yaml": "bin.mjs" - }, - "engines": { - "node": ">= 14" - } - }, "node_modules/opener": { "version": "1.5.2", "resolved": "https://registry.npmjs.org/opener/-/opener-1.5.2.tgz", @@ -22768,7 +22724,7 @@ "version": "10.9.1", "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==", - "devOptional": true, + "dev": true, "dependencies": { "@cspotcode/source-map-support": "^0.8.0", "@tsconfig/node10": "^1.0.7", @@ -23253,7 +23209,7 @@ "version": "5.3.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz", "integrity": "sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==", - "devOptional": true, + "dev": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -23481,7 +23437,7 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", - "devOptional": true + "dev": true }, "node_modules/v8-to-istanbul": { "version": "9.2.0", @@ -24556,7 +24512,7 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", - "devOptional": true, + "dev": true, "engines": { "node": ">=6" } diff --git a/package.json b/package.json index 03ea733..42bcf34 100644 --- a/package.json +++ b/package.json @@ -92,5 +92,8 @@ "typescript": "~5.3.2", "verdaccio": "^5.0.4", "webpack-cli": "^5.1.4" + }, + "nx": { + "includedScripts": [] } } diff --git a/tsconfig.base.json b/tsconfig.base.json index c000886..c2d9ac2 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -18,6 +18,12 @@ "@klerick/nestjs-json-rpc": [ "libs/json-rpc/nestjs-json-rpc/src/index.ts" ], + "@klerick/nestjs-json-rpc-sdk": [ + "libs/json-rpc/nestjs-json-rpc-sdk/src/index.ts" + ], + "@klerick/nestjs-json-rpc-sdk/json-rpc-sdk.module": [ + "libs/json-rpc/nestjs-json-rpc-sdk/src/json-rpc-sdk.module.ts" + ], "database": ["libs/database/src/index.ts"], "json-api-nestjs": ["libs/json-api/json-api-nestjs/src/index.ts"], "json-api-nestjs-sdk": ["libs/json-api/json-api-nestjs-sdk/src/index.ts"],