diff --git a/package.json b/package.json index bf01aac..4631d77 100644 --- a/package.json +++ b/package.json @@ -39,7 +39,7 @@ "husky": "^8.0.3", "lint-staged": "^13.2.1", "prettier": "^2.8.7", - "rollup": "^3.20.2", + "rollup": "^3.20.3", "turbo": "^1.9.1", "typescript": "^5.0.4" }, diff --git a/packages/nestjs/client/.npmignore b/packages/nestjs/client/.npmignore new file mode 100644 index 0000000..e1941c8 --- /dev/null +++ b/packages/nestjs/client/.npmignore @@ -0,0 +1,4 @@ +.turbo +src +tsconfig.json +rollup.config.ts diff --git a/packages/nestjs/client/README.md b/packages/nestjs/client/README.md new file mode 100644 index 0000000..a64c814 --- /dev/null +++ b/packages/nestjs/client/README.md @@ -0,0 +1,126 @@ +NestJS's Dynamic Module for Client. + +# Install + +```sh +npm install --save @grpc.ts/nestjs-client + +# or + +yarn add @grpc.ts/nestjs-client + +# or + +pnpm add @grpc.ts/nestjs-client +``` + +# Usage + +```proto +// example.proto + +syntax = "proto3"; + +import "google/protobuf/timestamp.proto"; + +package example.v1; + +message Message { + string message = 1; + google.protobuf.Timestamp created_at = 2; +} + +message SendMessageRequest { + string message = 1; + google.protobuf.Timestamp created_at = 2; +} + +message GetMessageResponse { Message message = 1; } + +service ExampleService { + rpc SendMessage(SendMessageRequest) returns (GetMessageResponse); +} +``` + +In NestJS + +```ts +// client.module.ts +import { Module } from '@nestjs/common'; +import { GrpcClient } from '@grpc.ts/nestjs-client'; + +import { ClientController } from './client.controller'; + +@Module({ + imports: [ + GrpcClient.register([ + { + url: 'localhost:3010', + package: [ + { + packageName: 'example.v1', + protoPath: '../proto/example.proto', + }, + { + packageName: 'example2.v1', + protoPath: '../proto/example2.proto', + }, + { + protoPath: '../proto/example3.proto', + }, + ], + packageDefinitionOptions: { + oneofs: true, + longs: String, + enums: String, + defaults: true, + }, + options: { + keepaliveTimeMs: 5_000, + }, + }, + ]), + ], + controllers: [ClientController], +}) +export class ClientModule {} +``` + +```ts +// client.controller.ts +import { Controller, Get } from '@nestjs/common'; +import { + GrpcService, + createMetadata, + dateToGrpcTimestamp, +} from '@grpc.ts/nestjs-client'; + +@Controller('/client') +export class ClientController { + constructor( + @GrpcService({ + serviceName: 'ExampleService', + }) + private readonly exampleService: any, + ) {} + + @Get() + public async sendMessage(): Promise { + this.exampleService + .sendMessage( + { message: 'hello', createdAt: dateToGrpcTimestamp(new Date()) }, + createMetadata({ + meta: 'test', + }), + ) + .then((data) => { + console.log(data); + }) + .catch((err) => { + console.log(err); + }); + + return 'Ok!'; + } +} +``` diff --git a/packages/nestjs/client/package.json b/packages/nestjs/client/package.json new file mode 100644 index 0000000..4d5ed1e --- /dev/null +++ b/packages/nestjs/client/package.json @@ -0,0 +1,46 @@ +{ + "name": "@grpc.ts/nestjs-client", + "version": "1.0.0", + "license": "MIT", + "directories": { + "lib": "lib" + }, + "author": "Alpha", + "description": "NestJS package for client", + "homepage": "https://github.com/zgid123/grpc-ts", + "keywords": [ + "grpc", + "grpc-ts", + "grpc-js", + "grpc-typescript", + "grpc-javascript", + "grpc-nodejs", + "grpc-nestjs", + "grpc-client" + ], + "repository": { + "type": "git", + "url": "git+https://github.com/zgid123/grpc-ts" + }, + "main": "./lib/index.cjs", + "module": "./lib/index.mjs", + "types": "./lib/index.d.ts", + "exports": { + ".": { + "import": "./lib/index.mjs", + "require": "./lib/index.cjs", + "types": "./lib/index.d.ts" + } + }, + "scripts": { + "prepublish": "pnpm build", + "build": "rollup --config rollup.config.ts --configPlugin typescript" + }, + "dependencies": { + "@grpc.ts/core": "workspace:*", + "@nestjs/common": "^9.4.0" + }, + "devDependencies": { + "@grpc.ts/client-commons": "workspace:*" + } +} diff --git a/packages/nestjs/client/rollup.config.ts b/packages/nestjs/client/rollup.config.ts new file mode 100644 index 0000000..f69901d --- /dev/null +++ b/packages/nestjs/client/rollup.config.ts @@ -0,0 +1,21 @@ +import { defineConfig } from 'rollup'; +import json from '@rollup/plugin-json'; +import commonjs from '@rollup/plugin-commonjs'; +import resolve from '@rollup/plugin-node-resolve'; +import typescript from '@rollup/plugin-typescript'; + +export default defineConfig({ + input: 'src/index.ts', + plugins: [json(), resolve(), commonjs(), typescript()], + external: ['@nestjs/common', '@grpc.ts/core'], + output: [ + { + file: './lib/index.cjs', + format: 'cjs', + }, + { + file: './lib/index.mjs', + format: 'es', + }, + ], +}); diff --git a/packages/nestjs/client/src/GrpcClient.ts b/packages/nestjs/client/src/GrpcClient.ts new file mode 100644 index 0000000..33bfd90 --- /dev/null +++ b/packages/nestjs/client/src/GrpcClient.ts @@ -0,0 +1,61 @@ +import { createClients } from '@grpc.ts/client-commons'; +import { + Module, + type Provider, + type DynamicModule, + type OnApplicationShutdown, +} from '@nestjs/common'; + +import type { + IGrpcClientProps, + IGrpcClientListProps, +} from '@grpc.ts/core/lib/interface'; + +import { normalizePattern } from './utils'; + +@Module({}) +export class GrpcClient { + public static async register( + options: IGrpcClientProps | IGrpcClientProps[], + ): Promise { + const clients = await createClients(options); + + const providers = this._createProviders(clients); + + return { + module: GrpcClient, + providers, + exports: providers, + }; + } + + protected static _createProviders(clients: IGrpcClientListProps): Provider[] { + return Object.entries(clients).reduce( + (result, [clientName, clientWrapper]) => { + Object.entries(clientWrapper.getPackages()).forEach( + ([packageName, serviceClientWrapper]) => { + Object.entries(serviceClientWrapper).forEach( + ([serviceName, serviceClient]) => { + ( + serviceClient as unknown as OnApplicationShutdown + ).onApplicationShutdown = serviceClient.close; + + result.push({ + provide: normalizePattern({ + serviceName, + clientName: clientName || '', + packageName: packageName || '', + }), + useValue: serviceClient, + }); + }, + ); + }, + ); + + return result; + }, + [], + ); + } +} diff --git a/packages/nestjs/client/src/decorators.ts b/packages/nestjs/client/src/decorators.ts new file mode 100644 index 0000000..83cd06e --- /dev/null +++ b/packages/nestjs/client/src/decorators.ts @@ -0,0 +1,9 @@ +import { Inject } from '@nestjs/common'; + +import { normalizePattern } from './utils'; + +import type { IGrpcServiceProps } from './interface'; + +export const GrpcService = (props: IGrpcServiceProps) => { + return Inject(normalizePattern(props)); +}; diff --git a/packages/nestjs/client/src/index.ts b/packages/nestjs/client/src/index.ts new file mode 100644 index 0000000..18605b7 --- /dev/null +++ b/packages/nestjs/client/src/index.ts @@ -0,0 +1,9 @@ +export { + Metadata, + createMetadata, + grpcTimestampToDate, + dateToGrpcTimestamp, +} from '@grpc.ts/core'; + +export * from './decorators'; +export * from './GrpcClient'; diff --git a/packages/nestjs/client/src/interface.ts b/packages/nestjs/client/src/interface.ts new file mode 100644 index 0000000..a78dfdc --- /dev/null +++ b/packages/nestjs/client/src/interface.ts @@ -0,0 +1,5 @@ +export interface IGrpcServiceProps { + clientName?: string; + serviceName: string; + packageName?: string; +} diff --git a/packages/nestjs/client/src/utils.ts b/packages/nestjs/client/src/utils.ts new file mode 100644 index 0000000..742695f --- /dev/null +++ b/packages/nestjs/client/src/utils.ts @@ -0,0 +1,18 @@ +import { IGrpcServiceProps } from './interface'; + +function combine(separator: string, ...data: string[]): string { + return data.filter((s) => !!s).join(separator); +} + +export function normalizePattern({ + serviceName, + clientName = '', + packageName = '', +}: IGrpcServiceProps): string { + return combine( + '::', + 'grpc', + combine('::', clientName, packageName), + serviceName, + ); +} diff --git a/packages/nestjs/client/tsconfig.json b/packages/nestjs/client/tsconfig.json new file mode 100644 index 0000000..cc276e4 --- /dev/null +++ b/packages/nestjs/client/tsconfig.json @@ -0,0 +1,14 @@ +{ + "extends": "../../../tsconfig.json", + "compilerOptions": { + "baseUrl": "./src", + "outDir": "./lib", + }, + "include": [ + "./src" + ], + "exclude": [ + "./lib", + "./node_modules" + ] +} diff --git a/packages/nestjs/server/.npmignore b/packages/nestjs/server/.npmignore new file mode 100644 index 0000000..e1941c8 --- /dev/null +++ b/packages/nestjs/server/.npmignore @@ -0,0 +1,4 @@ +.turbo +src +tsconfig.json +rollup.config.ts diff --git a/packages/nestjs/server/README.md b/packages/nestjs/server/README.md new file mode 100644 index 0000000..bda7316 --- /dev/null +++ b/packages/nestjs/server/README.md @@ -0,0 +1,136 @@ +NestJS's Dynamic Module for Server. + +# Install + +```sh +npm install --save @grpc.ts/nestjs-server + +# or + +yarn add @grpc.ts/nestjs-server + +# or + +pnpm add @grpc.ts/nestjs-server +``` + +# Usage + +```proto +// example.proto + +syntax = "proto3"; + +import "google/protobuf/timestamp.proto"; + +package example.v1; + +message Message { + string message = 1; + google.protobuf.Timestamp created_at = 2; +} + +message SendMessageRequest { + string message = 1; + google.protobuf.Timestamp created_at = 2; +} + +message GetMessageResponse { Message message = 1; } + +service ExampleService { + rpc SendMessage(SendMessageRequest) returns (GetMessageResponse); +} +``` + +In NestJS + +```ts +// main.ts +import detect from 'detect-port'; +import { NestFactory } from '@nestjs/core'; +import { GrpcServer } from '@grpc.ts/nestjs-server'; + +import { AppModule } from './app.module'; + +async function bootstrap() { + const app = await NestFactory.create(AppModule); + + app.connectMicroservice( + GrpcServer.createService([ + { + url: 'localhost:3010', + package: [ + { + packageName: 'example.v1', + protoPath: '../proto/example.proto', + }, + { + packageName: 'example2.v1', + protoPath: '../proto/example2.proto', + }, + { + protoPath: '../proto/example3.proto', + }, + ], + packageDefinitionOptions: { + oneofs: true, + longs: String, + enums: String, + defaults: true, + }, + options: { + keepaliveTimeMs: 5_000, + }, + }, + ]), + ); + + const port = await detect(3_000); + await app.startAllMicroservices(); + await app.listen(port); + + console.log(`Run on ${port}`); +} + +bootstrap(); +``` + +```ts +// server.ts +import { Controller } from '@nestjs/common'; +import { + GrpcUnaryMethod, + dateToGrpcTimestamp, + type Metadata, + type Timestamp, + type ServerUnaryCall, +} from '@grpc.ts/nestjs-server'; + +@Controller() +export class ServerController { + @GrpcUnaryMethod({ + serviceName: 'ExampleService', + }) + public async sendMessage( + request: unknown, + metadata: Metadata, + call: ServerUnaryCall, + ): Promise<{ + message: { + message: string; + createdAt: Timestamp.AsObject; + }; + }> { + console.log('request', request); + console.log('metadata', metadata); + console.log('call', call); + + return { + message: { + message: 'hola', + createdAt: dateToGrpcTimestamp(new Date()), + }, + }; + } +} +``` diff --git a/packages/nestjs/server/package.json b/packages/nestjs/server/package.json new file mode 100644 index 0000000..3936309 --- /dev/null +++ b/packages/nestjs/server/package.json @@ -0,0 +1,46 @@ +{ + "name": "@grpc.ts/nestjs-server", + "version": "1.0.0", + "license": "MIT", + "directories": { + "lib": "lib" + }, + "author": "Alpha", + "description": "NestJS package for server", + "homepage": "https://github.com/zgid123/grpc-ts", + "keywords": [ + "grpc", + "grpc-ts", + "grpc-js", + "grpc-typescript", + "grpc-javascript", + "grpc-nodejs", + "grpc-nestjs", + "grpc-server" + ], + "repository": { + "type": "git", + "url": "git+https://github.com/zgid123/grpc-ts" + }, + "main": "./lib/index.cjs", + "module": "./lib/index.mjs", + "types": "./lib/index.d.ts", + "exports": { + ".": { + "import": "./lib/index.mjs", + "require": "./lib/index.cjs", + "types": "./lib/index.d.ts" + } + }, + "scripts": { + "prepublish": "pnpm build", + "build": "rollup --config rollup.config.ts --configPlugin typescript" + }, + "dependencies": { + "@grpc.ts/core": "workspace:*", + "@nestjs/common": "^9.4.0" + }, + "devDependencies": { + "@grpc.ts/server-commons": "workspace:^" + } +} diff --git a/packages/nestjs/server/rollup.config.ts b/packages/nestjs/server/rollup.config.ts new file mode 100644 index 0000000..f69901d --- /dev/null +++ b/packages/nestjs/server/rollup.config.ts @@ -0,0 +1,21 @@ +import { defineConfig } from 'rollup'; +import json from '@rollup/plugin-json'; +import commonjs from '@rollup/plugin-commonjs'; +import resolve from '@rollup/plugin-node-resolve'; +import typescript from '@rollup/plugin-typescript'; + +export default defineConfig({ + input: 'src/index.ts', + plugins: [json(), resolve(), commonjs(), typescript()], + external: ['@nestjs/common', '@grpc.ts/core'], + output: [ + { + file: './lib/index.cjs', + format: 'cjs', + }, + { + file: './lib/index.mjs', + format: 'es', + }, + ], +}); diff --git a/packages/nestjs/server/src/GrpcServer.ts b/packages/nestjs/server/src/GrpcServer.ts new file mode 100644 index 0000000..e5690e5 --- /dev/null +++ b/packages/nestjs/server/src/GrpcServer.ts @@ -0,0 +1,121 @@ +import { Logger } from '@nestjs/common'; +import { createServers } from '@grpc.ts/server-commons'; + +import type { Metadata, ServerUnaryCall } from '@grpc.ts/core'; + +import type { + IGrpcServerProps, + IGrpcServerListProps, +} from '@grpc.ts/core/lib/interface'; + +import { normalizePattern, omit } from './utils'; + +import type { ISubscribeParams } from './interface'; + +type TCallback = () => void; + +interface ICreateServiceReturnProps { + strategy: GrpcServer; +} + +interface IMessageHandlerProps { + ( + data: TData, + metadata: Metadata, + call: ServerUnaryCall, + ): Promise; +} + +type TOptions = IGrpcServerProps | IGrpcServerProps[]; + +export class GrpcServer { + #options: TOptions; + #grpcServers: IGrpcServerListProps = {}; + #patterns: ISubscribeParams[] = []; + #logger = new Logger('gRPCServer'); + #messageHandlers = new Map(); + + constructor(props: TOptions) { + this.#options = props; + } + + public static createService(params: TOptions): ICreateServiceReturnProps { + return { + strategy: new GrpcServer(params), + }; + } + + public addHandler( + pattern: ISubscribeParams & { isGrpc: boolean }, + callback: IMessageHandlerProps, + isEventHandler = false, + _extras: Record = {}, + ) { + if (typeof pattern === 'object' && pattern.isGrpc) { + pattern = omit(pattern, ['isGrpc']) as ISubscribeParams & { + isGrpc: boolean; + }; + + this.#patterns.push(pattern); + } + + const normalizedPattern = normalizePattern(pattern); + (callback as any).isEventHandler = isEventHandler; + this.#messageHandlers.set(normalizedPattern, callback); + } + + public async listen(callback: TCallback) { + const patterns = this.#patterns; + const handleMessage = this.#handleMessage.bind(this); + + await this.#initServers(this.#options); + + patterns.forEach(async (pattern) => { + const { serverName = '', serviceName, rpcName, options } = pattern; + const server = this.#grpcServers[serverName]; + + if (!server) { + return this.#logger.error(`Unknown server ${serverName}`); + } + + server.addUnaryHandler( + serviceName, + rpcName, + (request, metadata, call) => { + return handleMessage(request, metadata, call, pattern); + }, + options, + ); + }); + + callback(); + } + + public async close() { + Object.values(this.#grpcServers).forEach((serverWrapper) => { + serverWrapper.server.forceShutdown(); + }); + } + + async #handleMessage( + request: unknown, + metadata: Metadata, + call: ServerUnaryCall, + pattern: ISubscribeParams, + ): Promise { + const patternAsString = normalizePattern(pattern); + const handler = this.#messageHandlers.get(patternAsString); + + if (!handler) { + return this.#logger.error( + `There is no matching event handler defined in the server. Event pattern: ${patternAsString}`, + ); + } + + return handler(request, metadata, call); + } + + async #initServers(options: TOptions): Promise { + this.#grpcServers = await createServers(options); + } +} diff --git a/packages/nestjs/server/src/decorators.ts b/packages/nestjs/server/src/decorators.ts new file mode 100644 index 0000000..6315f5b --- /dev/null +++ b/packages/nestjs/server/src/decorators.ts @@ -0,0 +1,49 @@ +import type { ISubscribeParams } from './interface'; + +const PAYLOAD_TYPE = 3; +const CONTEXT_TYPE = 6; +const GRPC_CALL_TYPE = 9; +const ROUTE_ARGS_METADATA = '__routeArguments__'; +const PATTERN_METADATA = 'microservices:pattern'; +const PATTERN_HANDLER_METADATA = 'microservices:handler_type'; + +const DEFAULT_GRPC_CALLBACK_METADATA = { + [`${CONTEXT_TYPE}:1`]: { index: 1, data: undefined, pipes: [] }, + [`${GRPC_CALL_TYPE}:2`]: { index: 2, data: undefined, pipes: [] }, + [`${PAYLOAD_TYPE}:0`]: { index: 0, data: undefined, pipes: [] }, +}; + +export function GrpcUnaryMethod({ + rpcName, + ...rest +}: Omit & { + rpcName?: string; +}): MethodDecorator { + return ( + target: object, + key: string | symbol, + descriptor: PropertyDescriptor, + ) => { + Reflect.defineMetadata( + PATTERN_METADATA, + [ + { + ...rest, + isGrpc: true, + type: 'unary', + rpcName: rpcName || key || descriptor.value.name, + }, + ], + descriptor.value, + ); + Reflect.defineMetadata(PATTERN_HANDLER_METADATA, 1, descriptor.value); + Reflect.defineMetadata( + ROUTE_ARGS_METADATA, + DEFAULT_GRPC_CALLBACK_METADATA, + target.constructor, + rpcName || key || descriptor.value.name, + ); + + return descriptor; + }; +} diff --git a/packages/nestjs/server/src/index.ts b/packages/nestjs/server/src/index.ts new file mode 100644 index 0000000..977cc6c --- /dev/null +++ b/packages/nestjs/server/src/index.ts @@ -0,0 +1,11 @@ +export { + Metadata, + createMetadata, + grpcTimestampToDate, + dateToGrpcTimestamp, + type Timestamp, + type ServerUnaryCall, +} from '@grpc.ts/core'; + +export { GrpcUnaryMethod } from './decorators'; +export * from './GrpcServer'; diff --git a/packages/nestjs/server/src/interface.ts b/packages/nestjs/server/src/interface.ts new file mode 100644 index 0000000..6c0ff0b --- /dev/null +++ b/packages/nestjs/server/src/interface.ts @@ -0,0 +1,9 @@ +import type { IAddUnaryHandlerOptionsProps } from '@grpc.ts/core'; + +export interface ISubscribeParams { + type?: 'unary'; + rpcName: string; + serverName?: string; + serviceName: string; + options?: IAddUnaryHandlerOptionsProps; +} diff --git a/packages/nestjs/server/src/utils.ts b/packages/nestjs/server/src/utils.ts new file mode 100644 index 0000000..97fdf90 --- /dev/null +++ b/packages/nestjs/server/src/utils.ts @@ -0,0 +1,38 @@ +export function omit, P extends keyof T>( + data: T, + keys: P[], +): Omit { + return Object.entries(data).reduce((result, [key, value]) => { + if (!keys.includes(key as P)) { + result[key] = value; + } + + return result; + }, {} as Record) as Omit; +} + +function isObject(data: unknown): boolean { + return !(data instanceof Date) && !!data && typeof data === 'object'; +} + +function sortedObj(obj: Record): Record { + return Object.keys(obj) + .sort() + .reduce>((result, key) => { + const value = obj[key]; + + if (Array.isArray(value)) { + result[key] = value.map((v) => sortedObj(v)); + } else if (isObject(value)) { + result[key] = sortedObj(value); + } else { + result[key] = value; + } + + return result; + }, {}); +} + +export function normalizePattern(pattern: Record): string { + return JSON.stringify(sortedObj(pattern)); +} diff --git a/packages/nestjs/server/tsconfig.json b/packages/nestjs/server/tsconfig.json new file mode 100644 index 0000000..cc276e4 --- /dev/null +++ b/packages/nestjs/server/tsconfig.json @@ -0,0 +1,14 @@ +{ + "extends": "../../../tsconfig.json", + "compilerOptions": { + "baseUrl": "./src", + "outDir": "./lib", + }, + "include": [ + "./src" + ], + "exclude": [ + "./lib", + "./node_modules" + ] +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ebb6b84..4ac65f9 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -10,16 +10,16 @@ importers: devDependencies: '@rollup/plugin-commonjs': specifier: ^24.1.0 - version: 24.1.0(rollup@3.20.2) + version: 24.1.0(rollup@3.20.3) '@rollup/plugin-json': specifier: ^6.0.0 - version: 6.0.0(rollup@3.20.2) + version: 6.0.0(rollup@3.20.3) '@rollup/plugin-node-resolve': specifier: ^15.0.2 - version: 15.0.2(rollup@3.20.2) + version: 15.0.2(rollup@3.20.3) '@rollup/plugin-typescript': specifier: ^11.1.0 - version: 11.1.0(rollup@3.20.2)(tslib@2.5.0)(typescript@5.0.4) + version: 11.1.0(rollup@3.20.3)(tslib@2.5.0)(typescript@5.0.4) '@typescript-eslint/eslint-plugin': specifier: ^5.58.0 version: 5.58.0(@typescript-eslint/parser@5.58.0)(eslint@8.38.0)(typescript@5.0.4) @@ -45,8 +45,8 @@ importers: specifier: ^2.8.7 version: 2.8.7 rollup: - specifier: ^3.20.2 - version: 3.20.2 + specifier: ^3.20.3 + version: 3.20.3 turbo: specifier: ^1.9.1 version: 1.9.1 @@ -157,6 +157,32 @@ importers: specifier: ^1.0.1 version: 1.0.1 + packages/nestjs/client: + dependencies: + '@grpc.ts/core': + specifier: workspace:* + version: link:../../core + '@nestjs/common': + specifier: ^9.4.0 + version: 9.4.0(reflect-metadata@0.1.13)(rxjs@7.8.0) + devDependencies: + '@grpc.ts/client-commons': + specifier: workspace:* + version: link:../../commons/client + + packages/nestjs/server: + dependencies: + '@grpc.ts/core': + specifier: workspace:* + version: link:../../core + '@nestjs/common': + specifier: ^9.4.0 + version: 9.4.0(reflect-metadata@0.1.13)(rxjs@7.8.0) + devDependencies: + '@grpc.ts/server-commons': + specifier: workspace:^ + version: link:../../commons/server + packages: /@esbuild/android-arm64@0.17.15: @@ -485,11 +511,39 @@ packages: resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==} dev: true + /@lukeed/csprng@1.1.0: + resolution: {integrity: sha512-Z7C/xXCiGWsg0KuKsHTKJxbWhpI3Vs5GwLfOean7MGyVFGqdRgBbAjOCh6u4bbjPc/8MJ2pZmK/0DLdCbivLDA==} + engines: {node: '>=8'} + dev: false + /@lukeed/ms@2.0.1: resolution: {integrity: sha512-Xs/4RZltsAL7pkvaNStUQt7netTkyxrS0K+RILcVr3TRMS/ToOg4I6uNfhB9SlGsnWBym4U+EaXq0f0cEMNkHA==} engines: {node: '>=8'} dev: true + /@nestjs/common@9.4.0(reflect-metadata@0.1.13)(rxjs@7.8.0): + resolution: {integrity: sha512-RUcVAQsEF4WPrmzFXEOUfZnPwrLTe1UVlzXTlSyfqfqbdWDPKDGlIPVelBLfc5/+RRUQ0I5iE4+CQvpCmkqldw==} + peerDependencies: + cache-manager: <=5 + class-transformer: '*' + class-validator: '*' + reflect-metadata: ^0.1.12 + rxjs: ^7.1.0 + peerDependenciesMeta: + cache-manager: + optional: true + class-transformer: + optional: true + class-validator: + optional: true + dependencies: + iterare: 1.2.1 + reflect-metadata: 0.1.13 + rxjs: 7.8.0 + tslib: 2.5.0 + uid: 2.0.2 + dev: false + /@nodelib/fs.scandir@2.1.5: resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} engines: {node: '>= 8'} @@ -554,7 +608,7 @@ packages: resolution: {integrity: sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==} dev: false - /@rollup/plugin-commonjs@24.1.0(rollup@3.20.2): + /@rollup/plugin-commonjs@24.1.0(rollup@3.20.3): resolution: {integrity: sha512-eSL45hjhCWI0jCCXcNtLVqM5N1JlBGvlFfY0m6oOYnLCJ6N0qEXoZql4sY2MOUArzhH4SA/qBpTxvvZp2Sc+DQ==} engines: {node: '>=14.0.0'} peerDependencies: @@ -563,16 +617,16 @@ packages: rollup: optional: true dependencies: - '@rollup/pluginutils': 5.0.2(rollup@3.20.2) + '@rollup/pluginutils': 5.0.2(rollup@3.20.3) commondir: 1.0.1 estree-walker: 2.0.2 glob: 8.1.0 is-reference: 1.2.1 magic-string: 0.27.0 - rollup: 3.20.2 + rollup: 3.20.3 dev: true - /@rollup/plugin-json@6.0.0(rollup@3.20.2): + /@rollup/plugin-json@6.0.0(rollup@3.20.3): resolution: {integrity: sha512-i/4C5Jrdr1XUarRhVu27EEwjt4GObltD7c+MkCIpO2QIbojw8MUs+CCTqOphQi3Qtg1FLmYt+l+6YeoIf51J7w==} engines: {node: '>=14.0.0'} peerDependencies: @@ -581,11 +635,11 @@ packages: rollup: optional: true dependencies: - '@rollup/pluginutils': 5.0.2(rollup@3.20.2) - rollup: 3.20.2 + '@rollup/pluginutils': 5.0.2(rollup@3.20.3) + rollup: 3.20.3 dev: true - /@rollup/plugin-node-resolve@15.0.2(rollup@3.20.2): + /@rollup/plugin-node-resolve@15.0.2(rollup@3.20.3): resolution: {integrity: sha512-Y35fRGUjC3FaurG722uhUuG8YHOJRJQbI6/CkbRkdPotSpDj9NtIN85z1zrcyDcCQIW4qp5mgG72U+gJ0TAFEg==} engines: {node: '>=14.0.0'} peerDependencies: @@ -594,16 +648,16 @@ packages: rollup: optional: true dependencies: - '@rollup/pluginutils': 5.0.2(rollup@3.20.2) + '@rollup/pluginutils': 5.0.2(rollup@3.20.3) '@types/resolve': 1.20.2 deepmerge: 4.3.1 is-builtin-module: 3.2.1 is-module: 1.0.0 resolve: 1.22.1 - rollup: 3.20.2 + rollup: 3.20.3 dev: true - /@rollup/plugin-typescript@11.1.0(rollup@3.20.2)(tslib@2.5.0)(typescript@5.0.4): + /@rollup/plugin-typescript@11.1.0(rollup@3.20.3)(tslib@2.5.0)(typescript@5.0.4): resolution: {integrity: sha512-86flrfE+bSHB69znnTV6kVjkncs2LBMhcTCyxWgRxLyfXfQrxg4UwlAqENnjrrxnSNS/XKCDJCl8EkdFJVHOxw==} engines: {node: '>=14.0.0'} peerDependencies: @@ -616,14 +670,14 @@ packages: tslib: optional: true dependencies: - '@rollup/pluginutils': 5.0.2(rollup@3.20.2) + '@rollup/pluginutils': 5.0.2(rollup@3.20.3) resolve: 1.22.1 - rollup: 3.20.2 + rollup: 3.20.3 tslib: 2.5.0 typescript: 5.0.4 dev: true - /@rollup/pluginutils@5.0.2(rollup@3.20.2): + /@rollup/pluginutils@5.0.2(rollup@3.20.3): resolution: {integrity: sha512-pTd9rIsP92h+B6wWwFbW8RkZv4hiR/xKsqre4SIuAOaOEQRxi0lqLke9k2/7WegC85GgUs9pjmOjCUi3In4vwA==} engines: {node: '>=14.0.0'} peerDependencies: @@ -635,7 +689,7 @@ packages: '@types/estree': 1.0.0 estree-walker: 2.0.2 picomatch: 2.3.1 - rollup: 3.20.2 + rollup: 3.20.3 dev: true /@types/detect-port@1.3.2: @@ -1822,6 +1876,11 @@ packages: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} dev: true + /iterare@1.2.1: + resolution: {integrity: sha512-RKYVTCjAnRthyJes037NX/IiqeidgN1xc3j1RjFfECFp28A1GVwK9nA+i0rJPaHqSZwygLzRnFlzUuHFoWWy+Q==} + engines: {node: '>=6'} + dev: false + /joycon@3.1.1: resolution: {integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==} engines: {node: '>=10'} @@ -2386,6 +2445,10 @@ packages: resolution: {integrity: sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==} engines: {node: '>= 12.13.0'} + /reflect-metadata@0.1.13: + resolution: {integrity: sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==} + dev: false + /require-directory@2.1.1: resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} engines: {node: '>=0.10.0'} @@ -2446,6 +2509,14 @@ packages: optionalDependencies: fsevents: 2.3.2 + /rollup@3.20.3: + resolution: {integrity: sha512-u6/O1X42CAZ79rbk+smyONJQLTpwFBL7InpRa/AVWia5lq60w5J/PUsVHCOgSolN0X9R2GjQ41fZm3x28Hk1lA==} + engines: {node: '>=14.18.0', npm: '>=8.0.0'} + hasBin: true + optionalDependencies: + fsevents: 2.3.2 + dev: true + /run-parallel@1.2.0: resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} dependencies: @@ -2456,7 +2527,6 @@ packages: resolution: {integrity: sha512-F2+gxDshqmIub1KdvZkaEfGDwLNpPvk9Fs6LD/MyQxNgMds/WH9OdDDXOmxUZpME+iSK3rQCctkL0DYyytUqMg==} dependencies: tslib: 2.5.0 - dev: true /safe-buffer@5.2.1: resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} @@ -2767,6 +2837,13 @@ packages: resolution: {integrity: sha512-MvlCc4GHrmZdAllBc0iUDowff36Q9Ndw/UzqmEKyrfSzokTd9ZCy1i+IIk5hrYKkjoYVQyNbrw7/F8XJ2rEwTg==} dev: true + /uid@2.0.2: + resolution: {integrity: sha512-u3xV3X7uzvi5b1MncmZo3i2Aw222Zk1keqLA1YkHldREkAhAqi65wuPfe7lHx8H/Wzy+8CE7S7uS3jekIM5s8g==} + engines: {node: '>=8'} + dependencies: + '@lukeed/csprng': 1.1.0 + dev: false + /universalify@2.0.0: resolution: {integrity: sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==} engines: {node: '>= 10.0.0'}