From 472f137cac09820ae5c60b7d72348d4820849b05 Mon Sep 17 00:00:00 2001 From: "Chakhsu.Lau" Date: Sun, 3 Dec 2023 17:25:44 +0800 Subject: [PATCH 01/12] feat: rewrite to ts --- src/config/defaultChannelOptions.ts | 23 ++ src/config/defaultLoadOptions.ts | 11 + src/index.ts | 236 ++++++++++++++++++++ src/proxy/clientProxy.ts | 326 ++++++++++++++++++++++++++++ src/proxy/serverProxy.ts | 294 +++++++++++++++++++++++++ src/schema/loader.ts | 33 +++ src/schema/server.ts | 13 ++ src/util/compose.ts | 41 ++++ src/util/iterator.ts | 200 +++++++++++++++++ src/util/prefixingDefinition.ts | 24 ++ 10 files changed, 1201 insertions(+) create mode 100644 src/config/defaultChannelOptions.ts create mode 100644 src/config/defaultLoadOptions.ts create mode 100644 src/index.ts create mode 100644 src/proxy/clientProxy.ts create mode 100644 src/proxy/serverProxy.ts create mode 100644 src/schema/loader.ts create mode 100644 src/schema/server.ts create mode 100644 src/util/compose.ts create mode 100644 src/util/iterator.ts create mode 100644 src/util/prefixingDefinition.ts diff --git a/src/config/defaultChannelOptions.ts b/src/config/defaultChannelOptions.ts new file mode 100644 index 0000000..8df951c --- /dev/null +++ b/src/config/defaultChannelOptions.ts @@ -0,0 +1,23 @@ +// gRPC channel options +// Doc: https://grpc.github.io/grpc/core/group__grpc__arg__keys.html +// Doc: https://github.com/grpc/grpc-node/blob/master/packages/grpc-js/src/channel-options.ts +import { ChannelOptions } from "@grpc/grpc-js"; + +export const defaultChannelOptions: ChannelOptions = { + "grpc.min_reconnect_backoff_ms": 1000, + "grpc.max_reconnect_backoff_ms": 10000, + "grpc.grpclb_call_timeout_ms": 5000, + "grpc.keepalive_timeout_ms": 20 * 1000, + "grpc.keepalive_time_ms": 120 * 1000, + "grpc.keepalive_permit_without_calls": 1, + "grpc.enable_retries": 1, + "grpc.service_config": JSON.stringify({ + retryPolicy: { + maxAttempts: 4, + initialBackoff: "0.1s", + maxBackoff: "1s", + backoffMultiplier: 2, + retryableStatusCodes: ["UNAVAILABLE"], + }, + }), +}; diff --git a/src/config/defaultLoadOptions.ts b/src/config/defaultLoadOptions.ts new file mode 100644 index 0000000..58fab36 --- /dev/null +++ b/src/config/defaultLoadOptions.ts @@ -0,0 +1,11 @@ +// GRPC protos loader options +// Doc: https://www.npmjs.com/package/@grpc/proto-loader +import { Options } from '@grpc/proto-loader' + +export const defaultLoadOptions: Options = { + keepCase: true, + longs: String, + enums: String, + defaults: false, + oneofs: true, +}; diff --git a/src/index.ts b/src/index.ts new file mode 100644 index 0000000..15115f5 --- /dev/null +++ b/src/index.ts @@ -0,0 +1,236 @@ +import assert from 'node:assert'; +import * as grpc from '@grpc/grpc-js'; +import * as protoLoader from '@grpc/proto-loader'; +import * as protobuf from 'protobufjs'; +import * as Descriptor from 'protobufjs/ext/descriptor'; +import * as _ from 'lodash'; +import * as Joi from 'joi'; + +import loaderSchemas from './schema/loader'; +import prefixingDefinition from './util/prefixingDefinition'; +import { defaultChannelOptions } from './config/defaultChannelOptions'; +import { defaultLoadOptions } from './config/defaultLoadOptions'; +import clientProxy from './proxy/clientProxy'; +import ServerProxy from './proxy/serverProxy'; + +class GrpcLoader { + private _protoFiles: any[]; + private _clientMap: Map; + private _clientAddrMap: Map; + private _types: any; + private _packagePrefix?: string; + private _appName?: string; + private _packageDefinition: any; + private _isDev?: boolean; + private _reflectedRoot: any; + private _insecureCredentials?: grpc.ChannelCredentials; + private _initDefaultClient?: boolean; + + constructor(protoFileOptions: any) { + Joi.assert(protoFileOptions, loaderSchemas.constructor, 'new GrpcLoader() params Error'); + + this._protoFiles = Array.isArray(protoFileOptions) ? protoFileOptions : [protoFileOptions]; + this._clientMap = new Map(); + this._clientAddrMap = new Map(); + } + + async init({ services = undefined, isDev = false, packagePrefix = '', loadOptions = {}, channelOptions = {}, appName }: any = {}) { + Joi.assert({ services, loadOptions, isDev, channelOptions, appName }, loaderSchemas.init, 'GrpcLoader.init() params Error'); + + if (this._types) { + return; + } + + try { + loadOptions = Object.assign({}, defaultLoadOptions, loadOptions); + this._isDev = isDev; + this._packagePrefix = packagePrefix; + this._appName = appName; + + loadOptions.includeDirs = this._protoFiles.map((p) => p.location).concat(loadOptions.includeDirs || []); + const files = this._protoFiles.reduce((result, p) => { + if (p.files && p.files.length > 0) { + result.push(...p.files); + } + return result; + }, []); + + const packageDefinition = await protoLoader.load(files, loadOptions); + + if (this._packagePrefix) { + this._packageDefinition = prefixingDefinition(packageDefinition, packagePrefix); + } else { + this._packageDefinition = packageDefinition; + } + + this._types = grpc.loadPackageDefinition(this._packageDefinition); + } catch (err) { + throw err; + } + + if (services) { + await this.initClients({ services, channelOptions }); + } + } + + async initClients({ services, channelOptions = {}, credentials = undefined }: any) { + Joi.assert({ services, channelOptions }, loaderSchemas.initClients, 'GrpcLoader.initClients() Options Error'); + + if (this._initDefaultClient) { + return; + } + + if (!this._packageDefinition) { + await this.init(); + } + + const serviceNames = Object.keys(services); + serviceNames.forEach((name) => { + const isDefaultClient = true; + const addr = _.isString(services[name]) ? services[name] : services[name].host + ':' + services[name].port; + this._makeClient(isDefaultClient, name, addr, credentials, channelOptions); + }); + + this._initDefaultClient = true; + } + + closeClients() { + this._clientMap.forEach((client, key) => { + if (client && typeof client.close === 'function') { + client.close(); + } + }); + this._clientMap.clear(); + this._clientAddrMap.clear(); + this._initDefaultClient = false; + } + + makeCredentials(rootCerts?: any, privateKey?: any, certChain?: any, verifyOptions?: any) { + if (rootCerts && privateKey && certChain) { + return grpc.credentials.createSsl(rootCerts, privateKey, certChain, verifyOptions); + } else { + if (!this._insecureCredentials) { + this._insecureCredentials = grpc.credentials.createInsecure(); + } + return this._insecureCredentials; + } + } + + service(name: string) { + assert(this._types, 'Must called init() first. proto file has not been loaded.'); + const fullName = this._isDev ? `${this._packagePrefix}.${name}` : name; + const service = _.get(this._types, `${fullName}.service`); + assert(service, `Cannot find service with name: ${fullName}, please check if the protos file is configured incorrectly or if the corresponding proto file is missing.`); + return service; + } + + type(name: string) { + assert(this._types, 'Must called init() first. proto file has not been loaded.'); + const fullName = this._isDev ? `${this._packagePrefix}.${name}` : name; + const type = _.get(this._types, `${fullName}`); + assert(type, `Cannot find type with name: ${fullName}, please check if the protos file is configured incorrectly or if the corresponding proto file is missing.`); + return type; + } + + message(name: string) { + let root = this._reflectedRoot; + + if (root) { + const found = root.lookupType(name); + if (found) { + return found; + } + } + + const descriptor = this.type(name).fileDescriptorProtos.map((proto: any) => Descriptor.FileDescriptorProto.decode(proto)) + root = (protobuf.Root as protobuf.RootConstructor).fromDescriptor({ file: descriptor }); + + this._reflectedRoot = root; + + return root.lookupType(name); + } + + client(name: string, { host = undefined, port = undefined, timeout = undefined, credentials = undefined, channelOptions = {} }: any = {}) { + const isDefaultClient = !(host && port); + const addr = `${host}:${port}`; + const cacheKeyPrefix = isDefaultClient ? 'defaultAddr' : addr.replace(/\./g, '-'); + const cacheKey = `proxy.${cacheKeyPrefix}.${name}.${timeout}`; + + if (this._clientMap.has(cacheKey)) { + return this._clientMap.get(cacheKey); + } else { + const client = this._makeClient(isDefaultClient, name, addr, credentials, channelOptions); + const appName = this._appName; + const proxy = clientProxy._proxy(client, { timeout }, appName); + this._clientMap.set(cacheKey, proxy); + return proxy; + } + } + + realClient(name: string, { host = undefined, port = undefined, credentials = undefined, channelOptions = {} }: any = {}) { + const isDefaultClient = !(host && port); + const client = this._makeClient(isDefaultClient, name, `${host}:${port}`, credentials, channelOptions); + return client; + } + + clientWithoutCache(name: string, { addr, timeout = undefined, credentials = undefined, channelOptions = {} }: any = {}) { + const client = this._makeClientWithoutCache(false, name, addr, credentials, channelOptions); + const appName = this._appName; + const proxy = clientProxy._proxy(client, { timeout }, appName); + return proxy; + } + + private _makeClient(isDefaultClient: boolean, name: string, addr: string, credentials: any, channelOptions: any = {}) { + const ctBool = !!credentials; + const cacheKeyPrefix = isDefaultClient ? 'defaultAddr' : addr.replace(/\./g, '-'); + const cacheKeyWithCt = `${cacheKeyPrefix}.${name}.${ctBool}`; + const cacheKey = `${cacheKeyPrefix}.${name}`; + + if (this._clientMap.has(cacheKey)) { + return this._clientMap.get(cacheKey); + } else if (this._clientMap.has(cacheKeyWithCt)) { + return this._clientMap.get(cacheKeyWithCt); + } else { + let cacheAddr: string = addr + if (addr === 'undefined:undefined') { + cacheAddr = this._clientAddrMap.get(name) || addr; + } + const client = this._makeClientWithoutCache(isDefaultClient, name, cacheAddr, credentials, channelOptions); + this._clientAddrMap.set(name, cacheAddr); + this._clientMap.set(cacheKey, client); + return client; + } + } + + private _makeClientWithoutCache(isDefaultClient: boolean, name: string, addr: string, credentials: any, channelOptions: any = {}) { + channelOptions = Object.assign({}, defaultChannelOptions, channelOptions); + + const ServiceProto = this.type(name); + const client = new ServiceProto(addr, credentials || this.makeCredentials(), channelOptions); + return client; + } + + makeMetadata(initialValues: any) { + assert(this._types, 'Must called init() first. proto file has not been loaded.'); + const meta = new grpc.Metadata(); + if (typeof initialValues === 'object') { + Object.entries(initialValues).forEach(([key, value]: [string, any]) => { + if (Array.isArray(value)) { + value.map((v) => meta.add(key, _.isString(v) ? v : Buffer.from(v))); + } else { + meta.add(key, _.isString(value) ? value : Buffer.from(value)); + } + }); + } + return meta; + } + + initServer(...args: any[]) { + assert(this._types, 'Must called init() first. proto file has not been loaded.'); + const server = new ServerProxy() + return server._init(this, ...args); + } +} + +export default GrpcLoader +module.exports = GrpcLoader diff --git a/src/proxy/clientProxy.ts b/src/proxy/clientProxy.ts new file mode 100644 index 0000000..0600cf7 --- /dev/null +++ b/src/proxy/clientProxy.ts @@ -0,0 +1,326 @@ +import { Metadata, MetadataValue, UntypedServiceImplementation } from '@grpc/grpc-js'; +import * as os from 'node:os'; +import iterator from '../util/iterator'; + +class ClientProxy { + private _getFuncStreamWay(func: any): { requestStream: boolean; responseStream: boolean } { + const { requestStream, responseStream } = func; + return { requestStream, responseStream }; + } + + private _prepareMetadata(metadata: Metadata | Record, options: Record, basicMeta: Record): [Metadata, Record] { + if (metadata instanceof Metadata) { + options = { ...options }; + } else { + options = { ...metadata }; + metadata = new Metadata(); + } + + if (basicMeta.hostname) { + metadata.add('x-client-hostname', basicMeta.hostname as MetadataValue); + } + + if (basicMeta.appName) { + metadata.add('x-client-app-name',basicMeta.appName as MetadataValue); + } + + return [metadata, options]; + } + + private _handlerError(err: any, basicMeta: Record) { + const newError = new Error() as { name: string; code: string; message: string; stack: string }; + + newError.name = 'GrpcClientError'; + newError.code = err.code; + newError.message = `${basicMeta.fullServiceName} (${err.message})`; + + const stacks = newError.stack!.split('\n'); + newError.stack = [ + stacks[0], + ...stacks.slice(2), + ' ...', + ...(err.stack!.split('\n').slice(1, 3) as string[]), + ].join('\n'); + + return newError; + } + + private _setDeadline(options: { deadline?: Date; timeout?: number }, defaultOptions: Record, basicMeta: { fullServiceName?: string }): { deadline?: Date } { + if (!options.deadline) { + const timeout = options.timeout || defaultOptions.timeout; + const deadline = new Date(Date.now() + (timeout as number)); + options.deadline = deadline; + delete options.timeout; + } + return options; + } + + private _promisifyUnaryMethod( + client: UntypedServiceImplementation, + func: any, + defaultOptions: Record, + basicMeta: Record + ): any { + const asyncUnaryMethod = async ( + request: any, + metadata: Metadata, + options: Record + ): Promise => { + if (typeof options === 'function') { + throw new Error('gRPCity: AsyncFunction should not contain a callback function'); + } else if (typeof metadata === 'function') { + throw new Error('gRPCity: AsyncFunction should not contain a callback function'); + } + + [metadata, options] = this._prepareMetadata(metadata, options, basicMeta); + options = this._setDeadline(options, defaultOptions, basicMeta); + + return new Promise((resolve, reject) => { + const result: { response?: any; metadata?: any; status?: any } = {}; + const argumentsList: Array = [request, metadata, options]; + argumentsList.push((err: any, response: any) => { + if (err) { + reject(this._handlerError(err, basicMeta)); + } + result.response = response; + }); + + const call = func.apply(client, argumentsList); + + call.on('metadata', (metadata: any) => { + result.metadata = metadata; + }); + call.on('status', (status: any) => { + result.status = status; + resolve(result); + }); + }); + }; + return asyncUnaryMethod; + } + + private _promisifyClientStreamMethod( + client: UntypedServiceImplementation, + func: any, + defaultOptions: Record, + basicMeta: Record + ): any { + const clientStreamMethod = ( + metadata: Metadata, + options: Record + ): any => { + if (typeof options === 'function') { + throw new Error('gRPCity: asyncStreamFunction should not contain a callback function'); + } else if (typeof metadata === 'function') { + throw new Error('gRPCity: asyncStreamFunction should not contain a callback function'); + } + + [metadata, options] = this._prepareMetadata(metadata, options, basicMeta); + options = this._setDeadline(options, defaultOptions, basicMeta); + + const result: { response?: any; metadata?: any; status?: any } = {}; + + const argumentsList: Array = [metadata, options]; + argumentsList.push((err: any, response: any) => { + if (err) { + throw this._handlerError(err, basicMeta); + } + result.response = response; + }); + + const call = func.apply(client, argumentsList); + + call.writeAll = (messages: any[]) => { + if (Array.isArray(messages)) { + messages.forEach((message) => { + call.write(message); + }); + } + }; + call.writeEnd = async () => { + call.end(); + await new Promise((resolve, reject) => { + call.on('metadata', (metadata: any) => { + result.metadata = metadata; + }); + call.on('status', (status: any) => { + result.status = status; + resolve(); + }); + }); + return result; + }; + + return call; + }; + + return clientStreamMethod; + } + + private _promisifyServerStreamMethod( + client: UntypedServiceImplementation, + func: any, + defaultOptions: Record, + basicMeta: { fullServiceName?: string } + ): any { + const serverStreamMethod = ( + request: any, + metadata: Metadata, + options: Record + ): any => { + if (typeof options === 'function') { + throw new Error('gRPCity: asyncStreamFunction should not contain a callback function'); + } else if (typeof metadata === 'function') { + throw new Error('gRPCity: asyncStreamFunction should not contain a callback function'); + } + + [metadata, options] = this._prepareMetadata(metadata, options, basicMeta); + options = this._setDeadline(options, defaultOptions, basicMeta); + + const call = func.apply(client, [request, metadata, options]); + + call.on('error', (err: Error) => { + throw this._handlerError(err, basicMeta); + }); + + const result: { metadata?: any; status?: any } = {}; + call.readAll = () => { + call.on('metadata', (metadata: any) => { + result.metadata = metadata; + }); + call.on('status', (status: any) => { + result.status = status; + }); + return iterator(call, 'data', { + resolutionEvents: ['status', 'end'], + }); + }; + call.readEnd = () => { + return result; + }; + + return call; + }; + + return serverStreamMethod; + } + + private _promisifyDuplexStreamMethod( + client: UntypedServiceImplementation, + func: any, + defaultOptions: Record, + basicMeta: { fullServiceName?: string } + ): any { + const duplexStreamMethod = ( + metadata: Metadata, + options: Record + ): any => { + if (typeof options === 'function') { + throw new Error('gRPCity: asyncStreamFunction should not contain a callback function'); + } else if (typeof metadata === 'function') { + throw new Error('gRPCity: asyncStreamFunction should not contain a callback function'); + } + + [metadata, options] = this._prepareMetadata(metadata, options, basicMeta); + options = this._setDeadline(options, defaultOptions, basicMeta); + + const call = func.apply(client, [metadata, options]); + + call.writeAll = (messages: any[]) => { + if (Array.isArray(messages)) { + messages.forEach((message) => { + call.write(message); + }); + } + }; + call.writeEnd = call.end; + + call.on('error', (err: Error) => { + throw this._handlerError(err, basicMeta); + }); + + const result: { metadata?: any; status?: any } = {}; + call.readAll = () => { + call.on('metadata', (metadata: any) => { + result.metadata = metadata; + }); + call.on('status', (status: any) => { + result.status = status; + }); + return iterator(call, 'data', { + resolutionEvents: ['status', 'end'], + }); + }; + call.readEnd = () => { + return result; + }; + + return call; + }; + + return duplexStreamMethod; + } + + private _keepCallbackMethod(client: UntypedServiceImplementation, func: any): (...argumentsList: any[]) => any { + const callbackMethod = (...argumentsList: any[]) => { + return func.apply(client, argumentsList); + }; + return callbackMethod; + } + + _proxy( + client: UntypedServiceImplementation, + defaultOptions: Record = {}, + appName?: string + ): any { + defaultOptions = defaultOptions || {}; + defaultOptions.timeout = defaultOptions.timeout || 1000 * 10; + + const prototype = Object.getPrototypeOf(client); + + const methodNames: any = Object.keys(prototype) + .filter((key) => prototype[key] && prototype[key].path) + .reduce((names: any, key) => { + names[key.toUpperCase()] = prototype[key].path; + return names; + }, {}); + + const basicMeta: Record = { hostname: os.hostname(), appName }; + + const target = Object.entries(prototype).reduce((target: any, [name, func]) => { + if (name !== 'constructor' && typeof func === 'function') { + basicMeta.fullServiceName = `${methodNames[name.toUpperCase()]}`; + + const { requestStream, responseStream } = this._getFuncStreamWay(func); + + if (!requestStream && !responseStream) { + // promisify unary method + target[name] = this._promisifyUnaryMethod(client, func, defaultOptions, basicMeta); + } + + // stream + if (requestStream && !responseStream) { + // promisify only client stream method + target[name] = this._promisifyClientStreamMethod(client, func, defaultOptions, basicMeta); + } + if (!requestStream && responseStream) { + // promisify only server stream method + target[name] = this._promisifyServerStreamMethod(client, func, defaultOptions, basicMeta); + } + if (requestStream && responseStream) { + // promisify duplex stream method + target[name] = this._promisifyDuplexStreamMethod(client, func, defaultOptions, basicMeta); + } + + // keep callback method + target.call[name] = this._keepCallbackMethod(client, func); + } + + return target; + }, { call: {} }); + + return target; + } +} + +export default new ClientProxy(); diff --git a/src/proxy/serverProxy.ts b/src/proxy/serverProxy.ts new file mode 100644 index 0000000..b3dd48c --- /dev/null +++ b/src/proxy/serverProxy.ts @@ -0,0 +1,294 @@ +import assert from 'node:assert'; +import * as util from 'node:util'; +import * as grpc from '@grpc/grpc-js'; +import * as _ from 'lodash'; +import * as Joi from 'joi'; +import serverSchemas from '../schema/server'; +import iterator from '../util/iterator'; +import { compose, MiddlewareFunction } from '../util/compose'; + +class ServerProxy { + private _middleware: MiddlewareFunction[]; + + private _loader?: any; + private _server?: grpc.Server; + private _insecureServerCredentials?: grpc.ServerCredentials; + + constructor() { + this._middleware = []; + } + + _init(loader: any, ...args: any[]): this { + if (!this._loader) { + this._loader = loader; + } + if (!this._server) { + this._server = new grpc.Server(...args); + } + return this; + } + + async listen(addr: any, credentials: grpc.ServerCredentials | undefined = undefined): Promise { + assert(this._server, 'must be first init() server before server listen()'); + Joi.assert(addr, serverSchemas.address, 'server listen() params Error'); + + const url = _.isString(addr) ? addr : `${addr.host}:${addr.port}`; + const bindPort = await new Promise((resolve, reject) => { + this._server!.bindAsync(url, credentials || this.makeServerCredentials(), (err, result) => ( + err ? reject(err) : resolve(result) + )); + }); + const port = addr.port ? addr.port : Number(addr.match(/:(\d+)/)![1]); + assert(bindPort === port, 'server bind port not to be right'); + + this._server!.start(); + } + + async shutdown(): Promise { + if (!this._server) { + return; + } + + await new Promise((resolve, reject) => { + this._server!.tryShutdown(err => { + if (err) { + reject(err); + } else { + resolve(); + } + }); + }); + + delete this._server; + delete this._loader; + } + + forceShutdown(): void { + if (!this._server) { + return; + } + + this._server!.forceShutdown(); + delete this._server; + delete this._loader; + } + + makeServerCredentials(rootCerts?: Buffer, keyCertPairs?: grpc.KeyCertPair[], checkClientCertificate?: boolean): grpc.ServerCredentials { + if (rootCerts && keyCertPairs) { + return grpc.ServerCredentials.createSsl(rootCerts, keyCertPairs, checkClientCertificate); + } else { + if (!this._insecureServerCredentials) { + this._insecureServerCredentials = grpc.ServerCredentials.createInsecure(); + } + return this._insecureServerCredentials; + } + } + + addService(name: string, implementation: any, { exclude = [], inherit }: { exclude?: string[], inherit?: any } = {}): void { + const service = this._loader.service(name); + + const options: any = { exclude, inherit, _implementationType: {} }; + Object.keys(service).forEach(key => { + const { requestStream, responseStream } = service[key]; + options._implementationType[service[key].originalName] = { requestStream, responseStream }; + }); + + this._server!.addService(service, this._callbackify(implementation, options)); + } + + removeService(name: string): void { + assert(this._server, 'must be first init() server before server removeService()'); + this._server!.removeService(this._loader.service(name)); + } + + addMiddleware(...args: MiddlewareFunction[]): void { + assert(args.length >= 1, 'server addMiddleware() takes at least one argument.'); + if (args.length === 1) { + if (Array.isArray(args[0])) { + args[0].forEach(fn => { + this._use(fn); + }); + } else { + this._use(args[0]); + } + } else { + args.forEach(fn => { + this._use(fn); + }); + } + } + + private _use(fn: MiddlewareFunction): void { + if (typeof fn !== 'function') throw new TypeError('grpcity loader server middleware must be a function!'); + this._middleware.push(fn); + } + + private _callbackify(target: any, { exclude = [], inherit, _implementationType }: { exclude?: string[], inherit?: any, _implementationType: any }): any { + assert(typeof target === 'object', 'Must callbackify an object'); + assert(Array.isArray(exclude), 'options.exclude must be an array of strings'); + + const protoPropertyNames = Object.getOwnPropertyNames(Object.getPrototypeOf({})); + exclude.push(...protoPropertyNames); + + const allPropertyNames = [ + ...new Set([ + ...Object.keys(target), + ...Object.getOwnPropertyNames(Object.getPrototypeOf(target)), + ...(inherit && inherit.prototype ? Object.getOwnPropertyNames(inherit.prototype) : []) + ]) + ]; + + const methods: { [key: string]: any } = {}; + for (const key of allPropertyNames) { + const fn = target[key]; + if (typeof fn === 'function' && key !== 'constructor' && !exclude.includes(key)) { + if (util.types.isAsyncFunction(fn)) { + const eglWrapFunction = this._proxy(target, key, _implementationType[key]); + methods[key] = eglWrapFunction; + } else { + methods[key] = fn; + } + } + } + + return methods; + } + + private _proxy(target: any, key: string, options: any = {}): any { + const { requestStream, responseStream } = options; + + const fn = compose(this._middleware); + + // unary + if (!requestStream && !responseStream) { + return this._callUnaryProxyMethod(target, key, fn); + } + // client stream + if (requestStream && !responseStream) { + return this._callClientStreamProxyMethod(target, key, fn); + } + // server stream + if (!requestStream && responseStream) { + return this._callServerStreamProxyMethod(target, key, fn); + } + // duplex stream + if (requestStream && responseStream) { + return this._callDuplexStreamProxyMethod(target, key, fn); + } + } + + private _createContext(call: any): any { + return { + // TODO: maybe need more details + // method: target.constructor.name + '.' + key, + path: call.call.handler.path || '', + request: call.request, + metadata: call.metadata.clone() + }; + } + + private _callUnaryProxyMethod(target: any, key: string, composeFunc: Function): grpc.handleUnaryCall { + return (call, callback) => { + const ctx = this._createContext(call); + + Promise.resolve().then(async () => { + const handleResponse = async () => { + ctx.response = await target[key](call); + }; + await composeFunc(ctx, handleResponse).catch((err: Error) => { + callback(this._createInternalErrorStatus(err)); + }); + callback(null, ctx.response); + }); + }; + } + + private _callClientStreamProxyMethod(target: any, key: string, composeFunc: Function): any { + return (call: any, callback: Function) => { + const ctx = this._createContext(call); + + call.readAll = () => { + return iterator(call, 'data', { + resolutionEvents: ['end'] + }); + }; + + Promise.resolve().then(async () => { + const handleResponse = async () => { + ctx.response = await target[key](call); + }; + await composeFunc(ctx, handleResponse).catch((err: Error) => { + callback(this._createInternalErrorStatus(err)); + }); + callback(null, ctx.response); + }); + }; + } + + private _callServerStreamProxyMethod(target: any, key: string, composeFunc: Function): any { + return (call: any) => { + const ctx = this._createContext(call); + + call.writeAll = (messages: any[]) => { + if (Array.isArray(messages)) { + messages.forEach(message => { + call.write(message); + }); + } + }; + call.writeEnd = call.end; + + Promise.resolve().then(async () => { + const handleResponse = async () => { + await target[key](call); + }; + await composeFunc(ctx, handleResponse).catch((err: Error) => { + call.destroy(this._createInternalErrorStatus(err)); + }); + call.end(); + }); + }; + } + + private _callDuplexStreamProxyMethod(target: any, key: string, composeFunc: Function): any { + return (call: any) => { + const ctx = this._createContext(call); + + call.writeAll = (messages: any[]) => { + if (Array.isArray(messages)) { + messages.forEach(message => { + call.write(message); + }); + } + }; + call.readAll = () => { + return iterator(call, 'data', { + resolutionEvents: ['end'] + }); + }; + + Promise.resolve().then(async () => { + const handleResponse = async () => { + await target[key](call); + }; + await composeFunc(ctx, handleResponse).catch((err: Error) => { + call.destroy(this._createInternalErrorStatus(err)); + }); + call.end(); + }); + }; + } + + private _createInternalErrorStatus(err: any): any { + err.code = err.code || 13; + if (typeof err.stack === 'string') { + const stack = err.stack.split('\n'); + err.messages += ` [Error Message From Server, stack: ${stack[1].trim()}]`; + } else { + err.messages += ' [Error Message From Server]'; + } + return err; + } +} + +export default ServerProxy; diff --git a/src/schema/loader.ts b/src/schema/loader.ts new file mode 100644 index 0000000..5632fbb --- /dev/null +++ b/src/schema/loader.ts @@ -0,0 +1,33 @@ +import Joi from 'joi'; + +const addressSchema = Joi.object() + .pattern(/\.*/, Joi.alternatives([ + Joi.string().regex(/:/, 'host and port like 127.0.0.1:9090'), + Joi.object({ + host: Joi.string().required(), + port: Joi.number().integer().min(0).max(65535).required() + }) + ])); + +const loaderSchemas = { + constructor: Joi.array().items( + Joi.object({ + location: Joi.string().required(), + files: Joi.array().items(Joi.string()).required() + }) + ).single(), + init: Joi.object({ + services: addressSchema.optional(), + isDev: Joi.boolean().optional(), + packagePrefix: Joi.string().optional(), + loadOptions: Joi.object().optional(), + channelOptions: Joi.object().optional(), + appName: Joi.string().optional() + }), + initClients: Joi.object({ + services: addressSchema.required(), + channelOptions: Joi.object().optional() + }) +}; + +export default loaderSchemas; diff --git a/src/schema/server.ts b/src/schema/server.ts new file mode 100644 index 0000000..3b22adf --- /dev/null +++ b/src/schema/server.ts @@ -0,0 +1,13 @@ +import Joi from 'joi'; + +const serverSchemas = { + address: Joi.alternatives([ + Joi.string().regex(/:/, 'host and port like 127.0.0.1:9090'), + Joi.object({ + host: Joi.string().required(), + port: Joi.number().integer().min(0).max(65535).required() + }) + ]) +}; + +export default serverSchemas; diff --git a/src/util/compose.ts b/src/util/compose.ts new file mode 100644 index 0000000..1a44caa --- /dev/null +++ b/src/util/compose.ts @@ -0,0 +1,41 @@ +export type MiddlewareFunction = ( + context: any, + next: () => Promise +) => Promise; + +/** + * Compose `middleware` returning + * a fully valid middleware comprised + * of all those which are passed. + * + * @param {Array} middleware + * @return {Function} + * @api public + */ +export const compose = (middleware: MiddlewareFunction[]) => { + if (!Array.isArray(middleware)) + throw new TypeError("Middleware stack must be an array!"); + for (const fn of middleware) { + if (typeof fn !== "function") + throw new TypeError("Middleware must be composed of functions!"); + } + + return function (context: any, next: () => Promise) { + // last called middleware # + let index = -1; + return dispatch(0); + function dispatch(i: number): Promise { + if (i <= index) + return Promise.reject(new Error("next() called multiple times")); + index = i; + let fn = middleware[i]; + if (i === middleware.length) fn = next; + if (!fn) return Promise.resolve(); + try { + return Promise.resolve(fn(context, dispatch.bind(null, i + 1))); + } catch (err) { + return Promise.reject(err); + } + } + }; +}; diff --git a/src/util/iterator.ts b/src/util/iterator.ts new file mode 100644 index 0000000..2881a9f --- /dev/null +++ b/src/util/iterator.ts @@ -0,0 +1,200 @@ +const symbolAsyncIterator = Symbol.asyncIterator || "@@asyncIterator"; + +const normalizeEmitter = ( + emitter: any +): { addListener: Function; removeListener: Function } => { + const addListener = + emitter.on || emitter.addListener || emitter.addEventListener; + const removeListener = + emitter.off || emitter.removeListener || emitter.removeEventListener; + + if (!addListener || !removeListener) { + throw new TypeError("Emitter is not compatible"); + } + + return { + addListener: addListener.bind(emitter), + removeListener: removeListener.bind(emitter), + }; +}; + +const toArray = (value: any): any[] => (Array.isArray(value) ? value : [value]); + +export default ( + emitter: any, + event: string | string[], + options: any +) => { + if (typeof options === "function") { + options = { filter: options }; + } + + // Allow multiple events + const events = toArray(event); + + options = { + rejectionEvents: ["error"], + resolutionEvents: [], + limit: Infinity, + multiArgs: false, + ...options, + }; + + const { limit } = options; + const isValidLimit = + limit >= 0 && (limit === Infinity || Number.isInteger(limit)); + if (!isValidLimit) { + throw new TypeError( + "The `limit` option should be a non-negative integer or Infinity" + ); + } + + if (limit === 0) { + // Return an empty async iterator to avoid any further cost + return { + [Symbol.asyncIterator](): any { + return this; + }, + async next(): Promise<{ done: boolean; value: any }> { + return { + done: true, + value: undefined, + }; + }, + }; + } + + const { addListener, removeListener } = normalizeEmitter(emitter); + + let isDone = false; + let error: any; + let hasPendingError = false; + const nextQueue: { resolve: Function; reject: Function }[] = []; + const valueQueue: any[] = []; + let eventCount = 0; + let isLimitReached = false; + + const valueHandler = (...args: any[]): void => { + eventCount++; + isLimitReached = eventCount === limit; + + const value = options.multiArgs ? args : args[0]; + + if (nextQueue.length > 0) { + const { resolve } = nextQueue.shift()!; + resolve({ done: false, value }); + + if (isLimitReached) { + cancel(); + } + + return; + } + + valueQueue.push(value); + + if (isLimitReached) { + cancel(); + } + }; + + const cancel = (): void => { + isDone = true; + for (const event of events) { + removeListener(event, valueHandler); + } + + for (const rejectionEvent of options.rejectionEvents!) { + removeListener(rejectionEvent, rejectHandler); + } + + for (const resolutionEvent of options.resolutionEvents!) { + removeListener(resolutionEvent, resolveHandler); + } + + while (nextQueue.length > 0) { + const { resolve } = nextQueue.shift()!; + resolve({ done: true, value: undefined }); + } + }; + + const rejectHandler = (...args: any[]): void => { + error = options.multiArgs ? args : args[0]; + + if (nextQueue.length > 0) { + const { reject } = nextQueue.shift()!; + reject(error); + } else { + hasPendingError = true; + } + + cancel(); + }; + + const resolveHandler = (...args: any[]): void => { + const value = options.multiArgs ? args : args[0]; + + if (options.filter && !options.filter(value)) { + return; + } + + if (nextQueue.length > 0) { + const { resolve } = nextQueue.shift()!; + resolve({ done: true, value }); + } else { + valueQueue.push(value); + } + + cancel(); + }; + + for (const event of events) { + addListener(event, valueHandler); + } + + for (const rejectionEvent of options.rejectionEvents!) { + addListener(rejectionEvent, rejectHandler); + } + + for (const resolutionEvent of options.resolutionEvents!) { + addListener(resolutionEvent, resolveHandler); + } + + return { + [symbolAsyncIterator](): any { + return this; + }, + async next(): Promise<{ done: boolean; value: any }> { + if (valueQueue.length > 0) { + const value = valueQueue.shift(); + return { + done: isDone && valueQueue.length === 0 && !isLimitReached, + value, + }; + } + + if (hasPendingError) { + hasPendingError = false; + throw error; + } + + if (isDone) { + return { + done: true, + value: undefined, + }; + } + + return new Promise((resolve, reject) => + nextQueue.push({ resolve, reject }) + ); + }, + async return(value: any): Promise<{ done: boolean; value: any }> { + cancel(); + return { + done: isDone, + value, + }; + }, + }; +}; diff --git a/src/util/prefixingDefinition.ts b/src/util/prefixingDefinition.ts new file mode 100644 index 0000000..d98b391 --- /dev/null +++ b/src/util/prefixingDefinition.ts @@ -0,0 +1,24 @@ +export default (packageDefinition: any, packagePrefix: any) => { + for (const qualifiedName in packageDefinition) { + const definition = packageDefinition[qualifiedName]; + const newPackage = `${packagePrefix}.${qualifiedName}`; + if ( + definition.format && + definition.type && + definition.fileDescriptorProtos + ) { + packageDefinition[newPackage] = definition; + } else { + const newDefinition: any = {}; + for (const method in definition) { + const service = definition[method]; + newDefinition[method] = Object.assign({}, service, { + path: service.path.replace(/^\//, `/${packagePrefix}.`), + }); + } + packageDefinition[newPackage] = newDefinition; + } + } + + return packageDefinition; +}; From e81319fcd4af3a8c4185ee12833ce6b5374fe8ac Mon Sep 17 00:00:00 2001 From: "Chakhsu.Lau" Date: Sun, 3 Dec 2023 17:25:57 +0800 Subject: [PATCH 02/12] feat: remove lib --- lib/config/defaultChannelOptions.js | 32 --- lib/config/defaultLoadOptions.js | 8 - lib/index.js | 240 ---------------------- lib/proxy/clientProxy.js | 306 ---------------------------- lib/proxy/serverProxy.js | 295 --------------------------- lib/schema/loader.js | 31 --- lib/schema/server.js | 13 -- lib/util/compose.js | 33 --- lib/util/iterator.js | 188 ----------------- lib/util/prefixingDefinition.js | 18 -- 10 files changed, 1164 deletions(-) delete mode 100755 lib/config/defaultChannelOptions.js delete mode 100644 lib/config/defaultLoadOptions.js delete mode 100755 lib/index.js delete mode 100755 lib/proxy/clientProxy.js delete mode 100644 lib/proxy/serverProxy.js delete mode 100644 lib/schema/loader.js delete mode 100644 lib/schema/server.js delete mode 100644 lib/util/compose.js delete mode 100644 lib/util/iterator.js delete mode 100644 lib/util/prefixingDefinition.js diff --git a/lib/config/defaultChannelOptions.js b/lib/config/defaultChannelOptions.js deleted file mode 100755 index 9247107..0000000 --- a/lib/config/defaultChannelOptions.js +++ /dev/null @@ -1,32 +0,0 @@ -// gRPC options, doc: https://grpc.github.io/grpc/core/group__grpc__arg__keys.html -module.exports = { - // grpc library options accept only numeric and string types - // Configure grpc reconnect time (1s to 10s random number) - 'grpc.min_reconnect_backoff_ms': 1000, - 'grpc.max_reconnect_backoff_ms': 10000, - // Communication timeout - 'grpc.grpclb_call_timeout_ms': 5000, - // The following 3 parameters address the issue of long-idle gRPC clients not promptly detecting TCP connection breaks - // After waiting for a duration of this time, if the keepalive ping sender does not receive the ping ack, it will close the transport. - 'grpc.keepalive_timeout_ms': (20 * 1000), - // duration of this time the client/server pings its peer to see if the transport is still alive - 'grpc.keepalive_time_ms': (120 * 1000), - 'grpc.keepalive_permit_without_calls': 1, - // Communication failure allows grpc library retry - 'grpc.enable_retries': 1, - // Configure retry parameters - // Reference: https://github.com/grpc/proposal/blob/master/A6-client-retries.md#integration-with-service-config - 'grpc.service_config': JSON.stringify({ - retryPolicy: { - // 1 normal send + 3 failed retries, each retry has the opportunity to be sent on a different subchannel than the original failure - maxAttempts: 4, - // Initial retry time interval: random(0, initialBackoff) seconds - // The nth retry time; random(0, min(initialBackoff*backoffMultiplier^(n-1), maxBackoff)) seconds - initialBackoff: '0.1s', - maxBackoff: '1s', - backoffMultiplier: 2, - // Retry only in the case of network unavailability - retryableStatusCodes: ['UNAVAILABLE'] - } - }) -} diff --git a/lib/config/defaultLoadOptions.js b/lib/config/defaultLoadOptions.js deleted file mode 100644 index 748a050..0000000 --- a/lib/config/defaultLoadOptions.js +++ /dev/null @@ -1,8 +0,0 @@ -// GRPC protos loader options, doc: https://www.npmjs.com/package/@grpc/proto-loader -module.exports = { - keepCase: true, - longs: String, - enums: String, - defaults: false, - oneofs: true -} diff --git a/lib/index.js b/lib/index.js deleted file mode 100755 index eb04386..0000000 --- a/lib/index.js +++ /dev/null @@ -1,240 +0,0 @@ -const assert = require('assert') - -const grpc = require('@grpc/grpc-js') -const protoLoader = require('@grpc/proto-loader') -const protobuf = require('protobufjs') -const Descriptor = require('protobufjs/ext/descriptor') - -const Joi = require('joi') -const _ = require('lodash') - -const loaderSchemas = require('./schema/loader') -const prefixingDefinition = require('./util/prefixingDefinition') -const defaultChannelOptions = require('./config/defaultChannelOptions') -const defaultLoadOptions = require('./config/defaultLoadOptions') -const clientProxy = require('./proxy/clientProxy') -const serverProxy = require('./proxy/serverProxy') - -const debug = require('debug')('grpcity') - -module.exports = class GrpcLoader { - constructor (protoFileOptions) { - Joi.assert(protoFileOptions, loaderSchemas.constructor, 'new GrpcLoader() params Error') - - this._protoFiles = Array.isArray(protoFileOptions) ? protoFileOptions : [protoFileOptions] - this._clientMap = new Map() - this._clientAddrMap = new Map() - } - - async init ({ services = undefined, isDev = false, packagePrefix = '', loadOptions = {}, channelOptions = {}, appName } = {}) { - Joi.assert({ services, loadOptions, isDev, channelOptions, appName }, loaderSchemas.init, 'GrpcLoader.init() params Error') - - debug('init()', { services, loadOptions, isDev, channelOptions, appName }) - - if (this._types) { - return - } - - try { - loadOptions = Object.assign({}, defaultLoadOptions, loadOptions) - this._isDev = isDev - this._packagePrefix = packagePrefix - this._appName = appName - - loadOptions.includeDirs = this._protoFiles.map(p => p.location).concat(loadOptions.includeDirs || []) - const files = this._protoFiles.reduce((result, p) => { - if (p.files && p.files.length > 0) { result.push(...p.files) } - return result - }, []) - - const packageDefinition = await protoLoader.load(files, loadOptions) - - if (this._packagePrefix) { - this._packageDefinition = prefixingDefinition(packageDefinition, packagePrefix) - } else { - this._packageDefinition = packageDefinition - } - - this._types = grpc.loadPackageDefinition(this._packageDefinition) - } catch (err) { - debug(err.message, { err }, this._protoFiles) - throw err - } - - if (services) { - await this.initClients({ services, channelOptions }) - } - } - - async initClients ({ services, channelOptions = {}, credentials = undefined }) { - Joi.assert({ services, channelOptions }, loaderSchemas.initClients, 'GrpcLoader.initClients() Options Error') - - debug('initClients()', { services }) - - if (this._initDefaultClient) { - return - } - - if (!this._packageDefinition) { - await this.init() - } - - const serviceNames = Object.keys(services) - serviceNames.forEach(name => { - const isDefaultClient = true - const addr = _.isString(services[name]) ? services[name] : services[name].host + ':' + services[name].port - this._makeClient(isDefaultClient, name, addr, credentials, channelOptions) - }) - - this._initDefaultClient = true - } - - closeClients () { - this._clientMap.forEach((client, key) => { - if (client && typeof client.close === 'function') { - client.close() - } - }) - this._clientMap.clear() - this._clientAddrMap.clear() - this._initDefaultClient = false - } - - makeCredentials (rootCerts, privateKey, certChain, verifyOptions) { - if (rootCerts) { - return grpc.credentials.createSsl(rootCerts, privateKey, certChain, verifyOptions) - } else { - if (!this._insecureCredentials) { - this._insecureCredentials = grpc.credentials.createInsecure() - } - return this._insecureCredentials - } - } - - service (name) { - assert(this._types, 'Must called init() first. proto file has not been loaded.') - const fullName = this._isDev ? `${this._packagePrefix}.${name}` : name - debug('get service:', fullName) - const service = _.get(this._types, `${fullName}.service`) - assert(service, `Cannot find service with name: ${fullName}, please check if the protos file is configured incorrectly or if the corresponding proto file is missing.`) - return service - } - - type (name) { - assert(this._types, 'Must called init() first. proto file has not been loaded.') - const fullName = this._isDev ? `${this._packagePrefix}.${name}` : name - debug('get type:', fullName) - const type = _.get(this._types, `${fullName}`) - assert(type, `Cannot find type with name: ${fullName}, please check if the protos file is configured incorrectly or if the corresponding proto file is missing.`) - return type - } - - message (name) { - let root = this._reflectedRoot - - if (root) { - const found = root.lookupType(name) - if (found) { return found } - } - - debug('create reflected message root:', name) - root = protobuf.Root.fromDescriptor({ - file: this.type(name).fileDescriptorProtos.map(proto => Descriptor.FileDescriptorProto.decode(proto)) - }, root) - - this._reflectedRoot = root - - return root.lookupType(name) - } - - // async method client, cached by { name, host, port } - client (name, { host = undefined, port = undefined, timeout = undefined, credentials = undefined, channelOptions = {} } = {}) { - const isDefaultClient = !(host && port) - const addr = `${host}:${port}` - const cacheKeyPrefix = isDefaultClient ? 'defaultAddr' : addr.replace(/\./g, '-') - const cacheKey = `proxy.${cacheKeyPrefix}.${name}.${timeout}` - - if (this._clientMap.has(cacheKey)) { - return this._clientMap.get(cacheKey) - } else { - const client = this._makeClient(isDefaultClient, name, addr, credentials, channelOptions) - const appName = this._appName - const proxy = clientProxy._proxy(client, { timeout }, appName) - this._clientMap.set(cacheKey, proxy) - return proxy - } - } - - // callback method client, cached by { name, host, port } - realClient (name, { host = undefined, port = undefined, credentials = undefined, channelOptions = {} } = {}) { - const isDefaultClient = !(host && port) - const client = this._makeClient(isDefaultClient, name, `${host}:${port}`, credentials, channelOptions) - return client - } - - // async method client, no cache. - // (used in conjunction with external service registration and discovery functionality) - clientWithoutCache (name, { addr, timeout = undefined, credentials = undefined, channelOptions = {} } = {}) { - const client = this._makeClientWithoutCache(false, name, addr, credentials, channelOptions) - const appName = this._appName - const proxy = clientProxy._proxy(client, { timeout }, appName) - return proxy - } - - _makeClient (isDefaultClient, name, addr, credentials, channelOptions = {}) { - const ctBool = !!credentials - const cacheKeyPrefix = isDefaultClient ? 'defaultAddr' : addr.replace(/\./g, '-') - const cacheKeyWithCt = `${cacheKeyPrefix}.${name}.${ctBool}` - const cacheKey = `${cacheKeyPrefix}.${name}` - - if (this._clientMap.has(cacheKey)) { - return this._clientMap.get(cacheKey) - } else if (this._clientMap.has(cacheKeyWithCt)) { - return this._clientMap.get(cacheKeyWithCt) - } else { - if (addr === 'undefined:undefined') { - addr = this._clientAddrMap.get(name) - } - const client = this._makeClientWithoutCache(isDefaultClient, name, addr, credentials, channelOptions = {}) - this._clientAddrMap.set(name, addr) - this._clientMap.set(cacheKey, client) - return client - } - } - - _makeClientWithoutCache (isDefaultClient, name, addr, credentials, channelOptions = {}) { - channelOptions = Object.assign({}, defaultChannelOptions, channelOptions) - debug('_makeClient()', { channelOptions }) - - const ServiceProto = this.type(name) - const client = new ServiceProto(addr, credentials || this.makeCredentials(), channelOptions) - debug(`create client: isDefaultClient=${isDefaultClient} serviceName=${name} addr=${addr}`) - return client - } - - makeMetadata (initialValues) { - assert(this._types, 'Must called init() first. proto file has not been loaded.') - const meta = new grpc.Metadata() - if (typeof initialValues === 'object') { - Object.entries(initialValues).forEach(([key, value]) => { - if (Array.isArray(value)) { - value.map(v => meta.add( - key, - _.isString(v) ? v : Buffer.from(v) - )) - } else { - meta.add( - key, - _.isString(value) ? value : Buffer.from(value) - ) - } - }) - } - return meta - } - - initServer (...args) { - assert(this._types, 'Must called init() first. proto file has not been loaded.') - return serverProxy._init(this, ...args) - } -} diff --git a/lib/proxy/clientProxy.js b/lib/proxy/clientProxy.js deleted file mode 100755 index d4a94cc..0000000 --- a/lib/proxy/clientProxy.js +++ /dev/null @@ -1,306 +0,0 @@ -const { Metadata } = require('@grpc/grpc-js') -const os = require('os') -const iterator = require('../util/iterator') - -const debug = require('debug')('grpcity:clientProxy') - -class ClientProxy { - _proxy (client, defaultOptions = { }, appName = undefined) { - defaultOptions = defaultOptions || {} - defaultOptions.timeout = defaultOptions.timeout || 1000 * 10 - - const prototype = Object.getPrototypeOf(client) - - const methodNames = Object.keys(prototype) - .filter(key => prototype[key] && prototype[key].path) - .reduce((names, key) => { - names[key.toUpperCase()] = prototype[key].path - return names - }, {}) - - const basicMeta = { hostname: os.hostname(), appName } - - const target = Object.entries(prototype).filter(([name, func]) => { - return name !== 'constructor' && typeof func === 'function' - }).reduce((target, [name, func]) => { - basicMeta.fullServiceName = `${methodNames[name.toUpperCase()]}` - debug('proxy method', basicMeta) - - const { requestStream, responseStream } = this._getFuncStreamWay(func) - - if (!requestStream && !responseStream) { - // promisify unary method - target[name] = this._promisifyUnaryMethod(client, func, defaultOptions, basicMeta) - } - - // stream - if (requestStream && !responseStream) { - // promisify only client stream method - target[name] = this._promisifyClientStreamMethod(client, func, defaultOptions, basicMeta) - } - if (!requestStream && responseStream) { - // promisify only server stream method - target[name] = this._promisifyServerStreamMethod(client, func, defaultOptions, basicMeta) - } - if (requestStream && responseStream) { - // promisify duplex stream method - target[name] = this._promisifyDuplexStreamMethod(client, func, defaultOptions, basicMeta) - } - - // keep callback method - target.call[name] = this._keepCallbackMethod(client, func) - - return target - }, { call: {} }) - - return target - } - - _getFuncStreamWay (func) { - const { requestStream, responseStream } = func - return { requestStream, responseStream } - } - - _promisifyUnaryMethod (client, func, defaultOptions, basicMeta) { - const asyncUnaryMethod = async (request, metadata, options) => { - if (typeof options === 'function') { - throw new Error('gRPCity: AsyncFunction should not contain callback function') - } else if (typeof metadata === 'function') { - throw new Error('gRPCity: AsyncFunction should not contain callback function') - } - - [metadata, options] = this._prepareMetadata(metadata, options, basicMeta) - options = this._setDeadline(options, defaultOptions, basicMeta) - - return new Promise((resolve, reject) => { - const result = {} - const argumentsList = [request, metadata, options] - argumentsList.push((err, response) => { - if (err) { - reject(this._handlerError(err, basicMeta)) - } - debug('unaryMethod get response', response) - result.response = response - }) - - const call = func.apply(client, argumentsList) - - call.on('metadata', metadata => { - debug('unaryMethod get metadata', metadata) - result.metadata = metadata - }) - call.on('status', status => { - debug('unaryMethod get status', status) - result.status = status - resolve(result) - }) - }) - } - return asyncUnaryMethod - } - - _promisifyClientStreamMethod (client, func, defaultOptions, basicMeta) { - const clientStreamMethod = (metadata, options) => { - if (typeof options === 'function') { - throw new Error('gRPCity: asyncStreamFunction should not contain callback function') - } else if (typeof metadata === 'function') { - throw new Error('gRPCity: asyncStreamFunction should not contain callback function') - } - - [metadata, options] = this._prepareMetadata(metadata, options, basicMeta) - options = this._setDeadline(options, defaultOptions, basicMeta) - - const result = {} - - const argumentsList = [metadata, options] - argumentsList.push((err, response) => { - if (err) { - throw this._handlerError(err, basicMeta) - } - debug('clientStreamMethod get response', response) - result.response = response - }) - - const call = func.apply(client, argumentsList) - - // write() already exists in call - // call.write = call.write - - call.writeAll = (messages) => { - if (Array.isArray(messages)) { - messages.forEach(message => { - call.write(message) - }) - } - } - call.writeEnd = async () => { - call.end() - await new Promise((resolve, reject) => { - call.on('metadata', metadata => { - debug('clientStreamMethod get metadata', metadata) - result.metadata = metadata - }) - call.on('status', status => { - debug('clientStreamMethod get status', status) - result.status = status - resolve() - }) - }) - return result - } - - return call - } - - return clientStreamMethod - } - - _promisifyServerStreamMethod (client, func, defaultOptions, basicMeta) { - const serverStreamMethod = (request, metadata, options) => { - if (typeof options === 'function') { - throw new Error('gRPCity: asyncStreamFunction should not contain callback function') - } else if (typeof metadata === 'function') { - throw new Error('gRPCity: asyncStreamFunction should not contain callback function') - } - - [metadata, options] = this._prepareMetadata(metadata, options, basicMeta) - options = this._setDeadline(options, defaultOptions, basicMeta) - - const call = func.apply(client, [request, metadata, options]) - - call.on('error', err => { - throw this._handlerError(err, basicMeta) - }) - - const result = {} - call.readAll = () => { - call.on('metadata', metadata => { - debug('serverStreamMethod get metadata', metadata) - result.metadata = metadata - }) - call.on('status', status => { - debug('serverStreamMethod get status', status) - result.status = status - }) - return iterator(call, 'data', { - resolutionEvents: ['status', 'end'] - }) - } - call.readEnd = () => { - return result - } - - return call - } - - return serverStreamMethod - } - - _promisifyDuplexStreamMethod (client, func, defaultOptions, basicMeta) { - const duplexStreamMethod = (metadata, options) => { - if (typeof options === 'function') { - throw new Error('gRPCity: asyncStreamFunction should not contain callback function') - } else if (typeof metadata === 'function') { - throw new Error('gRPCity: asyncStreamFunction should not contain callback function') - } - - [metadata, options] = this._prepareMetadata(metadata, options, basicMeta) - options = this._setDeadline(options, defaultOptions, basicMeta) - - const call = func.apply(client, [metadata, options]) - - // write() already exists in call - // call.write = call.write - - call.writeAll = (messages) => { - if (Array.isArray(messages)) { - messages.forEach(message => { - call.write(message) - }) - } - } - call.writeEnd = call.end - - call.on('error', err => { - throw this._handlerError(err, basicMeta) - }) - - // readAll() needs to execute writeAll() or write() first before it can be executed - const result = {} - call.readAll = () => { - call.on('metadata', metadata => { - debug('serverStreamMethod get metadata', metadata) - result.metadata = metadata - }) - call.on('status', status => { - debug('serverStreamMethod get status', status) - result.status = status - }) - return iterator(call, 'data', { - resolutionEvents: ['status', 'end'] - }) - } - call.readEnd = () => { - return result - } - - return call - } - - return duplexStreamMethod - } - - _keepCallbackMethod (client, func) { - const callbackMethod = (...argumentsList) => { - return func.apply(client, argumentsList) - } - return callbackMethod - } - - _prepareMetadata (metadata, options, basicMeta) { - if (metadata instanceof Metadata) { - options = Object.assign({}, options) - } else { - options = Object.assign({}, metadata) - metadata = new Metadata() - } - - metadata.add('x-client-hostname', basicMeta.hostname) - - if (basicMeta.appName) { - metadata.add('x-client-app-name', basicMeta.appName) - } - - return [metadata, options] - } - - _handlerError (err, basicMeta) { - const newError = new Error() - newError.name = 'GrpcClientError' - newError.code = err.code - newError.message = `${basicMeta.fullServiceName} (${err.message})` - - const stacks = newError.stack.split('\n') - newError.stack = [ - stacks[0], - ...stacks.slice(2), - ' ...', - ...err.stack.split('\n').slice(1, 3) - ].join('\n') - - return newError - } - - _setDeadline (options, defaultOptions, basicMeta) { - if (!options.deadline) { - const timeout = options.timeout || defaultOptions.timeout - const deadline = new Date(Date.now() + timeout) - options.deadline = deadline - delete options.timeout - debug('grpc client request will timeout at', { fullServiceName: basicMeta.fullServiceName, deadline }) - } - return options - } -} - -module.exports = new ClientProxy() diff --git a/lib/proxy/serverProxy.js b/lib/proxy/serverProxy.js deleted file mode 100644 index 35f0dc0..0000000 --- a/lib/proxy/serverProxy.js +++ /dev/null @@ -1,295 +0,0 @@ -const grpc = require('@grpc/grpc-js') -const assert = require('assert') -const util = require('util') -const _ = require('lodash') -const Joi = require('joi') -const serverSchemas = require('../schema/server') -const iterator = require('../util/iterator') -const compose = require('../util/compose') -const debug = require('debug')('grpcity:serverProxy') - -class ServerProxy { - constructor () { - this._middleware = [] - } - - _init (loader, ...args) { - if (!this._loader) { - this._loader = loader - } - if (!this._server) { - this._server = new grpc.Server(...args) - } - return this - } - - async listen (addr, credentials = undefined) { - assert(this._server, 'must be first init() server before server listen()') - Joi.assert(addr, serverSchemas.address, 'server listen() params Error') - debug('server listen options', addr) - - const url = _.isString(addr) ? addr : `${addr.host}:${addr.port}` - const bindPort = await new Promise((resolve, reject) => { - this._server.bindAsync(url, credentials || this.makeServerCredentials(), (err, result) => ( - err ? reject(err) : resolve(result)) - ) - }) - const port = addr.port ? addr.port : Number(addr.match(/:(\d+)/)[1]) - assert(bindPort === port, 'server bind port not to be right') - - this._server.start() - } - - async shutdown () { - if (!this._server) { - return - } - - await new Promise((resolve, reject) => { - this._server.tryShutdown(err => { - if (err) { - reject(err) - } else { - resolve() - } - }) - }) - - delete this._server - delete this._loader - } - - forceShutdown () { - if (!this._server) { - return - } - - this._server.forceShutdown() - delete this._server - delete this._loader - } - - makeServerCredentials (rootCerts, keyCertPairs, checkClientCertificate) { - if (rootCerts) { - return grpc.ServerCredentials.createSsl(rootCerts, keyCertPairs, checkClientCertificate) - } else { - if (!this._insecureServerCredentials) { - this._insecureServerCredentials = grpc.ServerCredentials.createInsecure() - } - return this._insecureServerCredentials - } - } - - addService (name, implementation, { exclude = [], inherit } = {}) { - const service = this._loader.service(name) - - const options = { exclude, inherit, _implementationType: {} } - Object.keys(service).forEach(key => { - const { requestStream, responseStream } = service[key] - options._implementationType[service[key].originalName] = { requestStream, responseStream } - }) - - this._server.addService(service, this._callbackify(implementation, options)) - } - - removeService (name) { - assert(this._server, 'must be first init() server before server removeService()') - this._server.removeService(this._loader.service(name)) - } - - addMiddleware (...args) { - assert(args.length >= 1, 'server addMiddleware() takes at least one argument.') - if (args.length === 1) { - if (Array.isArray(args[0])) { - args[0].forEach(fn => { - this._use(fn) - }) - } else { - this._use(args[0]) - } - } else { - args.forEach(fn => { - this._use(fn) - }) - } - } - - _use (fn) { - if (typeof fn !== 'function') throw new TypeError('grpcity loader server middleware must be a function!') - this._middleware.push(fn) - } - - // async func --- to --> callback type func - // use in grpc server side mostly - _callbackify (target, { exclude = [], inherit, _implementationType } = {}) { - assert(typeof target === 'object', 'Must callbackify an object') - assert(Array.isArray(exclude), 'options.exclude must be an array of strings') - - const protoPropertyNames = Object.getOwnPropertyNames(Object.getPrototypeOf({})) - exclude.push(...protoPropertyNames) - - const allPropertyNames = [ - ...new Set([ - ...Object.keys(target), - ...Object.getOwnPropertyNames(Object.getPrototypeOf(target)), - ...(inherit && inherit.prototype ? Object.getOwnPropertyNames(inherit.prototype) : []) - ]) - ] - - const methods = {} - for (const key of allPropertyNames) { - const fn = target[key] - if (typeof fn === 'function' && key !== 'constructor' && !exclude.includes(key)) { - if (util.types.isAsyncFunction(fn)) { - const eglWrapFunction = this._proxy(target, key, _implementationType[key]) - debug(`callbackify async function: ${key}`) - methods[key] = eglWrapFunction - } else { - debug(`copy non-async function: ${key}`) - methods[key] = fn - } - } - } - - debug('callbackify()', methods) - return methods - } - - _proxy (target, key, options = {}) { - const { requestStream, responseStream } = options - - const fn = compose(this._middleware) - - // unary - if (!requestStream && !responseStream) { - return this._callUnaryProxyMethod(target, key, fn) - } - // client stream - if (requestStream && !responseStream) { - return this._callClientStreamProxyMethod(target, key, fn) - } - // server stream - if (!requestStream && responseStream) { - return this._callServerStreamProxyMethod(target, key, fn) - } - // duplex stream - if (requestStream && responseStream) { - return this._callDuplexStreamProxyMethod(target, key, fn) - } - } - - _createContext (call) { - return { - // TODO: maybe need more details - // method: target.constructor.name + '.' + key, - path: call.call.handler.path || '', - request: call.request, - metadata: call.metadata.clone() - } - } - - _callUnaryProxyMethod (target, key, composeFunc) { - return (call, callback) => { - const ctx = this._createContext(call) - - Promise.resolve().then(async () => { - const handleResponse = async () => { - ctx.response = await target[key](call) - } - await composeFunc(ctx, handleResponse).catch(err => { - callback(this._createInternalErrorStatus(err)) - }) - callback(null, ctx.response) - }) - } - } - - _callClientStreamProxyMethod (target, key, composeFunc) { - return (call, callback) => { - const ctx = this._createContext(call) - - call.readAll = () => { - return iterator(call, 'data', { - resolutionEvents: ['end'] - }) - } - - Promise.resolve().then(async () => { - const handleResponse = async () => { - ctx.response = await target[key](call) - } - await composeFunc(ctx, handleResponse).catch(err => { - callback(this._createInternalErrorStatus(err)) - }) - callback(null, ctx.response) - }) - } - } - - _callServerStreamProxyMethod (target, key, composeFunc) { - return (call) => { - const ctx = this._createContext(call) - - call.writeAll = (messages) => { - if (Array.isArray(messages)) { - messages.forEach(message => { - call.write(message) - }) - } - } - call.writeEnd = call.end - - Promise.resolve().then(async () => { - const handleResponse = async () => { - await target[key](call) - } - await composeFunc(ctx, handleResponse).catch(err => { - call.destroy(this._createInternalErrorStatus(err)) - }) - call.end() - }) - } - } - - _callDuplexStreamProxyMethod (target, key, composeFunc) { - return (call) => { - const ctx = this._createContext(call) - - call.writeAll = (messages) => { - if (Array.isArray(messages)) { - messages.forEach(message => { - call.write(message) - }) - } - } - call.readAll = () => { - return iterator(call, 'data', { - resolutionEvents: ['end'] - }) - } - - Promise.resolve().then(async () => { - const handleResponse = async () => { - await target[key](call) - } - await composeFunc(ctx, handleResponse).catch(err => { - call.destroy(this._createInternalErrorStatus(err)) - }) - call.end() - }) - } - } - - _createInternalErrorStatus (err) { - err.code = err.code || 13 - if (typeof err.stack === 'string') { - const stack = err.stack.split('\n') - err.messages += ` [Error Message From Server, stack: ${stack[1].trim()}]` - } else { - err.messages += ' [Error Message From Server]' - } - return err - } -} - -module.exports = new ServerProxy() diff --git a/lib/schema/loader.js b/lib/schema/loader.js deleted file mode 100644 index eb059f0..0000000 --- a/lib/schema/loader.js +++ /dev/null @@ -1,31 +0,0 @@ -const Joi = require('joi') - -const addressSchema = Joi.object() - .pattern(/\.*/, Joi.alternatives([ - Joi.string().regex(/:/, 'host and port like 127.0.0.1:9090'), - Joi.object().keys({ - host: Joi.string().required(), - port: Joi.number().integer().min(0).max(65535).required() - }) - ])) - -const loaderSchemas = { - constructor: Joi.array().items(Joi.object().keys({ - location: Joi.string().required(), - files: Joi.array().items(Joi.string()).required() - })).single(), - init: Joi.object().keys({ - services: addressSchema.optional(), - isDev: Joi.boolean().optional(), - packagePrefix: Joi.string().optional(), - loadOptions: Joi.object().optional(), - channelOptions: Joi.object().optional(), - appName: Joi.string().optional() - }), - initClients: Joi.object().keys({ - services: addressSchema.required(), - channelOptions: Joi.object().optional() - }) -} - -module.exports = loaderSchemas diff --git a/lib/schema/server.js b/lib/schema/server.js deleted file mode 100644 index f53a9bb..0000000 --- a/lib/schema/server.js +++ /dev/null @@ -1,13 +0,0 @@ -const Joi = require('joi') - -const serverSchemas = { - address: Joi.alternatives([ - Joi.string().regex(/:/, 'host and port like 127.0.0.1:9090'), - Joi.object().keys({ - host: Joi.string().required(), - port: Joi.number().integer().min(0).max(65535).required() - }) - ]) -} - -module.exports = serverSchemas diff --git a/lib/util/compose.js b/lib/util/compose.js deleted file mode 100644 index 47d3ce2..0000000 --- a/lib/util/compose.js +++ /dev/null @@ -1,33 +0,0 @@ -/** - * Compose `middleware` returning - * a fully valid middleware comprised - * of all those which are passed. - * - * @param {Array} middleware - * @return {Function} - * @api public - */ -module.exports = (middleware) => { - if (!Array.isArray(middleware)) throw new TypeError('Middleware stack must be an array!') - for (const fn of middleware) { - if (typeof fn !== 'function') throw new TypeError('Middleware must be composed of functions!') - } - - return function (context, next) { - // last called middleware # - let index = -1 - return dispatch(0) - function dispatch (i) { - if (i <= index) return Promise.reject(new Error('next() called multiple times')) - index = i - let fn = middleware[i] - if (i === middleware.length) fn = next - if (!fn) return Promise.resolve() - try { - return Promise.resolve(fn(context, dispatch.bind(null, i + 1))) - } catch (err) { - return Promise.reject(err) - } - } - } -} diff --git a/lib/util/iterator.js b/lib/util/iterator.js deleted file mode 100644 index 20f97dd..0000000 --- a/lib/util/iterator.js +++ /dev/null @@ -1,188 +0,0 @@ -const symbolAsyncIterator = Symbol.asyncIterator || '@@asyncIterator' - -const normalizeEmitter = emitter => { - const addListener = emitter.on || emitter.addListener || emitter.addEventListener - const removeListener = emitter.off || emitter.removeListener || emitter.removeEventListener - - if (!addListener || !removeListener) { - throw new TypeError('Emitter is not compatible') - } - - return { - addListener: addListener.bind(emitter), - removeListener: removeListener.bind(emitter) - } -} - -const toArray = value => Array.isArray(value) ? value : [value] - -module.exports = (emitter, event, options) => { - if (typeof options === 'function') { - options = { filter: options } - } - - // Allow multiple events - const events = toArray(event) - - options = { - rejectionEvents: ['error'], - resolutionEvents: [], - limit: Infinity, - multiArgs: false, - ...options - } - - const { limit } = options - const isValidLimit = limit >= 0 && (limit === Infinity || Number.isInteger(limit)) - if (!isValidLimit) { - throw new TypeError('The `limit` option should be a non-negative integer or Infinity') - } - - if (limit === 0) { - // Return an empty async iterator to avoid any further cost - return { - [Symbol.asyncIterator] () { - return this - }, - async next () { - return { - done: true, - value: undefined - } - } - } - } - - const { addListener, removeListener } = normalizeEmitter(emitter) - - let isDone = false - let error - let hasPendingError = false - const nextQueue = [] - const valueQueue = [] - let eventCount = 0 - let isLimitReached = false - - const valueHandler = (...args) => { - eventCount++ - isLimitReached = eventCount === limit - - const value = options.multiArgs ? args : args[0] - - if (nextQueue.length > 0) { - const { resolve } = nextQueue.shift() - - resolve({ done: false, value }) - - if (isLimitReached) { - cancel() - } - - return - } - - valueQueue.push(value) - - if (isLimitReached) { - cancel() - } - } - - const cancel = () => { - isDone = true - for (const event of events) { - removeListener(event, valueHandler) - } - - for (const rejectionEvent of options.rejectionEvents) { - removeListener(rejectionEvent, rejectHandler) - } - - for (const resolutionEvent of options.resolutionEvents) { - removeListener(resolutionEvent, resolveHandler) - } - - while (nextQueue.length > 0) { - const { resolve } = nextQueue.shift() - resolve({ done: true, value: undefined }) - } - } - - const rejectHandler = (...args) => { - error = options.multiArgs ? args : args[0] - - if (nextQueue.length > 0) { - const { reject } = nextQueue.shift() - reject(error) - } else { - hasPendingError = true - } - - cancel() - } - - const resolveHandler = (...args) => { - const value = options.multiArgs ? args : args[0] - - if (options.filter && !options.filter(value)) { - return - } - - if (nextQueue.length > 0) { - const { resolve } = nextQueue.shift() - resolve({ done: true, value }) - } else { - valueQueue.push(value) - } - - cancel() - } - - for (const event of events) { - addListener(event, valueHandler) - } - - for (const rejectionEvent of options.rejectionEvents) { - addListener(rejectionEvent, rejectHandler) - } - - for (const resolutionEvent of options.resolutionEvents) { - addListener(resolutionEvent, resolveHandler) - } - - return { - [symbolAsyncIterator] () { - return this - }, - async next () { - if (valueQueue.length > 0) { - const value = valueQueue.shift() - return { - done: isDone && valueQueue.length === 0 && !isLimitReached, - value - } - } - - if (hasPendingError) { - hasPendingError = false - throw error - } - - if (isDone) { - return { - done: true, - value: undefined - } - } - - return new Promise((resolve, reject) => nextQueue.push({ resolve, reject })) - }, - async return (value) { - cancel() - return { - done: isDone, - value - } - } - } -} diff --git a/lib/util/prefixingDefinition.js b/lib/util/prefixingDefinition.js deleted file mode 100644 index 8729a7e..0000000 --- a/lib/util/prefixingDefinition.js +++ /dev/null @@ -1,18 +0,0 @@ -module.exports = (packageDefinition, packagePrefix) => { - for (const qualifiedName in packageDefinition) { - const definition = packageDefinition[qualifiedName] - const newPackage = `${packagePrefix}.${qualifiedName}` - if (definition.format && definition.type && definition.fileDescriptorProtos) { - packageDefinition[newPackage] = definition - } else { - const newDefinition = {} - for (const method in definition) { - const service = definition[method] - newDefinition[method] = Object.assign({}, service, { path: service.path.replace(/^\//, `/${packagePrefix}.`) }) - } - packageDefinition[newPackage] = newDefinition - } - } - - return packageDefinition -} From 5ea3e8564f4345cffc906879c5bb75666c389bf2 Mon Sep 17 00:00:00 2001 From: "Chakhsu.Lau" Date: Sun, 3 Dec 2023 17:26:15 +0800 Subject: [PATCH 03/12] feat: regen types --- types/config/defaultChannelOptions.d.ts | 13 +- types/config/defaultChannelOptions.js | 43 ++-- types/config/defaultLoadOptions.d.ts | 7 +- types/config/defaultLoadOptions.js | 6 +- types/index.d.ts | 113 +++-------- types/index.js | 122 +++++++----- types/proxy/clientProxy.d.ts | 30 ++- types/proxy/clientProxy.js | 252 ++++++++++++------------ types/proxy/serverProxy.d.ts | 56 +++--- types/proxy/serverProxy.js | 83 +++++--- types/schema/loader.d.ts | 11 +- types/schema/loader.js | 41 ++-- types/schema/server.d.ts | 7 +- types/schema/server.js | 17 +- types/util/compose.d.ts | 13 +- types/util/compose.js | 12 +- types/util/iterator.d.ts | 28 +-- types/util/iterator.js | 32 +-- types/util/prefixingDefinition.d.ts | 4 +- types/util/prefixingDefinition.js | 10 +- 20 files changed, 433 insertions(+), 467 deletions(-) diff --git a/types/config/defaultChannelOptions.d.ts b/types/config/defaultChannelOptions.d.ts index 2be5f54..53d4c20 100644 --- a/types/config/defaultChannelOptions.d.ts +++ b/types/config/defaultChannelOptions.d.ts @@ -1,11 +1,2 @@ -declare const _exports: { - 'grpc.min_reconnect_backoff_ms': number; - 'grpc.max_reconnect_backoff_ms': number; - 'grpc.grpclb_call_timeout_ms': number; - 'grpc.keepalive_timeout_ms': number; - 'grpc.keepalive_time_ms': number; - 'grpc.keepalive_permit_without_calls': number; - 'grpc.enable_retries': number; - 'grpc.service_config': string; -}; -export = _exports; +import { ChannelOptions } from "@grpc/grpc-js"; +export declare const defaultChannelOptions: ChannelOptions; diff --git a/types/config/defaultChannelOptions.js b/types/config/defaultChannelOptions.js index c1e4e07..3b76e03 100644 --- a/types/config/defaultChannelOptions.js +++ b/types/config/defaultChannelOptions.js @@ -1,34 +1,21 @@ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -// gRPC options, doc: https://grpc.github.io/grpc/core/group__grpc__arg__keys.html -module.exports = { - // grpc library options accept only numeric and string types - // Configure grpc reconnect time (1s to 10s random number) - 'grpc.min_reconnect_backoff_ms': 1000, - 'grpc.max_reconnect_backoff_ms': 10000, - // Communication timeout - 'grpc.grpclb_call_timeout_ms': 5000, - // The following 3 parameters address the issue of long-idle gRPC clients not promptly detecting TCP connection breaks - // After waiting for a duration of this time, if the keepalive ping sender does not receive the ping ack, it will close the transport. - 'grpc.keepalive_timeout_ms': (20 * 1000), - // duration of this time the client/server pings its peer to see if the transport is still alive - 'grpc.keepalive_time_ms': (120 * 1000), - 'grpc.keepalive_permit_without_calls': 1, - // Communication failure allows grpc library retry - 'grpc.enable_retries': 1, - // Configure retry parameters - // Reference: https://github.com/grpc/proposal/blob/master/A6-client-retries.md#integration-with-service-config - 'grpc.service_config': JSON.stringify({ +exports.defaultChannelOptions = void 0; +exports.defaultChannelOptions = { + "grpc.min_reconnect_backoff_ms": 1000, + "grpc.max_reconnect_backoff_ms": 10000, + "grpc.grpclb_call_timeout_ms": 5000, + "grpc.keepalive_timeout_ms": 20 * 1000, + "grpc.keepalive_time_ms": 120 * 1000, + "grpc.keepalive_permit_without_calls": 1, + "grpc.enable_retries": 1, + "grpc.service_config": JSON.stringify({ retryPolicy: { - // 1 normal send + 3 failed retries, each retry has the opportunity to be sent on a different subchannel than the original failure maxAttempts: 4, - // Initial retry time interval: random(0, initialBackoff) seconds - // The nth retry time; random(0, min(initialBackoff*backoffMultiplier^(n-1), maxBackoff)) seconds - initialBackoff: '0.1s', - maxBackoff: '1s', + initialBackoff: "0.1s", + maxBackoff: "1s", backoffMultiplier: 2, - // Retry only in the case of network unavailability - retryableStatusCodes: ['UNAVAILABLE'] - } - }) + retryableStatusCodes: ["UNAVAILABLE"], + }, + }), }; diff --git a/types/config/defaultLoadOptions.d.ts b/types/config/defaultLoadOptions.d.ts index c1dcc09..9d1f2e1 100644 --- a/types/config/defaultLoadOptions.d.ts +++ b/types/config/defaultLoadOptions.d.ts @@ -1,5 +1,2 @@ -export let keepCase: boolean; -export let longs: StringConstructor; -export let enums: StringConstructor; -export let defaults: boolean; -export let oneofs: boolean; +import { Options } from '@grpc/proto-loader'; +export declare const defaultLoadOptions: Options; diff --git a/types/config/defaultLoadOptions.js b/types/config/defaultLoadOptions.js index 27502ec..af6fc55 100644 --- a/types/config/defaultLoadOptions.js +++ b/types/config/defaultLoadOptions.js @@ -1,10 +1,10 @@ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -// GRPC protos loader options, doc: https://www.npmjs.com/package/@grpc/proto-loader -module.exports = { +exports.defaultLoadOptions = void 0; +exports.defaultLoadOptions = { keepCase: true, longs: String, enums: String, defaults: false, - oneofs: true + oneofs: true, }; diff --git a/types/index.d.ts b/types/index.d.ts index 60fd186..7256de4 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -1,92 +1,31 @@ -export = GrpcLoader; +import * as grpc from '@grpc/grpc-js'; +import ServerProxy from './proxy/serverProxy'; declare class GrpcLoader { + private _protoFiles; + private _clientMap; + private _clientAddrMap; + private _types; + private _packagePrefix?; + private _appName?; + private _packageDefinition; + private _isDev?; + private _reflectedRoot; + private _insecureCredentials?; + private _initDefaultClient?; constructor(protoFileOptions: any); - _protoFiles: any[]; - _clientMap: Map; - _clientAddrMap: Map; - init({ services, isDev, packagePrefix, loadOptions, channelOptions, appName }?: { - services?: undefined; - isDev?: boolean | undefined; - packagePrefix?: string | undefined; - loadOptions?: {} | undefined; - channelOptions?: {} | undefined; - appName: any; - }): Promise; - _isDev: boolean | undefined; - _packagePrefix: string | undefined; - _appName: any; - _packageDefinition: any; - _types: grpc.GrpcObject | undefined; - initClients({ services, channelOptions, credentials }: { - services: any; - channelOptions?: {} | undefined; - credentials?: undefined; - }): Promise; - _initDefaultClient: boolean | undefined; + init({ services, isDev, packagePrefix, loadOptions, channelOptions, appName }?: any): Promise; + initClients({ services, channelOptions, credentials }: any): Promise; closeClients(): void; - makeCredentials(rootCerts: any, privateKey: any, certChain: any, verifyOptions: any): grpc.ChannelCredentials; - _insecureCredentials: grpc.ChannelCredentials | undefined; - service(name: any): any; - type(name: any): any; - message(name: any): any; - _reflectedRoot: any; - client(name: any, { host, port, timeout, credentials, channelOptions }?: { - host?: undefined; - port?: undefined; - timeout?: undefined; - credentials?: undefined; - channelOptions?: {} | undefined; - }): any; - realClient(name: any, { host, port, credentials, channelOptions }?: { - host?: undefined; - port?: undefined; - credentials?: undefined; - channelOptions?: {} | undefined; - }): any; - clientWithoutCache(name: any, { addr, timeout, credentials, channelOptions }?: { - addr: any; - timeout?: undefined; - credentials?: undefined; - channelOptions?: {} | undefined; - }): { - call: {}; - }; - _makeClient(isDefaultClient: any, name: any, addr: any, credentials: any, channelOptions?: {}): any; - _makeClientWithoutCache(isDefaultClient: any, name: any, addr: any, credentials: any, channelOptions?: {}): any; + makeCredentials(rootCerts?: any, privateKey?: any, certChain?: any, verifyOptions?: any): grpc.ChannelCredentials; + service(name: string): any; + type(name: string): any; + message(name: string): any; + client(name: string, { host, port, timeout, credentials, channelOptions }?: any): any; + realClient(name: string, { host, port, credentials, channelOptions }?: any): any; + clientWithoutCache(name: string, { addr, timeout, credentials, channelOptions }?: any): any; + private _makeClient; + private _makeClientWithoutCache; makeMetadata(initialValues: any): grpc.Metadata; - initServer(...args: any[]): { - _middleware: any[]; - _init(loader: any, ...args: any[]): any; - _loader: any; - _server: grpc.Server | undefined; - listen(addr: any, credentials?: undefined): Promise; - shutdown(): Promise; - forceShutdown(): void; - makeServerCredentials(rootCerts: any, keyCertPairs: any, checkClientCertificate: any): grpc.ServerCredentials; - _insecureServerCredentials: grpc.ServerCredentials | undefined; - addService(name: any, implementation: any, { exclude, inherit }?: { - exclude?: any[] | undefined; - inherit: any; - }): void; - removeService(name: any): void; - addMiddleware(...args: any[]): void; - _use(fn: any): void; - _callbackify(target: any, { exclude, inherit, _implementationType }?: { - exclude?: any[] | undefined; - inherit: any; - _implementationType: any; - }): {}; - _proxy(target: any, key: any, options?: {}): ((call: any, callback: any) => void) | undefined; - _createContext(call: any): { - path: any; - request: any; - metadata: any; - }; - _callUnaryProxyMethod(target: any, key: any, composeFunc: any): (call: any, callback: any) => void; - _callClientStreamProxyMethod(target: any, key: any, composeFunc: any): (call: any, callback: any) => void; - _callServerStreamProxyMethod(target: any, key: any, composeFunc: any): (call: any) => void; - _callDuplexStreamProxyMethod(target: any, key: any, composeFunc: any): (call: any) => void; - _createInternalErrorStatus(err: any): any; - }; + initServer(...args: any[]): ServerProxy; } -import grpc = require("@grpc/grpc-js"); +export default GrpcLoader; diff --git a/types/index.js b/types/index.js index 9cb2a3d..e8e20c4 100644 --- a/types/index.js +++ b/types/index.js @@ -1,38 +1,62 @@ "use strict"; +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { + desc = { enumerable: true, get: function() { return m[k]; } }; + } + Object.defineProperty(o, k2, desc); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { + Object.defineProperty(o, "default", { enumerable: true, value: v }); +}) : function(o, v) { + o["default"] = v; +}); +var __importStar = (this && this.__importStar) || function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); + __setModuleDefault(result, mod); + return result; +}; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; Object.defineProperty(exports, "__esModule", { value: true }); -const assert = require('assert'); -const grpc = require('@grpc/grpc-js'); -const protoLoader = require('@grpc/proto-loader'); -const protobuf = require('protobufjs'); -const Descriptor = require('protobufjs/ext/descriptor'); -const Joi = require('joi'); -const _ = require('lodash'); -const loaderSchemas = require('./schema/loader'); -const prefixingDefinition = require('./util/prefixingDefinition'); -const defaultChannelOptions = require('./config/defaultChannelOptions'); -const defaultLoadOptions = require('./config/defaultLoadOptions'); -const clientProxy = require('./proxy/clientProxy'); -const serverProxy = require('./proxy/serverProxy'); -const debug = require('debug')('grpcity'); -module.exports = class GrpcLoader { +const node_assert_1 = __importDefault(require("node:assert")); +const grpc = __importStar(require("@grpc/grpc-js")); +const protoLoader = __importStar(require("@grpc/proto-loader")); +const protobuf = __importStar(require("protobufjs")); +const Descriptor = __importStar(require("protobufjs/ext/descriptor")); +const _ = __importStar(require("lodash")); +const Joi = __importStar(require("joi")); +const loader_1 = __importDefault(require("./schema/loader")); +const prefixingDefinition_1 = __importDefault(require("./util/prefixingDefinition")); +const defaultChannelOptions_1 = require("./config/defaultChannelOptions"); +const defaultLoadOptions_1 = require("./config/defaultLoadOptions"); +const clientProxy_1 = __importDefault(require("./proxy/clientProxy")); +const serverProxy_1 = __importDefault(require("./proxy/serverProxy")); +class GrpcLoader { constructor(protoFileOptions) { - Joi.assert(protoFileOptions, loaderSchemas.constructor, 'new GrpcLoader() params Error'); + Joi.assert(protoFileOptions, loader_1.default.constructor, 'new GrpcLoader() params Error'); this._protoFiles = Array.isArray(protoFileOptions) ? protoFileOptions : [protoFileOptions]; this._clientMap = new Map(); this._clientAddrMap = new Map(); } async init({ services = undefined, isDev = false, packagePrefix = '', loadOptions = {}, channelOptions = {}, appName } = {}) { - Joi.assert({ services, loadOptions, isDev, channelOptions, appName }, loaderSchemas.init, 'GrpcLoader.init() params Error'); - debug('init()', { services, loadOptions, isDev, channelOptions, appName }); + Joi.assert({ services, loadOptions, isDev, channelOptions, appName }, loader_1.default.init, 'GrpcLoader.init() params Error'); if (this._types) { return; } try { - loadOptions = Object.assign({}, defaultLoadOptions, loadOptions); + loadOptions = Object.assign({}, defaultLoadOptions_1.defaultLoadOptions, loadOptions); this._isDev = isDev; this._packagePrefix = packagePrefix; this._appName = appName; - loadOptions.includeDirs = this._protoFiles.map(p => p.location).concat(loadOptions.includeDirs || []); + loadOptions.includeDirs = this._protoFiles.map((p) => p.location).concat(loadOptions.includeDirs || []); const files = this._protoFiles.reduce((result, p) => { if (p.files && p.files.length > 0) { result.push(...p.files); @@ -41,7 +65,7 @@ module.exports = class GrpcLoader { }, []); const packageDefinition = await protoLoader.load(files, loadOptions); if (this._packagePrefix) { - this._packageDefinition = prefixingDefinition(packageDefinition, packagePrefix); + this._packageDefinition = (0, prefixingDefinition_1.default)(packageDefinition, packagePrefix); } else { this._packageDefinition = packageDefinition; @@ -49,7 +73,6 @@ module.exports = class GrpcLoader { this._types = grpc.loadPackageDefinition(this._packageDefinition); } catch (err) { - debug(err.message, { err }, this._protoFiles); throw err; } if (services) { @@ -57,8 +80,7 @@ module.exports = class GrpcLoader { } } async initClients({ services, channelOptions = {}, credentials = undefined }) { - Joi.assert({ services, channelOptions }, loaderSchemas.initClients, 'GrpcLoader.initClients() Options Error'); - debug('initClients()', { services }); + Joi.assert({ services, channelOptions }, loader_1.default.initClients, 'GrpcLoader.initClients() Options Error'); if (this._initDefaultClient) { return; } @@ -66,7 +88,7 @@ module.exports = class GrpcLoader { await this.init(); } const serviceNames = Object.keys(services); - serviceNames.forEach(name => { + serviceNames.forEach((name) => { const isDefaultClient = true; const addr = _.isString(services[name]) ? services[name] : services[name].host + ':' + services[name].port; this._makeClient(isDefaultClient, name, addr, credentials, channelOptions); @@ -84,7 +106,7 @@ module.exports = class GrpcLoader { this._initDefaultClient = false; } makeCredentials(rootCerts, privateKey, certChain, verifyOptions) { - if (rootCerts) { + if (rootCerts && privateKey && certChain) { return grpc.credentials.createSsl(rootCerts, privateKey, certChain, verifyOptions); } else { @@ -95,19 +117,17 @@ module.exports = class GrpcLoader { } } service(name) { - assert(this._types, 'Must called init() first. proto file has not been loaded.'); + (0, node_assert_1.default)(this._types, 'Must called init() first. proto file has not been loaded.'); const fullName = this._isDev ? `${this._packagePrefix}.${name}` : name; - debug('get service:', fullName); const service = _.get(this._types, `${fullName}.service`); - assert(service, `Cannot find service with name: ${fullName}, please check if the protos file is configured incorrectly or if the corresponding proto file is missing.`); + (0, node_assert_1.default)(service, `Cannot find service with name: ${fullName}, please check if the protos file is configured incorrectly or if the corresponding proto file is missing.`); return service; } type(name) { - assert(this._types, 'Must called init() first. proto file has not been loaded.'); + (0, node_assert_1.default)(this._types, 'Must called init() first. proto file has not been loaded.'); const fullName = this._isDev ? `${this._packagePrefix}.${name}` : name; - debug('get type:', fullName); const type = _.get(this._types, `${fullName}`); - assert(type, `Cannot find type with name: ${fullName}, please check if the protos file is configured incorrectly or if the corresponding proto file is missing.`); + (0, node_assert_1.default)(type, `Cannot find type with name: ${fullName}, please check if the protos file is configured incorrectly or if the corresponding proto file is missing.`); return type; } message(name) { @@ -118,14 +138,11 @@ module.exports = class GrpcLoader { return found; } } - debug('create reflected message root:', name); - root = protobuf.Root.fromDescriptor({ - file: this.type(name).fileDescriptorProtos.map(proto => Descriptor.FileDescriptorProto.decode(proto)) - }, root); + const descriptor = this.type(name).fileDescriptorProtos.map((proto) => Descriptor.FileDescriptorProto.decode(proto)); + root = protobuf.Root.fromDescriptor({ file: descriptor }); this._reflectedRoot = root; return root.lookupType(name); } - // async method client, cached by { name, host, port } client(name, { host = undefined, port = undefined, timeout = undefined, credentials = undefined, channelOptions = {} } = {}) { const isDefaultClient = !(host && port); const addr = `${host}:${port}`; @@ -137,23 +154,20 @@ module.exports = class GrpcLoader { else { const client = this._makeClient(isDefaultClient, name, addr, credentials, channelOptions); const appName = this._appName; - const proxy = clientProxy._proxy(client, { timeout }, appName); + const proxy = clientProxy_1.default._proxy(client, { timeout }, appName); this._clientMap.set(cacheKey, proxy); return proxy; } } - // callback method client, cached by { name, host, port } realClient(name, { host = undefined, port = undefined, credentials = undefined, channelOptions = {} } = {}) { const isDefaultClient = !(host && port); const client = this._makeClient(isDefaultClient, name, `${host}:${port}`, credentials, channelOptions); return client; } - // async method client, no cache. - // (used in conjunction with external service registration and discovery functionality) clientWithoutCache(name, { addr, timeout = undefined, credentials = undefined, channelOptions = {} } = {}) { const client = this._makeClientWithoutCache(false, name, addr, credentials, channelOptions); const appName = this._appName; - const proxy = clientProxy._proxy(client, { timeout }, appName); + const proxy = clientProxy_1.default._proxy(client, { timeout }, appName); return proxy; } _makeClient(isDefaultClient, name, addr, credentials, channelOptions = {}) { @@ -168,30 +182,29 @@ module.exports = class GrpcLoader { return this._clientMap.get(cacheKeyWithCt); } else { + let cacheAddr = addr; if (addr === 'undefined:undefined') { - addr = this._clientAddrMap.get(name); + cacheAddr = this._clientAddrMap.get(name) || addr; } - const client = this._makeClientWithoutCache(isDefaultClient, name, addr, credentials, channelOptions = {}); - this._clientAddrMap.set(name, addr); + const client = this._makeClientWithoutCache(isDefaultClient, name, cacheAddr, credentials, channelOptions); + this._clientAddrMap.set(name, cacheAddr); this._clientMap.set(cacheKey, client); return client; } } _makeClientWithoutCache(isDefaultClient, name, addr, credentials, channelOptions = {}) { - channelOptions = Object.assign({}, defaultChannelOptions, channelOptions); - debug('_makeClient()', { channelOptions }); + channelOptions = Object.assign({}, defaultChannelOptions_1.defaultChannelOptions, channelOptions); const ServiceProto = this.type(name); const client = new ServiceProto(addr, credentials || this.makeCredentials(), channelOptions); - debug(`create client: isDefaultClient=${isDefaultClient} serviceName=${name} addr=${addr}`); return client; } makeMetadata(initialValues) { - assert(this._types, 'Must called init() first. proto file has not been loaded.'); + (0, node_assert_1.default)(this._types, 'Must called init() first. proto file has not been loaded.'); const meta = new grpc.Metadata(); if (typeof initialValues === 'object') { Object.entries(initialValues).forEach(([key, value]) => { if (Array.isArray(value)) { - value.map(v => meta.add(key, _.isString(v) ? v : Buffer.from(v))); + value.map((v) => meta.add(key, _.isString(v) ? v : Buffer.from(v))); } else { meta.add(key, _.isString(value) ? value : Buffer.from(value)); @@ -201,7 +214,10 @@ module.exports = class GrpcLoader { return meta; } initServer(...args) { - assert(this._types, 'Must called init() first. proto file has not been loaded.'); - return serverProxy._init(this, ...args); + (0, node_assert_1.default)(this._types, 'Must called init() first. proto file has not been loaded.'); + const server = new serverProxy_1.default(); + return server._init(this, ...args); } -}; +} +exports.default = GrpcLoader; +module.exports = GrpcLoader; diff --git a/types/proxy/clientProxy.d.ts b/types/proxy/clientProxy.d.ts index 4555475..e6cac3d 100644 --- a/types/proxy/clientProxy.d.ts +++ b/types/proxy/clientProxy.d.ts @@ -1,19 +1,15 @@ -declare const _exports: ClientProxy; -export = _exports; +import { UntypedServiceImplementation } from '@grpc/grpc-js'; declare class ClientProxy { - _proxy(client: any, defaultOptions?: {}, appName?: undefined): { - call: {}; - }; - _getFuncStreamWay(func: any): { - requestStream: any; - responseStream: any; - }; - _promisifyUnaryMethod(client: any, func: any, defaultOptions: any, basicMeta: any): (request: any, metadata: any, options: any) => Promise; - _promisifyClientStreamMethod(client: any, func: any, defaultOptions: any, basicMeta: any): (metadata: any, options: any) => any; - _promisifyServerStreamMethod(client: any, func: any, defaultOptions: any, basicMeta: any): (request: any, metadata: any, options: any) => any; - _promisifyDuplexStreamMethod(client: any, func: any, defaultOptions: any, basicMeta: any): (metadata: any, options: any) => any; - _keepCallbackMethod(client: any, func: any): (...argumentsList: any[]) => any; - _prepareMetadata(metadata: any, options: any, basicMeta: any): any[]; - _handlerError(err: any, basicMeta: any): Error; - _setDeadline(options: any, defaultOptions: any, basicMeta: any): any; + private _getFuncStreamWay; + private _prepareMetadata; + private _handlerError; + private _setDeadline; + private _promisifyUnaryMethod; + private _promisifyClientStreamMethod; + private _promisifyServerStreamMethod; + private _promisifyDuplexStreamMethod; + private _keepCallbackMethod; + _proxy(client: UntypedServiceImplementation, defaultOptions?: Record, appName?: string): any; } +declare const _default: ClientProxy; +export default _default; diff --git a/types/proxy/clientProxy.js b/types/proxy/clientProxy.js index 56a8e04..2e9a0b9 100644 --- a/types/proxy/clientProxy.js +++ b/types/proxy/clientProxy.js @@ -1,61 +1,85 @@ "use strict"; +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { + desc = { enumerable: true, get: function() { return m[k]; } }; + } + Object.defineProperty(o, k2, desc); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { + Object.defineProperty(o, "default", { enumerable: true, value: v }); +}) : function(o, v) { + o["default"] = v; +}); +var __importStar = (this && this.__importStar) || function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); + __setModuleDefault(result, mod); + return result; +}; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; Object.defineProperty(exports, "__esModule", { value: true }); -const { Metadata } = require('@grpc/grpc-js'); -const os = require('os'); -const iterator = require('../util/iterator'); -const debug = require('debug')('grpcity:clientProxy'); +const grpc_js_1 = require("@grpc/grpc-js"); +const os = __importStar(require("node:os")); +const iterator_1 = __importDefault(require("../util/iterator")); class ClientProxy { - _proxy(client, defaultOptions = {}, appName = undefined) { - defaultOptions = defaultOptions || {}; - defaultOptions.timeout = defaultOptions.timeout || 1000 * 10; - const prototype = Object.getPrototypeOf(client); - const methodNames = Object.keys(prototype) - .filter(key => prototype[key] && prototype[key].path) - .reduce((names, key) => { - names[key.toUpperCase()] = prototype[key].path; - return names; - }, {}); - const basicMeta = { hostname: os.hostname(), appName }; - const target = Object.entries(prototype).filter(([name, func]) => { - return name !== 'constructor' && typeof func === 'function'; - }).reduce((target, [name, func]) => { - basicMeta.fullServiceName = `${methodNames[name.toUpperCase()]}`; - debug('proxy method', basicMeta); - const { requestStream, responseStream } = this._getFuncStreamWay(func); - if (!requestStream && !responseStream) { - // promisify unary method - target[name] = this._promisifyUnaryMethod(client, func, defaultOptions, basicMeta); - } - // stream - if (requestStream && !responseStream) { - // promisify only client stream method - target[name] = this._promisifyClientStreamMethod(client, func, defaultOptions, basicMeta); - } - if (!requestStream && responseStream) { - // promisify only server stream method - target[name] = this._promisifyServerStreamMethod(client, func, defaultOptions, basicMeta); - } - if (requestStream && responseStream) { - // promisify duplex stream method - target[name] = this._promisifyDuplexStreamMethod(client, func, defaultOptions, basicMeta); - } - // keep callback method - target.call[name] = this._keepCallbackMethod(client, func); - return target; - }, { call: {} }); - return target; - } _getFuncStreamWay(func) { const { requestStream, responseStream } = func; return { requestStream, responseStream }; } + _prepareMetadata(metadata, options, basicMeta) { + if (metadata instanceof grpc_js_1.Metadata) { + options = { ...options }; + } + else { + options = { ...metadata }; + metadata = new grpc_js_1.Metadata(); + } + if (basicMeta.hostname) { + metadata.add('x-client-hostname', basicMeta.hostname); + } + if (basicMeta.appName) { + metadata.add('x-client-app-name', basicMeta.appName); + } + return [metadata, options]; + } + _handlerError(err, basicMeta) { + const newError = new Error(); + newError.name = 'GrpcClientError'; + newError.code = err.code; + newError.message = `${basicMeta.fullServiceName} (${err.message})`; + const stacks = newError.stack.split('\n'); + newError.stack = [ + stacks[0], + ...stacks.slice(2), + ' ...', + ...err.stack.split('\n').slice(1, 3), + ].join('\n'); + return newError; + } + _setDeadline(options, defaultOptions, basicMeta) { + if (!options.deadline) { + const timeout = options.timeout || defaultOptions.timeout; + const deadline = new Date(Date.now() + timeout); + options.deadline = deadline; + delete options.timeout; + } + return options; + } _promisifyUnaryMethod(client, func, defaultOptions, basicMeta) { const asyncUnaryMethod = async (request, metadata, options) => { if (typeof options === 'function') { - throw new Error('gRPCity: AsyncFunction should not contain callback function'); + throw new Error('gRPCity: AsyncFunction should not contain a callback function'); } else if (typeof metadata === 'function') { - throw new Error('gRPCity: AsyncFunction should not contain callback function'); + throw new Error('gRPCity: AsyncFunction should not contain a callback function'); } [metadata, options] = this._prepareMetadata(metadata, options, basicMeta); options = this._setDeadline(options, defaultOptions, basicMeta); @@ -66,16 +90,13 @@ class ClientProxy { if (err) { reject(this._handlerError(err, basicMeta)); } - debug('unaryMethod get response', response); result.response = response; }); const call = func.apply(client, argumentsList); - call.on('metadata', metadata => { - debug('unaryMethod get metadata', metadata); + call.on('metadata', (metadata) => { result.metadata = metadata; }); - call.on('status', status => { - debug('unaryMethod get status', status); + call.on('status', (status) => { result.status = status; resolve(result); }); @@ -86,10 +107,10 @@ class ClientProxy { _promisifyClientStreamMethod(client, func, defaultOptions, basicMeta) { const clientStreamMethod = (metadata, options) => { if (typeof options === 'function') { - throw new Error('gRPCity: asyncStreamFunction should not contain callback function'); + throw new Error('gRPCity: asyncStreamFunction should not contain a callback function'); } else if (typeof metadata === 'function') { - throw new Error('gRPCity: asyncStreamFunction should not contain callback function'); + throw new Error('gRPCity: asyncStreamFunction should not contain a callback function'); } [metadata, options] = this._prepareMetadata(metadata, options, basicMeta); options = this._setDeadline(options, defaultOptions, basicMeta); @@ -99,15 +120,12 @@ class ClientProxy { if (err) { throw this._handlerError(err, basicMeta); } - debug('clientStreamMethod get response', response); result.response = response; }); const call = func.apply(client, argumentsList); - // write() already exists in call - // call.write = call.write call.writeAll = (messages) => { if (Array.isArray(messages)) { - messages.forEach(message => { + messages.forEach((message) => { call.write(message); }); } @@ -115,12 +133,10 @@ class ClientProxy { call.writeEnd = async () => { call.end(); await new Promise((resolve, reject) => { - call.on('metadata', metadata => { - debug('clientStreamMethod get metadata', metadata); + call.on('metadata', (metadata) => { result.metadata = metadata; }); - call.on('status', status => { - debug('clientStreamMethod get status', status); + call.on('status', (status) => { result.status = status; resolve(); }); @@ -134,29 +150,27 @@ class ClientProxy { _promisifyServerStreamMethod(client, func, defaultOptions, basicMeta) { const serverStreamMethod = (request, metadata, options) => { if (typeof options === 'function') { - throw new Error('gRPCity: asyncStreamFunction should not contain callback function'); + throw new Error('gRPCity: asyncStreamFunction should not contain a callback function'); } else if (typeof metadata === 'function') { - throw new Error('gRPCity: asyncStreamFunction should not contain callback function'); + throw new Error('gRPCity: asyncStreamFunction should not contain a callback function'); } [metadata, options] = this._prepareMetadata(metadata, options, basicMeta); options = this._setDeadline(options, defaultOptions, basicMeta); const call = func.apply(client, [request, metadata, options]); - call.on('error', err => { + call.on('error', (err) => { throw this._handlerError(err, basicMeta); }); const result = {}; call.readAll = () => { - call.on('metadata', metadata => { - debug('serverStreamMethod get metadata', metadata); + call.on('metadata', (metadata) => { result.metadata = metadata; }); - call.on('status', status => { - debug('serverStreamMethod get status', status); + call.on('status', (status) => { result.status = status; }); - return iterator(call, 'data', { - resolutionEvents: ['status', 'end'] + return (0, iterator_1.default)(call, 'data', { + resolutionEvents: ['status', 'end'], }); }; call.readEnd = () => { @@ -169,40 +183,35 @@ class ClientProxy { _promisifyDuplexStreamMethod(client, func, defaultOptions, basicMeta) { const duplexStreamMethod = (metadata, options) => { if (typeof options === 'function') { - throw new Error('gRPCity: asyncStreamFunction should not contain callback function'); + throw new Error('gRPCity: asyncStreamFunction should not contain a callback function'); } else if (typeof metadata === 'function') { - throw new Error('gRPCity: asyncStreamFunction should not contain callback function'); + throw new Error('gRPCity: asyncStreamFunction should not contain a callback function'); } [metadata, options] = this._prepareMetadata(metadata, options, basicMeta); options = this._setDeadline(options, defaultOptions, basicMeta); const call = func.apply(client, [metadata, options]); - // write() already exists in call - // call.write = call.write call.writeAll = (messages) => { if (Array.isArray(messages)) { - messages.forEach(message => { + messages.forEach((message) => { call.write(message); }); } }; call.writeEnd = call.end; - call.on('error', err => { + call.on('error', (err) => { throw this._handlerError(err, basicMeta); }); - // readAll() needs to execute writeAll() or write() first before it can be executed const result = {}; call.readAll = () => { - call.on('metadata', metadata => { - debug('serverStreamMethod get metadata', metadata); + call.on('metadata', (metadata) => { result.metadata = metadata; }); - call.on('status', status => { - debug('serverStreamMethod get status', status); + call.on('status', (status) => { result.status = status; }); - return iterator(call, 'data', { - resolutionEvents: ['status', 'end'] + return (0, iterator_1.default)(call, 'data', { + resolutionEvents: ['status', 'end'], }); }; call.readEnd = () => { @@ -218,43 +227,44 @@ class ClientProxy { }; return callbackMethod; } - _prepareMetadata(metadata, options, basicMeta) { - if (metadata instanceof Metadata) { - options = Object.assign({}, options); - } - else { - options = Object.assign({}, metadata); - metadata = new Metadata(); - } - metadata.add('x-client-hostname', basicMeta.hostname); - if (basicMeta.appName) { - metadata.add('x-client-app-name', basicMeta.appName); - } - return [metadata, options]; - } - _handlerError(err, basicMeta) { - const newError = new Error(); - newError.name = 'GrpcClientError'; - newError.code = err.code; - newError.message = `${basicMeta.fullServiceName} (${err.message})`; - const stacks = newError.stack.split('\n'); - newError.stack = [ - stacks[0], - ...stacks.slice(2), - ' ...', - ...err.stack.split('\n').slice(1, 3) - ].join('\n'); - return newError; - } - _setDeadline(options, defaultOptions, basicMeta) { - if (!options.deadline) { - const timeout = options.timeout || defaultOptions.timeout; - const deadline = new Date(Date.now() + timeout); - options.deadline = deadline; - delete options.timeout; - debug('grpc client request will timeout at', { fullServiceName: basicMeta.fullServiceName, deadline }); - } - return options; + _proxy(client, defaultOptions = {}, appName) { + defaultOptions = defaultOptions || {}; + defaultOptions.timeout = defaultOptions.timeout || 1000 * 10; + const prototype = Object.getPrototypeOf(client); + const methodNames = Object.keys(prototype) + .filter((key) => prototype[key] && prototype[key].path) + .reduce((names, key) => { + names[key.toUpperCase()] = prototype[key].path; + return names; + }, {}); + const basicMeta = { hostname: os.hostname(), appName }; + const target = Object.entries(prototype).reduce((target, [name, func]) => { + if (name !== 'constructor' && typeof func === 'function') { + basicMeta.fullServiceName = `${methodNames[name.toUpperCase()]}`; + const { requestStream, responseStream } = this._getFuncStreamWay(func); + if (!requestStream && !responseStream) { + // promisify unary method + target[name] = this._promisifyUnaryMethod(client, func, defaultOptions, basicMeta); + } + // stream + if (requestStream && !responseStream) { + // promisify only client stream method + target[name] = this._promisifyClientStreamMethod(client, func, defaultOptions, basicMeta); + } + if (!requestStream && responseStream) { + // promisify only server stream method + target[name] = this._promisifyServerStreamMethod(client, func, defaultOptions, basicMeta); + } + if (requestStream && responseStream) { + // promisify duplex stream method + target[name] = this._promisifyDuplexStreamMethod(client, func, defaultOptions, basicMeta); + } + // keep callback method + target.call[name] = this._keepCallbackMethod(client, func); + } + return target; + }, { call: {} }); + return target; } } -module.exports = new ClientProxy(); +exports.default = new ClientProxy(); diff --git a/types/proxy/serverProxy.d.ts b/types/proxy/serverProxy.d.ts index b511d99..d69cdb1 100644 --- a/types/proxy/serverProxy.d.ts +++ b/types/proxy/serverProxy.d.ts @@ -1,37 +1,31 @@ -declare const _exports: ServerProxy; -export = _exports; +/// +import * as grpc from '@grpc/grpc-js'; +import { MiddlewareFunction } from '../util/compose'; declare class ServerProxy { - _middleware: any[]; + private _middleware; + private _loader?; + private _server?; + private _insecureServerCredentials?; + constructor(); _init(loader: any, ...args: any[]): this; - _loader: any; - _server: grpc.Server | undefined; - listen(addr: any, credentials?: undefined): Promise; + listen(addr: any, credentials?: grpc.ServerCredentials | undefined): Promise; shutdown(): Promise; forceShutdown(): void; - makeServerCredentials(rootCerts: any, keyCertPairs: any, checkClientCertificate: any): grpc.ServerCredentials; - _insecureServerCredentials: grpc.ServerCredentials | undefined; - addService(name: any, implementation: any, { exclude, inherit }?: { - exclude?: any[] | undefined; - inherit: any; + makeServerCredentials(rootCerts?: Buffer, keyCertPairs?: grpc.KeyCertPair[], checkClientCertificate?: boolean): grpc.ServerCredentials; + addService(name: string, implementation: any, { exclude, inherit }?: { + exclude?: string[]; + inherit?: any; }): void; - removeService(name: any): void; - addMiddleware(...args: any[]): void; - _use(fn: any): void; - _callbackify(target: any, { exclude, inherit, _implementationType }?: { - exclude?: any[] | undefined; - inherit: any; - _implementationType: any; - }): {}; - _proxy(target: any, key: any, options?: {}): ((call: any, callback: any) => void) | undefined; - _createContext(call: any): { - path: any; - request: any; - metadata: any; - }; - _callUnaryProxyMethod(target: any, key: any, composeFunc: any): (call: any, callback: any) => void; - _callClientStreamProxyMethod(target: any, key: any, composeFunc: any): (call: any, callback: any) => void; - _callServerStreamProxyMethod(target: any, key: any, composeFunc: any): (call: any) => void; - _callDuplexStreamProxyMethod(target: any, key: any, composeFunc: any): (call: any) => void; - _createInternalErrorStatus(err: any): any; + removeService(name: string): void; + addMiddleware(...args: MiddlewareFunction[]): void; + private _use; + private _callbackify; + private _proxy; + private _createContext; + private _callUnaryProxyMethod; + private _callClientStreamProxyMethod; + private _callServerStreamProxyMethod; + private _callDuplexStreamProxyMethod; + private _createInternalErrorStatus; } -import grpc = require("@grpc/grpc-js"); +export default ServerProxy; diff --git a/types/proxy/serverProxy.js b/types/proxy/serverProxy.js index c9e0abb..3558df1 100644 --- a/types/proxy/serverProxy.js +++ b/types/proxy/serverProxy.js @@ -1,14 +1,39 @@ "use strict"; +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { + desc = { enumerable: true, get: function() { return m[k]; } }; + } + Object.defineProperty(o, k2, desc); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { + Object.defineProperty(o, "default", { enumerable: true, value: v }); +}) : function(o, v) { + o["default"] = v; +}); +var __importStar = (this && this.__importStar) || function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); + __setModuleDefault(result, mod); + return result; +}; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; Object.defineProperty(exports, "__esModule", { value: true }); -const grpc = require('@grpc/grpc-js'); -const assert = require('assert'); -const util = require('util'); -const _ = require('lodash'); -const Joi = require('joi'); -const serverSchemas = require('../schema/server'); -const iterator = require('../util/iterator'); -const compose = require('../util/compose'); -const debug = require('debug')('grpcity:serverProxy'); +const node_assert_1 = __importDefault(require("node:assert")); +const util = __importStar(require("node:util")); +const grpc = __importStar(require("@grpc/grpc-js")); +const _ = __importStar(require("lodash")); +const Joi = __importStar(require("joi")); +const server_1 = __importDefault(require("../schema/server")); +const iterator_1 = __importDefault(require("../util/iterator")); +const compose_1 = require("../util/compose"); class ServerProxy { constructor() { this._middleware = []; @@ -23,15 +48,14 @@ class ServerProxy { return this; } async listen(addr, credentials = undefined) { - assert(this._server, 'must be first init() server before server listen()'); - Joi.assert(addr, serverSchemas.address, 'server listen() params Error'); - debug('server listen options', addr); + (0, node_assert_1.default)(this._server, 'must be first init() server before server listen()'); + Joi.assert(addr, server_1.default.address, 'server listen() params Error'); const url = _.isString(addr) ? addr : `${addr.host}:${addr.port}`; const bindPort = await new Promise((resolve, reject) => { this._server.bindAsync(url, credentials || this.makeServerCredentials(), (err, result) => (err ? reject(err) : resolve(result))); }); const port = addr.port ? addr.port : Number(addr.match(/:(\d+)/)[1]); - assert(bindPort === port, 'server bind port not to be right'); + (0, node_assert_1.default)(bindPort === port, 'server bind port not to be right'); this._server.start(); } async shutdown() { @@ -60,7 +84,7 @@ class ServerProxy { delete this._loader; } makeServerCredentials(rootCerts, keyCertPairs, checkClientCertificate) { - if (rootCerts) { + if (rootCerts && keyCertPairs) { return grpc.ServerCredentials.createSsl(rootCerts, keyCertPairs, checkClientCertificate); } else { @@ -80,11 +104,11 @@ class ServerProxy { this._server.addService(service, this._callbackify(implementation, options)); } removeService(name) { - assert(this._server, 'must be first init() server before server removeService()'); + (0, node_assert_1.default)(this._server, 'must be first init() server before server removeService()'); this._server.removeService(this._loader.service(name)); } addMiddleware(...args) { - assert(args.length >= 1, 'server addMiddleware() takes at least one argument.'); + (0, node_assert_1.default)(args.length >= 1, 'server addMiddleware() takes at least one argument.'); if (args.length === 1) { if (Array.isArray(args[0])) { args[0].forEach(fn => { @@ -106,11 +130,9 @@ class ServerProxy { throw new TypeError('grpcity loader server middleware must be a function!'); this._middleware.push(fn); } - // async func --- to --> callback type func - // use in grpc server side mostly - _callbackify(target, { exclude = [], inherit, _implementationType } = {}) { - assert(typeof target === 'object', 'Must callbackify an object'); - assert(Array.isArray(exclude), 'options.exclude must be an array of strings'); + _callbackify(target, { exclude = [], inherit, _implementationType }) { + (0, node_assert_1.default)(typeof target === 'object', 'Must callbackify an object'); + (0, node_assert_1.default)(Array.isArray(exclude), 'options.exclude must be an array of strings'); const protoPropertyNames = Object.getOwnPropertyNames(Object.getPrototypeOf({})); exclude.push(...protoPropertyNames); const allPropertyNames = [ @@ -126,21 +148,18 @@ class ServerProxy { if (typeof fn === 'function' && key !== 'constructor' && !exclude.includes(key)) { if (util.types.isAsyncFunction(fn)) { const eglWrapFunction = this._proxy(target, key, _implementationType[key]); - debug(`callbackify async function: ${key}`); methods[key] = eglWrapFunction; } else { - debug(`copy non-async function: ${key}`); methods[key] = fn; } } } - debug('callbackify()', methods); return methods; } _proxy(target, key, options = {}) { const { requestStream, responseStream } = options; - const fn = compose(this._middleware); + const fn = (0, compose_1.compose)(this._middleware); // unary if (!requestStream && !responseStream) { return this._callUnaryProxyMethod(target, key, fn); @@ -174,7 +193,7 @@ class ServerProxy { const handleResponse = async () => { ctx.response = await target[key](call); }; - await composeFunc(ctx, handleResponse).catch(err => { + await composeFunc(ctx, handleResponse).catch((err) => { callback(this._createInternalErrorStatus(err)); }); callback(null, ctx.response); @@ -185,7 +204,7 @@ class ServerProxy { return (call, callback) => { const ctx = this._createContext(call); call.readAll = () => { - return iterator(call, 'data', { + return (0, iterator_1.default)(call, 'data', { resolutionEvents: ['end'] }); }; @@ -193,7 +212,7 @@ class ServerProxy { const handleResponse = async () => { ctx.response = await target[key](call); }; - await composeFunc(ctx, handleResponse).catch(err => { + await composeFunc(ctx, handleResponse).catch((err) => { callback(this._createInternalErrorStatus(err)); }); callback(null, ctx.response); @@ -215,7 +234,7 @@ class ServerProxy { const handleResponse = async () => { await target[key](call); }; - await composeFunc(ctx, handleResponse).catch(err => { + await composeFunc(ctx, handleResponse).catch((err) => { call.destroy(this._createInternalErrorStatus(err)); }); call.end(); @@ -233,7 +252,7 @@ class ServerProxy { } }; call.readAll = () => { - return iterator(call, 'data', { + return (0, iterator_1.default)(call, 'data', { resolutionEvents: ['end'] }); }; @@ -241,7 +260,7 @@ class ServerProxy { const handleResponse = async () => { await target[key](call); }; - await composeFunc(ctx, handleResponse).catch(err => { + await composeFunc(ctx, handleResponse).catch((err) => { call.destroy(this._createInternalErrorStatus(err)); }); call.end(); @@ -260,4 +279,4 @@ class ServerProxy { return err; } } -module.exports = new ServerProxy(); +exports.default = ServerProxy; diff --git a/types/schema/loader.d.ts b/types/schema/loader.d.ts index f2a1554..87b2011 100644 --- a/types/schema/loader.d.ts +++ b/types/schema/loader.d.ts @@ -1,4 +1,7 @@ -import Joi = require("joi"); -export let constructor: Joi.ArraySchema; -export let init: Joi.ObjectSchema; -export let initClients: Joi.ObjectSchema; +import Joi from 'joi'; +declare const loaderSchemas: { + constructor: Joi.ArraySchema; + init: Joi.ObjectSchema; + initClients: Joi.ObjectSchema; +}; +export default loaderSchemas; diff --git a/types/schema/loader.js b/types/schema/loader.js index f5702fd..7c5d393 100644 --- a/types/schema/loader.js +++ b/types/schema/loader.js @@ -1,30 +1,33 @@ "use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; Object.defineProperty(exports, "__esModule", { value: true }); -const Joi = require('joi'); -const addressSchema = Joi.object() - .pattern(/\.*/, Joi.alternatives([ - Joi.string().regex(/:/, 'host and port like 127.0.0.1:9090'), - Joi.object().keys({ - host: Joi.string().required(), - port: Joi.number().integer().min(0).max(65535).required() +const joi_1 = __importDefault(require("joi")); +const addressSchema = joi_1.default.object() + .pattern(/\.*/, joi_1.default.alternatives([ + joi_1.default.string().regex(/:/, 'host and port like 127.0.0.1:9090'), + joi_1.default.object({ + host: joi_1.default.string().required(), + port: joi_1.default.number().integer().min(0).max(65535).required() }) ])); const loaderSchemas = { - constructor: Joi.array().items(Joi.object().keys({ - location: Joi.string().required(), - files: Joi.array().items(Joi.string()).required() + constructor: joi_1.default.array().items(joi_1.default.object({ + location: joi_1.default.string().required(), + files: joi_1.default.array().items(joi_1.default.string()).required() })).single(), - init: Joi.object().keys({ + init: joi_1.default.object({ services: addressSchema.optional(), - isDev: Joi.boolean().optional(), - packagePrefix: Joi.string().optional(), - loadOptions: Joi.object().optional(), - channelOptions: Joi.object().optional(), - appName: Joi.string().optional() + isDev: joi_1.default.boolean().optional(), + packagePrefix: joi_1.default.string().optional(), + loadOptions: joi_1.default.object().optional(), + channelOptions: joi_1.default.object().optional(), + appName: joi_1.default.string().optional() }), - initClients: Joi.object().keys({ + initClients: joi_1.default.object({ services: addressSchema.required(), - channelOptions: Joi.object().optional() + channelOptions: joi_1.default.object().optional() }) }; -module.exports = loaderSchemas; +exports.default = loaderSchemas; diff --git a/types/schema/server.d.ts b/types/schema/server.d.ts index 8d92b11..5b6a583 100644 --- a/types/schema/server.d.ts +++ b/types/schema/server.d.ts @@ -1,2 +1,5 @@ -import Joi = require("joi"); -export let address: Joi.AlternativesSchema; +import Joi from 'joi'; +declare const serverSchemas: { + address: Joi.AlternativesSchema; +}; +export default serverSchemas; diff --git a/types/schema/server.js b/types/schema/server.js index c078b68..43a17e8 100644 --- a/types/schema/server.js +++ b/types/schema/server.js @@ -1,13 +1,16 @@ "use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; Object.defineProperty(exports, "__esModule", { value: true }); -const Joi = require('joi'); +const joi_1 = __importDefault(require("joi")); const serverSchemas = { - address: Joi.alternatives([ - Joi.string().regex(/:/, 'host and port like 127.0.0.1:9090'), - Joi.object().keys({ - host: Joi.string().required(), - port: Joi.number().integer().min(0).max(65535).required() + address: joi_1.default.alternatives([ + joi_1.default.string().regex(/:/, 'host and port like 127.0.0.1:9090'), + joi_1.default.object({ + host: joi_1.default.string().required(), + port: joi_1.default.number().integer().min(0).max(65535).required() }) ]) }; -module.exports = serverSchemas; +exports.default = serverSchemas; diff --git a/types/util/compose.d.ts b/types/util/compose.d.ts index a37fb2b..de2ce79 100644 --- a/types/util/compose.d.ts +++ b/types/util/compose.d.ts @@ -1,2 +1,11 @@ -declare function _exports(middleware: any[]): Function; -export = _exports; +export type MiddlewareFunction = (context: any, next: () => Promise) => Promise; +/** + * Compose `middleware` returning + * a fully valid middleware comprised + * of all those which are passed. + * + * @param {Array} middleware + * @return {Function} + * @api public + */ +export declare const compose: (middleware: MiddlewareFunction[]) => (context: any, next: () => Promise) => Promise; diff --git a/types/util/compose.js b/types/util/compose.js index 477a4a4..5be353e 100644 --- a/types/util/compose.js +++ b/types/util/compose.js @@ -1,5 +1,6 @@ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); +exports.compose = void 0; /** * Compose `middleware` returning * a fully valid middleware comprised @@ -9,12 +10,12 @@ Object.defineProperty(exports, "__esModule", { value: true }); * @return {Function} * @api public */ -module.exports = (middleware) => { +const compose = (middleware) => { if (!Array.isArray(middleware)) - throw new TypeError('Middleware stack must be an array!'); + throw new TypeError("Middleware stack must be an array!"); for (const fn of middleware) { - if (typeof fn !== 'function') - throw new TypeError('Middleware must be composed of functions!'); + if (typeof fn !== "function") + throw new TypeError("Middleware must be composed of functions!"); } return function (context, next) { // last called middleware # @@ -22,7 +23,7 @@ module.exports = (middleware) => { return dispatch(0); function dispatch(i) { if (i <= index) - return Promise.reject(new Error('next() called multiple times')); + return Promise.reject(new Error("next() called multiple times")); index = i; let fn = middleware[i]; if (i === middleware.length) @@ -38,3 +39,4 @@ module.exports = (middleware) => { } }; }; +exports.compose = compose; diff --git a/types/util/iterator.d.ts b/types/util/iterator.d.ts index 0e8347d..15db39e 100644 --- a/types/util/iterator.d.ts +++ b/types/util/iterator.d.ts @@ -1,30 +1,20 @@ -declare function _exports(emitter: any, event: any, options: any): { - [Symbol.asyncIterator](): { - [Symbol.asyncIterator](): any; - next(): Promise<{ - done: boolean; - value: undefined; - }>; - }; +declare const _default: (emitter: any, event: string | string[], options: any) => { + [Symbol.asyncIterator](): any; next(): Promise<{ done: boolean; - value: undefined; + value: any; }>; return?: undefined; } | { - [x: symbol]: () => { - [x: symbol]: any; - next(): Promise; - return(value: any): Promise<{ - done: boolean; - value: any; - }>; - }; - next(): Promise; + [x: symbol]: () => any; + next(): Promise<{ + done: boolean; + value: any; + }>; return(value: any): Promise<{ done: boolean; value: any; }>; [Symbol.asyncIterator]?: undefined; }; -export = _exports; +export default _default; diff --git a/types/util/iterator.js b/types/util/iterator.js index 2b67a74..348cb94 100644 --- a/types/util/iterator.js +++ b/types/util/iterator.js @@ -1,35 +1,35 @@ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const symbolAsyncIterator = Symbol.asyncIterator || '@@asyncIterator'; -const normalizeEmitter = emitter => { +const symbolAsyncIterator = Symbol.asyncIterator || "@@asyncIterator"; +const normalizeEmitter = (emitter) => { const addListener = emitter.on || emitter.addListener || emitter.addEventListener; const removeListener = emitter.off || emitter.removeListener || emitter.removeEventListener; if (!addListener || !removeListener) { - throw new TypeError('Emitter is not compatible'); + throw new TypeError("Emitter is not compatible"); } return { addListener: addListener.bind(emitter), - removeListener: removeListener.bind(emitter) + removeListener: removeListener.bind(emitter), }; }; -const toArray = value => Array.isArray(value) ? value : [value]; -module.exports = (emitter, event, options) => { - if (typeof options === 'function') { +const toArray = (value) => (Array.isArray(value) ? value : [value]); +exports.default = (emitter, event, options) => { + if (typeof options === "function") { options = { filter: options }; } // Allow multiple events const events = toArray(event); options = { - rejectionEvents: ['error'], + rejectionEvents: ["error"], resolutionEvents: [], limit: Infinity, multiArgs: false, - ...options + ...options, }; const { limit } = options; const isValidLimit = limit >= 0 && (limit === Infinity || Number.isInteger(limit)); if (!isValidLimit) { - throw new TypeError('The `limit` option should be a non-negative integer or Infinity'); + throw new TypeError("The `limit` option should be a non-negative integer or Infinity"); } if (limit === 0) { // Return an empty async iterator to avoid any further cost @@ -40,9 +40,9 @@ module.exports = (emitter, event, options) => { async next() { return { done: true, - value: undefined + value: undefined, }; - } + }, }; } const { addListener, removeListener } = normalizeEmitter(emitter); @@ -129,7 +129,7 @@ module.exports = (emitter, event, options) => { const value = valueQueue.shift(); return { done: isDone && valueQueue.length === 0 && !isLimitReached, - value + value, }; } if (hasPendingError) { @@ -139,7 +139,7 @@ module.exports = (emitter, event, options) => { if (isDone) { return { done: true, - value: undefined + value: undefined, }; } return new Promise((resolve, reject) => nextQueue.push({ resolve, reject })); @@ -148,8 +148,8 @@ module.exports = (emitter, event, options) => { cancel(); return { done: isDone, - value + value, }; - } + }, }; }; diff --git a/types/util/prefixingDefinition.d.ts b/types/util/prefixingDefinition.d.ts index 6b582c4..6805329 100644 --- a/types/util/prefixingDefinition.d.ts +++ b/types/util/prefixingDefinition.d.ts @@ -1,2 +1,2 @@ -declare function _exports(packageDefinition: any, packagePrefix: any): any; -export = _exports; +declare const _default: (packageDefinition: any, packagePrefix: any) => any; +export default _default; diff --git a/types/util/prefixingDefinition.js b/types/util/prefixingDefinition.js index 43cd4c2..0cec5eb 100644 --- a/types/util/prefixingDefinition.js +++ b/types/util/prefixingDefinition.js @@ -1,17 +1,21 @@ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -module.exports = (packageDefinition, packagePrefix) => { +exports.default = (packageDefinition, packagePrefix) => { for (const qualifiedName in packageDefinition) { const definition = packageDefinition[qualifiedName]; const newPackage = `${packagePrefix}.${qualifiedName}`; - if (definition.format && definition.type && definition.fileDescriptorProtos) { + if (definition.format && + definition.type && + definition.fileDescriptorProtos) { packageDefinition[newPackage] = definition; } else { const newDefinition = {}; for (const method in definition) { const service = definition[method]; - newDefinition[method] = Object.assign({}, service, { path: service.path.replace(/^\//, `/${packagePrefix}.`) }); + newDefinition[method] = Object.assign({}, service, { + path: service.path.replace(/^\//, `/${packagePrefix}.`), + }); } packageDefinition[newPackage] = newDefinition; } From 4c0e1cd0bf7bb265d3caff7376b8eb3ea9854d44 Mon Sep 17 00:00:00 2001 From: "Chakhsu.Lau" Date: Sun, 3 Dec 2023 17:26:47 +0800 Subject: [PATCH 04/12] feat: update to v1.3.0-beta.0 --- package-lock.json | 7 +++++++ package.json | 25 +++++++------------------ tsconfig.json | 4 +--- 3 files changed, 15 insertions(+), 21 deletions(-) diff --git a/package-lock.json b/package-lock.json index bb9b5f1..57e6ec2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -18,6 +18,7 @@ }, "devDependencies": { "@tsconfig/node14": "^14.1.0", + "@types/lodash": "^4.14.202", "@types/node": "^20.9.5", "chai": "^4.3.10", "mocha": "^10.2.0", @@ -332,6 +333,12 @@ "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", "dev": true }, + "node_modules/@types/lodash": { + "version": "4.14.202", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.202.tgz", + "integrity": "sha512-OvlIYQK9tNneDlS0VN54LLd5uiPCBOp7gS5Z0f1mjoJYBrtStzgmJBxONW3U6OZqdtNzZPmn9BS/7WI7BFFcFQ==", + "dev": true + }, "node_modules/@types/node": { "version": "20.9.5", "resolved": "https://registry.npmjs.org/@types/node/-/node-20.9.5.tgz", diff --git a/package.json b/package.json index 13388ac..043c042 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "grpcity", - "version": "1.2.1", + "version": "1.3.0-beta.0", "description": "A powerful and complete gRPC framework for Node.js", "author": "Chakhsu.Lau", "license": "MIT", @@ -9,7 +9,8 @@ "grpc.js", "grpc", "microservice", - "framework" + "framework", + "typescript" ], "repository": { "type": "git", @@ -20,16 +21,13 @@ "url": "https://github.com/chakhsu/grpcity/issues" }, "main": "./types/index.js", - "types": "./types/index.d.ts", + "typings": "./types/index.d.ts", "scripts": { - "debug": "DEBUG=grpcity* mocha --exit --extension .test.js --recursive test", "test": "mocha --exit --extension .test.js --recursive test", - "fix": "standard --fix 'lib/**/*.js' 'test/**/*.js' | snazzy", - "lint": "standard -v 'lib/**/*.js' 'test/**/*.js' | snazzy", - "type-gen": "tsc -P tsconfig.json" + "build": "rm -rf types && tsc -P tsconfig.json" }, "engines": { - "node": ">=14" + "node": ">=16" }, "dependencies": { "@grpc/grpc-js": "^1.9.11", @@ -41,20 +39,11 @@ }, "devDependencies": { "@tsconfig/node14": "^14.1.0", + "@types/lodash": "^4.14.202", "@types/node": "^20.9.5", "chai": "^4.3.10", "mocha": "^10.2.0", "snazzy": "^9.0.0", - "standard": "^17.1.0", "typescript": "^5.3.2" - }, - "standard": { - "parser": "", - "ignore": [ - "types" - ], - "envs": [ - "mocha" - ] } } diff --git a/tsconfig.json b/tsconfig.json index 5e68110..5f6b2ac 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,13 +1,11 @@ { "extends": "@tsconfig/node14/tsconfig.json", "compilerOptions": { - "target": "ES2018", - "lib": ["ES2018"], "outDir": "types", "sourceMap": false, "declaration": true, "stripInternal": true, "allowJs": true }, - "include": ["lib/*.js"] + "include": ["src/*.ts"] } \ No newline at end of file From 329966f45dac5868e92d017f16a3015463c51cc1 Mon Sep 17 00:00:00 2001 From: "Chakhsu.Lau" Date: Sun, 3 Dec 2023 19:41:12 +0800 Subject: [PATCH 05/12] feat: add prettier --- .editorconfig | 3 + .husky/pre-commit | 4 + .prettierignore | 1 + README_CN.md | 19 +- package-lock.json | 4255 -------------------------------------------- package.json | 19 +- pnpm-lock.yaml | 1681 +++++++++++++++++ prettier.config.js | 7 + 8 files changed, 1720 insertions(+), 4269 deletions(-) create mode 100644 .editorconfig create mode 100755 .husky/pre-commit create mode 100644 .prettierignore delete mode 100644 package-lock.json create mode 100644 pnpm-lock.yaml create mode 100644 prettier.config.js diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..76a93c0 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,3 @@ +[*] +indent_style = space +indent_size = 2 diff --git a/.husky/pre-commit b/.husky/pre-commit new file mode 100755 index 0000000..58b1861 --- /dev/null +++ b/.husky/pre-commit @@ -0,0 +1,4 @@ +#!/usr/bin/env sh +. "$(dirname -- "$0")/_/husky.sh" + +pnpm exec lint-staged diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000..3c3629e --- /dev/null +++ b/.prettierignore @@ -0,0 +1 @@ +node_modules diff --git a/README_CN.md b/README_CN.md index f05462a..7c1ed8d 100644 --- a/README_CN.md +++ b/README_CN.md @@ -4,9 +4,13 @@ ## 介绍 -`gRPCity` 是一个运行在 Node.js 的 gRPC 微服务库,结合了 `proto-loader` 和 `grpc-js`,提供了非常简易的方式去加载 proto 文件,简化了很多难以理解的技术概念,只需要几个函数就可以轻松实现客户端和服务端,同时也提供非常多高级的功能满足大多数开发场景。 +`gRPCity` 是一个运行在 Node.js 的 gRPC 微服务库,结合了 `proto-loader` 和 +`grpc-js`,提供了非常简易的方式去加载 proto 文件,简化了很多难以理解的技术概念, +只需要几个函数就可以轻松实现客户端和服务端,同时也提供非常多高级的功能满足大多数 +开发场景。 -> 名字来源于: gRPC + City = gRPCity,寄托了作者希望这个库能支撑了业务城市的建设,以技术底座的视角,让大家聚焦业务,更好地支撑交付。 +> 名字来源于: gRPC + City = gRPCity,寄托了作者希望这个库能支撑了业务城市的建 +> 设,以技术底座的视角,让大家聚焦业务,更好地支撑交付。 特性如下: @@ -67,9 +71,7 @@ const __dirname = path.dirname(fileURLToPath(import.meta.url)) export default new GrpcLoader({ location: path.join(__dirname, './'), - files: [ - 'greeter.proto' - ] + files: ['greeter.proto'] }) ``` @@ -89,7 +91,7 @@ class Greeter { } } -const start = async (addr) => { +const start = async addr => { await loader.init() const server = loader.initServer() @@ -107,9 +109,9 @@ start('127.0.0.1:9099') 最后,创建`client.js`, 编写下面的代码到其中: ```js -import loader from "./loader.js" +import loader from './loader.js' -const start = async (addr) => { +const start = async addr => { await loader.init() await loader.initClients({ @@ -137,7 +139,6 @@ node ./client.js 可通过访问 [grpcity.js.org](https://grpcity.js.org) 查看完整的文档和示例。 - ## License Released under the MIT License. diff --git a/package-lock.json b/package-lock.json deleted file mode 100644 index 57e6ec2..0000000 --- a/package-lock.json +++ /dev/null @@ -1,4255 +0,0 @@ -{ - "name": "grpcity", - "version": "1.2.1", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "grpcity", - "version": "1.2.1", - "license": "MIT", - "dependencies": { - "@grpc/grpc-js": "^1.9.11", - "@grpc/proto-loader": "^0.7.10", - "debug": "^4.3.4", - "joi": "^17.11.0", - "lodash": "^4.17.21", - "protobufjs": "^7.2.5" - }, - "devDependencies": { - "@tsconfig/node14": "^14.1.0", - "@types/lodash": "^4.14.202", - "@types/node": "^20.9.5", - "chai": "^4.3.10", - "mocha": "^10.2.0", - "snazzy": "^9.0.0", - "standard": "^17.1.0", - "typescript": "^5.3.2" - }, - "engines": { - "node": ">=14" - } - }, - "node_modules/@aashutoshrathi/word-wrap": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", - "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/@eslint-community/eslint-utils": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", - "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", - "dev": true, - "dependencies": { - "eslint-visitor-keys": "^3.3.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" - } - }, - "node_modules/@eslint-community/regexpp": { - "version": "4.10.0", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.0.tgz", - "integrity": "sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==", - "dev": true, - "engines": { - "node": "^12.0.0 || ^14.0.0 || >=16.0.0" - } - }, - "node_modules/@eslint/eslintrc": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.2.tgz", - "integrity": "sha512-+wvgpDsrB1YqAMdEUCcnTlpfVBH7Vqn6A/NT3D8WVXFIaKMlErPIZT3oCIAVCOtarRpMtelZLqJeU3t7WY6X6g==", - "dev": true, - "dependencies": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^9.6.0", - "globals": "^13.19.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.1.2", - "strip-json-comments": "^3.1.1" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/@eslint/eslintrc/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/@eslint/js": { - "version": "8.52.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.52.0.tgz", - "integrity": "sha512-mjZVbpaeMZludF2fsWLD0Z9gCref1Tk4i9+wddjRvpUNqqcndPkBD09N/Mapey0b3jaXbLm2kICwFv2E64QinA==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, - "node_modules/@grpc/grpc-js": { - "version": "1.9.11", - "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.9.11.tgz", - "integrity": "sha512-QDhMfbTROOXUhLHMroow8f3EHiCKUOh6UwxMP5S3EuXMnWMNSVIhatGZRwkpg9OUTYdZPsDUVH3cOAkWhGFUJw==", - "dependencies": { - "@grpc/proto-loader": "^0.7.8", - "@types/node": ">=12.12.47" - }, - "engines": { - "node": "^8.13.0 || >=10.10.0" - } - }, - "node_modules/@grpc/proto-loader": { - "version": "0.7.10", - "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.7.10.tgz", - "integrity": "sha512-CAqDfoaQ8ykFd9zqBDn4k6iWT9loLAlc2ETmDFS9JCD70gDcnA4L3AFEo2iV7KyAtAAHFW9ftq1Fz+Vsgq80RQ==", - "dependencies": { - "lodash.camelcase": "^4.3.0", - "long": "^5.0.0", - "protobufjs": "^7.2.4", - "yargs": "^17.7.2" - }, - "bin": { - "proto-loader-gen-types": "build/bin/proto-loader-gen-types.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/@hapi/hoek": { - "version": "9.3.0", - "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.3.0.tgz", - "integrity": "sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==" - }, - "node_modules/@hapi/topo": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/@hapi/topo/-/topo-5.1.0.tgz", - "integrity": "sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg==", - "dependencies": { - "@hapi/hoek": "^9.0.0" - } - }, - "node_modules/@humanwhocodes/config-array": { - "version": "0.11.13", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.13.tgz", - "integrity": "sha512-JSBDMiDKSzQVngfRjOdFXgFfklaXI4K9nLF49Auh21lmBWRLIK3+xTErTWD4KU54pb6coM6ESE7Awz/FNU3zgQ==", - "dev": true, - "dependencies": { - "@humanwhocodes/object-schema": "^2.0.1", - "debug": "^4.1.1", - "minimatch": "^3.0.5" - }, - "engines": { - "node": ">=10.10.0" - } - }, - "node_modules/@humanwhocodes/config-array/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/@humanwhocodes/config-array/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/@humanwhocodes/module-importer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", - "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", - "dev": true, - "engines": { - "node": ">=12.22" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, - "node_modules/@humanwhocodes/object-schema": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.1.tgz", - "integrity": "sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==", - "dev": true - }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, - "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, - "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@protobufjs/aspromise": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", - "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==" - }, - "node_modules/@protobufjs/base64": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", - "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==" - }, - "node_modules/@protobufjs/codegen": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", - "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==" - }, - "node_modules/@protobufjs/eventemitter": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", - "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==" - }, - "node_modules/@protobufjs/fetch": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", - "integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==", - "dependencies": { - "@protobufjs/aspromise": "^1.1.1", - "@protobufjs/inquire": "^1.1.0" - } - }, - "node_modules/@protobufjs/float": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", - "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==" - }, - "node_modules/@protobufjs/inquire": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", - "integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==" - }, - "node_modules/@protobufjs/path": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", - "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==" - }, - "node_modules/@protobufjs/pool": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", - "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==" - }, - "node_modules/@protobufjs/utf8": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", - "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==" - }, - "node_modules/@sideway/address": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.4.tgz", - "integrity": "sha512-7vwq+rOHVWjyXxVlR76Agnvhy8I9rpzjosTESvmhNeXOXdZZB15Fl+TI9x1SiHZH5Jv2wTGduSxFDIaq0m3DUw==", - "dependencies": { - "@hapi/hoek": "^9.0.0" - } - }, - "node_modules/@sideway/formula": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@sideway/formula/-/formula-3.0.1.tgz", - "integrity": "sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg==" - }, - "node_modules/@sideway/pinpoint": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@sideway/pinpoint/-/pinpoint-2.0.0.tgz", - "integrity": "sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==" - }, - "node_modules/@tsconfig/node14": { - "version": "14.1.0", - "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-14.1.0.tgz", - "integrity": "sha512-VmsCG04YR58ciHBeJKBDNMWWfYbyP8FekWVuTlpstaUPlat1D0x/tXzkWP7yCMU0eSz9V4OZU0LBWTFJ3xZf6w==", - "dev": true - }, - "node_modules/@types/json5": { - "version": "0.0.29", - "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", - "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", - "dev": true - }, - "node_modules/@types/lodash": { - "version": "4.14.202", - "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.202.tgz", - "integrity": "sha512-OvlIYQK9tNneDlS0VN54LLd5uiPCBOp7gS5Z0f1mjoJYBrtStzgmJBxONW3U6OZqdtNzZPmn9BS/7WI7BFFcFQ==", - "dev": true - }, - "node_modules/@types/node": { - "version": "20.9.5", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.9.5.tgz", - "integrity": "sha512-Uq2xbNq0chGg+/WQEU0LJTSs/1nKxz6u1iemLcGomkSnKokbW1fbLqc3HOqCf2JP7KjlL4QkS7oZZTrOQHQYgQ==", - "dependencies": { - "undici-types": "~5.26.4" - } - }, - "node_modules/@ungap/structured-clone": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", - "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", - "dev": true - }, - "node_modules/acorn": { - "version": "8.11.2", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.2.tgz", - "integrity": "sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w==", - "dev": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, - "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, - "node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ansi-colors": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", - "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "engines": { - "node": ">=8" - } - }, - "node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/anymatch": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", - "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", - "dev": true, - "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, - "node_modules/array-buffer-byte-length": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz", - "integrity": "sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "is-array-buffer": "^3.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array-includes": { - "version": "3.1.7", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.7.tgz", - "integrity": "sha512-dlcsNBIiWhPkHdOEEKnehA+RNUWDc4UqFtnIXU4uuYDPtA4LDkr7qip2p0VvFAEXNDr0yWZ9PJyIRiGjRLQzwQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "get-intrinsic": "^1.2.1", - "is-string": "^1.0.7" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array.prototype.findlastindex": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.3.tgz", - "integrity": "sha512-LzLoiOMAxvy+Gd3BAq3B7VeIgPdo+Q8hthvKtXybMvRV0jrXfJM/t8mw7nNlpEcVlVUnCnM2KSX4XU5HmpodOA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "es-shim-unscopables": "^1.0.0", - "get-intrinsic": "^1.2.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array.prototype.flat": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.2.tgz", - "integrity": "sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "es-shim-unscopables": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array.prototype.flatmap": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.2.tgz", - "integrity": "sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "es-shim-unscopables": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array.prototype.tosorted": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.2.tgz", - "integrity": "sha512-HuQCHOlk1Weat5jzStICBCd83NxiIMwqDg/dHEsoefabn/hJRj5pVdWcPUSpRrwhwxZOsQassMpgN/xRYFBMIg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "es-shim-unscopables": "^1.0.0", - "get-intrinsic": "^1.2.1" - } - }, - "node_modules/arraybuffer.prototype.slice": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.2.tgz", - "integrity": "sha512-yMBKppFur/fbHu9/6USUe03bZ4knMYiwFBcyiaXB8Go0qNehwX6inYPzK9U0NeQvGxKthcmHcaR8P5MStSRBAw==", - "dev": true, - "dependencies": { - "array-buffer-byte-length": "^1.0.0", - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "get-intrinsic": "^1.2.1", - "is-array-buffer": "^3.0.2", - "is-shared-array-buffer": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/assertion-error": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", - "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/asynciterator.prototype": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/asynciterator.prototype/-/asynciterator.prototype-1.0.0.tgz", - "integrity": "sha512-wwHYEIS0Q80f5mosx3L/dfG5t5rjEa9Ft51GTaNt862EnpyGHpgz2RkZvLPp1oF5TnAiTohkEKVEu8pQPJI7Vg==", - "dev": true, - "dependencies": { - "has-symbols": "^1.0.3" - } - }, - "node_modules/available-typed-arrays": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", - "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true - }, - "node_modules/binary-extensions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", - "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "dependencies": { - "fill-range": "^7.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/browser-stdout": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", - "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", - "dev": true - }, - "node_modules/buffer-from": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", - "dev": true - }, - "node_modules/builtins": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/builtins/-/builtins-5.0.1.tgz", - "integrity": "sha512-qwVpFEHNfhYJIzNRBvd2C1kyo6jz3ZSMPyyuR47OPdiKWlbYnZNyDWuyR175qDnAJLiCo5fBBqPb3RiXgWlkOQ==", - "dev": true, - "dependencies": { - "semver": "^7.0.0" - } - }, - "node_modules/builtins/node_modules/semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/call-bind": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.5.tgz", - "integrity": "sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.1", - "set-function-length": "^1.1.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/chai": { - "version": "4.3.10", - "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.10.tgz", - "integrity": "sha512-0UXG04VuVbruMUYbJ6JctvH0YnC/4q3/AkT18q4NaITo91CUm0liMS9VqzT9vZhVQ/1eqPanMWjBM+Juhfb/9g==", - "dev": true, - "dependencies": { - "assertion-error": "^1.1.0", - "check-error": "^1.0.3", - "deep-eql": "^4.1.3", - "get-func-name": "^2.0.2", - "loupe": "^2.3.6", - "pathval": "^1.1.1", - "type-detect": "^4.0.8" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/chalk/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/check-error": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.3.tgz", - "integrity": "sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==", - "dev": true, - "dependencies": { - "get-func-name": "^2.0.2" - }, - "engines": { - "node": "*" - } - }, - "node_modules/chokidar": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", - "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - ], - "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - }, - "engines": { - "node": ">= 8.10.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, - "node_modules/cliui": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", - "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true - }, - "node_modules/concat-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-2.0.0.tgz", - "integrity": "sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==", - "dev": true, - "engines": [ - "node >= 6.0" - ], - "dependencies": { - "buffer-from": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^3.0.2", - "typedarray": "^0.0.6" - } - }, - "node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/decamelize": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", - "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/deep-eql": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.3.tgz", - "integrity": "sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==", - "dev": true, - "dependencies": { - "type-detect": "^4.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true - }, - "node_modules/define-data-property": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.1.tgz", - "integrity": "sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ==", - "dev": true, - "dependencies": { - "get-intrinsic": "^1.2.1", - "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/define-properties": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", - "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", - "dev": true, - "dependencies": { - "define-data-property": "^1.0.1", - "has-property-descriptors": "^1.0.0", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/diff": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", - "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", - "dev": true, - "engines": { - "node": ">=0.3.1" - } - }, - "node_modules/doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dev": true, - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" - }, - "node_modules/error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "dev": true, - "dependencies": { - "is-arrayish": "^0.2.1" - } - }, - "node_modules/es-abstract": { - "version": "1.22.3", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.22.3.tgz", - "integrity": "sha512-eiiY8HQeYfYH2Con2berK+To6GrK2RxbPawDkGq4UiCQQfZHb6wX9qQqkbpPqaxQFcl8d9QzZqo0tGE0VcrdwA==", - "dev": true, - "dependencies": { - "array-buffer-byte-length": "^1.0.0", - "arraybuffer.prototype.slice": "^1.0.2", - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.5", - "es-set-tostringtag": "^2.0.1", - "es-to-primitive": "^1.2.1", - "function.prototype.name": "^1.1.6", - "get-intrinsic": "^1.2.2", - "get-symbol-description": "^1.0.0", - "globalthis": "^1.0.3", - "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.0", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3", - "hasown": "^2.0.0", - "internal-slot": "^1.0.5", - "is-array-buffer": "^3.0.2", - "is-callable": "^1.2.7", - "is-negative-zero": "^2.0.2", - "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.2", - "is-string": "^1.0.7", - "is-typed-array": "^1.1.12", - "is-weakref": "^1.0.2", - "object-inspect": "^1.13.1", - "object-keys": "^1.1.1", - "object.assign": "^4.1.4", - "regexp.prototype.flags": "^1.5.1", - "safe-array-concat": "^1.0.1", - "safe-regex-test": "^1.0.0", - "string.prototype.trim": "^1.2.8", - "string.prototype.trimend": "^1.0.7", - "string.prototype.trimstart": "^1.0.7", - "typed-array-buffer": "^1.0.0", - "typed-array-byte-length": "^1.0.0", - "typed-array-byte-offset": "^1.0.0", - "typed-array-length": "^1.0.4", - "unbox-primitive": "^1.0.2", - "which-typed-array": "^1.1.13" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/es-iterator-helpers": { - "version": "1.0.15", - "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.0.15.tgz", - "integrity": "sha512-GhoY8uYqd6iwUl2kgjTm4CZAf6oo5mHK7BPqx3rKgx893YSsy0LGHV6gfqqQvZt/8xM8xeOnfXBCfqclMKkJ5g==", - "dev": true, - "dependencies": { - "asynciterator.prototype": "^1.0.0", - "call-bind": "^1.0.2", - "define-properties": "^1.2.1", - "es-abstract": "^1.22.1", - "es-set-tostringtag": "^2.0.1", - "function-bind": "^1.1.1", - "get-intrinsic": "^1.2.1", - "globalthis": "^1.0.3", - "has-property-descriptors": "^1.0.0", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3", - "internal-slot": "^1.0.5", - "iterator.prototype": "^1.1.2", - "safe-array-concat": "^1.0.1" - } - }, - "node_modules/es-set-tostringtag": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.2.tgz", - "integrity": "sha512-BuDyupZt65P9D2D2vA/zqcI3G5xRsklm5N3xCwuiy+/vKy8i0ifdsQP1sLgO4tZDSCaQUSnmC48khknGMV3D2Q==", - "dev": true, - "dependencies": { - "get-intrinsic": "^1.2.2", - "has-tostringtag": "^1.0.0", - "hasown": "^2.0.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-shim-unscopables": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.2.tgz", - "integrity": "sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==", - "dev": true, - "dependencies": { - "hasown": "^2.0.0" - } - }, - "node_modules/es-to-primitive": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", - "dev": true, - "dependencies": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", - "engines": { - "node": ">=6" - } - }, - "node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint": { - "version": "8.52.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.52.0.tgz", - "integrity": "sha512-zh/JHnaixqHZsolRB/w9/02akBk9EPrOs9JwcTP2ek7yL5bVvXuRariiaAjjoJ5DvuwQ1WAE/HsMz+w17YgBCg==", - "dev": true, - "dependencies": { - "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.6.1", - "@eslint/eslintrc": "^2.1.2", - "@eslint/js": "8.52.0", - "@humanwhocodes/config-array": "^0.11.13", - "@humanwhocodes/module-importer": "^1.0.1", - "@nodelib/fs.walk": "^1.2.8", - "@ungap/structured-clone": "^1.2.0", - "ajv": "^6.12.4", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", - "debug": "^4.3.2", - "doctrine": "^3.0.0", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.2.2", - "eslint-visitor-keys": "^3.4.3", - "espree": "^9.6.1", - "esquery": "^1.4.2", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", - "find-up": "^5.0.0", - "glob-parent": "^6.0.2", - "globals": "^13.19.0", - "graphemer": "^1.4.0", - "ignore": "^5.2.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "is-path-inside": "^3.0.3", - "js-yaml": "^4.1.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.1.2", - "natural-compare": "^1.4.0", - "optionator": "^0.9.3", - "strip-ansi": "^6.0.1", - "text-table": "^0.2.0" - }, - "bin": { - "eslint": "bin/eslint.js" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-config-standard": { - "version": "17.1.0", - "resolved": "https://registry.npmjs.org/eslint-config-standard/-/eslint-config-standard-17.1.0.tgz", - "integrity": "sha512-IwHwmaBNtDK4zDHQukFDW5u/aTb8+meQWZvNFWkiGmbWjD6bqyuSSBxxXKkCftCUzc1zwCH2m/baCNDLGmuO5Q==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "eslint": "^8.0.1", - "eslint-plugin-import": "^2.25.2", - "eslint-plugin-n": "^15.0.0 || ^16.0.0 ", - "eslint-plugin-promise": "^6.0.0" - } - }, - "node_modules/eslint-config-standard-jsx": { - "version": "11.0.0", - "resolved": "https://registry.npmjs.org/eslint-config-standard-jsx/-/eslint-config-standard-jsx-11.0.0.tgz", - "integrity": "sha512-+1EV/R0JxEK1L0NGolAr8Iktm3Rgotx3BKwgaX+eAuSX8D952LULKtjgZD3F+e6SvibONnhLwoTi9DPxN5LvvQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "peerDependencies": { - "eslint": "^8.8.0", - "eslint-plugin-react": "^7.28.0" - } - }, - "node_modules/eslint-import-resolver-node": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz", - "integrity": "sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==", - "dev": true, - "dependencies": { - "debug": "^3.2.7", - "is-core-module": "^2.13.0", - "resolve": "^1.22.4" - } - }, - "node_modules/eslint-import-resolver-node/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/eslint-module-utils": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.8.0.tgz", - "integrity": "sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw==", - "dev": true, - "dependencies": { - "debug": "^3.2.7" - }, - "engines": { - "node": ">=4" - }, - "peerDependenciesMeta": { - "eslint": { - "optional": true - } - } - }, - "node_modules/eslint-module-utils/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/eslint-plugin-es": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-es/-/eslint-plugin-es-4.1.0.tgz", - "integrity": "sha512-GILhQTnjYE2WorX5Jyi5i4dz5ALWxBIdQECVQavL6s7cI76IZTDWleTHkxz/QT3kvcs2QlGHvKLYsSlPOlPXnQ==", - "dev": true, - "dependencies": { - "eslint-utils": "^2.0.0", - "regexpp": "^3.0.0" - }, - "engines": { - "node": ">=8.10.0" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" - }, - "peerDependencies": { - "eslint": ">=4.19.1" - } - }, - "node_modules/eslint-plugin-es/node_modules/eslint-utils": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", - "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", - "dev": true, - "dependencies": { - "eslint-visitor-keys": "^1.1.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" - } - }, - "node_modules/eslint-plugin-es/node_modules/eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/eslint-plugin-import": { - "version": "2.29.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.29.0.tgz", - "integrity": "sha512-QPOO5NO6Odv5lpoTkddtutccQjysJuFxoPS7fAHO+9m9udNHvTCPSAMW9zGAYj8lAIdr40I8yPCdUYrncXtrwg==", - "dev": true, - "dependencies": { - "array-includes": "^3.1.7", - "array.prototype.findlastindex": "^1.2.3", - "array.prototype.flat": "^1.3.2", - "array.prototype.flatmap": "^1.3.2", - "debug": "^3.2.7", - "doctrine": "^2.1.0", - "eslint-import-resolver-node": "^0.3.9", - "eslint-module-utils": "^2.8.0", - "hasown": "^2.0.0", - "is-core-module": "^2.13.1", - "is-glob": "^4.0.3", - "minimatch": "^3.1.2", - "object.fromentries": "^2.0.7", - "object.groupby": "^1.0.1", - "object.values": "^1.1.7", - "semver": "^6.3.1", - "tsconfig-paths": "^3.14.2" - }, - "engines": { - "node": ">=4" - }, - "peerDependencies": { - "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8" - } - }, - "node_modules/eslint-plugin-import/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/eslint-plugin-import/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/eslint-plugin-import/node_modules/doctrine": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", - "dev": true, - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/eslint-plugin-import/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/eslint-plugin-n": { - "version": "15.7.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-n/-/eslint-plugin-n-15.7.0.tgz", - "integrity": "sha512-jDex9s7D/Qial8AGVIHq4W7NswpUD5DPDL2RH8Lzd9EloWUuvUkHfv4FRLMipH5q2UtyurorBkPeNi1wVWNh3Q==", - "dev": true, - "dependencies": { - "builtins": "^5.0.1", - "eslint-plugin-es": "^4.1.0", - "eslint-utils": "^3.0.0", - "ignore": "^5.1.1", - "is-core-module": "^2.11.0", - "minimatch": "^3.1.2", - "resolve": "^1.22.1", - "semver": "^7.3.8" - }, - "engines": { - "node": ">=12.22.0" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" - }, - "peerDependencies": { - "eslint": ">=7.0.0" - } - }, - "node_modules/eslint-plugin-n/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/eslint-plugin-n/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/eslint-plugin-n/node_modules/semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/eslint-plugin-promise": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-6.1.1.tgz", - "integrity": "sha512-tjqWDwVZQo7UIPMeDReOpUgHCmCiH+ePnVT+5zVapL0uuHnegBUs2smM13CzOs2Xb5+MHMRFTs9v24yjba4Oig==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0" - } - }, - "node_modules/eslint-plugin-react": { - "version": "7.33.2", - "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.33.2.tgz", - "integrity": "sha512-73QQMKALArI8/7xGLNI/3LylrEYrlKZSb5C9+q3OtOewTnMQi5cT+aE9E41sLCmli3I9PGGmD1yiZydyo4FEPw==", - "dev": true, - "dependencies": { - "array-includes": "^3.1.6", - "array.prototype.flatmap": "^1.3.1", - "array.prototype.tosorted": "^1.1.1", - "doctrine": "^2.1.0", - "es-iterator-helpers": "^1.0.12", - "estraverse": "^5.3.0", - "jsx-ast-utils": "^2.4.1 || ^3.0.0", - "minimatch": "^3.1.2", - "object.entries": "^1.1.6", - "object.fromentries": "^2.0.6", - "object.hasown": "^1.1.2", - "object.values": "^1.1.6", - "prop-types": "^15.8.1", - "resolve": "^2.0.0-next.4", - "semver": "^6.3.1", - "string.prototype.matchall": "^4.0.8" - }, - "engines": { - "node": ">=4" - }, - "peerDependencies": { - "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8" - } - }, - "node_modules/eslint-plugin-react/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/eslint-plugin-react/node_modules/doctrine": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", - "dev": true, - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/eslint-plugin-react/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/eslint-plugin-react/node_modules/resolve": { - "version": "2.0.0-next.5", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.5.tgz", - "integrity": "sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==", - "dev": true, - "dependencies": { - "is-core-module": "^2.13.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/eslint-scope": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", - "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", - "dev": true, - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-utils": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", - "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", - "dev": true, - "dependencies": { - "eslint-visitor-keys": "^2.0.0" - }, - "engines": { - "node": "^10.0.0 || ^12.0.0 || >= 14.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" - }, - "peerDependencies": { - "eslint": ">=5" - } - }, - "node_modules/eslint-utils/node_modules/eslint-visitor-keys": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", - "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/eslint-visitor-keys": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/eslint/node_modules/glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.3" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/eslint/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/espree": { - "version": "9.6.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", - "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", - "dev": true, - "dependencies": { - "acorn": "^8.9.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.4.1" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/esquery": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", - "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", - "dev": true, - "dependencies": { - "estraverse": "^5.1.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, - "dependencies": { - "estraverse": "^5.2.0" - }, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true - }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true - }, - "node_modules/fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true - }, - "node_modules/fastq": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", - "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", - "dev": true, - "dependencies": { - "reusify": "^1.0.4" - } - }, - "node_modules/file-entry-cache": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", - "dev": true, - "dependencies": { - "flat-cache": "^3.0.4" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, - "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/flat": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", - "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", - "dev": true, - "bin": { - "flat": "cli.js" - } - }, - "node_modules/flat-cache": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.1.1.tgz", - "integrity": "sha512-/qM2b3LUIaIgviBQovTLvijfyOQXPtSRnRK26ksj2J7rzPIecePUIpJsZ4T02Qg+xiAEKIs5K8dsHEd+VaKa/Q==", - "dev": true, - "dependencies": { - "flatted": "^3.2.9", - "keyv": "^4.5.3", - "rimraf": "^3.0.2" - }, - "engines": { - "node": ">=12.0.0" - } - }, - "node_modules/flatted": { - "version": "3.2.9", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.9.tgz", - "integrity": "sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==", - "dev": true - }, - "node_modules/for-each": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", - "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", - "dev": true, - "dependencies": { - "is-callable": "^1.1.3" - } - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true - }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/function-bind": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/function.prototype.name": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.6.tgz", - "integrity": "sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "functions-have-names": "^1.2.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/functions-have-names": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", - "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "engines": { - "node": "6.* || 8.* || >= 10.*" - } - }, - "node_modules/get-func-name": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz", - "integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/get-intrinsic": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.2.tgz", - "integrity": "sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.2", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3", - "hasown": "^2.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-stdin": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-8.0.0.tgz", - "integrity": "sha512-sY22aA6xchAzprjyqmSEQv4UbAAzRN0L2dQB0NlN5acTTK9Don6nhoc3eAbUnpZiCANAMfd/+40kVdKfFygohg==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/get-symbol-description": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", - "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/glob": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", - "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/glob/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/glob/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/globals": { - "version": "13.23.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.23.0.tgz", - "integrity": "sha512-XAmF0RjlrjY23MA51q3HltdlGxUpXPvg0GioKiD9X6HD28iMjo2dKC8Vqwm7lne4GNr78+RHTfliktR6ZH09wA==", - "dev": true, - "dependencies": { - "type-fest": "^0.20.2" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/globalthis": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz", - "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==", - "dev": true, - "dependencies": { - "define-properties": "^1.1.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/gopd": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", - "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", - "dev": true, - "dependencies": { - "get-intrinsic": "^1.1.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/graceful-fs": { - "version": "4.2.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "dev": true - }, - "node_modules/graphemer": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", - "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", - "dev": true - }, - "node_modules/has-bigints": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", - "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/has-property-descriptors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.1.tgz", - "integrity": "sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg==", - "dev": true, - "dependencies": { - "get-intrinsic": "^1.2.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", - "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-symbols": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-tostringtag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", - "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", - "dev": true, - "dependencies": { - "has-symbols": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/hasown": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz", - "integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/he": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", - "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", - "dev": true, - "bin": { - "he": "bin/he" - } - }, - "node_modules/ignore": { - "version": "5.2.4", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", - "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", - "dev": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dev": true, - "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "dev": true, - "engines": { - "node": ">=0.8.19" - } - }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "dev": true, - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true - }, - "node_modules/internal-slot": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.6.tgz", - "integrity": "sha512-Xj6dv+PsbtwyPpEflsejS+oIZxmMlV44zAhG479uYu89MsjcYOhCFnNyKrkJrihbsiasQyY0afoCl/9BLR65bg==", - "dev": true, - "dependencies": { - "get-intrinsic": "^1.2.2", - "hasown": "^2.0.0", - "side-channel": "^1.0.4" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/is-array-buffer": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.2.tgz", - "integrity": "sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.2.0", - "is-typed-array": "^1.1.10" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", - "dev": true - }, - "node_modules/is-async-function": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.0.0.tgz", - "integrity": "sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA==", - "dev": true, - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-bigint": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", - "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", - "dev": true, - "dependencies": { - "has-bigints": "^1.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dev": true, - "dependencies": { - "binary-extensions": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-boolean-object": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", - "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-callable": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", - "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-core-module": { - "version": "2.13.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", - "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", - "dev": true, - "dependencies": { - "hasown": "^2.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-date-object": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", - "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", - "dev": true, - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-finalizationregistry": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.0.2.tgz", - "integrity": "sha512-0by5vtUJs8iFQb5TYUHHPudOR+qXYIMKtiUzvLIZITZUjknFmziyBJuLhVRc+Ds0dREFlskDNJKYIdIzu/9pfw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "engines": { - "node": ">=8" - } - }, - "node_modules/is-generator-function": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz", - "integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==", - "dev": true, - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-map": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.2.tgz", - "integrity": "sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-negative-zero": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", - "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/is-number-object": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", - "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", - "dev": true, - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-path-inside": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", - "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-plain-obj": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", - "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-regex": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", - "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-set": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.2.tgz", - "integrity": "sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-shared-array-buffer": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", - "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-string": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", - "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", - "dev": true, - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-symbol": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", - "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", - "dev": true, - "dependencies": { - "has-symbols": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-typed-array": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.12.tgz", - "integrity": "sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg==", - "dev": true, - "dependencies": { - "which-typed-array": "^1.1.11" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-unicode-supported": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", - "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-weakmap": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.1.tgz", - "integrity": "sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-weakref": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", - "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-weakset": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.2.tgz", - "integrity": "sha512-t2yVvttHkQktwnNNmBQ98AhENLdPUTDTE21uPqAQ0ARwQfGeQKRVS0NNurH7bTf7RrvcVn1OOge45CnBeHCSmg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/isarray": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", - "dev": true - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true - }, - "node_modules/iterator.prototype": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.2.tgz", - "integrity": "sha512-DR33HMMr8EzwuRL8Y9D3u2BMj8+RqSE850jfGu59kS7tbmPLzGkZmVSfyCFSDxuZiEY6Rzt3T2NA/qU+NwVj1w==", - "dev": true, - "dependencies": { - "define-properties": "^1.2.1", - "get-intrinsic": "^1.2.1", - "has-symbols": "^1.0.3", - "reflect.getprototypeof": "^1.0.4", - "set-function-name": "^2.0.1" - } - }, - "node_modules/joi": { - "version": "17.11.0", - "resolved": "https://registry.npmjs.org/joi/-/joi-17.11.0.tgz", - "integrity": "sha512-NgB+lZLNoqISVy1rZocE9PZI36bL/77ie924Ri43yEvi9GUUMPeyVIr8KdFTMUlby1p0PBYMk9spIxEUQYqrJQ==", - "dependencies": { - "@hapi/hoek": "^9.0.0", - "@hapi/topo": "^5.0.0", - "@sideway/address": "^4.1.3", - "@sideway/formula": "^3.0.1", - "@sideway/pinpoint": "^2.0.0" - } - }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true - }, - "node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/json-buffer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", - "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", - "dev": true - }, - "node_modules/json-parse-better-errors": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", - "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", - "dev": true - }, - "node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "node_modules/json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "dev": true - }, - "node_modules/json5": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", - "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", - "dev": true, - "dependencies": { - "minimist": "^1.2.0" - }, - "bin": { - "json5": "lib/cli.js" - } - }, - "node_modules/jsx-ast-utils": { - "version": "3.3.5", - "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz", - "integrity": "sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==", - "dev": true, - "dependencies": { - "array-includes": "^3.1.6", - "array.prototype.flat": "^1.3.1", - "object.assign": "^4.1.4", - "object.values": "^1.1.6" - }, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/keyv": { - "version": "4.5.4", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", - "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", - "dev": true, - "dependencies": { - "json-buffer": "3.0.1" - } - }, - "node_modules/levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dev": true, - "dependencies": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/load-json-file": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-5.3.0.tgz", - "integrity": "sha512-cJGP40Jc/VXUsp8/OrnyKyTZ1y6v/dphm3bioS+RrKXjK2BB6wHUd6JptZEFDGgGahMT+InnZO5i1Ei9mpC8Bw==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.1.15", - "parse-json": "^4.0.0", - "pify": "^4.0.1", - "strip-bom": "^3.0.0", - "type-fest": "^0.3.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/load-json-file/node_modules/type-fest": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.3.1.tgz", - "integrity": "sha512-cUGJnCdr4STbePCgqNFbpVNCepa+kAVohJs1sLhxzdH+gnEoOd8VhbYa7pD3zZYGiURWM2xzEII3fQcRizDkYQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, - "dependencies": { - "p-locate": "^5.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" - }, - "node_modules/lodash.camelcase": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", - "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==" - }, - "node_modules/lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true - }, - "node_modules/log-symbols": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", - "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", - "dev": true, - "dependencies": { - "chalk": "^4.1.0", - "is-unicode-supported": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/long": { - "version": "5.2.3", - "resolved": "https://registry.npmjs.org/long/-/long-5.2.3.tgz", - "integrity": "sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q==" - }, - "node_modules/loose-envify": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", - "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "dev": true, - "dependencies": { - "js-tokens": "^3.0.0 || ^4.0.0" - }, - "bin": { - "loose-envify": "cli.js" - } - }, - "node_modules/loupe": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.7.tgz", - "integrity": "sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==", - "dev": true, - "dependencies": { - "get-func-name": "^2.0.1" - } - }, - "node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/minimatch": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz", - "integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==", - "dev": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/minimist": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", - "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/mocha": { - "version": "10.2.0", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.2.0.tgz", - "integrity": "sha512-IDY7fl/BecMwFHzoqF2sg/SHHANeBoMMXFlS9r0OXKDssYE1M5O43wUY/9BVPeIvfH2zmEbBfseqN9gBQZzXkg==", - "dev": true, - "dependencies": { - "ansi-colors": "4.1.1", - "browser-stdout": "1.3.1", - "chokidar": "3.5.3", - "debug": "4.3.4", - "diff": "5.0.0", - "escape-string-regexp": "4.0.0", - "find-up": "5.0.0", - "glob": "7.2.0", - "he": "1.2.0", - "js-yaml": "4.1.0", - "log-symbols": "4.1.0", - "minimatch": "5.0.1", - "ms": "2.1.3", - "nanoid": "3.3.3", - "serialize-javascript": "6.0.0", - "strip-json-comments": "3.1.1", - "supports-color": "8.1.1", - "workerpool": "6.2.1", - "yargs": "16.2.0", - "yargs-parser": "20.2.4", - "yargs-unparser": "2.0.0" - }, - "bin": { - "_mocha": "bin/_mocha", - "mocha": "bin/mocha.js" - }, - "engines": { - "node": ">= 14.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/mochajs" - } - }, - "node_modules/mocha/node_modules/cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", - "dev": true, - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" - } - }, - "node_modules/mocha/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true - }, - "node_modules/mocha/node_modules/yargs": { - "version": "16.2.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", - "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", - "dev": true, - "dependencies": { - "cliui": "^7.0.2", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.0", - "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, - "node_modules/nanoid": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.3.tgz", - "integrity": "sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==", - "dev": true, - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, - "node_modules/natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true - }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-inspect": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", - "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "dev": true, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/object.assign": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz", - "integrity": "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "has-symbols": "^1.0.3", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object.entries": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.7.tgz", - "integrity": "sha512-jCBs/0plmPsOnrKAfFQXRG2NFjlhZgjjcBLSmTnEhU8U6vVTsVe8ANeQJCHTl3gSsI4J+0emOoCgoKlmQPMgmA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/object.fromentries": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.7.tgz", - "integrity": "sha512-UPbPHML6sL8PI/mOqPwsH4G6iyXcCGzLin8KvEPenOZN5lpCNBZZQ+V62vdjB1mQHrmqGQt5/OJzemUA+KJmEA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object.groupby": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.1.tgz", - "integrity": "sha512-HqaQtqLnp/8Bn4GL16cj+CUYbnpe1bh0TtEaWvybszDG4tgxCJuRpV8VGuvNaI1fAnI4lUJzDG55MXcOH4JZcQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "get-intrinsic": "^1.2.1" - } - }, - "node_modules/object.hasown": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/object.hasown/-/object.hasown-1.1.3.tgz", - "integrity": "sha512-fFI4VcYpRHvSLXxP7yiZOMAd331cPfd2p7PFDVbgUsYOfCT3tICVqXWngbjr4m49OvsBwUBQ6O2uQoJvy3RexA==", - "dev": true, - "dependencies": { - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object.values": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.7.tgz", - "integrity": "sha512-aU6xnDFYT3x17e/f0IiiwlGPTy2jzMySGfUB4fq6z7CV8l85CWHDk5ErhyhpfDHhrOMwGFhSQkhMGHaIotA6Ng==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dev": true, - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/optionator": { - "version": "0.9.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", - "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", - "dev": true, - "dependencies": { - "@aashutoshrathi/word-wrap": "^1.2.3", - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, - "dependencies": { - "p-limit": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, - "dependencies": { - "callsites": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/parse-json": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", - "integrity": "sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==", - "dev": true, - "dependencies": { - "error-ex": "^1.3.1", - "json-parse-better-errors": "^1.0.1" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true - }, - "node_modules/pathval": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", - "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/pify": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", - "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/pkg-conf": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/pkg-conf/-/pkg-conf-3.1.0.tgz", - "integrity": "sha512-m0OTbR/5VPNPqO1ph6Fqbj7Hv6QU7gR/tQW40ZqrL1rjgCU85W6C1bJn0BItuJqnR98PWzw7Z8hHeChD1WrgdQ==", - "dev": true, - "dependencies": { - "find-up": "^3.0.0", - "load-json-file": "^5.2.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/pkg-conf/node_modules/find-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", - "dev": true, - "dependencies": { - "locate-path": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/pkg-conf/node_modules/locate-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", - "dev": true, - "dependencies": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/pkg-conf/node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/pkg-conf/node_modules/p-locate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", - "dev": true, - "dependencies": { - "p-limit": "^2.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/pkg-conf/node_modules/path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/prop-types": { - "version": "15.8.1", - "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", - "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", - "dev": true, - "dependencies": { - "loose-envify": "^1.4.0", - "object-assign": "^4.1.1", - "react-is": "^16.13.1" - } - }, - "node_modules/protobufjs": { - "version": "7.2.5", - "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.2.5.tgz", - "integrity": "sha512-gGXRSXvxQ7UiPgfw8gevrfRWcTlSbOFg+p/N+JVJEK5VhueL2miT6qTymqAmjr1Q5WbOCyJbyrk6JfWKwlFn6A==", - "hasInstallScript": true, - "dependencies": { - "@protobufjs/aspromise": "^1.1.2", - "@protobufjs/base64": "^1.1.2", - "@protobufjs/codegen": "^2.0.4", - "@protobufjs/eventemitter": "^1.1.0", - "@protobufjs/fetch": "^1.1.0", - "@protobufjs/float": "^1.0.2", - "@protobufjs/inquire": "^1.1.0", - "@protobufjs/path": "^1.1.2", - "@protobufjs/pool": "^1.1.0", - "@protobufjs/utf8": "^1.1.0", - "@types/node": ">=13.7.0", - "long": "^5.0.0" - }, - "engines": { - "node": ">=12.0.0" - } - }, - "node_modules/punycode": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", - "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "dev": true, - "dependencies": { - "safe-buffer": "^5.1.0" - } - }, - "node_modules/react-is": { - "version": "16.13.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", - "dev": true - }, - "node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "dev": true, - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dev": true, - "dependencies": { - "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=8.10.0" - } - }, - "node_modules/reflect.getprototypeof": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.4.tgz", - "integrity": "sha512-ECkTw8TmJwW60lOTR+ZkODISW6RQ8+2CL3COqtiJKLd6MmB45hN51HprHFziKLGkAuTGQhBb91V8cy+KHlaCjw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "get-intrinsic": "^1.2.1", - "globalthis": "^1.0.3", - "which-builtin-type": "^1.1.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/regexp.prototype.flags": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.1.tgz", - "integrity": "sha512-sy6TXMN+hnP/wMy+ISxg3krXx7BAtWVO4UouuCN/ziM9UEne0euamVNafDfvC83bRNr95y0V5iijeDQFUNpvrg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "set-function-name": "^2.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/regexpp": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", - "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" - } - }, - "node_modules/require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/resolve": { - "version": "1.22.8", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", - "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", - "dev": true, - "dependencies": { - "is-core-module": "^2.13.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "dev": true, - "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" - } - }, - "node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "queue-microtask": "^1.2.2" - } - }, - "node_modules/safe-array-concat": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.0.1.tgz", - "integrity": "sha512-6XbUAseYE2KtOuGueyeobCySj9L4+66Tn6KQMOPQJrAJEowYKW/YR/MGJZl7FdydUdaFu4LYyDZjxf4/Nmo23Q==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.2.1", - "has-symbols": "^1.0.3", - "isarray": "^2.0.5" - }, - "engines": { - "node": ">=0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/safe-regex-test": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz", - "integrity": "sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.3", - "is-regex": "^1.1.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/serialize-javascript": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", - "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", - "dev": true, - "dependencies": { - "randombytes": "^2.1.0" - } - }, - "node_modules/set-function-length": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.1.1.tgz", - "integrity": "sha512-VoaqjbBJKiWtg4yRcKBQ7g7wnGnLV3M8oLvVWwOk2PdYY6PEFegR1vezXR0tw6fZGF9csVakIRjrJiy2veSBFQ==", - "dev": true, - "dependencies": { - "define-data-property": "^1.1.1", - "get-intrinsic": "^1.2.1", - "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/set-function-name": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.1.tgz", - "integrity": "sha512-tMNCiqYVkXIZgc2Hnoy2IvC/f8ezc5koaRFkCjrpWzGpCd3qbZXPzVy9MAZzK1ch/X0jvSkojys3oqJN0qCmdA==", - "dev": true, - "dependencies": { - "define-data-property": "^1.0.1", - "functions-have-names": "^1.2.3", - "has-property-descriptors": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/side-channel": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/snazzy": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/snazzy/-/snazzy-9.0.0.tgz", - "integrity": "sha512-8QZmJb11OiYaUP90Nnjqcj/LEpO8CLgChnP87Wqjv5tNB4djwHaz27VO2usSRR0NmViapeGW04p0aWAMhxxLXg==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "chalk": "^4.1.0", - "inherits": "^2.0.4", - "minimist": "^1.2.5", - "readable-stream": "^3.6.0", - "standard-json": "^1.1.0", - "strip-ansi": "^6.0.0", - "text-table": "^0.2.0" - }, - "bin": { - "snazzy": "bin/cmd.js" - } - }, - "node_modules/standard": { - "version": "17.1.0", - "resolved": "https://registry.npmjs.org/standard/-/standard-17.1.0.tgz", - "integrity": "sha512-jaDqlNSzLtWYW4lvQmU0EnxWMUGQiwHasZl5ZEIwx3S/ijZDjZOzs1y1QqKwKs5vqnFpGtizo4NOYX2s0Voq/g==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "eslint": "^8.41.0", - "eslint-config-standard": "17.1.0", - "eslint-config-standard-jsx": "^11.0.0", - "eslint-plugin-import": "^2.27.5", - "eslint-plugin-n": "^15.7.0", - "eslint-plugin-promise": "^6.1.1", - "eslint-plugin-react": "^7.32.2", - "standard-engine": "^15.0.0", - "version-guard": "^1.1.1" - }, - "bin": { - "standard": "bin/cmd.cjs" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, - "node_modules/standard-engine": { - "version": "15.1.0", - "resolved": "https://registry.npmjs.org/standard-engine/-/standard-engine-15.1.0.tgz", - "integrity": "sha512-VHysfoyxFu/ukT+9v49d4BRXIokFRZuH3z1VRxzFArZdjSCFpro6rEIU3ji7e4AoAtuSfKBkiOmsrDqKW5ZSRw==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "get-stdin": "^8.0.0", - "minimist": "^1.2.6", - "pkg-conf": "^3.1.0", - "xdg-basedir": "^4.0.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, - "node_modules/standard-json": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/standard-json/-/standard-json-1.1.0.tgz", - "integrity": "sha512-nkonX+n5g3pyVBvJZmvRlFtT/7JyLbNh4CtrYC3Qfxihgs8PKX52f6ONKQXORStuBWJ5PI83EUrNXme7LKfiTQ==", - "dev": true, - "dependencies": { - "concat-stream": "^2.0.0" - }, - "bin": { - "standard-json": "bin.js" - } - }, - "node_modules/string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "dev": true, - "dependencies": { - "safe-buffer": "~5.2.0" - } - }, - "node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/string.prototype.matchall": { - "version": "4.0.10", - "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.10.tgz", - "integrity": "sha512-rGXbGmOEosIQi6Qva94HUjgPs9vKW+dkG7Y8Q5O2OYkWL6wFaTRZO8zM4mhP94uX55wgyrXzfS2aGtGzUL7EJQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "get-intrinsic": "^1.2.1", - "has-symbols": "^1.0.3", - "internal-slot": "^1.0.5", - "regexp.prototype.flags": "^1.5.0", - "set-function-name": "^2.0.0", - "side-channel": "^1.0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/string.prototype.trim": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.8.tgz", - "integrity": "sha512-lfjY4HcixfQXOfaqCvcBuOIapyaroTXhbkfJN3gcB1OtyupngWK4sEET9Knd0cXd28kTUqu/kHoV4HKSJdnjiQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/string.prototype.trimend": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.7.tgz", - "integrity": "sha512-Ni79DqeB72ZFq1uH/L6zJ+DKZTkOtPIHovb3YZHQViE+HDouuU4mBrLOLDn5Dde3RF8qw5qVETEjhu9locMLvA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/string.prototype.trimstart": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.7.tgz", - "integrity": "sha512-NGhtDFu3jCEm7B4Fy0DpLewdJQOZcQ0rGbwQ/+stjnrp2i+rlKeCvos9hOIeCmqwratM47OBxY7uFZzjxHXmrg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, - "node_modules/supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", - "dev": true - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/tsconfig-paths": { - "version": "3.14.2", - "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.2.tgz", - "integrity": "sha512-o/9iXgCYc5L/JxCHPe3Hvh8Q/2xm5Z+p18PESBU6Ff33695QnCHBEjcytY2q19ua7Mbl/DavtBOLq+oG0RCL+g==", - "dev": true, - "dependencies": { - "@types/json5": "^0.0.29", - "json5": "^1.0.2", - "minimist": "^1.2.6", - "strip-bom": "^3.0.0" - } - }, - "node_modules/type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", - "dev": true, - "dependencies": { - "prelude-ls": "^1.2.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/type-detect": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", - "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/typed-array-buffer": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.0.tgz", - "integrity": "sha512-Y8KTSIglk9OZEr8zywiIHG/kmQ7KWyjseXs1CbSo8vC42w7hg2HgYTxSWwP0+is7bWDc1H+Fo026CpHFwm8tkw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.2.1", - "is-typed-array": "^1.1.10" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/typed-array-byte-length": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.0.tgz", - "integrity": "sha512-Or/+kvLxNpeQ9DtSydonMxCx+9ZXOswtwJn17SNLvhptaXYDJvkFFP5zbfU/uLmvnBJlI4yrnXRxpdWH/M5tNA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "for-each": "^0.3.3", - "has-proto": "^1.0.1", - "is-typed-array": "^1.1.10" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/typed-array-byte-offset": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.0.tgz", - "integrity": "sha512-RD97prjEt9EL8YgAgpOkf3O4IF9lhJFr9g0htQkm0rchFp/Vx7LW5Q8fSXXub7BXAODyUQohRMyOc3faCPd0hg==", - "dev": true, - "dependencies": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "for-each": "^0.3.3", - "has-proto": "^1.0.1", - "is-typed-array": "^1.1.10" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/typed-array-length": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.4.tgz", - "integrity": "sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "for-each": "^0.3.3", - "is-typed-array": "^1.1.9" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/typedarray": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", - "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==", - "dev": true - }, - "node_modules/typescript": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.2.tgz", - "integrity": "sha512-6l+RyNy7oAHDfxC4FzSJcz9vnjTKxrLpDG5M2Vu4SHRVNg6xzqZp6LYSR9zjqQTu8DU/f5xwxUdADOkbrIX2gQ==", - "dev": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, - "node_modules/unbox-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", - "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "has-bigints": "^1.0.2", - "has-symbols": "^1.0.3", - "which-boxed-primitive": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/undici-types": { - "version": "5.26.5", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", - "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==" - }, - "node_modules/uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, - "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "dev": true - }, - "node_modules/version-guard": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/version-guard/-/version-guard-1.1.1.tgz", - "integrity": "sha512-MGQLX89UxmYHgDvcXyjBI0cbmoW+t/dANDppNPrno64rYr8nH4SHSuElQuSYdXGEs0mUzdQe1BY+FhVPNsAmJQ==", - "dev": true, - "engines": { - "node": ">=0.10.48" - } - }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/which-boxed-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", - "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", - "dev": true, - "dependencies": { - "is-bigint": "^1.0.1", - "is-boolean-object": "^1.1.0", - "is-number-object": "^1.0.4", - "is-string": "^1.0.5", - "is-symbol": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/which-builtin-type": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.1.3.tgz", - "integrity": "sha512-YmjsSMDBYsM1CaFiayOVT06+KJeXf0o5M/CAd4o1lTadFAtacTUM49zoYxr/oroopFDfhvN6iEcBxUyc3gvKmw==", - "dev": true, - "dependencies": { - "function.prototype.name": "^1.1.5", - "has-tostringtag": "^1.0.0", - "is-async-function": "^2.0.0", - "is-date-object": "^1.0.5", - "is-finalizationregistry": "^1.0.2", - "is-generator-function": "^1.0.10", - "is-regex": "^1.1.4", - "is-weakref": "^1.0.2", - "isarray": "^2.0.5", - "which-boxed-primitive": "^1.0.2", - "which-collection": "^1.0.1", - "which-typed-array": "^1.1.9" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/which-collection": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.1.tgz", - "integrity": "sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A==", - "dev": true, - "dependencies": { - "is-map": "^2.0.1", - "is-set": "^2.0.1", - "is-weakmap": "^2.0.1", - "is-weakset": "^2.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/which-typed-array": { - "version": "1.1.13", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.13.tgz", - "integrity": "sha512-P5Nra0qjSncduVPEAr7xhoF5guty49ArDTwzJ/yNuPIbZppyRxFQsRCWrocxIY+CnMVG+qfbU2FmDKyvSGClow==", - "dev": true, - "dependencies": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.4", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/workerpool": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz", - "integrity": "sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==", - "dev": true - }, - "node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true - }, - "node_modules/xdg-basedir": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-4.0.0.tgz", - "integrity": "sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "engines": { - "node": ">=10" - } - }, - "node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "node_modules/yargs": { - "version": "17.7.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", - "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", - "dependencies": { - "cliui": "^8.0.1", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.3", - "y18n": "^5.0.5", - "yargs-parser": "^21.1.1" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/yargs-parser": { - "version": "20.2.4", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", - "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/yargs-unparser": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", - "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", - "dev": true, - "dependencies": { - "camelcase": "^6.0.0", - "decamelize": "^4.0.0", - "flat": "^5.0.2", - "is-plain-obj": "^2.1.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/yargs/node_modules/yargs-parser": { - "version": "21.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", - "engines": { - "node": ">=12" - } - }, - "node_modules/yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - } - } -} diff --git a/package.json b/package.json index 043c042..884be24 100644 --- a/package.json +++ b/package.json @@ -22,15 +22,21 @@ }, "main": "./types/index.js", "typings": "./types/index.d.ts", + "engines": { + "node": ">=16" + }, "scripts": { "test": "mocha --exit --extension .test.js --recursive test", - "build": "rm -rf types && tsc -P tsconfig.json" + "build": "rm -rf types && tsc -P tsconfig.json", + "lint:prettier": "prettier --cache --check --ignore-path .gitignore --ignore-path .prettierignore .", + "prettier": "pnpm lint:prettier --write", + "prepare": "husky install" }, - "engines": { - "node": ">=16" + "lint-staged": { + "*.{ts,js,md,json,yaml}": "prettier --write" }, "dependencies": { - "@grpc/grpc-js": "^1.9.11", + "@grpc/grpc-js": "^1.9.12", "@grpc/proto-loader": "^0.7.10", "debug": "^4.3.4", "joi": "^17.11.0", @@ -40,9 +46,12 @@ "devDependencies": { "@tsconfig/node14": "^14.1.0", "@types/lodash": "^4.14.202", - "@types/node": "^20.9.5", + "@types/node": "^20.10.2", "chai": "^4.3.10", + "husky": "^8.0.3", + "lint-staged": "^15.1.0", "mocha": "^10.2.0", + "prettier": "3.1.0", "snazzy": "^9.0.0", "typescript": "^5.3.2" } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml new file mode 100644 index 0000000..495b1b7 --- /dev/null +++ b/pnpm-lock.yaml @@ -0,0 +1,1681 @@ +lockfileVersion: '6.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +dependencies: + '@grpc/grpc-js': + specifier: ^1.9.12 + version: 1.9.12 + '@grpc/proto-loader': + specifier: ^0.7.10 + version: 0.7.10 + debug: + specifier: ^4.3.4 + version: 4.3.4(supports-color@8.1.1) + joi: + specifier: ^17.11.0 + version: 17.11.0 + lodash: + specifier: ^4.17.21 + version: 4.17.21 + protobufjs: + specifier: ^7.2.5 + version: 7.2.5 + +devDependencies: + '@tsconfig/node14': + specifier: ^14.1.0 + version: 14.1.0 + '@types/lodash': + specifier: ^4.14.202 + version: 4.14.202 + '@types/node': + specifier: ^20.10.2 + version: 20.10.2 + chai: + specifier: ^4.3.10 + version: 4.3.10 + husky: + specifier: ^8.0.3 + version: 8.0.3 + lint-staged: + specifier: ^15.1.0 + version: 15.1.0 + mocha: + specifier: ^10.2.0 + version: 10.2.0 + prettier: + specifier: 3.1.0 + version: 3.1.0 + snazzy: + specifier: ^9.0.0 + version: 9.0.0 + typescript: + specifier: ^5.3.2 + version: 5.3.2 + +packages: + /@grpc/grpc-js@1.9.12: + resolution: + { + integrity: sha512-Um5MBuge32TS3lAKX02PGCnFM4xPT996yLgZNb5H03pn6NyJ4Iwn5YcPq6Jj9yxGRk7WOgaZFtVRH5iTdYBeUg== + } + engines: { node: ^8.13.0 || >=10.10.0 } + dependencies: + '@grpc/proto-loader': 0.7.10 + '@types/node': 20.10.2 + dev: false + + /@grpc/proto-loader@0.7.10: + resolution: + { + integrity: sha512-CAqDfoaQ8ykFd9zqBDn4k6iWT9loLAlc2ETmDFS9JCD70gDcnA4L3AFEo2iV7KyAtAAHFW9ftq1Fz+Vsgq80RQ== + } + engines: { node: '>=6' } + hasBin: true + dependencies: + lodash.camelcase: 4.3.0 + long: 5.2.3 + protobufjs: 7.2.5 + yargs: 17.7.2 + dev: false + + /@hapi/hoek@9.3.0: + resolution: + { + integrity: sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ== + } + dev: false + + /@hapi/topo@5.1.0: + resolution: + { + integrity: sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg== + } + dependencies: + '@hapi/hoek': 9.3.0 + dev: false + + /@protobufjs/aspromise@1.1.2: + resolution: + { + integrity: sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ== + } + dev: false + + /@protobufjs/base64@1.1.2: + resolution: + { + integrity: sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg== + } + dev: false + + /@protobufjs/codegen@2.0.4: + resolution: + { + integrity: sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg== + } + dev: false + + /@protobufjs/eventemitter@1.1.0: + resolution: + { + integrity: sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q== + } + dev: false + + /@protobufjs/fetch@1.1.0: + resolution: + { + integrity: sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ== + } + dependencies: + '@protobufjs/aspromise': 1.1.2 + '@protobufjs/inquire': 1.1.0 + dev: false + + /@protobufjs/float@1.0.2: + resolution: + { + integrity: sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ== + } + dev: false + + /@protobufjs/inquire@1.1.0: + resolution: + { + integrity: sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q== + } + dev: false + + /@protobufjs/path@1.1.2: + resolution: + { + integrity: sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA== + } + dev: false + + /@protobufjs/pool@1.1.0: + resolution: + { + integrity: sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw== + } + dev: false + + /@protobufjs/utf8@1.1.0: + resolution: + { + integrity: sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw== + } + dev: false + + /@sideway/address@4.1.4: + resolution: + { + integrity: sha512-7vwq+rOHVWjyXxVlR76Agnvhy8I9rpzjosTESvmhNeXOXdZZB15Fl+TI9x1SiHZH5Jv2wTGduSxFDIaq0m3DUw== + } + dependencies: + '@hapi/hoek': 9.3.0 + dev: false + + /@sideway/formula@3.0.1: + resolution: + { + integrity: sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg== + } + dev: false + + /@sideway/pinpoint@2.0.0: + resolution: + { + integrity: sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ== + } + dev: false + + /@tsconfig/node14@14.1.0: + resolution: + { + integrity: sha512-VmsCG04YR58ciHBeJKBDNMWWfYbyP8FekWVuTlpstaUPlat1D0x/tXzkWP7yCMU0eSz9V4OZU0LBWTFJ3xZf6w== + } + dev: true + + /@types/lodash@4.14.202: + resolution: + { + integrity: sha512-OvlIYQK9tNneDlS0VN54LLd5uiPCBOp7gS5Z0f1mjoJYBrtStzgmJBxONW3U6OZqdtNzZPmn9BS/7WI7BFFcFQ== + } + dev: true + + /@types/node@20.10.2: + resolution: + { + integrity: sha512-37MXfxkb0vuIlRKHNxwCkb60PNBpR94u4efQuN4JgIAm66zfCDXGSAFCef9XUWFovX2R1ok6Z7MHhtdVXXkkIw== + } + dependencies: + undici-types: 5.26.5 + + /ansi-colors@4.1.1: + resolution: + { + integrity: sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA== + } + engines: { node: '>=6' } + dev: true + + /ansi-escapes@5.0.0: + resolution: + { + integrity: sha512-5GFMVX8HqE/TB+FuBJGuO5XG0WrsA6ptUqoODaT/n9mmUaZFkqnBueB4leqGBCmrUHnCnC4PCZTCd0E7QQ83bA== + } + engines: { node: '>=12' } + dependencies: + type-fest: 1.4.0 + dev: true + + /ansi-regex@5.0.1: + resolution: + { + integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== + } + engines: { node: '>=8' } + + /ansi-regex@6.0.1: + resolution: + { + integrity: sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA== + } + engines: { node: '>=12' } + dev: true + + /ansi-styles@4.3.0: + resolution: + { + integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== + } + engines: { node: '>=8' } + dependencies: + color-convert: 2.0.1 + + /ansi-styles@6.2.1: + resolution: + { + integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug== + } + engines: { node: '>=12' } + dev: true + + /anymatch@3.1.3: + resolution: + { + integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw== + } + engines: { node: '>= 8' } + dependencies: + normalize-path: 3.0.0 + picomatch: 2.3.1 + dev: true + + /argparse@2.0.1: + resolution: + { + integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== + } + dev: true + + /assertion-error@1.1.0: + resolution: + { + integrity: sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw== + } + dev: true + + /balanced-match@1.0.2: + resolution: + { + integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== + } + dev: true + + /binary-extensions@2.2.0: + resolution: + { + integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA== + } + engines: { node: '>=8' } + dev: true + + /brace-expansion@1.1.11: + resolution: + { + integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== + } + dependencies: + balanced-match: 1.0.2 + concat-map: 0.0.1 + dev: true + + /brace-expansion@2.0.1: + resolution: + { + integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA== + } + dependencies: + balanced-match: 1.0.2 + dev: true + + /braces@3.0.2: + resolution: + { + integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== + } + engines: { node: '>=8' } + dependencies: + fill-range: 7.0.1 + dev: true + + /browser-stdout@1.3.1: + resolution: + { + integrity: sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw== + } + dev: true + + /buffer-from@1.1.2: + resolution: + { + integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== + } + dev: true + + /camelcase@6.3.0: + resolution: + { + integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== + } + engines: { node: '>=10' } + dev: true + + /chai@4.3.10: + resolution: + { + integrity: sha512-0UXG04VuVbruMUYbJ6JctvH0YnC/4q3/AkT18q4NaITo91CUm0liMS9VqzT9vZhVQ/1eqPanMWjBM+Juhfb/9g== + } + engines: { node: '>=4' } + dependencies: + assertion-error: 1.1.0 + check-error: 1.0.3 + deep-eql: 4.1.3 + get-func-name: 2.0.2 + loupe: 2.3.7 + pathval: 1.1.1 + type-detect: 4.0.8 + dev: true + + /chalk@4.1.2: + resolution: + { + integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== + } + engines: { node: '>=10' } + dependencies: + ansi-styles: 4.3.0 + supports-color: 7.2.0 + dev: true + + /chalk@5.3.0: + resolution: + { + integrity: sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w== + } + engines: { node: ^12.17.0 || ^14.13 || >=16.0.0 } + dev: true + + /check-error@1.0.3: + resolution: + { + integrity: sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg== + } + dependencies: + get-func-name: 2.0.2 + dev: true + + /chokidar@3.5.3: + resolution: + { + integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw== + } + engines: { node: '>= 8.10.0' } + dependencies: + anymatch: 3.1.3 + braces: 3.0.2 + glob-parent: 5.1.2 + is-binary-path: 2.1.0 + is-glob: 4.0.3 + normalize-path: 3.0.0 + readdirp: 3.6.0 + optionalDependencies: + fsevents: 2.3.3 + dev: true + + /cli-cursor@4.0.0: + resolution: + { + integrity: sha512-VGtlMu3x/4DOtIUwEkRezxUZ2lBacNJCHash0N0WeZDBS+7Ux1dm3XWAgWYxLJFMMdOeXMHXorshEFhbMSGelg== + } + engines: { node: ^12.20.0 || ^14.13.1 || >=16.0.0 } + dependencies: + restore-cursor: 4.0.0 + dev: true + + /cli-truncate@3.1.0: + resolution: + { + integrity: sha512-wfOBkjXteqSnI59oPcJkcPl/ZmwvMMOj340qUIY1SKZCv0B9Cf4D4fAucRkIKQmsIuYK3x1rrgU7MeGRruiuiA== + } + engines: { node: ^12.20.0 || ^14.13.1 || >=16.0.0 } + dependencies: + slice-ansi: 5.0.0 + string-width: 5.1.2 + dev: true + + /cliui@7.0.4: + resolution: + { + integrity: sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ== + } + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 7.0.0 + dev: true + + /cliui@8.0.1: + resolution: + { + integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ== + } + engines: { node: '>=12' } + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 7.0.0 + dev: false + + /color-convert@2.0.1: + resolution: + { + integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== + } + engines: { node: '>=7.0.0' } + dependencies: + color-name: 1.1.4 + + /color-name@1.1.4: + resolution: + { + integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + } + + /colorette@2.0.20: + resolution: + { + integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w== + } + dev: true + + /commander@11.1.0: + resolution: + { + integrity: sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ== + } + engines: { node: '>=16' } + dev: true + + /concat-map@0.0.1: + resolution: + { + integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== + } + dev: true + + /concat-stream@2.0.0: + resolution: + { + integrity: sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A== + } + engines: { '0': node >= 6.0 } + dependencies: + buffer-from: 1.1.2 + inherits: 2.0.4 + readable-stream: 3.6.2 + typedarray: 0.0.6 + dev: true + + /cross-spawn@7.0.3: + resolution: + { + integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== + } + engines: { node: '>= 8' } + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 + dev: true + + /debug@4.3.4(supports-color@8.1.1): + resolution: + { + integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== + } + engines: { node: '>=6.0' } + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + dependencies: + ms: 2.1.2 + supports-color: 8.1.1 + + /decamelize@4.0.0: + resolution: + { + integrity: sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ== + } + engines: { node: '>=10' } + dev: true + + /deep-eql@4.1.3: + resolution: + { + integrity: sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw== + } + engines: { node: '>=6' } + dependencies: + type-detect: 4.0.8 + dev: true + + /diff@5.0.0: + resolution: + { + integrity: sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w== + } + engines: { node: '>=0.3.1' } + dev: true + + /eastasianwidth@0.2.0: + resolution: + { + integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA== + } + dev: true + + /emoji-regex@8.0.0: + resolution: + { + integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== + } + + /emoji-regex@9.2.2: + resolution: + { + integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg== + } + dev: true + + /escalade@3.1.1: + resolution: + { + integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== + } + engines: { node: '>=6' } + + /escape-string-regexp@4.0.0: + resolution: + { + integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== + } + engines: { node: '>=10' } + dev: true + + /eventemitter3@5.0.1: + resolution: + { + integrity: sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA== + } + dev: true + + /execa@8.0.1: + resolution: + { + integrity: sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg== + } + engines: { node: '>=16.17' } + dependencies: + cross-spawn: 7.0.3 + get-stream: 8.0.1 + human-signals: 5.0.0 + is-stream: 3.0.0 + merge-stream: 2.0.0 + npm-run-path: 5.1.0 + onetime: 6.0.0 + signal-exit: 4.1.0 + strip-final-newline: 3.0.0 + dev: true + + /fill-range@7.0.1: + resolution: + { + integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== + } + engines: { node: '>=8' } + dependencies: + to-regex-range: 5.0.1 + dev: true + + /find-up@5.0.0: + resolution: + { + integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng== + } + engines: { node: '>=10' } + dependencies: + locate-path: 6.0.0 + path-exists: 4.0.0 + dev: true + + /flat@5.0.2: + resolution: + { + integrity: sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ== + } + hasBin: true + dev: true + + /fs.realpath@1.0.0: + resolution: + { + integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== + } + dev: true + + /fsevents@2.3.3: + resolution: + { + integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== + } + engines: { node: ^8.16.0 || ^10.6.0 || >=11.0.0 } + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /get-caller-file@2.0.5: + resolution: + { + integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== + } + engines: { node: 6.* || 8.* || >= 10.* } + + /get-func-name@2.0.2: + resolution: + { + integrity: sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ== + } + dev: true + + /get-stream@8.0.1: + resolution: + { + integrity: sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA== + } + engines: { node: '>=16' } + dev: true + + /glob-parent@5.1.2: + resolution: + { + integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== + } + engines: { node: '>= 6' } + dependencies: + is-glob: 4.0.3 + dev: true + + /glob@7.2.0: + resolution: + { + integrity: sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q== + } + dependencies: + fs.realpath: 1.0.0 + inflight: 1.0.6 + inherits: 2.0.4 + minimatch: 3.1.2 + once: 1.4.0 + path-is-absolute: 1.0.1 + dev: true + + /has-flag@4.0.0: + resolution: + { + integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== + } + engines: { node: '>=8' } + + /he@1.2.0: + resolution: + { + integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== + } + hasBin: true + dev: true + + /human-signals@5.0.0: + resolution: + { + integrity: sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ== + } + engines: { node: '>=16.17.0' } + dev: true + + /husky@8.0.3: + resolution: + { + integrity: sha512-+dQSyqPh4x1hlO1swXBiNb2HzTDN1I2IGLQx1GrBuiqFJfoMrnZWwVmatvSiO+Iz8fBUnf+lekwNo4c2LlXItg== + } + engines: { node: '>=14' } + hasBin: true + dev: true + + /inflight@1.0.6: + resolution: + { + integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== + } + dependencies: + once: 1.4.0 + wrappy: 1.0.2 + dev: true + + /inherits@2.0.4: + resolution: + { + integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + } + dev: true + + /is-binary-path@2.1.0: + resolution: + { + integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== + } + engines: { node: '>=8' } + dependencies: + binary-extensions: 2.2.0 + dev: true + + /is-extglob@2.1.1: + resolution: + { + integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== + } + engines: { node: '>=0.10.0' } + dev: true + + /is-fullwidth-code-point@3.0.0: + resolution: + { + integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== + } + engines: { node: '>=8' } + + /is-fullwidth-code-point@4.0.0: + resolution: + { + integrity: sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ== + } + engines: { node: '>=12' } + dev: true + + /is-glob@4.0.3: + resolution: + { + integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== + } + engines: { node: '>=0.10.0' } + dependencies: + is-extglob: 2.1.1 + dev: true + + /is-number@7.0.0: + resolution: + { + integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== + } + engines: { node: '>=0.12.0' } + dev: true + + /is-plain-obj@2.1.0: + resolution: + { + integrity: sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA== + } + engines: { node: '>=8' } + dev: true + + /is-stream@3.0.0: + resolution: + { + integrity: sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA== + } + engines: { node: ^12.20.0 || ^14.13.1 || >=16.0.0 } + dev: true + + /is-unicode-supported@0.1.0: + resolution: + { + integrity: sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw== + } + engines: { node: '>=10' } + dev: true + + /isexe@2.0.0: + resolution: + { + integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== + } + dev: true + + /joi@17.11.0: + resolution: + { + integrity: sha512-NgB+lZLNoqISVy1rZocE9PZI36bL/77ie924Ri43yEvi9GUUMPeyVIr8KdFTMUlby1p0PBYMk9spIxEUQYqrJQ== + } + dependencies: + '@hapi/hoek': 9.3.0 + '@hapi/topo': 5.1.0 + '@sideway/address': 4.1.4 + '@sideway/formula': 3.0.1 + '@sideway/pinpoint': 2.0.0 + dev: false + + /js-yaml@4.1.0: + resolution: + { + integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== + } + hasBin: true + dependencies: + argparse: 2.0.1 + dev: true + + /lilconfig@2.1.0: + resolution: + { + integrity: sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ== + } + engines: { node: '>=10' } + dev: true + + /lint-staged@15.1.0: + resolution: + { + integrity: sha512-ZPKXWHVlL7uwVpy8OZ7YQjYDAuO5X4kMh0XgZvPNxLcCCngd0PO5jKQyy3+s4TL2EnHoIXIzP1422f/l3nZKMw== + } + engines: { node: '>=18.12.0' } + hasBin: true + dependencies: + chalk: 5.3.0 + commander: 11.1.0 + debug: 4.3.4(supports-color@8.1.1) + execa: 8.0.1 + lilconfig: 2.1.0 + listr2: 7.0.2 + micromatch: 4.0.5 + pidtree: 0.6.0 + string-argv: 0.3.2 + yaml: 2.3.4 + transitivePeerDependencies: + - supports-color + dev: true + + /listr2@7.0.2: + resolution: + { + integrity: sha512-rJysbR9GKIalhTbVL2tYbF2hVyDnrf7pFUZBwjPaMIdadYHmeT+EVi/Bu3qd7ETQPahTotg2WRCatXwRBW554g== + } + engines: { node: '>=16.0.0' } + dependencies: + cli-truncate: 3.1.0 + colorette: 2.0.20 + eventemitter3: 5.0.1 + log-update: 5.0.1 + rfdc: 1.3.0 + wrap-ansi: 8.1.0 + dev: true + + /locate-path@6.0.0: + resolution: + { + integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw== + } + engines: { node: '>=10' } + dependencies: + p-locate: 5.0.0 + dev: true + + /lodash.camelcase@4.3.0: + resolution: + { + integrity: sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA== + } + dev: false + + /lodash@4.17.21: + resolution: + { + integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== + } + dev: false + + /log-symbols@4.1.0: + resolution: + { + integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg== + } + engines: { node: '>=10' } + dependencies: + chalk: 4.1.2 + is-unicode-supported: 0.1.0 + dev: true + + /log-update@5.0.1: + resolution: + { + integrity: sha512-5UtUDQ/6edw4ofyljDNcOVJQ4c7OjDro4h3y8e1GQL5iYElYclVHJ3zeWchylvMaKnDbDilC8irOVyexnA/Slw== + } + engines: { node: ^12.20.0 || ^14.13.1 || >=16.0.0 } + dependencies: + ansi-escapes: 5.0.0 + cli-cursor: 4.0.0 + slice-ansi: 5.0.0 + strip-ansi: 7.1.0 + wrap-ansi: 8.1.0 + dev: true + + /long@5.2.3: + resolution: + { + integrity: sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q== + } + dev: false + + /loupe@2.3.7: + resolution: + { + integrity: sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA== + } + dependencies: + get-func-name: 2.0.2 + dev: true + + /merge-stream@2.0.0: + resolution: + { + integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== + } + dev: true + + /micromatch@4.0.5: + resolution: + { + integrity: sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA== + } + engines: { node: '>=8.6' } + dependencies: + braces: 3.0.2 + picomatch: 2.3.1 + dev: true + + /mimic-fn@2.1.0: + resolution: + { + integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== + } + engines: { node: '>=6' } + dev: true + + /mimic-fn@4.0.0: + resolution: + { + integrity: sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw== + } + engines: { node: '>=12' } + dev: true + + /minimatch@3.1.2: + resolution: + { + integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== + } + dependencies: + brace-expansion: 1.1.11 + dev: true + + /minimatch@5.0.1: + resolution: + { + integrity: sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g== + } + engines: { node: '>=10' } + dependencies: + brace-expansion: 2.0.1 + dev: true + + /minimist@1.2.8: + resolution: + { + integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== + } + dev: true + + /mocha@10.2.0: + resolution: + { + integrity: sha512-IDY7fl/BecMwFHzoqF2sg/SHHANeBoMMXFlS9r0OXKDssYE1M5O43wUY/9BVPeIvfH2zmEbBfseqN9gBQZzXkg== + } + engines: { node: '>= 14.0.0' } + hasBin: true + dependencies: + ansi-colors: 4.1.1 + browser-stdout: 1.3.1 + chokidar: 3.5.3 + debug: 4.3.4(supports-color@8.1.1) + diff: 5.0.0 + escape-string-regexp: 4.0.0 + find-up: 5.0.0 + glob: 7.2.0 + he: 1.2.0 + js-yaml: 4.1.0 + log-symbols: 4.1.0 + minimatch: 5.0.1 + ms: 2.1.3 + nanoid: 3.3.3 + serialize-javascript: 6.0.0 + strip-json-comments: 3.1.1 + supports-color: 8.1.1 + workerpool: 6.2.1 + yargs: 16.2.0 + yargs-parser: 20.2.4 + yargs-unparser: 2.0.0 + dev: true + + /ms@2.1.2: + resolution: + { + integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== + } + + /ms@2.1.3: + resolution: + { + integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== + } + dev: true + + /nanoid@3.3.3: + resolution: + { + integrity: sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w== + } + engines: { node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1 } + hasBin: true + dev: true + + /normalize-path@3.0.0: + resolution: + { + integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== + } + engines: { node: '>=0.10.0' } + dev: true + + /npm-run-path@5.1.0: + resolution: + { + integrity: sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q== + } + engines: { node: ^12.20.0 || ^14.13.1 || >=16.0.0 } + dependencies: + path-key: 4.0.0 + dev: true + + /once@1.4.0: + resolution: + { + integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== + } + dependencies: + wrappy: 1.0.2 + dev: true + + /onetime@5.1.2: + resolution: + { + integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== + } + engines: { node: '>=6' } + dependencies: + mimic-fn: 2.1.0 + dev: true + + /onetime@6.0.0: + resolution: + { + integrity: sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ== + } + engines: { node: '>=12' } + dependencies: + mimic-fn: 4.0.0 + dev: true + + /p-limit@3.1.0: + resolution: + { + integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== + } + engines: { node: '>=10' } + dependencies: + yocto-queue: 0.1.0 + dev: true + + /p-locate@5.0.0: + resolution: + { + integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw== + } + engines: { node: '>=10' } + dependencies: + p-limit: 3.1.0 + dev: true + + /path-exists@4.0.0: + resolution: + { + integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== + } + engines: { node: '>=8' } + dev: true + + /path-is-absolute@1.0.1: + resolution: + { + integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== + } + engines: { node: '>=0.10.0' } + dev: true + + /path-key@3.1.1: + resolution: + { + integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== + } + engines: { node: '>=8' } + dev: true + + /path-key@4.0.0: + resolution: + { + integrity: sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ== + } + engines: { node: '>=12' } + dev: true + + /pathval@1.1.1: + resolution: + { + integrity: sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ== + } + dev: true + + /picomatch@2.3.1: + resolution: + { + integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== + } + engines: { node: '>=8.6' } + dev: true + + /pidtree@0.6.0: + resolution: + { + integrity: sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g== + } + engines: { node: '>=0.10' } + hasBin: true + dev: true + + /prettier@3.1.0: + resolution: + { + integrity: sha512-TQLvXjq5IAibjh8EpBIkNKxO749UEWABoiIZehEPiY4GNpVdhaFKqSTu+QrlU6D2dPAfubRmtJTi4K4YkQ5eXw== + } + engines: { node: '>=14' } + hasBin: true + dev: true + + /protobufjs@7.2.5: + resolution: + { + integrity: sha512-gGXRSXvxQ7UiPgfw8gevrfRWcTlSbOFg+p/N+JVJEK5VhueL2miT6qTymqAmjr1Q5WbOCyJbyrk6JfWKwlFn6A== + } + engines: { node: '>=12.0.0' } + requiresBuild: true + dependencies: + '@protobufjs/aspromise': 1.1.2 + '@protobufjs/base64': 1.1.2 + '@protobufjs/codegen': 2.0.4 + '@protobufjs/eventemitter': 1.1.0 + '@protobufjs/fetch': 1.1.0 + '@protobufjs/float': 1.0.2 + '@protobufjs/inquire': 1.1.0 + '@protobufjs/path': 1.1.2 + '@protobufjs/pool': 1.1.0 + '@protobufjs/utf8': 1.1.0 + '@types/node': 20.10.2 + long: 5.2.3 + dev: false + + /randombytes@2.1.0: + resolution: + { + integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ== + } + dependencies: + safe-buffer: 5.2.1 + dev: true + + /readable-stream@3.6.2: + resolution: + { + integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA== + } + engines: { node: '>= 6' } + dependencies: + inherits: 2.0.4 + string_decoder: 1.3.0 + util-deprecate: 1.0.2 + dev: true + + /readdirp@3.6.0: + resolution: + { + integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA== + } + engines: { node: '>=8.10.0' } + dependencies: + picomatch: 2.3.1 + dev: true + + /require-directory@2.1.1: + resolution: + { + integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q== + } + engines: { node: '>=0.10.0' } + + /restore-cursor@4.0.0: + resolution: + { + integrity: sha512-I9fPXU9geO9bHOt9pHHOhOkYerIMsmVaWB0rA2AI9ERh/+x/i7MV5HKBNrg+ljO5eoPVgCcnFuRjJ9uH6I/3eg== + } + engines: { node: ^12.20.0 || ^14.13.1 || >=16.0.0 } + dependencies: + onetime: 5.1.2 + signal-exit: 3.0.7 + dev: true + + /rfdc@1.3.0: + resolution: + { + integrity: sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA== + } + dev: true + + /safe-buffer@5.2.1: + resolution: + { + integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== + } + dev: true + + /serialize-javascript@6.0.0: + resolution: + { + integrity: sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag== + } + dependencies: + randombytes: 2.1.0 + dev: true + + /shebang-command@2.0.0: + resolution: + { + integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== + } + engines: { node: '>=8' } + dependencies: + shebang-regex: 3.0.0 + dev: true + + /shebang-regex@3.0.0: + resolution: + { + integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== + } + engines: { node: '>=8' } + dev: true + + /signal-exit@3.0.7: + resolution: + { + integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== + } + dev: true + + /signal-exit@4.1.0: + resolution: + { + integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw== + } + engines: { node: '>=14' } + dev: true + + /slice-ansi@5.0.0: + resolution: + { + integrity: sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ== + } + engines: { node: '>=12' } + dependencies: + ansi-styles: 6.2.1 + is-fullwidth-code-point: 4.0.0 + dev: true + + /snazzy@9.0.0: + resolution: + { + integrity: sha512-8QZmJb11OiYaUP90Nnjqcj/LEpO8CLgChnP87Wqjv5tNB4djwHaz27VO2usSRR0NmViapeGW04p0aWAMhxxLXg== + } + hasBin: true + dependencies: + chalk: 4.1.2 + inherits: 2.0.4 + minimist: 1.2.8 + readable-stream: 3.6.2 + standard-json: 1.1.0 + strip-ansi: 6.0.1 + text-table: 0.2.0 + dev: true + + /standard-json@1.1.0: + resolution: + { + integrity: sha512-nkonX+n5g3pyVBvJZmvRlFtT/7JyLbNh4CtrYC3Qfxihgs8PKX52f6ONKQXORStuBWJ5PI83EUrNXme7LKfiTQ== + } + hasBin: true + dependencies: + concat-stream: 2.0.0 + dev: true + + /string-argv@0.3.2: + resolution: + { + integrity: sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q== + } + engines: { node: '>=0.6.19' } + dev: true + + /string-width@4.2.3: + resolution: + { + integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + } + engines: { node: '>=8' } + dependencies: + emoji-regex: 8.0.0 + is-fullwidth-code-point: 3.0.0 + strip-ansi: 6.0.1 + + /string-width@5.1.2: + resolution: + { + integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA== + } + engines: { node: '>=12' } + dependencies: + eastasianwidth: 0.2.0 + emoji-regex: 9.2.2 + strip-ansi: 7.1.0 + dev: true + + /string_decoder@1.3.0: + resolution: + { + integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== + } + dependencies: + safe-buffer: 5.2.1 + dev: true + + /strip-ansi@6.0.1: + resolution: + { + integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + } + engines: { node: '>=8' } + dependencies: + ansi-regex: 5.0.1 + + /strip-ansi@7.1.0: + resolution: + { + integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ== + } + engines: { node: '>=12' } + dependencies: + ansi-regex: 6.0.1 + dev: true + + /strip-final-newline@3.0.0: + resolution: + { + integrity: sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw== + } + engines: { node: '>=12' } + dev: true + + /strip-json-comments@3.1.1: + resolution: + { + integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== + } + engines: { node: '>=8' } + dev: true + + /supports-color@7.2.0: + resolution: + { + integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== + } + engines: { node: '>=8' } + dependencies: + has-flag: 4.0.0 + dev: true + + /supports-color@8.1.1: + resolution: + { + integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== + } + engines: { node: '>=10' } + dependencies: + has-flag: 4.0.0 + + /text-table@0.2.0: + resolution: + { + integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw== + } + dev: true + + /to-regex-range@5.0.1: + resolution: + { + integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== + } + engines: { node: '>=8.0' } + dependencies: + is-number: 7.0.0 + dev: true + + /type-detect@4.0.8: + resolution: + { + integrity: sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g== + } + engines: { node: '>=4' } + dev: true + + /type-fest@1.4.0: + resolution: + { + integrity: sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA== + } + engines: { node: '>=10' } + dev: true + + /typedarray@0.0.6: + resolution: + { + integrity: sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA== + } + dev: true + + /typescript@5.3.2: + resolution: + { + integrity: sha512-6l+RyNy7oAHDfxC4FzSJcz9vnjTKxrLpDG5M2Vu4SHRVNg6xzqZp6LYSR9zjqQTu8DU/f5xwxUdADOkbrIX2gQ== + } + engines: { node: '>=14.17' } + hasBin: true + dev: true + + /undici-types@5.26.5: + resolution: + { + integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA== + } + + /util-deprecate@1.0.2: + resolution: + { + integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== + } + dev: true + + /which@2.0.2: + resolution: + { + integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== + } + engines: { node: '>= 8' } + hasBin: true + dependencies: + isexe: 2.0.0 + dev: true + + /workerpool@6.2.1: + resolution: + { + integrity: sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw== + } + dev: true + + /wrap-ansi@7.0.0: + resolution: + { + integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + } + engines: { node: '>=10' } + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + + /wrap-ansi@8.1.0: + resolution: + { + integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ== + } + engines: { node: '>=12' } + dependencies: + ansi-styles: 6.2.1 + string-width: 5.1.2 + strip-ansi: 7.1.0 + dev: true + + /wrappy@1.0.2: + resolution: + { + integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== + } + dev: true + + /y18n@5.0.8: + resolution: + { + integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== + } + engines: { node: '>=10' } + + /yaml@2.3.4: + resolution: + { + integrity: sha512-8aAvwVUSHpfEqTQ4w/KMlf3HcRdt50E5ODIQJBw1fQ5RL34xabzxtUlzTXVqc4rkZsPbvrXKWnABCD7kWSmocA== + } + engines: { node: '>= 14' } + dev: true + + /yargs-parser@20.2.4: + resolution: + { + integrity: sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA== + } + engines: { node: '>=10' } + dev: true + + /yargs-parser@21.1.1: + resolution: + { + integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw== + } + engines: { node: '>=12' } + dev: false + + /yargs-unparser@2.0.0: + resolution: + { + integrity: sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA== + } + engines: { node: '>=10' } + dependencies: + camelcase: 6.3.0 + decamelize: 4.0.0 + flat: 5.0.2 + is-plain-obj: 2.1.0 + dev: true + + /yargs@16.2.0: + resolution: + { + integrity: sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw== + } + engines: { node: '>=10' } + dependencies: + cliui: 7.0.4 + escalade: 3.1.1 + get-caller-file: 2.0.5 + require-directory: 2.1.1 + string-width: 4.2.3 + y18n: 5.0.8 + yargs-parser: 20.2.4 + dev: true + + /yargs@17.7.2: + resolution: + { + integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w== + } + engines: { node: '>=12' } + dependencies: + cliui: 8.0.1 + escalade: 3.1.1 + get-caller-file: 2.0.5 + require-directory: 2.1.1 + string-width: 4.2.3 + y18n: 5.0.8 + yargs-parser: 21.1.1 + dev: false + + /yocto-queue@0.1.0: + resolution: + { + integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== + } + engines: { node: '>=10' } + dev: true diff --git a/prettier.config.js b/prettier.config.js new file mode 100644 index 0000000..601d47e --- /dev/null +++ b/prettier.config.js @@ -0,0 +1,7 @@ +module.exports = { + semi: false, + singleQuote: true, + trailingComma: 'none', + arrowParens: 'avoid', + proseWrap: 'always' +} From 8bc08135f42939c161f35b6e3410b28bba02f933 Mon Sep 17 00:00:00 2001 From: "Chakhsu.Lau" Date: Sun, 3 Dec 2023 19:41:47 +0800 Subject: [PATCH 06/12] feat: update code style --- .github/workflows/tests.yml | 30 +- .vscode/settings.json | 2 +- README.md | 51 ++- package.json | 2 +- src/config/defaultChannelOptions.ts | 30 +- src/config/defaultLoadOptions.ts | 4 +- src/index.ts | 395 ++++++++++------ src/proxy/clientProxy.ts | 379 +++++++++------- src/proxy/serverProxy.ts | 341 ++++++++------ src/schema/loader.ts | 28 +- src/schema/server.ts | 6 +- src/util/compose.ts | 30 +- src/util/iterator.ts | 168 ++++--- src/util/prefixingDefinition.ts | 20 +- test/benchmark/README.md | 2 + test/benchmark/server-grpcity.js | 4 +- test/benchmark/server-grpcjs.js | 19 +- test/client.js | 20 +- test/index.test.js | 54 ++- test/server.js | 42 +- test/stream/client-v2.js | 7 +- test/stream/client.js | 25 +- test/stream/server-v2.js | 24 +- test/stream/server.js | 18 +- tsconfig.json | 2 +- types/config/defaultChannelOptions.d.ts | 4 +- types/config/defaultChannelOptions.js | 40 +- types/config/defaultLoadOptions.d.ts | 4 +- types/config/defaultLoadOptions.js | 18 +- types/index.d.ts | 79 ++-- types/index.js | 562 ++++++++++++++--------- types/proxy/clientProxy.d.ts | 30 +- types/proxy/clientProxy.js | 575 ++++++++++++----------- types/proxy/serverProxy.d.ts | 70 +-- types/proxy/serverProxy.js | 579 +++++++++++++----------- types/schema/loader.d.ts | 12 +- types/schema/loader.js | 63 +-- types/schema/server.d.ts | 8 +- types/schema/server.js | 32 +- types/util/compose.d.ts | 9 +- types/util/compose.js | 61 ++- types/util/iterator.d.ts | 46 +- types/util/iterator.js | 295 ++++++------ types/util/prefixingDefinition.d.ts | 4 +- types/util/prefixingDefinition.js | 45 +- 45 files changed, 2445 insertions(+), 1794 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index bb85c4e..598e3b3 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -2,9 +2,9 @@ name: build on: push: - branches: [ "main" ] + branches: ['main'] pull_request: - branches: [ "main" ] + branches: ['main'] permissions: contents: read @@ -20,16 +20,16 @@ jobs: os: [ubuntu-latest, windows-latest, macos-latest] steps: - - uses: actions/checkout@v4 - - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v3 - with: - cache: 'npm' - node-version: ${{ matrix.node-version }} - # Use separate run commands so command status handled correctly on Windows - - name: npm install - run: npm ci - - name: npm test - run: npm test - - name: npm run lint - run: npm run lint \ No newline at end of file + - uses: actions/checkout@v4 + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v3 + with: + cache: 'npm' + node-version: ${{ matrix.node-version }} + # Use separate run commands so command status handled correctly on Windows + - name: npm install + run: npm ci + - name: npm test + run: npm test + - name: npm run lint + run: npm run lint diff --git a/.vscode/settings.json b/.vscode/settings.json index c4b8dab..1957872 100755 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -2,4 +2,4 @@ "standard.enable": true, "standard.autoFixOnSave": true, "eslint.enable": false -} \ No newline at end of file +} diff --git a/README.md b/README.md index 88e7278..e7986c6 100644 --- a/README.md +++ b/README.md @@ -4,22 +4,37 @@ ## Introduction -`gRPCity` is a gRPC microservices library running on Node.js. It combines `proto-loader` and `grpc-js` to offer an exceptionally easy way to load proto files. It simplifies many complex technical concepts, allowing clients and servers to be implemented with just a few functions. Additionally, it provides numerous advanced features to meet the needs of most development scenarios. +`gRPCity` is a gRPC microservices library running on Node.js. It combines +`proto-loader` and `grpc-js` to offer an exceptionally easy way to load proto +files. It simplifies many complex technical concepts, allowing clients and +servers to be implemented with just a few functions. Additionally, it provides +numerous advanced features to meet the needs of most development scenarios. -> The name is derived from "gRPC + City = gRPCity", symbolizing the author's hope that this library can support the development of business cities. Taking a technological perspective as the foundation, it enables everyone to focus on business and better support delivery. +> The name is derived from "gRPC + City = gRPCity", symbolizing the author's +> hope that this library can support the development of business cities. Taking +> a technological perspective as the foundation, it enables everyone to focus on +> business and better support delivery. Here is the feature: -- **API**: The communication protocol is based on gRPC and defined using Protobuf. -- **Protobuf**: Supports only dynamic loading of pb, simplifying the loading process of pb files. -- **Client**: Configured once and can be called anytime, anywhere, supporting multi-server invocation. -- **Server**: Simplifies the initialization process, starting the server in three steps, supporting multi-server startup. +- **API**: The communication protocol is based on gRPC and defined using + Protobuf. +- **Protobuf**: Supports only dynamic loading of pb, simplifying the loading + process of pb files. +- **Client**: Configured once and can be called anytime, anywhere, supporting + multi-server invocation. +- **Server**: Simplifies the initialization process, starting the server in + three steps, supporting multi-server startup. - **No-Route**: No routing, RPC is inherently bound to methods. -- **Middleware**: Integrates middleware mechanism similar to Koa, providing pre and post-processing capabilities for RPC. +- **Middleware**: Integrates middleware mechanism similar to Koa, providing pre + and post-processing capabilities for RPC. - **Metadata**: Standardizes the transmission and retrieval of metadata. -- **Error**: Provides dedicated Error objects to ensure targeted handling of exceptions after catching. -- **Promise**: Supports promisify internally in RPC methods while also preserving callbackify. -- **Config**: Aligned with official configurations, supports pb load configuration and gRPC channel configuration. +- **Error**: Provides dedicated Error objects to ensure targeted handling of + exceptions after catching. +- **Promise**: Supports promisify internally in RPC methods while also + preserving callbackify. +- **Config**: Aligned with official configurations, supports pb load + configuration and gRPC channel configuration. - **Pattern**: Singleton pattern ensures the uniqueness of instance objects. - **Typescript**: Supported, ensuring compatibility between TS and JS. @@ -27,7 +42,8 @@ Here is the feature: --- -View full documentation and examples on [grpcity.js.org](https://grpcity.js.org). +View full documentation and examples on +[grpcity.js.org](https://grpcity.js.org). ## Quick Start @@ -67,9 +83,7 @@ const __dirname = path.dirname(fileURLToPath(import.meta.url)) export default new GrpcLoader({ location: path.join(__dirname, './'), - files: [ - 'greeter.proto' - ] + files: ['greeter.proto'] }) ``` @@ -89,7 +103,7 @@ class Greeter { } } -const start = async (addr) => { +const start = async addr => { await loader.init() const server = loader.initServer() @@ -107,9 +121,9 @@ start('127.0.0.1:9099') Finally, create `client.js` and write the following code in it: ```js -import loader from "./loader.js" +import loader from './loader.js' -const start = async (addr) => { +const start = async addr => { await loader.init() await loader.initClients({ @@ -135,7 +149,8 @@ node ./client.js --- -View full documentation and examples on [grpcity.js.org](https://grpcity.js.org). +View full documentation and examples on +[grpcity.js.org](https://grpcity.js.org). ## License diff --git a/package.json b/package.json index 884be24..5c60f7a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "grpcity", - "version": "1.3.0-beta.0", + "version": "1.3.0-beta.1", "description": "A powerful and complete gRPC framework for Node.js", "author": "Chakhsu.Lau", "license": "MIT", diff --git a/src/config/defaultChannelOptions.ts b/src/config/defaultChannelOptions.ts index 8df951c..13f727c 100644 --- a/src/config/defaultChannelOptions.ts +++ b/src/config/defaultChannelOptions.ts @@ -1,23 +1,23 @@ // gRPC channel options // Doc: https://grpc.github.io/grpc/core/group__grpc__arg__keys.html // Doc: https://github.com/grpc/grpc-node/blob/master/packages/grpc-js/src/channel-options.ts -import { ChannelOptions } from "@grpc/grpc-js"; +import { ChannelOptions } from '@grpc/grpc-js' export const defaultChannelOptions: ChannelOptions = { - "grpc.min_reconnect_backoff_ms": 1000, - "grpc.max_reconnect_backoff_ms": 10000, - "grpc.grpclb_call_timeout_ms": 5000, - "grpc.keepalive_timeout_ms": 20 * 1000, - "grpc.keepalive_time_ms": 120 * 1000, - "grpc.keepalive_permit_without_calls": 1, - "grpc.enable_retries": 1, - "grpc.service_config": JSON.stringify({ + 'grpc.min_reconnect_backoff_ms': 1000, + 'grpc.max_reconnect_backoff_ms': 10000, + 'grpc.grpclb_call_timeout_ms': 5000, + 'grpc.keepalive_timeout_ms': 20 * 1000, + 'grpc.keepalive_time_ms': 120 * 1000, + 'grpc.keepalive_permit_without_calls': 1, + 'grpc.enable_retries': 1, + 'grpc.service_config': JSON.stringify({ retryPolicy: { maxAttempts: 4, - initialBackoff: "0.1s", - maxBackoff: "1s", + initialBackoff: '0.1s', + maxBackoff: '1s', backoffMultiplier: 2, - retryableStatusCodes: ["UNAVAILABLE"], - }, - }), -}; + retryableStatusCodes: ['UNAVAILABLE'] + } + }) +} diff --git a/src/config/defaultLoadOptions.ts b/src/config/defaultLoadOptions.ts index 58fab36..63eb666 100644 --- a/src/config/defaultLoadOptions.ts +++ b/src/config/defaultLoadOptions.ts @@ -7,5 +7,5 @@ export const defaultLoadOptions: Options = { longs: String, enums: String, defaults: false, - oneofs: true, -}; + oneofs: true +} diff --git a/src/index.ts b/src/index.ts index 15115f5..e34915e 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,234 +1,367 @@ -import assert from 'node:assert'; -import * as grpc from '@grpc/grpc-js'; -import * as protoLoader from '@grpc/proto-loader'; -import * as protobuf from 'protobufjs'; -import * as Descriptor from 'protobufjs/ext/descriptor'; -import * as _ from 'lodash'; -import * as Joi from 'joi'; - -import loaderSchemas from './schema/loader'; -import prefixingDefinition from './util/prefixingDefinition'; -import { defaultChannelOptions } from './config/defaultChannelOptions'; -import { defaultLoadOptions } from './config/defaultLoadOptions'; -import clientProxy from './proxy/clientProxy'; -import ServerProxy from './proxy/serverProxy'; +import assert from 'node:assert' +import * as grpc from '@grpc/grpc-js' +import * as protoLoader from '@grpc/proto-loader' +import * as protobuf from 'protobufjs' +import * as Descriptor from 'protobufjs/ext/descriptor' +import * as _ from 'lodash' +import * as Joi from 'joi' + +import loaderSchemas from './schema/loader' +import prefixingDefinition from './util/prefixingDefinition' +import { defaultChannelOptions } from './config/defaultChannelOptions' +import { defaultLoadOptions } from './config/defaultLoadOptions' +import clientProxy from './proxy/clientProxy' +import ServerProxy from './proxy/serverProxy' class GrpcLoader { - private _protoFiles: any[]; - private _clientMap: Map; - private _clientAddrMap: Map; - private _types: any; - private _packagePrefix?: string; - private _appName?: string; - private _packageDefinition: any; - private _isDev?: boolean; - private _reflectedRoot: any; - private _insecureCredentials?: grpc.ChannelCredentials; - private _initDefaultClient?: boolean; + private _protoFiles: any[] + private _clientMap: Map + private _clientAddrMap: Map + private _types: any + private _packagePrefix?: string + private _appName?: string + private _packageDefinition: any + private _isDev?: boolean + private _reflectedRoot: any + private _insecureCredentials?: grpc.ChannelCredentials + private _initDefaultClient?: boolean constructor(protoFileOptions: any) { - Joi.assert(protoFileOptions, loaderSchemas.constructor, 'new GrpcLoader() params Error'); - - this._protoFiles = Array.isArray(protoFileOptions) ? protoFileOptions : [protoFileOptions]; - this._clientMap = new Map(); - this._clientAddrMap = new Map(); + Joi.assert( + protoFileOptions, + loaderSchemas.constructor, + 'new GrpcLoader() params Error' + ) + + this._protoFiles = Array.isArray(protoFileOptions) + ? protoFileOptions + : [protoFileOptions] + this._clientMap = new Map() + this._clientAddrMap = new Map() } - async init({ services = undefined, isDev = false, packagePrefix = '', loadOptions = {}, channelOptions = {}, appName }: any = {}) { - Joi.assert({ services, loadOptions, isDev, channelOptions, appName }, loaderSchemas.init, 'GrpcLoader.init() params Error'); + async init({ + services = undefined, + isDev = false, + packagePrefix = '', + loadOptions = {}, + channelOptions = {}, + appName + }: any = {}) { + Joi.assert( + { services, loadOptions, isDev, channelOptions, appName }, + loaderSchemas.init, + 'GrpcLoader.init() params Error' + ) if (this._types) { - return; + return } try { - loadOptions = Object.assign({}, defaultLoadOptions, loadOptions); - this._isDev = isDev; - this._packagePrefix = packagePrefix; - this._appName = appName; - - loadOptions.includeDirs = this._protoFiles.map((p) => p.location).concat(loadOptions.includeDirs || []); + loadOptions = Object.assign({}, defaultLoadOptions, loadOptions) + this._isDev = isDev + this._packagePrefix = packagePrefix + this._appName = appName + + loadOptions.includeDirs = this._protoFiles + .map(p => p.location) + .concat(loadOptions.includeDirs || []) const files = this._protoFiles.reduce((result, p) => { if (p.files && p.files.length > 0) { - result.push(...p.files); + result.push(...p.files) } - return result; - }, []); + return result + }, []) - const packageDefinition = await protoLoader.load(files, loadOptions); + const packageDefinition = await protoLoader.load(files, loadOptions) if (this._packagePrefix) { - this._packageDefinition = prefixingDefinition(packageDefinition, packagePrefix); + this._packageDefinition = prefixingDefinition( + packageDefinition, + packagePrefix + ) } else { - this._packageDefinition = packageDefinition; + this._packageDefinition = packageDefinition } - this._types = grpc.loadPackageDefinition(this._packageDefinition); + this._types = grpc.loadPackageDefinition(this._packageDefinition) } catch (err) { - throw err; + throw err } if (services) { - await this.initClients({ services, channelOptions }); + await this.initClients({ services, channelOptions }) } } - async initClients({ services, channelOptions = {}, credentials = undefined }: any) { - Joi.assert({ services, channelOptions }, loaderSchemas.initClients, 'GrpcLoader.initClients() Options Error'); + async initClients({ + services, + channelOptions = {}, + credentials = undefined + }: any) { + Joi.assert( + { services, channelOptions }, + loaderSchemas.initClients, + 'GrpcLoader.initClients() Options Error' + ) if (this._initDefaultClient) { - return; + return } if (!this._packageDefinition) { - await this.init(); + await this.init() } - const serviceNames = Object.keys(services); - serviceNames.forEach((name) => { - const isDefaultClient = true; - const addr = _.isString(services[name]) ? services[name] : services[name].host + ':' + services[name].port; - this._makeClient(isDefaultClient, name, addr, credentials, channelOptions); - }); + const serviceNames = Object.keys(services) + serviceNames.forEach(name => { + const isDefaultClient = true + const addr = _.isString(services[name]) + ? services[name] + : services[name].host + ':' + services[name].port + this._makeClient(isDefaultClient, name, addr, credentials, channelOptions) + }) - this._initDefaultClient = true; + this._initDefaultClient = true } closeClients() { this._clientMap.forEach((client, key) => { if (client && typeof client.close === 'function') { - client.close(); + client.close() } - }); - this._clientMap.clear(); - this._clientAddrMap.clear(); - this._initDefaultClient = false; + }) + this._clientMap.clear() + this._clientAddrMap.clear() + this._initDefaultClient = false } - makeCredentials(rootCerts?: any, privateKey?: any, certChain?: any, verifyOptions?: any) { + makeCredentials( + rootCerts?: any, + privateKey?: any, + certChain?: any, + verifyOptions?: any + ) { if (rootCerts && privateKey && certChain) { - return grpc.credentials.createSsl(rootCerts, privateKey, certChain, verifyOptions); + return grpc.credentials.createSsl( + rootCerts, + privateKey, + certChain, + verifyOptions + ) } else { if (!this._insecureCredentials) { - this._insecureCredentials = grpc.credentials.createInsecure(); + this._insecureCredentials = grpc.credentials.createInsecure() } - return this._insecureCredentials; + return this._insecureCredentials } } service(name: string) { - assert(this._types, 'Must called init() first. proto file has not been loaded.'); - const fullName = this._isDev ? `${this._packagePrefix}.${name}` : name; - const service = _.get(this._types, `${fullName}.service`); - assert(service, `Cannot find service with name: ${fullName}, please check if the protos file is configured incorrectly or if the corresponding proto file is missing.`); - return service; + assert( + this._types, + 'Must called init() first. proto file has not been loaded.' + ) + const fullName = this._isDev ? `${this._packagePrefix}.${name}` : name + const service = _.get(this._types, `${fullName}.service`) + assert( + service, + `Cannot find service with name: ${fullName}, please check if the protos file is configured incorrectly or if the corresponding proto file is missing.` + ) + return service } type(name: string) { - assert(this._types, 'Must called init() first. proto file has not been loaded.'); - const fullName = this._isDev ? `${this._packagePrefix}.${name}` : name; - const type = _.get(this._types, `${fullName}`); - assert(type, `Cannot find type with name: ${fullName}, please check if the protos file is configured incorrectly or if the corresponding proto file is missing.`); - return type; + assert( + this._types, + 'Must called init() first. proto file has not been loaded.' + ) + const fullName = this._isDev ? `${this._packagePrefix}.${name}` : name + const type = _.get(this._types, `${fullName}`) + assert( + type, + `Cannot find type with name: ${fullName}, please check if the protos file is configured incorrectly or if the corresponding proto file is missing.` + ) + return type } message(name: string) { - let root = this._reflectedRoot; + let root = this._reflectedRoot if (root) { - const found = root.lookupType(name); + const found = root.lookupType(name) if (found) { - return found; + return found } } - const descriptor = this.type(name).fileDescriptorProtos.map((proto: any) => Descriptor.FileDescriptorProto.decode(proto)) - root = (protobuf.Root as protobuf.RootConstructor).fromDescriptor({ file: descriptor }); + const descriptor = this.type(name).fileDescriptorProtos.map((proto: any) => + Descriptor.FileDescriptorProto.decode(proto) + ) + root = (protobuf.Root as protobuf.RootConstructor).fromDescriptor({ + file: descriptor + }) - this._reflectedRoot = root; + this._reflectedRoot = root - return root.lookupType(name); + return root.lookupType(name) } - client(name: string, { host = undefined, port = undefined, timeout = undefined, credentials = undefined, channelOptions = {} }: any = {}) { - const isDefaultClient = !(host && port); - const addr = `${host}:${port}`; - const cacheKeyPrefix = isDefaultClient ? 'defaultAddr' : addr.replace(/\./g, '-'); - const cacheKey = `proxy.${cacheKeyPrefix}.${name}.${timeout}`; + client( + name: string, + { + host = undefined, + port = undefined, + timeout = undefined, + credentials = undefined, + channelOptions = {} + }: any = {} + ) { + const isDefaultClient = !(host && port) + const addr = `${host}:${port}` + const cacheKeyPrefix = isDefaultClient + ? 'defaultAddr' + : addr.replace(/\./g, '-') + const cacheKey = `proxy.${cacheKeyPrefix}.${name}.${timeout}` if (this._clientMap.has(cacheKey)) { - return this._clientMap.get(cacheKey); + return this._clientMap.get(cacheKey) } else { - const client = this._makeClient(isDefaultClient, name, addr, credentials, channelOptions); - const appName = this._appName; - const proxy = clientProxy._proxy(client, { timeout }, appName); - this._clientMap.set(cacheKey, proxy); - return proxy; + const client = this._makeClient( + isDefaultClient, + name, + addr, + credentials, + channelOptions + ) + const appName = this._appName + const proxy = clientProxy._proxy(client, { timeout }, appName) + this._clientMap.set(cacheKey, proxy) + return proxy } } - realClient(name: string, { host = undefined, port = undefined, credentials = undefined, channelOptions = {} }: any = {}) { - const isDefaultClient = !(host && port); - const client = this._makeClient(isDefaultClient, name, `${host}:${port}`, credentials, channelOptions); - return client; + realClient( + name: string, + { + host = undefined, + port = undefined, + credentials = undefined, + channelOptions = {} + }: any = {} + ) { + const isDefaultClient = !(host && port) + const client = this._makeClient( + isDefaultClient, + name, + `${host}:${port}`, + credentials, + channelOptions + ) + return client } - clientWithoutCache(name: string, { addr, timeout = undefined, credentials = undefined, channelOptions = {} }: any = {}) { - const client = this._makeClientWithoutCache(false, name, addr, credentials, channelOptions); - const appName = this._appName; - const proxy = clientProxy._proxy(client, { timeout }, appName); - return proxy; + clientWithoutCache( + name: string, + { + addr, + timeout = undefined, + credentials = undefined, + channelOptions = {} + }: any = {} + ) { + const client = this._makeClientWithoutCache( + false, + name, + addr, + credentials, + channelOptions + ) + const appName = this._appName + const proxy = clientProxy._proxy(client, { timeout }, appName) + return proxy } - private _makeClient(isDefaultClient: boolean, name: string, addr: string, credentials: any, channelOptions: any = {}) { - const ctBool = !!credentials; - const cacheKeyPrefix = isDefaultClient ? 'defaultAddr' : addr.replace(/\./g, '-'); - const cacheKeyWithCt = `${cacheKeyPrefix}.${name}.${ctBool}`; - const cacheKey = `${cacheKeyPrefix}.${name}`; + private _makeClient( + isDefaultClient: boolean, + name: string, + addr: string, + credentials: any, + channelOptions: any = {} + ) { + const ctBool = !!credentials + const cacheKeyPrefix = isDefaultClient + ? 'defaultAddr' + : addr.replace(/\./g, '-') + const cacheKeyWithCt = `${cacheKeyPrefix}.${name}.${ctBool}` + const cacheKey = `${cacheKeyPrefix}.${name}` if (this._clientMap.has(cacheKey)) { - return this._clientMap.get(cacheKey); + return this._clientMap.get(cacheKey) } else if (this._clientMap.has(cacheKeyWithCt)) { - return this._clientMap.get(cacheKeyWithCt); + return this._clientMap.get(cacheKeyWithCt) } else { let cacheAddr: string = addr if (addr === 'undefined:undefined') { - cacheAddr = this._clientAddrMap.get(name) || addr; + cacheAddr = this._clientAddrMap.get(name) || addr } - const client = this._makeClientWithoutCache(isDefaultClient, name, cacheAddr, credentials, channelOptions); - this._clientAddrMap.set(name, cacheAddr); - this._clientMap.set(cacheKey, client); - return client; + const client = this._makeClientWithoutCache( + isDefaultClient, + name, + cacheAddr, + credentials, + channelOptions + ) + this._clientAddrMap.set(name, cacheAddr) + this._clientMap.set(cacheKey, client) + return client } } - private _makeClientWithoutCache(isDefaultClient: boolean, name: string, addr: string, credentials: any, channelOptions: any = {}) { - channelOptions = Object.assign({}, defaultChannelOptions, channelOptions); - - const ServiceProto = this.type(name); - const client = new ServiceProto(addr, credentials || this.makeCredentials(), channelOptions); - return client; + private _makeClientWithoutCache( + isDefaultClient: boolean, + name: string, + addr: string, + credentials: any, + channelOptions: any = {} + ) { + channelOptions = Object.assign({}, defaultChannelOptions, channelOptions) + + const ServiceProto = this.type(name) + const client = new ServiceProto( + addr, + credentials || this.makeCredentials(), + channelOptions + ) + return client } makeMetadata(initialValues: any) { - assert(this._types, 'Must called init() first. proto file has not been loaded.'); - const meta = new grpc.Metadata(); + assert( + this._types, + 'Must called init() first. proto file has not been loaded.' + ) + const meta = new grpc.Metadata() if (typeof initialValues === 'object') { Object.entries(initialValues).forEach(([key, value]: [string, any]) => { if (Array.isArray(value)) { - value.map((v) => meta.add(key, _.isString(v) ? v : Buffer.from(v))); + value.map(v => meta.add(key, _.isString(v) ? v : Buffer.from(v))) } else { - meta.add(key, _.isString(value) ? value : Buffer.from(value)); + meta.add(key, _.isString(value) ? value : Buffer.from(value)) } - }); + }) } - return meta; + return meta } initServer(...args: any[]) { - assert(this._types, 'Must called init() first. proto file has not been loaded.'); + assert( + this._types, + 'Must called init() first. proto file has not been loaded.' + ) const server = new ServerProxy() - return server._init(this, ...args); + return server._init(this, ...args) } } diff --git a/src/proxy/clientProxy.ts b/src/proxy/clientProxy.ts index 0600cf7..19e3097 100644 --- a/src/proxy/clientProxy.ts +++ b/src/proxy/clientProxy.ts @@ -1,58 +1,78 @@ -import { Metadata, MetadataValue, UntypedServiceImplementation } from '@grpc/grpc-js'; -import * as os from 'node:os'; -import iterator from '../util/iterator'; +import { + Metadata, + MetadataValue, + UntypedServiceImplementation +} from '@grpc/grpc-js' +import * as os from 'node:os' +import iterator from '../util/iterator' class ClientProxy { - private _getFuncStreamWay(func: any): { requestStream: boolean; responseStream: boolean } { - const { requestStream, responseStream } = func; - return { requestStream, responseStream }; + private _getFuncStreamWay(func: any): { + requestStream: boolean + responseStream: boolean + } { + const { requestStream, responseStream } = func + return { requestStream, responseStream } } - private _prepareMetadata(metadata: Metadata | Record, options: Record, basicMeta: Record): [Metadata, Record] { + private _prepareMetadata( + metadata: Metadata | Record, + options: Record, + basicMeta: Record + ): [Metadata, Record] { if (metadata instanceof Metadata) { - options = { ...options }; + options = { ...options } } else { - options = { ...metadata }; - metadata = new Metadata(); + options = { ...metadata } + metadata = new Metadata() } if (basicMeta.hostname) { - metadata.add('x-client-hostname', basicMeta.hostname as MetadataValue); + metadata.add('x-client-hostname', basicMeta.hostname as MetadataValue) } if (basicMeta.appName) { - metadata.add('x-client-app-name',basicMeta.appName as MetadataValue); + metadata.add('x-client-app-name', basicMeta.appName as MetadataValue) } - return [metadata, options]; + return [metadata, options] } private _handlerError(err: any, basicMeta: Record) { - const newError = new Error() as { name: string; code: string; message: string; stack: string }; + const newError = new Error() as { + name: string + code: string + message: string + stack: string + } - newError.name = 'GrpcClientError'; - newError.code = err.code; - newError.message = `${basicMeta.fullServiceName} (${err.message})`; + newError.name = 'GrpcClientError' + newError.code = err.code + newError.message = `${basicMeta.fullServiceName} (${err.message})` - const stacks = newError.stack!.split('\n'); + const stacks = newError.stack!.split('\n') newError.stack = [ stacks[0], ...stacks.slice(2), ' ...', - ...(err.stack!.split('\n').slice(1, 3) as string[]), - ].join('\n'); + ...(err.stack!.split('\n').slice(1, 3) as string[]) + ].join('\n') - return newError; + return newError } - private _setDeadline(options: { deadline?: Date; timeout?: number }, defaultOptions: Record, basicMeta: { fullServiceName?: string }): { deadline?: Date } { + private _setDeadline( + options: { deadline?: Date; timeout?: number }, + defaultOptions: Record, + basicMeta: { fullServiceName?: string } + ): { deadline?: Date } { if (!options.deadline) { - const timeout = options.timeout || defaultOptions.timeout; - const deadline = new Date(Date.now() + (timeout as number)); - options.deadline = deadline; - delete options.timeout; + const timeout = options.timeout || defaultOptions.timeout + const deadline = new Date(Date.now() + (timeout as number)) + options.deadline = deadline + delete options.timeout } - return options; + return options } private _promisifyUnaryMethod( @@ -67,36 +87,40 @@ class ClientProxy { options: Record ): Promise => { if (typeof options === 'function') { - throw new Error('gRPCity: AsyncFunction should not contain a callback function'); + throw new Error( + 'gRPCity: AsyncFunction should not contain a callback function' + ) } else if (typeof metadata === 'function') { - throw new Error('gRPCity: AsyncFunction should not contain a callback function'); + throw new Error( + 'gRPCity: AsyncFunction should not contain a callback function' + ) } - [metadata, options] = this._prepareMetadata(metadata, options, basicMeta); - options = this._setDeadline(options, defaultOptions, basicMeta); + ;[metadata, options] = this._prepareMetadata(metadata, options, basicMeta) + options = this._setDeadline(options, defaultOptions, basicMeta) return new Promise((resolve, reject) => { - const result: { response?: any; metadata?: any; status?: any } = {}; - const argumentsList: Array = [request, metadata, options]; + const result: { response?: any; metadata?: any; status?: any } = {} + const argumentsList: Array = [request, metadata, options] argumentsList.push((err: any, response: any) => { if (err) { - reject(this._handlerError(err, basicMeta)); + reject(this._handlerError(err, basicMeta)) } - result.response = response; - }); + result.response = response + }) - const call = func.apply(client, argumentsList); + const call = func.apply(client, argumentsList) call.on('metadata', (metadata: any) => { - result.metadata = metadata; - }); + result.metadata = metadata + }) call.on('status', (status: any) => { - result.status = status; - resolve(result); - }); - }); - }; - return asyncUnaryMethod; + result.status = status + resolve(result) + }) + }) + } + return asyncUnaryMethod } private _promisifyClientStreamMethod( @@ -110,51 +134,55 @@ class ClientProxy { options: Record ): any => { if (typeof options === 'function') { - throw new Error('gRPCity: asyncStreamFunction should not contain a callback function'); + throw new Error( + 'gRPCity: asyncStreamFunction should not contain a callback function' + ) } else if (typeof metadata === 'function') { - throw new Error('gRPCity: asyncStreamFunction should not contain a callback function'); + throw new Error( + 'gRPCity: asyncStreamFunction should not contain a callback function' + ) } - [metadata, options] = this._prepareMetadata(metadata, options, basicMeta); - options = this._setDeadline(options, defaultOptions, basicMeta); + ;[metadata, options] = this._prepareMetadata(metadata, options, basicMeta) + options = this._setDeadline(options, defaultOptions, basicMeta) - const result: { response?: any; metadata?: any; status?: any } = {}; + const result: { response?: any; metadata?: any; status?: any } = {} - const argumentsList: Array = [metadata, options]; + const argumentsList: Array = [metadata, options] argumentsList.push((err: any, response: any) => { if (err) { - throw this._handlerError(err, basicMeta); + throw this._handlerError(err, basicMeta) } - result.response = response; - }); + result.response = response + }) - const call = func.apply(client, argumentsList); + const call = func.apply(client, argumentsList) call.writeAll = (messages: any[]) => { if (Array.isArray(messages)) { - messages.forEach((message) => { - call.write(message); - }); + messages.forEach(message => { + call.write(message) + }) } - }; + } call.writeEnd = async () => { - call.end(); + call.end() await new Promise((resolve, reject) => { call.on('metadata', (metadata: any) => { - result.metadata = metadata; - }); + result.metadata = metadata + }) call.on('status', (status: any) => { - result.status = status; - resolve(); - }); - }); - return result; - }; + result.status = status + resolve() + }) + }) + return result + } - return call; - }; + return call + } - return clientStreamMethod; + return clientStreamMethod } private _promisifyServerStreamMethod( @@ -169,40 +197,44 @@ class ClientProxy { options: Record ): any => { if (typeof options === 'function') { - throw new Error('gRPCity: asyncStreamFunction should not contain a callback function'); + throw new Error( + 'gRPCity: asyncStreamFunction should not contain a callback function' + ) } else if (typeof metadata === 'function') { - throw new Error('gRPCity: asyncStreamFunction should not contain a callback function'); + throw new Error( + 'gRPCity: asyncStreamFunction should not contain a callback function' + ) } - [metadata, options] = this._prepareMetadata(metadata, options, basicMeta); - options = this._setDeadline(options, defaultOptions, basicMeta); + ;[metadata, options] = this._prepareMetadata(metadata, options, basicMeta) + options = this._setDeadline(options, defaultOptions, basicMeta) - const call = func.apply(client, [request, metadata, options]); + const call = func.apply(client, [request, metadata, options]) call.on('error', (err: Error) => { - throw this._handlerError(err, basicMeta); - }); + throw this._handlerError(err, basicMeta) + }) - const result: { metadata?: any; status?: any } = {}; + const result: { metadata?: any; status?: any } = {} call.readAll = () => { call.on('metadata', (metadata: any) => { - result.metadata = metadata; - }); + result.metadata = metadata + }) call.on('status', (status: any) => { - result.status = status; - }); + result.status = status + }) return iterator(call, 'data', { - resolutionEvents: ['status', 'end'], - }); - }; + resolutionEvents: ['status', 'end'] + }) + } call.readEnd = () => { - return result; - }; + return result + } - return call; - }; + return call + } - return serverStreamMethod; + return serverStreamMethod } private _promisifyDuplexStreamMethod( @@ -216,56 +248,63 @@ class ClientProxy { options: Record ): any => { if (typeof options === 'function') { - throw new Error('gRPCity: asyncStreamFunction should not contain a callback function'); + throw new Error( + 'gRPCity: asyncStreamFunction should not contain a callback function' + ) } else if (typeof metadata === 'function') { - throw new Error('gRPCity: asyncStreamFunction should not contain a callback function'); + throw new Error( + 'gRPCity: asyncStreamFunction should not contain a callback function' + ) } - [metadata, options] = this._prepareMetadata(metadata, options, basicMeta); - options = this._setDeadline(options, defaultOptions, basicMeta); + ;[metadata, options] = this._prepareMetadata(metadata, options, basicMeta) + options = this._setDeadline(options, defaultOptions, basicMeta) - const call = func.apply(client, [metadata, options]); + const call = func.apply(client, [metadata, options]) call.writeAll = (messages: any[]) => { if (Array.isArray(messages)) { - messages.forEach((message) => { - call.write(message); - }); + messages.forEach(message => { + call.write(message) + }) } - }; - call.writeEnd = call.end; + } + call.writeEnd = call.end call.on('error', (err: Error) => { - throw this._handlerError(err, basicMeta); - }); + throw this._handlerError(err, basicMeta) + }) - const result: { metadata?: any; status?: any } = {}; + const result: { metadata?: any; status?: any } = {} call.readAll = () => { call.on('metadata', (metadata: any) => { - result.metadata = metadata; - }); + result.metadata = metadata + }) call.on('status', (status: any) => { - result.status = status; - }); + result.status = status + }) return iterator(call, 'data', { - resolutionEvents: ['status', 'end'], - }); - }; + resolutionEvents: ['status', 'end'] + }) + } call.readEnd = () => { - return result; - }; + return result + } - return call; - }; + return call + } - return duplexStreamMethod; + return duplexStreamMethod } - private _keepCallbackMethod(client: UntypedServiceImplementation, func: any): (...argumentsList: any[]) => any { + private _keepCallbackMethod( + client: UntypedServiceImplementation, + func: any + ): (...argumentsList: any[]) => any { const callbackMethod = (...argumentsList: any[]) => { - return func.apply(client, argumentsList); - }; - return callbackMethod; + return func.apply(client, argumentsList) + } + return callbackMethod } _proxy( @@ -273,54 +312,80 @@ class ClientProxy { defaultOptions: Record = {}, appName?: string ): any { - defaultOptions = defaultOptions || {}; - defaultOptions.timeout = defaultOptions.timeout || 1000 * 10; + defaultOptions = defaultOptions || {} + defaultOptions.timeout = defaultOptions.timeout || 1000 * 10 - const prototype = Object.getPrototypeOf(client); + const prototype = Object.getPrototypeOf(client) const methodNames: any = Object.keys(prototype) - .filter((key) => prototype[key] && prototype[key].path) + .filter(key => prototype[key] && prototype[key].path) .reduce((names: any, key) => { - names[key.toUpperCase()] = prototype[key].path; - return names; - }, {}); - - const basicMeta: Record = { hostname: os.hostname(), appName }; + names[key.toUpperCase()] = prototype[key].path + return names + }, {}) - const target = Object.entries(prototype).reduce((target: any, [name, func]) => { - if (name !== 'constructor' && typeof func === 'function') { - basicMeta.fullServiceName = `${methodNames[name.toUpperCase()]}`; + const basicMeta: Record = { + hostname: os.hostname(), + appName + } - const { requestStream, responseStream } = this._getFuncStreamWay(func); + const target = Object.entries(prototype).reduce( + (target: any, [name, func]) => { + if (name !== 'constructor' && typeof func === 'function') { + basicMeta.fullServiceName = `${methodNames[name.toUpperCase()]}` + + const { requestStream, responseStream } = this._getFuncStreamWay(func) + + if (!requestStream && !responseStream) { + // promisify unary method + target[name] = this._promisifyUnaryMethod( + client, + func, + defaultOptions, + basicMeta + ) + } - if (!requestStream && !responseStream) { - // promisify unary method - target[name] = this._promisifyUnaryMethod(client, func, defaultOptions, basicMeta); - } + // stream + if (requestStream && !responseStream) { + // promisify only client stream method + target[name] = this._promisifyClientStreamMethod( + client, + func, + defaultOptions, + basicMeta + ) + } + if (!requestStream && responseStream) { + // promisify only server stream method + target[name] = this._promisifyServerStreamMethod( + client, + func, + defaultOptions, + basicMeta + ) + } + if (requestStream && responseStream) { + // promisify duplex stream method + target[name] = this._promisifyDuplexStreamMethod( + client, + func, + defaultOptions, + basicMeta + ) + } - // stream - if (requestStream && !responseStream) { - // promisify only client stream method - target[name] = this._promisifyClientStreamMethod(client, func, defaultOptions, basicMeta); - } - if (!requestStream && responseStream) { - // promisify only server stream method - target[name] = this._promisifyServerStreamMethod(client, func, defaultOptions, basicMeta); + // keep callback method + target.call[name] = this._keepCallbackMethod(client, func) } - if (requestStream && responseStream) { - // promisify duplex stream method - target[name] = this._promisifyDuplexStreamMethod(client, func, defaultOptions, basicMeta); - } - - // keep callback method - target.call[name] = this._keepCallbackMethod(client, func); - } - return target; - }, { call: {} }); + return target + }, + { call: {} } + ) - return target; + return target } } -export default new ClientProxy(); +export default new ClientProxy() diff --git a/src/proxy/serverProxy.ts b/src/proxy/serverProxy.ts index b3dd48c..d5ef36f 100644 --- a/src/proxy/serverProxy.ts +++ b/src/proxy/serverProxy.ts @@ -1,179 +1,234 @@ -import assert from 'node:assert'; -import * as util from 'node:util'; -import * as grpc from '@grpc/grpc-js'; -import * as _ from 'lodash'; -import * as Joi from 'joi'; -import serverSchemas from '../schema/server'; -import iterator from '../util/iterator'; -import { compose, MiddlewareFunction } from '../util/compose'; +import assert from 'node:assert' +import * as util from 'node:util' +import * as grpc from '@grpc/grpc-js' +import * as _ from 'lodash' +import * as Joi from 'joi' +import serverSchemas from '../schema/server' +import iterator from '../util/iterator' +import { compose, MiddlewareFunction } from '../util/compose' class ServerProxy { - private _middleware: MiddlewareFunction[]; + private _middleware: MiddlewareFunction[] - private _loader?: any; - private _server?: grpc.Server; - private _insecureServerCredentials?: grpc.ServerCredentials; + private _loader?: any + private _server?: grpc.Server + private _insecureServerCredentials?: grpc.ServerCredentials constructor() { - this._middleware = []; + this._middleware = [] } _init(loader: any, ...args: any[]): this { if (!this._loader) { - this._loader = loader; + this._loader = loader } if (!this._server) { - this._server = new grpc.Server(...args); + this._server = new grpc.Server(...args) } - return this; + return this } - async listen(addr: any, credentials: grpc.ServerCredentials | undefined = undefined): Promise { - assert(this._server, 'must be first init() server before server listen()'); - Joi.assert(addr, serverSchemas.address, 'server listen() params Error'); + async listen( + addr: any, + credentials: grpc.ServerCredentials | undefined = undefined + ): Promise { + assert(this._server, 'must be first init() server before server listen()') + Joi.assert(addr, serverSchemas.address, 'server listen() params Error') - const url = _.isString(addr) ? addr : `${addr.host}:${addr.port}`; + const url = _.isString(addr) ? addr : `${addr.host}:${addr.port}` const bindPort = await new Promise((resolve, reject) => { - this._server!.bindAsync(url, credentials || this.makeServerCredentials(), (err, result) => ( - err ? reject(err) : resolve(result) - )); - }); - const port = addr.port ? addr.port : Number(addr.match(/:(\d+)/)![1]); - assert(bindPort === port, 'server bind port not to be right'); - - this._server!.start(); + this._server!.bindAsync( + url, + credentials || this.makeServerCredentials(), + (err, result) => (err ? reject(err) : resolve(result)) + ) + }) + const port = addr.port ? addr.port : Number(addr.match(/:(\d+)/)![1]) + assert(bindPort === port, 'server bind port not to be right') + + this._server!.start() } async shutdown(): Promise { if (!this._server) { - return; + return } await new Promise((resolve, reject) => { this._server!.tryShutdown(err => { if (err) { - reject(err); + reject(err) } else { - resolve(); + resolve() } - }); - }); + }) + }) - delete this._server; - delete this._loader; + delete this._server + delete this._loader } forceShutdown(): void { if (!this._server) { - return; + return } - this._server!.forceShutdown(); - delete this._server; - delete this._loader; + this._server!.forceShutdown() + delete this._server + delete this._loader } - makeServerCredentials(rootCerts?: Buffer, keyCertPairs?: grpc.KeyCertPair[], checkClientCertificate?: boolean): grpc.ServerCredentials { + makeServerCredentials( + rootCerts?: Buffer, + keyCertPairs?: grpc.KeyCertPair[], + checkClientCertificate?: boolean + ): grpc.ServerCredentials { if (rootCerts && keyCertPairs) { - return grpc.ServerCredentials.createSsl(rootCerts, keyCertPairs, checkClientCertificate); + return grpc.ServerCredentials.createSsl( + rootCerts, + keyCertPairs, + checkClientCertificate + ) } else { if (!this._insecureServerCredentials) { - this._insecureServerCredentials = grpc.ServerCredentials.createInsecure(); + this._insecureServerCredentials = + grpc.ServerCredentials.createInsecure() } - return this._insecureServerCredentials; + return this._insecureServerCredentials } } - addService(name: string, implementation: any, { exclude = [], inherit }: { exclude?: string[], inherit?: any } = {}): void { - const service = this._loader.service(name); + addService( + name: string, + implementation: any, + { exclude = [], inherit }: { exclude?: string[]; inherit?: any } = {} + ): void { + const service = this._loader.service(name) - const options: any = { exclude, inherit, _implementationType: {} }; + const options: any = { exclude, inherit, _implementationType: {} } Object.keys(service).forEach(key => { - const { requestStream, responseStream } = service[key]; - options._implementationType[service[key].originalName] = { requestStream, responseStream }; - }); + const { requestStream, responseStream } = service[key] + options._implementationType[service[key].originalName] = { + requestStream, + responseStream + } + }) - this._server!.addService(service, this._callbackify(implementation, options)); + this._server!.addService( + service, + this._callbackify(implementation, options) + ) } removeService(name: string): void { - assert(this._server, 'must be first init() server before server removeService()'); - this._server!.removeService(this._loader.service(name)); + assert( + this._server, + 'must be first init() server before server removeService()' + ) + this._server!.removeService(this._loader.service(name)) } addMiddleware(...args: MiddlewareFunction[]): void { - assert(args.length >= 1, 'server addMiddleware() takes at least one argument.'); + assert( + args.length >= 1, + 'server addMiddleware() takes at least one argument.' + ) if (args.length === 1) { if (Array.isArray(args[0])) { args[0].forEach(fn => { - this._use(fn); - }); + this._use(fn) + }) } else { - this._use(args[0]); + this._use(args[0]) } } else { args.forEach(fn => { - this._use(fn); - }); + this._use(fn) + }) } } private _use(fn: MiddlewareFunction): void { - if (typeof fn !== 'function') throw new TypeError('grpcity loader server middleware must be a function!'); - this._middleware.push(fn); + if (typeof fn !== 'function') + throw new TypeError( + 'grpcity loader server middleware must be a function!' + ) + this._middleware.push(fn) } - private _callbackify(target: any, { exclude = [], inherit, _implementationType }: { exclude?: string[], inherit?: any, _implementationType: any }): any { - assert(typeof target === 'object', 'Must callbackify an object'); - assert(Array.isArray(exclude), 'options.exclude must be an array of strings'); - - const protoPropertyNames = Object.getOwnPropertyNames(Object.getPrototypeOf({})); - exclude.push(...protoPropertyNames); + private _callbackify( + target: any, + { + exclude = [], + inherit, + _implementationType + }: { exclude?: string[]; inherit?: any; _implementationType: any } + ): any { + assert(typeof target === 'object', 'Must callbackify an object') + assert( + Array.isArray(exclude), + 'options.exclude must be an array of strings' + ) + + const protoPropertyNames = Object.getOwnPropertyNames( + Object.getPrototypeOf({}) + ) + exclude.push(...protoPropertyNames) const allPropertyNames = [ ...new Set([ ...Object.keys(target), ...Object.getOwnPropertyNames(Object.getPrototypeOf(target)), - ...(inherit && inherit.prototype ? Object.getOwnPropertyNames(inherit.prototype) : []) + ...(inherit && inherit.prototype + ? Object.getOwnPropertyNames(inherit.prototype) + : []) ]) - ]; + ] - const methods: { [key: string]: any } = {}; + const methods: { [key: string]: any } = {} for (const key of allPropertyNames) { - const fn = target[key]; - if (typeof fn === 'function' && key !== 'constructor' && !exclude.includes(key)) { + const fn = target[key] + if ( + typeof fn === 'function' && + key !== 'constructor' && + !exclude.includes(key) + ) { if (util.types.isAsyncFunction(fn)) { - const eglWrapFunction = this._proxy(target, key, _implementationType[key]); - methods[key] = eglWrapFunction; + const eglWrapFunction = this._proxy( + target, + key, + _implementationType[key] + ) + methods[key] = eglWrapFunction } else { - methods[key] = fn; + methods[key] = fn } } } - return methods; + return methods } private _proxy(target: any, key: string, options: any = {}): any { - const { requestStream, responseStream } = options; + const { requestStream, responseStream } = options - const fn = compose(this._middleware); + const fn = compose(this._middleware) // unary if (!requestStream && !responseStream) { - return this._callUnaryProxyMethod(target, key, fn); + return this._callUnaryProxyMethod(target, key, fn) } // client stream if (requestStream && !responseStream) { - return this._callClientStreamProxyMethod(target, key, fn); + return this._callClientStreamProxyMethod(target, key, fn) } // server stream if (!requestStream && responseStream) { - return this._callServerStreamProxyMethod(target, key, fn); + return this._callServerStreamProxyMethod(target, key, fn) } // duplex stream if (requestStream && responseStream) { - return this._callDuplexStreamProxyMethod(target, key, fn); + return this._callDuplexStreamProxyMethod(target, key, fn) } } @@ -184,111 +239,127 @@ class ServerProxy { path: call.call.handler.path || '', request: call.request, metadata: call.metadata.clone() - }; + } } - private _callUnaryProxyMethod(target: any, key: string, composeFunc: Function): grpc.handleUnaryCall { + private _callUnaryProxyMethod( + target: any, + key: string, + composeFunc: Function + ): grpc.handleUnaryCall { return (call, callback) => { - const ctx = this._createContext(call); + const ctx = this._createContext(call) Promise.resolve().then(async () => { const handleResponse = async () => { - ctx.response = await target[key](call); - }; + ctx.response = await target[key](call) + } await composeFunc(ctx, handleResponse).catch((err: Error) => { - callback(this._createInternalErrorStatus(err)); - }); - callback(null, ctx.response); - }); - }; + callback(this._createInternalErrorStatus(err)) + }) + callback(null, ctx.response) + }) + } } - private _callClientStreamProxyMethod(target: any, key: string, composeFunc: Function): any { + private _callClientStreamProxyMethod( + target: any, + key: string, + composeFunc: Function + ): any { return (call: any, callback: Function) => { - const ctx = this._createContext(call); + const ctx = this._createContext(call) call.readAll = () => { return iterator(call, 'data', { resolutionEvents: ['end'] - }); - }; + }) + } Promise.resolve().then(async () => { const handleResponse = async () => { - ctx.response = await target[key](call); - }; + ctx.response = await target[key](call) + } await composeFunc(ctx, handleResponse).catch((err: Error) => { - callback(this._createInternalErrorStatus(err)); - }); - callback(null, ctx.response); - }); - }; + callback(this._createInternalErrorStatus(err)) + }) + callback(null, ctx.response) + }) + } } - private _callServerStreamProxyMethod(target: any, key: string, composeFunc: Function): any { + private _callServerStreamProxyMethod( + target: any, + key: string, + composeFunc: Function + ): any { return (call: any) => { - const ctx = this._createContext(call); + const ctx = this._createContext(call) call.writeAll = (messages: any[]) => { if (Array.isArray(messages)) { messages.forEach(message => { - call.write(message); - }); + call.write(message) + }) } - }; - call.writeEnd = call.end; + } + call.writeEnd = call.end Promise.resolve().then(async () => { const handleResponse = async () => { - await target[key](call); - }; + await target[key](call) + } await composeFunc(ctx, handleResponse).catch((err: Error) => { - call.destroy(this._createInternalErrorStatus(err)); - }); - call.end(); - }); - }; + call.destroy(this._createInternalErrorStatus(err)) + }) + call.end() + }) + } } - private _callDuplexStreamProxyMethod(target: any, key: string, composeFunc: Function): any { + private _callDuplexStreamProxyMethod( + target: any, + key: string, + composeFunc: Function + ): any { return (call: any) => { - const ctx = this._createContext(call); + const ctx = this._createContext(call) call.writeAll = (messages: any[]) => { if (Array.isArray(messages)) { messages.forEach(message => { - call.write(message); - }); + call.write(message) + }) } - }; + } call.readAll = () => { return iterator(call, 'data', { resolutionEvents: ['end'] - }); - }; + }) + } Promise.resolve().then(async () => { const handleResponse = async () => { - await target[key](call); - }; + await target[key](call) + } await composeFunc(ctx, handleResponse).catch((err: Error) => { - call.destroy(this._createInternalErrorStatus(err)); - }); - call.end(); - }); - }; + call.destroy(this._createInternalErrorStatus(err)) + }) + call.end() + }) + } } private _createInternalErrorStatus(err: any): any { - err.code = err.code || 13; + err.code = err.code || 13 if (typeof err.stack === 'string') { - const stack = err.stack.split('\n'); - err.messages += ` [Error Message From Server, stack: ${stack[1].trim()}]`; + const stack = err.stack.split('\n') + err.messages += ` [Error Message From Server, stack: ${stack[1].trim()}]` } else { - err.messages += ' [Error Message From Server]'; + err.messages += ' [Error Message From Server]' } - return err; + return err } } -export default ServerProxy; +export default ServerProxy diff --git a/src/schema/loader.ts b/src/schema/loader.ts index 5632fbb..251f484 100644 --- a/src/schema/loader.ts +++ b/src/schema/loader.ts @@ -1,21 +1,25 @@ -import Joi from 'joi'; +import Joi from 'joi' -const addressSchema = Joi.object() - .pattern(/\.*/, Joi.alternatives([ +const addressSchema = Joi.object().pattern( + /\.*/, + Joi.alternatives([ Joi.string().regex(/:/, 'host and port like 127.0.0.1:9090'), Joi.object({ host: Joi.string().required(), port: Joi.number().integer().min(0).max(65535).required() }) - ])); + ]) +) const loaderSchemas = { - constructor: Joi.array().items( - Joi.object({ - location: Joi.string().required(), - files: Joi.array().items(Joi.string()).required() - }) - ).single(), + constructor: Joi.array() + .items( + Joi.object({ + location: Joi.string().required(), + files: Joi.array().items(Joi.string()).required() + }) + ) + .single(), init: Joi.object({ services: addressSchema.optional(), isDev: Joi.boolean().optional(), @@ -28,6 +32,6 @@ const loaderSchemas = { services: addressSchema.required(), channelOptions: Joi.object().optional() }) -}; +} -export default loaderSchemas; +export default loaderSchemas diff --git a/src/schema/server.ts b/src/schema/server.ts index 3b22adf..bf087a6 100644 --- a/src/schema/server.ts +++ b/src/schema/server.ts @@ -1,4 +1,4 @@ -import Joi from 'joi'; +import Joi from 'joi' const serverSchemas = { address: Joi.alternatives([ @@ -8,6 +8,6 @@ const serverSchemas = { port: Joi.number().integer().min(0).max(65535).required() }) ]) -}; +} -export default serverSchemas; +export default serverSchemas diff --git a/src/util/compose.ts b/src/util/compose.ts index 1a44caa..5a90a51 100644 --- a/src/util/compose.ts +++ b/src/util/compose.ts @@ -1,7 +1,7 @@ export type MiddlewareFunction = ( context: any, next: () => Promise -) => Promise; +) => Promise /** * Compose `middleware` returning @@ -14,28 +14,28 @@ export type MiddlewareFunction = ( */ export const compose = (middleware: MiddlewareFunction[]) => { if (!Array.isArray(middleware)) - throw new TypeError("Middleware stack must be an array!"); + throw new TypeError('Middleware stack must be an array!') for (const fn of middleware) { - if (typeof fn !== "function") - throw new TypeError("Middleware must be composed of functions!"); + if (typeof fn !== 'function') + throw new TypeError('Middleware must be composed of functions!') } return function (context: any, next: () => Promise) { // last called middleware # - let index = -1; - return dispatch(0); + let index = -1 + return dispatch(0) function dispatch(i: number): Promise { if (i <= index) - return Promise.reject(new Error("next() called multiple times")); - index = i; - let fn = middleware[i]; - if (i === middleware.length) fn = next; - if (!fn) return Promise.resolve(); + return Promise.reject(new Error('next() called multiple times')) + index = i + let fn = middleware[i] + if (i === middleware.length) fn = next + if (!fn) return Promise.resolve() try { - return Promise.resolve(fn(context, dispatch.bind(null, i + 1))); + return Promise.resolve(fn(context, dispatch.bind(null, i + 1))) } catch (err) { - return Promise.reject(err); + return Promise.reject(err) } } - }; -}; + } +} diff --git a/src/util/iterator.ts b/src/util/iterator.ts index 2881a9f..c12cbbd 100644 --- a/src/util/iterator.ts +++ b/src/util/iterator.ts @@ -1,200 +1,196 @@ -const symbolAsyncIterator = Symbol.asyncIterator || "@@asyncIterator"; +const symbolAsyncIterator = Symbol.asyncIterator || '@@asyncIterator' const normalizeEmitter = ( emitter: any ): { addListener: Function; removeListener: Function } => { const addListener = - emitter.on || emitter.addListener || emitter.addEventListener; + emitter.on || emitter.addListener || emitter.addEventListener const removeListener = - emitter.off || emitter.removeListener || emitter.removeEventListener; + emitter.off || emitter.removeListener || emitter.removeEventListener if (!addListener || !removeListener) { - throw new TypeError("Emitter is not compatible"); + throw new TypeError('Emitter is not compatible') } return { addListener: addListener.bind(emitter), - removeListener: removeListener.bind(emitter), - }; -}; - -const toArray = (value: any): any[] => (Array.isArray(value) ? value : [value]); - -export default ( - emitter: any, - event: string | string[], - options: any -) => { - if (typeof options === "function") { - options = { filter: options }; + removeListener: removeListener.bind(emitter) + } +} + +const toArray = (value: any): any[] => (Array.isArray(value) ? value : [value]) + +export default (emitter: any, event: string | string[], options: any) => { + if (typeof options === 'function') { + options = { filter: options } } // Allow multiple events - const events = toArray(event); + const events = toArray(event) options = { - rejectionEvents: ["error"], + rejectionEvents: ['error'], resolutionEvents: [], limit: Infinity, multiArgs: false, - ...options, - }; + ...options + } - const { limit } = options; + const { limit } = options const isValidLimit = - limit >= 0 && (limit === Infinity || Number.isInteger(limit)); + limit >= 0 && (limit === Infinity || Number.isInteger(limit)) if (!isValidLimit) { throw new TypeError( - "The `limit` option should be a non-negative integer or Infinity" - ); + 'The `limit` option should be a non-negative integer or Infinity' + ) } if (limit === 0) { // Return an empty async iterator to avoid any further cost return { [Symbol.asyncIterator](): any { - return this; + return this }, async next(): Promise<{ done: boolean; value: any }> { return { done: true, - value: undefined, - }; - }, - }; + value: undefined + } + } + } } - const { addListener, removeListener } = normalizeEmitter(emitter); + const { addListener, removeListener } = normalizeEmitter(emitter) - let isDone = false; - let error: any; - let hasPendingError = false; - const nextQueue: { resolve: Function; reject: Function }[] = []; - const valueQueue: any[] = []; - let eventCount = 0; - let isLimitReached = false; + let isDone = false + let error: any + let hasPendingError = false + const nextQueue: { resolve: Function; reject: Function }[] = [] + const valueQueue: any[] = [] + let eventCount = 0 + let isLimitReached = false const valueHandler = (...args: any[]): void => { - eventCount++; - isLimitReached = eventCount === limit; + eventCount++ + isLimitReached = eventCount === limit - const value = options.multiArgs ? args : args[0]; + const value = options.multiArgs ? args : args[0] if (nextQueue.length > 0) { - const { resolve } = nextQueue.shift()!; - resolve({ done: false, value }); + const { resolve } = nextQueue.shift()! + resolve({ done: false, value }) if (isLimitReached) { - cancel(); + cancel() } - return; + return } - valueQueue.push(value); + valueQueue.push(value) if (isLimitReached) { - cancel(); + cancel() } - }; + } const cancel = (): void => { - isDone = true; + isDone = true for (const event of events) { - removeListener(event, valueHandler); + removeListener(event, valueHandler) } for (const rejectionEvent of options.rejectionEvents!) { - removeListener(rejectionEvent, rejectHandler); + removeListener(rejectionEvent, rejectHandler) } for (const resolutionEvent of options.resolutionEvents!) { - removeListener(resolutionEvent, resolveHandler); + removeListener(resolutionEvent, resolveHandler) } while (nextQueue.length > 0) { - const { resolve } = nextQueue.shift()!; - resolve({ done: true, value: undefined }); + const { resolve } = nextQueue.shift()! + resolve({ done: true, value: undefined }) } - }; + } const rejectHandler = (...args: any[]): void => { - error = options.multiArgs ? args : args[0]; + error = options.multiArgs ? args : args[0] if (nextQueue.length > 0) { - const { reject } = nextQueue.shift()!; - reject(error); + const { reject } = nextQueue.shift()! + reject(error) } else { - hasPendingError = true; + hasPendingError = true } - cancel(); - }; + cancel() + } const resolveHandler = (...args: any[]): void => { - const value = options.multiArgs ? args : args[0]; + const value = options.multiArgs ? args : args[0] if (options.filter && !options.filter(value)) { - return; + return } if (nextQueue.length > 0) { - const { resolve } = nextQueue.shift()!; - resolve({ done: true, value }); + const { resolve } = nextQueue.shift()! + resolve({ done: true, value }) } else { - valueQueue.push(value); + valueQueue.push(value) } - cancel(); - }; + cancel() + } for (const event of events) { - addListener(event, valueHandler); + addListener(event, valueHandler) } for (const rejectionEvent of options.rejectionEvents!) { - addListener(rejectionEvent, rejectHandler); + addListener(rejectionEvent, rejectHandler) } for (const resolutionEvent of options.resolutionEvents!) { - addListener(resolutionEvent, resolveHandler); + addListener(resolutionEvent, resolveHandler) } return { [symbolAsyncIterator](): any { - return this; + return this }, async next(): Promise<{ done: boolean; value: any }> { if (valueQueue.length > 0) { - const value = valueQueue.shift(); + const value = valueQueue.shift() return { done: isDone && valueQueue.length === 0 && !isLimitReached, - value, - }; + value + } } if (hasPendingError) { - hasPendingError = false; - throw error; + hasPendingError = false + throw error } if (isDone) { return { done: true, - value: undefined, - }; + value: undefined + } } return new Promise((resolve, reject) => nextQueue.push({ resolve, reject }) - ); + ) }, async return(value: any): Promise<{ done: boolean; value: any }> { - cancel(); + cancel() return { done: isDone, - value, - }; - }, - }; -}; + value + } + } + } +} diff --git a/src/util/prefixingDefinition.ts b/src/util/prefixingDefinition.ts index d98b391..33654bc 100644 --- a/src/util/prefixingDefinition.ts +++ b/src/util/prefixingDefinition.ts @@ -1,24 +1,24 @@ export default (packageDefinition: any, packagePrefix: any) => { for (const qualifiedName in packageDefinition) { - const definition = packageDefinition[qualifiedName]; - const newPackage = `${packagePrefix}.${qualifiedName}`; + const definition = packageDefinition[qualifiedName] + const newPackage = `${packagePrefix}.${qualifiedName}` if ( definition.format && definition.type && definition.fileDescriptorProtos ) { - packageDefinition[newPackage] = definition; + packageDefinition[newPackage] = definition } else { - const newDefinition: any = {}; + const newDefinition: any = {} for (const method in definition) { - const service = definition[method]; + const service = definition[method] newDefinition[method] = Object.assign({}, service, { - path: service.path.replace(/^\//, `/${packagePrefix}.`), - }); + path: service.path.replace(/^\//, `/${packagePrefix}.`) + }) } - packageDefinition[newPackage] = newDefinition; + packageDefinition[newPackage] = newDefinition } } - return packageDefinition; -}; + return packageDefinition +} diff --git a/test/benchmark/README.md b/test/benchmark/README.md index 46b7d16..c516a52 100644 --- a/test/benchmark/README.md +++ b/test/benchmark/README.md @@ -17,6 +17,7 @@ ghz --insecure \ ``` result: + ``` Summary: Count: 10000 @@ -67,6 +68,7 @@ ghz --insecure \ ``` result: + ``` Summary: Count: 10000 diff --git a/test/benchmark/server-grpcity.js b/test/benchmark/server-grpcity.js index 8bdb980..30625bc 100755 --- a/test/benchmark/server-grpcity.js +++ b/test/benchmark/server-grpcity.js @@ -2,12 +2,12 @@ const GrpcLoader = require('../../types') const path = require('path') const implementation = { - sayHello: async (call) => { + sayHello: async call => { return { message: 'Hello ' + call.request.name } } } -const start = async (addr) => { +const start = async addr => { const loader = new GrpcLoader({ location: path.resolve(__dirname, './'), files: ['helloworld.proto'] diff --git a/test/benchmark/server-grpcjs.js b/test/benchmark/server-grpcjs.js index cf914a2..f5d892a 100644 --- a/test/benchmark/server-grpcjs.js +++ b/test/benchmark/server-grpcjs.js @@ -3,16 +3,13 @@ const protoLoader = require('@grpc/proto-loader') const path = require('path') const PROTO_PATH = path.resolve(__dirname, 'helloworld.proto') -const packageDefinition = protoLoader.loadSync( - PROTO_PATH, - { - keepCase: true, - longs: String, - enums: String, - defaults: true, - oneofs: true - } -) +const packageDefinition = protoLoader.loadSync(PROTO_PATH, { + keepCase: true, + longs: String, + enums: String, + defaults: true, + oneofs: true +}) const helloProto = grpc.loadPackageDefinition(packageDefinition).helloworld const implementation = { @@ -21,7 +18,7 @@ const implementation = { } } -const start = (addr) => { +const start = addr => { const server = new grpc.Server() server.addService(helloProto.Greeter.service, implementation) server.bindAsync(addr, grpc.ServerCredentials.createInsecure(), () => { diff --git a/test/client.js b/test/client.js index e75d373..c516c43 100755 --- a/test/client.js +++ b/test/client.js @@ -2,7 +2,7 @@ const GrpcLoader = require('../types') const path = require('path') const fs = require('fs') -const start = async (addr) => { +const start = async addr => { const loader = new GrpcLoader({ location: path.resolve(__dirname, 'protos'), files: ['test/helloworld/helloworld.proto'] @@ -33,8 +33,14 @@ const start = async (addr) => { }) // greeterClient - const greeterClient = loader.client('test.helloworld.Greeter', { credentials }) - const { status, metadata, response: result } = await greeterClient.sayHello({ name: 'greeter' }, meta) + const greeterClient = loader.client('test.helloworld.Greeter', { + credentials + }) + const { + status, + metadata, + response: result + } = await greeterClient.sayHello({ name: 'greeter' }, meta) console.log('greeterClient.sayHello', result) console.log('greeterClient.sayHello metadata', metadata) console.log('greeterClient.sayHello status', status) @@ -50,7 +56,9 @@ const start = async (addr) => { loader.closeClients() try { - const { response: result4 } = await hellorClient.sayHello({ name: 'hellor4' }) + const { response: result4 } = await hellorClient.sayHello({ + name: 'hellor4' + }) console.log('hellorClient.sayHello, must not log here', result4) } catch (error) { // reconnect @@ -61,7 +69,9 @@ const start = async (addr) => { credentials }) const newHellorClient = loader.client('test.helloworld.Hellor') - const { response: result5 } = await newHellorClient.sayHello({ name: 'hellor5' }) + const { response: result5 } = await newHellorClient.sayHello({ + name: 'hellor5' + }) console.log('newHellorClient.sayHello', result5) } } diff --git a/test/index.test.js b/test/index.test.js index 586ed91..dc5f1e6 100755 --- a/test/index.test.js +++ b/test/index.test.js @@ -4,11 +4,11 @@ const { expect } = require('chai') describe('Grpc Loader', () => { class Greeter { - async init (server) { + async init(server) { server.addService('test.helloworld.Greeter', this, { exclude: ['init'] }) } - async SayHello (call) { + async SayHello(call) { const metadata = call.metadata.clone() metadata.add('x-timestamp-server', 'received=' + new Date().toISOString()) call.sendMetadata(metadata) @@ -17,7 +17,7 @@ describe('Grpc Loader', () => { } if (metadata.get('x-long-delay').length > 0) { - await new Promise((resolve) => setTimeout(resolve, 1000 * 10)) + await new Promise(resolve => setTimeout(resolve, 1000 * 10)) } expect(this).to.be.an('object') @@ -25,7 +25,7 @@ describe('Grpc Loader', () => { return { message: `hello, ${call.request.name || 'world'}` } } - async SayHello2 (call) { + async SayHello2(call) { return this.SayHello(call) } } @@ -57,13 +57,20 @@ describe('Grpc Loader', () => { // 支持相同service的client访问不同host和port const timeout = 20 - const client2 = loader.client('test.helloworld.Greeter', { host: 'localhost', port: 12305, timeout }) + const client2 = loader.client('test.helloworld.Greeter', { + host: 'localhost', + port: 12305, + timeout + }) const { response: result2 } = await client2.sayHello({ name: 'grpc' }) expect(result2).to.be.an('object') expect(result2.message).to.be.eq('hello, grpc') try { - await client2.sayHello({ name: 'grpc' }, loader.makeMetadata({ 'x-throw-error': 'true' })) + await client2.sayHello( + { name: 'grpc' }, + loader.makeMetadata({ 'x-throw-error': 'true' }) + ) expect.fail('should not run here') } catch (err) { expect(/x-throw-error/.test(err.message)).to.be.eq(true) @@ -72,7 +79,10 @@ describe('Grpc Loader', () => { const start = Date.now() try { - await client2.sayHello({ name: 'grpc' }, loader.makeMetadata({ 'x-long-delay': 'true' })) + await client2.sayHello( + { name: 'grpc' }, + loader.makeMetadata({ 'x-long-delay': 'true' }) + ) expect.fail('should not run here') } catch (err) { expect(Date.now() - start).to.be.lte(timeout * 2) @@ -113,20 +123,28 @@ describe('Grpc Loader', () => { 'x-business-id': ['grpcity', 'testing'], 'x-timestamp-client': 'begin=' + timestampClientSend.toISOString() }) - const call = client.call.sayHello({ name: 'grpc' }, meta, (err, result) => { - if (err) { - reject(err) - return + const call = client.call.sayHello( + { name: 'grpc' }, + meta, + (err, result) => { + if (err) { + reject(err) + return + } + expect(result).to.be.an('object') + expect(result.message).to.be.eq('hello, grpc') + + resolve() } - expect(result).to.be.an('object') - expect(result.message).to.be.eq('hello, grpc') - - resolve() - }) + ) call.on('metadata', metadata => { - expect(metadata.get('x-cache-control')).to.be.an('array').deep.eq(['max-age=100']) - expect(metadata.get('x-business-id')).to.be.an('array').deep.eq(['grpcity, testing']) + expect(metadata.get('x-cache-control')) + .to.be.an('array') + .deep.eq(['max-age=100']) + expect(metadata.get('x-business-id')) + .to.be.an('array') + .deep.eq(['grpcity, testing']) const timestamps = metadata.get('x-timestamp-server') expect(timestamps).to.be.an('array').with.lengthOf(1) diff --git a/test/server.js b/test/server.js index 0d00b8a..e019d05 100755 --- a/test/server.js +++ b/test/server.js @@ -2,20 +2,20 @@ const GrpcLoader = require('../types') const path = require('path') const fs = require('fs') -const timeout = (ms) => { +const timeout = ms => { return new Promise((resolve, reject) => setTimeout(resolve, ms)) } class Greeter { - constructor () { + constructor() { this.count = 0 } - async init (server) { + async init(server) { server.addService('test.helloworld.Greeter', this, { exclude: ['init'] }) } - async SayHello (call) { + async SayHello(call) { const metadata = call.metadata.clone() metadata.add('x-timestamp-server', 'received=' + new Date().toISOString()) call.sendMetadata(metadata) @@ -24,25 +24,28 @@ class Greeter { } if (metadata.get('x-long-delay').length > 0) { - await new Promise((resolve) => setTimeout(resolve, 1000 * 10)) + await new Promise(resolve => setTimeout(resolve, 1000 * 10)) } await timeout(1000) this.count++ - return { message: `hello, ${call.request.name || 'world'}`, name_count: this.count } + return { + message: `hello, ${call.request.name || 'world'}`, + name_count: this.count + } } - async SayHello2 (call) { + async SayHello2(call) { return this.SayHello(call) } } class Hellor { - async init (server) { + async init(server) { server.addService('test.helloworld.Hellor', this, { exclude: ['init'] }) } - async SayHello (call) { + async SayHello(call) { const metadata = call.metadata.clone() metadata.add('x-timestamp-server', 'received=' + new Date().toISOString()) call.sendMetadata(metadata) @@ -51,13 +54,13 @@ class Hellor { } if (metadata.get('x-long-delay').length > 0) { - await new Promise((resolve) => setTimeout(resolve, 1000 * 10)) + await new Promise(resolve => setTimeout(resolve, 1000 * 10)) } return { message: `hello, ${call.request.name || 'world'}` } } - async SayHello2 (call) { + async SayHello2(call) { return this.SayHello(call) } } @@ -80,7 +83,7 @@ const middlewareB = async (ctx, next) => { console.log('middlewareB: 2', ctx, endTime, endTime - beginTime) } -const start = async (addr) => { +const start = async addr => { const loader = new GrpcLoader({ location: path.resolve(__dirname, 'protos'), files: ['test/helloworld/helloworld.proto'] @@ -100,10 +103,17 @@ const start = async (addr) => { await Promise.all(servicers.map(async s => s.init(server))) const credentials = server.makeServerCredentials( - fs.readFileSync(path.resolve(__dirname, 'certs/ca.crt')), [{ - private_key: fs.readFileSync(path.resolve(__dirname, 'certs/server.key')), - cert_chain: fs.readFileSync(path.resolve(__dirname, 'certs/server.crt')) - }], true) + fs.readFileSync(path.resolve(__dirname, 'certs/ca.crt')), + [ + { + private_key: fs.readFileSync( + path.resolve(__dirname, 'certs/server.key') + ), + cert_chain: fs.readFileSync(path.resolve(__dirname, 'certs/server.crt')) + } + ], + true + ) await server.listen(addr, credentials) console.log('start:', addr) diff --git a/test/stream/client-v2.js b/test/stream/client-v2.js index e9f1714..201c6d2 100644 --- a/test/stream/client-v2.js +++ b/test/stream/client-v2.js @@ -1,7 +1,7 @@ const GrpcLoader = require('../../types') const path = require('path') -const start = async (addr) => { +const start = async addr => { const loader = new GrpcLoader({ location: path.resolve(__dirname, './'), files: ['stream.proto'] @@ -37,7 +37,10 @@ const start = async (addr) => { console.log(writeResult) // client to stream server - const serverStreamHelloCall = client.serverStreamHello({ message: 'Hello! How are you?' }, meta) + const serverStreamHelloCall = client.serverStreamHello( + { message: 'Hello! How are you?' }, + meta + ) const serverReadAllResult = serverStreamHelloCall.readAll() for await (const data of serverReadAllResult) { console.log(data) diff --git a/test/stream/client.js b/test/stream/client.js index 788b458..df94db7 100644 --- a/test/stream/client.js +++ b/test/stream/client.js @@ -1,7 +1,7 @@ const GrpcLoader = require('../../types') const path = require('path') -const start = async (addr) => { +const start = async addr => { const loader = new GrpcLoader({ location: path.resolve(__dirname, './'), files: ['stream.proto'] @@ -35,20 +35,25 @@ const start = async (addr) => { }) // stream client to server - const clientStreamHelloCall = client.call.clientStreamHello(meta, (err, response) => { - if (err) { - console.log(err) - } else { - console.log(response) + const clientStreamHelloCall = client.call.clientStreamHello( + meta, + (err, response) => { + if (err) { + console.log(err) + } else { + console.log(response) + } } - }) + ) clientStreamHelloCall.write({ message: 'Hello!' }) clientStreamHelloCall.write({ message: 'How are you?' }) clientStreamHelloCall.end() // client to stream server - const serverStreamHelloCall = client.call.serverStreamHello({ message: 'Hello! How are you?' }) - serverStreamHelloCall.on('data', (chunk) => { + const serverStreamHelloCall = client.call.serverStreamHello({ + message: 'Hello! How are you?' + }) + serverStreamHelloCall.on('data', chunk => { console.log(chunk) }) serverStreamHelloCall.on('end', () => { @@ -61,7 +66,7 @@ const start = async (addr) => { mutualStreamHelloCall.write({ message: 'How are you?' }) mutualStreamHelloCall.write({ message: 'other thing x' }) - mutualStreamHelloCall.on('data', (data) => { + mutualStreamHelloCall.on('data', data => { console.log(data) if (data.message === 'delay 1s') { mutualStreamHelloCall.write({ message: 'ok, I known you delay 1s' }) diff --git a/test/stream/server-v2.js b/test/stream/server-v2.js index 367ebcb..9ff4615 100644 --- a/test/stream/server-v2.js +++ b/test/stream/server-v2.js @@ -1,17 +1,17 @@ const GrpcLoader = require('../../types') const path = require('path') -function timeout (ms) { +function timeout(ms) { return new Promise((resolve, reject) => setTimeout(resolve, ms)) } class Stream { - async unaryHello (call) { + async unaryHello(call) { console.log(call.request.message) return { message: 'hello ' + call.request.message } } - async clientStreamHello (call) { + async clientStreamHello(call) { const metadata = call.metadata.clone() metadata.add('x-timestamp-server', 'received=' + new Date().toISOString()) call.sendMetadata(metadata) @@ -22,7 +22,7 @@ class Stream { return { message: "Hello! I'm fine, thank you!" } } - async serverStreamHello (call) { + async serverStreamHello(call) { const metadata = call.metadata.clone() metadata.add('x-timestamp-server', 'received=' + new Date().toISOString()) call.sendMetadata(metadata) @@ -30,14 +30,11 @@ class Stream { console.log(call.request.message) call.write({ message: 'Hello! I got you message.' }) call.write({ message: "I'm fine, thank you" }) - call.writeAll([ - { message: 'other thing x' }, - { message: 'other thing y' } - ]) + call.writeAll([{ message: 'other thing x' }, { message: 'other thing y' }]) call.end() } - async mutualStreamHello (call) { + async mutualStreamHello(call) { const metadata = call.metadata.clone() metadata.add('x-timestamp-server', 'received=' + new Date().toISOString()) call.sendMetadata(metadata) @@ -49,13 +46,10 @@ class Stream { if (data.message === 'Hello!') { call.write({ message: 'Hello too.' }) } else if (data.message === 'How are you?') { - call.write({ message: 'I\'m fine, thank you' }) + call.write({ message: "I'm fine, thank you" }) await timeout(1000) call.write({ message: 'delay 1s' }) - call.writeAll([ - { message: 'emm... ' }, - { message: 'emm......' } - ]) + call.writeAll([{ message: 'emm... ' }, { message: 'emm......' }]) } else { call.write({ message: 'pardon?' }) } @@ -65,7 +59,7 @@ class Stream { } } -const start = async (addr) => { +const start = async addr => { const loader = new GrpcLoader({ location: path.resolve(__dirname, './'), files: ['stream.proto'] diff --git a/test/stream/server.js b/test/stream/server.js index 55df95a..33d26a5 100644 --- a/test/stream/server.js +++ b/test/stream/server.js @@ -2,21 +2,21 @@ const GrpcLoader = require('../../types') const path = require('path') class Stream { - constructor () { + constructor() { this.count = 0 } - unaryHello (call, callback) { + unaryHello(call, callback) { console.log(call.request.message) callback(null, { message: 'hello ' + call.request.message }) } - clientStreamHello (call, callback) { + clientStreamHello(call, callback) { const metadata = call.metadata.clone() metadata.add('x-timestamp-server', 'received=' + new Date().toISOString()) call.sendMetadata(metadata) - call.on('data', (data) => { + call.on('data', data => { console.log(data) }) call.on('end', () => { @@ -24,7 +24,7 @@ class Stream { }) } - serverStreamHello (call) { + serverStreamHello(call) { const metadata = call.metadata.clone() metadata.add('x-timestamp-server', 'received=' + new Date().toISOString()) call.sendMetadata(metadata) @@ -35,18 +35,18 @@ class Stream { call.end() } - mutualStreamHello (call) { + mutualStreamHello(call) { const metadata = call.metadata.clone() metadata.add('x-timestamp-server', 'received=' + new Date().toISOString()) call.sendMetadata(metadata) call.write({ message: 'emmm...' }) - call.on('data', (chunk) => { + call.on('data', chunk => { console.log(chunk.message) if (chunk.message === 'Hello!') { call.write({ message: 'Hello too.' }) } else if (chunk.message === 'How are you?') { - call.write({ message: 'I\'m fine, thank you' }) + call.write({ message: "I'm fine, thank you" }) setTimeout(() => { call.write({ message: 'delay 1s' }) }, 1000) @@ -63,7 +63,7 @@ class Stream { } } -const start = async (addr) => { +const start = async addr => { const loader = new GrpcLoader({ location: path.resolve(__dirname, './'), files: ['stream.proto'] diff --git a/tsconfig.json b/tsconfig.json index 5f6b2ac..a7fb047 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -8,4 +8,4 @@ "allowJs": true }, "include": ["src/*.ts"] -} \ No newline at end of file +} diff --git a/types/config/defaultChannelOptions.d.ts b/types/config/defaultChannelOptions.d.ts index 53d4c20..c6aaf26 100644 --- a/types/config/defaultChannelOptions.d.ts +++ b/types/config/defaultChannelOptions.d.ts @@ -1,2 +1,2 @@ -import { ChannelOptions } from "@grpc/grpc-js"; -export declare const defaultChannelOptions: ChannelOptions; +import { ChannelOptions } from '@grpc/grpc-js' +export declare const defaultChannelOptions: ChannelOptions diff --git a/types/config/defaultChannelOptions.js b/types/config/defaultChannelOptions.js index 3b76e03..f6aa22e 100644 --- a/types/config/defaultChannelOptions.js +++ b/types/config/defaultChannelOptions.js @@ -1,21 +1,21 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.defaultChannelOptions = void 0; +'use strict' +Object.defineProperty(exports, '__esModule', { value: true }) +exports.defaultChannelOptions = void 0 exports.defaultChannelOptions = { - "grpc.min_reconnect_backoff_ms": 1000, - "grpc.max_reconnect_backoff_ms": 10000, - "grpc.grpclb_call_timeout_ms": 5000, - "grpc.keepalive_timeout_ms": 20 * 1000, - "grpc.keepalive_time_ms": 120 * 1000, - "grpc.keepalive_permit_without_calls": 1, - "grpc.enable_retries": 1, - "grpc.service_config": JSON.stringify({ - retryPolicy: { - maxAttempts: 4, - initialBackoff: "0.1s", - maxBackoff: "1s", - backoffMultiplier: 2, - retryableStatusCodes: ["UNAVAILABLE"], - }, - }), -}; + 'grpc.min_reconnect_backoff_ms': 1000, + 'grpc.max_reconnect_backoff_ms': 10000, + 'grpc.grpclb_call_timeout_ms': 5000, + 'grpc.keepalive_timeout_ms': 20 * 1000, + 'grpc.keepalive_time_ms': 120 * 1000, + 'grpc.keepalive_permit_without_calls': 1, + 'grpc.enable_retries': 1, + 'grpc.service_config': JSON.stringify({ + retryPolicy: { + maxAttempts: 4, + initialBackoff: '0.1s', + maxBackoff: '1s', + backoffMultiplier: 2, + retryableStatusCodes: ['UNAVAILABLE'] + } + }) +} diff --git a/types/config/defaultLoadOptions.d.ts b/types/config/defaultLoadOptions.d.ts index 9d1f2e1..684e049 100644 --- a/types/config/defaultLoadOptions.d.ts +++ b/types/config/defaultLoadOptions.d.ts @@ -1,2 +1,2 @@ -import { Options } from '@grpc/proto-loader'; -export declare const defaultLoadOptions: Options; +import { Options } from '@grpc/proto-loader' +export declare const defaultLoadOptions: Options diff --git a/types/config/defaultLoadOptions.js b/types/config/defaultLoadOptions.js index af6fc55..1d4728f 100644 --- a/types/config/defaultLoadOptions.js +++ b/types/config/defaultLoadOptions.js @@ -1,10 +1,10 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.defaultLoadOptions = void 0; +'use strict' +Object.defineProperty(exports, '__esModule', { value: true }) +exports.defaultLoadOptions = void 0 exports.defaultLoadOptions = { - keepCase: true, - longs: String, - enums: String, - defaults: false, - oneofs: true, -}; + keepCase: true, + longs: String, + enums: String, + defaults: false, + oneofs: true +} diff --git a/types/index.d.ts b/types/index.d.ts index 7256de4..6b08ff7 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -1,31 +1,52 @@ -import * as grpc from '@grpc/grpc-js'; -import ServerProxy from './proxy/serverProxy'; +import * as grpc from '@grpc/grpc-js' +import ServerProxy from './proxy/serverProxy' declare class GrpcLoader { - private _protoFiles; - private _clientMap; - private _clientAddrMap; - private _types; - private _packagePrefix?; - private _appName?; - private _packageDefinition; - private _isDev?; - private _reflectedRoot; - private _insecureCredentials?; - private _initDefaultClient?; - constructor(protoFileOptions: any); - init({ services, isDev, packagePrefix, loadOptions, channelOptions, appName }?: any): Promise; - initClients({ services, channelOptions, credentials }: any): Promise; - closeClients(): void; - makeCredentials(rootCerts?: any, privateKey?: any, certChain?: any, verifyOptions?: any): grpc.ChannelCredentials; - service(name: string): any; - type(name: string): any; - message(name: string): any; - client(name: string, { host, port, timeout, credentials, channelOptions }?: any): any; - realClient(name: string, { host, port, credentials, channelOptions }?: any): any; - clientWithoutCache(name: string, { addr, timeout, credentials, channelOptions }?: any): any; - private _makeClient; - private _makeClientWithoutCache; - makeMetadata(initialValues: any): grpc.Metadata; - initServer(...args: any[]): ServerProxy; + private _protoFiles + private _clientMap + private _clientAddrMap + private _types + private _packagePrefix? + private _appName? + private _packageDefinition + private _isDev? + private _reflectedRoot + private _insecureCredentials? + private _initDefaultClient? + constructor(protoFileOptions: any) + init({ + services, + isDev, + packagePrefix, + loadOptions, + channelOptions, + appName + }?: any): Promise + initClients({ services, channelOptions, credentials }: any): Promise + closeClients(): void + makeCredentials( + rootCerts?: any, + privateKey?: any, + certChain?: any, + verifyOptions?: any + ): grpc.ChannelCredentials + service(name: string): any + type(name: string): any + message(name: string): any + client( + name: string, + { host, port, timeout, credentials, channelOptions }?: any + ): any + realClient( + name: string, + { host, port, credentials, channelOptions }?: any + ): any + clientWithoutCache( + name: string, + { addr, timeout, credentials, channelOptions }?: any + ): any + private _makeClient + private _makeClientWithoutCache + makeMetadata(initialValues: any): grpc.Metadata + initServer(...args: any[]): ServerProxy } -export default GrpcLoader; +export default GrpcLoader diff --git a/types/index.js b/types/index.js index e8e20c4..d494151 100644 --- a/types/index.js +++ b/types/index.js @@ -1,223 +1,369 @@ -"use strict"; -var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - var desc = Object.getOwnPropertyDescriptor(m, k); - if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { - desc = { enumerable: true, get: function() { return m[k]; } }; - } - Object.defineProperty(o, k2, desc); -}) : (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - o[k2] = m[k]; -})); -var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { - Object.defineProperty(o, "default", { enumerable: true, value: v }); -}) : function(o, v) { - o["default"] = v; -}); -var __importStar = (this && this.__importStar) || function (mod) { - if (mod && mod.__esModule) return mod; - var result = {}; - if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); - __setModuleDefault(result, mod); - return result; -}; -var __importDefault = (this && this.__importDefault) || function (mod) { - return (mod && mod.__esModule) ? mod : { "default": mod }; -}; -Object.defineProperty(exports, "__esModule", { value: true }); -const node_assert_1 = __importDefault(require("node:assert")); -const grpc = __importStar(require("@grpc/grpc-js")); -const protoLoader = __importStar(require("@grpc/proto-loader")); -const protobuf = __importStar(require("protobufjs")); -const Descriptor = __importStar(require("protobufjs/ext/descriptor")); -const _ = __importStar(require("lodash")); -const Joi = __importStar(require("joi")); -const loader_1 = __importDefault(require("./schema/loader")); -const prefixingDefinition_1 = __importDefault(require("./util/prefixingDefinition")); -const defaultChannelOptions_1 = require("./config/defaultChannelOptions"); -const defaultLoadOptions_1 = require("./config/defaultLoadOptions"); -const clientProxy_1 = __importDefault(require("./proxy/clientProxy")); -const serverProxy_1 = __importDefault(require("./proxy/serverProxy")); -class GrpcLoader { - constructor(protoFileOptions) { - Joi.assert(protoFileOptions, loader_1.default.constructor, 'new GrpcLoader() params Error'); - this._protoFiles = Array.isArray(protoFileOptions) ? protoFileOptions : [protoFileOptions]; - this._clientMap = new Map(); - this._clientAddrMap = new Map(); - } - async init({ services = undefined, isDev = false, packagePrefix = '', loadOptions = {}, channelOptions = {}, appName } = {}) { - Joi.assert({ services, loadOptions, isDev, channelOptions, appName }, loader_1.default.init, 'GrpcLoader.init() params Error'); - if (this._types) { - return; - } - try { - loadOptions = Object.assign({}, defaultLoadOptions_1.defaultLoadOptions, loadOptions); - this._isDev = isDev; - this._packagePrefix = packagePrefix; - this._appName = appName; - loadOptions.includeDirs = this._protoFiles.map((p) => p.location).concat(loadOptions.includeDirs || []); - const files = this._protoFiles.reduce((result, p) => { - if (p.files && p.files.length > 0) { - result.push(...p.files); - } - return result; - }, []); - const packageDefinition = await protoLoader.load(files, loadOptions); - if (this._packagePrefix) { - this._packageDefinition = (0, prefixingDefinition_1.default)(packageDefinition, packagePrefix); +'use strict' +var __createBinding = + (this && this.__createBinding) || + (Object.create + ? function (o, m, k, k2) { + if (k2 === undefined) k2 = k + var desc = Object.getOwnPropertyDescriptor(m, k) + if ( + !desc || + ('get' in desc ? !m.__esModule : desc.writable || desc.configurable) + ) { + desc = { + enumerable: true, + get: function () { + return m[k] } - else { - this._packageDefinition = packageDefinition; - } - this._types = grpc.loadPackageDefinition(this._packageDefinition); - } - catch (err) { - throw err; - } - if (services) { - await this.initClients({ services, channelOptions }); + } } + Object.defineProperty(o, k2, desc) + } + : function (o, m, k, k2) { + if (k2 === undefined) k2 = k + o[k2] = m[k] + }) +var __setModuleDefault = + (this && this.__setModuleDefault) || + (Object.create + ? function (o, v) { + Object.defineProperty(o, 'default', { enumerable: true, value: v }) + } + : function (o, v) { + o['default'] = v + }) +var __importStar = + (this && this.__importStar) || + function (mod) { + if (mod && mod.__esModule) return mod + var result = {} + if (mod != null) + for (var k in mod) + if (k !== 'default' && Object.prototype.hasOwnProperty.call(mod, k)) + __createBinding(result, mod, k) + __setModuleDefault(result, mod) + return result + } +var __importDefault = + (this && this.__importDefault) || + function (mod) { + return mod && mod.__esModule ? mod : { default: mod } + } +Object.defineProperty(exports, '__esModule', { value: true }) +const node_assert_1 = __importDefault(require('node:assert')) +const grpc = __importStar(require('@grpc/grpc-js')) +const protoLoader = __importStar(require('@grpc/proto-loader')) +const protobuf = __importStar(require('protobufjs')) +const Descriptor = __importStar(require('protobufjs/ext/descriptor')) +const _ = __importStar(require('lodash')) +const Joi = __importStar(require('joi')) +const loader_1 = __importDefault(require('./schema/loader')) +const prefixingDefinition_1 = __importDefault( + require('./util/prefixingDefinition') +) +const defaultChannelOptions_1 = require('./config/defaultChannelOptions') +const defaultLoadOptions_1 = require('./config/defaultLoadOptions') +const clientProxy_1 = __importDefault(require('./proxy/clientProxy')) +const serverProxy_1 = __importDefault(require('./proxy/serverProxy')) +class GrpcLoader { + constructor(protoFileOptions) { + Joi.assert( + protoFileOptions, + loader_1.default.constructor, + 'new GrpcLoader() params Error' + ) + this._protoFiles = Array.isArray(protoFileOptions) + ? protoFileOptions + : [protoFileOptions] + this._clientMap = new Map() + this._clientAddrMap = new Map() + } + async init({ + services = undefined, + isDev = false, + packagePrefix = '', + loadOptions = {}, + channelOptions = {}, + appName + } = {}) { + Joi.assert( + { services, loadOptions, isDev, channelOptions, appName }, + loader_1.default.init, + 'GrpcLoader.init() params Error' + ) + if (this._types) { + return } - async initClients({ services, channelOptions = {}, credentials = undefined }) { - Joi.assert({ services, channelOptions }, loader_1.default.initClients, 'GrpcLoader.initClients() Options Error'); - if (this._initDefaultClient) { - return; - } - if (!this._packageDefinition) { - await this.init(); + try { + loadOptions = Object.assign( + {}, + defaultLoadOptions_1.defaultLoadOptions, + loadOptions + ) + this._isDev = isDev + this._packagePrefix = packagePrefix + this._appName = appName + loadOptions.includeDirs = this._protoFiles + .map(p => p.location) + .concat(loadOptions.includeDirs || []) + const files = this._protoFiles.reduce((result, p) => { + if (p.files && p.files.length > 0) { + result.push(...p.files) } - const serviceNames = Object.keys(services); - serviceNames.forEach((name) => { - const isDefaultClient = true; - const addr = _.isString(services[name]) ? services[name] : services[name].host + ':' + services[name].port; - this._makeClient(isDefaultClient, name, addr, credentials, channelOptions); - }); - this._initDefaultClient = true; + return result + }, []) + const packageDefinition = await protoLoader.load(files, loadOptions) + if (this._packagePrefix) { + this._packageDefinition = (0, prefixingDefinition_1.default)( + packageDefinition, + packagePrefix + ) + } else { + this._packageDefinition = packageDefinition + } + this._types = grpc.loadPackageDefinition(this._packageDefinition) + } catch (err) { + throw err } - closeClients() { - this._clientMap.forEach((client, key) => { - if (client && typeof client.close === 'function') { - client.close(); - } - }); - this._clientMap.clear(); - this._clientAddrMap.clear(); - this._initDefaultClient = false; + if (services) { + await this.initClients({ services, channelOptions }) } - makeCredentials(rootCerts, privateKey, certChain, verifyOptions) { - if (rootCerts && privateKey && certChain) { - return grpc.credentials.createSsl(rootCerts, privateKey, certChain, verifyOptions); - } - else { - if (!this._insecureCredentials) { - this._insecureCredentials = grpc.credentials.createInsecure(); - } - return this._insecureCredentials; - } + } + async initClients({ + services, + channelOptions = {}, + credentials = undefined + }) { + Joi.assert( + { services, channelOptions }, + loader_1.default.initClients, + 'GrpcLoader.initClients() Options Error' + ) + if (this._initDefaultClient) { + return } - service(name) { - (0, node_assert_1.default)(this._types, 'Must called init() first. proto file has not been loaded.'); - const fullName = this._isDev ? `${this._packagePrefix}.${name}` : name; - const service = _.get(this._types, `${fullName}.service`); - (0, node_assert_1.default)(service, `Cannot find service with name: ${fullName}, please check if the protos file is configured incorrectly or if the corresponding proto file is missing.`); - return service; + if (!this._packageDefinition) { + await this.init() } - type(name) { - (0, node_assert_1.default)(this._types, 'Must called init() first. proto file has not been loaded.'); - const fullName = this._isDev ? `${this._packagePrefix}.${name}` : name; - const type = _.get(this._types, `${fullName}`); - (0, node_assert_1.default)(type, `Cannot find type with name: ${fullName}, please check if the protos file is configured incorrectly or if the corresponding proto file is missing.`); - return type; + const serviceNames = Object.keys(services) + serviceNames.forEach(name => { + const isDefaultClient = true + const addr = _.isString(services[name]) + ? services[name] + : services[name].host + ':' + services[name].port + this._makeClient(isDefaultClient, name, addr, credentials, channelOptions) + }) + this._initDefaultClient = true + } + closeClients() { + this._clientMap.forEach((client, key) => { + if (client && typeof client.close === 'function') { + client.close() + } + }) + this._clientMap.clear() + this._clientAddrMap.clear() + this._initDefaultClient = false + } + makeCredentials(rootCerts, privateKey, certChain, verifyOptions) { + if (rootCerts && privateKey && certChain) { + return grpc.credentials.createSsl( + rootCerts, + privateKey, + certChain, + verifyOptions + ) + } else { + if (!this._insecureCredentials) { + this._insecureCredentials = grpc.credentials.createInsecure() + } + return this._insecureCredentials } - message(name) { - let root = this._reflectedRoot; - if (root) { - const found = root.lookupType(name); - if (found) { - return found; - } - } - const descriptor = this.type(name).fileDescriptorProtos.map((proto) => Descriptor.FileDescriptorProto.decode(proto)); - root = protobuf.Root.fromDescriptor({ file: descriptor }); - this._reflectedRoot = root; - return root.lookupType(name); - } - client(name, { host = undefined, port = undefined, timeout = undefined, credentials = undefined, channelOptions = {} } = {}) { - const isDefaultClient = !(host && port); - const addr = `${host}:${port}`; - const cacheKeyPrefix = isDefaultClient ? 'defaultAddr' : addr.replace(/\./g, '-'); - const cacheKey = `proxy.${cacheKeyPrefix}.${name}.${timeout}`; - if (this._clientMap.has(cacheKey)) { - return this._clientMap.get(cacheKey); - } - else { - const client = this._makeClient(isDefaultClient, name, addr, credentials, channelOptions); - const appName = this._appName; - const proxy = clientProxy_1.default._proxy(client, { timeout }, appName); - this._clientMap.set(cacheKey, proxy); - return proxy; - } - } - realClient(name, { host = undefined, port = undefined, credentials = undefined, channelOptions = {} } = {}) { - const isDefaultClient = !(host && port); - const client = this._makeClient(isDefaultClient, name, `${host}:${port}`, credentials, channelOptions); - return client; + } + service(name) { + ;(0, node_assert_1.default)( + this._types, + 'Must called init() first. proto file has not been loaded.' + ) + const fullName = this._isDev ? `${this._packagePrefix}.${name}` : name + const service = _.get(this._types, `${fullName}.service`) + ;(0, node_assert_1.default)( + service, + `Cannot find service with name: ${fullName}, please check if the protos file is configured incorrectly or if the corresponding proto file is missing.` + ) + return service + } + type(name) { + ;(0, node_assert_1.default)( + this._types, + 'Must called init() first. proto file has not been loaded.' + ) + const fullName = this._isDev ? `${this._packagePrefix}.${name}` : name + const type = _.get(this._types, `${fullName}`) + ;(0, node_assert_1.default)( + type, + `Cannot find type with name: ${fullName}, please check if the protos file is configured incorrectly or if the corresponding proto file is missing.` + ) + return type + } + message(name) { + let root = this._reflectedRoot + if (root) { + const found = root.lookupType(name) + if (found) { + return found + } } - clientWithoutCache(name, { addr, timeout = undefined, credentials = undefined, channelOptions = {} } = {}) { - const client = this._makeClientWithoutCache(false, name, addr, credentials, channelOptions); - const appName = this._appName; - const proxy = clientProxy_1.default._proxy(client, { timeout }, appName); - return proxy; + const descriptor = this.type(name).fileDescriptorProtos.map(proto => + Descriptor.FileDescriptorProto.decode(proto) + ) + root = protobuf.Root.fromDescriptor({ file: descriptor }) + this._reflectedRoot = root + return root.lookupType(name) + } + client( + name, + { + host = undefined, + port = undefined, + timeout = undefined, + credentials = undefined, + channelOptions = {} + } = {} + ) { + const isDefaultClient = !(host && port) + const addr = `${host}:${port}` + const cacheKeyPrefix = isDefaultClient + ? 'defaultAddr' + : addr.replace(/\./g, '-') + const cacheKey = `proxy.${cacheKeyPrefix}.${name}.${timeout}` + if (this._clientMap.has(cacheKey)) { + return this._clientMap.get(cacheKey) + } else { + const client = this._makeClient( + isDefaultClient, + name, + addr, + credentials, + channelOptions + ) + const appName = this._appName + const proxy = clientProxy_1.default._proxy(client, { timeout }, appName) + this._clientMap.set(cacheKey, proxy) + return proxy } - _makeClient(isDefaultClient, name, addr, credentials, channelOptions = {}) { - const ctBool = !!credentials; - const cacheKeyPrefix = isDefaultClient ? 'defaultAddr' : addr.replace(/\./g, '-'); - const cacheKeyWithCt = `${cacheKeyPrefix}.${name}.${ctBool}`; - const cacheKey = `${cacheKeyPrefix}.${name}`; - if (this._clientMap.has(cacheKey)) { - return this._clientMap.get(cacheKey); - } - else if (this._clientMap.has(cacheKeyWithCt)) { - return this._clientMap.get(cacheKeyWithCt); - } - else { - let cacheAddr = addr; - if (addr === 'undefined:undefined') { - cacheAddr = this._clientAddrMap.get(name) || addr; - } - const client = this._makeClientWithoutCache(isDefaultClient, name, cacheAddr, credentials, channelOptions); - this._clientAddrMap.set(name, cacheAddr); - this._clientMap.set(cacheKey, client); - return client; - } - } - _makeClientWithoutCache(isDefaultClient, name, addr, credentials, channelOptions = {}) { - channelOptions = Object.assign({}, defaultChannelOptions_1.defaultChannelOptions, channelOptions); - const ServiceProto = this.type(name); - const client = new ServiceProto(addr, credentials || this.makeCredentials(), channelOptions); - return client; + } + realClient( + name, + { + host = undefined, + port = undefined, + credentials = undefined, + channelOptions = {} + } = {} + ) { + const isDefaultClient = !(host && port) + const client = this._makeClient( + isDefaultClient, + name, + `${host}:${port}`, + credentials, + channelOptions + ) + return client + } + clientWithoutCache( + name, + { + addr, + timeout = undefined, + credentials = undefined, + channelOptions = {} + } = {} + ) { + const client = this._makeClientWithoutCache( + false, + name, + addr, + credentials, + channelOptions + ) + const appName = this._appName + const proxy = clientProxy_1.default._proxy(client, { timeout }, appName) + return proxy + } + _makeClient(isDefaultClient, name, addr, credentials, channelOptions = {}) { + const ctBool = !!credentials + const cacheKeyPrefix = isDefaultClient + ? 'defaultAddr' + : addr.replace(/\./g, '-') + const cacheKeyWithCt = `${cacheKeyPrefix}.${name}.${ctBool}` + const cacheKey = `${cacheKeyPrefix}.${name}` + if (this._clientMap.has(cacheKey)) { + return this._clientMap.get(cacheKey) + } else if (this._clientMap.has(cacheKeyWithCt)) { + return this._clientMap.get(cacheKeyWithCt) + } else { + let cacheAddr = addr + if (addr === 'undefined:undefined') { + cacheAddr = this._clientAddrMap.get(name) || addr + } + const client = this._makeClientWithoutCache( + isDefaultClient, + name, + cacheAddr, + credentials, + channelOptions + ) + this._clientAddrMap.set(name, cacheAddr) + this._clientMap.set(cacheKey, client) + return client } - makeMetadata(initialValues) { - (0, node_assert_1.default)(this._types, 'Must called init() first. proto file has not been loaded.'); - const meta = new grpc.Metadata(); - if (typeof initialValues === 'object') { - Object.entries(initialValues).forEach(([key, value]) => { - if (Array.isArray(value)) { - value.map((v) => meta.add(key, _.isString(v) ? v : Buffer.from(v))); - } - else { - meta.add(key, _.isString(value) ? value : Buffer.from(value)); - } - }); + } + _makeClientWithoutCache( + isDefaultClient, + name, + addr, + credentials, + channelOptions = {} + ) { + channelOptions = Object.assign( + {}, + defaultChannelOptions_1.defaultChannelOptions, + channelOptions + ) + const ServiceProto = this.type(name) + const client = new ServiceProto( + addr, + credentials || this.makeCredentials(), + channelOptions + ) + return client + } + makeMetadata(initialValues) { + ;(0, node_assert_1.default)( + this._types, + 'Must called init() first. proto file has not been loaded.' + ) + const meta = new grpc.Metadata() + if (typeof initialValues === 'object') { + Object.entries(initialValues).forEach(([key, value]) => { + if (Array.isArray(value)) { + value.map(v => meta.add(key, _.isString(v) ? v : Buffer.from(v))) + } else { + meta.add(key, _.isString(value) ? value : Buffer.from(value)) } - return meta; - } - initServer(...args) { - (0, node_assert_1.default)(this._types, 'Must called init() first. proto file has not been loaded.'); - const server = new serverProxy_1.default(); - return server._init(this, ...args); + }) } + return meta + } + initServer(...args) { + ;(0, node_assert_1.default)( + this._types, + 'Must called init() first. proto file has not been loaded.' + ) + const server = new serverProxy_1.default() + return server._init(this, ...args) + } } -exports.default = GrpcLoader; -module.exports = GrpcLoader; +exports.default = GrpcLoader +module.exports = GrpcLoader diff --git a/types/proxy/clientProxy.d.ts b/types/proxy/clientProxy.d.ts index e6cac3d..e40a53a 100644 --- a/types/proxy/clientProxy.d.ts +++ b/types/proxy/clientProxy.d.ts @@ -1,15 +1,19 @@ -import { UntypedServiceImplementation } from '@grpc/grpc-js'; +import { UntypedServiceImplementation } from '@grpc/grpc-js' declare class ClientProxy { - private _getFuncStreamWay; - private _prepareMetadata; - private _handlerError; - private _setDeadline; - private _promisifyUnaryMethod; - private _promisifyClientStreamMethod; - private _promisifyServerStreamMethod; - private _promisifyDuplexStreamMethod; - private _keepCallbackMethod; - _proxy(client: UntypedServiceImplementation, defaultOptions?: Record, appName?: string): any; + private _getFuncStreamWay + private _prepareMetadata + private _handlerError + private _setDeadline + private _promisifyUnaryMethod + private _promisifyClientStreamMethod + private _promisifyServerStreamMethod + private _promisifyDuplexStreamMethod + private _keepCallbackMethod + _proxy( + client: UntypedServiceImplementation, + defaultOptions?: Record, + appName?: string + ): any } -declare const _default: ClientProxy; -export default _default; +declare const _default: ClientProxy +export default _default diff --git a/types/proxy/clientProxy.js b/types/proxy/clientProxy.js index 2e9a0b9..f8d862c 100644 --- a/types/proxy/clientProxy.js +++ b/types/proxy/clientProxy.js @@ -1,270 +1,327 @@ -"use strict"; -var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - var desc = Object.getOwnPropertyDescriptor(m, k); - if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { - desc = { enumerable: true, get: function() { return m[k]; } }; - } - Object.defineProperty(o, k2, desc); -}) : (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - o[k2] = m[k]; -})); -var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { - Object.defineProperty(o, "default", { enumerable: true, value: v }); -}) : function(o, v) { - o["default"] = v; -}); -var __importStar = (this && this.__importStar) || function (mod) { - if (mod && mod.__esModule) return mod; - var result = {}; - if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); - __setModuleDefault(result, mod); - return result; -}; -var __importDefault = (this && this.__importDefault) || function (mod) { - return (mod && mod.__esModule) ? mod : { "default": mod }; -}; -Object.defineProperty(exports, "__esModule", { value: true }); -const grpc_js_1 = require("@grpc/grpc-js"); -const os = __importStar(require("node:os")); -const iterator_1 = __importDefault(require("../util/iterator")); -class ClientProxy { - _getFuncStreamWay(func) { - const { requestStream, responseStream } = func; - return { requestStream, responseStream }; - } - _prepareMetadata(metadata, options, basicMeta) { - if (metadata instanceof grpc_js_1.Metadata) { - options = { ...options }; - } - else { - options = { ...metadata }; - metadata = new grpc_js_1.Metadata(); - } - if (basicMeta.hostname) { - metadata.add('x-client-hostname', basicMeta.hostname); - } - if (basicMeta.appName) { - metadata.add('x-client-app-name', basicMeta.appName); +'use strict' +var __createBinding = + (this && this.__createBinding) || + (Object.create + ? function (o, m, k, k2) { + if (k2 === undefined) k2 = k + var desc = Object.getOwnPropertyDescriptor(m, k) + if ( + !desc || + ('get' in desc ? !m.__esModule : desc.writable || desc.configurable) + ) { + desc = { + enumerable: true, + get: function () { + return m[k] + } + } } - return [metadata, options]; + Object.defineProperty(o, k2, desc) + } + : function (o, m, k, k2) { + if (k2 === undefined) k2 = k + o[k2] = m[k] + }) +var __setModuleDefault = + (this && this.__setModuleDefault) || + (Object.create + ? function (o, v) { + Object.defineProperty(o, 'default', { enumerable: true, value: v }) + } + : function (o, v) { + o['default'] = v + }) +var __importStar = + (this && this.__importStar) || + function (mod) { + if (mod && mod.__esModule) return mod + var result = {} + if (mod != null) + for (var k in mod) + if (k !== 'default' && Object.prototype.hasOwnProperty.call(mod, k)) + __createBinding(result, mod, k) + __setModuleDefault(result, mod) + return result + } +var __importDefault = + (this && this.__importDefault) || + function (mod) { + return mod && mod.__esModule ? mod : { default: mod } + } +Object.defineProperty(exports, '__esModule', { value: true }) +const grpc_js_1 = require('@grpc/grpc-js') +const os = __importStar(require('node:os')) +const iterator_1 = __importDefault(require('../util/iterator')) +class ClientProxy { + _getFuncStreamWay(func) { + const { requestStream, responseStream } = func + return { requestStream, responseStream } + } + _prepareMetadata(metadata, options, basicMeta) { + if (metadata instanceof grpc_js_1.Metadata) { + options = { ...options } + } else { + options = { ...metadata } + metadata = new grpc_js_1.Metadata() } - _handlerError(err, basicMeta) { - const newError = new Error(); - newError.name = 'GrpcClientError'; - newError.code = err.code; - newError.message = `${basicMeta.fullServiceName} (${err.message})`; - const stacks = newError.stack.split('\n'); - newError.stack = [ - stacks[0], - ...stacks.slice(2), - ' ...', - ...err.stack.split('\n').slice(1, 3), - ].join('\n'); - return newError; + if (basicMeta.hostname) { + metadata.add('x-client-hostname', basicMeta.hostname) } - _setDeadline(options, defaultOptions, basicMeta) { - if (!options.deadline) { - const timeout = options.timeout || defaultOptions.timeout; - const deadline = new Date(Date.now() + timeout); - options.deadline = deadline; - delete options.timeout; - } - return options; + if (basicMeta.appName) { + metadata.add('x-client-app-name', basicMeta.appName) } - _promisifyUnaryMethod(client, func, defaultOptions, basicMeta) { - const asyncUnaryMethod = async (request, metadata, options) => { - if (typeof options === 'function') { - throw new Error('gRPCity: AsyncFunction should not contain a callback function'); - } - else if (typeof metadata === 'function') { - throw new Error('gRPCity: AsyncFunction should not contain a callback function'); - } - [metadata, options] = this._prepareMetadata(metadata, options, basicMeta); - options = this._setDeadline(options, defaultOptions, basicMeta); - return new Promise((resolve, reject) => { - const result = {}; - const argumentsList = [request, metadata, options]; - argumentsList.push((err, response) => { - if (err) { - reject(this._handlerError(err, basicMeta)); - } - result.response = response; - }); - const call = func.apply(client, argumentsList); - call.on('metadata', (metadata) => { - result.metadata = metadata; - }); - call.on('status', (status) => { - result.status = status; - resolve(result); - }); - }); - }; - return asyncUnaryMethod; + return [metadata, options] + } + _handlerError(err, basicMeta) { + const newError = new Error() + newError.name = 'GrpcClientError' + newError.code = err.code + newError.message = `${basicMeta.fullServiceName} (${err.message})` + const stacks = newError.stack.split('\n') + newError.stack = [ + stacks[0], + ...stacks.slice(2), + ' ...', + ...err.stack.split('\n').slice(1, 3) + ].join('\n') + return newError + } + _setDeadline(options, defaultOptions, basicMeta) { + if (!options.deadline) { + const timeout = options.timeout || defaultOptions.timeout + const deadline = new Date(Date.now() + timeout) + options.deadline = deadline + delete options.timeout } - _promisifyClientStreamMethod(client, func, defaultOptions, basicMeta) { - const clientStreamMethod = (metadata, options) => { - if (typeof options === 'function') { - throw new Error('gRPCity: asyncStreamFunction should not contain a callback function'); - } - else if (typeof metadata === 'function') { - throw new Error('gRPCity: asyncStreamFunction should not contain a callback function'); - } - [metadata, options] = this._prepareMetadata(metadata, options, basicMeta); - options = this._setDeadline(options, defaultOptions, basicMeta); - const result = {}; - const argumentsList = [metadata, options]; - argumentsList.push((err, response) => { - if (err) { - throw this._handlerError(err, basicMeta); - } - result.response = response; - }); - const call = func.apply(client, argumentsList); - call.writeAll = (messages) => { - if (Array.isArray(messages)) { - messages.forEach((message) => { - call.write(message); - }); - } - }; - call.writeEnd = async () => { - call.end(); - await new Promise((resolve, reject) => { - call.on('metadata', (metadata) => { - result.metadata = metadata; - }); - call.on('status', (status) => { - result.status = status; - resolve(); - }); - }); - return result; - }; - return call; - }; - return clientStreamMethod; + return options + } + _promisifyUnaryMethod(client, func, defaultOptions, basicMeta) { + const asyncUnaryMethod = async (request, metadata, options) => { + if (typeof options === 'function') { + throw new Error( + 'gRPCity: AsyncFunction should not contain a callback function' + ) + } else if (typeof metadata === 'function') { + throw new Error( + 'gRPCity: AsyncFunction should not contain a callback function' + ) + } + ;[metadata, options] = this._prepareMetadata(metadata, options, basicMeta) + options = this._setDeadline(options, defaultOptions, basicMeta) + return new Promise((resolve, reject) => { + const result = {} + const argumentsList = [request, metadata, options] + argumentsList.push((err, response) => { + if (err) { + reject(this._handlerError(err, basicMeta)) + } + result.response = response + }) + const call = func.apply(client, argumentsList) + call.on('metadata', metadata => { + result.metadata = metadata + }) + call.on('status', status => { + result.status = status + resolve(result) + }) + }) } - _promisifyServerStreamMethod(client, func, defaultOptions, basicMeta) { - const serverStreamMethod = (request, metadata, options) => { - if (typeof options === 'function') { - throw new Error('gRPCity: asyncStreamFunction should not contain a callback function'); - } - else if (typeof metadata === 'function') { - throw new Error('gRPCity: asyncStreamFunction should not contain a callback function'); - } - [metadata, options] = this._prepareMetadata(metadata, options, basicMeta); - options = this._setDeadline(options, defaultOptions, basicMeta); - const call = func.apply(client, [request, metadata, options]); - call.on('error', (err) => { - throw this._handlerError(err, basicMeta); - }); - const result = {}; - call.readAll = () => { - call.on('metadata', (metadata) => { - result.metadata = metadata; - }); - call.on('status', (status) => { - result.status = status; - }); - return (0, iterator_1.default)(call, 'data', { - resolutionEvents: ['status', 'end'], - }); - }; - call.readEnd = () => { - return result; - }; - return call; - }; - return serverStreamMethod; + return asyncUnaryMethod + } + _promisifyClientStreamMethod(client, func, defaultOptions, basicMeta) { + const clientStreamMethod = (metadata, options) => { + if (typeof options === 'function') { + throw new Error( + 'gRPCity: asyncStreamFunction should not contain a callback function' + ) + } else if (typeof metadata === 'function') { + throw new Error( + 'gRPCity: asyncStreamFunction should not contain a callback function' + ) + } + ;[metadata, options] = this._prepareMetadata(metadata, options, basicMeta) + options = this._setDeadline(options, defaultOptions, basicMeta) + const result = {} + const argumentsList = [metadata, options] + argumentsList.push((err, response) => { + if (err) { + throw this._handlerError(err, basicMeta) + } + result.response = response + }) + const call = func.apply(client, argumentsList) + call.writeAll = messages => { + if (Array.isArray(messages)) { + messages.forEach(message => { + call.write(message) + }) + } + } + call.writeEnd = async () => { + call.end() + await new Promise((resolve, reject) => { + call.on('metadata', metadata => { + result.metadata = metadata + }) + call.on('status', status => { + result.status = status + resolve() + }) + }) + return result + } + return call } - _promisifyDuplexStreamMethod(client, func, defaultOptions, basicMeta) { - const duplexStreamMethod = (metadata, options) => { - if (typeof options === 'function') { - throw new Error('gRPCity: asyncStreamFunction should not contain a callback function'); - } - else if (typeof metadata === 'function') { - throw new Error('gRPCity: asyncStreamFunction should not contain a callback function'); - } - [metadata, options] = this._prepareMetadata(metadata, options, basicMeta); - options = this._setDeadline(options, defaultOptions, basicMeta); - const call = func.apply(client, [metadata, options]); - call.writeAll = (messages) => { - if (Array.isArray(messages)) { - messages.forEach((message) => { - call.write(message); - }); - } - }; - call.writeEnd = call.end; - call.on('error', (err) => { - throw this._handlerError(err, basicMeta); - }); - const result = {}; - call.readAll = () => { - call.on('metadata', (metadata) => { - result.metadata = metadata; - }); - call.on('status', (status) => { - result.status = status; - }); - return (0, iterator_1.default)(call, 'data', { - resolutionEvents: ['status', 'end'], - }); - }; - call.readEnd = () => { - return result; - }; - return call; - }; - return duplexStreamMethod; + return clientStreamMethod + } + _promisifyServerStreamMethod(client, func, defaultOptions, basicMeta) { + const serverStreamMethod = (request, metadata, options) => { + if (typeof options === 'function') { + throw new Error( + 'gRPCity: asyncStreamFunction should not contain a callback function' + ) + } else if (typeof metadata === 'function') { + throw new Error( + 'gRPCity: asyncStreamFunction should not contain a callback function' + ) + } + ;[metadata, options] = this._prepareMetadata(metadata, options, basicMeta) + options = this._setDeadline(options, defaultOptions, basicMeta) + const call = func.apply(client, [request, metadata, options]) + call.on('error', err => { + throw this._handlerError(err, basicMeta) + }) + const result = {} + call.readAll = () => { + call.on('metadata', metadata => { + result.metadata = metadata + }) + call.on('status', status => { + result.status = status + }) + return (0, iterator_1.default)(call, 'data', { + resolutionEvents: ['status', 'end'] + }) + } + call.readEnd = () => { + return result + } + return call } - _keepCallbackMethod(client, func) { - const callbackMethod = (...argumentsList) => { - return func.apply(client, argumentsList); - }; - return callbackMethod; + return serverStreamMethod + } + _promisifyDuplexStreamMethod(client, func, defaultOptions, basicMeta) { + const duplexStreamMethod = (metadata, options) => { + if (typeof options === 'function') { + throw new Error( + 'gRPCity: asyncStreamFunction should not contain a callback function' + ) + } else if (typeof metadata === 'function') { + throw new Error( + 'gRPCity: asyncStreamFunction should not contain a callback function' + ) + } + ;[metadata, options] = this._prepareMetadata(metadata, options, basicMeta) + options = this._setDeadline(options, defaultOptions, basicMeta) + const call = func.apply(client, [metadata, options]) + call.writeAll = messages => { + if (Array.isArray(messages)) { + messages.forEach(message => { + call.write(message) + }) + } + } + call.writeEnd = call.end + call.on('error', err => { + throw this._handlerError(err, basicMeta) + }) + const result = {} + call.readAll = () => { + call.on('metadata', metadata => { + result.metadata = metadata + }) + call.on('status', status => { + result.status = status + }) + return (0, iterator_1.default)(call, 'data', { + resolutionEvents: ['status', 'end'] + }) + } + call.readEnd = () => { + return result + } + return call } - _proxy(client, defaultOptions = {}, appName) { - defaultOptions = defaultOptions || {}; - defaultOptions.timeout = defaultOptions.timeout || 1000 * 10; - const prototype = Object.getPrototypeOf(client); - const methodNames = Object.keys(prototype) - .filter((key) => prototype[key] && prototype[key].path) - .reduce((names, key) => { - names[key.toUpperCase()] = prototype[key].path; - return names; - }, {}); - const basicMeta = { hostname: os.hostname(), appName }; - const target = Object.entries(prototype).reduce((target, [name, func]) => { - if (name !== 'constructor' && typeof func === 'function') { - basicMeta.fullServiceName = `${methodNames[name.toUpperCase()]}`; - const { requestStream, responseStream } = this._getFuncStreamWay(func); - if (!requestStream && !responseStream) { - // promisify unary method - target[name] = this._promisifyUnaryMethod(client, func, defaultOptions, basicMeta); - } - // stream - if (requestStream && !responseStream) { - // promisify only client stream method - target[name] = this._promisifyClientStreamMethod(client, func, defaultOptions, basicMeta); - } - if (!requestStream && responseStream) { - // promisify only server stream method - target[name] = this._promisifyServerStreamMethod(client, func, defaultOptions, basicMeta); - } - if (requestStream && responseStream) { - // promisify duplex stream method - target[name] = this._promisifyDuplexStreamMethod(client, func, defaultOptions, basicMeta); - } - // keep callback method - target.call[name] = this._keepCallbackMethod(client, func); - } - return target; - }, { call: {} }); - return target; + return duplexStreamMethod + } + _keepCallbackMethod(client, func) { + const callbackMethod = (...argumentsList) => { + return func.apply(client, argumentsList) } + return callbackMethod + } + _proxy(client, defaultOptions = {}, appName) { + defaultOptions = defaultOptions || {} + defaultOptions.timeout = defaultOptions.timeout || 1000 * 10 + const prototype = Object.getPrototypeOf(client) + const methodNames = Object.keys(prototype) + .filter(key => prototype[key] && prototype[key].path) + .reduce((names, key) => { + names[key.toUpperCase()] = prototype[key].path + return names + }, {}) + const basicMeta = { hostname: os.hostname(), appName } + const target = Object.entries(prototype).reduce( + (target, [name, func]) => { + if (name !== 'constructor' && typeof func === 'function') { + basicMeta.fullServiceName = `${methodNames[name.toUpperCase()]}` + const { requestStream, responseStream } = this._getFuncStreamWay(func) + if (!requestStream && !responseStream) { + // promisify unary method + target[name] = this._promisifyUnaryMethod( + client, + func, + defaultOptions, + basicMeta + ) + } + // stream + if (requestStream && !responseStream) { + // promisify only client stream method + target[name] = this._promisifyClientStreamMethod( + client, + func, + defaultOptions, + basicMeta + ) + } + if (!requestStream && responseStream) { + // promisify only server stream method + target[name] = this._promisifyServerStreamMethod( + client, + func, + defaultOptions, + basicMeta + ) + } + if (requestStream && responseStream) { + // promisify duplex stream method + target[name] = this._promisifyDuplexStreamMethod( + client, + func, + defaultOptions, + basicMeta + ) + } + // keep callback method + target.call[name] = this._keepCallbackMethod(client, func) + } + return target + }, + { call: {} } + ) + return target + } } -exports.default = new ClientProxy(); +exports.default = new ClientProxy() diff --git a/types/proxy/serverProxy.d.ts b/types/proxy/serverProxy.d.ts index d69cdb1..2b1467b 100644 --- a/types/proxy/serverProxy.d.ts +++ b/types/proxy/serverProxy.d.ts @@ -1,31 +1,45 @@ /// -import * as grpc from '@grpc/grpc-js'; -import { MiddlewareFunction } from '../util/compose'; +import * as grpc from '@grpc/grpc-js' +import { MiddlewareFunction } from '../util/compose' declare class ServerProxy { - private _middleware; - private _loader?; - private _server?; - private _insecureServerCredentials?; - constructor(); - _init(loader: any, ...args: any[]): this; - listen(addr: any, credentials?: grpc.ServerCredentials | undefined): Promise; - shutdown(): Promise; - forceShutdown(): void; - makeServerCredentials(rootCerts?: Buffer, keyCertPairs?: grpc.KeyCertPair[], checkClientCertificate?: boolean): grpc.ServerCredentials; - addService(name: string, implementation: any, { exclude, inherit }?: { - exclude?: string[]; - inherit?: any; - }): void; - removeService(name: string): void; - addMiddleware(...args: MiddlewareFunction[]): void; - private _use; - private _callbackify; - private _proxy; - private _createContext; - private _callUnaryProxyMethod; - private _callClientStreamProxyMethod; - private _callServerStreamProxyMethod; - private _callDuplexStreamProxyMethod; - private _createInternalErrorStatus; + private _middleware + private _loader? + private _server? + private _insecureServerCredentials? + constructor() + _init(loader: any, ...args: any[]): this + listen( + addr: any, + credentials?: grpc.ServerCredentials | undefined + ): Promise + shutdown(): Promise + forceShutdown(): void + makeServerCredentials( + rootCerts?: Buffer, + keyCertPairs?: grpc.KeyCertPair[], + checkClientCertificate?: boolean + ): grpc.ServerCredentials + addService( + name: string, + implementation: any, + { + exclude, + inherit + }?: { + exclude?: string[] + inherit?: any + } + ): void + removeService(name: string): void + addMiddleware(...args: MiddlewareFunction[]): void + private _use + private _callbackify + private _proxy + private _createContext + private _callUnaryProxyMethod + private _callClientStreamProxyMethod + private _callServerStreamProxyMethod + private _callDuplexStreamProxyMethod + private _createInternalErrorStatus } -export default ServerProxy; +export default ServerProxy diff --git a/types/proxy/serverProxy.js b/types/proxy/serverProxy.js index 3558df1..2bb4476 100644 --- a/types/proxy/serverProxy.js +++ b/types/proxy/serverProxy.js @@ -1,282 +1,343 @@ -"use strict"; -var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - var desc = Object.getOwnPropertyDescriptor(m, k); - if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { - desc = { enumerable: true, get: function() { return m[k]; } }; - } - Object.defineProperty(o, k2, desc); -}) : (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - o[k2] = m[k]; -})); -var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { - Object.defineProperty(o, "default", { enumerable: true, value: v }); -}) : function(o, v) { - o["default"] = v; -}); -var __importStar = (this && this.__importStar) || function (mod) { - if (mod && mod.__esModule) return mod; - var result = {}; - if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); - __setModuleDefault(result, mod); - return result; -}; -var __importDefault = (this && this.__importDefault) || function (mod) { - return (mod && mod.__esModule) ? mod : { "default": mod }; -}; -Object.defineProperty(exports, "__esModule", { value: true }); -const node_assert_1 = __importDefault(require("node:assert")); -const util = __importStar(require("node:util")); -const grpc = __importStar(require("@grpc/grpc-js")); -const _ = __importStar(require("lodash")); -const Joi = __importStar(require("joi")); -const server_1 = __importDefault(require("../schema/server")); -const iterator_1 = __importDefault(require("../util/iterator")); -const compose_1 = require("../util/compose"); +'use strict' +var __createBinding = + (this && this.__createBinding) || + (Object.create + ? function (o, m, k, k2) { + if (k2 === undefined) k2 = k + var desc = Object.getOwnPropertyDescriptor(m, k) + if ( + !desc || + ('get' in desc ? !m.__esModule : desc.writable || desc.configurable) + ) { + desc = { + enumerable: true, + get: function () { + return m[k] + } + } + } + Object.defineProperty(o, k2, desc) + } + : function (o, m, k, k2) { + if (k2 === undefined) k2 = k + o[k2] = m[k] + }) +var __setModuleDefault = + (this && this.__setModuleDefault) || + (Object.create + ? function (o, v) { + Object.defineProperty(o, 'default', { enumerable: true, value: v }) + } + : function (o, v) { + o['default'] = v + }) +var __importStar = + (this && this.__importStar) || + function (mod) { + if (mod && mod.__esModule) return mod + var result = {} + if (mod != null) + for (var k in mod) + if (k !== 'default' && Object.prototype.hasOwnProperty.call(mod, k)) + __createBinding(result, mod, k) + __setModuleDefault(result, mod) + return result + } +var __importDefault = + (this && this.__importDefault) || + function (mod) { + return mod && mod.__esModule ? mod : { default: mod } + } +Object.defineProperty(exports, '__esModule', { value: true }) +const node_assert_1 = __importDefault(require('node:assert')) +const util = __importStar(require('node:util')) +const grpc = __importStar(require('@grpc/grpc-js')) +const _ = __importStar(require('lodash')) +const Joi = __importStar(require('joi')) +const server_1 = __importDefault(require('../schema/server')) +const iterator_1 = __importDefault(require('../util/iterator')) +const compose_1 = require('../util/compose') class ServerProxy { - constructor() { - this._middleware = []; + constructor() { + this._middleware = [] + } + _init(loader, ...args) { + if (!this._loader) { + this._loader = loader } - _init(loader, ...args) { - if (!this._loader) { - this._loader = loader; - } - if (!this._server) { - this._server = new grpc.Server(...args); - } - return this; + if (!this._server) { + this._server = new grpc.Server(...args) } - async listen(addr, credentials = undefined) { - (0, node_assert_1.default)(this._server, 'must be first init() server before server listen()'); - Joi.assert(addr, server_1.default.address, 'server listen() params Error'); - const url = _.isString(addr) ? addr : `${addr.host}:${addr.port}`; - const bindPort = await new Promise((resolve, reject) => { - this._server.bindAsync(url, credentials || this.makeServerCredentials(), (err, result) => (err ? reject(err) : resolve(result))); - }); - const port = addr.port ? addr.port : Number(addr.match(/:(\d+)/)[1]); - (0, node_assert_1.default)(bindPort === port, 'server bind port not to be right'); - this._server.start(); + return this + } + async listen(addr, credentials = undefined) { + ;(0, node_assert_1.default)( + this._server, + 'must be first init() server before server listen()' + ) + Joi.assert(addr, server_1.default.address, 'server listen() params Error') + const url = _.isString(addr) ? addr : `${addr.host}:${addr.port}` + const bindPort = await new Promise((resolve, reject) => { + this._server.bindAsync( + url, + credentials || this.makeServerCredentials(), + (err, result) => (err ? reject(err) : resolve(result)) + ) + }) + const port = addr.port ? addr.port : Number(addr.match(/:(\d+)/)[1]) + ;(0, node_assert_1.default)( + bindPort === port, + 'server bind port not to be right' + ) + this._server.start() + } + async shutdown() { + if (!this._server) { + return } - async shutdown() { - if (!this._server) { - return; + await new Promise((resolve, reject) => { + this._server.tryShutdown(err => { + if (err) { + reject(err) + } else { + resolve() } - await new Promise((resolve, reject) => { - this._server.tryShutdown(err => { - if (err) { - reject(err); - } - else { - resolve(); - } - }); - }); - delete this._server; - delete this._loader; + }) + }) + delete this._server + delete this._loader + } + forceShutdown() { + if (!this._server) { + return } - forceShutdown() { - if (!this._server) { - return; - } - this._server.forceShutdown(); - delete this._server; - delete this._loader; + this._server.forceShutdown() + delete this._server + delete this._loader + } + makeServerCredentials(rootCerts, keyCertPairs, checkClientCertificate) { + if (rootCerts && keyCertPairs) { + return grpc.ServerCredentials.createSsl( + rootCerts, + keyCertPairs, + checkClientCertificate + ) + } else { + if (!this._insecureServerCredentials) { + this._insecureServerCredentials = + grpc.ServerCredentials.createInsecure() + } + return this._insecureServerCredentials } - makeServerCredentials(rootCerts, keyCertPairs, checkClientCertificate) { - if (rootCerts && keyCertPairs) { - return grpc.ServerCredentials.createSsl(rootCerts, keyCertPairs, checkClientCertificate); - } - else { - if (!this._insecureServerCredentials) { - this._insecureServerCredentials = grpc.ServerCredentials.createInsecure(); - } - return this._insecureServerCredentials; + } + addService(name, implementation, { exclude = [], inherit } = {}) { + const service = this._loader.service(name) + const options = { exclude, inherit, _implementationType: {} } + Object.keys(service).forEach(key => { + const { requestStream, responseStream } = service[key] + options._implementationType[service[key].originalName] = { + requestStream, + responseStream + } + }) + this._server.addService(service, this._callbackify(implementation, options)) + } + removeService(name) { + ;(0, node_assert_1.default)( + this._server, + 'must be first init() server before server removeService()' + ) + this._server.removeService(this._loader.service(name)) + } + addMiddleware(...args) { + ;(0, node_assert_1.default)( + args.length >= 1, + 'server addMiddleware() takes at least one argument.' + ) + if (args.length === 1) { + if (Array.isArray(args[0])) { + args[0].forEach(fn => { + this._use(fn) + }) + } else { + this._use(args[0]) + } + } else { + args.forEach(fn => { + this._use(fn) + }) + } + } + _use(fn) { + if (typeof fn !== 'function') + throw new TypeError( + 'grpcity loader server middleware must be a function!' + ) + this._middleware.push(fn) + } + _callbackify(target, { exclude = [], inherit, _implementationType }) { + ;(0, node_assert_1.default)( + typeof target === 'object', + 'Must callbackify an object' + ) + ;(0, node_assert_1.default)( + Array.isArray(exclude), + 'options.exclude must be an array of strings' + ) + const protoPropertyNames = Object.getOwnPropertyNames( + Object.getPrototypeOf({}) + ) + exclude.push(...protoPropertyNames) + const allPropertyNames = [ + ...new Set([ + ...Object.keys(target), + ...Object.getOwnPropertyNames(Object.getPrototypeOf(target)), + ...(inherit && inherit.prototype + ? Object.getOwnPropertyNames(inherit.prototype) + : []) + ]) + ] + const methods = {} + for (const key of allPropertyNames) { + const fn = target[key] + if ( + typeof fn === 'function' && + key !== 'constructor' && + !exclude.includes(key) + ) { + if (util.types.isAsyncFunction(fn)) { + const eglWrapFunction = this._proxy( + target, + key, + _implementationType[key] + ) + methods[key] = eglWrapFunction + } else { + methods[key] = fn } + } } - addService(name, implementation, { exclude = [], inherit } = {}) { - const service = this._loader.service(name); - const options = { exclude, inherit, _implementationType: {} }; - Object.keys(service).forEach(key => { - const { requestStream, responseStream } = service[key]; - options._implementationType[service[key].originalName] = { requestStream, responseStream }; - }); - this._server.addService(service, this._callbackify(implementation, options)); + return methods + } + _proxy(target, key, options = {}) { + const { requestStream, responseStream } = options + const fn = (0, compose_1.compose)(this._middleware) + // unary + if (!requestStream && !responseStream) { + return this._callUnaryProxyMethod(target, key, fn) } - removeService(name) { - (0, node_assert_1.default)(this._server, 'must be first init() server before server removeService()'); - this._server.removeService(this._loader.service(name)); + // client stream + if (requestStream && !responseStream) { + return this._callClientStreamProxyMethod(target, key, fn) } - addMiddleware(...args) { - (0, node_assert_1.default)(args.length >= 1, 'server addMiddleware() takes at least one argument.'); - if (args.length === 1) { - if (Array.isArray(args[0])) { - args[0].forEach(fn => { - this._use(fn); - }); - } - else { - this._use(args[0]); - } - } - else { - args.forEach(fn => { - this._use(fn); - }); - } + // server stream + if (!requestStream && responseStream) { + return this._callServerStreamProxyMethod(target, key, fn) } - _use(fn) { - if (typeof fn !== 'function') - throw new TypeError('grpcity loader server middleware must be a function!'); - this._middleware.push(fn); + // duplex stream + if (requestStream && responseStream) { + return this._callDuplexStreamProxyMethod(target, key, fn) } - _callbackify(target, { exclude = [], inherit, _implementationType }) { - (0, node_assert_1.default)(typeof target === 'object', 'Must callbackify an object'); - (0, node_assert_1.default)(Array.isArray(exclude), 'options.exclude must be an array of strings'); - const protoPropertyNames = Object.getOwnPropertyNames(Object.getPrototypeOf({})); - exclude.push(...protoPropertyNames); - const allPropertyNames = [ - ...new Set([ - ...Object.keys(target), - ...Object.getOwnPropertyNames(Object.getPrototypeOf(target)), - ...(inherit && inherit.prototype ? Object.getOwnPropertyNames(inherit.prototype) : []) - ]) - ]; - const methods = {}; - for (const key of allPropertyNames) { - const fn = target[key]; - if (typeof fn === 'function' && key !== 'constructor' && !exclude.includes(key)) { - if (util.types.isAsyncFunction(fn)) { - const eglWrapFunction = this._proxy(target, key, _implementationType[key]); - methods[key] = eglWrapFunction; - } - else { - methods[key] = fn; - } - } - } - return methods; + } + _createContext(call) { + return { + // TODO: maybe need more details + // method: target.constructor.name + '.' + key, + path: call.call.handler.path || '', + request: call.request, + metadata: call.metadata.clone() } - _proxy(target, key, options = {}) { - const { requestStream, responseStream } = options; - const fn = (0, compose_1.compose)(this._middleware); - // unary - if (!requestStream && !responseStream) { - return this._callUnaryProxyMethod(target, key, fn); + } + _callUnaryProxyMethod(target, key, composeFunc) { + return (call, callback) => { + const ctx = this._createContext(call) + Promise.resolve().then(async () => { + const handleResponse = async () => { + ctx.response = await target[key](call) } - // client stream - if (requestStream && !responseStream) { - return this._callClientStreamProxyMethod(target, key, fn); + await composeFunc(ctx, handleResponse).catch(err => { + callback(this._createInternalErrorStatus(err)) + }) + callback(null, ctx.response) + }) + } + } + _callClientStreamProxyMethod(target, key, composeFunc) { + return (call, callback) => { + const ctx = this._createContext(call) + call.readAll = () => { + return (0, iterator_1.default)(call, 'data', { + resolutionEvents: ['end'] + }) + } + Promise.resolve().then(async () => { + const handleResponse = async () => { + ctx.response = await target[key](call) } - // server stream - if (!requestStream && responseStream) { - return this._callServerStreamProxyMethod(target, key, fn); + await composeFunc(ctx, handleResponse).catch(err => { + callback(this._createInternalErrorStatus(err)) + }) + callback(null, ctx.response) + }) + } + } + _callServerStreamProxyMethod(target, key, composeFunc) { + return call => { + const ctx = this._createContext(call) + call.writeAll = messages => { + if (Array.isArray(messages)) { + messages.forEach(message => { + call.write(message) + }) } - // duplex stream - if (requestStream && responseStream) { - return this._callDuplexStreamProxyMethod(target, key, fn); + } + call.writeEnd = call.end + Promise.resolve().then(async () => { + const handleResponse = async () => { + await target[key](call) } + await composeFunc(ctx, handleResponse).catch(err => { + call.destroy(this._createInternalErrorStatus(err)) + }) + call.end() + }) } - _createContext(call) { - return { - // TODO: maybe need more details - // method: target.constructor.name + '.' + key, - path: call.call.handler.path || '', - request: call.request, - metadata: call.metadata.clone() - }; - } - _callUnaryProxyMethod(target, key, composeFunc) { - return (call, callback) => { - const ctx = this._createContext(call); - Promise.resolve().then(async () => { - const handleResponse = async () => { - ctx.response = await target[key](call); - }; - await composeFunc(ctx, handleResponse).catch((err) => { - callback(this._createInternalErrorStatus(err)); - }); - callback(null, ctx.response); - }); - }; - } - _callClientStreamProxyMethod(target, key, composeFunc) { - return (call, callback) => { - const ctx = this._createContext(call); - call.readAll = () => { - return (0, iterator_1.default)(call, 'data', { - resolutionEvents: ['end'] - }); - }; - Promise.resolve().then(async () => { - const handleResponse = async () => { - ctx.response = await target[key](call); - }; - await composeFunc(ctx, handleResponse).catch((err) => { - callback(this._createInternalErrorStatus(err)); - }); - callback(null, ctx.response); - }); - }; - } - _callServerStreamProxyMethod(target, key, composeFunc) { - return (call) => { - const ctx = this._createContext(call); - call.writeAll = (messages) => { - if (Array.isArray(messages)) { - messages.forEach(message => { - call.write(message); - }); - } - }; - call.writeEnd = call.end; - Promise.resolve().then(async () => { - const handleResponse = async () => { - await target[key](call); - }; - await composeFunc(ctx, handleResponse).catch((err) => { - call.destroy(this._createInternalErrorStatus(err)); - }); - call.end(); - }); - }; - } - _callDuplexStreamProxyMethod(target, key, composeFunc) { - return (call) => { - const ctx = this._createContext(call); - call.writeAll = (messages) => { - if (Array.isArray(messages)) { - messages.forEach(message => { - call.write(message); - }); - } - }; - call.readAll = () => { - return (0, iterator_1.default)(call, 'data', { - resolutionEvents: ['end'] - }); - }; - Promise.resolve().then(async () => { - const handleResponse = async () => { - await target[key](call); - }; - await composeFunc(ctx, handleResponse).catch((err) => { - call.destroy(this._createInternalErrorStatus(err)); - }); - call.end(); - }); - }; - } - _createInternalErrorStatus(err) { - err.code = err.code || 13; - if (typeof err.stack === 'string') { - const stack = err.stack.split('\n'); - err.messages += ` [Error Message From Server, stack: ${stack[1].trim()}]`; + } + _callDuplexStreamProxyMethod(target, key, composeFunc) { + return call => { + const ctx = this._createContext(call) + call.writeAll = messages => { + if (Array.isArray(messages)) { + messages.forEach(message => { + call.write(message) + }) } - else { - err.messages += ' [Error Message From Server]'; + } + call.readAll = () => { + return (0, iterator_1.default)(call, 'data', { + resolutionEvents: ['end'] + }) + } + Promise.resolve().then(async () => { + const handleResponse = async () => { + await target[key](call) } - return err; + await composeFunc(ctx, handleResponse).catch(err => { + call.destroy(this._createInternalErrorStatus(err)) + }) + call.end() + }) + } + } + _createInternalErrorStatus(err) { + err.code = err.code || 13 + if (typeof err.stack === 'string') { + const stack = err.stack.split('\n') + err.messages += ` [Error Message From Server, stack: ${stack[1].trim()}]` + } else { + err.messages += ' [Error Message From Server]' } + return err + } } -exports.default = ServerProxy; +exports.default = ServerProxy diff --git a/types/schema/loader.d.ts b/types/schema/loader.d.ts index 87b2011..58d636f 100644 --- a/types/schema/loader.d.ts +++ b/types/schema/loader.d.ts @@ -1,7 +1,7 @@ -import Joi from 'joi'; +import Joi from 'joi' declare const loaderSchemas: { - constructor: Joi.ArraySchema; - init: Joi.ObjectSchema; - initClients: Joi.ObjectSchema; -}; -export default loaderSchemas; + constructor: Joi.ArraySchema + init: Joi.ObjectSchema + initClients: Joi.ObjectSchema +} +export default loaderSchemas diff --git a/types/schema/loader.js b/types/schema/loader.js index 7c5d393..03fb97e 100644 --- a/types/schema/loader.js +++ b/types/schema/loader.js @@ -1,33 +1,42 @@ -"use strict"; -var __importDefault = (this && this.__importDefault) || function (mod) { - return (mod && mod.__esModule) ? mod : { "default": mod }; -}; -Object.defineProperty(exports, "__esModule", { value: true }); -const joi_1 = __importDefault(require("joi")); -const addressSchema = joi_1.default.object() - .pattern(/\.*/, joi_1.default.alternatives([ +'use strict' +var __importDefault = + (this && this.__importDefault) || + function (mod) { + return mod && mod.__esModule ? mod : { default: mod } + } +Object.defineProperty(exports, '__esModule', { value: true }) +const joi_1 = __importDefault(require('joi')) +const addressSchema = joi_1.default.object().pattern( + /\.*/, + joi_1.default.alternatives([ joi_1.default.string().regex(/:/, 'host and port like 127.0.0.1:9090'), joi_1.default.object({ - host: joi_1.default.string().required(), - port: joi_1.default.number().integer().min(0).max(65535).required() + host: joi_1.default.string().required(), + port: joi_1.default.number().integer().min(0).max(65535).required() }) -])); + ]) +) const loaderSchemas = { - constructor: joi_1.default.array().items(joi_1.default.object({ + constructor: joi_1.default + .array() + .items( + joi_1.default.object({ location: joi_1.default.string().required(), files: joi_1.default.array().items(joi_1.default.string()).required() - })).single(), - init: joi_1.default.object({ - services: addressSchema.optional(), - isDev: joi_1.default.boolean().optional(), - packagePrefix: joi_1.default.string().optional(), - loadOptions: joi_1.default.object().optional(), - channelOptions: joi_1.default.object().optional(), - appName: joi_1.default.string().optional() - }), - initClients: joi_1.default.object({ - services: addressSchema.required(), - channelOptions: joi_1.default.object().optional() - }) -}; -exports.default = loaderSchemas; + }) + ) + .single(), + init: joi_1.default.object({ + services: addressSchema.optional(), + isDev: joi_1.default.boolean().optional(), + packagePrefix: joi_1.default.string().optional(), + loadOptions: joi_1.default.object().optional(), + channelOptions: joi_1.default.object().optional(), + appName: joi_1.default.string().optional() + }), + initClients: joi_1.default.object({ + services: addressSchema.required(), + channelOptions: joi_1.default.object().optional() + }) +} +exports.default = loaderSchemas diff --git a/types/schema/server.d.ts b/types/schema/server.d.ts index 5b6a583..f3f6e43 100644 --- a/types/schema/server.d.ts +++ b/types/schema/server.d.ts @@ -1,5 +1,5 @@ -import Joi from 'joi'; +import Joi from 'joi' declare const serverSchemas: { - address: Joi.AlternativesSchema; -}; -export default serverSchemas; + address: Joi.AlternativesSchema +} +export default serverSchemas diff --git a/types/schema/server.js b/types/schema/server.js index 43a17e8..b777ef0 100644 --- a/types/schema/server.js +++ b/types/schema/server.js @@ -1,16 +1,18 @@ -"use strict"; -var __importDefault = (this && this.__importDefault) || function (mod) { - return (mod && mod.__esModule) ? mod : { "default": mod }; -}; -Object.defineProperty(exports, "__esModule", { value: true }); -const joi_1 = __importDefault(require("joi")); +'use strict' +var __importDefault = + (this && this.__importDefault) || + function (mod) { + return mod && mod.__esModule ? mod : { default: mod } + } +Object.defineProperty(exports, '__esModule', { value: true }) +const joi_1 = __importDefault(require('joi')) const serverSchemas = { - address: joi_1.default.alternatives([ - joi_1.default.string().regex(/:/, 'host and port like 127.0.0.1:9090'), - joi_1.default.object({ - host: joi_1.default.string().required(), - port: joi_1.default.number().integer().min(0).max(65535).required() - }) - ]) -}; -exports.default = serverSchemas; + address: joi_1.default.alternatives([ + joi_1.default.string().regex(/:/, 'host and port like 127.0.0.1:9090'), + joi_1.default.object({ + host: joi_1.default.string().required(), + port: joi_1.default.number().integer().min(0).max(65535).required() + }) + ]) +} +exports.default = serverSchemas diff --git a/types/util/compose.d.ts b/types/util/compose.d.ts index de2ce79..d300cd6 100644 --- a/types/util/compose.d.ts +++ b/types/util/compose.d.ts @@ -1,4 +1,7 @@ -export type MiddlewareFunction = (context: any, next: () => Promise) => Promise; +export type MiddlewareFunction = ( + context: any, + next: () => Promise +) => Promise /** * Compose `middleware` returning * a fully valid middleware comprised @@ -8,4 +11,6 @@ export type MiddlewareFunction = (context: any, next: () => Promise) => Pro * @return {Function} * @api public */ -export declare const compose: (middleware: MiddlewareFunction[]) => (context: any, next: () => Promise) => Promise; +export declare const compose: ( + middleware: MiddlewareFunction[] +) => (context: any, next: () => Promise) => Promise diff --git a/types/util/compose.js b/types/util/compose.js index 5be353e..1440015 100644 --- a/types/util/compose.js +++ b/types/util/compose.js @@ -1,6 +1,6 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.compose = void 0; +'use strict' +Object.defineProperty(exports, '__esModule', { value: true }) +exports.compose = void 0 /** * Compose `middleware` returning * a fully valid middleware comprised @@ -10,33 +10,30 @@ exports.compose = void 0; * @return {Function} * @api public */ -const compose = (middleware) => { - if (!Array.isArray(middleware)) - throw new TypeError("Middleware stack must be an array!"); - for (const fn of middleware) { - if (typeof fn !== "function") - throw new TypeError("Middleware must be composed of functions!"); +const compose = middleware => { + if (!Array.isArray(middleware)) + throw new TypeError('Middleware stack must be an array!') + for (const fn of middleware) { + if (typeof fn !== 'function') + throw new TypeError('Middleware must be composed of functions!') + } + return function (context, next) { + // last called middleware # + let index = -1 + return dispatch(0) + function dispatch(i) { + if (i <= index) + return Promise.reject(new Error('next() called multiple times')) + index = i + let fn = middleware[i] + if (i === middleware.length) fn = next + if (!fn) return Promise.resolve() + try { + return Promise.resolve(fn(context, dispatch.bind(null, i + 1))) + } catch (err) { + return Promise.reject(err) + } } - return function (context, next) { - // last called middleware # - let index = -1; - return dispatch(0); - function dispatch(i) { - if (i <= index) - return Promise.reject(new Error("next() called multiple times")); - index = i; - let fn = middleware[i]; - if (i === middleware.length) - fn = next; - if (!fn) - return Promise.resolve(); - try { - return Promise.resolve(fn(context, dispatch.bind(null, i + 1))); - } - catch (err) { - return Promise.reject(err); - } - } - }; -}; -exports.compose = compose; + } +} +exports.compose = compose diff --git a/types/util/iterator.d.ts b/types/util/iterator.d.ts index 15db39e..8614cd3 100644 --- a/types/util/iterator.d.ts +++ b/types/util/iterator.d.ts @@ -1,20 +1,26 @@ -declare const _default: (emitter: any, event: string | string[], options: any) => { - [Symbol.asyncIterator](): any; - next(): Promise<{ - done: boolean; - value: any; - }>; - return?: undefined; -} | { - [x: symbol]: () => any; - next(): Promise<{ - done: boolean; - value: any; - }>; - return(value: any): Promise<{ - done: boolean; - value: any; - }>; - [Symbol.asyncIterator]?: undefined; -}; -export default _default; +declare const _default: ( + emitter: any, + event: string | string[], + options: any +) => + | { + [Symbol.asyncIterator](): any + next(): Promise<{ + done: boolean + value: any + }> + return?: undefined + } + | { + [x: symbol]: () => any + next(): Promise<{ + done: boolean + value: any + }> + return(value: any): Promise<{ + done: boolean + value: any + }> + [Symbol.asyncIterator]?: undefined + } +export default _default diff --git a/types/util/iterator.js b/types/util/iterator.js index 348cb94..9db9132 100644 --- a/types/util/iterator.js +++ b/types/util/iterator.js @@ -1,155 +1,160 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -const symbolAsyncIterator = Symbol.asyncIterator || "@@asyncIterator"; -const normalizeEmitter = (emitter) => { - const addListener = emitter.on || emitter.addListener || emitter.addEventListener; - const removeListener = emitter.off || emitter.removeListener || emitter.removeEventListener; - if (!addListener || !removeListener) { - throw new TypeError("Emitter is not compatible"); - } - return { - addListener: addListener.bind(emitter), - removeListener: removeListener.bind(emitter), - }; -}; -const toArray = (value) => (Array.isArray(value) ? value : [value]); +'use strict' +Object.defineProperty(exports, '__esModule', { value: true }) +const symbolAsyncIterator = Symbol.asyncIterator || '@@asyncIterator' +const normalizeEmitter = emitter => { + const addListener = + emitter.on || emitter.addListener || emitter.addEventListener + const removeListener = + emitter.off || emitter.removeListener || emitter.removeEventListener + if (!addListener || !removeListener) { + throw new TypeError('Emitter is not compatible') + } + return { + addListener: addListener.bind(emitter), + removeListener: removeListener.bind(emitter) + } +} +const toArray = value => (Array.isArray(value) ? value : [value]) exports.default = (emitter, event, options) => { - if (typeof options === "function") { - options = { filter: options }; + if (typeof options === 'function') { + options = { filter: options } + } + // Allow multiple events + const events = toArray(event) + options = { + rejectionEvents: ['error'], + resolutionEvents: [], + limit: Infinity, + multiArgs: false, + ...options + } + const { limit } = options + const isValidLimit = + limit >= 0 && (limit === Infinity || Number.isInteger(limit)) + if (!isValidLimit) { + throw new TypeError( + 'The `limit` option should be a non-negative integer or Infinity' + ) + } + if (limit === 0) { + // Return an empty async iterator to avoid any further cost + return { + [Symbol.asyncIterator]() { + return this + }, + async next() { + return { + done: true, + value: undefined + } + } } - // Allow multiple events - const events = toArray(event); - options = { - rejectionEvents: ["error"], - resolutionEvents: [], - limit: Infinity, - multiArgs: false, - ...options, - }; - const { limit } = options; - const isValidLimit = limit >= 0 && (limit === Infinity || Number.isInteger(limit)); - if (!isValidLimit) { - throw new TypeError("The `limit` option should be a non-negative integer or Infinity"); + } + const { addListener, removeListener } = normalizeEmitter(emitter) + let isDone = false + let error + let hasPendingError = false + const nextQueue = [] + const valueQueue = [] + let eventCount = 0 + let isLimitReached = false + const valueHandler = (...args) => { + eventCount++ + isLimitReached = eventCount === limit + const value = options.multiArgs ? args : args[0] + if (nextQueue.length > 0) { + const { resolve } = nextQueue.shift() + resolve({ done: false, value }) + if (isLimitReached) { + cancel() + } + return } - if (limit === 0) { - // Return an empty async iterator to avoid any further cost - return { - [Symbol.asyncIterator]() { - return this; - }, - async next() { - return { - done: true, - value: undefined, - }; - }, - }; + valueQueue.push(value) + if (isLimitReached) { + cancel() } - const { addListener, removeListener } = normalizeEmitter(emitter); - let isDone = false; - let error; - let hasPendingError = false; - const nextQueue = []; - const valueQueue = []; - let eventCount = 0; - let isLimitReached = false; - const valueHandler = (...args) => { - eventCount++; - isLimitReached = eventCount === limit; - const value = options.multiArgs ? args : args[0]; - if (nextQueue.length > 0) { - const { resolve } = nextQueue.shift(); - resolve({ done: false, value }); - if (isLimitReached) { - cancel(); - } - return; - } - valueQueue.push(value); - if (isLimitReached) { - cancel(); - } - }; - const cancel = () => { - isDone = true; - for (const event of events) { - removeListener(event, valueHandler); - } - for (const rejectionEvent of options.rejectionEvents) { - removeListener(rejectionEvent, rejectHandler); - } - for (const resolutionEvent of options.resolutionEvents) { - removeListener(resolutionEvent, resolveHandler); - } - while (nextQueue.length > 0) { - const { resolve } = nextQueue.shift(); - resolve({ done: true, value: undefined }); - } - }; - const rejectHandler = (...args) => { - error = options.multiArgs ? args : args[0]; - if (nextQueue.length > 0) { - const { reject } = nextQueue.shift(); - reject(error); - } - else { - hasPendingError = true; - } - cancel(); - }; - const resolveHandler = (...args) => { - const value = options.multiArgs ? args : args[0]; - if (options.filter && !options.filter(value)) { - return; - } - if (nextQueue.length > 0) { - const { resolve } = nextQueue.shift(); - resolve({ done: true, value }); - } - else { - valueQueue.push(value); - } - cancel(); - }; + } + const cancel = () => { + isDone = true for (const event of events) { - addListener(event, valueHandler); + removeListener(event, valueHandler) } for (const rejectionEvent of options.rejectionEvents) { - addListener(rejectionEvent, rejectHandler); + removeListener(rejectionEvent, rejectHandler) } for (const resolutionEvent of options.resolutionEvents) { - addListener(resolutionEvent, resolveHandler); + removeListener(resolutionEvent, resolveHandler) } - return { - [symbolAsyncIterator]() { - return this; - }, - async next() { - if (valueQueue.length > 0) { - const value = valueQueue.shift(); - return { - done: isDone && valueQueue.length === 0 && !isLimitReached, - value, - }; - } - if (hasPendingError) { - hasPendingError = false; - throw error; - } - if (isDone) { - return { - done: true, - value: undefined, - }; - } - return new Promise((resolve, reject) => nextQueue.push({ resolve, reject })); - }, - async return(value) { - cancel(); - return { - done: isDone, - value, - }; - }, - }; -}; + while (nextQueue.length > 0) { + const { resolve } = nextQueue.shift() + resolve({ done: true, value: undefined }) + } + } + const rejectHandler = (...args) => { + error = options.multiArgs ? args : args[0] + if (nextQueue.length > 0) { + const { reject } = nextQueue.shift() + reject(error) + } else { + hasPendingError = true + } + cancel() + } + const resolveHandler = (...args) => { + const value = options.multiArgs ? args : args[0] + if (options.filter && !options.filter(value)) { + return + } + if (nextQueue.length > 0) { + const { resolve } = nextQueue.shift() + resolve({ done: true, value }) + } else { + valueQueue.push(value) + } + cancel() + } + for (const event of events) { + addListener(event, valueHandler) + } + for (const rejectionEvent of options.rejectionEvents) { + addListener(rejectionEvent, rejectHandler) + } + for (const resolutionEvent of options.resolutionEvents) { + addListener(resolutionEvent, resolveHandler) + } + return { + [symbolAsyncIterator]() { + return this + }, + async next() { + if (valueQueue.length > 0) { + const value = valueQueue.shift() + return { + done: isDone && valueQueue.length === 0 && !isLimitReached, + value + } + } + if (hasPendingError) { + hasPendingError = false + throw error + } + if (isDone) { + return { + done: true, + value: undefined + } + } + return new Promise((resolve, reject) => + nextQueue.push({ resolve, reject }) + ) + }, + async return(value) { + cancel() + return { + done: isDone, + value + } + } + } +} diff --git a/types/util/prefixingDefinition.d.ts b/types/util/prefixingDefinition.d.ts index 6805329..2ca407c 100644 --- a/types/util/prefixingDefinition.d.ts +++ b/types/util/prefixingDefinition.d.ts @@ -1,2 +1,2 @@ -declare const _default: (packageDefinition: any, packagePrefix: any) => any; -export default _default; +declare const _default: (packageDefinition: any, packagePrefix: any) => any +export default _default diff --git a/types/util/prefixingDefinition.js b/types/util/prefixingDefinition.js index 0cec5eb..2fa5a97 100644 --- a/types/util/prefixingDefinition.js +++ b/types/util/prefixingDefinition.js @@ -1,24 +1,25 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); +'use strict' +Object.defineProperty(exports, '__esModule', { value: true }) exports.default = (packageDefinition, packagePrefix) => { - for (const qualifiedName in packageDefinition) { - const definition = packageDefinition[qualifiedName]; - const newPackage = `${packagePrefix}.${qualifiedName}`; - if (definition.format && - definition.type && - definition.fileDescriptorProtos) { - packageDefinition[newPackage] = definition; - } - else { - const newDefinition = {}; - for (const method in definition) { - const service = definition[method]; - newDefinition[method] = Object.assign({}, service, { - path: service.path.replace(/^\//, `/${packagePrefix}.`), - }); - } - packageDefinition[newPackage] = newDefinition; - } + for (const qualifiedName in packageDefinition) { + const definition = packageDefinition[qualifiedName] + const newPackage = `${packagePrefix}.${qualifiedName}` + if ( + definition.format && + definition.type && + definition.fileDescriptorProtos + ) { + packageDefinition[newPackage] = definition + } else { + const newDefinition = {} + for (const method in definition) { + const service = definition[method] + newDefinition[method] = Object.assign({}, service, { + path: service.path.replace(/^\//, `/${packagePrefix}.`) + }) + } + packageDefinition[newPackage] = newDefinition } - return packageDefinition; -}; + } + return packageDefinition +} From e5242c01865b0729e39f2ce836dc0d961c084764 Mon Sep 17 00:00:00 2001 From: "Chakhsu.Lau" Date: Sun, 3 Dec 2023 19:52:07 +0800 Subject: [PATCH 07/12] feat: update to v1.3.0 --- README.md | 2 +- README_CN.md | 2 +- package.json | 4 ++-- test/index.test.js | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index e7986c6..d7aa909 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# gRPCity ![build-status](https://github.com/chakhsu/grpcity/actions/workflows/tests.yml/badge.svg) ![npm](https://img.shields.io/npm/v/grpcity) ![license](https://img.shields.io/npm/l/grpcity) ![code-style](https://img.shields.io/badge/code_style-standard-brightgreen.svg) +# gRPCity ![build-status](https://github.com/chakhsu/grpcity/actions/workflows/tests.yml/badge.svg) ![npm](https://img.shields.io/npm/v/grpcity) ![license](https://img.shields.io/npm/l/grpcity) ![code-style](https://img.shields.io/badge/code_style-prettier-brightgreen.svg) [English](./README.md) | [简体中文](./README_CN.md) diff --git a/README_CN.md b/README_CN.md index 7c1ed8d..6d3fc95 100644 --- a/README_CN.md +++ b/README_CN.md @@ -1,4 +1,4 @@ -# gRPCity ![build-status](https://github.com/chakhsu/grpcity/actions/workflows/tests.yml/badge.svg) ![npm](https://img.shields.io/npm/v/grpcity) ![license](https://img.shields.io/npm/l/grpcity) ![code-style](https://img.shields.io/badge/code_style-standard-brightgreen.svg) +# gRPCity ![build-status](https://github.com/chakhsu/grpcity/actions/workflows/tests.yml/badge.svg) ![npm](https://img.shields.io/npm/v/grpcity) ![license](https://img.shields.io/npm/l/grpcity) ![code-style](https://img.shields.io/badge/code_style-prettier-brightgreen.svg) [English](./README.md) | [简体中文](./README_CN.md) diff --git a/package.json b/package.json index 5c60f7a..9922fb4 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "grpcity", - "version": "1.3.0-beta.1", + "version": "1.3.0", "description": "A powerful and complete gRPC framework for Node.js", "author": "Chakhsu.Lau", "license": "MIT", @@ -21,7 +21,7 @@ "url": "https://github.com/chakhsu/grpcity/issues" }, "main": "./types/index.js", - "typings": "./types/index.d.ts", + "types": "./types/index.d.ts", "engines": { "node": ">=16" }, diff --git a/test/index.test.js b/test/index.test.js index dc5f1e6..599ab5f 100755 --- a/test/index.test.js +++ b/test/index.test.js @@ -56,7 +56,7 @@ describe('Grpc Loader', () => { expect(result.message).to.be.eq('hello, grpc') // 支持相同service的client访问不同host和port - const timeout = 20 + const timeout = 50 const client2 = loader.client('test.helloworld.Greeter', { host: 'localhost', port: 12305, From 0e58f71d7bea7553f9280d6eb703e5830341803b Mon Sep 17 00:00:00 2001 From: "Chakhsu.Lau" Date: Sun, 3 Dec 2023 20:00:36 +0800 Subject: [PATCH 08/12] feat: update github action --- .github/workflows/tests.yml | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 598e3b3..7675e15 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -20,16 +20,22 @@ jobs: os: [ubuntu-latest, windows-latest, macos-latest] steps: + - name: Checkout master - uses: actions/checkout@v4 + + - uses: pnpm/action-setup@v2.4.0 + - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: - cache: 'npm' node-version: ${{ matrix.node-version }} - # Use separate run commands so command status handled correctly on Windows - - name: npm install - run: npm ci - - name: npm test - run: npm test - - name: npm run lint - run: npm run lint + cache: 'pnpm' + + - name: Install Dependencies + run: pnpm i + + - name: Test + run: pnpm test + + - name: Clean + run: pnpm clean From d70e62b0b43eff2fbd830f90cb161a859e5b8c07 Mon Sep 17 00:00:00 2001 From: "Chakhsu.Lau" Date: Sun, 3 Dec 2023 20:08:16 +0800 Subject: [PATCH 09/12] chore: update github action --- .github/workflows/tests.yml | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 7675e15..a12b040 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -22,20 +22,16 @@ jobs: steps: - name: Checkout master - uses: actions/checkout@v4 - - - uses: pnpm/action-setup@v2.4.0 - + - name: Install pnpm + uses: pnpm/action-setup@v2 - name: Use Node.js ${{ matrix.node-version }} uses: actions/setup-node@v4 with: node-version: ${{ matrix.node-version }} cache: 'pnpm' - - name: Install Dependencies run: pnpm i - - name: Test run: pnpm test - - name: Clean run: pnpm clean From 11b1ab44d50a58014263136682e0778f2751246e Mon Sep 17 00:00:00 2001 From: "Chakhsu.Lau" Date: Sun, 3 Dec 2023 20:11:52 +0800 Subject: [PATCH 10/12] chore: update --- .github/workflows/tests.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index a12b040..8eb54e3 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -21,9 +21,11 @@ jobs: steps: - name: Checkout master - - uses: actions/checkout@v4 + - uses: actions/checkout@v3 - name: Install pnpm uses: pnpm/action-setup@v2 + with: + version: 8 - name: Use Node.js ${{ matrix.node-version }} uses: actions/setup-node@v4 with: From dca3e69e4b6fea97c747bb8613ba0f904cf1fb36 Mon Sep 17 00:00:00 2001 From: "Chakhsu.Lau" Date: Sun, 3 Dec 2023 20:15:01 +0800 Subject: [PATCH 11/12] fix: action not work --- .github/workflows/tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 8eb54e3..2fefb39 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -21,7 +21,7 @@ jobs: steps: - name: Checkout master - - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Install pnpm uses: pnpm/action-setup@v2 with: From 72e4660a87c44b07fe657f2c945ba93645064137 Mon Sep 17 00:00:00 2001 From: "Chakhsu.Lau" Date: Sun, 3 Dec 2023 20:16:59 +0800 Subject: [PATCH 12/12] fix: remove clean --- .github/workflows/tests.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 2fefb39..9e3b52c 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -35,5 +35,3 @@ jobs: run: pnpm i - name: Test run: pnpm test - - name: Clean - run: pnpm clean