diff --git a/.gitignore b/.gitignore index 54512fe..dbf2fae 100644 --- a/.gitignore +++ b/.gitignore @@ -1,11 +1,3 @@ -dist -node_modules -yarn.lock -logs -.rpt2_cache -.nyc_output -coverage -docs -temp -lib -.ds_store \ No newline at end of file +node_modules +dist +.DS_STORE \ No newline at end of file diff --git a/.mocharc.js b/.mocharc.js index 034220e..c7aec06 100644 --- a/.mocharc.js +++ b/.mocharc.js @@ -1,22 +1,11 @@ -module.exports = { - require: [ - 'ts-node/register', - './test/Base.ts' - ], - exit: true, - timeout: 999999, - 'preserve-symlinks': true, - spec: [ - './test/cases/http.test.ts', - './test/cases/httpJSON.test.ts', - './test/cases/ws.test.ts', - './test/cases/wsJSON.test.ts', - './test/cases/inner.test.ts', - './test/cases/inputJSON.test.ts', - './test/cases/inputBuffer.test.ts', - ], - // parallel: false, - - // 'expose-gc': true, - // fgrep: 'throw type error in server' +module.exports = { + require: [ + 'ts-node/register', + ], + timeout: 999999, + exit: true, + spec: [ + './test/**/*.test.ts' + ], + 'preserve-symlinks': true } \ No newline at end of file diff --git a/.vscode/launch.json b/.vscode/launch.json index c77bfcb..a6fa343 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -1,34 +1,30 @@ -{ - // 使用 IntelliSense 了解相关属性。 - // 悬停以查看现有属性的描述。 - // 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387 - "version": "0.2.0", - "configurations": [ - { - "type": "node", - "request": "launch", - "name": "mocha current file", - "program": "${workspaceFolder}/node_modules/mocha/bin/_mocha", - "args": [ - "${file}" - ], - "internalConsoleOptions": "openOnSessionStart", - "cwd": "${workspaceFolder}" - }, - { - "type": "node", - "request": "launch", - "name": "ts-node current file", - "protocol": "inspector", - "args": [ - "${relativeFile}" - ], - "cwd": "${workspaceRoot}", - "runtimeArgs": [ - "-r", - "ts-node/register" - ], - "internalConsoleOptions": "openOnSessionStart" - } - ] +{ + "configurations": [ + { + "type": "node", + "request": "launch", + "name": "mocha current file", + "program": "${workspaceFolder}/node_modules/mocha/bin/_mocha", + "args": [ + "${file}" + ], + "internalConsoleOptions": "openOnSessionStart", + "cwd": "${workspaceFolder}" + }, + { + "type": "node", + "request": "launch", + "name": "ts-node current file", + "protocol": "inspector", + "args": [ + "${relativeFile}" + ], + "cwd": "${workspaceRoot}", + "runtimeArgs": [ + "-r", + "ts-node/register" + ], + "internalConsoleOptions": "openOnSessionStart" + } + ] } \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json index 00ad71f..e9b3c5f 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,3 +1,3 @@ -{ - "typescript.tsdk": "node_modules\\typescript\\lib" +{ + "typescript.tsdk": "node_modules\\typescript\\lib" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md deleted file mode 100644 index f16c3cd..0000000 --- a/CHANGELOG.md +++ /dev/null @@ -1,161 +0,0 @@ -# CHANGELOG - -## [3.3.1-dev.0] - 2022-04-27 -### Fixed -- `HttpConnection.status` not correct when request aborted by client - -## [3.3.0] - 2022-04-15 -### Added -- Builtin heartbeat support -- New options `logLevel` -### Fixed -- Add response header `Content-Type: application/json; charset=utf-8` for JSON mode under HttpServer, to fix the decoding issue in Chrome dev tools. - -## [3.2.5] - 2022-04-12 -### Added -- New server options `corsMaxAge` to optimized preflight requests, default value is 3600. -### Fixed -- `NonNullable` cannot be encoded and decoded when as a property in interface - -## [3.2.3] - 2022-03-25 -### Added -- Print debug-level log when "pre flow" is canceled -### Changed -- Log `[ResErr]` renamed to `[ApiErr]` to consist with client's. -- Log `ApiRes` and `ApiErr` once they are ready to send, instead of after send them. -### Fixed -- When `preSendDataFlow` return undefined, do not send "Internal Server Error". -- Remove some unused code. - -## [3.2.2] - 2022-03-22 -### Fixed -- `postDisconnectFlow` not executed when `disconnect()` manually - - -## [3.2.1] - 2022-03-21 -### Added -- `preRecvDataFlow` add param `serviceName` -- Support change `dataType` in `postConnectFlow` -### Fixed -- Remark text error - -## [3.2.0] - 2022-02-26 -### Added -- Support using `keyof` -- Support type alias and `keyof` in `Pick` and `Omit` -- Support `Pick` and `Omit` -- Support `interface` extends Mapped Type, like `Pick` `Omit` -- Support `Pick` -- Support `Pick` -- Support `Pick` and `Pick`, the same to `Omit` -- Support reference enum value as literal type,like: - ```ts - export enum Types { - Type1, - Type2 - } - export interface Obj { - type: Types.Type1, - value: string - } - ``` -### Changed -- `SchemaType` switched to class - -## [3.1.9] - 2022-01-12 -### Added -- `mongodb-polyfill.d.ts` to fixed mongodb type bug. - -## [3.1.6] - 2021-12-29 -### Changed -- Return request type error detail when using JSON - -## [3.1.5] - 2021-12-23 -### Fixed -- Optimize aliyun FC support of `server.inputJSON` - -## [3.1.4] - 2021-12-18 -### Added -- `WsServer` now support client use `buffer` as transfering format when server set `json: true` -### Fixed -- Type error when disable `skipLibChecks` -- Cannot resolve JSON when `headers` is `application/json; charset=utf-8` -- Cannot resolve serviceName when there is query string in the URL - -## [3.1.3] - 2021-12-04 -### Added -- `conn.listenMsg` -### Fixed -- Do not `broadcastMsg` when `conns.length` is `0` - -## [3.1.2] - 2021-11-17 -### Added -- `server.inputJSON` and `server.inputBuffer` -- Add new dataType `json` - -## [3.1.1] - 2021-11-09 -### Added -- HTTP Text 传输模式下,区分 HTTP 状态码返回,不再统一返回 200 - -## [3.1.0] - 2021-11-08 -### Added -- WebSocket 支持 JSON 格式传输 -- JSON 格式传输支持 `ArrayBuffer`、`Date`、`ObjectId`,自动根据协议编解码为 `string` -### Changed -- `jsonEnabled` -> `json` - -## [3.0.14] - 2021-10-25 -### Added -- 增加 `server.autoImplementApi` 第二个参数 `delay`,用于延迟自动协议注册,加快冷启动速度。 - -## [3.0.13] - 2021-10-22 -### Added -- 增加 `server.callApi` 的支持,以更方便的适配 Serverless 云函数等自定义传输场景。 - -## [3.0.12] - 2021-10-22 -### Fixed -- 修复 `WsServer` 客户端断开连接后,日志显示的 `ActiveConn` 总是比实际多 1 的 BUG - -## [3.0.11] - 2021-10-18 -### Added -- 增加对 `mongodb/ObjectId` 的支持 - -## [3.0.10] - 2021-10-13 -### Changed -- `BaseConnection` 泛型参数默认为 `any`,便于扩展类型 -- `HttpClient` and `WsClient` no longer have default type param - -## [3.0.9] - 2021-10-06 -### Changed -- `strictNullChecks` 默认改为 `false` - -## [3.0.8] - 2021-10-06 -### Added -- Optimize log level - -## [3.0.7] - 2021-10-06 -### Added -- Optimize log color -## [3.0.6] - 2021-09-30 -### Added -- "Server started at ..." 前增加 "ERROR:X API registered failed." -### Changed -- `HttpServer.onInputBufferError` 改为 `call.error('InputBufferError')` -- 替换 `colors` 为 `chalk` - -## [3.0.5] - 2021-08-14 -### Added -- Optimize log for `sendMsg` and `broadcastMsg` -- Return `Internal Server Error` when `SendReturnErr` occured - -### Changed -- Remove error `API not return anything` -- handler of `client.listenMsg` changed to `(msg, msgName, client)=>void` - -### Fixed -- NodeJS 12 compability issue (`Uint8Array` and `Buffer` is not treated samely) - -## [3.0.3] - 2021-06-27 - -### Added -- `server.listenMsg` would return `handler` that passed in \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..d1d63a4 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,30 @@ +FROM node + +# 使用淘宝 NPM 镜像(国内机器构建推荐启用) +# RUN npm config set registry https://registry.npm.taobao.org/ + +# npm install +ADD package*.json /src/ +WORKDIR /src +RUN npm i + +# build +ADD . /src +RUN npm run build + +# clean +RUN npm prune --production + +# move +RUN rm -rf /app \ + && mv dist /app \ + && mv node_modules /app/ \ + && rm -rf /src + +# ENV +ENV NODE_ENV production + +EXPOSE 3000 + +WORKDIR /app +CMD node index.js \ No newline at end of file diff --git a/LICENSE b/LICENSE deleted file mode 100644 index 2cb5e68..0000000 --- a/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) King Wang. https://github.com/k8w - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE -OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/README.md b/README.md index a8c3dfb..d79ac50 100644 --- a/README.md +++ b/README.md @@ -1,70 +1,31 @@ -# TSRPC - -EN / [中文](https://tsrpc.cn/docs/introduction.html) - -A TypeScript RPC framework with runtime type checking and binary serialization. - -Official site: https://tsrpc.cn (English version is on the way) - -## Features -- Runtime type checking -- Binary serialization -- Pure TypeScript, without any decorater or other language -- HTTP / WebSocket / and more protocols... -- Optional backward-compatibility to JSON -- High performance and reliable, verified by services over 100,000,000 users - -## Create Full-stack Project -``` -npx create-tsrpc-app@latest -``` - -## Usage - -### Define Protocol (Shared) -```ts -export interface ReqHello { - name: string; -} - -export interface ResHello { - reply: string; -} -``` - -### Implement API (Server) -```ts -import { ApiCall } from "tsrpc"; - -export async function ApiHello(call: ApiCall) { - call.succ({ - reply: 'Hello, ' + call.req.name - }); -} -``` - -### Call API (Client) -```ts -let ret = await client.callApi('Hello', { - name: 'World' -}); -``` - -## Examples - -https://github.com/k8w/tsrpc-examples - -## Serialization Algorithm -The best TypeScript serialization algorithm ever. -Without any 3rd-party IDL language (like protobuf), it is fully based on TypeScript source file. Define the protocols directly by your code. - -This is powered by [TSBuffer](https://github.com/tsbuffer), which is going to be open-source. - -TypeScript has the best type system, with some unique advanced features like union type, intersection type, mapped type, etc. - -TSBuffer may be the only serialization algorithm that support them all. - - - -## API Reference -See [API Reference](./docs/api/tsrpc.md). \ No newline at end of file +# TSRPC Server + +## Usage +### Local dev server + +Dev server would restart automatically when code changed. + +``` +npm run dev +``` + +### Build +``` +npm run build +``` + +### Generate API document + +Generate API document in swagger/openapi and markdown format. + +```shell +npm run doc +``` + +### Run unit Test +Execute `npm run dev` first, then execute: +``` +npm run test +``` + +--- \ No newline at end of file diff --git a/api-extractor.json b/api-extractor.json deleted file mode 100644 index f563567..0000000 --- a/api-extractor.json +++ /dev/null @@ -1,345 +0,0 @@ -/** - * Config file for API Extractor. For more info, please visit: https://api-extractor.com - */ -{ - "$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json", - /** - * Optionally specifies another JSON config file that this file extends from. This provides a way for - * standard settings to be shared across multiple projects. - * - * If the path starts with "./" or "../", the path is resolved relative to the folder of the file that contains - * the "extends" field. Otherwise, the first path segment is interpreted as an NPM package name, and will be - * resolved using NodeJS require(). - * - * SUPPORTED TOKENS: none - * DEFAULT VALUE: "" - */ - // "extends": "./shared/api-extractor-base.json" - // "extends": "my-package/include/api-extractor-base.json" - /** - * Determines the "" token that can be used with other config file settings. The project folder - * typically contains the tsconfig.json and package.json config files, but the path is user-defined. - * - * The path is resolved relative to the folder of the config file that contains the setting. - * - * The default value for "projectFolder" is the token "", which means the folder is determined by traversing - * parent folders, starting from the folder containing api-extractor.json, and stopping at the first folder - * that contains a tsconfig.json file. If a tsconfig.json file cannot be found in this way, then an error - * will be reported. - * - * SUPPORTED TOKENS: - * DEFAULT VALUE: "" - */ - // "projectFolder": "..", - /** - * (REQUIRED) Specifies the .d.ts file to be used as the starting point for analysis. API Extractor - * analyzes the symbols exported by this module. - * - * The file extension must be ".d.ts" and not ".ts". - * - * The path is resolved relative to the folder of the config file that contains the setting; to change this, - * prepend a folder token such as "". - * - * SUPPORTED TOKENS: , , - */ - "mainEntryPointFilePath": "/lib/index.d.ts", - /** - * A list of NPM package names whose exports should be treated as part of this package. - * - * For example, suppose that Webpack is used to generate a distributed bundle for the project "library1", - * and another NPM package "library2" is embedded in this bundle. Some types from library2 may become part - * of the exported API for library1, but by default API Extractor would generate a .d.ts rollup that explicitly - * imports library2. To avoid this, we can specify: - * - * "bundledPackages": [ "library2" ], - * - * This would direct API Extractor to embed those types directly in the .d.ts rollup, as if they had been - * local files for library1. - */ - "bundledPackages": [], - /** - * Determines how the TypeScript compiler engine will be invoked by API Extractor. - */ - "compiler": { - /** - * Specifies the path to the tsconfig.json file to be used by API Extractor when analyzing the project. - * - * The path is resolved relative to the folder of the config file that contains the setting; to change this, - * prepend a folder token such as "". - * - * Note: This setting will be ignored if "overrideTsconfig" is used. - * - * SUPPORTED TOKENS: , , - * DEFAULT VALUE: "/tsconfig.json" - */ - // "tsconfigFilePath": "/tsconfig.json", - /** - * Provides a compiler configuration that will be used instead of reading the tsconfig.json file from disk. - * The object must conform to the TypeScript tsconfig schema: - * - * http://json.schemastore.org/tsconfig - * - * If omitted, then the tsconfig.json file will be read from the "projectFolder". - * - * DEFAULT VALUE: no overrideTsconfig section - */ - // "overrideTsconfig": { - // . . . - // } - /** - * This option causes the compiler to be invoked with the --skipLibCheck option. This option is not recommended - * and may cause API Extractor to produce incomplete or incorrect declarations, but it may be required when - * dependencies contain declarations that are incompatible with the TypeScript engine that API Extractor uses - * for its analysis. Where possible, the underlying issue should be fixed rather than relying on skipLibCheck. - * - * DEFAULT VALUE: false - */ - // "skipLibCheck": true, - }, - /** - * Configures how the API report file (*.api.md) will be generated. - */ - "apiReport": { - /** - * (REQUIRED) Whether to generate an API report. - */ - "enabled": false - /** - * The filename for the API report files. It will be combined with "reportFolder" or "reportTempFolder" to produce - * a full file path. - * - * The file extension should be ".api.md", and the string should not contain a path separator such as "\" or "/". - * - * SUPPORTED TOKENS: , - * DEFAULT VALUE: ".api.md" - */ - // "reportFileName": ".api.md", - /** - * Specifies the folder where the API report file is written. The file name portion is determined by - * the "reportFileName" setting. - * - * The API report file is normally tracked by Git. Changes to it can be used to trigger a branch policy, - * e.g. for an API review. - * - * The path is resolved relative to the folder of the config file that contains the setting; to change this, - * prepend a folder token such as "". - * - * SUPPORTED TOKENS: , , - * DEFAULT VALUE: "/etc/" - */ - // "reportFolder": "/etc/", - /** - * Specifies the folder where the temporary report file is written. The file name portion is determined by - * the "reportFileName" setting. - * - * After the temporary file is written to disk, it is compared with the file in the "reportFolder". - * If they are different, a production build will fail. - * - * The path is resolved relative to the folder of the config file that contains the setting; to change this, - * prepend a folder token such as "". - * - * SUPPORTED TOKENS: , , - * DEFAULT VALUE: "/temp/" - */ - // "reportTempFolder": "/temp/" - }, - /** - * Configures how the doc model file (*.api.json) will be generated. - */ - "docModel": { - /** - * (REQUIRED) Whether to generate a doc model file. - */ - "enabled": true - /** - * The output path for the doc model file. The file extension should be ".api.json". - * - * The path is resolved relative to the folder of the config file that contains the setting; to change this, - * prepend a folder token such as "". - * - * SUPPORTED TOKENS: , , - * DEFAULT VALUE: "/temp/.api.json" - */ - // "apiJsonFilePath": "/temp/.api.json" - }, - /** - * Configures how the .d.ts rollup file will be generated. - */ - "dtsRollup": { - /** - * (REQUIRED) Whether to generate the .d.ts rollup file. - */ - "enabled": true, - /** - * Specifies the output path for a .d.ts rollup file to be generated without any trimming. - * This file will include all declarations that are exported by the main entry point. - * - * If the path is an empty string, then this file will not be written. - * - * The path is resolved relative to the folder of the config file that contains the setting; to change this, - * prepend a folder token such as "". - * - * SUPPORTED TOKENS: , , - * DEFAULT VALUE: "/dist/.d.ts" - */ - "untrimmedFilePath": "", - /** - * Specifies the output path for a .d.ts rollup file to be generated with trimming for a "beta" release. - * This file will include only declarations that are marked as "@public" or "@beta". - * - * The path is resolved relative to the folder of the config file that contains the setting; to change this, - * prepend a folder token such as "". - * - * SUPPORTED TOKENS: , , - * DEFAULT VALUE: "" - */ - // "betaTrimmedFilePath": "/dist/-beta.d.ts", - /** - * Specifies the output path for a .d.ts rollup file to be generated with trimming for a "public" release. - * This file will include only declarations that are marked as "@public". - * - * If the path is an empty string, then this file will not be written. - * - * The path is resolved relative to the folder of the config file that contains the setting; to change this, - * prepend a folder token such as "". - * - * SUPPORTED TOKENS: , , - * DEFAULT VALUE: "" - */ - "publicTrimmedFilePath": "/dist/index.d.ts", - /** - * When a declaration is trimmed, by default it will be replaced by a code comment such as - * "Excluded from this release type: exampleMember". Set "omitTrimmingComments" to true to remove the - * declaration completely. - * - * DEFAULT VALUE: false - */ - "omitTrimmingComments": true - }, - /** - * Configures how the tsdoc-metadata.json file will be generated. - */ - "tsdocMetadata": { - /** - * Whether to generate the tsdoc-metadata.json file. - * - * DEFAULT VALUE: true - */ - "enabled": false - /** - * Specifies where the TSDoc metadata file should be written. - * - * The path is resolved relative to the folder of the config file that contains the setting; to change this, - * prepend a folder token such as "". - * - * The default value is "", which causes the path to be automatically inferred from the "tsdocMetadata", - * "typings" or "main" fields of the project's package.json. If none of these fields are set, the lookup - * falls back to "tsdoc-metadata.json" in the package folder. - * - * SUPPORTED TOKENS: , , - * DEFAULT VALUE: "" - */ - // "tsdocMetadataFilePath": "/dist/tsdoc-metadata.json" - }, - /** - * Specifies what type of newlines API Extractor should use when writing output files. By default, the output files - * will be written with Windows-style newlines. To use POSIX-style newlines, specify "lf" instead. - * To use the OS's default newline kind, specify "os". - * - * DEFAULT VALUE: "crlf" - */ - // "newlineKind": "crlf", - /** - * Configures how API Extractor reports error and warning messages produced during analysis. - * - * There are three sources of messages: compiler messages, API Extractor messages, and TSDoc messages. - */ - "messages": { - /** - * Configures handling of diagnostic messages reported by the TypeScript compiler engine while analyzing - * the input .d.ts files. - * - * TypeScript message identifiers start with "TS" followed by an integer. For example: "TS2551" - * - * DEFAULT VALUE: A single "default" entry with logLevel=warning. - */ - "compilerMessageReporting": { - /** - * Configures the default routing for messages that don't match an explicit rule in this table. - */ - "default": { - /** - * Specifies whether the message should be written to the the tool's output log. Note that - * the "addToApiReportFile" property may supersede this option. - * - * Possible values: "error", "warning", "none" - * - * Errors cause the build to fail and return a nonzero exit code. Warnings cause a production build fail - * and return a nonzero exit code. For a non-production build (e.g. when "api-extractor run" includes - * the "--local" option), the warning is displayed but the build will not fail. - * - * DEFAULT VALUE: "warning" - */ - "logLevel": "warning" - /** - * When addToApiReportFile is true: If API Extractor is configured to write an API report file (.api.md), - * then the message will be written inside that file; otherwise, the message is instead logged according to - * the "logLevel" option. - * - * DEFAULT VALUE: false - */ - // "addToApiReportFile": false - } - // "TS2551": { - // "logLevel": "warning", - // "addToApiReportFile": true - // }, - // - // . . . - }, - /** - * Configures handling of messages reported by API Extractor during its analysis. - * - * API Extractor message identifiers start with "ae-". For example: "ae-extra-release-tag" - * - * DEFAULT VALUE: See api-extractor-defaults.json for the complete table of extractorMessageReporting mappings - */ - "extractorMessageReporting": { - "default": { - "logLevel": "warning" - // "addToApiReportFile": false - }, - "ae-missing-release-tag": { - "logLevel": "none" - } - // "ae-extra-release-tag": { - // "logLevel": "warning", - // "addToApiReportFile": true - // }, - // - // . . . - }, - /** - * Configures handling of messages reported by the TSDoc parser when analyzing code comments. - * - * TSDoc message identifiers start with "tsdoc-". For example: "tsdoc-link-tag-unescaped-text" - * - * DEFAULT VALUE: A single "default" entry with logLevel=warning. - */ - "tsdocMessageReporting": { - "default": { - "logLevel": "warning" - // "addToApiReportFile": false - }, - "tsdoc-param-tag-missing-hyphen": { - "logLevel": "none" - } - // "tsdoc-link-tag-unescaped-text": { - // "logLevel": "warning", - // "addToApiReportFile": true - // }, - // - // . . . - } - } -} \ No newline at end of file diff --git a/benchmark/config/BenchmarkConfig.ts b/benchmark/config/BenchmarkConfig.ts deleted file mode 100644 index 9f24144..0000000 --- a/benchmark/config/BenchmarkConfig.ts +++ /dev/null @@ -1,13 +0,0 @@ -export const benchmarkConfig = { - /** 压测使用的APIServer */ - server: 'http://127.0.0.1:3000', - - /** 一共运行几次压测事务 */ - total: 200000, - /** 同时并发的请求数量 */ - concurrency: 100, - /** API请求的超时时间(超时将断开HTTP连接,释放资源,前端默认为10) */ - timeout: 10000, - /** 是否将错误的详情日志打印到Log */ - showError: false -} \ No newline at end of file diff --git a/benchmark/http.ts b/benchmark/http.ts deleted file mode 100644 index a20dbaa..0000000 --- a/benchmark/http.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { benchmarkConfig } from './config/BenchmarkConfig'; -import { HttpRunner } from './models/HTTPRunner'; - -const req = { - a: 123456, - b: 'Hello, World!', - c: true, - d: new Uint8Array(100000) -} - -new HttpRunner(async function () { - await this.callApi('Test', req); -}, benchmarkConfig).start(); \ No newline at end of file diff --git a/benchmark/models/HTTPRunner.ts b/benchmark/models/HTTPRunner.ts deleted file mode 100644 index 00a233f..0000000 --- a/benchmark/models/HTTPRunner.ts +++ /dev/null @@ -1,285 +0,0 @@ -import 'colors'; -import * as http from "http"; -import * as https from "https"; -import 'k8w-extend-native'; -import { TsrpcError, TsrpcErrorType } from "tsrpc-proto"; -import { HttpClient } from '../../src/client/http/HttpClient'; -import { benchmarkConfig } from "../config/BenchmarkConfig"; -import { serviceProto } from '../protocols/proto'; - -export interface HttpRunnerConfig { - total: number; - concurrency: number; - showError?: boolean; -} - -export class HttpRunner { - - private _config: HttpRunnerConfig; - - // 执行单个事务的方法 - private _single: (this: HttpRunner) => Promise; - - // 执行进度信息 - private _progress?: { - startTime: number, - lastSuccTime?: number, - started: number, - finished: number, - succ: number, - fail: number - }; - - constructor(single: HttpRunner['_single'], config: HttpRunnerConfig) { - this._single = single.bind(this); - this._config = config; - } - - start() { - this._progress = { - startTime: Date.now(), - started: 0, - finished: 0, - succ: 0, - fail: 0 - } - - // 启动并发 - for (let i = 0; i < this._config.concurrency; ++i) { - this._doTrans(); - } - - console.log('Benchmark start!'); - this._startReport(); - } - - private _doTrans() { - if (this._isStoped || !this._progress) { - return; - } - - if (this._progress.started < this._config.total) { - ++this._progress.started; - let startTime = Date.now(); - this._single().then(v => { - ++this._progress!.succ; - this._progress!.lastSuccTime = Date.now(); - }).catch(e => { - ++this._progress!.fail; - if (this._config.showError) { - console.error('[Error]', e.message); - } - }).then(() => { - ++this._progress!.finished; - if (this._progress!.finished === this._config.total) { - this._finish(); - } - else { - this._doTrans(); - } - }) - } - } - - private _reportInterval?: NodeJS.Timeout; - private _startReport() { - this._reportInterval = setInterval(() => { - this._report(); - }, 1000) - } - - private _isStoped = false; - stop() { - this._isStoped = true; - } - - private _finish() { - if (!this._progress) { - return; - } - - this._reportInterval && clearInterval(this._reportInterval); - - console.log('\n\n-------------------------------\n Benchmark finished! \n-------------------------------'); - - let usedTime = Date.now() - this._progress.startTime; - console.log(` Transaction Execution Result `.bgBlue.white); - console.log(`Started=${this._progress.started}, Finished=${this._progress.finished}, UsedTime=${usedTime}ms`.green); - console.log(`Succ=${this._progress.succ}, Fail=${this._progress.fail}, TPS=${this._progress.succ / (this._progress.lastSuccTime! - this._progress.startTime) * 1000 | 0}\n`.green) - - // TIME TPS(完成的) - console.log(` API Execution Result `.bgBlue.white); - - // [KEY] RPS(完成的) AVG P95 P99 - for (let key in this._apiStat) { - let stat = this._apiStat[key]; - stat.resTime = stat.resTime.orderBy(v => v); - - let send = stat.sendReq; - let succ = stat.resTime.length; - let netErr = stat.networkError; - let apiErr = stat.otherError; - let avg = stat.resTime[stat.resTime.length >> 1] | 0; - let p95 = stat.resTime[stat.resTime.length * 0.95 | 0] | 0; - let p99 = stat.resTime[stat.resTime.length * 0.99 | 0] | 0; - - this._logTable([ - [{ text: 'Api' + key + ' '.repeat(this._maxApiNameLength - key.length), color: 'green' }, 'Send', 'Succ', 'QPS', 'NetErr', 'ApiErr', 'AVG ', 'P95 ', 'P99 '], - ['', '' + send, - { text: '' + succ, color: 'green' }, - { text: '' + (succ / (stat.last.succTime - stat.startTime) * 1000 | 0), color: 'green' }, - netErr ? { text: '' + netErr, color: 'red' } : '0', - apiErr ? { text: '' + apiErr, color: 'red' } : '0', - { text: avg ? avg + 'ms' : '-', color: 'yellow' }, - { text: p95 ? p95 + 'ms' : '-', color: 'yellow' }, - { text: p99 ? p99 + 'ms' : '-', color: 'yellow' } - ] - ]) - } - } - - private _apiStat: { - [key: string]: { - sendReq: number, - resTime: number[], - succ: number, - networkError: number, - otherError: number, - startTime: number, - last: { - sendReq: number, - resTime: number[], - succ: number, - networkError: number, - otherError: number, - startTime: number, - succTime: number - } - } - } = {}; - - private _maxApiNameLength = 0; - /** - * callApi 并且计入统计 - */ - callApi: typeof benchmarkClient.callApi = async (apiName, req) => { - this._maxApiNameLength = Math.max(apiName.length, this._maxApiNameLength); - - if (!this._apiStat[apiName]) { - this._apiStat[apiName] = { - sendReq: 0, - resTime: [], - succ: 0, - networkError: 0, - otherError: 0, - startTime: Date.now(), - last: { - sendReq: 0, - resTime: [], - succ: 0, - networkError: 0, - otherError: 0, - startTime: Date.now(), - succTime: 0 - } - }; - } - - ++this._apiStat[apiName].sendReq; - ++this._apiStat[apiName].last.sendReq; - - let startTime = Date.now(); - let ret = await benchmarkClient.callApi(apiName, req); - - if (ret.isSucc) { - this._apiStat[apiName].last.succTime = Date.now(); - this._apiStat[apiName].resTime.push(Date.now() - startTime); - this._apiStat[apiName].last.resTime.push(Date.now() - startTime); - ++this._apiStat[apiName].succ; - ++this._apiStat[apiName].last.succ; - } - else { - if (ret.err.type === TsrpcErrorType.NetworkError) { - ++this._apiStat[apiName].networkError; - ++this._apiStat[apiName].last.networkError; - } - else { - ++this._apiStat[apiName].otherError; - ++this._apiStat[apiName].last.otherError; - } - } - - return ret; - } - - private _report() { - console.log(new Date().format('hh:mm:ss').gray, `Started=${this._progress!.started}/${this._config.total}, Finished=${this._progress!.finished}, Succ=${this._progress!.succ.toString().green}, Fail=${this._progress!.fail.toString()[this._progress!.fail > 0 ? 'red' : 'white']}`, - this._progress!.lastSuccTime ? `TPS=${this._progress!.succ / (this._progress!.lastSuccTime - this._progress!.startTime) * 1000 | 0}` : '') - - for (let key in this._apiStat) { - let stat = this._apiStat[key]; - - let send = stat.last.sendReq; - let succ = stat.last.resTime.length; - let netErr = stat.last.networkError; - let apiErr = stat.last.otherError; - - this._logTable([ - [{ text: 'Api' + key + ' '.repeat(this._maxApiNameLength - key.length), color: 'green' }, 'Send', 'Succ', 'QPS', 'NetErr', 'ApiErr'], - ['', '' + send, - { text: '' + succ, color: 'green' }, - { text: '' + (succ / (stat.last.succTime - stat.last.startTime) * 1000 | 0), color: 'green' }, - netErr ? { text: '' + netErr, color: 'red' } : '0', - apiErr ? { text: '' + apiErr, color: 'red' } : '0' - ] - ]) - - Object.assign(stat.last, { - sendReq: 0, - resTime: [], - succ: 0, - networkError: 0, - otherError: 0, - startTime: Date.now(), - }) - } - } - - private _logTable(rows: [TableCellItem[], TableCellItem[]]) { - let cellWidths: number[] = []; - for (let cell of rows[0]) { - cellWidths.push(typeof cell === 'string' ? cell.length + 4 : cell.text.length + 4); - } - - for (let row of rows) { - let line = ''; - for (let i = 0; i < row.length; ++i) { - let cell = row[i]; - let cellWidth = cellWidths[i]; - if (typeof cell === 'string') { - line += cell + ' '.repeat(cellWidth - cell.length); - } - else { - line += cell.text[cell.color] + ' '.repeat(cellWidth - cell.text.length); - } - } - console.log(line); - } - } -} - -export const benchmarkClient = new HttpClient(serviceProto, { - server: benchmarkConfig.server, - logger: { - debug: function () { }, - log: function () { }, - warn: function () { }, - error: function () { }, - }, - timeout: benchmarkConfig.timeout, - agent: new (benchmarkConfig.server.startsWith('https') ? https : http).Agent({ - keepAlive: true - }) -}) - -type TableCellItem = (string | { text: string, color: 'green' | 'red' | 'yellow' }); \ No newline at end of file diff --git a/benchmark/models/WsRunner.ts b/benchmark/models/WsRunner.ts deleted file mode 100644 index 677f39c..0000000 --- a/benchmark/models/WsRunner.ts +++ /dev/null @@ -1,283 +0,0 @@ -import assert from 'assert'; -import 'colors'; -import 'k8w-extend-native'; -import { TsrpcErrorType } from "tsrpc-proto"; -import { WsClient } from '../../src/client/ws/WsClient'; -import { benchmarkConfig } from "../config/BenchmarkConfig"; -import { serviceProto } from '../protocols/proto'; - -export interface WsRunnerConfig { - total: number; - concurrency: number; - showError?: boolean; -} - -export class WsRunner { - - private _config: WsRunnerConfig; - - // 执行单个事务的方法 - private _single: (this: WsRunner) => Promise; - - // 执行进度信息 - private _progress?: { - startTime: number, - lastSuccTime?: number, - started: number, - finished: number, - succ: number, - fail: number - }; - - constructor(single: WsRunner['_single'], config: WsRunnerConfig) { - this._single = single.bind(this); - this._config = config; - } - - async start() { - this._progress = { - startTime: Date.now(), - started: 0, - finished: 0, - succ: 0, - fail: 0 - } - - assert.ok(await benchmarkClient.connect(), 'Connect failed'); - - // 启动并发 - for (let i = 0; i < this._config.concurrency; ++i) { - this._doTrans(); - } - - console.log('Benchmark start!'); - this._startReport(); - } - - private _doTrans() { - if (this._isStoped || !this._progress) { - return; - } - - if (this._progress.started < this._config.total) { - ++this._progress.started; - let startTime = Date.now(); - this._single().then(v => { - ++this._progress!.succ; - this._progress!.lastSuccTime = Date.now(); - }).catch(e => { - ++this._progress!.fail; - if (this._config.showError) { - console.error('[Error]', e.message); - } - }).then(() => { - ++this._progress!.finished; - if (this._progress!.finished === this._config.total) { - this._finish(); - } - else { - this._doTrans(); - } - }) - } - } - - private _reportInterval?: NodeJS.Timeout; - private _startReport() { - this._reportInterval = setInterval(() => { - this._report(); - }, 1000) - } - - private _isStoped = false; - stop() { - this._isStoped = true; - } - - private _finish() { - if (!this._progress) { - return; - } - - this._reportInterval && clearInterval(this._reportInterval); - - console.log('\n\n-------------------------------\n Benchmark finished! \n-------------------------------'); - - let usedTime = Date.now() - this._progress.startTime; - console.log(` Transaction Execution Result `.bgBlue.white); - console.log(`Started=${this._progress.started}, Finished=${this._progress.finished}, UsedTime=${usedTime}ms`.green); - console.log(`Succ=${this._progress.succ}, Fail=${this._progress.fail}, TPS=${this._progress.succ / (this._progress.lastSuccTime! - this._progress.startTime) * 1000 | 0}\n`.green) - - // TIME TPS(完成的) - console.log(` API Execution Result `.bgBlue.white); - - // [KEY] RPS(完成的) AVG P95 P99 - for (let key in this._apiStat) { - let stat = this._apiStat[key]; - stat.resTime = stat.resTime.orderBy(v => v); - - let send = stat.sendReq; - let succ = stat.resTime.length; - let netErr = stat.networkError; - let apiErr = stat.otherError; - let avg = stat.resTime[stat.resTime.length >> 1] | 0; - let p95 = stat.resTime[stat.resTime.length * 0.95 | 0] | 0; - let p99 = stat.resTime[stat.resTime.length * 0.99 | 0] | 0; - - this._logTable([ - [{ text: 'Api' + key + ' '.repeat(this._maxApiNameLength - key.length), color: 'green' }, 'Send', 'Succ', 'QPS', 'NetErr', 'ApiErr', 'AVG ', 'P95 ', 'P99 '], - ['', '' + send, - { text: '' + succ, color: 'green' }, - { text: '' + (succ / (stat.last.succTime - stat.startTime) * 1000 | 0), color: 'green' }, - netErr ? { text: '' + netErr, color: 'red' } : '0', - apiErr ? { text: '' + apiErr, color: 'red' } : '0', - { text: avg ? avg + 'ms' : '-', color: 'yellow' }, - { text: p95 ? p95 + 'ms' : '-', color: 'yellow' }, - { text: p99 ? p99 + 'ms' : '-', color: 'yellow' } - ] - ]) - } - } - - private _apiStat: { - [key: string]: { - sendReq: number, - resTime: number[], - succ: number, - networkError: number, - otherError: number, - startTime: number, - last: { - sendReq: number, - resTime: number[], - succ: number, - networkError: number, - otherError: number, - startTime: number, - succTime: number - } - } - } = {}; - - private _maxApiNameLength = 0; - /** - * callApi 并且计入统计 - */ - callApi: typeof benchmarkClient.callApi = async (apiName, req) => { - this._maxApiNameLength = Math.max(apiName.length, this._maxApiNameLength); - - if (!this._apiStat[apiName]) { - this._apiStat[apiName] = { - sendReq: 0, - resTime: [], - succ: 0, - networkError: 0, - otherError: 0, - startTime: Date.now(), - last: { - sendReq: 0, - resTime: [], - succ: 0, - networkError: 0, - otherError: 0, - startTime: Date.now(), - succTime: 0 - } - }; - } - - ++this._apiStat[apiName].sendReq; - ++this._apiStat[apiName].last.sendReq; - - let startTime = Date.now(); - let ret = await benchmarkClient.callApi(apiName, req); - - if (ret.isSucc) { - this._apiStat[apiName].last.succTime = Date.now(); - this._apiStat[apiName].resTime.push(Date.now() - startTime); - this._apiStat[apiName].last.resTime.push(Date.now() - startTime); - ++this._apiStat[apiName].succ; - ++this._apiStat[apiName].last.succ; - } - else { - if (ret.err.type === TsrpcErrorType.NetworkError) { - ++this._apiStat[apiName].networkError; - ++this._apiStat[apiName].last.networkError; - } - else { - ++this._apiStat[apiName].otherError; - ++this._apiStat[apiName].last.otherError; - } - } - - return ret; - } - - private _report() { - console.log(new Date().format('hh:mm:ss').gray, `Started=${this._progress!.started}/${this._config.total}, Finished=${this._progress!.finished}, Succ=${this._progress!.succ.toString().green}, Fail=${this._progress!.fail.toString()[this._progress!.fail > 0 ? 'red' : 'white']}`, - this._progress!.lastSuccTime ? `TPS=${this._progress!.succ / (this._progress!.lastSuccTime - this._progress!.startTime) * 1000 | 0}` : '') - - for (let key in this._apiStat) { - let stat = this._apiStat[key]; - - let send = stat.last.sendReq; - let succ = stat.last.resTime.length; - let netErr = stat.last.networkError; - let apiErr = stat.last.otherError; - - this._logTable([ - [{ text: 'Api' + key + ' '.repeat(this._maxApiNameLength - key.length), color: 'green' }, 'Send', 'Succ', 'QPS', 'NetErr', 'ApiErr'], - ['', '' + send, - { text: '' + succ, color: 'green' }, - { text: '' + (succ / (stat.last.succTime - stat.last.startTime) * 1000 | 0), color: 'green' }, - netErr ? { text: '' + netErr, color: 'red' } : '0', - apiErr ? { text: '' + apiErr, color: 'red' } : '0' - ] - ]) - - Object.assign(stat.last, { - sendReq: 0, - resTime: [], - succ: 0, - networkError: 0, - otherError: 0, - startTime: Date.now(), - }) - } - } - - private _logTable(rows: [TableCellItem[], TableCellItem[]]) { - let cellWidths: number[] = []; - for (let cell of rows[0]) { - cellWidths.push(typeof cell === 'string' ? cell.length + 4 : cell.text.length + 4); - } - - for (let row of rows) { - let line = ''; - for (let i = 0; i < row.length; ++i) { - let cell = row[i]; - let cellWidth = cellWidths[i]; - if (typeof cell === 'string') { - line += cell + ' '.repeat(cellWidth - cell.length); - } - else { - line += cell.text[cell.color] + ' '.repeat(cellWidth - cell.text.length); - } - } - console.log(line); - } - } -} - -export const benchmarkClient = new WsClient(serviceProto, { - server: benchmarkConfig.server, - logger: { - debug: function () { }, - log: function () { }, - warn: function () { }, - error: function () { }, - }, - timeout: benchmarkConfig.timeout -}) - -type TableCellItem = (string | { text: string, color: 'green' | 'red' | 'yellow' }); \ No newline at end of file diff --git a/benchmark/protocols/PtlTest.ts b/benchmark/protocols/PtlTest.ts deleted file mode 100644 index 24a3e06..0000000 --- a/benchmark/protocols/PtlTest.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { uint } from 'tsbuffer-schema'; -export interface ReqTest { - a?: uint; - b?: string; - c?: boolean; - d?: Uint8Array; -} - -export interface ResTest { - a?: uint; - b?: string; - c?: boolean; - d?: Uint8Array; -} \ No newline at end of file diff --git a/benchmark/protocols/proto.ts b/benchmark/protocols/proto.ts deleted file mode 100644 index dae4eb8..0000000 --- a/benchmark/protocols/proto.ts +++ /dev/null @@ -1,104 +0,0 @@ -import { ServiceProto } from 'tsrpc-proto'; -import { ReqTest, ResTest } from './PtlTest' - -export interface ServiceType { - api: { - "Test": { - req: ReqTest, - res: ResTest - } - }, - msg: { - - } -} - -export const serviceProto: ServiceProto = { - "services": [ - { - "id": 0, - "name": "Test", - "type": "api" - } - ], - "types": { - "PtlTest/ReqTest": { - "type": "Interface", - "properties": [ - { - "id": 0, - "name": "a", - "type": { - "type": "Number", - "scalarType": "uint" - }, - "optional": true - }, - { - "id": 1, - "name": "b", - "type": { - "type": "String" - }, - "optional": true - }, - { - "id": 2, - "name": "c", - "type": { - "type": "Boolean" - }, - "optional": true - }, - { - "id": 3, - "name": "d", - "type": { - "type": "Buffer", - "arrayType": "Uint8Array" - }, - "optional": true - } - ] - }, - "PtlTest/ResTest": { - "type": "Interface", - "properties": [ - { - "id": 0, - "name": "a", - "type": { - "type": "Number", - "scalarType": "uint" - }, - "optional": true - }, - { - "id": 1, - "name": "b", - "type": { - "type": "String" - }, - "optional": true - }, - { - "id": 2, - "name": "c", - "type": { - "type": "Boolean" - }, - "optional": true - }, - { - "id": 3, - "name": "d", - "type": { - "type": "Buffer", - "arrayType": "Uint8Array" - }, - "optional": true - } - ] - } - } -}; \ No newline at end of file diff --git a/benchmark/server/http.ts b/benchmark/server/http.ts deleted file mode 100644 index 6127a65..0000000 --- a/benchmark/server/http.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { HttpServer } from '../../src/index'; -import { serviceProto } from "../protocols/proto"; - -async function main() { - let server = new HttpServer(serviceProto, { - logger: { - debug: () => { }, - log: () => { }, - error: console.error.bind(console), - warn: console.warn.bind(console) - } - }); - - server.implementApi('Test', call => { - call.succ(call.req); - }); - - await server.start(); - - setInterval(() => { - let used = process.memoryUsage().heapUsed / 1024 / 1024; - console.log(`内存: ${Math.round(used * 100) / 100} MB`); - }, 2000) -} - -main(); \ No newline at end of file diff --git a/benchmark/server/ws.ts b/benchmark/server/ws.ts deleted file mode 100644 index 4ef9980..0000000 --- a/benchmark/server/ws.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { WsServer } from '../../src/index'; -import { serviceProto } from "../protocols/proto"; - -async function main() { - let server = new WsServer(serviceProto, { - logger: { - debug: () => { }, - log: () => { }, - error: console.error.bind(console), - warn: console.warn.bind(console) - } - }); - - server.implementApi('Test', call => { - call.succ(call.req); - }); - - await server.start(); - - setInterval(() => { - let used = process.memoryUsage().heapUsed / 1024 / 1024; - console.log(`内存: ${Math.round(used * 100) / 100} MB`); - }, 2000) -} - -main(); \ No newline at end of file diff --git a/benchmark/tsconfig.json b/benchmark/tsconfig.json deleted file mode 100644 index e7f648d..0000000 --- a/benchmark/tsconfig.json +++ /dev/null @@ -1,63 +0,0 @@ -{ - "compilerOptions": { - /* Basic Options */ - // "incremental": true, /* Enable incremental compilation */ - "target": "es6", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */ - "module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */ - // "lib": [], /* Specify library files to be included in the compilation. */ - // "allowJs": true, /* Allow javascript files to be compiled. */ - // "checkJs": true, /* Report errors in .js files. */ - // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */ - // "declaration": true, /* Generates corresponding '.d.ts' file. */ - // "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */ - // "sourceMap": true, /* Generates corresponding '.map' file. */ - // "outFile": "./", /* Concatenate and emit output to single file. */ - // "outDir": "./", /* Redirect output structure to the directory. */ - // "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */ - // "composite": true, /* Enable project compilation */ - // "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */ - // "removeComments": true, /* Do not emit comments to output. */ - // "noEmit": true, /* Do not emit outputs. */ - // "importHelpers": true, /* Import emit helpers from 'tslib'. */ - // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */ - // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ - - /* Strict Type-Checking Options */ - "strict": true, /* Enable all strict type-checking options. */ - // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ - // "strictNullChecks": true, /* Enable strict null checks. */ - // "strictFunctionTypes": true, /* Enable strict checking of function types. */ - // "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */ - // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ - // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ - // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ - - /* Additional Checks */ - // "noUnusedLocals": true, /* Report errors on unused locals. */ - // "noUnusedParameters": true, /* Report errors on unused parameters. */ - // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ - // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ - - /* Module Resolution Options */ - // "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */ - // "baseUrl": "./", /* Base directory to resolve non-absolute module names. */ - // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ - // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ - // "typeRoots": [], /* List of folders to include type definitions from. */ - // "types": [], /* Type declaration files to be included in compilation. */ - // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ - "esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */ - // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ - // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ - - /* Source Map Options */ - // "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */ - // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ - // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */ - // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ - - /* Experimental Options */ - // "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */ - // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ - } -} diff --git a/benchmark/ws.ts b/benchmark/ws.ts deleted file mode 100644 index 123fc97..0000000 --- a/benchmark/ws.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { benchmarkConfig } from './config/BenchmarkConfig'; -import { WsRunner } from './models/WsRunner'; - -const req = { - a: 123456, - b: 'Hello, World!', - c: true, - d: new Uint8Array(100000) -} - -new WsRunner(async function () { - await this.callApi('Test', req); -}, benchmarkConfig).start(); \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 938d855..37b09e3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,442 +1,36 @@ { - "name": "tsrpc", - "version": "3.3.0", + "name": "tsrpc_test-.", + "version": "0.1.0", "lockfileVersion": 2, "requires": true, "packages": { "": { - "name": "tsrpc", - "version": "3.3.0", - "license": "MIT", + "name": "tsrpc_test-.", + "version": "0.1.0", "dependencies": { - "@types/ws": "^7.4.7", - "bson": "*", - "chalk": "^4.1.2", - "tsbuffer": "^2.2.2", - "tsrpc-base-client": "^2.0.5", - "tsrpc-proto": "^1.4.1", - "uuid": "^8.3.2", - "ws": "^7.5.7" + "tsrpc": "^3.3.0" }, "devDependencies": { - "@microsoft/api-documenter": "^7.17.9", - "@microsoft/api-extractor": "^7.22.2", - "@types/chai": "^4.3.1", "@types/mocha": "^8.2.3", "@types/node": "^15.14.9", - "@types/uuid": "^8.3.4", - "chai": "^4.3.6", "mocha": "^9.2.2", - "nyc": "^15.1.0", - "rollup": "^2.70.2", - "rollup-plugin-typescript2": "^0.31.2", + "onchange": "^7.1.0", "ts-node": "^10.7.0", - "typescript": "^4.6.3" + "tsrpc-cli": "^2.4.3", + "typescript": "^4.6.4" } }, - "node_modules/@ampproject/remapping": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.1.2.tgz", - "integrity": "sha512-hoyByceqwKirw7w3Z7gnIIZC3Wx3J484Y3L/cMpXFbr7d9ZQj2mODrirNzcJa+SM3UlpWXYvKV4RlRpFXlWgXg==", - "dev": true, - "dependencies": { - "@jridgewell/trace-mapping": "^0.3.0" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/code-frame": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.7.tgz", - "integrity": "sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg==", - "dev": true, - "dependencies": { - "@babel/highlight": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/compat-data": { - "version": "7.17.0", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.17.0.tgz", - "integrity": "sha512-392byTlpGWXMv4FbyWw3sAZ/FrW/DrwqLGXpy0mbyNe9Taqv1mg9yON5/o0cnr8XYCkFTZbC1eV+c+LAROgrng==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/core": { - "version": "7.17.5", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.17.5.tgz", - "integrity": "sha512-/BBMw4EvjmyquN5O+t5eh0+YqB3XXJkYD2cjKpYtWOfFy4lQ4UozNSmxAcWT8r2XtZs0ewG+zrfsqeR15i1ajA==", - "dev": true, - "dependencies": { - "@ampproject/remapping": "^2.1.0", - "@babel/code-frame": "^7.16.7", - "@babel/generator": "^7.17.3", - "@babel/helper-compilation-targets": "^7.16.7", - "@babel/helper-module-transforms": "^7.16.7", - "@babel/helpers": "^7.17.2", - "@babel/parser": "^7.17.3", - "@babel/template": "^7.16.7", - "@babel/traverse": "^7.17.3", - "@babel/types": "^7.17.0", - "convert-source-map": "^1.7.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.1.2", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/babel" - } - }, - "node_modules/@babel/core/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/@babel/generator": { - "version": "7.17.3", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.17.3.tgz", - "integrity": "sha512-+R6Dctil/MgUsZsZAkYgK+ADNSZzJRRy0TvY65T71z/CR854xHQ1EweBYXdfT+HNeN7w0cSJJEzgxZMv40pxsg==", - "dev": true, - "dependencies": { - "@babel/types": "^7.17.0", - "jsesc": "^2.5.1", - "source-map": "^0.5.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/generator/node_modules/source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/@babel/helper-compilation-targets": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.16.7.tgz", - "integrity": "sha512-mGojBwIWcwGD6rfqgRXVlVYmPAv7eOpIemUG3dGnDdCY4Pae70ROij3XmfrH6Fa1h1aiDylpglbZyktfzyo/hA==", - "dev": true, - "dependencies": { - "@babel/compat-data": "^7.16.4", - "@babel/helper-validator-option": "^7.16.7", - "browserslist": "^4.17.5", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-compilation-targets/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/@babel/helper-environment-visitor": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.16.7.tgz", - "integrity": "sha512-SLLb0AAn6PkUeAfKJCCOl9e1R53pQlGAfc4y4XuMRZfqeMYLE0dM1LMhqbGAlGQY0lfw5/ohoYWAe9V1yibRag==", - "dev": true, - "dependencies": { - "@babel/types": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-function-name": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.16.7.tgz", - "integrity": "sha512-QfDfEnIUyyBSR3HtrtGECuZ6DAyCkYFp7GHl75vFtTnn6pjKeK0T1DB5lLkFvBea8MdaiUABx3osbgLyInoejA==", - "dev": true, - "dependencies": { - "@babel/helper-get-function-arity": "^7.16.7", - "@babel/template": "^7.16.7", - "@babel/types": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-get-function-arity": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.16.7.tgz", - "integrity": "sha512-flc+RLSOBXzNzVhcLu6ujeHUrD6tANAOU5ojrRx/as+tbzf8+stUCj7+IfRRoAbEZqj/ahXEMsjhOhgeZsrnTw==", - "dev": true, - "dependencies": { - "@babel/types": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-hoist-variables": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.16.7.tgz", - "integrity": "sha512-m04d/0Op34H5v7pbZw6pSKP7weA6lsMvfiIAMeIvkY/R4xQtBSMFEigu9QTZ2qB/9l22vsxtM8a+Q8CzD255fg==", - "dev": true, - "dependencies": { - "@babel/types": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-imports": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.16.7.tgz", - "integrity": "sha512-LVtS6TqjJHFc+nYeITRo6VLXve70xmq7wPhWTqDJusJEgGmkAACWwMiTNrvfoQo6hEhFwAIixNkvB0jPXDL8Wg==", - "dev": true, - "dependencies": { - "@babel/types": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-transforms": { - "version": "7.17.6", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.17.6.tgz", - "integrity": "sha512-2ULmRdqoOMpdvkbT8jONrZML/XALfzxlb052bldftkicAUy8AxSCkD5trDPQcwHNmolcl7wP6ehNqMlyUw6AaA==", - "dev": true, - "dependencies": { - "@babel/helper-environment-visitor": "^7.16.7", - "@babel/helper-module-imports": "^7.16.7", - "@babel/helper-simple-access": "^7.16.7", - "@babel/helper-split-export-declaration": "^7.16.7", - "@babel/helper-validator-identifier": "^7.16.7", - "@babel/template": "^7.16.7", - "@babel/traverse": "^7.17.3", - "@babel/types": "^7.17.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-simple-access": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.16.7.tgz", - "integrity": "sha512-ZIzHVyoeLMvXMN/vok/a4LWRy8G2v205mNP0XOuf9XRLyX5/u9CnVulUtDgUTama3lT+bf/UqucuZjqiGuTS1g==", - "dev": true, - "dependencies": { - "@babel/types": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-split-export-declaration": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.16.7.tgz", - "integrity": "sha512-xbWoy/PFoxSWazIToT9Sif+jJTlrMcndIsaOKvTA6u7QEo7ilkRZpjew18/W3c7nm8fXdUDXh02VXTbZ0pGDNw==", - "dev": true, - "dependencies": { - "@babel/types": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz", - "integrity": "sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-option": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.16.7.tgz", - "integrity": "sha512-TRtenOuRUVo9oIQGPC5G9DgK4743cdxvtOw0weQNpZXaS16SCBi5MNjZF8vba3ETURjZpTbVn7Vvcf2eAwFozQ==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helpers": { - "version": "7.17.2", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.17.2.tgz", - "integrity": "sha512-0Qu7RLR1dILozr/6M0xgj+DFPmi6Bnulgm9M8BVa9ZCWxDqlSnqt3cf8IDPB5m45sVXUZ0kuQAgUrdSFFH79fQ==", - "dev": true, - "dependencies": { - "@babel/template": "^7.16.7", - "@babel/traverse": "^7.17.0", - "@babel/types": "^7.17.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/highlight": { - "version": "7.16.10", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.16.10.tgz", - "integrity": "sha512-5FnTQLSLswEj6IkgVw5KusNUUFY9ZGqe/TRFnP/BKYHYgfh7tc+C7mwiy95/yNP7Dh9x580Vv8r7u7ZfTBFxdw==", - "dev": true, - "dependencies": { - "@babel/helper-validator-identifier": "^7.16.7", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/highlight/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/@babel/highlight/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "node_modules/@blakeembrey/deque": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@blakeembrey/deque/-/deque-1.0.5.tgz", + "integrity": "sha512-6xnwtvp9DY1EINIKdTfvfeAtCYw4OqBZJhtiqkT3ivjnEfa25VQ3TsKvaFfKm8MyGIEfE95qLe+bNEt3nB0Ylg==", "dev": true }, - "node_modules/@babel/highlight/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/@babel/highlight/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/parser": { - "version": "7.17.3", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.17.3.tgz", - "integrity": "sha512-7yJPvPV+ESz2IUTPbOL+YkIGyCqOyNIzdguKQuJGnH7bg1WTIifuM21YqokFt/THWh1AkCRn9IgoykTRCBVpzA==", - "dev": true, - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/template": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.16.7.tgz", - "integrity": "sha512-I8j/x8kHUrbYRTUxXrrMbfCa7jxkE7tZre39x3kjr9hvI82cK1FfqLygotcWN5kdPGWcLdWMHpSBavse5tWw3w==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.16.7", - "@babel/parser": "^7.16.7", - "@babel/types": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/traverse": { - "version": "7.17.3", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.17.3.tgz", - "integrity": "sha512-5irClVky7TxRWIRtxlh2WPUUOLhcPN06AGgaQSB8AEwuyEBgJVuJ5imdHm5zxk8w0QS5T+tDfnDxAlhWjpb7cw==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.16.7", - "@babel/generator": "^7.17.3", - "@babel/helper-environment-visitor": "^7.16.7", - "@babel/helper-function-name": "^7.16.7", - "@babel/helper-hoist-variables": "^7.16.7", - "@babel/helper-split-export-declaration": "^7.16.7", - "@babel/parser": "^7.17.3", - "@babel/types": "^7.17.0", - "debug": "^4.1.0", - "globals": "^11.1.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/types": { - "version": "7.17.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.17.0.tgz", - "integrity": "sha512-TmKSNO4D5rzhL5bjWFcVHHLETzfQ/AmbKpKPOSjlP0WoHZ6L911fgoOKY4Alp/emzG4cHJdyN49zpgkbXFEHHw==", - "dev": true, - "dependencies": { - "@babel/helper-validator-identifier": "^7.16.7", - "to-fast-properties": "^2.0.0" - }, - "engines": { - "node": ">=6.9.0" - } + "node_modules/@blakeembrey/template": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@blakeembrey/template/-/template-1.1.0.tgz", + "integrity": "sha512-iZf+UWfL+DogJVpd/xMQyP6X6McYd6ArdYoPMiv/zlOTzeXXfQbYxBNJJBF6tThvsjLMbA8tLjkCdm9RWMFCCw==", + "dev": true }, "node_modules/@cspotcode/source-map-consumer": { "version": "0.8.0", @@ -459,262 +53,6 @@ "node": ">=12" } }, - "node_modules/@istanbuljs/load-nyc-config": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", - "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", - "dev": true, - "dependencies": { - "camelcase": "^5.3.1", - "find-up": "^4.1.0", - "get-package-type": "^0.1.0", - "js-yaml": "^3.13.1", - "resolve-from": "^5.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "dependencies": { - "p-locate": "^4.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@istanbuljs/load-nyc-config/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/@istanbuljs/load-nyc-config/node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "dependencies": { - "p-limit": "^2.2.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@istanbuljs/schema": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", - "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.0.5.tgz", - "integrity": "sha512-VPeQ7+wH0itvQxnG+lIzWgkysKIr3L9sslimFW55rHMdGu/qCQ5z5h9zq4gI8uBtqkpHhsF4Z/OwExufUCThew==", - "dev": true, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.11", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.11.tgz", - "integrity": "sha512-Fg32GrJo61m+VqYSdRSjRXMjQ06j8YIYfcTqndLYVAaHmroZHLJZCydsWBOTDqXS2v+mjxohBWEMfg97GXmYQg==", - "dev": true - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.4", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.4.tgz", - "integrity": "sha512-vFv9ttIedivx0ux3QSjhgtCVjPZd5l46ZOMDSCwnH1yUO2e964gO8LZGyv2QkqcgR6TnBU1v+1IFqmeoG+0UJQ==", - "dev": true, - "dependencies": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" - } - }, - "node_modules/@microsoft/api-documenter": { - "version": "7.17.9", - "resolved": "https://registry.npmjs.org/@microsoft/api-documenter/-/api-documenter-7.17.9.tgz", - "integrity": "sha512-crmuhaqKG0zfeoCjIjvRfUzUe/JZaMGE3HS7FwtH7jROy/AHU8nL2Zpq8RzFRNKV9yHMiF8wVcEgfGmH5oM3hw==", - "dev": true, - "dependencies": { - "@microsoft/api-extractor-model": "7.17.1", - "@microsoft/tsdoc": "0.14.1", - "@rushstack/node-core-library": "3.45.3", - "@rushstack/ts-command-line": "4.10.9", - "colors": "~1.2.1", - "js-yaml": "~3.13.1", - "resolve": "~1.17.0" - }, - "bin": { - "api-documenter": "bin/api-documenter" - } - }, - "node_modules/@microsoft/api-extractor": { - "version": "7.22.2", - "resolved": "https://registry.npmjs.org/@microsoft/api-extractor/-/api-extractor-7.22.2.tgz", - "integrity": "sha512-G7vXz6UHz+qoaUGPf2k5Md4bSpHii9nFys3sIe3bmFUbmhAe+HfSB/dCn1PsLhW7tZfEXwMHTj7fbL5vcZkrEw==", - "dev": true, - "dependencies": { - "@microsoft/api-extractor-model": "7.17.1", - "@microsoft/tsdoc": "0.14.1", - "@microsoft/tsdoc-config": "~0.16.1", - "@rushstack/node-core-library": "3.45.3", - "@rushstack/rig-package": "0.3.10", - "@rushstack/ts-command-line": "4.10.9", - "colors": "~1.2.1", - "lodash": "~4.17.15", - "resolve": "~1.17.0", - "semver": "~7.3.0", - "source-map": "~0.6.1", - "typescript": "~4.5.2" - }, - "bin": { - "api-extractor": "bin/api-extractor" - } - }, - "node_modules/@microsoft/api-extractor-model": { - "version": "7.17.1", - "resolved": "https://registry.npmjs.org/@microsoft/api-extractor-model/-/api-extractor-model-7.17.1.tgz", - "integrity": "sha512-DCDtD8TdEpNk2lW4JvXgwwpxKy70P0JLad55iahwO8A+C63KYsrHIpAzo0FUauh5pwJ0v5QVNIJ+OBgKGteemg==", - "dev": true, - "dependencies": { - "@microsoft/tsdoc": "0.14.1", - "@microsoft/tsdoc-config": "~0.16.1", - "@rushstack/node-core-library": "3.45.3" - } - }, - "node_modules/@microsoft/api-extractor/node_modules/typescript": { - "version": "4.5.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.5.5.tgz", - "integrity": "sha512-TCTIul70LyWe6IJWT8QSYeA54WQe8EjQFU4wY52Fasj5UKx88LNYKCgBEHcOMOrFF1rKGbD8v/xcNWVUq9SymA==", - "dev": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=4.2.0" - } - }, - "node_modules/@microsoft/tsdoc": { - "version": "0.14.1", - "resolved": "https://registry.npmjs.org/@microsoft/tsdoc/-/tsdoc-0.14.1.tgz", - "integrity": "sha512-6Wci+Tp3CgPt/B9B0a3J4s3yMgLNSku6w5TV6mN+61C71UqsRBv2FUibBf3tPGlNxebgPHMEUzKpb1ggE8KCKw==", - "dev": true - }, - "node_modules/@microsoft/tsdoc-config": { - "version": "0.16.1", - "resolved": "https://registry.npmjs.org/@microsoft/tsdoc-config/-/tsdoc-config-0.16.1.tgz", - "integrity": "sha512-2RqkwiD4uN6MLnHFljqBlZIXlt/SaUT6cuogU1w2ARw4nKuuppSmR0+s+NC+7kXBQykd9zzu0P4HtBpZT5zBpQ==", - "dev": true, - "dependencies": { - "@microsoft/tsdoc": "0.14.1", - "ajv": "~6.12.6", - "jju": "~1.4.0", - "resolve": "~1.19.0" - } - }, - "node_modules/@microsoft/tsdoc-config/node_modules/resolve": { - "version": "1.19.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.19.0.tgz", - "integrity": "sha512-rArEXAgsBG4UgRGcynxWIWKFvh/XZCcS8UJdHhwy91zwAvCZIbcs+vAbflgBnNjYMs/i/i+/Ux6IZhML1yPvxg==", - "dev": true, - "dependencies": { - "is-core-module": "^2.1.0", - "path-parse": "^1.0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/@rollup/pluginutils": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-4.1.2.tgz", - "integrity": "sha512-ROn4qvkxP9SyPeHaf7uQC/GPFY6L/OWy9+bd9AwcjOAWQwxRscoEyAUD8qCY5o5iL4jqQwoLk2kaTKJPb/HwzQ==", - "dev": true, - "dependencies": { - "estree-walker": "^2.0.1", - "picomatch": "^2.2.2" - }, - "engines": { - "node": ">= 8.0.0" - } - }, - "node_modules/@rushstack/node-core-library": { - "version": "3.45.3", - "resolved": "https://registry.npmjs.org/@rushstack/node-core-library/-/node-core-library-3.45.3.tgz", - "integrity": "sha512-Rn0mxqC3MPb+YbvaeFcRWfcYHLwyZ99/ffYA8chpq5OpqoY+Mr1ycTbMvzl5AxWf1pYmi/2+Eo3iTOsQdYR8xw==", - "dev": true, - "dependencies": { - "@types/node": "12.20.24", - "colors": "~1.2.1", - "fs-extra": "~7.0.1", - "import-lazy": "~4.0.0", - "jju": "~1.4.0", - "resolve": "~1.17.0", - "semver": "~7.3.0", - "timsort": "~0.3.0", - "z-schema": "~5.0.2" - } - }, - "node_modules/@rushstack/node-core-library/node_modules/@types/node": { - "version": "12.20.24", - "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.24.tgz", - "integrity": "sha512-yxDeaQIAJlMav7fH5AQqPH1u8YIuhYJXYBzxaQ4PifsU0GDO38MSdmEDeRlIxrKbC6NbEaaEHDanWb+y30U8SQ==", - "dev": true - }, - "node_modules/@rushstack/rig-package": { - "version": "0.3.10", - "resolved": "https://registry.npmjs.org/@rushstack/rig-package/-/rig-package-0.3.10.tgz", - "integrity": "sha512-4Z2HhXM4YBWOi4ZYFQNK6Yxz641v+cvc8NKiaNZh+RIdNb3D4Rfpy3XUkggbCozpfDriBfL1+KaXlJtfJfAIXw==", - "dev": true, - "dependencies": { - "resolve": "~1.17.0", - "strip-json-comments": "~3.1.1" - } - }, - "node_modules/@rushstack/ts-command-line": { - "version": "4.10.9", - "resolved": "https://registry.npmjs.org/@rushstack/ts-command-line/-/ts-command-line-4.10.9.tgz", - "integrity": "sha512-TE3eZgHNVHOY3p8lp38FoNEJUr0+swPb24sCcYuwlC+MHgMGXyJNM+p7l3TKSBRiY01XShoL2k601oGwL00KlA==", - "dev": true, - "dependencies": { - "@types/argparse": "1.0.38", - "argparse": "~1.0.9", - "colors": "~1.2.1", - "string-argv": "~0.3.1" - } - }, "node_modules/@tsconfig/node10": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.8.tgz", @@ -739,18 +77,6 @@ "integrity": "sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA==", "dev": true }, - "node_modules/@types/argparse": { - "version": "1.0.38", - "resolved": "https://registry.npmjs.org/@types/argparse/-/argparse-1.0.38.tgz", - "integrity": "sha512-ebDJ9b0e702Yr7pWgB0jzm+CX4Srzz8RcXtLJDJB+BSccqMa36uyH/zUsSYao5+BD1ytv3k3rPYCq4mAE1hsXA==", - "dev": true - }, - "node_modules/@types/chai": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.1.tgz", - "integrity": "sha512-/zPMqDkzSZ8t3VtxOa4KPq7uzzW978M9Tvh+j7GHKuo6k6GTLxPJ4J5gE5cjfJ26pnXst0N5Hax8Sr0T2Mi9zQ==", - "dev": true - }, "node_modules/@types/mocha": { "version": "8.2.3", "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-8.2.3.tgz", @@ -762,12 +88,6 @@ "resolved": "https://registry.npmjs.org/@types/node/-/node-15.14.9.tgz", "integrity": "sha512-qjd88DrCxupx/kJD5yQgZdcYKZKSIGBVDIBE1/LTGcNm3d2Np/jxojkdePDdfnBHJc5W7vSMpbJ1aB7p/Py69A==" }, - "node_modules/@types/uuid": { - "version": "8.3.4", - "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.4.tgz", - "integrity": "sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw==", - "dev": true - }, "node_modules/@types/ws": { "version": "7.4.7", "resolved": "https://registry.npmjs.org/@types/ws/-/ws-7.4.7.tgz", @@ -782,47 +102,10 @@ "integrity": "sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==", "dev": true }, - "node_modules/@yarn-tool/resolve-package": { - "version": "1.0.43", - "resolved": "https://registry.npmjs.org/@yarn-tool/resolve-package/-/resolve-package-1.0.43.tgz", - "integrity": "sha512-axFruggDvKkfTuevJzqYFJ9XtJkKqaDYjXA1Ugx9mEpMX8HRGib86IgryAf5HfN3RCbawIkwCLjzGFm8H4DkPA==", - "dev": true, - "dependencies": { - "pkg-dir": "< 6 >= 5", - "tslib": "^2.3.1", - "upath2": "^3.1.12" - } - }, - "node_modules/@yarn-tool/resolve-package/node_modules/pkg-dir": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-5.0.0.tgz", - "integrity": "sha512-NPE8TDbzl/3YQYY7CSS228s3g2ollTFnc+Qi3tqmqJp9Vg2ovUpixcJEo2HJScN2Ez+kEaal6y70c0ehqJBJeA==", - "dev": true, - "dependencies": { - "find-up": "^5.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@yarn-tool/resolve-package/node_modules/upath2": { - "version": "3.1.12", - "resolved": "https://registry.npmjs.org/upath2/-/upath2-3.1.12.tgz", - "integrity": "sha512-yC3eZeCyCXFWjy7Nu4pgjLhXNYjuzuUmJiRgSSw6TJp8Emc+E4951HGPJf+bldFC5SL7oBLeNbtm1fGzXn2gxw==", - "dev": true, - "dependencies": { - "path-is-network-drive": "^1.0.13", - "path-strip-sep": "^1.0.10", - "tslib": "^2.3.1" - }, - "peerDependencies": { - "@types/node": "*" - } - }, "node_modules/acorn": { - "version": "8.7.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz", - "integrity": "sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==", + "version": "8.7.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.1.tgz", + "integrity": "sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A==", "dev": true, "bin": { "acorn": "bin/acorn" @@ -840,35 +123,6 @@ "node": ">=0.4.0" } }, - "node_modules/aggregate-error": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", - "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", - "dev": true, - "dependencies": { - "clean-stack": "^2.0.0", - "indent-string": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "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", @@ -878,6 +132,21 @@ "node": ">=6" } }, + "node_modules/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", @@ -914,24 +183,6 @@ "node": ">= 8" } }, - "node_modules/append-transform": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/append-transform/-/append-transform-2.0.0.tgz", - "integrity": "sha512-7yeyCEurROLQJFv5Xj4lEGTy0borxepjFv1g22oAdqFu//SrAlDl1O1Nxx15SH1RoliUml6p8dwJW9jvZughhg==", - "dev": true, - "dependencies": { - "default-require-extensions": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/archy": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz", - "integrity": "sha1-+cjBN1fMHde8N5rHeyxipcKGjEA=", - "dev": true - }, "node_modules/arg": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", @@ -939,22 +190,10 @@ "dev": true }, "node_modules/argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "dependencies": { - "sprintf-js": "~1.0.2" - } - }, - "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": "*" - } + "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/balanced-match": { "version": "1.0.2", @@ -990,6 +229,17 @@ "node": ">=8" } }, + "node_modules/bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "dev": true, + "dependencies": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, "node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -1018,33 +268,10 @@ "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", "dev": true }, - "node_modules/browserslist": { - "version": "4.19.3", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.19.3.tgz", - "integrity": "sha512-XK3X4xtKJ+Txj8G5c30B4gsm71s69lqXlkYui4s6EkKxuv49qjYlY6oVd+IFJ73d4YymtM3+djvvt/R/iJwwDg==", - "dev": true, - "dependencies": { - "caniuse-lite": "^1.0.30001312", - "electron-to-chromium": "^1.4.71", - "escalade": "^3.1.1", - "node-releases": "^2.0.2", - "picocolors": "^1.0.0" - }, - "bin": { - "browserslist": "cli.js" - }, - "engines": { - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - } - }, "node_modules/bson": { - "version": "4.6.1", - "resolved": "https://registry.npmjs.org/bson/-/bson-4.6.1.tgz", - "integrity": "sha512-I1LQ7Hz5zgwR4QquilLNZwbhPw0Apx7i7X9kGMBTsqPdml/03Q9NBtD9nt/19ahjlphktQImrnderxqpzeVDjw==", + "version": "4.6.3", + "resolved": "https://registry.npmjs.org/bson/-/bson-4.6.3.tgz", + "integrity": "sha512-rAqP5hcUVJhXP2MCSNVsf0oM2OGU1So6A9pVRDYayvJ5+hygXHQApf87wd5NlhPM1J9RJnbqxIG/f8QTzRoQ4A==", "dependencies": { "buffer": "^5.6.0" }, @@ -1075,56 +302,16 @@ "ieee754": "^1.1.13" } }, - "node_modules/caching-transform": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/caching-transform/-/caching-transform-4.0.0.tgz", - "integrity": "sha512-kpqOvwXnjjN44D89K5ccQC+RUrsy7jB/XLlRrx0D7/2HNcTPqzsb6XgYoErwko6QsV184CA2YgS1fxDiiDZMWA==", - "dev": true, - "dependencies": { - "hasha": "^5.0.0", - "make-dir": "^3.0.0", - "package-hash": "^4.0.0", - "write-file-atomic": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", "dev": true, "engines": { - "node": ">=6" - } - }, - "node_modules/caniuse-lite": { - "version": "1.0.30001312", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001312.tgz", - "integrity": "sha512-Wiz1Psk2MEK0pX3rUzWaunLTZzqS2JYZFzNKqAiJGiuxIjRPLgV6+VDPOg6lQOUxmDwhTlh198JsTTi8Hzw6aQ==", - "dev": true, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - } - }, - "node_modules/chai": { - "version": "4.3.6", - "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.6.tgz", - "integrity": "sha512-bbcp3YfHCUzMOvKqsztczerVgBKSsEijCySNlHHbX3VG1nskvqjz5Rfso1gGwD6w6oOV3eI60pKuMOV5MV7p3Q==", - "dev": true, - "dependencies": { - "assertion-error": "^1.1.0", - "check-error": "^1.0.2", - "deep-eql": "^3.0.1", - "get-func-name": "^2.0.0", - "loupe": "^2.3.1", - "pathval": "^1.1.1", - "type-detect": "^4.0.5" + "node": ">=10" }, - "engines": { - "node": ">=4" + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/chalk": { @@ -1142,15 +329,23 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/check-error": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", - "integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=", - "dev": true, + "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==", + "dependencies": { + "has-flag": "^4.0.0" + }, "engines": { - "node": "*" + "node": ">=8" } }, + "node_modules/chardet": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", + "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", + "dev": true + }, "node_modules/chokidar": { "version": "3.5.3", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", @@ -1178,13 +373,37 @@ "fsevents": "~2.3.2" } }, - "node_modules/clean-stack": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", - "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "node_modules/cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "dev": true, + "dependencies": { + "restore-cursor": "^3.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cli-spinners": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.6.1.tgz", + "integrity": "sha512-x/5fWmGMnbKQAaNwN+UZlV79qBLM9JFnJuJ03gIi5whrob0xV0ofNVHy9DhwGdsMJQc2OKv0oGmLzvaqvAVv+g==", "dev": true, "engines": { "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-width": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", + "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==", + "dev": true, + "engines": { + "node": ">= 10" } }, "node_modules/cliui": { @@ -1198,6 +417,15 @@ "wrap-ansi": "^7.0.0" } }, + "node_modules/clone": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=", + "dev": true, + "engines": { + "node": ">=0.8" + } + }, "node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -1214,26 +442,16 @@ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, - "node_modules/colors": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/colors/-/colors-1.2.5.tgz", - "integrity": "sha512-erNRLao/Y3Fv54qUa0LBB+//Uf3YwMUmdJinN20yMXm9zdKKqH9wt7R9IIVZ+K7ShzfpLV/Zg8+VyrBJYB4lpg==", - "dev": true, - "engines": { - "node": ">=0.1.90" - } - }, "node_modules/commander": { "version": "2.20.3", "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "dev": true, - "optional": true + "dev": true }, - "node_modules/commondir": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", - "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", + "node_modules/commandpost": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/commandpost/-/commandpost-1.4.0.tgz", + "integrity": "sha512-aE2Y4MTFJ870NuB/+2z1cXBhSBBzRydVVjzhFC4gtenEhpnj15yu0qptWGJsO9YGrcPZ3ezX8AWb1VA391MKpQ==", "dev": true }, "node_modules/concat-map": { @@ -1242,15 +460,6 @@ "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", "dev": true }, - "node_modules/convert-source-map": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz", - "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==", - "dev": true, - "dependencies": { - "safe-buffer": "~5.1.1" - } - }, "node_modules/create-require": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", @@ -1295,36 +504,24 @@ "dev": true }, "node_modules/decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", + "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": ">=0.10.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/deep-eql": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz", - "integrity": "sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==", + "node_modules/defaults": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.3.tgz", + "integrity": "sha1-xlYFHpgX2f8I7YgUd/P+QBnz730=", "dev": true, "dependencies": { - "type-detect": "^4.0.0" - }, - "engines": { - "node": ">=0.12" - } - }, - "node_modules/default-require-extensions": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-3.0.0.tgz", - "integrity": "sha512-ek6DpXq/SCpvjhpFsLFRVtIxJCRw6fUR42lYMVZuUMK7n8eMz4Uh5clckdBjEpLhn/gEBZo7hDJnJcwdKLKQjg==", - "dev": true, - "dependencies": { - "strip-bom": "^4.0.0" - }, - "engines": { - "node": ">=8" + "clone": "^1.0.2" } }, "node_modules/diff": { @@ -1336,11 +533,20 @@ "node": ">=0.3.1" } }, - "node_modules/electron-to-chromium": { - "version": "1.4.72", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.72.tgz", - "integrity": "sha512-9LkRQwjW6/wnSfevR21a3k8sOJ+XWSH7kkzs9/EUenKmuDkndP3W9y1yCZpOxufwGbX3JV8glZZSDb4o95zwXQ==", - "dev": true + "node_modules/editorconfig": { + "version": "0.15.3", + "resolved": "https://registry.npmjs.org/editorconfig/-/editorconfig-0.15.3.tgz", + "integrity": "sha512-M9wIMFx96vq0R4F+gRpY3o2exzb8hEj/n9S8unZtHSvYjibBp/iMufSzvmOcV/laG0ZtuTVGtiJggPOSW2r93g==", + "dev": true, + "dependencies": { + "commander": "^2.19.0", + "lru-cache": "^4.1.5", + "semver": "^5.6.0", + "sigmund": "^1.0.1" + }, + "bin": { + "editorconfig": "bin/editorconfig" + } }, "node_modules/emoji-regex": { "version": "8.0.0", @@ -1348,11 +554,14 @@ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "dev": true }, - "node_modules/es6-error": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz", - "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==", - "dev": true + "node_modules/end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dev": true, + "dependencies": { + "once": "^1.4.0" + } }, "node_modules/escalade": { "version": "3.1.1", @@ -1375,36 +584,66 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "node_modules/execa": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-4.1.0.tgz", + "integrity": "sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==", "dev": true, - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" + "dependencies": { + "cross-spawn": "^7.0.0", + "get-stream": "^5.0.0", + "human-signals": "^1.1.1", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.0", + "onetime": "^5.1.0", + "signal-exit": "^3.0.2", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/external-editor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", + "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", + "dev": true, + "dependencies": { + "chardet": "^0.7.0", + "iconv-lite": "^0.4.24", + "tmp": "^0.0.33" }, "engines": { "node": ">=4" } }, - "node_modules/estree-walker": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", - "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", - "dev": true + "node_modules/figures": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", + "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", + "dev": true, + "dependencies": { + "escape-string-regexp": "^1.0.5" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, - "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/figures/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true, + "engines": { + "node": ">=0.8.0" + } }, "node_modules/fill-range": { "version": "7.0.1", @@ -1418,23 +657,6 @@ "node": ">=8" } }, - "node_modules/find-cache-dir": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz", - "integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==", - "dev": true, - "dependencies": { - "commondir": "^1.0.1", - "make-dir": "^3.0.2", - "pkg-dir": "^4.1.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/avajs/find-cache-dir?sponsor=1" - } - }, "node_modules/find-up": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", @@ -1460,51 +682,18 @@ "flat": "cli.js" } }, - "node_modules/foreground-child": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-2.0.0.tgz", - "integrity": "sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA==", - "dev": true, - "dependencies": { - "cross-spawn": "^7.0.0", - "signal-exit": "^3.0.2" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/fromentries": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/fromentries/-/fromentries-1.3.2.tgz", - "integrity": "sha512-cHEpEQHUg0f8XdtZCc2ZAhrHzKzT0MrFUTcvx+hfxYu7rGMDc5SKoXFh+n4YigxsHXRzc6OrCshdR1bWH6HHyg==", - "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/fs-extra": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz", - "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", "dev": true, "dependencies": { - "graceful-fs": "^4.1.2", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" }, "engines": { - "node": ">=6 <7 || >=8" + "node": ">=12" } }, "node_modules/fs.realpath": { @@ -1527,21 +716,6 @@ "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, - "node_modules/function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true - }, - "node_modules/gensync": { - "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/get-caller-file": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", @@ -1551,22 +725,19 @@ "node": "6.* || 8.* || >= 10.*" } }, - "node_modules/get-func-name": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", - "integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=", + "node_modules/get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", "dev": true, + "dependencies": { + "pump": "^3.0.0" + }, "engines": { - "node": "*" - } - }, - "node_modules/get-package-type": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", - "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", - "dev": true, - "engines": { - "node": ">=8.0.0" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/glob": { @@ -1601,19 +772,22 @@ "node": ">= 6" } }, - "node_modules/globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "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": ">=4" + "node": "*" } }, "node_modules/graceful-fs": { - "version": "4.2.9", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.9.tgz", - "integrity": "sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ==", + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", "dev": true }, "node_modules/growl": { @@ -1625,18 +799,6 @@ "node": ">=4.x" } }, - "node_modules/has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.1" - }, - "engines": { - "node": ">= 0.4.0" - } - }, "node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -1645,22 +807,6 @@ "node": ">=8" } }, - "node_modules/hasha": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/hasha/-/hasha-5.2.2.tgz", - "integrity": "sha512-Hrp5vIK/xr5SkeN2onO32H0MgNZ0f17HRNH39WfL0SYUNOTZ5Lz1TJ8Pajo/87dYGEFlLMm7mIc/k/s6Bvz9HQ==", - "dev": true, - "dependencies": { - "is-stream": "^2.0.0", - "type-fest": "^0.8.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/he": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", @@ -1670,11 +816,26 @@ "he": "bin/he" } }, - "node_modules/html-escaper": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", - "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", - "dev": true + "node_modules/human-signals": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz", + "integrity": "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==", + "dev": true, + "engines": { + "node": ">=8.12.0" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } }, "node_modules/ieee754": { "version": "1.2.1", @@ -1695,31 +856,13 @@ } ] }, - "node_modules/import-lazy": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-4.0.0.tgz", - "integrity": "sha512-rKtvo6a868b5Hu3heneU+L4yEQ4jYKLtjpnPeUdK7h0yzXGmyBTypknlkCvHFBqfX9YlorEiMM6Dnq/5atfHkw==", + "node_modules/ignore": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", + "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", "dev": true, "engines": { - "node": ">=8" - } - }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", - "dev": true, - "engines": { - "node": ">=0.8.19" - } - }, - "node_modules/indent-string": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", - "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", - "dev": true, - "engines": { - "node": ">=8" + "node": ">= 4" } }, "node_modules/inflight": { @@ -1738,6 +881,44 @@ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "dev": true }, + "node_modules/inquirer": { + "version": "8.2.4", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.4.tgz", + "integrity": "sha512-nn4F01dxU8VeKfq192IjLsxu0/OmMZ4Lg3xKAns148rCaXP6ntAoEkVYZThWjwON8AlzdZZi6oqnhNbxUG9hVg==", + "dev": true, + "dependencies": { + "ansi-escapes": "^4.2.1", + "chalk": "^4.1.1", + "cli-cursor": "^3.1.0", + "cli-width": "^3.0.0", + "external-editor": "^3.0.3", + "figures": "^3.0.0", + "lodash": "^4.17.21", + "mute-stream": "0.0.8", + "ora": "^5.4.1", + "run-async": "^2.4.0", + "rxjs": "^7.5.5", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0", + "through": "^2.3.6", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/invert-kv": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-3.0.1.tgz", + "integrity": "sha512-CYdFeFexxhv/Bcny+Q0BfOV+ltRlJcd4BBZBYFX/O0u4npJrgZtIcjokegtiSMAvlMTJ+Koq0GBCc//3bueQxw==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sindresorhus/invert-kv?sponsor=1" + } + }, "node_modules/is-binary-path": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", @@ -1750,18 +931,6 @@ "node": ">=8" } }, - "node_modules/is-core-module": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.1.tgz", - "integrity": "sha512-SdNCUs284hr40hFTFP6l0IfZ/RSrMXF3qgoRHd3/79unUTvrFO/JoXwkGm+5J/Oe3E/b5GsnG330uUNgRpu1PA==", - "dev": true, - "dependencies": { - "has": "^1.0.3" - }, - "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", @@ -1792,6 +961,15 @@ "node": ">=0.10.0" } }, + "node_modules/is-interactive": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", + "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", @@ -1822,12 +1000,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", - "dev": true - }, "node_modules/is-unicode-supported": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", @@ -1840,202 +1012,42 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/is-windows": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", - "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", "dev": true }, - "node_modules/istanbul-lib-coverage": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", - "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-hook": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-hook/-/istanbul-lib-hook-3.0.0.tgz", - "integrity": "sha512-Pt/uge1Q9s+5VAZ+pCo16TYMWPBIl+oaNIjgLQxcX0itS6ueeaA+pEfThZpH8WxhFgCiEb8sAJY6MdUKgiIWaQ==", - "dev": true, - "dependencies": { - "append-transform": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-instrument": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.3.tgz", - "integrity": "sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ==", - "dev": true, - "dependencies": { - "@babel/core": "^7.7.5", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-coverage": "^3.0.0", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-instrument/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/istanbul-lib-processinfo": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/istanbul-lib-processinfo/-/istanbul-lib-processinfo-2.0.2.tgz", - "integrity": "sha512-kOwpa7z9hme+IBPZMzQ5vdQj8srYgAtaRqeI48NGmAQ+/5yKiHLV0QbYqQpxsdEF0+w14SoB8YbnHKcXE2KnYw==", - "dev": true, - "dependencies": { - "archy": "^1.0.0", - "cross-spawn": "^7.0.0", - "istanbul-lib-coverage": "^3.0.0-alpha.1", - "make-dir": "^3.0.0", - "p-map": "^3.0.0", - "rimraf": "^3.0.0", - "uuid": "^3.3.3" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-processinfo/node_modules/uuid": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", - "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", - "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", - "dev": true, - "bin": { - "uuid": "bin/uuid" - } - }, - "node_modules/istanbul-lib-report": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", - "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", - "dev": true, - "dependencies": { - "istanbul-lib-coverage": "^3.0.0", - "make-dir": "^3.0.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-source-maps": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", - "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", - "dev": true, - "dependencies": { - "debug": "^4.1.1", - "istanbul-lib-coverage": "^3.0.0", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/istanbul-reports": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.4.tgz", - "integrity": "sha512-r1/DshN4KSE7xWEknZLLLLDn5CJybV3nw01VTkp6D5jzLuELlcbudfj/eSQFvrKsJuTVCGnePO7ho82Nw9zzfw==", - "dev": true, - "dependencies": { - "html-escaper": "^2.0.0", - "istanbul-lib-report": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jju": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/jju/-/jju-1.4.0.tgz", - "integrity": "sha1-o6vicYryQaKykE+EpiWXDzia4yo=", - "dev": true - }, - "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": "3.13.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", - "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", + "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": "^1.0.7", - "esprima": "^4.0.0" + "argparse": "^2.0.1" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, - "node_modules/jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", - "dev": true, - "bin": { - "jsesc": "bin/jsesc" - }, - "engines": { - "node": ">=4" - } - }, - "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/json5": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz", - "integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==", + "node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", "dev": true, "dependencies": { - "minimist": "^1.2.5" + "universalify": "^2.0.0" }, - "bin": { - "json5": "lib/cli.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/jsonfile": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", - "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", - "dev": true, "optionalDependencies": { "graceful-fs": "^4.1.6" } }, + "node_modules/k8w-crypto": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/k8w-crypto/-/k8w-crypto-0.2.0.tgz", + "integrity": "sha512-M6u4eQ6CQaU5xO3s4zaUUp9G79xNDhXtTU0X7N80tDcBhQC5ggowlyOzj95v7WiCuk7xkV0aFsTmCpuf0m0djw==", + "dev": true + }, "node_modules/k8w-extend-native": { "version": "1.4.6", "resolved": "https://registry.npmjs.org/k8w-extend-native/-/k8w-extend-native-1.4.6.tgz", @@ -2061,6 +1073,18 @@ "resolved": "https://registry.npmjs.org/k8w-super-object/-/k8w-super-object-0.3.0.tgz", "integrity": "sha512-u2jfh4goYXKZmSucaLaOTaNbLRatjv0CSRpzE0KU0732+9XtYZFd5vrdw/mzJfK5fPHb/zyikOSHDX5mJrav+g==" }, + "node_modules/lcid": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/lcid/-/lcid-3.1.1.tgz", + "integrity": "sha512-M6T051+5QCGLBQb8id3hdvIW8+zeFV2FyBGFS9IEK5H9Wt4MueD4bW1eWikpHgZp+5xR3l5c8pZUkQsIA0BFZg==", + "dev": true, + "dependencies": { + "invert-kv": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/locate-path": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", @@ -2082,24 +1106,6 @@ "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", "dev": true }, - "node_modules/lodash.flattendeep": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz", - "integrity": "sha1-+wMJF/hqMTTlvJvsDWngAT3f7bI=", - "dev": true - }, - "node_modules/lodash.get": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", - "integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=", - "dev": true - }, - "node_modules/lodash.isequal": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", - "integrity": "sha1-QVxEePK8wwEgwizhDtMib30+GOA=", - "dev": true - }, "node_modules/log-symbols": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", @@ -2116,49 +1122,14 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/loupe": { - "version": "2.3.4", - "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.4.tgz", - "integrity": "sha512-OvKfgCC2Ndby6aSTREl5aCCPTNIzlDfQZvZxNUrBrihDhL3xcrYegTblhmEiCrg2kKQz4XsFIaemE5BF4ybSaQ==", - "dev": true, - "dependencies": { - "get-func-name": "^2.0.0" - } - }, "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==", + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", + "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", "dev": true, "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "dev": true, - "dependencies": { - "semver": "^6.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/make-dir/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, - "bin": { - "semver": "bin/semver.js" + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" } }, "node_modules/make-error": { @@ -2167,22 +1138,63 @@ "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", "dev": true }, + "node_modules/map-age-cleaner": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz", + "integrity": "sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==", + "dev": true, + "dependencies": { + "p-defer": "^1.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/mem": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/mem/-/mem-5.1.1.tgz", + "integrity": "sha512-qvwipnozMohxLXG1pOqoLiZKNkC4r4qqRucSoDwXowsNGDSULiqFTRUF05vcZWnwJSG22qTsynQhxbaMtnX9gw==", + "dev": true, + "dependencies": { + "map-age-cleaner": "^0.1.3", + "mimic-fn": "^2.1.0", + "p-is-promise": "^2.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-4.2.1.tgz", + "integrity": "sha512-9Uq1ChtSZO+Mxa/CL1eGizn2vRn3MlLgzhT0Iz8zaY8NdvxvB0d5QdPFmCKf7JKA9Lerx5vRrnwO03jsSfGG9g==", "dev": true, "dependencies": { "brace-expansion": "^1.1.7" }, "engines": { - "node": "*" + "node": ">=10" } }, "node_modules/minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", + "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", "dev": true }, "node_modules/mocha": { @@ -2228,57 +1240,18 @@ "url": "https://opencollective.com/mochajs" } }, - "node_modules/mocha/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/mocha/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/mocha/node_modules/minimatch": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-4.2.1.tgz", - "integrity": "sha512-9Uq1ChtSZO+Mxa/CL1eGizn2vRn3MlLgzhT0Iz8zaY8NdvxvB0d5QdPFmCKf7JKA9Lerx5vRrnwO03jsSfGG9g==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/mocha/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/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/mute-stream": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", + "dev": true + }, "node_modules/nanoid": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.1.tgz", @@ -2291,24 +1264,6 @@ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, - "node_modules/node-preload": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/node-preload/-/node-preload-0.2.1.tgz", - "integrity": "sha512-RM5oyBy45cLEoHqCeh+MNuFAxO0vTFBLskvQbOKnEE7YTTSN4tbN8QWDIPQ6L+WvKsB/qLEGpYe2ZZ9d4W9OIQ==", - "dev": true, - "dependencies": { - "process-on-spawn": "^1.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/node-releases": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.2.tgz", - "integrity": "sha512-XxYDdcQ6eKqp/YjI+tb2C5WM2LgjnZrfYg4vgQt49EK268b6gYCHsBLrK2qvJo4FmCtqmKezb0WZFK4fkrZNsg==", - "dev": true - }, "node_modules/normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", @@ -2318,165 +1273,18 @@ "node": ">=0.10.0" } }, - "node_modules/nyc": { - "version": "15.1.0", - "resolved": "https://registry.npmjs.org/nyc/-/nyc-15.1.0.tgz", - "integrity": "sha512-jMW04n9SxKdKi1ZMGhvUTHBN0EICCRkHemEoE5jm6mTYcqcdas0ATzgUgejlQUHMvpnOZqGB5Xxsv9KxJW1j8A==", + "node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", "dev": true, "dependencies": { - "@istanbuljs/load-nyc-config": "^1.0.0", - "@istanbuljs/schema": "^0.1.2", - "caching-transform": "^4.0.0", - "convert-source-map": "^1.7.0", - "decamelize": "^1.2.0", - "find-cache-dir": "^3.2.0", - "find-up": "^4.1.0", - "foreground-child": "^2.0.0", - "get-package-type": "^0.1.0", - "glob": "^7.1.6", - "istanbul-lib-coverage": "^3.0.0", - "istanbul-lib-hook": "^3.0.0", - "istanbul-lib-instrument": "^4.0.0", - "istanbul-lib-processinfo": "^2.0.2", - "istanbul-lib-report": "^3.0.0", - "istanbul-lib-source-maps": "^4.0.0", - "istanbul-reports": "^3.0.2", - "make-dir": "^3.0.0", - "node-preload": "^0.2.1", - "p-map": "^3.0.0", - "process-on-spawn": "^1.0.0", - "resolve-from": "^5.0.0", - "rimraf": "^3.0.0", - "signal-exit": "^3.0.2", - "spawn-wrap": "^2.0.0", - "test-exclude": "^6.0.0", - "yargs": "^15.0.2" - }, - "bin": { - "nyc": "bin/nyc.js" - }, - "engines": { - "node": ">=8.9" - } - }, - "node_modules/nyc/node_modules/cliui": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", - "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", - "dev": true, - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^6.2.0" - } - }, - "node_modules/nyc/node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" + "path-key": "^3.0.0" }, "engines": { "node": ">=8" } }, - "node_modules/nyc/node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "dependencies": { - "p-locate": "^4.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/nyc/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/nyc/node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "dependencies": { - "p-limit": "^2.2.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/nyc/node_modules/wrap-ansi": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", - "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/nyc/node_modules/y18n": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", - "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", - "dev": true - }, - "node_modules/nyc/node_modules/yargs": { - "version": "15.4.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", - "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", - "dev": true, - "dependencies": { - "cliui": "^6.0.0", - "decamelize": "^1.2.0", - "find-up": "^4.1.0", - "get-caller-file": "^2.0.1", - "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", - "set-blocking": "^2.0.0", - "string-width": "^4.2.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^18.1.2" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/nyc/node_modules/yargs-parser": { - "version": "18.1.3", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", - "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", - "dev": true, - "dependencies": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - }, - "engines": { - "node": ">=6" - } - }, "node_modules/once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -2486,6 +1294,106 @@ "wrappy": "1" } }, + "node_modules/onchange": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/onchange/-/onchange-7.1.0.tgz", + "integrity": "sha512-ZJcqsPiWUAUpvmnJri5TPBooqJOPmC0ttN65juhN15Q8xA+Nbg3BaxBHXQ45EistKKlKElb0edmbPWnKSBkvMg==", + "dev": true, + "dependencies": { + "@blakeembrey/deque": "^1.0.5", + "@blakeembrey/template": "^1.0.0", + "arg": "^4.1.3", + "chokidar": "^3.3.1", + "cross-spawn": "^7.0.1", + "ignore": "^5.1.4", + "tree-kill": "^1.2.2" + }, + "bin": { + "onchange": "dist/bin.js" + } + }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ora": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", + "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", + "dev": true, + "dependencies": { + "bl": "^4.1.0", + "chalk": "^4.1.0", + "cli-cursor": "^3.1.0", + "cli-spinners": "^2.5.0", + "is-interactive": "^1.0.0", + "is-unicode-supported": "^0.1.0", + "log-symbols": "^4.1.0", + "strip-ansi": "^6.0.0", + "wcwidth": "^1.0.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/os-locale": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-5.0.0.tgz", + "integrity": "sha512-tqZcNEDAIZKBEPnHPlVDvKrp7NzgLi7jRmhKiUoa2NUmhl13FtkAGLUVR+ZsYvApBQdBfYm43A4tXXQ4IrYLBA==", + "dev": true, + "dependencies": { + "execa": "^4.0.0", + "lcid": "^3.0.0", + "mem": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/p-defer": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-defer/-/p-defer-1.0.0.tgz", + "integrity": "sha1-n26xgvbJqozXQwBKfU+WsZaw+ww=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/p-is-promise": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-2.1.0.tgz", + "integrity": "sha512-Y3W0wlRPK8ZMRbNq97l4M5otioeA5lm1z7bkNkxCka8HSPjR0xRWmpCmc9utiaLP9Jb1eD8BgeIxTW4AIF45Pg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/p-limit": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", @@ -2516,42 +1424,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/p-map": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-3.0.0.tgz", - "integrity": "sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ==", - "dev": true, - "dependencies": { - "aggregate-error": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "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/package-hash": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/package-hash/-/package-hash-4.0.0.tgz", - "integrity": "sha512-whdkPIooSu/bASggZ96BWVvZTRMOFxnyUG5PnTSGKoJE2gd5mbVNmR2Nj20QFzxYYgAXpoqC+AiXzl+UMRh7zQ==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.1.15", - "hasha": "^5.0.0", - "lodash.flattendeep": "^4.4.0", - "release-zalgo": "^1.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", @@ -2570,15 +1442,6 @@ "node": ">=0.10.0" } }, - "node_modules/path-is-network-drive": { - "version": "1.0.13", - "resolved": "https://registry.npmjs.org/path-is-network-drive/-/path-is-network-drive-1.0.13.tgz", - "integrity": "sha512-Hg74mRN6mmXV+gTm3INjFK40ncAmC/Lo4qoQaSZ+GT3hZzlKdWQSqAjqyPeW0SvObP2W073WyYEBWY9d3wOm3A==", - "dev": true, - "dependencies": { - "tslib": "^2.3.1" - } - }, "node_modules/path-key": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", @@ -2588,36 +1451,6 @@ "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/path-strip-sep": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/path-strip-sep/-/path-strip-sep-1.0.10.tgz", - "integrity": "sha512-JpCy+8LAJQQTO1bQsb/84s1g+/Stm3h39aOpPRBQ/paMUGVPPZChLTOTKHoaCkc/6sKuF7yVsnq5Pe1S6xQGcA==", - "dev": true, - "dependencies": { - "tslib": "^2.3.1" - } - }, - "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/picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", - "dev": true - }, "node_modules/picomatch": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", @@ -2630,89 +1463,20 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/pkg-dir": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "node_modules/pseudomap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", + "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", + "dev": true + }, + "node_modules/pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", "dev": true, "dependencies": { - "find-up": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/pkg-dir/node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/pkg-dir/node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "dependencies": { - "p-locate": "^4.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/pkg-dir/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-dir/node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "dependencies": { - "p-limit": "^2.2.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/process-on-spawn": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/process-on-spawn/-/process-on-spawn-1.0.0.tgz", - "integrity": "sha512-1WsPDsUSMmZH5LeMLegqkPDrsGgsWwk1Exipy2hvB0o/F0ASzbpIctSCcZIK1ykJvtTJULEH+20WOFjMvGnCTg==", - "dev": true, - "dependencies": { - "fromentries": "^1.2.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", - "dev": true, - "engines": { - "node": ">=6" + "end-of-stream": "^1.1.0", + "once": "^1.3.1" } }, "node_modules/randombytes": { @@ -2724,6 +1488,20 @@ "safe-buffer": "^5.1.0" } }, + "node_modules/readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "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", @@ -2736,18 +1514,6 @@ "node": ">=8.10.0" } }, - "node_modules/release-zalgo": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/release-zalgo/-/release-zalgo-1.0.0.tgz", - "integrity": "sha1-CXALflB0Mpc5Mw5TXFqQ+2eFFzA=", - "dev": true, - "dependencies": { - "es6-error": "^4.0.1" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -2757,152 +1523,70 @@ "node": ">=0.10.0" } }, - "node_modules/require-main-filename": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", - "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", - "dev": true - }, - "node_modules/resolve": { - "version": "1.17.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz", - "integrity": "sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==", + "node_modules/restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", "dev": true, "dependencies": { - "path-parse": "^1.0.6" + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true, "engines": { "node": ">=8" } }, - "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/rollup": { - "version": "2.70.2", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.70.2.tgz", - "integrity": "sha512-EitogNZnfku65I1DD5Mxe8JYRUCy0hkK5X84IlDtUs+O6JRMpRciXTzyCUuX11b5L5pvjH+OmFXiQ3XjabcXgg==", - "dev": true, - "bin": { - "rollup": "dist/bin/rollup" - }, - "engines": { - "node": ">=10.0.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, - "node_modules/rollup-plugin-typescript2": { - "version": "0.31.2", - "resolved": "https://registry.npmjs.org/rollup-plugin-typescript2/-/rollup-plugin-typescript2-0.31.2.tgz", - "integrity": "sha512-hRwEYR1C8xDGVVMFJQdEVnNAeWRvpaY97g5mp3IeLnzhNXzSVq78Ye/BJ9PAaUfN4DXa/uDnqerifMOaMFY54Q==", - "dev": true, - "dependencies": { - "@rollup/pluginutils": "^4.1.2", - "@yarn-tool/resolve-package": "^1.0.40", - "find-cache-dir": "^3.3.2", - "fs-extra": "^10.0.0", - "resolve": "^1.20.0", - "tslib": "^2.3.1" - }, - "peerDependencies": { - "rollup": ">=1.26.3", - "typescript": ">=2.4.0" - } - }, - "node_modules/rollup-plugin-typescript2/node_modules/fs-extra": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.0.1.tgz", - "integrity": "sha512-NbdoVMZso2Lsrn/QwLXOy6rm0ufY2zEOKCDzJR/0kBsb0E6qed0P3iYK+Ath3BfvXEeu4JhEtXLgILx5psUfag==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/rollup-plugin-typescript2/node_modules/jsonfile": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", - "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", - "dev": true, - "dependencies": { - "universalify": "^2.0.0" - }, - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, - "node_modules/rollup-plugin-typescript2/node_modules/resolve": { - "version": "1.22.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz", - "integrity": "sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==", - "dev": true, - "dependencies": { - "is-core-module": "^2.8.1", - "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/rollup-plugin-typescript2/node_modules/universalify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", - "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", + "node_modules/run-async": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", + "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", "dev": true, "engines": { - "node": ">= 10.0.0" + "node": ">=0.12.0" + } + }, + "node_modules/rxjs": { + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.5.5.tgz", + "integrity": "sha512-sy+H0pQofO95VDmFLzyaw9xNJU4KTRSwQIGM6+iG3SypAtCiLDzpeG8sJrNCWn2Up9km+KhkvTdbkrdy+yzZdw==", + "dev": true, + "dependencies": { + "tslib": "^2.1.0" } }, "node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "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/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "dev": true }, "node_modules/semver": { - "version": "7.3.7", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", - "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" + "semver": "bin/semver" } }, "node_modules/serialize-javascript": { @@ -2914,12 +1598,6 @@ "randombytes": "^2.1.0" } }, - "node_modules/set-blocking": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", - "dev": true - }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -2941,51 +1619,25 @@ "node": ">=8" } }, + "node_modules/sigmund": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz", + "integrity": "sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA=", + "dev": true + }, "node_modules/signal-exit": { "version": "3.0.7", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", "dev": true }, - "node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/spawn-wrap": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/spawn-wrap/-/spawn-wrap-2.0.0.tgz", - "integrity": "sha512-EeajNjfN9zMnULLwhZZQU3GWBoFNkbngTUPfaawT4RkMiviTxcX0qfhVbGey39mfctfDHkWtuecgQ8NJcyQWHg==", + "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": { - "foreground-child": "^2.0.0", - "is-windows": "^1.0.2", - "make-dir": "^3.0.0", - "rimraf": "^3.0.0", - "signal-exit": "^3.0.2", - "which": "^2.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", - "dev": true - }, - "node_modules/string-argv": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.1.tgz", - "integrity": "sha512-a1uQGz7IyVy9YwhqjZIZu1c8JO8dNIe20xBmSS6qu9kv++k3JGzCVmprbNN5Kn+BgzD5E7YYwg1CcjuJMRNsvg==", - "dev": true, - "engines": { - "node": ">=0.6.19" + "safe-buffer": "~5.2.0" } }, "node_modules/string-width": { @@ -3014,13 +1666,13 @@ "node": ">=8" } }, - "node_modules/strip-bom": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", - "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", + "node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", "dev": true, "engines": { - "node": ">=8" + "node": ">=6" } }, "node_modules/strip-json-comments": { @@ -3036,55 +1688,36 @@ } }, "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==", + "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": ">=8" - } - }, - "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" + "node": ">=10" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/chalk/supports-color?sponsor=1" } }, - "node_modules/test-exclude": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", - "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", - "dev": true, - "dependencies": { - "@istanbuljs/schema": "^0.1.2", - "glob": "^7.1.4", - "minimatch": "^3.0.4" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/timsort": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/timsort/-/timsort-0.3.0.tgz", - "integrity": "sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q=", + "node_modules/through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", "dev": true }, - "node_modules/to-fast-properties": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", + "node_modules/tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", "dev": true, + "dependencies": { + "os-tmpdir": "~1.0.2" + }, "engines": { - "node": ">=4" + "node": ">=0.6.0" } }, "node_modules/to-regex-range": { @@ -3099,6 +1732,15 @@ "node": ">=8.0" } }, + "node_modules/tree-kill": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", + "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", + "dev": true, + "bin": { + "tree-kill": "cli.js" + } + }, "node_modules/ts-node": { "version": "10.7.0", "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.7.0.tgz", @@ -3161,6 +1803,19 @@ "tslib": "*" } }, + "node_modules/tsbuffer-proto-generator": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/tsbuffer-proto-generator/-/tsbuffer-proto-generator-1.7.1.tgz", + "integrity": "sha512-PU4fxphid6LMbhuyO++6BmXR7oG/5j/QthZcmmJQhxy5GjGeiIdqyV9Nf8ADEdsKAhE503J8r3JnIC5Pq1tbxA==", + "dev": true, + "dependencies": { + "k8w-crypto": "^0.2.0", + "k8w-extend-native": "^1.4.6", + "tsbuffer-schema": "^2.2.0", + "tslib": "*", + "typescript": "^4" + } + }, "node_modules/tsbuffer-schema": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/tsbuffer-schema/-/tsbuffer-schema-2.2.0.tgz", @@ -3177,9 +1832,24 @@ } }, "node_modules/tslib": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", - "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==" + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", + "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==" + }, + "node_modules/tsrpc": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/tsrpc/-/tsrpc-3.3.0.tgz", + "integrity": "sha512-a7QYKrCBRzHy/RJoJVltCsJYoppSpIFcbhrytgCG1EHBbBOKZADJi3+W9tjdOpiNG5330KjBfLhHPew/nf9e5w==", + "dependencies": { + "@types/ws": "^7.4.7", + "bson": "*", + "chalk": "^4.1.2", + "tsbuffer": "^2.2.2", + "tsrpc-base-client": "^2.0.5", + "tsrpc-proto": "^1.4.1", + "uuid": "^8.3.2", + "ws": "^7.5.7" + } }, "node_modules/tsrpc-base-client": { "version": "2.0.5", @@ -3192,46 +1862,59 @@ "tsrpc-proto": "^1.4.1" } }, + "node_modules/tsrpc-cli": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/tsrpc-cli/-/tsrpc-cli-2.4.3.tgz", + "integrity": "sha512-L7lUqIOiKIz0Yt2P64ji7sFb/qRLI4KjPF9JUpaP0HbvaYCMn7+l1xEhVK39C1JCnFJomtAIgceMtL571E4d+g==", + "dev": true, + "dependencies": { + "chalk": "^4.1.2", + "chokidar": "^3.5.3", + "fs-extra": "^10.1.0", + "glob": "^7.2.0", + "inquirer": "^8.2.3", + "k8w-extend-native": "^1.4.6", + "minimist": "^1.2.6", + "ora": "^5.4.1", + "os-locale": "^5.0.0", + "ts-node": "^10.7.0", + "tsbuffer": "^2.2.2", + "tsbuffer-proto-generator": "^1.7.1", + "tsbuffer-schema": "^2.2.0", + "tsrpc-proto": "^1.4.2", + "typescript": "^4.6.3", + "typescript-formatter": "^7.2.2" + }, + "bin": { + "tsrpc": "bin.js", + "tsrpc-cli": "bin.js" + } + }, "node_modules/tsrpc-proto": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/tsrpc-proto/-/tsrpc-proto-1.4.1.tgz", - "integrity": "sha512-qk0/vd5QSf8lx2kHxhhf59wji20RU7KjZ2md8NHLwFV09kLJ/jvR2kwM6lNQRIxYOrM9HvvdySlrnSJUkNkRyA==", + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/tsrpc-proto/-/tsrpc-proto-1.4.2.tgz", + "integrity": "sha512-MIjOfLixuk6C0CZZzgsBQX/RzlmPBhBasDhoyOUzdi4oOZekdDiia2q70B0ThzXPwIfnwa/uduZxkYx4jPzRdQ==", "dependencies": { "tsbuffer-schema": "^2.2.0", "tslib": "*" } }, - "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.8.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", - "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", "dev": true, "engines": { - "node": ">=8" - } - }, - "node_modules/typedarray-to-buffer": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", - "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", - "dev": true, - "dependencies": { - "is-typedarray": "^1.0.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/typescript": { - "version": "4.6.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.6.3.tgz", - "integrity": "sha512-yNIatDa5iaofVozS/uQJEl3JRWLKKGJKh6Yaiv0GLGSuhpFJe7P3SbHZ8/yjAHRQwKRoA6YZqlfjXWmVzoVSMw==", + "version": "4.6.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.6.4.tgz", + "integrity": "sha512-9ia/jWHIEbo49HfjrLGfKbZSuWo9iTMwXO+Ca3pRsSpbsMbc7/IU8NKdCZVRRBafVPGnoJeFL76ZOAA84I9fEg==", "dev": true, "bin": { "tsc": "bin/tsc", @@ -3241,24 +1924,40 @@ "node": ">=4.2.0" } }, - "node_modules/universalify": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", - "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", - "dev": true, - "engines": { - "node": ">= 4.0.0" - } - }, - "node_modules/uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "node_modules/typescript-formatter": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/typescript-formatter/-/typescript-formatter-7.2.2.tgz", + "integrity": "sha512-V7vfI9XArVhriOTYHPzMU2WUnm5IMdu9X/CPxs8mIMGxmTBFpDABlbkBka64PZJ9/xgQeRpK8KzzAG4MPzxBDQ==", "dev": true, "dependencies": { - "punycode": "^2.1.0" + "commandpost": "^1.0.0", + "editorconfig": "^0.15.0" + }, + "bin": { + "tsfmt": "bin/tsfmt" + }, + "engines": { + "node": ">= 4.2.0" + }, + "peerDependencies": { + "typescript": "^2.1.6 || >=2.7.0-dev || >=2.8.0-dev || >=2.9.0-dev || >=3.0.0-dev" } }, + "node_modules/universalify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", + "dev": true, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", + "dev": true + }, "node_modules/uuid": { "version": "8.3.2", "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", @@ -3268,18 +1967,18 @@ } }, "node_modules/v8-compile-cache-lib": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.0.tgz", - "integrity": "sha512-mpSYqfsFvASnSn5qMiwrr4VKfumbPyONLCOPmsR3A6pTY/r0+tSaVbgPWSAIuzbk3lCTa+FForeTiO+wBQGkjA==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", "dev": true }, - "node_modules/validator": { - "version": "13.7.0", - "resolved": "https://registry.npmjs.org/validator/-/validator-13.7.0.tgz", - "integrity": "sha512-nYXQLCBkpJ8X6ltALua9dRrZDHVYxjJ1wgskNt1lH9fzGjs3tgojGSCBjmEPwkWS1y29+DrizMTW19Pr9uB2nw==", + "node_modules/wcwidth": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", + "integrity": "sha1-8LDc+RW8X/FSivrbLA4XtTLaL+g=", "dev": true, - "engines": { - "node": ">= 0.10" + "dependencies": { + "defaults": "^1.0.3" } }, "node_modules/which": { @@ -3297,12 +1996,6 @@ "node": ">= 8" } }, - "node_modules/which-module": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", - "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", - "dev": true - }, "node_modules/workerpool": { "version": "6.2.0", "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.0.tgz", @@ -3332,18 +2025,6 @@ "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", "dev": true }, - "node_modules/write-file-atomic": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", - "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", - "dev": true, - "dependencies": { - "imurmurhash": "^0.1.4", - "is-typedarray": "^1.0.0", - "signal-exit": "^3.0.2", - "typedarray-to-buffer": "^3.1.5" - } - }, "node_modules/ws": { "version": "7.5.7", "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.7.tgz", @@ -3374,9 +2055,9 @@ } }, "node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", "dev": true }, "node_modules/yargs": { @@ -3421,30 +2102,6 @@ "node": ">=10" } }, - "node_modules/yargs-unparser/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/yargs-unparser/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/yn": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", @@ -3465,341 +2122,21 @@ "funding": { "url": "https://github.com/sponsors/sindresorhus" } - }, - "node_modules/z-schema": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/z-schema/-/z-schema-5.0.3.tgz", - "integrity": "sha512-sGvEcBOTNum68x9jCpCVGPFJ6mWnkD0YxOcddDlJHRx3tKdB2q8pCHExMVZo/AV/6geuVJXG7hljDaWG8+5GDw==", - "dev": true, - "dependencies": { - "lodash.get": "^4.4.2", - "lodash.isequal": "^4.5.0", - "validator": "^13.7.0" - }, - "bin": { - "z-schema": "bin/z-schema" - }, - "engines": { - "node": ">=8.0.0" - }, - "optionalDependencies": { - "commander": "^2.20.3" - } } }, "dependencies": { - "@ampproject/remapping": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.1.2.tgz", - "integrity": "sha512-hoyByceqwKirw7w3Z7gnIIZC3Wx3J484Y3L/cMpXFbr7d9ZQj2mODrirNzcJa+SM3UlpWXYvKV4RlRpFXlWgXg==", - "dev": true, - "requires": { - "@jridgewell/trace-mapping": "^0.3.0" - } - }, - "@babel/code-frame": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.7.tgz", - "integrity": "sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg==", - "dev": true, - "requires": { - "@babel/highlight": "^7.16.7" - } - }, - "@babel/compat-data": { - "version": "7.17.0", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.17.0.tgz", - "integrity": "sha512-392byTlpGWXMv4FbyWw3sAZ/FrW/DrwqLGXpy0mbyNe9Taqv1mg9yON5/o0cnr8XYCkFTZbC1eV+c+LAROgrng==", + "@blakeembrey/deque": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@blakeembrey/deque/-/deque-1.0.5.tgz", + "integrity": "sha512-6xnwtvp9DY1EINIKdTfvfeAtCYw4OqBZJhtiqkT3ivjnEfa25VQ3TsKvaFfKm8MyGIEfE95qLe+bNEt3nB0Ylg==", "dev": true }, - "@babel/core": { - "version": "7.17.5", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.17.5.tgz", - "integrity": "sha512-/BBMw4EvjmyquN5O+t5eh0+YqB3XXJkYD2cjKpYtWOfFy4lQ4UozNSmxAcWT8r2XtZs0ewG+zrfsqeR15i1ajA==", - "dev": true, - "requires": { - "@ampproject/remapping": "^2.1.0", - "@babel/code-frame": "^7.16.7", - "@babel/generator": "^7.17.3", - "@babel/helper-compilation-targets": "^7.16.7", - "@babel/helper-module-transforms": "^7.16.7", - "@babel/helpers": "^7.17.2", - "@babel/parser": "^7.17.3", - "@babel/template": "^7.16.7", - "@babel/traverse": "^7.17.3", - "@babel/types": "^7.17.0", - "convert-source-map": "^1.7.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.1.2", - "semver": "^6.3.0" - }, - "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - } - } - }, - "@babel/generator": { - "version": "7.17.3", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.17.3.tgz", - "integrity": "sha512-+R6Dctil/MgUsZsZAkYgK+ADNSZzJRRy0TvY65T71z/CR854xHQ1EweBYXdfT+HNeN7w0cSJJEzgxZMv40pxsg==", - "dev": true, - "requires": { - "@babel/types": "^7.17.0", - "jsesc": "^2.5.1", - "source-map": "^0.5.0" - }, - "dependencies": { - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - } - } - }, - "@babel/helper-compilation-targets": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.16.7.tgz", - "integrity": "sha512-mGojBwIWcwGD6rfqgRXVlVYmPAv7eOpIemUG3dGnDdCY4Pae70ROij3XmfrH6Fa1h1aiDylpglbZyktfzyo/hA==", - "dev": true, - "requires": { - "@babel/compat-data": "^7.16.4", - "@babel/helper-validator-option": "^7.16.7", - "browserslist": "^4.17.5", - "semver": "^6.3.0" - }, - "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - } - } - }, - "@babel/helper-environment-visitor": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.16.7.tgz", - "integrity": "sha512-SLLb0AAn6PkUeAfKJCCOl9e1R53pQlGAfc4y4XuMRZfqeMYLE0dM1LMhqbGAlGQY0lfw5/ohoYWAe9V1yibRag==", - "dev": true, - "requires": { - "@babel/types": "^7.16.7" - } - }, - "@babel/helper-function-name": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.16.7.tgz", - "integrity": "sha512-QfDfEnIUyyBSR3HtrtGECuZ6DAyCkYFp7GHl75vFtTnn6pjKeK0T1DB5lLkFvBea8MdaiUABx3osbgLyInoejA==", - "dev": true, - "requires": { - "@babel/helper-get-function-arity": "^7.16.7", - "@babel/template": "^7.16.7", - "@babel/types": "^7.16.7" - } - }, - "@babel/helper-get-function-arity": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.16.7.tgz", - "integrity": "sha512-flc+RLSOBXzNzVhcLu6ujeHUrD6tANAOU5ojrRx/as+tbzf8+stUCj7+IfRRoAbEZqj/ahXEMsjhOhgeZsrnTw==", - "dev": true, - "requires": { - "@babel/types": "^7.16.7" - } - }, - "@babel/helper-hoist-variables": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.16.7.tgz", - "integrity": "sha512-m04d/0Op34H5v7pbZw6pSKP7weA6lsMvfiIAMeIvkY/R4xQtBSMFEigu9QTZ2qB/9l22vsxtM8a+Q8CzD255fg==", - "dev": true, - "requires": { - "@babel/types": "^7.16.7" - } - }, - "@babel/helper-module-imports": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.16.7.tgz", - "integrity": "sha512-LVtS6TqjJHFc+nYeITRo6VLXve70xmq7wPhWTqDJusJEgGmkAACWwMiTNrvfoQo6hEhFwAIixNkvB0jPXDL8Wg==", - "dev": true, - "requires": { - "@babel/types": "^7.16.7" - } - }, - "@babel/helper-module-transforms": { - "version": "7.17.6", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.17.6.tgz", - "integrity": "sha512-2ULmRdqoOMpdvkbT8jONrZML/XALfzxlb052bldftkicAUy8AxSCkD5trDPQcwHNmolcl7wP6ehNqMlyUw6AaA==", - "dev": true, - "requires": { - "@babel/helper-environment-visitor": "^7.16.7", - "@babel/helper-module-imports": "^7.16.7", - "@babel/helper-simple-access": "^7.16.7", - "@babel/helper-split-export-declaration": "^7.16.7", - "@babel/helper-validator-identifier": "^7.16.7", - "@babel/template": "^7.16.7", - "@babel/traverse": "^7.17.3", - "@babel/types": "^7.17.0" - } - }, - "@babel/helper-simple-access": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.16.7.tgz", - "integrity": "sha512-ZIzHVyoeLMvXMN/vok/a4LWRy8G2v205mNP0XOuf9XRLyX5/u9CnVulUtDgUTama3lT+bf/UqucuZjqiGuTS1g==", - "dev": true, - "requires": { - "@babel/types": "^7.16.7" - } - }, - "@babel/helper-split-export-declaration": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.16.7.tgz", - "integrity": "sha512-xbWoy/PFoxSWazIToT9Sif+jJTlrMcndIsaOKvTA6u7QEo7ilkRZpjew18/W3c7nm8fXdUDXh02VXTbZ0pGDNw==", - "dev": true, - "requires": { - "@babel/types": "^7.16.7" - } - }, - "@babel/helper-validator-identifier": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz", - "integrity": "sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw==", + "@blakeembrey/template": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@blakeembrey/template/-/template-1.1.0.tgz", + "integrity": "sha512-iZf+UWfL+DogJVpd/xMQyP6X6McYd6ArdYoPMiv/zlOTzeXXfQbYxBNJJBF6tThvsjLMbA8tLjkCdm9RWMFCCw==", "dev": true }, - "@babel/helper-validator-option": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.16.7.tgz", - "integrity": "sha512-TRtenOuRUVo9oIQGPC5G9DgK4743cdxvtOw0weQNpZXaS16SCBi5MNjZF8vba3ETURjZpTbVn7Vvcf2eAwFozQ==", - "dev": true - }, - "@babel/helpers": { - "version": "7.17.2", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.17.2.tgz", - "integrity": "sha512-0Qu7RLR1dILozr/6M0xgj+DFPmi6Bnulgm9M8BVa9ZCWxDqlSnqt3cf8IDPB5m45sVXUZ0kuQAgUrdSFFH79fQ==", - "dev": true, - "requires": { - "@babel/template": "^7.16.7", - "@babel/traverse": "^7.17.0", - "@babel/types": "^7.17.0" - } - }, - "@babel/highlight": { - "version": "7.16.10", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.16.10.tgz", - "integrity": "sha512-5FnTQLSLswEj6IkgVw5KusNUUFY9ZGqe/TRFnP/BKYHYgfh7tc+C7mwiy95/yNP7Dh9x580Vv8r7u7ZfTBFxdw==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.16.7", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "@babel/parser": { - "version": "7.17.3", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.17.3.tgz", - "integrity": "sha512-7yJPvPV+ESz2IUTPbOL+YkIGyCqOyNIzdguKQuJGnH7bg1WTIifuM21YqokFt/THWh1AkCRn9IgoykTRCBVpzA==", - "dev": true - }, - "@babel/template": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.16.7.tgz", - "integrity": "sha512-I8j/x8kHUrbYRTUxXrrMbfCa7jxkE7tZre39x3kjr9hvI82cK1FfqLygotcWN5kdPGWcLdWMHpSBavse5tWw3w==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.16.7", - "@babel/parser": "^7.16.7", - "@babel/types": "^7.16.7" - } - }, - "@babel/traverse": { - "version": "7.17.3", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.17.3.tgz", - "integrity": "sha512-5irClVky7TxRWIRtxlh2WPUUOLhcPN06AGgaQSB8AEwuyEBgJVuJ5imdHm5zxk8w0QS5T+tDfnDxAlhWjpb7cw==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.16.7", - "@babel/generator": "^7.17.3", - "@babel/helper-environment-visitor": "^7.16.7", - "@babel/helper-function-name": "^7.16.7", - "@babel/helper-hoist-variables": "^7.16.7", - "@babel/helper-split-export-declaration": "^7.16.7", - "@babel/parser": "^7.17.3", - "@babel/types": "^7.17.0", - "debug": "^4.1.0", - "globals": "^11.1.0" - } - }, - "@babel/types": { - "version": "7.17.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.17.0.tgz", - "integrity": "sha512-TmKSNO4D5rzhL5bjWFcVHHLETzfQ/AmbKpKPOSjlP0WoHZ6L911fgoOKY4Alp/emzG4cHJdyN49zpgkbXFEHHw==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.16.7", - "to-fast-properties": "^2.0.0" - } - }, "@cspotcode/source-map-consumer": { "version": "0.8.0", "resolved": "https://registry.npmjs.org/@cspotcode/source-map-consumer/-/source-map-consumer-0.8.0.tgz", @@ -3815,227 +2152,6 @@ "@cspotcode/source-map-consumer": "0.8.0" } }, - "@istanbuljs/load-nyc-config": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", - "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", - "dev": true, - "requires": { - "camelcase": "^5.3.1", - "find-up": "^4.1.0", - "get-package-type": "^0.1.0", - "js-yaml": "^3.13.1", - "resolve-from": "^5.0.0" - }, - "dependencies": { - "find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "requires": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - } - }, - "locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "requires": { - "p-locate": "^4.1.0" - } - }, - "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, - "requires": { - "p-try": "^2.0.0" - } - }, - "p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "requires": { - "p-limit": "^2.2.0" - } - } - } - }, - "@istanbuljs/schema": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", - "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", - "dev": true - }, - "@jridgewell/resolve-uri": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.0.5.tgz", - "integrity": "sha512-VPeQ7+wH0itvQxnG+lIzWgkysKIr3L9sslimFW55rHMdGu/qCQ5z5h9zq4gI8uBtqkpHhsF4Z/OwExufUCThew==", - "dev": true - }, - "@jridgewell/sourcemap-codec": { - "version": "1.4.11", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.11.tgz", - "integrity": "sha512-Fg32GrJo61m+VqYSdRSjRXMjQ06j8YIYfcTqndLYVAaHmroZHLJZCydsWBOTDqXS2v+mjxohBWEMfg97GXmYQg==", - "dev": true - }, - "@jridgewell/trace-mapping": { - "version": "0.3.4", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.4.tgz", - "integrity": "sha512-vFv9ttIedivx0ux3QSjhgtCVjPZd5l46ZOMDSCwnH1yUO2e964gO8LZGyv2QkqcgR6TnBU1v+1IFqmeoG+0UJQ==", - "dev": true, - "requires": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" - } - }, - "@microsoft/api-documenter": { - "version": "7.17.9", - "resolved": "https://registry.npmjs.org/@microsoft/api-documenter/-/api-documenter-7.17.9.tgz", - "integrity": "sha512-crmuhaqKG0zfeoCjIjvRfUzUe/JZaMGE3HS7FwtH7jROy/AHU8nL2Zpq8RzFRNKV9yHMiF8wVcEgfGmH5oM3hw==", - "dev": true, - "requires": { - "@microsoft/api-extractor-model": "7.17.1", - "@microsoft/tsdoc": "0.14.1", - "@rushstack/node-core-library": "3.45.3", - "@rushstack/ts-command-line": "4.10.9", - "colors": "~1.2.1", - "js-yaml": "~3.13.1", - "resolve": "~1.17.0" - } - }, - "@microsoft/api-extractor": { - "version": "7.22.2", - "resolved": "https://registry.npmjs.org/@microsoft/api-extractor/-/api-extractor-7.22.2.tgz", - "integrity": "sha512-G7vXz6UHz+qoaUGPf2k5Md4bSpHii9nFys3sIe3bmFUbmhAe+HfSB/dCn1PsLhW7tZfEXwMHTj7fbL5vcZkrEw==", - "dev": true, - "requires": { - "@microsoft/api-extractor-model": "7.17.1", - "@microsoft/tsdoc": "0.14.1", - "@microsoft/tsdoc-config": "~0.16.1", - "@rushstack/node-core-library": "3.45.3", - "@rushstack/rig-package": "0.3.10", - "@rushstack/ts-command-line": "4.10.9", - "colors": "~1.2.1", - "lodash": "~4.17.15", - "resolve": "~1.17.0", - "semver": "~7.3.0", - "source-map": "~0.6.1", - "typescript": "~4.5.2" - }, - "dependencies": { - "typescript": { - "version": "4.5.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.5.5.tgz", - "integrity": "sha512-TCTIul70LyWe6IJWT8QSYeA54WQe8EjQFU4wY52Fasj5UKx88LNYKCgBEHcOMOrFF1rKGbD8v/xcNWVUq9SymA==", - "dev": true - } - } - }, - "@microsoft/api-extractor-model": { - "version": "7.17.1", - "resolved": "https://registry.npmjs.org/@microsoft/api-extractor-model/-/api-extractor-model-7.17.1.tgz", - "integrity": "sha512-DCDtD8TdEpNk2lW4JvXgwwpxKy70P0JLad55iahwO8A+C63KYsrHIpAzo0FUauh5pwJ0v5QVNIJ+OBgKGteemg==", - "dev": true, - "requires": { - "@microsoft/tsdoc": "0.14.1", - "@microsoft/tsdoc-config": "~0.16.1", - "@rushstack/node-core-library": "3.45.3" - } - }, - "@microsoft/tsdoc": { - "version": "0.14.1", - "resolved": "https://registry.npmjs.org/@microsoft/tsdoc/-/tsdoc-0.14.1.tgz", - "integrity": "sha512-6Wci+Tp3CgPt/B9B0a3J4s3yMgLNSku6w5TV6mN+61C71UqsRBv2FUibBf3tPGlNxebgPHMEUzKpb1ggE8KCKw==", - "dev": true - }, - "@microsoft/tsdoc-config": { - "version": "0.16.1", - "resolved": "https://registry.npmjs.org/@microsoft/tsdoc-config/-/tsdoc-config-0.16.1.tgz", - "integrity": "sha512-2RqkwiD4uN6MLnHFljqBlZIXlt/SaUT6cuogU1w2ARw4nKuuppSmR0+s+NC+7kXBQykd9zzu0P4HtBpZT5zBpQ==", - "dev": true, - "requires": { - "@microsoft/tsdoc": "0.14.1", - "ajv": "~6.12.6", - "jju": "~1.4.0", - "resolve": "~1.19.0" - }, - "dependencies": { - "resolve": { - "version": "1.19.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.19.0.tgz", - "integrity": "sha512-rArEXAgsBG4UgRGcynxWIWKFvh/XZCcS8UJdHhwy91zwAvCZIbcs+vAbflgBnNjYMs/i/i+/Ux6IZhML1yPvxg==", - "dev": true, - "requires": { - "is-core-module": "^2.1.0", - "path-parse": "^1.0.6" - } - } - } - }, - "@rollup/pluginutils": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-4.1.2.tgz", - "integrity": "sha512-ROn4qvkxP9SyPeHaf7uQC/GPFY6L/OWy9+bd9AwcjOAWQwxRscoEyAUD8qCY5o5iL4jqQwoLk2kaTKJPb/HwzQ==", - "dev": true, - "requires": { - "estree-walker": "^2.0.1", - "picomatch": "^2.2.2" - } - }, - "@rushstack/node-core-library": { - "version": "3.45.3", - "resolved": "https://registry.npmjs.org/@rushstack/node-core-library/-/node-core-library-3.45.3.tgz", - "integrity": "sha512-Rn0mxqC3MPb+YbvaeFcRWfcYHLwyZ99/ffYA8chpq5OpqoY+Mr1ycTbMvzl5AxWf1pYmi/2+Eo3iTOsQdYR8xw==", - "dev": true, - "requires": { - "@types/node": "12.20.24", - "colors": "~1.2.1", - "fs-extra": "~7.0.1", - "import-lazy": "~4.0.0", - "jju": "~1.4.0", - "resolve": "~1.17.0", - "semver": "~7.3.0", - "timsort": "~0.3.0", - "z-schema": "~5.0.2" - }, - "dependencies": { - "@types/node": { - "version": "12.20.24", - "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.24.tgz", - "integrity": "sha512-yxDeaQIAJlMav7fH5AQqPH1u8YIuhYJXYBzxaQ4PifsU0GDO38MSdmEDeRlIxrKbC6NbEaaEHDanWb+y30U8SQ==", - "dev": true - } - } - }, - "@rushstack/rig-package": { - "version": "0.3.10", - "resolved": "https://registry.npmjs.org/@rushstack/rig-package/-/rig-package-0.3.10.tgz", - "integrity": "sha512-4Z2HhXM4YBWOi4ZYFQNK6Yxz641v+cvc8NKiaNZh+RIdNb3D4Rfpy3XUkggbCozpfDriBfL1+KaXlJtfJfAIXw==", - "dev": true, - "requires": { - "resolve": "~1.17.0", - "strip-json-comments": "~3.1.1" - } - }, - "@rushstack/ts-command-line": { - "version": "4.10.9", - "resolved": "https://registry.npmjs.org/@rushstack/ts-command-line/-/ts-command-line-4.10.9.tgz", - "integrity": "sha512-TE3eZgHNVHOY3p8lp38FoNEJUr0+swPb24sCcYuwlC+MHgMGXyJNM+p7l3TKSBRiY01XShoL2k601oGwL00KlA==", - "dev": true, - "requires": { - "@types/argparse": "1.0.38", - "argparse": "~1.0.9", - "colors": "~1.2.1", - "string-argv": "~0.3.1" - } - }, "@tsconfig/node10": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.8.tgz", @@ -4060,18 +2176,6 @@ "integrity": "sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA==", "dev": true }, - "@types/argparse": { - "version": "1.0.38", - "resolved": "https://registry.npmjs.org/@types/argparse/-/argparse-1.0.38.tgz", - "integrity": "sha512-ebDJ9b0e702Yr7pWgB0jzm+CX4Srzz8RcXtLJDJB+BSccqMa36uyH/zUsSYao5+BD1ytv3k3rPYCq4mAE1hsXA==", - "dev": true - }, - "@types/chai": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.1.tgz", - "integrity": "sha512-/zPMqDkzSZ8t3VtxOa4KPq7uzzW978M9Tvh+j7GHKuo6k6GTLxPJ4J5gE5cjfJ26pnXst0N5Hax8Sr0T2Mi9zQ==", - "dev": true - }, "@types/mocha": { "version": "8.2.3", "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-8.2.3.tgz", @@ -4083,12 +2187,6 @@ "resolved": "https://registry.npmjs.org/@types/node/-/node-15.14.9.tgz", "integrity": "sha512-qjd88DrCxupx/kJD5yQgZdcYKZKSIGBVDIBE1/LTGcNm3d2Np/jxojkdePDdfnBHJc5W7vSMpbJ1aB7p/Py69A==" }, - "@types/uuid": { - "version": "8.3.4", - "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.4.tgz", - "integrity": "sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw==", - "dev": true - }, "@types/ws": { "version": "7.4.7", "resolved": "https://registry.npmjs.org/@types/ws/-/ws-7.4.7.tgz", @@ -4103,43 +2201,10 @@ "integrity": "sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==", "dev": true }, - "@yarn-tool/resolve-package": { - "version": "1.0.43", - "resolved": "https://registry.npmjs.org/@yarn-tool/resolve-package/-/resolve-package-1.0.43.tgz", - "integrity": "sha512-axFruggDvKkfTuevJzqYFJ9XtJkKqaDYjXA1Ugx9mEpMX8HRGib86IgryAf5HfN3RCbawIkwCLjzGFm8H4DkPA==", - "dev": true, - "requires": { - "pkg-dir": "< 6 >= 5", - "tslib": "^2.3.1", - "upath2": "^3.1.12" - }, - "dependencies": { - "pkg-dir": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-5.0.0.tgz", - "integrity": "sha512-NPE8TDbzl/3YQYY7CSS228s3g2ollTFnc+Qi3tqmqJp9Vg2ovUpixcJEo2HJScN2Ez+kEaal6y70c0ehqJBJeA==", - "dev": true, - "requires": { - "find-up": "^5.0.0" - } - }, - "upath2": { - "version": "3.1.12", - "resolved": "https://registry.npmjs.org/upath2/-/upath2-3.1.12.tgz", - "integrity": "sha512-yC3eZeCyCXFWjy7Nu4pgjLhXNYjuzuUmJiRgSSw6TJp8Emc+E4951HGPJf+bldFC5SL7oBLeNbtm1fGzXn2gxw==", - "dev": true, - "requires": { - "path-is-network-drive": "^1.0.13", - "path-strip-sep": "^1.0.10", - "tslib": "^2.3.1" - } - } - } - }, "acorn": { - "version": "8.7.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz", - "integrity": "sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==", + "version": "8.7.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.1.tgz", + "integrity": "sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A==", "dev": true }, "acorn-walk": { @@ -4148,34 +2213,21 @@ "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", "dev": true }, - "aggregate-error": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", - "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", - "dev": true, - "requires": { - "clean-stack": "^2.0.0", - "indent-string": "^4.0.0" - } - }, - "ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "requires": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - } - }, "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 }, + "ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "requires": { + "type-fest": "^0.21.3" + } + }, "ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", @@ -4200,21 +2252,6 @@ "picomatch": "^2.0.4" } }, - "append-transform": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/append-transform/-/append-transform-2.0.0.tgz", - "integrity": "sha512-7yeyCEurROLQJFv5Xj4lEGTy0borxepjFv1g22oAdqFu//SrAlDl1O1Nxx15SH1RoliUml6p8dwJW9jvZughhg==", - "dev": true, - "requires": { - "default-require-extensions": "^3.0.0" - } - }, - "archy": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz", - "integrity": "sha1-+cjBN1fMHde8N5rHeyxipcKGjEA=", - "dev": true - }, "arg": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", @@ -4222,18 +2259,9 @@ "dev": true }, "argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "requires": { - "sprintf-js": "~1.0.2" - } - }, - "assertion-error": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", - "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", + "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 }, "balanced-match": { @@ -4253,6 +2281,17 @@ "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", "dev": true }, + "bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "dev": true, + "requires": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, "brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -4278,23 +2317,10 @@ "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", "dev": true }, - "browserslist": { - "version": "4.19.3", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.19.3.tgz", - "integrity": "sha512-XK3X4xtKJ+Txj8G5c30B4gsm71s69lqXlkYui4s6EkKxuv49qjYlY6oVd+IFJ73d4YymtM3+djvvt/R/iJwwDg==", - "dev": true, - "requires": { - "caniuse-lite": "^1.0.30001312", - "electron-to-chromium": "^1.4.71", - "escalade": "^3.1.1", - "node-releases": "^2.0.2", - "picocolors": "^1.0.0" - } - }, "bson": { - "version": "4.6.1", - "resolved": "https://registry.npmjs.org/bson/-/bson-4.6.1.tgz", - "integrity": "sha512-I1LQ7Hz5zgwR4QquilLNZwbhPw0Apx7i7X9kGMBTsqPdml/03Q9NBtD9nt/19ahjlphktQImrnderxqpzeVDjw==", + "version": "4.6.3", + "resolved": "https://registry.npmjs.org/bson/-/bson-4.6.3.tgz", + "integrity": "sha512-rAqP5hcUVJhXP2MCSNVsf0oM2OGU1So6A9pVRDYayvJ5+hygXHQApf87wd5NlhPM1J9RJnbqxIG/f8QTzRoQ4A==", "requires": { "buffer": "^5.6.0" } @@ -4308,45 +2334,12 @@ "ieee754": "^1.1.13" } }, - "caching-transform": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/caching-transform/-/caching-transform-4.0.0.tgz", - "integrity": "sha512-kpqOvwXnjjN44D89K5ccQC+RUrsy7jB/XLlRrx0D7/2HNcTPqzsb6XgYoErwko6QsV184CA2YgS1fxDiiDZMWA==", - "dev": true, - "requires": { - "hasha": "^5.0.0", - "make-dir": "^3.0.0", - "package-hash": "^4.0.0", - "write-file-atomic": "^3.0.0" - } - }, "camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", "dev": true }, - "caniuse-lite": { - "version": "1.0.30001312", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001312.tgz", - "integrity": "sha512-Wiz1Psk2MEK0pX3rUzWaunLTZzqS2JYZFzNKqAiJGiuxIjRPLgV6+VDPOg6lQOUxmDwhTlh198JsTTi8Hzw6aQ==", - "dev": true - }, - "chai": { - "version": "4.3.6", - "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.6.tgz", - "integrity": "sha512-bbcp3YfHCUzMOvKqsztczerVgBKSsEijCySNlHHbX3VG1nskvqjz5Rfso1gGwD6w6oOV3eI60pKuMOV5MV7p3Q==", - "dev": true, - "requires": { - "assertion-error": "^1.1.0", - "check-error": "^1.0.2", - "deep-eql": "^3.0.1", - "get-func-name": "^2.0.0", - "loupe": "^2.3.1", - "pathval": "^1.1.1", - "type-detect": "^4.0.5" - } - }, "chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -4354,12 +2347,22 @@ "requires": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" + }, + "dependencies": { + "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==", + "requires": { + "has-flag": "^4.0.0" + } + } } }, - "check-error": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", - "integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=", + "chardet": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", + "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", "dev": true }, "chokidar": { @@ -4378,10 +2381,25 @@ "readdirp": "~3.6.0" } }, - "clean-stack": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", - "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "dev": true, + "requires": { + "restore-cursor": "^3.1.0" + } + }, + "cli-spinners": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.6.1.tgz", + "integrity": "sha512-x/5fWmGMnbKQAaNwN+UZlV79qBLM9JFnJuJ03gIi5whrob0xV0ofNVHy9DhwGdsMJQc2OKv0oGmLzvaqvAVv+g==", + "dev": true + }, + "cli-width": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", + "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==", "dev": true }, "cliui": { @@ -4395,6 +2413,12 @@ "wrap-ansi": "^7.0.0" } }, + "clone": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=", + "dev": true + }, "color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -4408,23 +2432,16 @@ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, - "colors": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/colors/-/colors-1.2.5.tgz", - "integrity": "sha512-erNRLao/Y3Fv54qUa0LBB+//Uf3YwMUmdJinN20yMXm9zdKKqH9wt7R9IIVZ+K7ShzfpLV/Zg8+VyrBJYB4lpg==", - "dev": true - }, "commander": { "version": "2.20.3", "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "dev": true, - "optional": true + "dev": true }, - "commondir": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", - "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", + "commandpost": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/commandpost/-/commandpost-1.4.0.tgz", + "integrity": "sha512-aE2Y4MTFJ870NuB/+2z1cXBhSBBzRydVVjzhFC4gtenEhpnj15yu0qptWGJsO9YGrcPZ3ezX8AWb1VA391MKpQ==", "dev": true }, "concat-map": { @@ -4433,15 +2450,6 @@ "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", "dev": true }, - "convert-source-map": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz", - "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==", - "dev": true, - "requires": { - "safe-buffer": "~5.1.1" - } - }, "create-require": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", @@ -4477,27 +2485,18 @@ } }, "decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", + "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", "dev": true }, - "deep-eql": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz", - "integrity": "sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==", + "defaults": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.3.tgz", + "integrity": "sha1-xlYFHpgX2f8I7YgUd/P+QBnz730=", "dev": true, "requires": { - "type-detect": "^4.0.0" - } - }, - "default-require-extensions": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-3.0.0.tgz", - "integrity": "sha512-ek6DpXq/SCpvjhpFsLFRVtIxJCRw6fUR42lYMVZuUMK7n8eMz4Uh5clckdBjEpLhn/gEBZo7hDJnJcwdKLKQjg==", - "dev": true, - "requires": { - "strip-bom": "^4.0.0" + "clone": "^1.0.2" } }, "diff": { @@ -4506,11 +2505,17 @@ "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", "dev": true }, - "electron-to-chromium": { - "version": "1.4.72", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.72.tgz", - "integrity": "sha512-9LkRQwjW6/wnSfevR21a3k8sOJ+XWSH7kkzs9/EUenKmuDkndP3W9y1yCZpOxufwGbX3JV8glZZSDb4o95zwXQ==", - "dev": true + "editorconfig": { + "version": "0.15.3", + "resolved": "https://registry.npmjs.org/editorconfig/-/editorconfig-0.15.3.tgz", + "integrity": "sha512-M9wIMFx96vq0R4F+gRpY3o2exzb8hEj/n9S8unZtHSvYjibBp/iMufSzvmOcV/laG0ZtuTVGtiJggPOSW2r93g==", + "dev": true, + "requires": { + "commander": "^2.19.0", + "lru-cache": "^4.1.5", + "semver": "^5.6.0", + "sigmund": "^1.0.1" + } }, "emoji-regex": { "version": "8.0.0", @@ -4518,11 +2523,14 @@ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "dev": true }, - "es6-error": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz", - "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==", - "dev": true + "end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dev": true, + "requires": { + "once": "^1.4.0" + } }, "escalade": { "version": "3.1.1", @@ -4536,29 +2544,50 @@ "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", "dev": true }, - "esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true + "execa": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-4.1.0.tgz", + "integrity": "sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==", + "dev": true, + "requires": { + "cross-spawn": "^7.0.0", + "get-stream": "^5.0.0", + "human-signals": "^1.1.1", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.0", + "onetime": "^5.1.0", + "signal-exit": "^3.0.2", + "strip-final-newline": "^2.0.0" + } }, - "estree-walker": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", - "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", - "dev": true + "external-editor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", + "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", + "dev": true, + "requires": { + "chardet": "^0.7.0", + "iconv-lite": "^0.4.24", + "tmp": "^0.0.33" + } }, - "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 - }, - "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 + "figures": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", + "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", + "dev": true, + "requires": { + "escape-string-regexp": "^1.0.5" + }, + "dependencies": { + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + } + } }, "fill-range": { "version": "7.0.1", @@ -4569,17 +2598,6 @@ "to-regex-range": "^5.0.1" } }, - "find-cache-dir": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz", - "integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==", - "dev": true, - "requires": { - "commondir": "^1.0.1", - "make-dir": "^3.0.2", - "pkg-dir": "^4.1.0" - } - }, "find-up": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", @@ -4596,31 +2614,15 @@ "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", "dev": true }, - "foreground-child": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-2.0.0.tgz", - "integrity": "sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA==", - "dev": true, - "requires": { - "cross-spawn": "^7.0.0", - "signal-exit": "^3.0.2" - } - }, - "fromentries": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/fromentries/-/fromentries-1.3.2.tgz", - "integrity": "sha512-cHEpEQHUg0f8XdtZCc2ZAhrHzKzT0MrFUTcvx+hfxYu7rGMDc5SKoXFh+n4YigxsHXRzc6OrCshdR1bWH6HHyg==", - "dev": true - }, "fs-extra": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz", - "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", "dev": true, "requires": { - "graceful-fs": "^4.1.2", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" } }, "fs.realpath": { @@ -4636,35 +2638,20 @@ "dev": true, "optional": true }, - "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true - }, - "gensync": { - "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "dev": true - }, "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==", "dev": true }, - "get-func-name": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", - "integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=", - "dev": true - }, - "get-package-type": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", - "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", - "dev": true + "get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "dev": true, + "requires": { + "pump": "^3.0.0" + } }, "glob": { "version": "7.2.0", @@ -4678,6 +2665,17 @@ "minimatch": "^3.0.4", "once": "^1.3.0", "path-is-absolute": "^1.0.0" + }, + "dependencies": { + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + } } }, "glob-parent": { @@ -4689,16 +2687,10 @@ "is-glob": "^4.0.1" } }, - "globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true - }, "graceful-fs": { - "version": "4.2.9", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.9.tgz", - "integrity": "sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ==", + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", "dev": true }, "growl": { @@ -4707,63 +2699,41 @@ "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", "dev": true }, - "has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, - "requires": { - "function-bind": "^1.1.1" - } - }, "has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" }, - "hasha": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/hasha/-/hasha-5.2.2.tgz", - "integrity": "sha512-Hrp5vIK/xr5SkeN2onO32H0MgNZ0f17HRNH39WfL0SYUNOTZ5Lz1TJ8Pajo/87dYGEFlLMm7mIc/k/s6Bvz9HQ==", - "dev": true, - "requires": { - "is-stream": "^2.0.0", - "type-fest": "^0.8.0" - } - }, "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 }, - "html-escaper": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", - "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "human-signals": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz", + "integrity": "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==", "dev": true }, + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, "ieee754": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==" }, - "import-lazy": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-4.0.0.tgz", - "integrity": "sha512-rKtvo6a868b5Hu3heneU+L4yEQ4jYKLtjpnPeUdK7h0yzXGmyBTypknlkCvHFBqfX9YlorEiMM6Dnq/5atfHkw==", - "dev": true - }, - "imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", - "dev": true - }, - "indent-string": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", - "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "ignore": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", + "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", "dev": true }, "inflight": { @@ -4782,6 +2752,35 @@ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "dev": true }, + "inquirer": { + "version": "8.2.4", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.4.tgz", + "integrity": "sha512-nn4F01dxU8VeKfq192IjLsxu0/OmMZ4Lg3xKAns148rCaXP6ntAoEkVYZThWjwON8AlzdZZi6oqnhNbxUG9hVg==", + "dev": true, + "requires": { + "ansi-escapes": "^4.2.1", + "chalk": "^4.1.1", + "cli-cursor": "^3.1.0", + "cli-width": "^3.0.0", + "external-editor": "^3.0.3", + "figures": "^3.0.0", + "lodash": "^4.17.21", + "mute-stream": "0.0.8", + "ora": "^5.4.1", + "run-async": "^2.4.0", + "rxjs": "^7.5.5", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0", + "through": "^2.3.6", + "wrap-ansi": "^7.0.0" + } + }, + "invert-kv": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-3.0.1.tgz", + "integrity": "sha512-CYdFeFexxhv/Bcny+Q0BfOV+ltRlJcd4BBZBYFX/O0u4npJrgZtIcjokegtiSMAvlMTJ+Koq0GBCc//3bueQxw==", + "dev": true + }, "is-binary-path": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", @@ -4791,15 +2790,6 @@ "binary-extensions": "^2.0.0" } }, - "is-core-module": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.1.tgz", - "integrity": "sha512-SdNCUs284hr40hFTFP6l0IfZ/RSrMXF3qgoRHd3/79unUTvrFO/JoXwkGm+5J/Oe3E/b5GsnG330uUNgRpu1PA==", - "dev": true, - "requires": { - "has": "^1.0.3" - } - }, "is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", @@ -4821,6 +2811,12 @@ "is-extglob": "^2.1.1" } }, + "is-interactive": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", + "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", + "dev": true + }, "is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", @@ -4839,172 +2835,43 @@ "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", "dev": true }, - "is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", - "dev": true - }, "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 }, - "is-windows": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", - "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", - "dev": true - }, "isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", "dev": true }, - "istanbul-lib-coverage": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", - "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==", - "dev": true - }, - "istanbul-lib-hook": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-hook/-/istanbul-lib-hook-3.0.0.tgz", - "integrity": "sha512-Pt/uge1Q9s+5VAZ+pCo16TYMWPBIl+oaNIjgLQxcX0itS6ueeaA+pEfThZpH8WxhFgCiEb8sAJY6MdUKgiIWaQ==", - "dev": true, - "requires": { - "append-transform": "^2.0.0" - } - }, - "istanbul-lib-instrument": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.3.tgz", - "integrity": "sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ==", - "dev": true, - "requires": { - "@babel/core": "^7.7.5", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-coverage": "^3.0.0", - "semver": "^6.3.0" - }, - "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - } - } - }, - "istanbul-lib-processinfo": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/istanbul-lib-processinfo/-/istanbul-lib-processinfo-2.0.2.tgz", - "integrity": "sha512-kOwpa7z9hme+IBPZMzQ5vdQj8srYgAtaRqeI48NGmAQ+/5yKiHLV0QbYqQpxsdEF0+w14SoB8YbnHKcXE2KnYw==", - "dev": true, - "requires": { - "archy": "^1.0.0", - "cross-spawn": "^7.0.0", - "istanbul-lib-coverage": "^3.0.0-alpha.1", - "make-dir": "^3.0.0", - "p-map": "^3.0.0", - "rimraf": "^3.0.0", - "uuid": "^3.3.3" - }, - "dependencies": { - "uuid": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", - "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", - "dev": true - } - } - }, - "istanbul-lib-report": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", - "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", - "dev": true, - "requires": { - "istanbul-lib-coverage": "^3.0.0", - "make-dir": "^3.0.0", - "supports-color": "^7.1.0" - } - }, - "istanbul-lib-source-maps": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", - "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", - "dev": true, - "requires": { - "debug": "^4.1.1", - "istanbul-lib-coverage": "^3.0.0", - "source-map": "^0.6.1" - } - }, - "istanbul-reports": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.4.tgz", - "integrity": "sha512-r1/DshN4KSE7xWEknZLLLLDn5CJybV3nw01VTkp6D5jzLuELlcbudfj/eSQFvrKsJuTVCGnePO7ho82Nw9zzfw==", - "dev": true, - "requires": { - "html-escaper": "^2.0.0", - "istanbul-lib-report": "^3.0.0" - } - }, - "jju": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/jju/-/jju-1.4.0.tgz", - "integrity": "sha1-o6vicYryQaKykE+EpiWXDzia4yo=", - "dev": true - }, - "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 - }, "js-yaml": { - "version": "3.13.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", - "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", "dev": true, "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - } - }, - "jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", - "dev": true - }, - "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 - }, - "json5": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz", - "integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==", - "dev": true, - "requires": { - "minimist": "^1.2.5" + "argparse": "^2.0.1" } }, "jsonfile": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", - "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", "dev": true, "requires": { - "graceful-fs": "^4.1.6" + "graceful-fs": "^4.1.6", + "universalify": "^2.0.0" } }, + "k8w-crypto": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/k8w-crypto/-/k8w-crypto-0.2.0.tgz", + "integrity": "sha512-M6u4eQ6CQaU5xO3s4zaUUp9G79xNDhXtTU0X7N80tDcBhQC5ggowlyOzj95v7WiCuk7xkV0aFsTmCpuf0m0djw==", + "dev": true + }, "k8w-extend-native": { "version": "1.4.6", "resolved": "https://registry.npmjs.org/k8w-extend-native/-/k8w-extend-native-1.4.6.tgz", @@ -5030,6 +2897,15 @@ "resolved": "https://registry.npmjs.org/k8w-super-object/-/k8w-super-object-0.3.0.tgz", "integrity": "sha512-u2jfh4goYXKZmSucaLaOTaNbLRatjv0CSRpzE0KU0732+9XtYZFd5vrdw/mzJfK5fPHb/zyikOSHDX5mJrav+g==" }, + "lcid": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/lcid/-/lcid-3.1.1.tgz", + "integrity": "sha512-M6T051+5QCGLBQb8id3hdvIW8+zeFV2FyBGFS9IEK5H9Wt4MueD4bW1eWikpHgZp+5xR3l5c8pZUkQsIA0BFZg==", + "dev": true, + "requires": { + "invert-kv": "^3.0.0" + } + }, "locate-path": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", @@ -5045,24 +2921,6 @@ "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", "dev": true }, - "lodash.flattendeep": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz", - "integrity": "sha1-+wMJF/hqMTTlvJvsDWngAT3f7bI=", - "dev": true - }, - "lodash.get": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", - "integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=", - "dev": true - }, - "lodash.isequal": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", - "integrity": "sha1-QVxEePK8wwEgwizhDtMib30+GOA=", - "dev": true - }, "log-symbols": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", @@ -5073,39 +2931,14 @@ "is-unicode-supported": "^0.1.0" } }, - "loupe": { - "version": "2.3.4", - "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.4.tgz", - "integrity": "sha512-OvKfgCC2Ndby6aSTREl5aCCPTNIzlDfQZvZxNUrBrihDhL3xcrYegTblhmEiCrg2kKQz4XsFIaemE5BF4ybSaQ==", - "dev": true, - "requires": { - "get-func-name": "^2.0.0" - } - }, "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==", + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", + "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", "dev": true, "requires": { - "yallist": "^4.0.0" - } - }, - "make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "dev": true, - "requires": { - "semver": "^6.0.0" - }, - "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - } + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" } }, "make-error": { @@ -5114,19 +2947,51 @@ "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", "dev": true }, + "map-age-cleaner": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz", + "integrity": "sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==", + "dev": true, + "requires": { + "p-defer": "^1.0.0" + } + }, + "mem": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/mem/-/mem-5.1.1.tgz", + "integrity": "sha512-qvwipnozMohxLXG1pOqoLiZKNkC4r4qqRucSoDwXowsNGDSULiqFTRUF05vcZWnwJSG22qTsynQhxbaMtnX9gw==", + "dev": true, + "requires": { + "map-age-cleaner": "^0.1.3", + "mimic-fn": "^2.1.0", + "p-is-promise": "^2.1.0" + } + }, + "merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, + "mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true + }, "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-4.2.1.tgz", + "integrity": "sha512-9Uq1ChtSZO+Mxa/CL1eGizn2vRn3MlLgzhT0Iz8zaY8NdvxvB0d5QdPFmCKf7JKA9Lerx5vRrnwO03jsSfGG9g==", "dev": true, "requires": { "brace-expansion": "^1.1.7" } }, "minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", + "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", "dev": true }, "mocha": { @@ -5159,41 +3024,6 @@ "yargs": "16.2.0", "yargs-parser": "20.2.4", "yargs-unparser": "2.0.0" - }, - "dependencies": { - "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 - }, - "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, - "requires": { - "argparse": "^2.0.1" - } - }, - "minimatch": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-4.2.1.tgz", - "integrity": "sha512-9Uq1ChtSZO+Mxa/CL1eGizn2vRn3MlLgzhT0Iz8zaY8NdvxvB0d5QdPFmCKf7JKA9Lerx5vRrnwO03jsSfGG9g==", - "dev": true, - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "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, - "requires": { - "has-flag": "^4.0.0" - } - } } }, "ms": { @@ -5202,162 +3032,31 @@ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "dev": true }, + "mute-stream": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", + "dev": true + }, "nanoid": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.1.tgz", "integrity": "sha512-n6Vs/3KGyxPQd6uO0eH4Bv0ojGSUvuLlIHtC3Y0kEO23YRge8H9x1GCzLn28YX0H66pMkxuaeESFq4tKISKwdw==", "dev": true }, - "node-preload": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/node-preload/-/node-preload-0.2.1.tgz", - "integrity": "sha512-RM5oyBy45cLEoHqCeh+MNuFAxO0vTFBLskvQbOKnEE7YTTSN4tbN8QWDIPQ6L+WvKsB/qLEGpYe2ZZ9d4W9OIQ==", - "dev": true, - "requires": { - "process-on-spawn": "^1.0.0" - } - }, - "node-releases": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.2.tgz", - "integrity": "sha512-XxYDdcQ6eKqp/YjI+tb2C5WM2LgjnZrfYg4vgQt49EK268b6gYCHsBLrK2qvJo4FmCtqmKezb0WZFK4fkrZNsg==", - "dev": true - }, "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 }, - "nyc": { - "version": "15.1.0", - "resolved": "https://registry.npmjs.org/nyc/-/nyc-15.1.0.tgz", - "integrity": "sha512-jMW04n9SxKdKi1ZMGhvUTHBN0EICCRkHemEoE5jm6mTYcqcdas0ATzgUgejlQUHMvpnOZqGB5Xxsv9KxJW1j8A==", + "npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", "dev": true, "requires": { - "@istanbuljs/load-nyc-config": "^1.0.0", - "@istanbuljs/schema": "^0.1.2", - "caching-transform": "^4.0.0", - "convert-source-map": "^1.7.0", - "decamelize": "^1.2.0", - "find-cache-dir": "^3.2.0", - "find-up": "^4.1.0", - "foreground-child": "^2.0.0", - "get-package-type": "^0.1.0", - "glob": "^7.1.6", - "istanbul-lib-coverage": "^3.0.0", - "istanbul-lib-hook": "^3.0.0", - "istanbul-lib-instrument": "^4.0.0", - "istanbul-lib-processinfo": "^2.0.2", - "istanbul-lib-report": "^3.0.0", - "istanbul-lib-source-maps": "^4.0.0", - "istanbul-reports": "^3.0.2", - "make-dir": "^3.0.0", - "node-preload": "^0.2.1", - "p-map": "^3.0.0", - "process-on-spawn": "^1.0.0", - "resolve-from": "^5.0.0", - "rimraf": "^3.0.0", - "signal-exit": "^3.0.2", - "spawn-wrap": "^2.0.0", - "test-exclude": "^6.0.0", - "yargs": "^15.0.2" - }, - "dependencies": { - "cliui": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", - "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", - "dev": true, - "requires": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^6.2.0" - } - }, - "find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "requires": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - } - }, - "locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "requires": { - "p-locate": "^4.1.0" - } - }, - "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, - "requires": { - "p-try": "^2.0.0" - } - }, - "p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "requires": { - "p-limit": "^2.2.0" - } - }, - "wrap-ansi": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", - "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", - "dev": true, - "requires": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - } - }, - "y18n": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", - "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", - "dev": true - }, - "yargs": { - "version": "15.4.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", - "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", - "dev": true, - "requires": { - "cliui": "^6.0.0", - "decamelize": "^1.2.0", - "find-up": "^4.1.0", - "get-caller-file": "^2.0.1", - "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", - "set-blocking": "^2.0.0", - "string-width": "^4.2.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^18.1.2" - } - }, - "yargs-parser": { - "version": "18.1.3", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", - "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", - "dev": true, - "requires": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - } - } + "path-key": "^3.0.0" } }, "once": { @@ -5369,6 +3068,76 @@ "wrappy": "1" } }, + "onchange": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/onchange/-/onchange-7.1.0.tgz", + "integrity": "sha512-ZJcqsPiWUAUpvmnJri5TPBooqJOPmC0ttN65juhN15Q8xA+Nbg3BaxBHXQ45EistKKlKElb0edmbPWnKSBkvMg==", + "dev": true, + "requires": { + "@blakeembrey/deque": "^1.0.5", + "@blakeembrey/template": "^1.0.0", + "arg": "^4.1.3", + "chokidar": "^3.3.1", + "cross-spawn": "^7.0.1", + "ignore": "^5.1.4", + "tree-kill": "^1.2.2" + } + }, + "onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "requires": { + "mimic-fn": "^2.1.0" + } + }, + "ora": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", + "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", + "dev": true, + "requires": { + "bl": "^4.1.0", + "chalk": "^4.1.0", + "cli-cursor": "^3.1.0", + "cli-spinners": "^2.5.0", + "is-interactive": "^1.0.0", + "is-unicode-supported": "^0.1.0", + "log-symbols": "^4.1.0", + "strip-ansi": "^6.0.0", + "wcwidth": "^1.0.1" + } + }, + "os-locale": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-5.0.0.tgz", + "integrity": "sha512-tqZcNEDAIZKBEPnHPlVDvKrp7NzgLi7jRmhKiUoa2NUmhl13FtkAGLUVR+ZsYvApBQdBfYm43A4tXXQ4IrYLBA==", + "dev": true, + "requires": { + "execa": "^4.0.0", + "lcid": "^3.0.0", + "mem": "^5.0.0" + } + }, + "os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", + "dev": true + }, + "p-defer": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-defer/-/p-defer-1.0.0.tgz", + "integrity": "sha1-n26xgvbJqozXQwBKfU+WsZaw+ww=", + "dev": true + }, + "p-is-promise": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-2.1.0.tgz", + "integrity": "sha512-Y3W0wlRPK8ZMRbNq97l4M5otioeA5lm1z7bkNkxCka8HSPjR0xRWmpCmc9utiaLP9Jb1eD8BgeIxTW4AIF45Pg==", + "dev": true + }, "p-limit": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", @@ -5387,33 +3156,6 @@ "p-limit": "^3.0.2" } }, - "p-map": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-3.0.0.tgz", - "integrity": "sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ==", - "dev": true, - "requires": { - "aggregate-error": "^3.0.0" - } - }, - "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 - }, - "package-hash": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/package-hash/-/package-hash-4.0.0.tgz", - "integrity": "sha512-whdkPIooSu/bASggZ96BWVvZTRMOFxnyUG5PnTSGKoJE2gd5mbVNmR2Nj20QFzxYYgAXpoqC+AiXzl+UMRh7zQ==", - "dev": true, - "requires": { - "graceful-fs": "^4.1.15", - "hasha": "^5.0.0", - "lodash.flattendeep": "^4.4.0", - "release-zalgo": "^1.0.0" - } - }, "path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", @@ -5426,117 +3168,34 @@ "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", "dev": true }, - "path-is-network-drive": { - "version": "1.0.13", - "resolved": "https://registry.npmjs.org/path-is-network-drive/-/path-is-network-drive-1.0.13.tgz", - "integrity": "sha512-Hg74mRN6mmXV+gTm3INjFK40ncAmC/Lo4qoQaSZ+GT3hZzlKdWQSqAjqyPeW0SvObP2W073WyYEBWY9d3wOm3A==", - "dev": true, - "requires": { - "tslib": "^2.3.1" - } - }, "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 }, - "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 - }, - "path-strip-sep": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/path-strip-sep/-/path-strip-sep-1.0.10.tgz", - "integrity": "sha512-JpCy+8LAJQQTO1bQsb/84s1g+/Stm3h39aOpPRBQ/paMUGVPPZChLTOTKHoaCkc/6sKuF7yVsnq5Pe1S6xQGcA==", - "dev": true, - "requires": { - "tslib": "^2.3.1" - } - }, - "pathval": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", - "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", - "dev": true - }, - "picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", - "dev": true - }, "picomatch": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "dev": true }, - "pkg-dir": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", - "dev": true, - "requires": { - "find-up": "^4.0.0" - }, - "dependencies": { - "find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "requires": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - } - }, - "locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "requires": { - "p-locate": "^4.1.0" - } - }, - "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, - "requires": { - "p-try": "^2.0.0" - } - }, - "p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "requires": { - "p-limit": "^2.2.0" - } - } - } - }, - "process-on-spawn": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/process-on-spawn/-/process-on-spawn-1.0.0.tgz", - "integrity": "sha512-1WsPDsUSMmZH5LeMLegqkPDrsGgsWwk1Exipy2hvB0o/F0ASzbpIctSCcZIK1ykJvtTJULEH+20WOFjMvGnCTg==", - "dev": true, - "requires": { - "fromentries": "^1.2.0" - } - }, - "punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "pseudomap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", + "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", "dev": true }, + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, "randombytes": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", @@ -5546,6 +3205,17 @@ "safe-buffer": "^5.1.0" } }, + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, "readdirp": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", @@ -5555,128 +3225,54 @@ "picomatch": "^2.2.1" } }, - "release-zalgo": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/release-zalgo/-/release-zalgo-1.0.0.tgz", - "integrity": "sha1-CXALflB0Mpc5Mw5TXFqQ+2eFFzA=", - "dev": true, - "requires": { - "es6-error": "^4.0.1" - } - }, "require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", "dev": true }, - "require-main-filename": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", - "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", + "restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "dev": true, + "requires": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + } + }, + "run-async": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", + "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", "dev": true }, - "resolve": { - "version": "1.17.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz", - "integrity": "sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==", + "rxjs": { + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.5.5.tgz", + "integrity": "sha512-sy+H0pQofO95VDmFLzyaw9xNJU4KTRSwQIGM6+iG3SypAtCiLDzpeG8sJrNCWn2Up9km+KhkvTdbkrdy+yzZdw==", "dev": true, "requires": { - "path-parse": "^1.0.6" - } - }, - "resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true - }, - "rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, - "requires": { - "glob": "^7.1.3" - } - }, - "rollup": { - "version": "2.70.2", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.70.2.tgz", - "integrity": "sha512-EitogNZnfku65I1DD5Mxe8JYRUCy0hkK5X84IlDtUs+O6JRMpRciXTzyCUuX11b5L5pvjH+OmFXiQ3XjabcXgg==", - "dev": true, - "requires": { - "fsevents": "~2.3.2" - } - }, - "rollup-plugin-typescript2": { - "version": "0.31.2", - "resolved": "https://registry.npmjs.org/rollup-plugin-typescript2/-/rollup-plugin-typescript2-0.31.2.tgz", - "integrity": "sha512-hRwEYR1C8xDGVVMFJQdEVnNAeWRvpaY97g5mp3IeLnzhNXzSVq78Ye/BJ9PAaUfN4DXa/uDnqerifMOaMFY54Q==", - "dev": true, - "requires": { - "@rollup/pluginutils": "^4.1.2", - "@yarn-tool/resolve-package": "^1.0.40", - "find-cache-dir": "^3.3.2", - "fs-extra": "^10.0.0", - "resolve": "^1.20.0", - "tslib": "^2.3.1" - }, - "dependencies": { - "fs-extra": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.0.1.tgz", - "integrity": "sha512-NbdoVMZso2Lsrn/QwLXOy6rm0ufY2zEOKCDzJR/0kBsb0E6qed0P3iYK+Ath3BfvXEeu4JhEtXLgILx5psUfag==", - "dev": true, - "requires": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - } - }, - "jsonfile": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", - "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", - "dev": true, - "requires": { - "graceful-fs": "^4.1.6", - "universalify": "^2.0.0" - } - }, - "resolve": { - "version": "1.22.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz", - "integrity": "sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==", - "dev": true, - "requires": { - "is-core-module": "^2.8.1", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - } - }, - "universalify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", - "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", - "dev": true - } + "tslib": "^2.1.0" } }, "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "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 + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "dev": true }, "semver": { - "version": "7.3.7", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", - "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true }, "serialize-javascript": { "version": "6.0.0", @@ -5687,12 +3283,6 @@ "randombytes": "^2.1.0" } }, - "set-blocking": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", - "dev": true - }, "shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -5708,44 +3298,27 @@ "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", "dev": true }, + "sigmund": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz", + "integrity": "sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA=", + "dev": true + }, "signal-exit": { "version": "3.0.7", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", "dev": true }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - }, - "spawn-wrap": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/spawn-wrap/-/spawn-wrap-2.0.0.tgz", - "integrity": "sha512-EeajNjfN9zMnULLwhZZQU3GWBoFNkbngTUPfaawT4RkMiviTxcX0qfhVbGey39mfctfDHkWtuecgQ8NJcyQWHg==", + "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, "requires": { - "foreground-child": "^2.0.0", - "is-windows": "^1.0.2", - "make-dir": "^3.0.0", - "rimraf": "^3.0.0", - "signal-exit": "^3.0.2", - "which": "^2.0.1" + "safe-buffer": "~5.2.0" } }, - "sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", - "dev": true - }, - "string-argv": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.1.tgz", - "integrity": "sha512-a1uQGz7IyVy9YwhqjZIZu1c8JO8dNIe20xBmSS6qu9kv++k3JGzCVmprbNN5Kn+BgzD5E7YYwg1CcjuJMRNsvg==", - "dev": true - }, "string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", @@ -5766,10 +3339,10 @@ "ansi-regex": "^5.0.1" } }, - "strip-bom": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", - "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", + "strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", "dev": true }, "strip-json-comments": { @@ -5779,42 +3352,29 @@ "dev": true }, "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==", + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, "requires": { "has-flag": "^4.0.0" } }, - "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==", + "through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", "dev": true }, - "test-exclude": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", - "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", "dev": true, "requires": { - "@istanbuljs/schema": "^0.1.2", - "glob": "^7.1.4", - "minimatch": "^3.0.4" + "os-tmpdir": "~1.0.2" } }, - "timsort": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/timsort/-/timsort-0.3.0.tgz", - "integrity": "sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q=", - "dev": true - }, - "to-fast-properties": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", - "dev": true - }, "to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -5824,6 +3384,12 @@ "is-number": "^7.0.0" } }, + "tree-kill": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", + "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", + "dev": true + }, "ts-node": { "version": "10.7.0", "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.7.0.tgz", @@ -5863,6 +3429,19 @@ "tslib": "*" } }, + "tsbuffer-proto-generator": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/tsbuffer-proto-generator/-/tsbuffer-proto-generator-1.7.1.tgz", + "integrity": "sha512-PU4fxphid6LMbhuyO++6BmXR7oG/5j/QthZcmmJQhxy5GjGeiIdqyV9Nf8ADEdsKAhE503J8r3JnIC5Pq1tbxA==", + "dev": true, + "requires": { + "k8w-crypto": "^0.2.0", + "k8w-extend-native": "^1.4.6", + "tsbuffer-schema": "^2.2.0", + "tslib": "*", + "typescript": "^4" + } + }, "tsbuffer-schema": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/tsbuffer-schema/-/tsbuffer-schema-2.2.0.tgz", @@ -5879,9 +3458,24 @@ } }, "tslib": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", - "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==" + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", + "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==" + }, + "tsrpc": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/tsrpc/-/tsrpc-3.3.0.tgz", + "integrity": "sha512-a7QYKrCBRzHy/RJoJVltCsJYoppSpIFcbhrytgCG1EHBbBOKZADJi3+W9tjdOpiNG5330KjBfLhHPew/nf9e5w==", + "requires": { + "@types/ws": "^7.4.7", + "bson": "*", + "chalk": "^4.1.2", + "tsbuffer": "^2.2.2", + "tsrpc-base-client": "^2.0.5", + "tsrpc-proto": "^1.4.1", + "uuid": "^8.3.2", + "ws": "^7.5.7" + } }, "tsrpc-base-client": { "version": "2.0.5", @@ -5894,73 +3488,92 @@ "tsrpc-proto": "^1.4.1" } }, + "tsrpc-cli": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/tsrpc-cli/-/tsrpc-cli-2.4.3.tgz", + "integrity": "sha512-L7lUqIOiKIz0Yt2P64ji7sFb/qRLI4KjPF9JUpaP0HbvaYCMn7+l1xEhVK39C1JCnFJomtAIgceMtL571E4d+g==", + "dev": true, + "requires": { + "chalk": "^4.1.2", + "chokidar": "^3.5.3", + "fs-extra": "^10.1.0", + "glob": "^7.2.0", + "inquirer": "^8.2.3", + "k8w-extend-native": "^1.4.6", + "minimist": "^1.2.6", + "ora": "^5.4.1", + "os-locale": "^5.0.0", + "ts-node": "^10.7.0", + "tsbuffer": "^2.2.2", + "tsbuffer-proto-generator": "^1.7.1", + "tsbuffer-schema": "^2.2.0", + "tsrpc-proto": "^1.4.2", + "typescript": "^4.6.3", + "typescript-formatter": "^7.2.2" + } + }, "tsrpc-proto": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/tsrpc-proto/-/tsrpc-proto-1.4.1.tgz", - "integrity": "sha512-qk0/vd5QSf8lx2kHxhhf59wji20RU7KjZ2md8NHLwFV09kLJ/jvR2kwM6lNQRIxYOrM9HvvdySlrnSJUkNkRyA==", + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/tsrpc-proto/-/tsrpc-proto-1.4.2.tgz", + "integrity": "sha512-MIjOfLixuk6C0CZZzgsBQX/RzlmPBhBasDhoyOUzdi4oOZekdDiia2q70B0ThzXPwIfnwa/uduZxkYx4jPzRdQ==", "requires": { "tsbuffer-schema": "^2.2.0", "tslib": "*" } }, - "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 - }, "type-fest": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", - "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", "dev": true }, - "typedarray-to-buffer": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", - "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", - "dev": true, - "requires": { - "is-typedarray": "^1.0.0" - } - }, "typescript": { - "version": "4.6.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.6.3.tgz", - "integrity": "sha512-yNIatDa5iaofVozS/uQJEl3JRWLKKGJKh6Yaiv0GLGSuhpFJe7P3SbHZ8/yjAHRQwKRoA6YZqlfjXWmVzoVSMw==", + "version": "4.6.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.6.4.tgz", + "integrity": "sha512-9ia/jWHIEbo49HfjrLGfKbZSuWo9iTMwXO+Ca3pRsSpbsMbc7/IU8NKdCZVRRBafVPGnoJeFL76ZOAA84I9fEg==", "dev": true }, - "universalify": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", - "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", - "dev": true - }, - "uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "typescript-formatter": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/typescript-formatter/-/typescript-formatter-7.2.2.tgz", + "integrity": "sha512-V7vfI9XArVhriOTYHPzMU2WUnm5IMdu9X/CPxs8mIMGxmTBFpDABlbkBka64PZJ9/xgQeRpK8KzzAG4MPzxBDQ==", "dev": true, "requires": { - "punycode": "^2.1.0" + "commandpost": "^1.0.0", + "editorconfig": "^0.15.0" } }, + "universalify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", + "dev": true + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", + "dev": true + }, "uuid": { "version": "8.3.2", "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==" }, "v8-compile-cache-lib": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.0.tgz", - "integrity": "sha512-mpSYqfsFvASnSn5qMiwrr4VKfumbPyONLCOPmsR3A6pTY/r0+tSaVbgPWSAIuzbk3lCTa+FForeTiO+wBQGkjA==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", "dev": true }, - "validator": { - "version": "13.7.0", - "resolved": "https://registry.npmjs.org/validator/-/validator-13.7.0.tgz", - "integrity": "sha512-nYXQLCBkpJ8X6ltALua9dRrZDHVYxjJ1wgskNt1lH9fzGjs3tgojGSCBjmEPwkWS1y29+DrizMTW19Pr9uB2nw==", - "dev": true + "wcwidth": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", + "integrity": "sha1-8LDc+RW8X/FSivrbLA4XtTLaL+g=", + "dev": true, + "requires": { + "defaults": "^1.0.3" + } }, "which": { "version": "2.0.2", @@ -5971,12 +3584,6 @@ "isexe": "^2.0.0" } }, - "which-module": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", - "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", - "dev": true - }, "workerpool": { "version": "6.2.0", "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.0.tgz", @@ -6000,18 +3607,6 @@ "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", "dev": true }, - "write-file-atomic": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", - "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", - "dev": true, - "requires": { - "imurmurhash": "^0.1.4", - "is-typedarray": "^1.0.0", - "signal-exit": "^3.0.2", - "typedarray-to-buffer": "^3.1.5" - } - }, "ws": { "version": "7.5.7", "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.7.tgz", @@ -6025,9 +3620,9 @@ "dev": true }, "yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", "dev": true }, "yargs": { @@ -6061,20 +3656,6 @@ "decamelize": "^4.0.0", "flat": "^5.0.2", "is-plain-obj": "^2.1.0" - }, - "dependencies": { - "camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", - "dev": true - }, - "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 - } } }, "yn": { @@ -6088,18 +3669,6 @@ "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", "dev": true - }, - "z-schema": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/z-schema/-/z-schema-5.0.3.tgz", - "integrity": "sha512-sGvEcBOTNum68x9jCpCVGPFJ6mWnkD0YxOcddDlJHRx3tKdB2q8pCHExMVZo/AV/6geuVJXG7hljDaWG8+5GDw==", - "dev": true, - "requires": { - "commander": "^2.20.3", - "lodash.get": "^4.4.2", - "lodash.isequal": "^4.5.0", - "validator": "^13.7.0" - } } } } diff --git a/package.json b/package.json index dd2efdb..2e74fff 100644 --- a/package.json +++ b/package.json @@ -1,77 +1,27 @@ { - "name": "tsrpc", - "version": "3.3.1-dev.0", - "description": "A TypeScript RPC Framework, with runtime type checking and built-in serialization, support both HTTP and WebSocket.", + "name": "tsrpc_test-.", + "version": "0.1.0", "main": "index.js", - "exports": { - "require": "./index.js", - "import": "./index.mjs" - }, - "typings": "index.d.ts", - "directories": { - "doc": "docs" - }, + "private": true, "scripts": { - "test": "npx mocha", - "genTestProto": "npx tsrpc-cli@latest proto --input test/proto --output test/proto/serviceProto.ts", - "coverage": "nyc mocha test/**/*.test.ts && start coverage\\index.html", - "build": "npm run build:js && npm run build:dts && npm run build:doc && node scripts/postBuild && cp package.json LICENSE README.md dist/", - "build:js": "rm -rf dist && npx rollup -c", - "build:dts": "rm -rf lib && npx tsc && npx api-extractor run --local --verbose && rm -rf lib", - "build:doc": "rm -rf docs/api && npx api-documenter markdown --input temp --output docs/api" + "dev": "tsrpc-cli dev", + "build": "tsrpc-cli build", + "doc": "tsrpc-cli doc", + "test": "mocha test/**/*.test.ts", + "proto": "tsrpc-cli proto", + "sync": "tsrpc-cli sync", + "api": "tsrpc-cli api" }, - "repository": { - "type": "git", - "url": "https://github.com/k8w/tsrpc.git" - }, - "keywords": [ - "k8w", - "ts", - "rpc", - "grpc", - "tsbuffer", - "fullstack", - "websocket", - "protobuf", - "socket.io" - ], - "author": "k8w", - "license": "MIT", "devDependencies": { - "@microsoft/api-documenter": "^7.17.9", - "@microsoft/api-extractor": "^7.22.2", - "@types/chai": "^4.3.1", "@types/mocha": "^8.2.3", "@types/node": "^15.14.9", - "@types/uuid": "^8.3.4", - "chai": "^4.3.6", "mocha": "^9.2.2", - "nyc": "^15.1.0", - "rollup": "^2.70.2", - "rollup-plugin-typescript2": "^0.31.2", + "onchange": "^7.1.0", "ts-node": "^10.7.0", - "typescript": "^4.6.3" + "tsrpc-cli": "^2.4.3", + "typescript": "^4.6.4" }, "dependencies": { - "@types/ws": "^7.4.7", - "bson": "*", - "chalk": "^4.1.2", - "tsbuffer": "^2.2.2", - "tsrpc-base-client": "^2.0.5", - "tsrpc-proto": "^1.4.1", - "uuid": "^8.3.2", - "ws": "^7.5.7" - }, - "nyc": { - "extension": [ - ".ts" - ], - "include": [ - "src/**/*.ts" - ], - "reporter": [ - "html" - ], - "all": true + "tsrpc": "^3.3.0" } } \ No newline at end of file diff --git a/res/mongodb-polyfill.d.ts b/res/mongodb-polyfill.d.ts deleted file mode 100644 index 2f4a675..0000000 --- a/res/mongodb-polyfill.d.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { ObjectId } from 'bson'; -import { OmitUnion } from 'k8w-extend-native'; - -type InsertOneResult = any; -type OptionalId = any; -type Document = any; - -declare module 'mongodb' { - export interface Collection { - insertOne(doc: OptionalUnlessRequiredId_1): Promise>; - } - export type OptionalUnlessRequiredId_1 = TSchema extends { - _id: ObjectId; - } ? (OmitUnion & { _id?: ObjectId }) : TSchema extends { - _id: any; - } ? TSchema : OptionalId; -} \ No newline at end of file diff --git a/rollup.config.js b/rollup.config.js deleted file mode 100644 index 5008f42..0000000 --- a/rollup.config.js +++ /dev/null @@ -1,42 +0,0 @@ -import typescript from 'rollup-plugin-typescript2'; - -export default [ - { - input: './src/index.ts', - output: [{ - format: 'cjs', - file: './dist/index.js', - banner: require('./scripts/copyright') - }], - plugins: [ - typescript({ - tsconfigOverride: { - compilerOptions: { - declaration: false, - declarationMap: false, - module: "esnext" - } - } - }) - ] - }, - { - input: './src/index.ts', - output: [{ - format: 'es', - file: './dist/index.mjs', - banner: require('./scripts/copyright') - }], - plugins: [ - typescript({ - tsconfigOverride: { - compilerOptions: { - declaration: false, - declarationMap: false, - module: "esnext" - } - } - }) - ] - } -] \ No newline at end of file diff --git a/scripts/copyright.js b/scripts/copyright.js deleted file mode 100644 index b17c121..0000000 --- a/scripts/copyright.js +++ /dev/null @@ -1,7 +0,0 @@ -module.exports = `/*! - * TSRPC v${require('../package.json').version} - * ----------------------------------------- - * Copyright (c) King Wang. - * MIT License - * https://github.com/k8w/tsrpc - */` \ No newline at end of file diff --git a/scripts/postBuild.js b/scripts/postBuild.js deleted file mode 100644 index 83c301f..0000000 --- a/scripts/postBuild.js +++ /dev/null @@ -1,26 +0,0 @@ -const fs = require('fs'); -const path = require('path'); - -// remove private / protected index.d.ts -(() => { - let content = fs.readFileSync(path.resolve(__dirname, '../dist/index.d.ts'), 'utf-8'); - content = content.replace(/^\s*(private|protected)\s+\_.+;/g, ''); - content = require('./copyright') + '\n' + content; - fs.writeFileSync(path.resolve(__dirname, '../dist/index.d.ts'), content, 'utf-8'); -})(); - -// replace __TSRPC_VERSION__from index.js/mjs -[ - path.resolve(__dirname, '../dist/index.js'), - path.resolve(__dirname, '../dist/index.mjs') -].forEach(filepath => { - let content = fs.readFileSync(filepath, 'utf-8'); - content = content.replace('__TSRPC_VERSION__', require('../package.json').version);; - fs.writeFileSync(filepath, content, 'utf-8'); -}); - -// mongodb-polyfill -fs.copyFileSync(path.resolve(__dirname, '../res/mongodb-polyfill.d.ts'), path.resolve(__dirname, '../dist/mongodb-polyfill.d.ts')); -let content = fs.readFileSync(path.resolve(__dirname, '../dist/index.d.ts'), 'utf-8'); -content = content.replace(`/// `, `/// \n/// `) -fs.writeFileSync(path.resolve(__dirname, '../dist/index.d.ts'), content, 'utf-8'); \ No newline at end of file diff --git a/src/api/ApiSend.ts b/src/api/ApiSend.ts new file mode 100644 index 0000000..1782b35 --- /dev/null +++ b/src/api/ApiSend.ts @@ -0,0 +1,26 @@ +import { ApiCall } from "tsrpc"; +import { server } from ".."; +import { ReqSend, ResSend } from "../shared/protocols/PtlSend"; + +// This is a demo code file +// Feel free to delete it + +export async function ApiSend(call: ApiCall) { + // Error + if (call.req.content.length === 0) { + call.error('Content is empty') + return; + } + + // Success + let time = new Date(); + call.succ({ + time: time + }); + + // Broadcast + server.broadcastMsg('Chat', { + content: call.req.content, + time: time + }) +} \ No newline at end of file diff --git a/src/client/http/HttpClient.ts b/src/client/http/HttpClient.ts deleted file mode 100644 index 41f61e5..0000000 --- a/src/client/http/HttpClient.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { ObjectId } from "bson"; -import http from "http"; -import https from "https"; -import { BaseHttpClient, BaseHttpClientOptions, defaultBaseHttpClientOptions } from "tsrpc-base-client"; -import { BaseServiceType, ServiceProto } from "tsrpc-proto"; -import { HttpProxy } from "./HttpProxy"; - -/** - * Client for TSRPC HTTP Server. - * It uses native http module of NodeJS. - * @typeParam ServiceType - `ServiceType` from generated `proto.ts` - */ -export class HttpClient extends BaseHttpClient { - - readonly options!: Readonly; - - constructor(proto: ServiceProto, options?: Partial) { - let httpProxy = new HttpProxy; - super(proto, httpProxy, { - customObjectIdClass: ObjectId, - ...defaultHttpClientOptions, - ...options - }); - - httpProxy.agent = this.options.agent; - } - -} - -const defaultHttpClientOptions: HttpClientOptions = { - ...defaultBaseHttpClientOptions -} - -export interface HttpClientOptions extends BaseHttpClientOptions { - /** NodeJS HTTP Agent */ - agent?: http.Agent | https.Agent; -} \ No newline at end of file diff --git a/src/client/http/HttpProxy.ts b/src/client/http/HttpProxy.ts deleted file mode 100644 index b21ffe9..0000000 --- a/src/client/http/HttpProxy.ts +++ /dev/null @@ -1,69 +0,0 @@ -import http from "http"; -import https from "https"; -import { IHttpProxy } from "tsrpc-base-client"; -import { TsrpcError } from "tsrpc-proto"; - -/** @internal */ -export class HttpProxy implements IHttpProxy { - - /** NodeJS HTTP Agent */ - agent?: http.Agent | https.Agent; - - fetch(options: Parameters[0]): ReturnType { - let nodeHttp = options.url.startsWith('https://') ? https : http; - - let rs!: (v: { isSucc: true, res: string | Uint8Array } | { isSucc: false, err: TsrpcError }) => void; - let promise: ReturnType['promise'] = new Promise(_rs => { - rs = _rs; - }) - - let httpReq: http.ClientRequest; - httpReq = nodeHttp.request(options.url, { - method: options.method, - agent: this.agent, - timeout: options.timeout, - headers: options.headers, - }, httpRes => { - let data: Buffer[] = []; - httpRes.on('data', (v: Buffer) => { - data.push(v) - }); - httpRes.on('end', () => { - let buf: Uint8Array = Buffer.concat(data); - if (options.responseType === 'text') { - rs({ - isSucc: true, - res: buf.toString() - }) - } - else { - rs({ - isSucc: true, - res: buf - }) - } - }) - }); - - httpReq.on('error', e => { - rs({ - isSucc: false, - err: new TsrpcError(e.message, { - type: TsrpcError.Type.NetworkError, - code: (e as any).code - }) - }); - }); - - let buf = options.data; - httpReq.end(typeof buf === 'string' ? buf : Buffer.from(buf.buffer, buf.byteOffset, buf.byteLength)); - - let abort = httpReq.abort.bind(httpReq); - - return { - promise: promise, - abort: abort - } - } - -} \ No newline at end of file diff --git a/src/client/ws/WebSocketProxy.ts b/src/client/ws/WebSocketProxy.ts deleted file mode 100644 index 65c74ae..0000000 --- a/src/client/ws/WebSocketProxy.ts +++ /dev/null @@ -1,58 +0,0 @@ -import { IWebSocketProxy } from "tsrpc-base-client"; -import { TsrpcError } from "tsrpc-proto"; -import WebSocket from 'ws'; - -/** - * @internal - */ -export class WebSocketProxy implements IWebSocketProxy { - - options!: IWebSocketProxy['options'] - - private _ws?: WebSocket; - connect(server: string, protocols?: string[]): void { - this._ws = new WebSocket(server, protocols); - this._ws.onopen = this.options.onOpen; - this._ws.onclose = e => { - this.options.onClose(e.code, e.reason); - this._ws = undefined; - } - this._ws.onerror = e => { - this.options.onError(e.error); - } - this._ws.onmessage = e => { - if (e.data instanceof ArrayBuffer) { - this.options.onMessage(new Uint8Array(e.data)); - } - else if (Array.isArray(e.data)) { - this.options.onMessage(Buffer.concat(e.data)); - } - else { - this.options.onMessage(e.data); - } - } - } - close(code?: number, reason?: string): void { - this._ws?.close(code, reason); - this._ws = undefined; - } - send(data: string | Uint8Array): Promise<{ err?: TsrpcError | undefined; }> { - return new Promise(rs => { - this._ws?.send(data, err => { - if (err) { - this.options.logger?.error('WebSocket Send Error:', err); - rs({ - err: new TsrpcError('Network Error', { - code: 'SEND_BUF_ERR', - type: TsrpcError.Type.NetworkError, - innerErr: err - }) - }); - return; - } - rs({}); - }); - }) - } - -} \ No newline at end of file diff --git a/src/client/ws/WsClient.ts b/src/client/ws/WsClient.ts deleted file mode 100644 index d4142dd..0000000 --- a/src/client/ws/WsClient.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { ObjectId } from "bson"; -import { BaseWsClient, BaseWsClientOptions, defaultBaseWsClientOptions } from "tsrpc-base-client"; -import { BaseServiceType, ServiceProto } from "tsrpc-proto"; -import { WebSocketProxy } from "./WebSocketProxy"; - -/** - * Client for TSRPC WebSocket Server. - * @typeParam ServiceType - `ServiceType` from generated `proto.ts` - */ -export class WsClient extends BaseWsClient { - - readonly options!: Readonly; - - constructor(proto: ServiceProto, options?: Partial) { - let wsp = new WebSocketProxy(); - super(proto, wsp, { - customObjectIdClass: ObjectId, - ...defaultWsClientOptions, - ...options - }) - } - -} - -const defaultWsClientOptions: WsClientOptions = { - ...defaultBaseWsClientOptions, -} - -export interface WsClientOptions extends BaseWsClientOptions { - -} \ No newline at end of file diff --git a/src/index.ts b/src/index.ts index c1c1208..b7c765f 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,27 +1,25 @@ -import 'k8w-extend-native'; - -// Common -export * from 'tsrpc-base-client'; -export * from 'tsrpc-proto'; -export * from './client/http/HttpClient'; -export * from './client/ws/WsClient'; -export * from './models/version'; -export * from './server/base/ApiCall'; -// Base -export * from './server/base/BaseCall'; -export * from './server/base/BaseConnection'; -export * from './server/base/BaseServer'; -export * from './server/base/MsgCall'; -export * from './server/http/ApiCallHttp'; -// Http -export * from './server/http/HttpConnection'; -export * from './server/http/HttpServer'; -export * from './server/http/MsgCallHttp'; -export * from './server/models/PrefixLogger'; -export * from './server/models/TerminalColorLogger'; -// WebSocket -export * from './server/ws/ApiCallWs'; -export * from './server/ws/MsgCallWs'; -export * from './server/ws/WsConnection'; -export * from './server/ws/WsServer'; - +import * as path from "path"; +import { WsServer } from "tsrpc"; +import { serviceProto } from './shared/protocols/serviceProto'; + +// Create the Server +export const server = new WsServer(serviceProto, { + port: 3000, + // Remove this to use binary mode (remove from the client too) + json: true +}); + +// Initialize before server start +async function init() { + await server.autoImplementApi(path.resolve(__dirname, 'api')); + + // TODO + // Prepare something... (e.g. connect the db) +}; + +// Entry function +async function main() { + await init(); + await server.start(); +} +main(); \ No newline at end of file diff --git a/src/models/HttpUtil.ts b/src/models/HttpUtil.ts deleted file mode 100644 index 7bbe72d..0000000 --- a/src/models/HttpUtil.ts +++ /dev/null @@ -1,22 +0,0 @@ -import * as http from "http"; - -export class HttpUtil { - static getClientIp(req: http.IncomingMessage) { - var ipAddress; - // The request may be forwarded from local web server. - var forwardedIpsStr = req.headers['x-forwarded-for'] as string | undefined; - if (forwardedIpsStr) { - // 'x-forwarded-for' header may return multiple IP addresses in - // the format: "client IP, proxy 1 IP, proxy 2 IP" so take the - // the first one - var forwardedIps = forwardedIpsStr.split(','); - ipAddress = forwardedIps[0]; - } - if (!ipAddress) { - // If request was not forwarded - ipAddress = req.connection.remoteAddress; - } - // Remove prefix ::ffff: - return ipAddress ? ipAddress.replace(/^::ffff:/, '') : ''; - }; -} \ No newline at end of file diff --git a/src/models/Pool.ts b/src/models/Pool.ts deleted file mode 100644 index af697b0..0000000 --- a/src/models/Pool.ts +++ /dev/null @@ -1,35 +0,0 @@ -export class Pool { - - private _pools: ItemClass[] = []; - private _itemClass: { new(): ItemClass }; - enabled: boolean; - - constructor(itemClass: { new(): ItemClass }, enabled: boolean) { - this._itemClass = itemClass; - this.enabled = enabled; - } - - get() { - let item = this.enabled && this._pools.pop(); - if (!item) { - item = new this._itemClass(); - } - item.reuse?.(); - return item; - } - - put(item: ItemClass) { - if (!this.enabled || this._pools.indexOf(item) > -1) { - return; - } - - item.unuse?.(); - this._pools.push(item); - } - -} - -export interface PoolItem { - reuse: () => void; - unuse: () => void; -} \ No newline at end of file diff --git a/src/models/version.ts b/src/models/version.ts deleted file mode 100644 index 061ebe8..0000000 --- a/src/models/version.ts +++ /dev/null @@ -1,2 +0,0 @@ -/** Version of TSRPC */ -export const TSRPC_VERSION = '__TSRPC_VERSION__'; \ No newline at end of file diff --git a/src/server/base/ApiCall.ts b/src/server/base/ApiCall.ts deleted file mode 100644 index 9a684eb..0000000 --- a/src/server/base/ApiCall.ts +++ /dev/null @@ -1,215 +0,0 @@ -import { TSBuffer } from 'tsbuffer'; -import { ApiService, TransportDataUtil } from "tsrpc-base-client"; -import { ApiReturn, BaseServiceType, ServerOutputData, TsrpcError, TsrpcErrorData, TsrpcErrorType } from "tsrpc-proto"; -import { PrefixLogger } from "../models/PrefixLogger"; -import { BaseCall, BaseCallOptions } from "./BaseCall"; -import { BaseConnection } from './BaseConnection'; - -export interface ApiCallOptions extends BaseCallOptions { - /** Which service the Call is belong to */ - service: ApiService, - /** Only exists in long connection, it is used to associate request and response. - * It is created by the client, and the server would return the same value in `ApiReturn`. - */ - sn?: number, - /** Request Data */ - req: Req -} - -/** - * A call request by `client.callApi()` - * @typeParam Req - Type of request - * @typeParam Res - Type of response - * @typeParam ServiceType - The same `ServiceType` to server, it is used for code auto hint. - */ -export abstract class ApiCall extends BaseCall { - readonly type = 'api' as const; - - /** - * Which `ApiService` the request is calling for - */ - readonly service!: ApiService; - /** Only exists in long connection, it is used to associate request and response. - * It is created by the client, and the server would return the same value in `ApiReturn`. - */ - readonly sn?: number; - /** - * Request data from the client, type of it is checked by the framework already. - */ - readonly req: Req; - - constructor(options: ApiCallOptions, logger?: PrefixLogger) { - super(options, logger ?? new PrefixLogger({ - logger: options.conn.logger, - prefixs: [`[Api:${options.service.name}]${options.sn !== undefined ? ` SN=${options.sn}` : ''}`] - })); - - this.sn = options.sn; - this.req = options.req; - } - - protected _return?: ApiReturn; - /** - * Response Data that sent already. - * `undefined` means no return data is sent yet. (Never `call.succ()` and `call.error()`) - */ - public get return(): ApiReturn | undefined { - return this._return; - } - - protected _usedTime: number | undefined; - /** Time from received req to send return data */ - public get usedTime(): number | undefined { - return this._usedTime; - } - - /** - * Send a successful `ApiReturn` with response data - * @param res - Response data - * @returns Promise resolved means the buffer is sent to kernel - */ - succ(res: Res): Promise { - return this._prepareReturn({ - isSucc: true, - res: res - }) - } - - /** - * Send a error `ApiReturn` with a `TsrpcError` - * @returns Promise resolved means the buffer is sent to kernel - */ - error(message: string, info?: Partial): Promise; - error(err: TsrpcError): Promise; - error(errOrMsg: string | TsrpcError, data?: Partial): Promise { - let error: TsrpcError = typeof errOrMsg === 'string' ? new TsrpcError(errOrMsg, data) : errOrMsg; - return this._prepareReturn({ - isSucc: false, - err: error - }) - }; - - - protected async _prepareReturn(ret: ApiReturn): Promise { - if (this._return) { - return; - } - this._return = ret; - - // Pre Flow - let preFlow = await this.server.flows.preApiReturnFlow.exec({ call: this, return: ret }, this.logger); - // Stopped! - if (!preFlow) { - this.logger.debug('[preApiReturnFlow]', 'Canceled') - return; - } - ret = preFlow.return; - - // record & log ret - this._usedTime = Date.now() - this.startTime; - if (ret.isSucc) { - this.logger.log('[ApiRes]', `${this.usedTime}ms`, this.server.options.logResBody ? ret.res : ''); - } - else { - if (ret.err.type === TsrpcErrorType.ApiError) { - this.logger.log('[ApiErr]', `${this.usedTime}ms`, ret.err, 'req=', this.req); - } - else { - this.logger.error(`[ApiErr]`, `${this.usedTime}ms`, ret.err, 'req=', this.req) - } - } - - // Do send! - this._return = ret; - let opSend = await this._sendReturn(ret); - if (!opSend.isSucc) { - if (opSend.canceledByFlow) { - this.logger.debug(`[${opSend.canceledByFlow}]`, 'Canceled'); - } - else { - this.logger.error('[SendDataErr]', opSend.errMsg); - if (ret.isSucc || ret.err.type === TsrpcErrorType.ApiError) { - this._return = undefined; - this.server.onInternalServerError({ message: opSend.errMsg, name: 'SendReturnErr' }, this) - } - } - - return; - } - - // Post Flow - await this.server.flows.postApiReturnFlow.exec(preFlow, this.logger); - } - - protected async _sendReturn(ret: ApiReturn): ReturnType> { - // Encode - let opServerOutput = ApiCall.encodeApiReturn(this.server.tsbuffer, this.service, ret, this.conn.dataType, this.sn);; - if (!opServerOutput.isSucc) { - this.server.onInternalServerError({ message: opServerOutput.errMsg, stack: ' |- TransportDataUtil.encodeApiReturn\n |- ApiCall._sendReturn' }, this); - return opServerOutput; - } - - let opSend = await this.conn.sendData(opServerOutput.output); - if (!opSend.isSucc) { - return opSend; - } - return opSend; - } - - static encodeApiReturn(tsbuffer: TSBuffer, service: ApiService, apiReturn: ApiReturn, type: 'text', sn?: number): EncodeApiReturnOutput - static encodeApiReturn(tsbuffer: TSBuffer, service: ApiService, apiReturn: ApiReturn, type: 'buffer', sn?: number): EncodeApiReturnOutput - static encodeApiReturn(tsbuffer: TSBuffer, service: ApiService, apiReturn: ApiReturn, type: 'json', sn?: number): EncodeApiReturnOutput - static encodeApiReturn(tsbuffer: TSBuffer, service: ApiService, apiReturn: ApiReturn, type: 'text' | 'buffer' | 'json', sn?: number): EncodeApiReturnOutput | EncodeApiReturnOutput | EncodeApiReturnOutput; - static encodeApiReturn(tsbuffer: TSBuffer, service: ApiService, apiReturn: ApiReturn, type: 'text' | 'buffer' | 'json', sn?: number): EncodeApiReturnOutput | EncodeApiReturnOutput | EncodeApiReturnOutput { - if (type === 'buffer') { - let serverOutputData: ServerOutputData = { - sn: sn, - serviceId: sn !== undefined ? service.id : undefined - }; - if (apiReturn.isSucc) { - let op = tsbuffer.encode(apiReturn.res, service.resSchemaId); - if (!op.isSucc) { - return op; - } - serverOutputData.buffer = op.buf; - } - else { - serverOutputData.error = apiReturn.err; - } - - let op = TransportDataUtil.tsbuffer.encode(serverOutputData, 'ServerOutputData'); - return op.isSucc ? { isSucc: true, output: op.buf } : { isSucc: false, errMsg: op.errMsg }; - } - else { - apiReturn = { ...apiReturn }; - if (apiReturn.isSucc) { - let op = tsbuffer.encodeJSON(apiReturn.res, service.resSchemaId); - if (!op.isSucc) { - return op; - } - apiReturn.res = op.json; - } - else { - apiReturn.err = { - ...apiReturn.err - } - } - let json = sn == undefined ? apiReturn : [service.name, apiReturn, sn]; - return { isSucc: true, output: type === 'json' ? json : JSON.stringify(json) }; - } - } -} - -export type SendReturnMethod = (ret: ApiReturn) => ReturnType; - -export declare type EncodeApiReturnOutput = { - isSucc: true; - /** Encoded binary buffer */ - output: T; - errMsg?: undefined; -} | { - isSucc: false; - /** Error message */ - errMsg: string; - output?: undefined; -}; \ No newline at end of file diff --git a/src/server/base/BaseCall.ts b/src/server/base/BaseCall.ts deleted file mode 100644 index 904740f..0000000 --- a/src/server/base/BaseCall.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { ApiService, MsgService } from 'tsrpc-base-client'; -import { BaseServiceType } from 'tsrpc-proto'; -import { PrefixLogger } from '../models/PrefixLogger'; -import { BaseConnection } from './BaseConnection'; - -export interface BaseCallOptions { - /** Connection */ - conn: BaseConnection, - /** Which service the call is belong to */ - service: ApiService | MsgService -} - -export abstract class BaseCall { - readonly conn: BaseConnection; - readonly service: ApiService | MsgService; - /** Time that server created the call */ - readonly startTime: number; - readonly logger: PrefixLogger; - - constructor(options: BaseCallOptions, logger: PrefixLogger) { - this.conn = options.conn; - this.service = options.service; - this.startTime = Date.now(); - this.logger = logger; - } - - get server(): this['conn']['server'] { - return this.conn.server; - } -} \ No newline at end of file diff --git a/src/server/base/BaseConnection.ts b/src/server/base/BaseConnection.ts deleted file mode 100644 index 66742ab..0000000 --- a/src/server/base/BaseConnection.ts +++ /dev/null @@ -1,182 +0,0 @@ -import { MsgHandlerManager, ParsedServerInput, TransportDataUtil } from "tsrpc-base-client"; -import { BaseServiceType } from "tsrpc-proto"; -import { PrefixLogger } from "../models/PrefixLogger"; -import { ApiCall } from "./ApiCall"; -import { BaseServer, MsgHandler } from "./BaseServer"; -import { MsgCall } from "./MsgCall"; - -export interface BaseConnectionOptions { - /** Created by server, each Call has a unique id. */ - id: string; - /** Client IP address */ - ip: string, - server: BaseServer, - dataType: 'text' | 'buffer' | 'json' -} - -export abstract class BaseConnection { - /** It is long connection or short connection */ - abstract readonly type: 'LONG' | 'SHORT'; - - protected abstract readonly ApiCallClass: { new(options: any): ApiCall }; - protected abstract readonly MsgCallClass: { new(options: any): MsgCall }; - - /** Connection unique ID */ - readonly id: string; - /** Client IP address */ - readonly ip: string; - readonly server: BaseServer; - readonly logger: PrefixLogger; - dataType: BaseConnectionOptions['dataType']; - - constructor(options: BaseConnectionOptions, logger: PrefixLogger) { - this.id = options.id; - this.ip = options.ip; - this.server = options.server; - this.logger = logger; - this.dataType = options.dataType; - } - - abstract get status(): ConnectionStatus; - /** Close the connection */ - abstract close(reason?: string): void; - - /** Send buffer (with pre-flow and post-flow) */ - async sendData(data: string | Uint8Array | object, call?: ApiCall): Promise<{ isSucc: true } | { isSucc: false, errMsg: string, canceledByFlow?: string }> { - // Pre Flow - let pre = await this.server.flows.preSendDataFlow.exec({ conn: this, data: data, call: call }, call?.logger || this.logger); - if (!pre) { - return { isSucc: false, errMsg: 'Canceled by preSendDataFlow', canceledByFlow: 'preSendDataFlow' }; - } - data = pre.data; - - // @deprecated Pre Buffer Flow - if (data instanceof Uint8Array) { - let preBuf = await this.server.flows.preSendBufferFlow.exec({ conn: this, buf: data, call: call }, call?.logger || this.logger); - if (!preBuf) { - return { isSucc: false, errMsg: 'Canceled by preSendBufferFlow', canceledByFlow: 'preSendBufferFlow' }; - } - data = preBuf.buf; - } - - // debugBuf log - if (this.server.options.debugBuf) { - if (typeof data === 'string') { - (call?.logger ?? this.logger)?.debug(`[SendText] length=${data.length}`, data); - } - else if (data instanceof Uint8Array) { - (call?.logger ?? this.logger)?.debug(`[SendBuf] length=${data.length}`, data); - } - else { - (call?.logger ?? this.logger)?.debug('[SendJSON]', data); - } - } - - return this.doSendData(data, call); - } - protected abstract doSendData(data: string | Uint8Array | object, call?: ApiCall): Promise<{ isSucc: true } | { isSucc: false, errMsg: string }>; - - makeCall(input: ParsedServerInput): ApiCall | MsgCall { - if (input.type === 'api') { - return new this.ApiCallClass({ - conn: this, - service: input.service, - req: input.req, - sn: input.sn, - }) - } - else { - return new this.MsgCallClass({ - conn: this, - service: input.service, - msg: input.msg - }) - } - } - - /** - * Send message to the client, only be available when it is long connection. - * @param msgName - * @param msg - Message body - * @returns Promise resolved when the buffer is sent to kernel, it not represents the server received it. - */ - async sendMsg(msgName: T, msg: ServiceType['msg'][T]): ReturnType { - if (this.type === 'SHORT') { - this.logger.warn('[SendMsgErr]', `[${msgName}]`, 'Short connection cannot sendMsg'); - return { isSucc: false, errMsg: 'Short connection cannot sendMsg' } - } - - let service = this.server.serviceMap.msgName2Service[msgName as string]; - if (!service) { - this.logger.warn('[SendMsgErr]', `[${msgName}]`, `Invalid msg name: ${msgName}`); - return { isSucc: false, errMsg: `Invalid msg name: ${msgName}` } - } - - // Pre Flow - let pre = await this.server.flows.preSendMsgFlow.exec({ conn: this, service: service, msg: msg }, this.logger); - if (!pre) { - this.logger.debug('[preSendMsgFlow]', 'Canceled'); - return { isSucc: false, errMsg: 'Canceled by preSendMsgFlow', canceledByFlow: 'preSendMsgFlow' }; - } - msg = pre.msg; - - // Encode - let opServerOutput = TransportDataUtil.encodeServerMsg(this.server.tsbuffer, service, msg, this.dataType, this.type); - if (!opServerOutput.isSucc) { - this.logger.warn('[SendMsgErr]', `[${msgName}]`, opServerOutput.errMsg); - return opServerOutput; - } - - // Do send! - this.server.options.logMsg && this.logger.log('[SendMsg]', `[${msgName}]`, msg); - let opSend = await this.sendData(opServerOutput.output); - if (!opSend.isSucc) { - return opSend; - } - - // Post Flow - await this.server.flows.postSendMsgFlow.exec(pre, this.logger); - - return { isSucc: true }; - } - - // 多个Handler将异步并行执行 - private _msgHandlers?: MsgHandlerManager; - /** - * Add a message handler, - * duplicate handlers to the same `msgName` would be ignored. - * @param msgName - * @param handler - */ - listenMsg>(msgName: Msg, handler: MsgHandler): MsgHandler { - if (!this._msgHandlers) { - this._msgHandlers = new MsgHandlerManager(); - } - this._msgHandlers.addHandler(msgName as string, handler); - return handler; - }; - /** - * Remove a message handler - */ - unlistenMsg>(msgName: Msg, handler: Function): void { - if (!this._msgHandlers) { - this._msgHandlers = new MsgHandlerManager(); - } - this._msgHandlers.removeHandler(msgName as string, handler); - }; - /** - * Remove all handlers from a message - */ - unlistenMsgAll>(msgName: Msg): void { - if (!this._msgHandlers) { - this._msgHandlers = new MsgHandlerManager(); - } - this._msgHandlers.removeAllHandlers(msgName as string); - }; -} - -export enum ConnectionStatus { - Opened = 'OPENED', - Closing = 'CLOSING', - Closed = 'CLOSED' -} \ No newline at end of file diff --git a/src/server/base/BaseServer.ts b/src/server/base/BaseServer.ts deleted file mode 100644 index 09bf809..0000000 --- a/src/server/base/BaseServer.ts +++ /dev/null @@ -1,937 +0,0 @@ -import { ObjectId } from "bson"; -import chalk from "chalk"; -import * as path from "path"; -import { TSBuffer } from 'tsbuffer'; -import { ApiService, Counter, Flow, getCustomObjectIdTypes, MsgHandlerManager, MsgService, ParsedServerInput, ServiceMap, ServiceMapUtil, TransportDataUtil } from 'tsrpc-base-client'; -import { ApiReturn, ApiServiceDef, BaseServiceType, Logger, LogLevel, ServerInputData, ServiceProto, setLogLevel, TsrpcError, TsrpcErrorType } from 'tsrpc-proto'; -import { ApiCallInner } from "../inner/ApiCallInner"; -import { InnerConnection } from "../inner/InnerConnection"; -import { TerminalColorLogger } from '../models/TerminalColorLogger'; -import { ApiCall } from './ApiCall'; -import { BaseConnection } from './BaseConnection'; -import { MsgCall } from './MsgCall'; - -/** - * Abstract base class for TSRPC Server. - * Implement on a transportation protocol (like HTTP WebSocket) by extend it. - * @typeParam ServiceType - `ServiceType` from generated `proto.ts` - */ -export abstract class BaseServer{ - /** - * Start the server - * @throws - */ - abstract start(): Promise; - - /** - * Stop server immediately, not waiting for the requests ending. - */ - abstract stop(): Promise; - - protected _status: ServerStatus = ServerStatus.Closed; - get status(): ServerStatus { - return this._status; - } - - // 配置及其衍生项 - readonly proto: ServiceProto; - readonly options: BaseServerOptions; - readonly tsbuffer: TSBuffer; - readonly serviceMap: ServiceMap; - readonly logger: Logger; - - protected _connIdCounter = new Counter(1); - - /** - * Flow is a specific concept created by TSRPC family. - * All pre-flow can interrupt latter behaviours. - * All post-flow can NOT interrupt latter behaviours. - */ - readonly flows = { - // Conn Flows - /** After the connection is created */ - postConnectFlow: new Flow>(), - /** After the connection is disconnected */ - postDisconnectFlow: new Flow<{ conn: BaseConnection, reason?: string }>(), - - // Buffer Flows - /** - * Before processing the received data, usually be used to encryption / decryption. - * Return `null | undefined` would ignore the buffer. - */ - preRecvDataFlow: new Flow<{ conn: BaseConnection, data: string | Uint8Array | object, serviceName?: string }>(), - /** - * Before send out data to network, usually be used to encryption / decryption. - * Return `null | undefined` would not send the buffer. - */ - preSendDataFlow: new Flow<{ conn: BaseConnection, data: string | Uint8Array | object, call?: ApiCall }>(), - /** - * @deprecated Use `preRecvDataFlow` instead. - */ - preRecvBufferFlow: new Flow<{ conn: BaseConnection, buf: Uint8Array }>(), - /** - * @deprecated Use `preSendDataFlow` instead. - */ - preSendBufferFlow: new Flow<{ conn: BaseConnection, buf: Uint8Array, call?: ApiCall }>(), - - // ApiCall Flows - /** - * Before a API request is send. - * Return `null | undefined` would cancel the request. - */ - preApiCallFlow: new Flow(), - /** - * Before return the `ApiReturn` to the client. - * It may be used to change the return value, or return `null | undefined` to abort the request. - */ - preApiReturnFlow: new Flow<{ call: ApiCall, return: ApiReturn }>(), - /** - * After the `ApiReturn` is send. - * return `null | undefined` would NOT interrupt latter behaviours. - */ - postApiReturnFlow: new Flow<{ call: ApiCall, return: ApiReturn }>(), - /** - * After the api handler is executed. - * return `null | undefined` would NOT interrupt latter behaviours. - */ - postApiCallFlow: new Flow(), - - // MsgCall Flows - /** - * Before handle a `MsgCall` - */ - preMsgCallFlow: new Flow(), - /** - * After handlers of a `MsgCall` are executed. - * return `null | undefined` would NOT interrupt latter behaviours. - */ - postMsgCallFlow: new Flow(), - /** - * Before send out a message. - * return `null | undefined` would NOT interrupt latter behaviours. - */ - preSendMsgFlow: new Flow<{ conn: BaseConnection, service: MsgService, msg: any }>(), - /** - * After send out a message. - * return `null | undefined` would NOT interrupt latter behaviours. - */ - postSendMsgFlow: new Flow<{ conn: BaseConnection, service: MsgService, msg: any }>(), - } as const; - - // Handlers - private _apiHandlers: { [apiName: string]: ApiHandler | undefined } = {}; - // 多个Handler将异步并行执行 - private _msgHandlers: MsgHandlerManager = new MsgHandlerManager(); - - private static _isUncaughtExceptionProcessed = false; - /** - * It makes the `uncaughtException` and `unhandledRejection` not lead to the server stopping. - * @param logger - * @returns - */ - static processUncaughtException(logger: Logger) { - if (this._isUncaughtExceptionProcessed) { - return; - } - this._isUncaughtExceptionProcessed = true; - - process.on('uncaughtException', e => { - logger.error('[uncaughtException]', e); - }); - - process.on('unhandledRejection', e => { - logger.error('[unhandledRejection]', e); - }); - } - - constructor(proto: ServiceProto, options: BaseServerOptions) { - this.proto = proto; - this.options = options; - - // @deprecated jsonEnabled - if (this.options.json) { - this.options.jsonEnabled = true; - } - - this.tsbuffer = new TSBuffer({ - ...proto.types, - // Support mongodb/ObjectId - ...getCustomObjectIdTypes(ObjectId) - }, { - strictNullChecks: this.options.strictNullChecks - }); - this.serviceMap = ServiceMapUtil.getServiceMap(proto); - this.logger = this.options.logger; - setLogLevel(this.logger, this.options.logLevel); - - // Process uncaught exception, so that Node.js process would not exit easily - BaseServer.processUncaughtException(this.logger); - - // default flows onError handler - this._setDefaultFlowOnError(); - } - - protected _setDefaultFlowOnError() { - // API Flow Error: return [InternalServerError] - this.flows.preApiCallFlow.onError = (e, call) => { - if (e instanceof TsrpcError) { - call.error(e) - } - else { - this.onInternalServerError(e, call) - } - }; - this.flows.postApiCallFlow.onError = (e, call) => { - if (!call.return) { - if (e instanceof TsrpcError) { - call.error(e) - } - else { - this.onInternalServerError(e, call) - } - } - else { - call.logger.error('postApiCallFlow Error:', e); - } - }; - this.flows.preApiReturnFlow.onError = (e, last) => { - last.call['_return'] = undefined; - if (e instanceof TsrpcError) { - last.call.error(e) - } - else { - this.onInternalServerError(e, last.call) - } - } - this.flows.postApiReturnFlow.onError = (e, last) => { - if (!last.call.return) { - if (e instanceof TsrpcError) { - last.call.error(e) - } - else { - this.onInternalServerError(e, last.call) - } - } - } - } - - protected _pendingApiCallNum = 0; - - // #region receive buffer process flow - /** - * Process the buffer, after the `preRecvBufferFlow`. - */ - async _onRecvData(conn: BaseConnection, data: string | Uint8Array | object, serviceName?: string) { - // 非 OPENED 状态 停止接受新的请求 - if (!(conn instanceof InnerConnection) && this.status !== ServerStatus.Opened) { - return; - } - - // debugBuf log - if (this.options.debugBuf) { - if (typeof data === 'string') { - conn.logger?.debug(`[RecvText] length=${data.length}`, data); - } - else if (data instanceof Uint8Array) { - conn.logger?.debug(`[RecvBuf] length=${data.length}`, data); - } - else { - conn.logger?.debug('[RecvJSON]', data); - } - } - - // jsonEnabled 未启用,不支持文本请求 - if (typeof data === 'string' && !this.options.jsonEnabled) { - this.onInputDataError('JSON mode is not enabled, please use binary instead.', conn, data); - return; - } - - let pre = await this.flows.preRecvDataFlow.exec({ conn: conn, data: data, serviceName: serviceName }, conn.logger); - if (!pre) { - conn.logger.debug('[preRecvDataFlow] Canceled'); - return; - } - data = pre.data; - serviceName = pre.serviceName; - - // @deprecated preRecvBuffer - if (data instanceof Uint8Array) { - let preBuf = await this.flows.preRecvBufferFlow.exec({ conn: conn, buf: data }, conn.logger); - if (!preBuf) { - conn.logger.debug('[preRecvBufferFlow] Canceled'); - return; - } - data = preBuf.buf; - } - - // Parse Call - let opInput = this._parseServerInput(this.tsbuffer, this.serviceMap, data, serviceName); - if (!opInput.isSucc) { - this.onInputDataError(opInput.errMsg, conn, data); - return; - } - let call = conn.makeCall(opInput.result); - - if (call.type === 'api') { - await this._handleApiCall(call); - } - else { - await this._onMsgCall(call); - } - } - - protected async _handleApiCall(call: ApiCall) { - ++this._pendingApiCallNum; - await this._onApiCall(call); - if (--this._pendingApiCallNum === 0) { - this._gracefulStop?.rs(); - } - } - - protected async _onApiCall(call: ApiCall) { - let timeoutTimer = this.options.apiTimeout ? setTimeout(() => { - if (!call.return) { - call.error('Server Timeout', { - code: 'SERVER_TIMEOUT', - type: TsrpcErrorType.ServerError - }) - } - timeoutTimer = undefined; - }, this.options.apiTimeout) : undefined; - - // Pre Flow - let preFlow = await this.flows.preApiCallFlow.exec(call, call.logger); - if (!preFlow) { - if (timeoutTimer) { - clearTimeout(timeoutTimer); - timeoutTimer = undefined; - } - call.logger.debug('[preApiCallFlow] Canceled'); - return; - } - call = preFlow; - - // exec ApiCall - call.logger.log('[ApiReq]', this.options.logReqBody ? call.req : ''); - let { handler } = await this.getApiHandler(call.service, this._delayImplementApiPath, call.logger); - // exec API handler - if (handler) { - try { - await handler(call); - } - catch (e: any) { - if (e instanceof TsrpcError) { - call.error(e); - } - else { - this.onInternalServerError(e, call); - } - } - } - // 未找到ApiHandler,且未进行任何输出 - else { - call.error(`Unhandled API: ${call.service.name}`, { code: 'UNHANDLED_API', type: TsrpcErrorType.ServerError }); - } - - // Post Flow - await this.flows.postApiCallFlow.exec(call, call.logger); - - if (timeoutTimer) { - clearTimeout(timeoutTimer); - timeoutTimer = undefined; - } - - // Destroy call - // if (!call.return) { - // this.onInternalServerError({ message: 'API not return anything' }, call); - // } - } - - protected async _onMsgCall(call: MsgCall) { - // 收到Msg即可断开连接(短连接) - if (call.conn.type === 'SHORT') { - call.conn.close(); - } - - // Pre Flow - let preFlow = await this.flows.preMsgCallFlow.exec(call, call.logger); - if (!preFlow) { - call.logger.debug('[preMsgCallFlow]', 'Canceled') - return; - } - call = preFlow; - - // MsgHandler - this.options.logMsg && call.logger.log('[RecvMsg]', call.msg); - let promises = [ - // Conn Handlers - ...(call.conn['_msgHandlers']?.forEachHandler(call.service.name, call.logger, call) ?? []), - // Server Handlers - this._msgHandlers.forEachHandler(call.service.name, call.logger, call) - ]; - if (!promises.length) { - this.logger.debug('[UNHANDLED_MSG]', call.service.name); - } - else { - await Promise.all(promises); - } - - // Post Flow - await this.flows.postMsgCallFlow.exec(call, call.logger); - } - // #endregion - - // #region Api/Msg handler register - /** - * Associate a `ApiHandler` to a specific `apiName`. - * So that when `ApiCall` is receiving, it can be handled correctly. - * @param apiName - * @param handler - */ - implementApi>(apiName: Api, handler: ApiHandler): void { - if (this._apiHandlers[apiName as string]) { - throw new Error('Already exist handler for API: ' + apiName); - } - this._apiHandlers[apiName as string] = handler; - this.logger.log(`API implemented succ: [${apiName}]`); - }; - - /** 用于延迟注册 API */ - protected _delayImplementApiPath?: string; - - /** - * Auto call `imeplementApi` by traverse the `apiPath` and find all matched `PtlXXX` and `ApiXXX`. - * It is matched by checking whether the relative path and name of an API is consistent to the service name in `serviceProto`. - * Notice that the name prefix of protocol is `Ptl`, of API is `Api`. - * For example, `protocols/a/b/c/PtlTest` is matched to `api/a/b/c/ApiTest`. - * @param apiPath Absolute path or relative path to `process.cwd()`. - * @returns - */ - async autoImplementApi(apiPath: string, delay?: boolean): Promise<{ succ: string[], fail: string[] }> { - let apiServices = Object.values(this.serviceMap.apiName2Service) as ApiServiceDef[]; - let output: { succ: string[], fail: string[] } = { succ: [], fail: [] }; - - if (delay) { - this._delayImplementApiPath = apiPath; - return output; - } - - for (let svc of apiServices) { - //get api handler - let { handler } = await this.getApiHandler(svc, apiPath, this.logger) - - if (!handler) { - output.fail.push(svc.name); - continue; - } - - this.implementApi(svc.name, handler); - output.succ.push(svc.name); - } - - if (output.fail.length) { - this.logger.error(chalk.red(`${output.fail.length} API implemented failed: ` + output.fail.map(v => chalk.cyan.underline(v)).join(' '))) - } - - return output; - } - - async getApiHandler(svc: ApiServiceDef, apiPath?: string, logger?: Logger): Promise<{ handler: ApiHandler, errMsg?: undefined } | { handler?: undefined, errMsg: string }> { - if (this._apiHandlers[svc.name]) { - return { handler: this._apiHandlers[svc.name]! }; - } - - if (!apiPath) { - return { errMsg: `Api not implemented: ${svc.name}` }; - } - - // get api last name - let match = svc.name.match(/^(.+\/)*(.+)$/); - if (!match) { - logger?.error('Invalid apiName: ' + svc.name); - return { errMsg: `Invalid api name: ${svc.name}` }; - } - let handlerPath = match[1] || ''; - let handlerName = match[2]; - - // try import - let modulePath = path.resolve(apiPath, handlerPath, 'Api' + handlerName); - try { - var handlerModule = await import(modulePath); - } - catch (e: unknown) { - this.logger.error(chalk.red(`Implement API ${chalk.cyan.underline(`${svc.name}`)} failed:`), e); - return { errMsg: (e as Error).message }; - } - - // 优先 default,其次 ApiName 同名 - let handler = handlerModule.default ?? handlerModule['Api' + handlerName]; - if (handler) { - return { handler: handler }; - } - else { - return { errMsg: `Missing 'export Api${handlerName}' or 'export default' in: ${modulePath}` } - } - } - - /** - * Add a message handler, - * duplicate handlers to the same `msgName` would be ignored. - * @param msgName - * @param handler - */ - listenMsg>(msgName: Msg, handler: MsgHandler): MsgHandler { - this._msgHandlers.addHandler(msgName as string, handler); - return handler; - }; - /** - * Remove a message handler - */ - unlistenMsg>(msgName: Msg, handler: Function): void { - this._msgHandlers.removeHandler(msgName as string, handler); - }; - /** - * Remove all handlers from a message - */ - unlistenMsgAll>(msgName: Msg): void { - this._msgHandlers.removeAllHandlers(msgName as string); - }; - // #endregion - - /** - * Event when the server cannot parse input buffer to api/msg call. - * By default, it will return "Input Data Error" . - */ - async onInputDataError(errMsg: string, conn: BaseConnection, data: string | Uint8Array | object) { - if (this.options.debugBuf) { - if (typeof data === 'string') { - conn.logger.error(`[InputDataError] ${errMsg} length = ${data.length}`, data) - } - else if (data instanceof Uint8Array) { - conn.logger.error(`[InputBufferError] ${errMsg} length = ${data.length}`, data.subarray(0, 16)) - } - else { - conn.logger.error(`[InputJsonError] ${errMsg} `, data) - } - } - - const message = data instanceof Uint8Array ? `Invalid request buffer, please check the version of service proto.` : errMsg; - - // Short conn, send apiReturn with error - if (conn.type === 'SHORT') { - // Return API Error - let opEncode = ApiCall.encodeApiReturn(this.tsbuffer, { - type: 'api', - name: '?', - id: 0, - reqSchemaId: '?', - resSchemaId: '?' - }, { - isSucc: false, - err: new TsrpcError({ - message: message, - type: TsrpcErrorType.ServerError, - code: 'INPUT_DATA_ERR' - }) - }, conn.dataType) - if (opEncode.isSucc) { - let opSend = await conn.sendData(opEncode.output); - if (opSend.isSucc) { - return; - } - } - } - - conn.close(message); - } - - /** - * Event when a uncaught error (except `TsrpcError`) is throwed. - * By default, it will return a `TsrpcError` with message "Internal server error". - * If `returnInnerError` is `true`, the original error would be returned as `innerErr` property. - */ - onInternalServerError(err: { message: string, stack?: string, name?: string }, call: ApiCall) { - call.logger.error(err); - call.error('Internal Server Error', { - code: 'INTERNAL_ERR', - type: TsrpcErrorType.ServerError, - innerErr: call.conn.server.options.returnInnerError ? err.message : undefined - }); - } - - protected _gracefulStop?: { - rs: () => void - }; - /** - * Stop the server gracefully. - * Wait all API requests finished and then stop the server. - * @param maxWaitTime - The max time(ms) to wait before force stop the server. - * `undefined` and `0` means unlimited time. - */ - async gracefulStop(maxWaitTime?: number) { - if (this._status !== ServerStatus.Opened) { - throw new Error(`Cannot gracefulStop when server status is '${this._status}'.`); - } - - this.logger.log('[GracefulStop] Start graceful stop, waiting all ApiCall finished...') - this._status = ServerStatus.Closing; - let promiseWaitApi = new Promise(rs => { - this._gracefulStop = { - rs: rs - }; - }); - - return new Promise(rs => { - let maxWaitTimer: ReturnType | undefined; - if (maxWaitTime) { - maxWaitTimer = setTimeout(() => { - maxWaitTimer = undefined; - if (this._gracefulStop) { - this._gracefulStop = undefined; - this.logger.log('Graceful stop timeout, stop the server directly.'); - this.stop().then(() => { rs() }); - } - }, maxWaitTime); - } - - promiseWaitApi.then(() => { - this.logger.log('All ApiCall finished, continue stop server.'); - if (maxWaitTimer) { - clearTimeout(maxWaitTimer); - maxWaitTimer = undefined; - } - if (this._gracefulStop) { - this._gracefulStop = undefined; - this.stop().then(() => { rs() }); - } - }) - }) - } - - /** - * Execute API function through the inner connection, which is useful for unit test. - * - * **NOTICE** - * The `req` and return value is native JavaScript object which is not compatible to JSON. (etc. ArrayBuffer, Date, ObjectId) - * If you are using pure JSON as transfering, you may need use `callApiByJSON`. - * @param apiName - * @param req - * @param options - */ - callApi(apiName: T, req: ServiceType['api'][T]['req']): Promise> { - return new Promise(rs => { - // 确认是哪个Service - let service = this.serviceMap.apiName2Service[apiName as string]; - if (!service) { - let errMsg = `Cannot find service: ${apiName}`; - this.logger.warn(`[callApi]`, errMsg); - rs({ isSucc: false, err: new TsrpcError(errMsg, { type: TsrpcErrorType.ServerError, code: 'ERR_API_NAME' }) }); - return; - } - - let conn = new InnerConnection({ - dataType: 'json', - server: this, - id: '' + this._connIdCounter.getNext(), - ip: '', - return: { - type: 'raw', - rs: rs - } - }); - let call = new ApiCallInner({ - conn: conn, - req: req, - service: service - }); - this._handleApiCall(call); - }) - } - - /** - * Like `server.callApi`, but both input and output are pure JSON object, - * which can be `JSON.stringify()` and `JSON.parse()` directly. - * Types that not compatible to JSON, would be encoded and decoded automatically. - * @param apiName - The same with `server.callApi`, may be parsed from the URL. - * @param jsonReq - Request data in pure JSON - * @returns Encoded `ApiReturn` in pure JSON - */ - - /** - * Process JSON request by inner proxy, this is useful when you are porting to cloud function services. - * Both the input and output is pure JSON, ArrayBuffer/Date/ObjectId are encoded to string automatically. - * @param apiName - Parsed from URL - * @param req - Pure JSON - * @returns - Pure JSON - */ - async inputJSON(apiName: string, req: object): Promise> { - if (apiName.startsWith('/')) { - apiName = apiName.slice(1); - } - if (!this.serviceMap.apiName2Service[apiName]) { - return { - isSucc: false, - err: new TsrpcError(`Invalid service name: ${apiName}`, { - type: TsrpcErrorType.ServerError, - code: 'INPUT_DATA_ERR' - }) - }; - } - - return new Promise(rs => { - let conn = new InnerConnection({ - dataType: 'json', - server: this, - id: '' + this._connIdCounter.getNext(), - ip: '', - return: { - type: 'json', - rs: rs - } - }); - - this._onRecvData(conn, req, apiName); - }) - } - - /** - * Process input buffer by inner proxy, this is useful when you are porting to cloud function services. - * @param buf Input buffer (may be sent by TSRPC client) - * @returns Response buffer - */ - inputBuffer(buf: Uint8Array): Promise { - return new Promise(rs => { - let conn = new InnerConnection({ - dataType: 'buffer', - server: this, - id: '' + this._connIdCounter.getNext(), - ip: '', - return: { - type: 'buffer', - rs: rs - } - }); - - this._onRecvData(conn, buf); - }) - } - - protected _parseServerInput(tsbuffer: TSBuffer, serviceMap: ServiceMap, data: string | Uint8Array | object, serviceName?: string): { isSucc: true, result: ParsedServerInput } | { isSucc: false, errMsg: string } { - if (data instanceof Uint8Array) { - let opServerInputData = TransportDataUtil.tsbuffer.decode(data, 'ServerInputData'); - - if (!opServerInputData.isSucc) { - return opServerInputData; - } - let serverInput = opServerInputData.value as ServerInputData; - - // 确认是哪个Service - let service = serviceMap.id2Service[serverInput.serviceId]; - if (!service) { - return { isSucc: false, errMsg: `Cannot find service ID: ${serverInput.serviceId}` } - } - - // 解码Body - if (service.type === 'api') { - let opReq = tsbuffer.decode(serverInput.buffer, service.reqSchemaId); - return opReq.isSucc ? { - isSucc: true, - result: { - type: 'api', - service: service, - req: opReq.value, - sn: serverInput.sn - } - } : opReq - } - else { - let opMsg = tsbuffer.decode(serverInput.buffer, service.msgSchemaId); - return opMsg.isSucc ? { - isSucc: true, - result: { - type: 'msg', - service: service, - msg: opMsg.value - } - } : opMsg; - } - } - else { - let json: object; - if (typeof data === 'string') { - try { - json = JSON.parse(data); - } - catch (e: any) { - return { isSucc: false, errMsg: `Input is not a valid JSON string: ${e.message}` }; - } - } - else { - json = data; - } - - let body: any; - let sn: number | undefined; - - // Parse serviceName / body / sn - let service: ApiService | MsgService | undefined; - const oriServiceName = serviceName; - if (serviceName == undefined) { - if (!Array.isArray(json)) { - return { isSucc: false, errMsg: `Invalid request format: unresolved service name.` }; - } - serviceName = json[0] as string; - body = json[1]; - sn = json[2]; - } - else { - body = json; - } - - // Get Service - service = serviceMap.apiName2Service[serviceName] ?? serviceMap.msgName2Service[serviceName]; - if (!service) { - let errMsg = `Invalid service name: ${chalk.cyan.underline(serviceName)}`; - - // 可能是 JSON 模式下,jsonHostPath 未设置妥当的原因,此时给予友好提示 - if (oriServiceName) { - // TODO - } - - return { isSucc: false, errMsg: errMsg }; - } - - // Decode - if (service.type === 'api') { - let op = tsbuffer.decodeJSON(body, service.reqSchemaId); - if (!op.isSucc) { - return op; - } - return { - isSucc: true, - result: { - type: 'api', - service: service, - sn: sn, - req: op.value - } - }; - } - else { - let op = tsbuffer.decodeJSON(body, service.msgSchemaId); - if (!op.isSucc) { - return op; - } - return { - isSucc: true, - result: { - type: 'msg', - service: service, - msg: op.value - } - } - } - } - } -} - -export interface BaseServerOptions { - /** - * Whether to enable JSON compatible mode. - * When it is true, it can be compatible with typical HTTP JSON request (like RESTful API). - * - * @remarks - * The JSON request methods are: - * - * 1. Add `Content-type: application/json` to request header. - * 2. HTTP request is: `POST /{jsonUrlPath}/{apiName}`. - * 3. POST body is JSON string. - * 4. The response body is JSON string also. - * - * NOTICE: Buffer type are not supported due to JSON not support them. - * For security and efficient reason, we strongly recommend you use binary encoded transportation. - * - * @defaultValue `false` - */ - json: boolean, - /** @deprecated Use `json` instead. */ - jsonEnabled?: boolean, - - // TSBuffer相关 - /** - * Whether to strictly distinguish between `null` and `undefined` when encoding, decoding, and type checking. - * @defaultValue false - */ - strictNullChecks: boolean, - - /** - * Timeout for processing an `ApiCall`(ms) - * `0` and `undefined` means unlimited time - * @defaultValue 30000 - */ - apiTimeout: number | undefined, - - // LOG相关 - /** - * Logger for processing log - * @defaultValue `new TerminalColorLogger()` (print to console with color) - */ - logger: Logger; - /** - * The minimum log level of `logger` - * @defaultValue `debug` - */ - logLevel: LogLevel; - /** - * Whethere to print API request body into log (may increase log size) - * @defaultValue `true` - */ - logReqBody: boolean; - /** - * Whethere to print API response body into log (may increase log size) - * @defaultValue `true` - */ - logResBody: boolean; - /** - * Whethere to print `[SendMsg]` and `[RecvMsg]` log into log - * @defaultValue `true` - */ - logMsg: boolean; - - /** - * If `true`, all sent and received raw buffer would be print into the log. - * It may be useful when you do something for buffer encryption/decryption, and want to debug them. - */ - debugBuf?: boolean; - - /** - * When uncaught error throwed, - * whether to return the original error as a property `innerErr`. - * (May include some sensitive information, suggests set to `false` in production environment.) - * @defaultValue It depends on environment variable `NODE_ENV`. - * If `NODE_ENV` equals to `production`, the default value is `false`, otherwise is `true`. - */ - returnInnerError: boolean; -} - -export const defaultBaseServerOptions: BaseServerOptions = { - json: false, - strictNullChecks: false, - apiTimeout: 30000, - logger: new TerminalColorLogger, - logLevel: 'debug', - logReqBody: true, - logResBody: true, - logMsg: true, - returnInnerError: process.env['NODE_ENV'] !== 'production' -} - -export type ApiHandler = (call: Call) => void | Promise; -export type MsgHandler = (call: Call) => void | Promise; - -export enum ServerStatus { - Opening = 'OPENING', - Opened = 'OPENED', - Closing = 'CLOSING', - Closed = 'CLOSED', -} \ No newline at end of file diff --git a/src/server/base/MsgCall.ts b/src/server/base/MsgCall.ts deleted file mode 100644 index 6fdf97c..0000000 --- a/src/server/base/MsgCall.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { MsgService } from "tsrpc-base-client"; -import { BaseServiceType } from "tsrpc-proto"; -import { PrefixLogger } from "../models/PrefixLogger"; -import { BaseCall, BaseCallOptions } from "./BaseCall"; - -export interface MsgCallOptions extends BaseCallOptions { - service: MsgService, - msg: Msg -} - -/** - * A call request by `client.sendMsg()` - * @typeParam Msg - Type of the message - * @typeParam ServiceType - The same `ServiceType` to server, it is used for code auto hint. - */ -export abstract class MsgCall extends BaseCall { - readonly type = 'msg' as const; - - readonly service!: MsgService; - readonly msg: Msg; - - constructor(options: MsgCallOptions, logger?: PrefixLogger) { - super(options, logger ?? new PrefixLogger({ - logger: options.conn.logger, - prefixs: [`[Msg:${options.service.name}]`] - })); - - this.msg = options.msg; - } -} diff --git a/src/server/http/ApiCallHttp.ts b/src/server/http/ApiCallHttp.ts deleted file mode 100644 index 4922158..0000000 --- a/src/server/http/ApiCallHttp.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { ApiReturn, BaseServiceType, TsrpcErrorType } from 'tsrpc-proto'; -import { ApiCall, ApiCallOptions } from '../base/ApiCall'; -import { HttpConnection } from './HttpConnection'; - -export interface ApiCallHttpOptions extends ApiCallOptions { - conn: HttpConnection; -} -export class ApiCallHttp extends ApiCall { - - readonly conn!: HttpConnection; - - constructor(options: ApiCallHttpOptions) { - super(options); - } - - protected async _sendReturn(ret: ApiReturn): Promise<{ isSucc: true } | { isSucc: false, errMsg: string }> { - if (this.conn.dataType === 'text') { - if (ret.isSucc) { - this.conn.httpRes.statusCode = 200; - } - else { - this.conn.httpRes.statusCode = ret.err.type === TsrpcErrorType.ApiError ? 200 : 500; - } - } - return super._sendReturn(ret); - } - -} \ No newline at end of file diff --git a/src/server/http/HttpConnection.ts b/src/server/http/HttpConnection.ts deleted file mode 100644 index b349131..0000000 --- a/src/server/http/HttpConnection.ts +++ /dev/null @@ -1,90 +0,0 @@ -import * as http from "http"; -import { ParsedServerInput } from "tsrpc-base-client"; -import { BaseServiceType } from "tsrpc-proto"; -import { ApiCall } from "../base/ApiCall"; -import { BaseConnection, BaseConnectionOptions, ConnectionStatus } from '../base/BaseConnection'; -import { PrefixLogger } from "../models/PrefixLogger"; -import { ApiCallHttp } from "./ApiCallHttp"; -import { HttpServer } from './HttpServer'; -import { MsgCallHttp } from "./MsgCallHttp"; - -export interface HttpConnectionOptions extends BaseConnectionOptions { - server: HttpServer, - httpReq: http.IncomingMessage, - httpRes: http.ServerResponse, -} - -export class HttpConnection extends BaseConnection { - readonly type = 'SHORT'; - - protected readonly ApiCallClass = ApiCallHttp; - protected readonly MsgCallClass = MsgCallHttp; - - readonly httpReq: http.IncomingMessage; - readonly httpRes: http.ServerResponse; - readonly server!: HttpServer; - /** - * Whether the transportation of the connection is JSON encoded instead of binary encoded. - */ - readonly isJSON: boolean | undefined; - - /** - * In short connection, one connection correspond one call. - * It may be `undefined` when the request data is not fully received yet. - */ - call?: ApiCallHttp | MsgCallHttp; - - constructor(options: HttpConnectionOptions) { - super(options, new PrefixLogger({ - logger: options.server.logger, - prefixs: [`${options.ip} #${options.id}`] - })); - - this.httpReq = options.httpReq; - this.httpRes = options.httpRes; - } - - - public get status(): ConnectionStatus { - if (this.httpRes.socket?.writableFinished) { - return ConnectionStatus.Closed; - } - else if (this.httpRes.socket?.writableEnded) { - return ConnectionStatus.Closing; - } - else { - return ConnectionStatus.Opened; - } - } - - protected async doSendData(data: string | Uint8Array, call?: ApiCall): Promise<{ isSucc: true; } | { isSucc: false; errMsg: string; }> { - if (typeof data === 'string') { - this.httpRes.setHeader('Content-Type', 'application/json; charset=utf-8'); - } - this.httpRes.end(typeof data === 'string' ? data : Buffer.from(data.buffer, data.byteOffset, data.byteLength)); - return { isSucc: true } - } - - /** - * Close the connection, the reason would be attached to response header `X-TSRPC-Close-Reason`. - */ - close(reason?: string) { - if (this.status !== ConnectionStatus.Opened) { - return; - } - - // 有Reason代表是异常关闭 - if (reason) { - this.logger.warn(this.httpReq.method, this.httpReq.url, reason); - } - reason && this.httpRes.setHeader('X-TSRPC-Close-Reason', reason); - this.httpRes.end(); - } - - // HTTP Server 一个conn只有一个call,对应关联之 - makeCall(input: ParsedServerInput): ApiCallHttp | MsgCallHttp { - let call = super.makeCall(input) as ApiCallHttp | MsgCallHttp; - this.call = call; - return call; - } -} \ No newline at end of file diff --git a/src/server/http/HttpServer.ts b/src/server/http/HttpServer.ts deleted file mode 100644 index 683ace0..0000000 --- a/src/server/http/HttpServer.ts +++ /dev/null @@ -1,241 +0,0 @@ -import * as http from "http"; -import { BaseServiceType, ServiceProto } from 'tsrpc-proto'; -import { HttpUtil } from '../../models/HttpUtil'; -import { TSRPC_VERSION } from "../../models/version"; -import { BaseServer, BaseServerOptions, defaultBaseServerOptions, ServerStatus } from '../base/BaseServer'; -import { HttpConnection } from './HttpConnection'; - -/** - * TSRPC Server, based on HTTP connection. - * @typeParam ServiceType - `ServiceType` from generated `proto.ts` - */ -export class HttpServer extends BaseServer{ - readonly options!: HttpServerOptions; - - constructor(proto: ServiceProto, options?: Partial>) { - super(proto, { - ...defaultHttpServerOptions, - ...options - }); - - // 确保 jsonHostPath 以 / 开头和结尾 - this.options.jsonHostPath = this.options.jsonHostPath ? - (this.options.jsonHostPath.startsWith('/') ? '' : '/') + this.options.jsonHostPath + (this.options.jsonHostPath.endsWith('/') ? '' : '/') - : '/'; - } - - /** Native `http.Server` of NodeJS */ - httpServer?: http.Server; - /** - * {@inheritDoc BaseServer.start} - */ - start(): Promise { - if (this.httpServer) { - throw new Error('Server already started'); - } - - return new Promise(rs => { - this._status = ServerStatus.Opening; - this.logger.log(`Starting HTTP server ...`); - this.httpServer = http.createServer((httpReq, httpRes) => { - if (this.status !== ServerStatus.Opened) { - httpRes.statusCode = 503; - httpRes.end(); - return; - } - - let ip = HttpUtil.getClientIp(httpReq); - - httpRes.statusCode = 200; - httpRes.setHeader('X-Powered-By', `TSRPC ${TSRPC_VERSION}`); - if (this.options.cors) { - httpRes.setHeader('Access-Control-Allow-Origin', this.options.cors); - httpRes.setHeader('Access-Control-Allow-Headers', 'Content-Type,*'); - if (this.options.corsMaxAge) { - httpRes.setHeader('Access-Control-Max-Age', '' + this.options.corsMaxAge); - } - if (httpReq.method === 'OPTIONS') { - httpRes.writeHead(200); - httpRes.end(); - return; - } - }; - - let chunks: Buffer[] = []; - httpReq.on('data', data => { - chunks.push(data); - }); - - let conn: HttpConnection | undefined; - httpReq.on('end', async () => { - let isJSON = this.options.jsonEnabled && httpReq.headers["content-type"]?.toLowerCase().includes('application/json') - && httpReq.method === 'POST' && httpReq.url?.startsWith(this.options.jsonHostPath); - conn = new HttpConnection({ - server: this, - id: '' + this._connIdCounter.getNext(), - ip: ip, - httpReq: httpReq, - httpRes: httpRes, - dataType: isJSON ? 'text' : 'buffer' - }); - await this.flows.postConnectFlow.exec(conn, conn.logger); - - let buf = chunks.length === 1 ? chunks[0] : Buffer.concat(chunks); - - if (conn.dataType === 'text') { - let url = conn.httpReq.url!; - - let urlEndPos = url.indexOf('?'); - if (urlEndPos > -1) { - url = url.slice(0, urlEndPos); - } - - let serviceName = url.slice(this.options.jsonHostPath.length); - this._onRecvData(conn, buf.toString(), serviceName); - } - else { - this._onRecvData(conn, buf); - } - }); - - // 处理连接异常关闭的情况 - httpRes.on('close', async () => { - // 客户端Abort - if (httpReq.aborted) { - if (conn) { - if (conn.call) { - conn.call.logger.log('[ReqAborted]'); - } - else { - conn.logger.log('[ReqAborted]'); - } - } - else { - this.logger.log('[ReqAborted]', { - url: httpReq.url, - method: httpReq.method, - ip: ip, - chunksLength: chunks.length, - chunksSize: chunks.sum(v => v.byteLength), - reqComplete: httpReq.complete, - headers: httpReq.rawHeaders - }); - } - } - // 非Abort,异常中断:直到连接关闭,Client也未end(Conn未生成) - else if (!conn) { - this.logger.warn('Socket closed before request end', { - url: httpReq.url, - method: httpReq.method, - ip: ip, - chunksLength: chunks.length, - chunksSize: chunks.sum(v => v.byteLength), - reqComplete: httpReq.complete, - headers: httpReq.rawHeaders - }); - } - // 有Conn,但连接非正常end:直到连接关闭,也未调用过 httpRes.end 方法 - else if (!httpRes.writableEnded) { - (conn.call?.logger || conn.logger).warn('Socket closed without response') - } - - // Post Flow - if (conn) { - await this.flows.postDisconnectFlow.exec({ conn: conn }, conn.logger) - } - }); - }); - - if (this.options.socketTimeout) { - this.httpServer.timeout = this.options.socketTimeout; - } - if (this.options.keepAliveTimeout) { - this.httpServer.keepAliveTimeout = this.options.keepAliveTimeout; - } - - this.httpServer.listen(this.options.port, () => { - this._status = ServerStatus.Opened; - this.logger.log(`Server started at ${this.options.port}.`); - rs(); - }) - }); - } - - /** - * {@inheritDoc BaseServer.stop} - */ - async stop(): Promise { - if (!this.httpServer) { - return; - } - this.logger.log('Stopping server...'); - - return new Promise((rs) => { - this._status = ServerStatus.Closing; - - // 立即close,不再接受新请求 - // 等所有连接都断开后rs - this.httpServer?.close(err => { - this._status = ServerStatus.Closed; - this.httpServer = undefined; - - if (err) { - this.logger.error(err); - } - this.logger.log('Server stopped'); - rs(); - }); - }) - - } -} - -export interface HttpServerOptions extends BaseServerOptions { - /** Which port the HTTP server listen to */ - port: number, - /** - * Passed to the `timeout` property to the native `http.Server` of NodeJS, in milliseconds. - * `0` and `undefined` will disable the socket timeout behavior. - * NOTICE: this `socketTimeout` be `undefined` only means disabling of the socket timeout, the `apiTimeout` is still working. - * `socketTimeout` should always greater than `apiTimeout`. - * @defaultValue `undefined` - * @see {@link https://nodejs.org/dist/latest-v14.x/docs/api/http.html#http_server_timeout} - */ - socketTimeout?: number, - /** - * Passed to the `keepAliveTimeout` property to the native `http.Server` of NodeJS, in milliseconds. - * It means keep-alive timeout of HTTP socket connection. - * @defaultValue 5000 (from NodeJS) - * @see {@link https://nodejs.org/dist/latest-v14.x/docs/api/http.html#http_server_keepalivetimeout} - */ - keepAliveTimeout?: number, - /** - * Response header value of `Access-Control-Allow-Origin`. - * If this has any value, it would also set `Access-Control-Allow-Headers` as `*`. - * `undefined` means no CORS header. - * @defaultValue `*` - */ - cors?: string, - /** - * Response header value of `Access-Control-Allow-Origin`. - * @defaultValue `3600` - */ - corsMaxAge?: number, - - /** - * Actual URL path is `${jsonHostPath}/${apiName}`. - * For example, if `jsonHostPath` is `'/api'`, then you can send `POST /api/a/b/c/Test` to call API `a/b/c/Test`. - * @defaultValue `'/'` - */ - jsonHostPath: string -} - -export const defaultHttpServerOptions: HttpServerOptions = { - ...defaultBaseServerOptions, - port: 3000, - cors: '*', - corsMaxAge: 3600, - jsonHostPath: '/', - - // TODO: keep-alive time (to SLB) -} \ No newline at end of file diff --git a/src/server/http/MsgCallHttp.ts b/src/server/http/MsgCallHttp.ts deleted file mode 100644 index cb24166..0000000 --- a/src/server/http/MsgCallHttp.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { BaseServiceType } from "tsrpc-proto"; -import { MsgCall, MsgCallOptions } from "../base/MsgCall"; -import { HttpConnection } from "./HttpConnection"; - -export interface MsgCallHttpOptions extends MsgCallOptions { - conn: HttpConnection; -} -export class MsgCallHttp extends MsgCall { - - readonly conn!: HttpConnection; - - constructor(options: MsgCallHttpOptions) { - super(options); - } - -} \ No newline at end of file diff --git a/src/server/inner/ApiCallInner.ts b/src/server/inner/ApiCallInner.ts deleted file mode 100644 index fe7b2c3..0000000 --- a/src/server/inner/ApiCallInner.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { ApiReturn, BaseServiceType } from 'tsrpc-proto'; -import { ApiCall, ApiCallOptions } from '../base/ApiCall'; -import { InnerConnection } from './InnerConnection'; - -export interface ApiCallInnerOptions extends ApiCallOptions { - conn: InnerConnection; -} -export class ApiCallInner extends ApiCall { - - readonly conn!: InnerConnection; - - constructor(options: ApiCallInnerOptions) { - super(options); - } - - protected async _sendReturn(ret: ApiReturn): Promise<{ isSucc: true } | { isSucc: false, errMsg: string }> { - if (this.conn.return.type === 'raw') { - // Validate Res - if (ret.isSucc) { - let resValidate = this.server.tsbuffer.validate(ret.res, this.service.resSchemaId); - if (!resValidate.isSucc) { - return resValidate; - } - } - return this.conn.sendData(ret); - } - - return super._sendReturn(ret); - } - -} \ No newline at end of file diff --git a/src/server/inner/InnerConnection.ts b/src/server/inner/InnerConnection.ts deleted file mode 100644 index 3ddc96a..0000000 --- a/src/server/inner/InnerConnection.ts +++ /dev/null @@ -1,79 +0,0 @@ -import { ApiReturn, TsrpcError, TsrpcErrorType } from "tsrpc-proto"; -import { ApiCall, BaseConnection, BaseServiceType, PrefixLogger, TransportDataUtil } from "../.."; -import { BaseConnectionOptions, ConnectionStatus } from "../base/BaseConnection"; -import { ApiCallInner } from "./ApiCallInner"; - -export interface InnerConnectionOptions extends BaseConnectionOptions { - return: { - type: 'raw' | 'json', - rs: (ret: ApiReturn) => void; - } | { - type: 'buffer', - rs: (ret: Uint8Array) => void; - } -} - -/** - * Server can `callApi` it self by using this inner connection - */ -export class InnerConnection extends BaseConnection { - readonly type = 'SHORT'; - - protected readonly ApiCallClass = ApiCallInner; - protected readonly MsgCallClass = null as any; - - return!: InnerConnectionOptions['return']; - - constructor(options: InnerConnectionOptions) { - super(options, new PrefixLogger({ - logger: options.server.logger, - prefixs: [`Inner #${options.id}`] - })); - - this.return = options.return; - } - - private _status: ConnectionStatus = ConnectionStatus.Opened; - get status(): ConnectionStatus { - return this._status; - } - - close(reason?: string): void { - this.doSendData({ - isSucc: false, - err: new TsrpcError(reason ?? 'Internal Server Error', { - type: TsrpcErrorType.ServerError, - code: 'CONN_CLOSED', - reason: reason - }) - }); - } - - protected async doSendData(data: Uint8Array | ApiReturn, call?: ApiCall): Promise<{ isSucc: true; } | { isSucc: false; errMsg: string; }> { - this._status = ConnectionStatus.Closed; - - if (this.return.type === 'buffer') { - if (!(data instanceof Uint8Array)) { - // encode tsrpc error - if (!data.isSucc) { - let op = TransportDataUtil.tsbuffer.encode({ - error: data.err - }, 'ServerOutputData'); - if (op.isSucc) { - return this.doSendData(op.buf, call); - } - } - return { isSucc: false, errMsg: 'Error data type' }; - } - this.return.rs(data); - return { isSucc: true } - } - else { - if (data instanceof Uint8Array) { - return { isSucc: false, errMsg: 'Error data type' }; - } - this.return.rs(data); - return { isSucc: true } - } - } -} \ No newline at end of file diff --git a/src/server/models/PrefixLogger.ts b/src/server/models/PrefixLogger.ts deleted file mode 100644 index 8ede758..0000000 --- a/src/server/models/PrefixLogger.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { Logger } from 'tsrpc-proto'; - -export interface PrefixLoggerOptions { - logger: Logger - prefixs: (string | (() => string))[]; -} - -/** - * Auto add prefix using existed `Logger` - */ -export class PrefixLogger implements Logger { - - readonly logger: PrefixLoggerOptions['logger']; - readonly prefixs: PrefixLoggerOptions['prefixs']; - - constructor(options: PrefixLoggerOptions) { - this.logger = options.logger; - this.prefixs = options.prefixs; - } - - getPrefix(): string[] { - return this.prefixs.map(v => typeof v === 'string' ? v : v()); - } - - log(...args: any[]) { - this.logger.log(...this.getPrefix().concat(args)); - } - - debug(...args: any[]) { - this.logger.debug(...this.getPrefix().concat(args)); - } - - warn(...args: any[]) { - this.logger.warn(...this.getPrefix().concat(args)); - } - - error(...args: any[]) { - this.logger.error(...this.getPrefix().concat(args)); - } - -} \ No newline at end of file diff --git a/src/server/models/TerminalColorLogger.ts b/src/server/models/TerminalColorLogger.ts deleted file mode 100644 index 0665985..0000000 --- a/src/server/models/TerminalColorLogger.ts +++ /dev/null @@ -1,54 +0,0 @@ -import chalk from "chalk"; -import { Logger } from "tsrpc-proto"; - -export interface TerminalColorLoggerOptions { - /** - * Process ID prefix - * @defaultValue `process.pid` - */ - pid: string, - - /** - * `undefined` represents not print time - * @defaultValue 'yyyy-MM-dd hh:mm:ss' - */ - timeFormat?: string -} - -/** - * Print log to terminal, with color. - */ -export class TerminalColorLogger implements Logger { - - options: TerminalColorLoggerOptions = { - pid: process.pid.toString(), - timeFormat: 'yyyy-MM-dd hh:mm:ss' - } - - private _pid: string; - constructor(options?: Partial) { - Object.assign(this.options, options); - this._pid = this.options.pid ? `<${this.options.pid}> ` : ''; - } - - private _time(): string { - return this.options.timeFormat ? new Date().format(this.options.timeFormat) : ''; - } - - debug(...args: any[]) { - console.debug.call(console, chalk.gray(`${this._pid}${this._time()}`), chalk.cyan('[DEBUG]'), ...args); - } - - log(...args: any[]) { - console.log.call(console, chalk.gray(`${this._pid}${this._time()}`), chalk.green('[INFO]'), ...args); - } - - warn(...args: any[]) { - console.warn.call(console, chalk.gray(`${this._pid}${this._time()}`), chalk.yellow('[WARN]'), ...args); - } - - error(...args: any[]) { - console.error.call(console, chalk.gray(`${this._pid}${this._time()}`), chalk.red('[ERROR]'), ...args); - } - -} \ No newline at end of file diff --git a/src/server/ws/ApiCallWs.ts b/src/server/ws/ApiCallWs.ts deleted file mode 100644 index 8a1efb9..0000000 --- a/src/server/ws/ApiCallWs.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { ApiReturn, BaseServiceType } from 'tsrpc-proto'; -import { ApiCall, ApiCallOptions, SendReturnMethod } from '../base/ApiCall'; -import { ConnectionStatus } from '../base/BaseConnection'; -import { WsConnection } from './WsConnection'; - -export interface ApiCallWsOptions extends ApiCallOptions { - conn: WsConnection -} - -export class ApiCallWs extends ApiCall { - - readonly conn!: WsConnection; - - constructor(options: ApiCallWsOptions) { - super(options); - } - - protected async _prepareReturn(ret: ApiReturn): Promise { - if (this.conn.status !== ConnectionStatus.Opened) { - this.logger.error('[SendReturnErr]', 'WebSocket is not opened', ret); - this._return = ret; - return; - } - - return super._prepareReturn(ret); - } -} \ No newline at end of file diff --git a/src/server/ws/MsgCallWs.ts b/src/server/ws/MsgCallWs.ts deleted file mode 100644 index 58407fb..0000000 --- a/src/server/ws/MsgCallWs.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { BaseServiceType } from "tsrpc-proto"; -import { MsgCall, MsgCallOptions } from "../base/MsgCall"; -import { WsConnection } from "./WsConnection"; - -export interface MsgCallWsOptions extends MsgCallOptions { - conn: WsConnection; -} -export class MsgCallWs extends MsgCall { - - readonly conn!: WsConnection; - - constructor(options: MsgCallWsOptions) { - super(options); - } - -} \ No newline at end of file diff --git a/src/server/ws/WsConnection.ts b/src/server/ws/WsConnection.ts deleted file mode 100644 index 9695329..0000000 --- a/src/server/ws/WsConnection.ts +++ /dev/null @@ -1,141 +0,0 @@ -import * as http from "http"; -import { TransportDataUtil } from "tsrpc-base-client"; -import { BaseServiceType } from "tsrpc-proto"; -import * as WebSocket from "ws"; -import { BaseConnection, BaseConnectionOptions, ConnectionStatus } from "../base/BaseConnection"; -import { PrefixLogger } from "../models/PrefixLogger"; -import { ApiCallWs } from "./ApiCallWs"; -import { MsgCallWs } from "./MsgCallWs"; -import { WsServer } from "./WsServer"; - -export interface WsConnectionOptions extends BaseConnectionOptions { - server: WsServer, - ws: WebSocket, - httpReq: http.IncomingMessage, - onClose: (conn: WsConnection, code: number, reason: string) => Promise, - dataType: 'text' | 'buffer', - isDataTypeConfirmed?: boolean -} - -/** - * Connected client - */ -export class WsConnection extends BaseConnection { - readonly type = "LONG"; - - protected readonly ApiCallClass = ApiCallWs; - protected readonly MsgCallClass = MsgCallWs; - - readonly ws: WebSocket; - readonly httpReq: http.IncomingMessage; - readonly server!: WsServer; - dataType!: 'text' | 'buffer'; - // 是否已经收到了客户端的第一条消息,以确认了客户端的 dataType - isDataTypeConfirmed?: boolean; - - constructor(options: WsConnectionOptions) { - super(options, new PrefixLogger({ - logger: options.server.logger, - prefixs: [`${options.ip} Conn#${options.id}`] - })); - this.ws = options.ws; - this.httpReq = options.httpReq; - this.isDataTypeConfirmed = options.isDataTypeConfirmed; - - if (this.server.options.heartbeatWaitTime) { - const timeout = this.server.options.heartbeatWaitTime; - this._heartbeatInterval = setInterval(() => { - if (Date.now() - this._lastHeartbeatTime > timeout) { - this.ws.close(3001, 'Receive heartbeat timeout'); - } - }, timeout); - } - - // Init WS - this.ws.onclose = async e => { - if (this._heartbeatInterval) { - clearInterval(this._heartbeatInterval); - this._heartbeatInterval = undefined; - } - await options.onClose(this, e.code, e.reason); - this._rsClose?.(); - }; - this.ws.onerror = e => { this.logger.warn('[ClientErr]', e.error) }; - this.ws.onmessage = e => { - let data: Buffer | string; - if (e.data instanceof ArrayBuffer) { - data = Buffer.from(e.data); - } - else if (Array.isArray(e.data)) { - data = Buffer.concat(e.data) - } - else if (Buffer.isBuffer(e.data)) { - data = e.data; - } - else { - data = e.data; - } - - // 心跳包,直接回复 - if (data instanceof Buffer && data.equals(TransportDataUtil.HeartbeatPacket)) { - this.server.options.debugBuf && this.logger.log('[Heartbeat] Recv ping and send pong', TransportDataUtil.HeartbeatPacket); - this._lastHeartbeatTime = Date.now(); - this.ws.send(TransportDataUtil.HeartbeatPacket); - return; - } - - // dataType 尚未确认,自动检测 - if (!this.isDataTypeConfirmed) { - if (this.server.options.jsonEnabled && typeof data === 'string') { - this.dataType = 'text'; - } - else { - this.dataType = 'buffer'; - } - - this.isDataTypeConfirmed = true; - } - - // dataType 已确认 - this.server._onRecvData(this, data) - }; - } - - private _lastHeartbeatTime = 0; - private _heartbeatInterval?: ReturnType; - - get status(): ConnectionStatus { - if (this.ws.readyState === WebSocket.CLOSED) { - return ConnectionStatus.Closed; - } - if (this.ws.readyState === WebSocket.CLOSING) { - return ConnectionStatus.Closing; - } - return ConnectionStatus.Opened; - } - - protected async doSendData(data: string | Uint8Array, call?: ApiCallWs): Promise<{ isSucc: true; } | { isSucc: false; errMsg: string; }> { - let opSend = await new Promise<{ isSucc: true } | { isSucc: false, errMsg: string }>((rs) => { - this.ws.send(data, e => { - e ? rs({ isSucc: false, errMsg: e.message || 'Send buffer error' }) : rs({ isSucc: true }); - }) - }); - if (!opSend.isSucc) { - return opSend; - } - - return { isSucc: true } - } - - protected _rsClose?: () => void; - /** Close WebSocket connection */ - close(reason?: string): Promise { - // 已连接 Close之 - return new Promise(rs => { - this._rsClose = rs; - this.ws.close(1000, reason); - }).finally(() => { - this._rsClose = undefined - }) - } -} \ No newline at end of file diff --git a/src/server/ws/WsServer.ts b/src/server/ws/WsServer.ts deleted file mode 100644 index fd9b325..0000000 --- a/src/server/ws/WsServer.ts +++ /dev/null @@ -1,241 +0,0 @@ -import * as http from "http"; -import { EncodeOutput, TransportDataUtil } from "tsrpc-base-client"; -import { BaseServiceType, ServiceProto } from 'tsrpc-proto'; -import * as WebSocket from 'ws'; -import { Server as WebSocketServer } from 'ws'; -import { HttpUtil } from '../../models/HttpUtil'; -import { BaseServer, BaseServerOptions, defaultBaseServerOptions, ServerStatus } from '../base/BaseServer'; -import { WsConnection } from './WsConnection'; - -/** - * TSRPC Server, based on WebSocket connection. - * It can support realtime cases. - * @typeParam ServiceType - `ServiceType` from generated `proto.ts` - */ -export class WsServer extends BaseServer { - readonly options!: WsServerOptions; - - readonly connections: WsConnection[] = []; - private readonly _id2Conn: { [connId: string]: WsConnection | undefined } = {}; - - constructor(proto: ServiceProto, options?: Partial>) { - super(proto, { - ...defaultWsServerOptions, - ...options - }); - } - - private _wsServer?: WebSocketServer; - - /** - * {@inheritDoc BaseServer.start} - */ - start(): Promise { - if (this._wsServer) { - throw new Error('Server already started'); - } - this._status = ServerStatus.Opening; - return new Promise((rs, rj) => { - this.logger.log('Starting WebSocket server...'); - this._wsServer = new WebSocketServer({ - port: this.options.port - }, () => { - this.logger.log(`Server started at ${this.options.port}...`); - this._status = ServerStatus.Opened; - rs(); - }); - - this._wsServer.on('connection', this._onClientConnect); - this._wsServer.on('error', e => { - this.logger.error('[ServerError]', e); - rj(e); - }); - }) - } - - /** - * {@inheritDoc BaseServer.stop} - */ - async stop(): Promise { - // Closed Already - if (!this._wsServer) { - throw new Error('Server has not been started') - } - if (this._status === ServerStatus.Closed) { - throw new Error('Server is closed already'); - } - - this._status = ServerStatus.Closing; - - return new Promise(async (rs, rj) => { - await Promise.all(this.connections.map(v => v.close('Server Stop'))); - this._wsServer!.close(err => { err ? rj(err) : rs() }) - }).then(() => { - this.logger.log('Server stopped'); - this._status = ServerStatus.Closed; - this._wsServer = undefined; - }); - } - - private _onClientConnect = (ws: WebSocket, httpReq: http.IncomingMessage) => { - // 停止中 不再接受新的连接 - if (this._status !== ServerStatus.Opened) { - ws.close(1012); - return; - } - - // 推测 dataType 和 isDataTypeConfirmed - let isDataTypeConfirmed = true; - let dataType: 'text' | 'buffer'; - let protocols = httpReq.headers['sec-websocket-protocol']?.split(',').map(v => v.trim()).filter(v => !!v); - if (protocols?.includes('text')) { - dataType = 'text'; - } - else if (protocols?.includes('buffer')) { - dataType = 'buffer'; - } - else { - dataType = this.options.jsonEnabled ? 'text' : 'buffer'; - isDataTypeConfirmed = false; - } - - // Create Active Connection - let conn = new WsConnection({ - id: '' + this._connIdCounter.getNext(), - ip: HttpUtil.getClientIp(httpReq), - server: this, - ws: ws, - httpReq: httpReq, - onClose: this._onClientClose, - dataType: dataType, - isDataTypeConfirmed: isDataTypeConfirmed - }); - this.connections.push(conn); - this._id2Conn[conn.id] = conn; - - conn.logger.log('[Connected]', `ActiveConn=${this.connections.length}`); - this.flows.postConnectFlow.exec(conn, conn.logger); - }; - - private _onClientClose = async (conn: WsConnection, code: number, reason: string) => { - this.connections.removeOne(v => v.id === conn.id); - delete this._id2Conn[conn.id]; - conn.logger.log('[Disconnected]', `Code=${code} ${reason ? `Reason=${reason} ` : ''}ActiveConn=${this.connections.length}`) - - await this.flows.postDisconnectFlow.exec({ conn: conn, reason: reason }, conn.logger); - } - - /** - * Send the same message to many connections. - * No matter how many target connections are, the message would be only encoded once. - * @param msgName - * @param msg - Message body - * @param connIds - `id` of target connections, `undefined` means broadcast to every connections. - * @returns Send result, `isSucc: true` means the message buffer is sent to kernel, not represents the clients received. - */ - async broadcastMsg(msgName: T, msg: ServiceType['msg'][T], conns?: WsConnection[]): Promise<{ isSucc: true; } | { isSucc: false; errMsg: string; }> { - let connStr: string; - if (!conns) { - conns = this.connections; - connStr = '*'; - } - else { - connStr = conns ? conns.map(v => v.id).join(',') : '*'; - } - - if (!conns.length) { - return { isSucc: true }; - } - - if (this.status !== ServerStatus.Opened) { - this.logger.warn('[BroadcastMsgErr]', `[${msgName}]`, `[To:${connStr}]`, 'Server not open'); - return { isSucc: false, errMsg: 'Server not open' }; - } - - // GetService - let service = this.serviceMap.msgName2Service[msgName as string]; - if (!service) { - this.logger.warn('[BroadcastMsgErr]', `[${msgName}]`, `[To:${connStr}]`, 'Invalid msg name: ' + msgName); - return { isSucc: false, errMsg: 'Invalid msg name: ' + msgName }; - } - - // Encode group by dataType - let _opEncodeBuf: EncodeOutput | undefined; - let _opEncodeText: EncodeOutput | undefined; - const getOpEncodeBuf = () => { - if (!_opEncodeBuf) { - _opEncodeBuf = TransportDataUtil.encodeServerMsg(this.tsbuffer, service!, msg, 'buffer', 'LONG'); - } - return _opEncodeBuf; - } - const getOpEncodeText = () => { - if (!_opEncodeText) { - _opEncodeText = TransportDataUtil.encodeServerMsg(this.tsbuffer, service!, msg, 'text', 'LONG'); - } - return _opEncodeText; - } - - // 测试一下编码可以通过 - let op = conns.some(v => v.dataType === 'buffer') ? getOpEncodeBuf() : getOpEncodeText(); - if (!op.isSucc) { - this.logger.warn('[BroadcastMsgErr]', `[${msgName}]`, `[To:${connStr}]`, op.errMsg); - return op; - } - - this.options.logMsg && this.logger.log(`[BroadcastMsg]`, `[${msgName}]`, `[To:${connStr}]`, msg); - - // Batch send - let errMsgs: string[] = []; - return Promise.all(conns.map(async conn => { - // Pre Flow - let pre = await this.flows.preSendMsgFlow.exec({ conn: conn, service: service!, msg: msg }, this.logger); - if (!pre) { - conn.logger.debug('[preSendMsgFlow]', 'Canceled'); - return { isSucc: false, errMsg: 'Prevented by preSendMsgFlow' }; - } - msg = pre.msg; - - // Do send! - let opSend = await conn.sendData((conn.dataType === 'buffer' ? getOpEncodeBuf() : getOpEncodeText())!.output!); - if (!opSend.isSucc) { - return opSend; - } - - // Post Flow - this.flows.postSendMsgFlow.exec(pre, this.logger); - - return { isSucc: true }; - })).then(results => { - for (let i = 0; i < results.length; ++i) { - let op = results[i]; - if (!op.isSucc) { - errMsgs.push(`Conn#conns[i].id: ${op.errMsg}`) - }; - } - if (errMsgs.length) { - return { isSucc: false, errMsg: errMsgs.join('\n') } - } - else { - return { isSucc: true } - } - }) - }; -} - -export interface WsServerOptions extends BaseServerOptions { - /** Which port the WebSocket server is listen to */ - port: number; - - /** - * Close a connection if not receive heartbeat after the time (ms). - * This value should be greater than `client.heartbeat.interval`, for exmaple 2x of it. - * `undefined` or `0` represent disable this feature. - * @defaultValue `undefined` - */ - heartbeatWaitTime?: number; -}; - -const defaultWsServerOptions: WsServerOptions = { - ...defaultBaseServerOptions, - port: 3000 -} \ No newline at end of file diff --git a/src/shared/protocols/MsgChat.ts b/src/shared/protocols/MsgChat.ts new file mode 100644 index 0000000..c879648 --- /dev/null +++ b/src/shared/protocols/MsgChat.ts @@ -0,0 +1,7 @@ +// This is a demo code file +// Feel free to delete it + +export interface MsgChat { + content: string, + time: Date +} \ No newline at end of file diff --git a/src/shared/protocols/PtlSend.ts b/src/shared/protocols/PtlSend.ts new file mode 100644 index 0000000..6a5d9f6 --- /dev/null +++ b/src/shared/protocols/PtlSend.ts @@ -0,0 +1,10 @@ +// This is a demo code file +// Feel free to delete it + +export interface ReqSend { + content: string +} + +export interface ResSend { + time: Date +} \ No newline at end of file diff --git a/src/shared/protocols/base.ts b/src/shared/protocols/base.ts new file mode 100644 index 0000000..4626ca8 --- /dev/null +++ b/src/shared/protocols/base.ts @@ -0,0 +1,15 @@ +export interface BaseRequest { + +} + +export interface BaseResponse { + +} + +export interface BaseConf { + +} + +export interface BaseMessage { + +} \ No newline at end of file diff --git a/src/shared/protocols/serviceProto.ts b/src/shared/protocols/serviceProto.ts new file mode 100644 index 0000000..854cea5 --- /dev/null +++ b/src/shared/protocols/serviceProto.ts @@ -0,0 +1,78 @@ +import { ServiceProto } from 'tsrpc-proto'; +import { MsgChat } from './MsgChat'; +import { ReqSend, ResSend } from './PtlSend'; + +// This is a demo service proto file (auto generated) +// Feel free to delete it + +export interface ServiceType { + api: { + "Send": { + req: ReqSend, + res: ResSend + } + }, + msg: { + "Chat": MsgChat + } +} + +export const serviceProto: ServiceProto = { + "services": [ + { + "id": 0, + "name": "Chat", + "type": "msg" + }, + { + "id": 1, + "name": "Send", + "type": "api" + } + ], + "types": { + "MsgChat/MsgChat": { + "type": "Interface", + "properties": [ + { + "id": 0, + "name": "content", + "type": { + "type": "String" + } + }, + { + "id": 1, + "name": "time", + "type": { + "type": "Date" + } + } + ] + }, + "PtlSend/ReqSend": { + "type": "Interface", + "properties": [ + { + "id": 0, + "name": "content", + "type": { + "type": "String" + } + } + ] + }, + "PtlSend/ResSend": { + "type": "Interface", + "properties": [ + { + "id": 0, + "name": "time", + "type": { + "type": "Date" + } + } + ] + } + } +}; \ No newline at end of file diff --git a/test/Base.ts b/test/Base.ts deleted file mode 100644 index 00fd439..0000000 --- a/test/Base.ts +++ /dev/null @@ -1 +0,0 @@ -import 'k8w-extend-native'; \ No newline at end of file diff --git a/test/api/ApiObjId.ts b/test/api/ApiObjId.ts deleted file mode 100644 index e28f321..0000000 --- a/test/api/ApiObjId.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { ApiCall } from "../../src/server/base/ApiCall"; -import { ReqObjId, ResObjId } from "../proto/PtlObjId"; - -export async function ApiObjId(call: ApiCall) { - call.succ({ - id2: call.req.id1, - buf: call.req.buf, - date: call.req.date - }) -} \ No newline at end of file diff --git a/test/api/ApiSend.test.ts b/test/api/ApiSend.test.ts new file mode 100644 index 0000000..f5fc948 --- /dev/null +++ b/test/api/ApiSend.test.ts @@ -0,0 +1,40 @@ +import assert from 'assert'; +import { TsrpcError, WsClient } from 'tsrpc'; +import { serviceProto } from '../../src/shared/protocols/serviceProto'; + +// 1. EXECUTE `npm run dev` TO START A LOCAL DEV SERVER +// 2. EXECUTE `npm test` TO START UNIT TEST + +describe('ApiSend', function () { + let client = new WsClient(serviceProto, { + server: 'ws://127.0.0.1:3000', + json: true, + logger: console + }); + + before(async function () { + let res = await client.connect(); + assert.strictEqual(res.isSucc, true, 'Failed to connect to server, have you executed `npm run dev` already?'); + }) + + it('Success', async function () { + let ret = await client.callApi('Send', { + content: 'Test' + }); + assert.ok(ret.isSucc) + }); + + it('Check content is empty', async function () { + let ret = await client.callApi('Send', { + content: '' + }); + assert.deepStrictEqual(ret, { + isSucc: false, + err: new TsrpcError('Content is empty') + }); + }) + + after(async function () { + await client.disconnect(); + }) +}) \ No newline at end of file diff --git a/test/api/ApiTest.ts b/test/api/ApiTest.ts deleted file mode 100644 index 0070a92..0000000 --- a/test/api/ApiTest.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { TsrpcError } from "tsrpc-proto"; -import { ApiCall } from "../../src/server/base/ApiCall"; -import { ReqTest, ResTest } from "../proto/PtlTest"; - -export async function ApiTest(call: ApiCall) { - if (call.req.name === 'InnerError') { - await new Promise(rs => { setTimeout(rs, 50) }) - throw new Error('Test InnerError') - } - else if (call.req.name === 'TsrpcError') { - await new Promise(rs => { setTimeout(rs, 50) }) - throw new TsrpcError('Test TsrpcError', { - code: 'CODE_TEST', - info: 'ErrInfo Test' - }); - } - else if (call.req.name === 'error') { - await new Promise(rs => { setTimeout(rs, 50) }) - call.error('Got an error') - } - else { - await new Promise(rs => { setTimeout(rs, 50) }) - call.succ({ - reply: 'Test reply: ' + call.req.name - }) - } -} \ No newline at end of file diff --git a/test/api/a/b/c/ApiTest.ts b/test/api/a/b/c/ApiTest.ts deleted file mode 100644 index c254272..0000000 --- a/test/api/a/b/c/ApiTest.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { TsrpcError } from "tsrpc-proto"; - -export async function ApiTest(call: any) { - if (call.req.name === 'InnerError') { - throw new Error('a/b/c/Test InnerError') - } - else if (call.req.name === 'TsrpcError') { - throw new TsrpcError('a/b/c/Test TsrpcError', { - code: 'CODE_TEST', - info: 'ErrInfo a/b/c/Test' - }); - } - else if (call.req.name === 'error') { - call.error('Got an error') - } - else { - call.succ({ - reply: 'a/b/c/Test reply: ' + call.req.name - }) - } -} \ No newline at end of file diff --git a/test/cases/http.test.ts b/test/cases/http.test.ts deleted file mode 100644 index 22ebc67..0000000 --- a/test/cases/http.test.ts +++ /dev/null @@ -1,907 +0,0 @@ -import { ObjectId } from 'bson'; -import { assert } from 'chai'; -import chalk from 'chalk'; -import * as path from "path"; -import { ServiceProto, TsrpcError, TsrpcErrorType } from 'tsrpc-proto'; -import { ApiCall, BaseServer, HttpConnection, MsgCall, TerminalColorLogger } from '../../src'; -import { HttpClient } from '../../src/client/http/HttpClient'; -import { HttpServer } from '../../src/server/http/HttpServer'; -import { PrefixLogger } from '../../src/server/models/PrefixLogger'; -import { ApiTest as ApiAbcTest } from '../api/a/b/c/ApiTest'; -import { ApiTest } from '../api/ApiTest'; -import { MsgChat } from '../proto/MsgChat'; -import { ReqTest, ResTest } from '../proto/PtlTest'; -import { serviceProto, ServiceType } from '../proto/serviceProto'; - -const serverLogger = new PrefixLogger({ - prefixs: [chalk.bgGreen.white(' Server ')], - logger: new TerminalColorLogger({ pid: 'Server' }) -}); -const clientLogger = new PrefixLogger({ - prefixs: [chalk.bgBlue.white(' Client ')], - logger: new TerminalColorLogger({ pid: 'Client' }) -}) - -const getProto = () => Object.merge({}, serviceProto) as ServiceProto; - -async function testApi(server: HttpServer, client: HttpClient) { - // Succ - assert.deepStrictEqual(await client.callApi('Test', { - name: 'Req1' - }), { - isSucc: true, - res: { - reply: 'Test reply: Req1' - } - }); - assert.deepStrictEqual(await client.callApi('a/b/c/Test', { - name: 'Req2' - }), { - isSucc: true, - res: { - reply: 'a/b/c/Test reply: Req2' - } - }); - - // Inner error - for (let v of ['Test', 'a/b/c/Test']) { - let ret = await client.callApi(v as any, { - name: 'InnerError' - }); - delete ret.err!.innerErr.stack; - - assert.deepStrictEqual(ret, { - isSucc: false, - err: new TsrpcError('Internal Server Error', { - code: 'INTERNAL_ERR', - type: TsrpcErrorType.ServerError, - innerErr: `${v} InnerError` - }) - }); - } - - // TsrpcError - for (let v of ['Test', 'a/b/c/Test']) { - let ret = await client.callApi(v as any, { - name: 'TsrpcError' - }); - assert.deepStrictEqual(ret, { - isSucc: false, - err: new TsrpcError(`${v} TsrpcError`, { - code: 'CODE_TEST', - type: TsrpcErrorType.ApiError, - info: 'ErrInfo ' + v - }) - }); - } - - // call.error - for (let v of ['Test', 'a/b/c/Test']) { - let ret = await client.callApi(v as any, { - name: 'error' - }); - assert.deepStrictEqual(ret, { - isSucc: false, - err: new TsrpcError('Got an error', { - type: TsrpcErrorType.ApiError - }) - }); - } -} - -describe('HTTP Server & Client basic', function () { - it('implement API manually', async function () { - let server = new HttpServer(getProto(), { - logger: serverLogger, - debugBuf: true - }); - await server.start(); - - server.implementApi('Test', ApiTest); - server.implementApi('a/b/c/Test', ApiAbcTest); - - let client = new HttpClient(getProto(), { - logger: clientLogger, - debugBuf: true - }) - - await testApi(server, client); - - await server.stop(); - }) - - it('extend call in handler', function () { - let server = new HttpServer(getProto(), { - logger: serverLogger, - debugBuf: true - }); - - type MyApiCall = ApiCall & { - value1?: string; - value2: string; - } - type MyMsgCall = MsgCall & { - value1?: string; - value2: string; - } - - server.implementApi('Test', (call: MyApiCall) => { - call.value1 = 'xxx'; - call.value2 = 'xxx'; - }); - server.listenMsg('Chat', (call: MyMsgCall) => { - call.msg.content; - call.value1 = 'xxx'; - call.value2 = 'xxx'; - }) - }) - - it('extend call in flow', function () { - let server = new HttpServer(getProto(), { - logger: serverLogger, - debugBuf: true - }); - - type MyApiCall = ApiCall & { - value1?: string; - value2: string; - } - type MyMsgCall = MsgCall & { - value1?: string; - value2: string; - } - type MyConn = HttpConnection & { - currentUser: { - uid: string, - nickName: string - } - } - - server.flows.postConnectFlow.push((conn: MyConn) => { - conn.currentUser.nickName = 'asdf'; - return conn; - }); - server.flows.postConnectFlow.exec(null as any as MyConn, console); - server.flows.preApiCallFlow.push((call: MyApiCall) => { - call.value2 = 'x'; - return call; - }); - server.flows.preSendMsgFlow.push((call: MyMsgCall) => { - call.value2 = 'f'; - return call; - }) - }) - - it('autoImplementApi', async function () { - let server = new HttpServer(getProto(), { - logger: serverLogger, - apiTimeout: 5000 - }); - await server.start(); - - server.autoImplementApi(path.resolve(__dirname, '../api')) - - let client = new HttpClient(getProto(), { - logger: clientLogger - }) - - await testApi(server, client); - - await server.stop(); - }); - - it('sendMsg', async function () { - let server = new HttpServer(getProto(), { - port: 3001, - logger: serverLogger, - // debugBuf: true - }); - - await server.start(); - - let client = new HttpClient(getProto(), { - server: 'http://127.0.0.1:3001', - logger: clientLogger, - // debugBuf: true - }); - - return new Promise(rs => { - let msg: MsgChat = { - channel: 123, - userName: 'fff', - content: '666', - time: Date.now() - }; - - server.listenMsg('Chat', async v => { - assert.deepStrictEqual(v.msg, msg); - await server.stop(); - rs(); - }); - - client.sendMsg('Chat', msg); - }) - }) - - it('abort', async function () { - let server = new HttpServer(getProto(), { - logger: serverLogger - }); - await server.start(); - - server.autoImplementApi(path.resolve(__dirname, '../api')) - - let client = new HttpClient(getProto(), { - logger: clientLogger - }) - - let result: any | undefined; - let promise = client.callApi('Test', { name: 'aaaaaaaa' }); - let sn = client.lastSN; - setTimeout(() => { - client.abort(sn) - }, 10); - promise.then(v => { - result = v; - }); - - await new Promise(rs => { - setTimeout(() => { - assert.strictEqual(result, undefined); - rs(); - }, 150) - }) - - await server.stop(); - }); - - it('abortByKey', async function () { - let server = new HttpServer(getProto(), { - logger: serverLogger - }); - await server.start(); - - server.autoImplementApi(path.resolve(__dirname, '../api')) - - let client = new HttpClient(getProto(), { - logger: clientLogger - }) - - let result: any | undefined; - let result1: any | undefined; - - client.callApi('Test', { name: 'aaaaaaaa' }, { abortKey: 'XXX' }).then(v => { result = v; }); - client.callApi('Test', { name: 'aaaaaaaa' }, { abortKey: 'XXX' }).then(v => { result = v; }); - client.callApi('Test', { name: 'aaaaaaaa' }, { abortKey: 'XXX' }).then(v => { result = v; }); - client.callApi('Test', { name: 'aaaaaaaa' }, { abortKey: 'XXX' }).then(v => { result = v; }); - client.callApi('Test', { name: 'aaaaaaaa' }, { abortKey: 'XXX' }).then(v => { result = v; }); - - client.callApi('Test', { name: 'bbbbbb' }).then(v => { result1 = v; }); - - setTimeout(() => { - client.abortByKey('XXX') - }, 10); - - await new Promise(rs => { - setTimeout(() => { - assert.strictEqual(result, undefined); - assert.deepStrictEqual(result1, { - isSucc: true, - res: { - reply: 'Test reply: bbbbbb' - } - }) - rs(); - }, 150) - }) - - await server.stop(); - }) - - it('abortAll', async function () { - let server = new HttpServer(getProto(), { - logger: serverLogger - }); - await server.start(); - - server.autoImplementApi(path.resolve(__dirname, '../api')) - - let client = new HttpClient(getProto(), { - logger: clientLogger - }) - - let result: any | undefined; - let result1: any | undefined; - - client.callApi('Test', { name: 'aaaaaaaa' }, { abortKey: 'XXX' }).then(v => { result = v; }); - client.callApi('Test', { name: 'aaaaaaaa' }, { abortKey: 'XXX' }).then(v => { result = v; }); - client.callApi('Test', { name: 'aaaaaaaa' }, { abortKey: 'XXX' }).then(v => { result = v; }); - client.callApi('Test', { name: 'aaaaaaaa' }, { abortKey: 'XXX' }).then(v => { result = v; }); - client.callApi('Test', { name: 'aaaaaaaa' }, { abortKey: 'XXX' }).then(v => { result = v; }); - - client.callApi('Test', { name: 'bbbbbb' }).then(v => { result1 = v; }); - - setTimeout(() => { - client.abortAll() - }, 10); - - await new Promise(rs => { - setTimeout(() => { - assert.strictEqual(result, undefined); - assert.strictEqual(result1, undefined); - rs(); - }, 150) - }) - - await server.stop(); - }) - - it('pendingApis', async function () { - let server = new HttpServer(getProto(), { - logger: serverLogger - }); - await server.start(); - - server.autoImplementApi(path.resolve(__dirname, '../api')) - - let client = new HttpClient(getProto(), { - logger: clientLogger - }) - - for (let i = 0; i < 10; ++i) { - let promise = Promise.all(Array.from({ length: 10 }, () => new Promise(rs => { - let name = ['Req', 'InnerError', 'TsrpcError', 'error'][Math.random() * 4 | 0]; - let ret: any | undefined; - let promise = client.callApi('Test', { name: name }); - let sn = client.lastSN; - let abort = Math.random() > 0.5; - if (abort) { - setTimeout(() => { - client.abort(sn) - }, 0); - } - promise.then(v => { - ret = v; - }); - - setTimeout(() => { - client.logger?.log('sn', sn, name, abort, ret) - if (abort) { - assert.strictEqual(ret, undefined); - } - else { - assert.notEqual(ret, undefined); - if (name === 'Req') { - assert.strictEqual(ret.isSucc, true); - } - else { - assert.strictEqual(ret.isSucc, false) - } - } - rs(); - }, 300) - }))); - assert.strictEqual(client['_pendingApis'].length, 10); - await promise; - assert.strictEqual(client['_pendingApis'].length, 0); - } - - await server.stop(); - }) - - it('error', async function () { - let server = new HttpServer(getProto(), { - logger: serverLogger - }); - await server.start(); - - let client1 = new HttpClient(getProto(), { - server: 'http://localhost:80', - logger: clientLogger - }) - - let ret = await client1.callApi('Test', { name: 'xx' }); - console.log(ret); - assert.strictEqual(ret.isSucc, false); - assert.strictEqual(ret.err?.code, 'ECONNREFUSED'); - assert.strictEqual(ret.err?.type, TsrpcErrorType.NetworkError); - - await server.stop(); - }) - - it('server timeout', async function () { - let server = new HttpServer(getProto(), { - logger: serverLogger, - apiTimeout: 100 - }); - server.implementApi('Test', call => { - return new Promise(rs => { - setTimeout(() => { - call.req && call.succ({ - reply: 'Hi, ' + call.req.name - }); - rs(); - }, 200) - }) - }) - await server.start(); - - let client = new HttpClient(getProto(), { - logger: clientLogger - }); - let ret = await client.callApi('Test', { name: 'Jack' }); - assert.deepStrictEqual(ret, { - isSucc: false, - err: new TsrpcError('Server Timeout', { - code: 'SERVER_TIMEOUT', - type: TsrpcErrorType.ServerError - }) - }); - - await server.stop(); - }); - - it('client timeout', async function () { - let server1 = new HttpServer(getProto(), { - logger: serverLogger - }); - server1.implementApi('Test', call => { - return new Promise(rs => { - setTimeout(() => { - call.succ({ - reply: 'Hello, ' + call.req.name - }); - rs(); - }, 2000) - }) - }) - await server1.start(); - - let client = new HttpClient(getProto(), { - timeout: 100, - logger: clientLogger - }); - - let ret = await client.callApi('Test', { name: 'Jack123' }); - // SERVER TIMEOUT的call还没执行完,但是call却被放入Pool了,导致这个BUG - assert.deepStrictEqual(ret, { - isSucc: false, - err: new TsrpcError({ - message: 'Request Timeout', - code: 'TIMEOUT', - type: TsrpcErrorType.NetworkError - }) - }); - await server1.stop(); - }); - - it('Graceful stop', async function () { - let server = new HttpServer(getProto(), { - logger: serverLogger - }); - - let reqNum = 0; - server.implementApi('Test', async call => { - if (++reqNum === 10) { - server.gracefulStop(); - } - await new Promise(rs => setTimeout(rs, parseInt(call.req.name))); - call.succ({ reply: 'OK' }); - }); - - await server.start(); - let isStopped = false; - - let client = new HttpClient(getProto(), { - logger: clientLogger - }) - - let succNum = 0; - await Promise.all(Array.from({ length: 10 }, (v, i) => client.callApi('Test', { name: '' + (i * 100) }).then(v => { - if (v.res?.reply === 'OK') { - ++succNum; - } - }))) - assert.strictEqual(succNum, 10); - }) -}) - -describe('HTTP Flows', function () { - it('Server conn flow', async function () { - let server = new HttpServer(getProto(), { - logger: serverLogger - }); - - const flowExecResult: { [K in (keyof BaseServer['flows'])]?: boolean } = {}; - - server.implementApi('Test', async call => { - assert.strictEqual((call.conn as any).xxxx, 'asdfasdf') - assert.strictEqual(flowExecResult.postConnectFlow, true); - assert.strictEqual(flowExecResult.postDisconnectFlow, undefined); - call.succ({ reply: 'ok' }); - assert.strictEqual(flowExecResult.postDisconnectFlow, undefined); - }); - - server.flows.postConnectFlow.push(v => { - flowExecResult.postConnectFlow = true; - (v as any).xxxx = 'asdfasdf'; - return v; - }); - server.flows.postDisconnectFlow.push(v => { - flowExecResult.postDisconnectFlow = true; - return v; - }) - - await server.start(); - - assert.strictEqual(flowExecResult.postConnectFlow, undefined); - assert.strictEqual(flowExecResult.postDisconnectFlow, undefined); - - let client = new HttpClient(getProto(), { - logger: clientLogger - }); - await client.callApi('Test', { name: 'xxx' }); - assert.strictEqual(flowExecResult.postConnectFlow, true); - assert.strictEqual(flowExecResult.postDisconnectFlow, true); - - await server.stop(); - }) - - it('Buffer enc/dec flow', async function () { - let server = new HttpServer(getProto(), { - logger: serverLogger - }); - - const flowExecResult: { [K in (keyof BaseServer['flows'])]?: boolean } = {}; - - server.implementApi('Test', async call => { - call.succ({ reply: 'Enc&Dec' }); - }); - - server.flows.preRecvBufferFlow.push(v => { - flowExecResult.preRecvBufferFlow = true; - for (let i = 0; i < v.buf.length; ++i) { - v.buf[i] ^= 128; - } - return v; - }); - server.flows.preSendBufferFlow.push(v => { - flowExecResult.preSendBufferFlow = true; - for (let i = 0; i < v.buf.length; ++i) { - v.buf[i] ^= 128; - } - return v; - }) - - await server.start(); - - let client = new HttpClient(getProto(), { - logger: clientLogger - }); - - client.flows.preSendBufferFlow.push(v => { - for (let i = 0; i < v.buf.length; ++i) { - v.buf[i] ^= 128; - } - return v; - }); - - client.flows.preRecvBufferFlow.push(v => { - for (let i = 0; i < v.buf.length; ++i) { - v.buf[i] ^= 128; - } - return v; - }); - - let ret = await client.callApi('Test', { name: 'xxx' }); - assert.strictEqual(flowExecResult.preRecvBufferFlow, true); - assert.strictEqual(flowExecResult.preSendBufferFlow, true); - assert.deepStrictEqual(ret, { - isSucc: true, - res: { - reply: 'Enc&Dec' - } - }) - - await server.stop(); - }); - - it('ApiCall flow', async function () { - let server = new HttpServer(getProto(), { - logger: serverLogger - }); - - const flowExecResult: { [K in (keyof BaseServer['flows'])]?: boolean } = {}; - - server.implementApi('Test', async call => { - call.succ({ reply: 'asdgasdgasdgasdg' }); - }); - - server.flows.preApiCallFlow.push(call => { - assert.strictEqual(call.req.name, 'Changed') - call.error('You need login'); - return call; - }); - server.flows.postApiCallFlow.push(v => { - flowExecResult.postApiCallFlow = true; - return v; - }) - - await server.start(); - - let client = new HttpClient(getProto(), { - logger: clientLogger - }); - - client.flows.preCallApiFlow.push(v => { - if (v.apiName !== 'ObjId') { - v.req.name = 'Changed' - } - return v; - }); - - let ret = await client.callApi('Test', { name: 'xxx' }); - assert.strictEqual(flowExecResult.postApiCallFlow, true); - assert.deepStrictEqual(ret, { - isSucc: false, - err: new TsrpcError('You need login') - }) - - await server.stop(); - }); - - it('ApiCall flow break', async function () { - let server = new HttpServer(getProto(), { - logger: serverLogger - }); - - const flowExecResult: { [K in (keyof BaseServer['flows'])]?: boolean } = {}; - - server.implementApi('Test', async call => { - call.succ({ reply: 'asdgasdgasdgasdg' }); - }); - - server.flows.preApiCallFlow.push(call => { - assert.strictEqual(call.req.name, 'Changed') - call.error('You need login'); - return undefined; - }); - server.flows.postApiCallFlow.push(v => { - flowExecResult.postApiCallFlow = true; - return v; - }) - - await server.start(); - - let client = new HttpClient(getProto(), { - logger: clientLogger - }); - - client.flows.preCallApiFlow.push(v => { - if (v.apiName !== 'ObjId') { - v.req.name = 'Changed' - } - return v; - }); - - let ret = await client.callApi('Test', { name: 'xxx' }); - assert.strictEqual(flowExecResult.postApiCallFlow, undefined); - assert.deepStrictEqual(ret, { - isSucc: false, - err: new TsrpcError('You need login') - }) - - await server.stop(); - }); - - it('ApiCall flow error', async function () { - let server = new HttpServer(getProto(), { - logger: serverLogger - }); - - const flowExecResult: { [K in (keyof BaseServer['flows'])]?: boolean } = {}; - - server.implementApi('Test', async call => { - call.succ({ reply: 'asdgasdgasdgasdg' }); - }); - - server.flows.preApiCallFlow.push(call => { - assert.strictEqual(call.req.name, 'Changed') - throw new Error('ASDFASDF') - }); - server.flows.postApiCallFlow.push(v => { - flowExecResult.postApiCallFlow = true; - return v; - }) - - await server.start(); - - let client = new HttpClient(getProto(), { - logger: clientLogger - }); - - client.flows.preCallApiFlow.push(v => { - if (v.apiName !== 'ObjId') { - v.req.name = 'Changed' - } - return v; - }); - - let ret = await client.callApi('Test', { name: 'xxx' }); - assert.strictEqual(flowExecResult.postApiCallFlow, undefined); - assert.deepStrictEqual(ret, { - isSucc: false, - err: new TsrpcError('Internal Server Error', { - type: TsrpcErrorType.ServerError, - innerErr: 'ASDFASDF', - code: 'INTERNAL_ERR' - }) - }) - - await server.stop(); - }); - - it('server ApiReturn flow', async function () { - let server = new HttpServer(getProto(), { - logger: serverLogger - }); - - const flowExecResult: { [K in (keyof BaseServer['flows'])]?: boolean } = {}; - - server.implementApi('Test', async call => { - call.succ({ reply: 'xxxxxxxxxxxxxxxxxxxx' }); - }); - - server.flows.preApiReturnFlow.push(v => { - flowExecResult.preApiReturnFlow = true; - v.return = { - isSucc: false, - err: new TsrpcError('Ret changed') - } - return v; - }); - server.flows.postApiReturnFlow.push(v => { - flowExecResult.postApiReturnFlow = true; - v.call.logger.log('RETTT', v.return); - return v; - }) - - await server.start(); - - let client = new HttpClient(getProto(), { - logger: clientLogger - }); - - - let ret = await client.callApi('Test', { name: 'xxx' }); - assert.strictEqual(flowExecResult.preApiReturnFlow, true); - assert.strictEqual(flowExecResult.postApiReturnFlow, true); - assert.deepStrictEqual(ret, { - isSucc: false, - err: new TsrpcError('Ret changed') - }) - - await server.stop(); - }); - - it('client ApiReturn flow', async function () { - let server = new HttpServer(getProto(), { - logger: serverLogger - }); - - const flowExecResult: { [K in (keyof HttpClient['flows'])]?: boolean } = {}; - - server.implementApi('Test', async call => { - call.succ({ reply: 'xxxxxxxxxxxxxxxxxxxx' }); - }); - - await server.start(); - - let client = new HttpClient(getProto(), { - logger: clientLogger - }); - - client.flows.preApiReturnFlow.push(v => { - flowExecResult.preApiReturnFlow = true; - v.return = { - isSucc: false, - err: new TsrpcError('Ret changed') - } - return v; - }); - client.flows.postApiReturnFlow.push(v => { - flowExecResult.postApiReturnFlow = true; - client.logger?.log('RETTT', v.return); - return v; - }) - - let ret = await client.callApi('Test', { name: 'xxx' }); - assert.strictEqual(flowExecResult.preApiReturnFlow, true); - assert.strictEqual(flowExecResult.postApiReturnFlow, true); - assert.deepStrictEqual(ret, { - isSucc: false, - err: new TsrpcError('Ret changed') - }) - - await server.stop(); - }); - - it('client SendBufferFlow prevent', async function () { - let server = new HttpServer(getProto(), { - logger: serverLogger - }); - - // const flowExecResult: { [K in (keyof BaseClient['flows'])]?: boolean } = {}; - - server.implementApi('Test', async call => { - call.succ({ reply: 'xxxxxxxxxxxxxxxxxxxx' }); - }); - - await server.start(); - - let client = new HttpClient(getProto(), { - logger: clientLogger - }); - - client.flows.preSendBufferFlow.push(v => { - return undefined - }); - - let ret: any; - client.callApi('Test', { name: 'xxx' }).then(v => { ret = v }); - await new Promise(rs => { setTimeout(rs, 200) }); - assert.strictEqual(ret, undefined) - - await server.stop(); - }); - - it('onInputBufferError', async function () { - let server = new HttpServer(getProto(), { - logger: serverLogger - }); - await server.start(); - - let client = new HttpClient(getProto(), { - logger: clientLogger - }); - client.flows.preSendBufferFlow.push(v => { - for (let i = 0; i < v.buf.length; ++i) { - v.buf[i] += 1; - } - return v; - }); - - let ret = await client.callApi('Test', { name: 'XXX' }); - assert.deepStrictEqual(ret, { - isSucc: false, - err: new TsrpcError('Invalid request buffer, please check the version of service proto.', { - type: TsrpcErrorType.ServerError, - code: 'INPUT_DATA_ERR' - }) - }) - - await server.stop(); - }) - - it('ObjectId', async function () { - let server = new HttpServer(getProto(), { - logger: serverLogger - }); - server.autoImplementApi(path.resolve(__dirname, '../api')) - await server.start(); - - let client = new HttpClient(getProto(), { - logger: clientLogger - }); - - // ObjectId - let objId1 = new ObjectId(); - let ret = await client.callApi('ObjId', { - id1: objId1 - }); - assert.strictEqual(ret.isSucc, true, ret.err?.message); - assert.strictEqual(objId1.toString(), ret.res!.id2.toString()); - - await server.stop(); - }) -}) \ No newline at end of file diff --git a/test/cases/httpJSON.test.ts b/test/cases/httpJSON.test.ts deleted file mode 100644 index ab4525b..0000000 --- a/test/cases/httpJSON.test.ts +++ /dev/null @@ -1,997 +0,0 @@ -import { ObjectId } from 'bson'; -import { assert } from 'chai'; -import chalk from 'chalk'; -import * as path from "path"; -import { ServiceProto, TsrpcError, TsrpcErrorType } from 'tsrpc-proto'; -import { ApiCall, BaseServer, HttpConnection, MsgCall, TerminalColorLogger } from '../../src'; -import { HttpClient } from '../../src/client/http/HttpClient'; -import { HttpProxy } from '../../src/client/http/HttpProxy'; -import { HttpServer } from '../../src/server/http/HttpServer'; -import { PrefixLogger } from '../../src/server/models/PrefixLogger'; -import { ApiTest as ApiAbcTest } from '../api/a/b/c/ApiTest'; -import { ApiTest } from '../api/ApiTest'; -import { MsgChat } from '../proto/MsgChat'; -import { ReqTest, ResTest } from '../proto/PtlTest'; -import { serviceProto, ServiceType } from '../proto/serviceProto'; - -const serverLogger = new PrefixLogger({ - prefixs: [chalk.bgGreen.white(' Server ')], - logger: new TerminalColorLogger({ pid: 'Server' }) -}); -const clientLogger = new PrefixLogger({ - prefixs: [chalk.bgBlue.white(' Client ')], - logger: new TerminalColorLogger({ pid: 'Client' }) -}) - -const getProto = () => Object.merge({}, serviceProto) as ServiceProto; - -async function testApi(server: HttpServer, client: HttpClient) { - // Succ - assert.deepStrictEqual(await client.callApi('Test', { - name: 'Req1' - }), { - isSucc: true, - res: { - reply: 'Test reply: Req1' - } - }); - assert.deepStrictEqual(await client.callApi('a/b/c/Test', { - name: 'Req2' - }), { - isSucc: true, - res: { - reply: 'a/b/c/Test reply: Req2' - } - }); - - // Inner error - for (let v of ['Test', 'a/b/c/Test']) { - let ret = await client.callApi(v as any, { - name: 'InnerError' - }); - delete ret.err!.innerErr.stack; - - assert.deepStrictEqual(ret, { - isSucc: false, - err: new TsrpcError('Internal Server Error', { - code: 'INTERNAL_ERR', - type: TsrpcErrorType.ServerError, - innerErr: `${v} InnerError` - }) - }); - } - - // TsrpcError - for (let v of ['Test', 'a/b/c/Test']) { - let ret = await client.callApi(v as any, { - name: 'TsrpcError' - }); - assert.deepStrictEqual(ret, { - isSucc: false, - err: new TsrpcError(`${v} TsrpcError`, { - code: 'CODE_TEST', - type: TsrpcErrorType.ApiError, - info: 'ErrInfo ' + v - }) - }); - } - - // call.error - for (let v of ['Test', 'a/b/c/Test']) { - let ret = await client.callApi(v as any, { - name: 'error' - }); - assert.deepStrictEqual(ret, { - isSucc: false, - err: new TsrpcError('Got an error', { - type: TsrpcErrorType.ApiError - }) - }); - } -} - -describe('HTTP Server & Client basic', function () { - it('implement API manually', async function () { - let server = new HttpServer(getProto(), { - json: true, - logger: serverLogger, - debugBuf: true - }); - await server.start(); - - server.implementApi('Test', ApiTest); - server.implementApi('a/b/c/Test', ApiAbcTest); - - let client = new HttpClient(getProto(), { - json: true, - logger: clientLogger, - debugBuf: true - }) - - await testApi(server, client); - - await server.stop(); - }) - - it('extend call in handler', function () { - let server = new HttpServer(getProto(), { - json: true, - logger: serverLogger, - debugBuf: true - }); - - type MyApiCall = ApiCall & { - value1?: string; - value2: string; - } - type MyMsgCall = MsgCall & { - value1?: string; - value2: string; - } - - server.implementApi('Test', (call: MyApiCall) => { - call.value1 = 'xxx'; - call.value2 = 'xxx'; - }); - server.listenMsg('Chat', (call: MyMsgCall) => { - call.msg.content; - call.value1 = 'xxx'; - call.value2 = 'xxx'; - }) - }) - - it('extend call in flow', function () { - let server = new HttpServer(getProto(), { - json: true, - logger: serverLogger, - debugBuf: true - }); - - type MyApiCall = ApiCall & { - value1?: string; - value2: string; - } - type MyMsgCall = MsgCall & { - value1?: string; - value2: string; - } - type MyConn = HttpConnection & { - currentUser: { - uid: string, - nickName: string - } - } - - server.flows.postConnectFlow.push((conn: MyConn) => { - conn.currentUser.nickName = 'asdf'; - return conn; - }); - server.flows.postConnectFlow.exec(null as any as MyConn, console); - server.flows.preApiCallFlow.push((call: MyApiCall) => { - call.value2 = 'x'; - return call; - }); - server.flows.preSendMsgFlow.push((call: MyMsgCall) => { - call.value2 = 'f'; - return call; - }) - }) - - it('autoImplementApi', async function () { - let server = new HttpServer(getProto(), { - json: true, - logger: serverLogger, - apiTimeout: 5000 - }); - await server.start(); - - server.autoImplementApi(path.resolve(__dirname, '../api')) - - let client = new HttpClient(getProto(), { - json: true, - logger: clientLogger - }) - - await testApi(server, client); - - await server.stop(); - }); - - it('sendMsg', async function () { - let server = new HttpServer(getProto(), { - json: true, - port: 3001, - logger: serverLogger, - // debugBuf: true - }); - - await server.start(); - - let client = new HttpClient(getProto(), { - json: true, - server: 'http://127.0.0.1:3001', - logger: clientLogger, - // debugBuf: true - }); - - return new Promise(rs => { - let msg: MsgChat = { - channel: 123, - userName: 'fff', - content: '666', - time: Date.now() - }; - - server.listenMsg('Chat', async v => { - assert.deepStrictEqual(v.msg, msg); - await server.stop(); - rs(); - }); - - client.sendMsg('Chat', msg); - }) - }) - - it('abort', async function () { - let server = new HttpServer(getProto(), { - json: true, - logger: serverLogger - }); - await server.start(); - - server.autoImplementApi(path.resolve(__dirname, '../api')) - - let client = new HttpClient(getProto(), { - json: true, - logger: clientLogger - }) - - let result: any | undefined; - let promise = client.callApi('Test', { name: 'aaaaaaaa' }); - let sn = client.lastSN; - setTimeout(() => { - client.abort(sn) - }, 10); - promise.then(v => { - result = v; - }); - - await new Promise(rs => { - setTimeout(() => { - assert.strictEqual(result, undefined); - rs(); - }, 150) - }) - - await server.stop(); - }); - - it('abortByKey', async function () { - let server = new HttpServer(getProto(), { - json: true, - logger: serverLogger - }); - await server.start(); - - server.autoImplementApi(path.resolve(__dirname, '../api')) - - let client = new HttpClient(getProto(), { - json: true, - logger: clientLogger - }) - - let result: any | undefined; - let result1: any | undefined; - - client.callApi('Test', { name: 'aaaaaaaa' }, { abortKey: 'XXX' }).then(v => { result = v; }); - client.callApi('Test', { name: 'aaaaaaaa' }, { abortKey: 'XXX' }).then(v => { result = v; }); - client.callApi('Test', { name: 'aaaaaaaa' }, { abortKey: 'XXX' }).then(v => { result = v; }); - client.callApi('Test', { name: 'aaaaaaaa' }, { abortKey: 'XXX' }).then(v => { result = v; }); - client.callApi('Test', { name: 'aaaaaaaa' }, { abortKey: 'XXX' }).then(v => { result = v; }); - - client.callApi('Test', { name: 'bbbbbb' }).then(v => { result1 = v; }); - - setTimeout(() => { - client.abortByKey('XXX') - }, 10); - - await new Promise(rs => { - setTimeout(() => { - assert.strictEqual(result, undefined); - assert.deepStrictEqual(result1, { - isSucc: true, - res: { - reply: 'Test reply: bbbbbb' - } - }) - rs(); - }, 150) - }) - - await server.stop(); - }) - - it('abortAll', async function () { - let server = new HttpServer(getProto(), { - json: true, - logger: serverLogger - }); - await server.start(); - - server.autoImplementApi(path.resolve(__dirname, '../api')) - - let client = new HttpClient(getProto(), { - json: true, - logger: clientLogger - }) - - let result: any | undefined; - let result1: any | undefined; - - client.callApi('Test', { name: 'aaaaaaaa' }, { abortKey: 'XXX' }).then(v => { result = v; }); - client.callApi('Test', { name: 'aaaaaaaa' }, { abortKey: 'XXX' }).then(v => { result = v; }); - client.callApi('Test', { name: 'aaaaaaaa' }, { abortKey: 'XXX' }).then(v => { result = v; }); - client.callApi('Test', { name: 'aaaaaaaa' }, { abortKey: 'XXX' }).then(v => { result = v; }); - client.callApi('Test', { name: 'aaaaaaaa' }, { abortKey: 'XXX' }).then(v => { result = v; }); - - client.callApi('Test', { name: 'bbbbbb' }).then(v => { result1 = v; }); - - setTimeout(() => { - client.abortAll() - }, 10); - - await new Promise(rs => { - setTimeout(() => { - assert.strictEqual(result, undefined); - assert.strictEqual(result1, undefined); - rs(); - }, 150) - }) - - await server.stop(); - }) - - it('pendingApis', async function () { - let server = new HttpServer(getProto(), { - json: true, - logger: serverLogger - }); - await server.start(); - - server.autoImplementApi(path.resolve(__dirname, '../api')) - - let client = new HttpClient(getProto(), { - json: true, - logger: clientLogger - }) - - for (let i = 0; i < 10; ++i) { - let promise = Promise.all(Array.from({ length: 10 }, () => new Promise(rs => { - let name = ['Req', 'InnerError', 'TsrpcError', 'error'][Math.random() * 4 | 0]; - let ret: any | undefined; - let promise = client.callApi('Test', { name: name }); - let sn = client.lastSN; - let abort = Math.random() > 0.5; - if (abort) { - setTimeout(() => { - client.abort(sn) - }, 0); - } - promise.then(v => { - ret = v; - }); - - setTimeout(() => { - client.logger?.log('sn', sn, name, abort, ret) - if (abort) { - assert.strictEqual(ret, undefined); - } - else { - assert.notEqual(ret, undefined); - if (name === 'Req') { - assert.strictEqual(ret.isSucc, true); - } - else { - assert.strictEqual(ret.isSucc, false) - } - } - rs(); - }, 300) - }))); - assert.strictEqual(client['_pendingApis'].length, 10); - await promise; - assert.strictEqual(client['_pendingApis'].length, 0); - } - - await server.stop(); - }) - - it('error', async function () { - let server = new HttpServer(getProto(), { - json: true, - logger: serverLogger - }); - await server.start(); - - let client1 = new HttpClient(getProto(), { - json: true, - server: 'http://localhost:80', - logger: clientLogger - }) - - let ret = await client1.callApi('Test', { name: 'xx' }); - console.log(ret); - assert.strictEqual(ret.isSucc, false); - assert.strictEqual(ret.err?.code, 'ECONNREFUSED'); - assert.strictEqual(ret.err?.type, TsrpcErrorType.NetworkError); - - await server.stop(); - }) - - it('server timeout', async function () { - let server = new HttpServer(getProto(), { - json: true, - logger: serverLogger, - apiTimeout: 100 - }); - server.implementApi('Test', call => { - return new Promise(rs => { - setTimeout(() => { - call.req && call.succ({ - reply: 'Hi, ' + call.req.name - }); - rs(); - }, 200) - }) - }) - await server.start(); - - let client = new HttpClient(getProto(), { - json: true, - logger: clientLogger - }); - let ret = await client.callApi('Test', { name: 'Jack' }); - assert.deepStrictEqual(ret, { - isSucc: false, - err: new TsrpcError('Server Timeout', { - code: 'SERVER_TIMEOUT', - type: TsrpcErrorType.ServerError - }) - }); - - await server.stop(); - }); - - it('client timeout', async function () { - let server1 = new HttpServer(getProto(), { - json: true, - logger: serverLogger - }); - server1.implementApi('Test', call => { - return new Promise(rs => { - setTimeout(() => { - call.succ({ - reply: 'Hello, ' + call.req.name - }); - rs(); - }, 2000) - }) - }) - await server1.start(); - - let client = new HttpClient(getProto(), { - json: true, - timeout: 100, - logger: clientLogger - }); - - let ret = await client.callApi('Test', { name: 'Jack123' }); - // SERVER TIMEOUT的call还没执行完,但是call却被放入Pool了,导致这个BUG - assert.deepStrictEqual(ret, { - isSucc: false, - err: new TsrpcError({ - message: 'Request Timeout', - code: 'TIMEOUT', - type: TsrpcErrorType.NetworkError - }) - }); - await server1.stop(); - }); - - it('Graceful stop', async function () { - let server = new HttpServer(getProto(), { - json: true, - logger: serverLogger - }); - - let reqNum = 0; - server.implementApi('Test', async call => { - if (++reqNum === 10) { - server.gracefulStop(); - } - await new Promise(rs => setTimeout(rs, parseInt(call.req.name))); - call.succ({ reply: 'OK' }); - }); - - await server.start(); - let isStopped = false; - - let client = new HttpClient(getProto(), { - json: true, - logger: clientLogger - }) - - let succNum = 0; - await Promise.all(Array.from({ length: 10 }, (v, i) => client.callApi('Test', { name: '' + (i * 100) }).then(v => { - if (v.res?.reply === 'OK') { - ++succNum; - } - }))) - assert.strictEqual(succNum, 10); - }) -}) - -describe('HTTP Flows', function () { - it('Server conn flow', async function () { - let server = new HttpServer(getProto(), { - json: true, - logger: serverLogger - }); - - const flowExecResult: { [K in (keyof BaseServer['flows'])]?: boolean } = {}; - - server.implementApi('Test', async call => { - assert.strictEqual((call.conn as any).xxxx, 'asdfasdf') - assert.strictEqual(flowExecResult.postConnectFlow, true); - assert.strictEqual(flowExecResult.postDisconnectFlow, undefined); - call.succ({ reply: 'ok' }); - assert.strictEqual(flowExecResult.postDisconnectFlow, undefined); - }); - - server.flows.postConnectFlow.push(v => { - flowExecResult.postConnectFlow = true; - (v as any).xxxx = 'asdfasdf'; - return v; - }); - server.flows.postDisconnectFlow.push(v => { - flowExecResult.postDisconnectFlow = true; - return v; - }) - - await server.start(); - - assert.strictEqual(flowExecResult.postConnectFlow, undefined); - assert.strictEqual(flowExecResult.postDisconnectFlow, undefined); - - let client = new HttpClient(getProto(), { - json: true, - logger: clientLogger - }); - await client.callApi('Test', { name: 'xxx' }); - assert.strictEqual(flowExecResult.postConnectFlow, true); - assert.strictEqual(flowExecResult.postDisconnectFlow, true); - - await server.stop(); - }) - - it('Buffer enc/dec flow', async function () { - let server = new HttpServer(getProto(), { - json: true, - logger: serverLogger - }); - - const flowExecResult: { [K in (keyof BaseServer['flows'])]?: boolean } = {}; - - server.implementApi('Test', async call => { - call.succ({ reply: 'Enc&Dec' }); - }); - - server.flows.preRecvDataFlow.push(v => { - flowExecResult.preRecvDataFlow = true; - v.data = (v.data as string).split('').reverse().join(''); - return v; - }); - server.flows.preSendDataFlow.push(v => { - flowExecResult.preSendDataFlow = true; - v.data = (v.data as string).split('').reverse().join(''); - return v; - }) - - await server.start(); - - let client = new HttpClient(getProto(), { - json: true, - logger: clientLogger - }); - - client.flows.preSendDataFlow.push(v => { - v.data = (v.data as string).split('').reverse().join(''); - return v; - }); - - client.flows.preRecvDataFlow.push(v => { - v.data = (v.data as string).split('').reverse().join(''); - return v; - }); - - let ret = await client.callApi('Test', { name: 'xxx' }); - assert.strictEqual(flowExecResult.preRecvDataFlow, true); - assert.strictEqual(flowExecResult.preSendDataFlow, true); - assert.deepStrictEqual(ret, { - isSucc: true, - res: { - reply: 'Enc&Dec' - } - }) - - await server.stop(); - }); - - it('ApiCall flow', async function () { - let server = new HttpServer(getProto(), { - json: true, - logger: serverLogger - }); - - const flowExecResult: { [K in (keyof BaseServer['flows'])]?: boolean } = {}; - - server.implementApi('Test', async call => { - call.succ({ reply: 'asdgasdgasdgasdg' }); - }); - - server.flows.preApiCallFlow.push(call => { - assert.strictEqual(call.req.name, 'Changed') - call.error('You need login'); - return call; - }); - server.flows.postApiCallFlow.push(v => { - flowExecResult.postApiCallFlow = true; - return v; - }) - - await server.start(); - - let client = new HttpClient(getProto(), { - json: true, - logger: clientLogger - }); - - client.flows.preCallApiFlow.push(v => { - if (v.apiName !== 'ObjId') { - v.req.name = 'Changed' - } - return v; - }); - - let ret = await client.callApi('Test', { name: 'xxx' }); - assert.strictEqual(flowExecResult.postApiCallFlow, true); - assert.deepStrictEqual(ret, { - isSucc: false, - err: new TsrpcError('You need login') - }) - - await server.stop(); - }); - - it('ApiCall flow break', async function () { - let server = new HttpServer(getProto(), { - json: true, - logger: serverLogger - }); - - const flowExecResult: { [K in (keyof BaseServer['flows'])]?: boolean } = {}; - - server.implementApi('Test', async call => { - call.succ({ reply: 'asdgasdgasdgasdg' }); - }); - - server.flows.preApiCallFlow.push(call => { - assert.strictEqual(call.req.name, 'Changed') - call.error('You need login'); - return undefined; - }); - server.flows.postApiCallFlow.push(v => { - flowExecResult.postApiCallFlow = true; - return v; - }) - - await server.start(); - - let client = new HttpClient(getProto(), { - json: true, - logger: clientLogger - }); - - client.flows.preCallApiFlow.push(v => { - if (v.apiName !== 'ObjId') { - v.req.name = 'Changed' - } - return v; - }); - - let ret = await client.callApi('Test', { name: 'xxx' }); - assert.strictEqual(flowExecResult.postApiCallFlow, undefined); - assert.deepStrictEqual(ret, { - isSucc: false, - err: new TsrpcError('You need login') - }) - - await server.stop(); - }); - - it('ApiCall flow error', async function () { - let server = new HttpServer(getProto(), { - json: true, - logger: serverLogger - }); - - const flowExecResult: { [K in (keyof BaseServer['flows'])]?: boolean } = {}; - - server.implementApi('Test', async call => { - call.succ({ reply: 'asdgasdgasdgasdg' }); - }); - - server.flows.preApiCallFlow.push(call => { - assert.strictEqual(call.req.name, 'Changed') - throw new Error('ASDFASDF') - }); - server.flows.postApiCallFlow.push(v => { - flowExecResult.postApiCallFlow = true; - return v; - }) - - await server.start(); - - let client = new HttpClient(getProto(), { - json: true, - logger: clientLogger - }); - - client.flows.preCallApiFlow.push(v => { - if (v.apiName !== 'ObjId') { - v.req.name = 'Changed' - } - return v; - }); - - let ret = await client.callApi('Test', { name: 'xxx' }); - assert.strictEqual(flowExecResult.postApiCallFlow, undefined); - assert.deepStrictEqual(ret, { - isSucc: false, - err: new TsrpcError('Internal Server Error', { - type: TsrpcErrorType.ServerError, - innerErr: 'ASDFASDF', - code: 'INTERNAL_ERR' - }) - }) - - await server.stop(); - }); - - it('server ApiReturn flow', async function () { - let server = new HttpServer(getProto(), { - json: true, - logger: serverLogger - }); - - const flowExecResult: { [K in (keyof BaseServer['flows'])]?: boolean } = {}; - - server.implementApi('Test', async call => { - call.succ({ reply: 'xxxxxxxxxxxxxxxxxxxx' }); - }); - - server.flows.preApiReturnFlow.push(v => { - flowExecResult.preApiReturnFlow = true; - v.return = { - isSucc: false, - err: new TsrpcError('Ret changed') - } - return v; - }); - server.flows.postApiReturnFlow.push(v => { - flowExecResult.postApiReturnFlow = true; - v.call.logger.log('RETTT', v.return); - return v; - }) - - await server.start(); - - let client = new HttpClient(getProto(), { - json: true, - logger: clientLogger - }); - - - let ret = await client.callApi('Test', { name: 'xxx' }); - assert.strictEqual(flowExecResult.preApiReturnFlow, true); - assert.strictEqual(flowExecResult.postApiReturnFlow, true); - assert.deepStrictEqual(ret, { - isSucc: false, - err: new TsrpcError('Ret changed') - }) - - await server.stop(); - }); - - it('client ApiReturn flow', async function () { - let server = new HttpServer(getProto(), { - json: true, - logger: serverLogger - }); - - const flowExecResult: { [K in (keyof HttpClient['flows'])]?: boolean } = {}; - - server.implementApi('Test', async call => { - call.succ({ reply: 'xxxxxxxxxxxxxxxxxxxx' }); - }); - - await server.start(); - - let client = new HttpClient(getProto(), { - json: true, - logger: clientLogger - }); - - client.flows.preApiReturnFlow.push(v => { - flowExecResult.preApiReturnFlow = true; - v.return = { - isSucc: false, - err: new TsrpcError('Ret changed') - } - return v; - }); - client.flows.postApiReturnFlow.push(v => { - flowExecResult.postApiReturnFlow = true; - client.logger?.log('RETTT', v.return); - return v; - }) - - let ret = await client.callApi('Test', { name: 'xxx' }); - assert.strictEqual(flowExecResult.preApiReturnFlow, true); - assert.strictEqual(flowExecResult.postApiReturnFlow, true); - assert.deepStrictEqual(ret, { - isSucc: false, - err: new TsrpcError('Ret changed') - }) - - await server.stop(); - }); - - it('client SendBufferFlow prevent', async function () { - let server = new HttpServer(getProto(), { - json: true, - logger: serverLogger - }); - - // const flowExecResult: { [K in (keyof BaseClient['flows'])]?: boolean } = {}; - - server.implementApi('Test', async call => { - call.succ({ reply: 'xxxxxxxxxxxxxxxxxxxx' }); - }); - - await server.start(); - - let client = new HttpClient(getProto(), { - json: true, - logger: clientLogger - }); - - client.flows.preSendDataFlow.push(v => { - return undefined - }); - - let ret: any; - client.callApi('Test', { name: 'xxx' }).then(v => { ret = v }); - await new Promise(rs => { setTimeout(rs, 200) }); - assert.strictEqual(ret, undefined) - - await server.stop(); - }); - - it('onInputBufferError', async function () { - let server = new HttpServer(getProto(), { - json: true, - logger: serverLogger - }); - await server.start(); - - let client = new HttpClient(getProto(), { - json: true, - logger: clientLogger - }); - client.flows.preSendDataFlow.push(v => { - v.data = (v.data as string).split('').reverse().join(''); - return v; - }); - - let ret = await client.callApi('Test', { name: 'XXX' }); - assert.deepStrictEqual(ret, { - isSucc: false, - err: new TsrpcError('Input is not a valid JSON string: Unexpected token } in JSON at position 0', { - type: TsrpcErrorType.ServerError, - code: 'INPUT_DATA_ERR' - }) - }) - - await server.stop(); - }) - - it('throw type error in client', async function () { - let server = new HttpServer(getProto(), { - json: true, - logger: serverLogger - }); - await server.start(); - - let client = new HttpClient(getProto(), { - json: true, - logger: clientLogger - }); - - let ret = await client.callApi('Test', { name: 23456 } as any); - assert.deepStrictEqual(ret, { - isSucc: false, - err: new TsrpcError({ - "code": "INPUT_DATA_ERR", - "message": "Property `name`: Expected type to be `string`, actually `number`.", - "type": TsrpcErrorType.ClientError - }) - }) - - await server.stop(); - }) - - it('throw type error in server', async function () { - let server = new HttpServer(getProto(), { - json: true, - logger: serverLogger - }); - await server.start(); - - let retHttp = await new HttpProxy().fetch({ - url: 'http://127.0.0.1:3000/Test', - data: JSON.stringify({ name: 12345 }), - method: 'POST', - headers: { - 'content-type': 'application/json; charset=utf-8' - }, - transportOptions: {}, - responseType: 'text' - }).promise; - - assert.deepStrictEqual(JSON.parse((retHttp as any).res), { - isSucc: false, - err: { - "code": "INPUT_DATA_ERR", - "message": "Property `name`: Expected type to be `string`, actually `number`.", - "type": TsrpcErrorType.ServerError - } - }) - - await server.stop(); - }) - - it('ObjectId', async function () { - let server = new HttpServer(getProto(), { - json: true, - logger: serverLogger - }); - server.autoImplementApi(path.resolve(__dirname, '../api')) - await server.start(); - - let client = new HttpClient(getProto(), { - json: true, - logger: clientLogger - }); - - // ObjectId - let objId1 = new ObjectId(); - let ret = await client.callApi('ObjId', { - id1: objId1 - }); - assert.strictEqual(ret.isSucc, true, ret.err?.message); - assert.strictEqual(objId1.toString(), ret.res!.id2.toString()); - - await server.stop(); - }) -}) \ No newline at end of file diff --git a/test/cases/inner.test.ts b/test/cases/inner.test.ts deleted file mode 100644 index a18371a..0000000 --- a/test/cases/inner.test.ts +++ /dev/null @@ -1,396 +0,0 @@ -import { ObjectId } from 'bson'; -import { assert } from 'chai'; -import chalk from 'chalk'; -import * as path from "path"; -import { ServiceProto, TsrpcError, TsrpcErrorType } from 'tsrpc-proto'; -import { ApiCall, BaseServer, HttpConnection, MsgCall, TerminalColorLogger } from '../../src'; -import { HttpServer } from '../../src/server/http/HttpServer'; -import { PrefixLogger } from '../../src/server/models/PrefixLogger'; -import { ApiTest as ApiAbcTest } from '../api/a/b/c/ApiTest'; -import { ApiTest } from '../api/ApiTest'; -import { MsgChat } from '../proto/MsgChat'; -import { ReqTest, ResTest } from '../proto/PtlTest'; -import { serviceProto, ServiceType } from '../proto/serviceProto'; - -const serverLogger = new PrefixLogger({ - prefixs: [chalk.bgGreen.white(' Server ')], - logger: new TerminalColorLogger({ pid: 'Server' }) -}); - -const getProto = () => Object.merge({}, serviceProto) as ServiceProto; - -async function testApi(server: HttpServer) { - // Succ - assert.deepStrictEqual(await server.callApi('Test', { - name: 'Req1' - }), { - isSucc: true, - res: { - reply: 'Test reply: Req1' - } - }); - assert.deepStrictEqual(await server.callApi('a/b/c/Test', { - name: 'Req2' - }), { - isSucc: true, - res: { - reply: 'a/b/c/Test reply: Req2' - } - }); - - // Inner error - for (let v of ['Test', 'a/b/c/Test']) { - let ret = await server.callApi(v as any, { - name: 'InnerError' - }); - delete ret.err!.innerErr.stack; - - assert.deepStrictEqual(ret, { - isSucc: false, - err: new TsrpcError('Internal Server Error', { - code: 'INTERNAL_ERR', - type: TsrpcErrorType.ServerError, - innerErr: `${v} InnerError` - }) - }); - } - - // TsrpcError - for (let v of ['Test', 'a/b/c/Test']) { - let ret = await server.callApi(v as any, { - name: 'TsrpcError' - }); - assert.deepStrictEqual(ret, { - isSucc: false, - err: new TsrpcError(`${v} TsrpcError`, { - code: 'CODE_TEST', - type: TsrpcErrorType.ApiError, - info: 'ErrInfo ' + v - }) - }); - } - - // call.error - for (let v of ['Test', 'a/b/c/Test']) { - let ret = await server.callApi(v as any, { - name: 'error' - }); - assert.deepStrictEqual(ret, { - isSucc: false, - err: new TsrpcError('Got an error', { - type: TsrpcErrorType.ApiError - }) - }); - } -} - -describe('HTTP Server & Client basic', function () { - it('implement API manually', async function () { - let server = new HttpServer(getProto(), { - logger: serverLogger, - debugBuf: true - }); - - - server.implementApi('Test', ApiTest); - server.implementApi('a/b/c/Test', ApiAbcTest); - - await testApi(server); - - - }) - - it('extend call in handler', function () { - let server = new HttpServer(getProto(), { - logger: serverLogger, - debugBuf: true - }); - - type MyApiCall = ApiCall & { - value1?: string; - value2: string; - } - type MyMsgCall = MsgCall & { - value1?: string; - value2: string; - } - - server.implementApi('Test', (call: MyApiCall) => { - call.value1 = 'xxx'; - call.value2 = 'xxx'; - }); - server.listenMsg('Chat', (call: MyMsgCall) => { - call.msg.content; - call.value1 = 'xxx'; - call.value2 = 'xxx'; - }) - }) - - it('extend call in flow', function () { - let server = new HttpServer(getProto(), { - logger: serverLogger, - debugBuf: true - }); - - type MyApiCall = ApiCall & { - value1?: string; - value2: string; - } - type MyMsgCall = MsgCall & { - value1?: string; - value2: string; - } - type MyConn = HttpConnection & { - currentUser: { - uid: string, - nickName: string - } - } - - server.flows.postConnectFlow.push((conn: MyConn) => { - conn.currentUser.nickName = 'asdf'; - return conn; - }); - server.flows.postConnectFlow.exec(null as any as MyConn, console); - server.flows.preApiCallFlow.push((call: MyApiCall) => { - call.value2 = 'x'; - return call; - }); - server.flows.preSendMsgFlow.push((call: MyMsgCall) => { - call.value2 = 'f'; - return call; - }) - }) - - it('autoImplementApi', async function () { - let server = new HttpServer(getProto(), { - logger: serverLogger, - apiTimeout: 5000 - }); - - await server.autoImplementApi(path.resolve(__dirname, '../api')) - - await testApi(server); - }); - - it('autoImplementApi delay', async function () { - let server = new HttpServer(getProto(), { - logger: serverLogger, - apiTimeout: 5000 - }); - - server.autoImplementApi(path.resolve(__dirname, '../api'), true) - - await testApi(server); - }); - - it('error', async function () { - let server = new HttpServer(getProto(), { - logger: serverLogger - }); - - - let ret = await server.callApi('TesASFt' as any, { name: 'xx' } as any); - console.log(ret); - assert.strictEqual(ret.isSucc, false); - assert.strictEqual(ret.err?.code, 'ERR_API_NAME'); - assert.strictEqual(ret.err?.type, TsrpcErrorType.ServerError); - - - }) - - it('server timeout', async function () { - let server = new HttpServer(getProto(), { - logger: serverLogger, - apiTimeout: 100 - }); - server.implementApi('Test', call => { - return new Promise(rs => { - setTimeout(() => { - call.req && call.succ({ - reply: 'Hi, ' + call.req.name - }); - rs(); - }, 200) - }) - }) - - - let ret = await server.callApi('Test', { name: 'Jack' }); - assert.deepStrictEqual(ret, { - isSucc: false, - err: new TsrpcError('Server Timeout', { - code: 'SERVER_TIMEOUT', - type: TsrpcErrorType.ServerError - }) - }); - - - }); - - it('Graceful stop', async function () { - let server = new HttpServer(getProto(), { - logger: serverLogger - }); - - let reqNum = 0; - server.implementApi('Test', async call => { - if (++reqNum === 10) { - server.gracefulStop(); - } - await new Promise(rs => setTimeout(rs, parseInt(call.req.name))); - call.succ({ reply: 'OK' }); - }); - - - let isStopped = false; - - let succNum = 0; - await Promise.all(Array.from({ length: 10 }, (v, i) => server.callApi('Test', { name: '' + (i * 100) }).then(v => { - if (v.res?.reply === 'OK') { - ++succNum; - } - }))) - assert.strictEqual(succNum, 10); - }) -}) - -describe('HTTP Flows', function () { - it('ApiCall flow', async function () { - let server = new HttpServer(getProto(), { - logger: serverLogger - }); - - server.implementApi('Test', async call => { - call.succ({ reply: 'asdgasdgasdgasdg' }); - }); - - server.flows.preApiCallFlow.push(call => { - if (call.req.apiName !== 'ObjId') { - call.req.name = 'Changed' - } - return call; - }); - - server.flows.preApiCallFlow.push(call => { - assert.strictEqual(call.req.name, 'Changed') - call.error('You need login'); - return call; - }); - - let ret = await server.callApi('Test', { name: 'xxx' }); - assert.deepStrictEqual(ret, { - isSucc: false, - err: new TsrpcError('You need login') - }) - }); - - it('ApiCall flow break', async function () { - let server = new HttpServer(getProto(), { - logger: serverLogger - }); - - const flowExecResult: { [K in (keyof BaseServer['flows'])]?: boolean } = {}; - - server.implementApi('Test', async call => { - call.succ({ reply: 'asdgasdgasdgasdg' }); - }); - - server.flows.preApiCallFlow.push(call => { - call.error('You need login'); - return undefined; - }); - - let ret = await server.callApi('Test', { name: 'xxx' }); - assert.deepStrictEqual(ret, { - isSucc: false, - err: new TsrpcError('You need login') - }) - - - }); - - it('ApiCall flow error', async function () { - let server = new HttpServer(getProto(), { - logger: serverLogger - }); - - const flowExecResult: { [K in (keyof BaseServer['flows'])]?: boolean } = {}; - - server.implementApi('Test', async call => { - call.succ({ reply: 'asdgasdgasdgasdg' }); - }); - - server.flows.preApiCallFlow.push(call => { - throw new Error('ASDFASDF') - }); - - let ret = await server.callApi('Test', { name: 'xxx' }); - assert.deepStrictEqual(ret, { - isSucc: false, - err: new TsrpcError('Internal Server Error', { - type: TsrpcErrorType.ServerError, - innerErr: 'ASDFASDF', - code: 'INTERNAL_ERR' - }) - }) - - - }); - - it('server ApiReturn flow', async function () { - let server = new HttpServer(getProto(), { - logger: serverLogger - }); - - const flowExecResult: { [K in (keyof BaseServer['flows'])]?: boolean } = {}; - - server.implementApi('Test', async call => { - call.succ({ reply: 'xxxxxxxxxxxxxxxxxxxx' }); - }); - - server.flows.preApiReturnFlow.push(v => { - flowExecResult.preApiReturnFlow = true; - v.return = { - isSucc: false, - err: new TsrpcError('Ret changed') - } - return v; - }); - - let ret = await server.callApi('Test', { name: 'xxx' }); - assert.strictEqual(flowExecResult.preApiReturnFlow, true); - assert.deepStrictEqual(ret, { - isSucc: false, - err: new TsrpcError('Ret changed') - }) - - - }); - - it('Extended JSON Types', async function () { - let server = new HttpServer(getProto(), { - logger: serverLogger - }); - await server.autoImplementApi(path.resolve(__dirname, '../api')) - - let buf = new Uint8Array([0, 1, 2, 3, 255, 254, 253, 252]); - let date = new Date('2021/11/17'); - - // ObjectId - let objId1 = new ObjectId(); - let ret = await server.callApi('ObjId', { - id1: objId1, - buf: buf, - date: date - }); - assert.deepStrictEqual(ret, { - isSucc: true, - res: { - id2: objId1, - buf: buf, - date: date - } - }); - }) -}) \ No newline at end of file diff --git a/test/cases/inputBuffer.test.ts b/test/cases/inputBuffer.test.ts deleted file mode 100644 index 6013e7a..0000000 --- a/test/cases/inputBuffer.test.ts +++ /dev/null @@ -1,414 +0,0 @@ -import { ObjectId } from 'bson'; -import { assert } from 'chai'; -import chalk from 'chalk'; -import * as path from "path"; -import { ServiceProto, TsrpcError, TsrpcErrorType } from 'tsrpc-proto'; -import { ApiCall, ApiService, BaseServer, HttpConnection, MsgCall, TerminalColorLogger, TransportDataUtil } from '../../src'; -import { HttpServer } from '../../src/server/http/HttpServer'; -import { PrefixLogger } from '../../src/server/models/PrefixLogger'; -import { ApiTest as ApiAbcTest } from '../api/a/b/c/ApiTest'; -import { ApiTest } from '../api/ApiTest'; -import { MsgChat } from '../proto/MsgChat'; -import { ReqTest, ResTest } from '../proto/PtlTest'; -import { serviceProto, ServiceType } from '../proto/serviceProto'; - -const serverLogger = new PrefixLogger({ - prefixs: [chalk.bgGreen.white(' Server ')], - logger: new TerminalColorLogger({ pid: 'Server' }) -}); - -async function inputBuffer(server: BaseServer, apiName: string, req: any) { - let apiSvc: ApiService | undefined = server.serviceMap.apiName2Service[apiName]; - let inputBuf = apiSvc ? (await TransportDataUtil.encodeApiReq(server.tsbuffer, apiSvc, req, 'buffer')).output : new Uint8Array([0, 1, 2, 3, 255, 254, 253, 252]); - if (!inputBuf) { - throw new Error('failed to encode inputBuf') - } - - let retBuf = await server.inputBuffer(inputBuf); - assert.ok(retBuf instanceof Uint8Array) - - let opDecode = await TransportDataUtil.parseServerOutout(server.tsbuffer, server.serviceMap, retBuf, apiSvc?.id ?? 0); - if (!opDecode.isSucc) { - throw new Error('decode buf failed') - } - if (opDecode.result.type !== 'api') { - throw new Error('decode result is not api') - } - return opDecode.result.ret; -} - -const getProto = () => Object.merge({}, serviceProto) as ServiceProto; - -async function testApi(server: HttpServer) { - // Succ - assert.deepStrictEqual(await inputBuffer(server, 'Test', { - name: 'Req1' - }), { - isSucc: true, - res: { - reply: 'Test reply: Req1' - } - }); - assert.deepStrictEqual(await inputBuffer(server, 'a/b/c/Test', { - name: 'Req2' - }), { - isSucc: true, - res: { - reply: 'a/b/c/Test reply: Req2' - } - }); - - // Inner error - for (let v of ['Test', 'a/b/c/Test']) { - let ret = await inputBuffer(server, v as any, { - name: 'InnerError' - }); - delete ret.err!.innerErr.stack; - - assert.deepStrictEqual(ret, { - isSucc: false, - err: new TsrpcError('Internal Server Error', { - code: 'INTERNAL_ERR', - type: TsrpcErrorType.ServerError, - innerErr: `${v} InnerError` - }) - }); - } - - // TsrpcError - for (let v of ['Test', 'a/b/c/Test']) { - let ret = await inputBuffer(server, v as any, { - name: 'TsrpcError' - }); - assert.deepStrictEqual(ret, { - isSucc: false, - err: new TsrpcError(`${v} TsrpcError`, { - code: 'CODE_TEST', - type: TsrpcErrorType.ApiError, - info: 'ErrInfo ' + v - }) - }); - } - - // call.error - for (let v of ['Test', 'a/b/c/Test']) { - let ret = await inputBuffer(server, v as any, { - name: 'error' - }); - assert.deepStrictEqual(ret, { - isSucc: false, - err: new TsrpcError('Got an error', { - type: TsrpcErrorType.ApiError - }) - }); - } -} - -describe('HTTP Server & Client basic', function () { - it('implement API manually', async function () { - let server = new HttpServer(getProto(), { - logger: serverLogger, - debugBuf: true - }); - - - server.implementApi('Test', ApiTest); - server.implementApi('a/b/c/Test', ApiAbcTest); - - await testApi(server); - - - }) - - it('extend call in handler', function () { - let server = new HttpServer(getProto(), { - logger: serverLogger, - debugBuf: true - }); - - type MyApiCall = ApiCall & { - value1?: string; - value2: string; - } - type MyMsgCall = MsgCall & { - value1?: string; - value2: string; - } - - server.implementApi('Test', (call: MyApiCall) => { - call.value1 = 'xxx'; - call.value2 = 'xxx'; - }); - server.listenMsg('Chat', (call: MyMsgCall) => { - call.msg.content; - call.value1 = 'xxx'; - call.value2 = 'xxx'; - }) - }) - - it('extend call in flow', function () { - let server = new HttpServer(getProto(), { - logger: serverLogger, - debugBuf: true - }); - - type MyApiCall = ApiCall & { - value1?: string; - value2: string; - } - type MyMsgCall = MsgCall & { - value1?: string; - value2: string; - } - type MyConn = HttpConnection & { - currentUser: { - uid: string, - nickName: string - } - } - - server.flows.postConnectFlow.push((conn: MyConn) => { - conn.currentUser.nickName = 'asdf'; - return conn; - }); - server.flows.postConnectFlow.exec(null as any as MyConn, console); - server.flows.preApiCallFlow.push((call: MyApiCall) => { - call.value2 = 'x'; - return call; - }); - server.flows.preSendMsgFlow.push((call: MyMsgCall) => { - call.value2 = 'f'; - return call; - }) - }) - - it('autoImplementApi', async function () { - let server = new HttpServer(getProto(), { - logger: serverLogger, - apiTimeout: 5000 - }); - - await server.autoImplementApi(path.resolve(__dirname, '../api')) - - await testApi(server); - }); - - it('autoImplementApi delay', async function () { - let server = new HttpServer(getProto(), { - logger: serverLogger, - apiTimeout: 5000 - }); - - server.autoImplementApi(path.resolve(__dirname, '../api'), true) - - await testApi(server); - }); - - it('error', async function () { - let server = new HttpServer(getProto(), { - logger: serverLogger - }); - - - let ret = await inputBuffer(server, 'TesASFt' as any, { name: 'xx' } as any); - console.log(ret); - assert.strictEqual(ret.isSucc, false); - assert.strictEqual(ret.err?.code, 'INPUT_DATA_ERR'); - assert.strictEqual(ret.err?.type, TsrpcErrorType.ServerError); - }) - - it('server timeout', async function () { - let server = new HttpServer(getProto(), { - logger: serverLogger, - apiTimeout: 100 - }); - server.implementApi('Test', call => { - return new Promise(rs => { - setTimeout(() => { - call.req && call.succ({ - reply: 'Hi, ' + call.req.name - }); - rs(); - }, 200) - }) - }) - - - let ret = await inputBuffer(server, 'Test', { name: 'Jack' }); - assert.deepStrictEqual(ret, { - isSucc: false, - err: new TsrpcError('Server Timeout', { - code: 'SERVER_TIMEOUT', - type: TsrpcErrorType.ServerError - }) - }); - - - }); - - it('Graceful stop', async function () { - let server = new HttpServer(getProto(), { - logger: serverLogger - }); - - let reqNum = 0; - server.implementApi('Test', async call => { - if (++reqNum === 10) { - server.gracefulStop(); - } - await new Promise(rs => setTimeout(rs, parseInt(call.req.name))); - call.succ({ reply: 'OK' }); - }); - - - let isStopped = false; - - let succNum = 0; - await Promise.all(Array.from({ length: 10 }, (v, i) => inputBuffer(server, 'Test', { name: '' + (i * 100) }).then((v: any) => { - if (v.res?.reply === 'OK') { - ++succNum; - } - }))) - assert.strictEqual(succNum, 10); - }) -}) - -describe('HTTP Flows', function () { - it('ApiCall flow', async function () { - let server = new HttpServer(getProto(), { - logger: serverLogger - }); - - server.implementApi('Test', async call => { - call.succ({ reply: 'asdgasdgasdgasdg' }); - }); - - server.flows.preApiCallFlow.push(call => { - if (call.req.apiName !== 'ObjId') { - call.req.name = 'Changed' - } - return call; - }); - - server.flows.preApiCallFlow.push(call => { - assert.strictEqual(call.req.name, 'Changed') - call.error('You need login'); - return call; - }); - - let ret = await inputBuffer(server, 'Test', { name: 'xxx' }); - assert.deepStrictEqual(ret, { - isSucc: false, - err: new TsrpcError('You need login') - }) - }); - - it('ApiCall flow break', async function () { - let server = new HttpServer(getProto(), { - logger: serverLogger - }); - - const flowExecResult: { [K in (keyof BaseServer['flows'])]?: boolean } = {}; - - server.implementApi('Test', async call => { - call.succ({ reply: 'asdgasdgasdgasdg' }); - }); - - server.flows.preApiCallFlow.push(call => { - call.error('You need login'); - return undefined; - }); - - let ret = await inputBuffer(server, 'Test', { name: 'xxx' }); - assert.deepStrictEqual(ret, { - isSucc: false, - err: new TsrpcError('You need login') - }) - - - }); - - it('ApiCall flow error', async function () { - let server = new HttpServer(getProto(), { - logger: serverLogger - }); - - const flowExecResult: { [K in (keyof BaseServer['flows'])]?: boolean } = {}; - - server.implementApi('Test', async call => { - call.succ({ reply: 'asdgasdgasdgasdg' }); - }); - - server.flows.preApiCallFlow.push(call => { - throw new Error('ASDFASDF') - }); - - let ret = await inputBuffer(server, 'Test', { name: 'xxx' }); - assert.deepStrictEqual(ret, { - isSucc: false, - err: new TsrpcError('Internal Server Error', { - type: TsrpcErrorType.ServerError, - innerErr: 'ASDFASDF', - code: 'INTERNAL_ERR' - }) - }) - - - }); - - it('server ApiReturn flow', async function () { - let server = new HttpServer(getProto(), { - logger: serverLogger - }); - - const flowExecResult: { [K in (keyof BaseServer['flows'])]?: boolean } = {}; - - server.implementApi('Test', async call => { - call.succ({ reply: 'xxxxxxxxxxxxxxxxxxxx' }); - }); - - server.flows.preApiReturnFlow.push(v => { - flowExecResult.preApiReturnFlow = true; - v.return = { - isSucc: false, - err: new TsrpcError('Ret changed') - } - return v; - }); - - let ret = await inputBuffer(server, 'Test', { name: 'xxx' }); - assert.strictEqual(flowExecResult.preApiReturnFlow, true); - assert.deepStrictEqual(ret, { - isSucc: false, - err: new TsrpcError('Ret changed') - }) - - - }); - - it('Extended JSON Types', async function () { - let server = new HttpServer(getProto(), { - logger: serverLogger - }); - await server.autoImplementApi(path.resolve(__dirname, '../api')) - - let buf = new Uint8Array([0, 1, 2, 3, 255, 254, 253, 252]); - let date = new Date('2021/11/17'); - - // ObjectId - let objId1 = new ObjectId(); - let ret = await inputBuffer(server, 'ObjId', { - id1: objId1, - buf: buf, - date: date - }); - assert.deepStrictEqual(ret, { - isSucc: true, - res: { - id2: objId1, - buf: buf, - date: date - } - }); - }) -}) \ No newline at end of file diff --git a/test/cases/inputJSON.test.ts b/test/cases/inputJSON.test.ts deleted file mode 100644 index d198587..0000000 --- a/test/cases/inputJSON.test.ts +++ /dev/null @@ -1,410 +0,0 @@ -import { ObjectId } from 'bson'; -import { assert } from 'chai'; -import chalk from 'chalk'; -import * as path from "path"; -import { Base64Util } from 'tsbuffer'; -import { ServiceProto, TsrpcError, TsrpcErrorType } from 'tsrpc-proto'; -import { ApiCall, BaseServer, HttpConnection, MsgCall, TerminalColorLogger } from '../../src'; -import { HttpServer } from '../../src/server/http/HttpServer'; -import { PrefixLogger } from '../../src/server/models/PrefixLogger'; -import { ApiTest as ApiAbcTest } from '../api/a/b/c/ApiTest'; -import { ApiTest } from '../api/ApiTest'; -import { MsgChat } from '../proto/MsgChat'; -import { ReqTest, ResTest } from '../proto/PtlTest'; -import { serviceProto, ServiceType } from '../proto/serviceProto'; - -const serverLogger = new PrefixLogger({ - prefixs: [chalk.bgGreen.white(' Server ')], - logger: new TerminalColorLogger({ pid: 'Server' }) -}); - -const getProto = () => Object.merge({}, serviceProto) as ServiceProto; - -async function testApi(server: HttpServer) { - // Succ - assert.deepStrictEqual(await server.inputJSON('Test', { - name: 'Req1' - }), { - isSucc: true, - res: { - reply: 'Test reply: Req1' - } - }); - assert.deepStrictEqual(await server.inputJSON('/a/b/c/Test', { - name: 'Req2' - }), { - isSucc: true, - res: { - reply: 'a/b/c/Test reply: Req2' - } - }); - - // Inner error - for (let v of ['Test', 'a/b/c/Test']) { - let ret = await server.inputJSON(v as any, { - name: 'InnerError' - }); - delete ret.err!.innerErr.stack; - - assert.deepStrictEqual(ret, { - isSucc: false, - err: { - ...new TsrpcError('Internal Server Error', { - code: 'INTERNAL_ERR', - type: TsrpcErrorType.ServerError, - innerErr: `${v} InnerError` - }) - } - }); - } - - // TsrpcError - for (let v of ['Test', 'a/b/c/Test']) { - let ret = await server.inputJSON(v as any, { - name: 'TsrpcError' - }); - assert.deepStrictEqual(ret, { - isSucc: false, - err: { - ...new TsrpcError(`${v} TsrpcError`, { - code: 'CODE_TEST', - type: TsrpcErrorType.ApiError, - info: 'ErrInfo ' + v - }) - } - }); - } - - // call.error - for (let v of ['Test', 'a/b/c/Test']) { - let ret = await server.inputJSON(v as any, { - name: 'error' - }); - assert.deepStrictEqual(ret, { - isSucc: false, - err: { - ...new TsrpcError('Got an error', { - type: TsrpcErrorType.ApiError - }) - } - }); - } -} - -describe('HTTP Server & Client basic', function () { - it('implement API manually', async function () { - let server = new HttpServer(getProto(), { - logger: serverLogger, - debugBuf: true - }); - - - server.implementApi('Test', ApiTest); - server.implementApi('a/b/c/Test', ApiAbcTest); - - await testApi(server); - - - }) - - it('extend call in handler', function () { - let server = new HttpServer(getProto(), { - logger: serverLogger, - debugBuf: true - }); - - type MyApiCall = ApiCall & { - value1?: string; - value2: string; - } - type MyMsgCall = MsgCall & { - value1?: string; - value2: string; - } - - server.implementApi('Test', (call: MyApiCall) => { - call.value1 = 'xxx'; - call.value2 = 'xxx'; - }); - server.listenMsg('Chat', (call: MyMsgCall) => { - call.msg.content; - call.value1 = 'xxx'; - call.value2 = 'xxx'; - }) - }) - - it('extend call in flow', function () { - let server = new HttpServer(getProto(), { - logger: serverLogger, - debugBuf: true - }); - - type MyApiCall = ApiCall & { - value1?: string; - value2: string; - } - type MyMsgCall = MsgCall & { - value1?: string; - value2: string; - } - type MyConn = HttpConnection & { - currentUser: { - uid: string, - nickName: string - } - } - - server.flows.postConnectFlow.push((conn: MyConn) => { - conn.currentUser.nickName = 'asdf'; - return conn; - }); - server.flows.postConnectFlow.exec(null as any as MyConn, console); - server.flows.preApiCallFlow.push((call: MyApiCall) => { - call.value2 = 'x'; - return call; - }); - server.flows.preSendMsgFlow.push((call: MyMsgCall) => { - call.value2 = 'f'; - return call; - }) - }) - - it('autoImplementApi', async function () { - let server = new HttpServer(getProto(), { - logger: serverLogger, - apiTimeout: 5000 - }); - - await server.autoImplementApi(path.resolve(__dirname, '../api')) - - await testApi(server); - }); - - it('autoImplementApi delay', async function () { - let server = new HttpServer(getProto(), { - logger: serverLogger, - apiTimeout: 5000 - }); - - server.autoImplementApi(path.resolve(__dirname, '../api'), true) - - await testApi(server); - }); - - it('error', async function () { - let server = new HttpServer(getProto(), { - logger: serverLogger - }); - - - let ret = await server.inputJSON('TesASFt' as any, { name: 'xx' } as any); - console.log(ret); - assert.strictEqual(ret.isSucc, false); - assert.strictEqual(ret.err?.message, 'Invalid service name: TesASFt'); - assert.strictEqual(ret.err?.code, 'INPUT_DATA_ERR'); - assert.strictEqual(ret.err?.type, TsrpcErrorType.ServerError); - }) - - it('server timeout', async function () { - let server = new HttpServer(getProto(), { - logger: serverLogger, - apiTimeout: 100 - }); - server.implementApi('Test', call => { - return new Promise(rs => { - setTimeout(() => { - call.req && call.succ({ - reply: 'Hi, ' + call.req.name - }); - rs(); - }, 200) - }) - }) - - - let ret = await server.inputJSON('Test', { name: 'Jack' }); - assert.deepStrictEqual(ret, { - isSucc: false, - err: { - ...new TsrpcError('Server Timeout', { - code: 'SERVER_TIMEOUT', - type: TsrpcErrorType.ServerError - }) - } - }); - - - }); - - it('Graceful stop', async function () { - let server = new HttpServer(getProto(), { - logger: serverLogger - }); - - let reqNum = 0; - server.implementApi('Test', async call => { - if (++reqNum === 10) { - server.gracefulStop(); - } - await new Promise(rs => setTimeout(rs, parseInt(call.req.name))); - call.succ({ reply: 'OK' }); - }); - - - let isStopped = false; - - let succNum = 0; - await Promise.all(Array.from({ length: 10 }, (v, i) => server.inputJSON('Test', { name: '' + (i * 100) }).then((v: any) => { - if (v.res?.reply === 'OK') { - ++succNum; - } - }))) - assert.strictEqual(succNum, 10); - }) -}) - -describe('HTTP Flows', function () { - it('ApiCall flow', async function () { - let server = new HttpServer(getProto(), { - logger: serverLogger - }); - - server.implementApi('Test', async call => { - call.succ({ reply: 'asdgasdgasdgasdg' }); - }); - - server.flows.preApiCallFlow.push(call => { - if (call.req.apiName !== 'ObjId') { - call.req.name = 'Changed' - } - return call; - }); - - server.flows.preApiCallFlow.push(call => { - assert.strictEqual(call.req.name, 'Changed') - call.error('You need login'); - return call; - }); - - let ret = await server.inputJSON('Test', { name: 'xxx' }); - assert.deepStrictEqual(ret, { - isSucc: false, - err: { - ...new TsrpcError('You need login') - } - }) - }); - - it('ApiCall flow break', async function () { - let server = new HttpServer(getProto(), { - logger: serverLogger - }); - - const flowExecResult: { [K in (keyof BaseServer['flows'])]?: boolean } = {}; - - server.implementApi('Test', async call => { - call.succ({ reply: 'asdgasdgasdgasdg' }); - }); - - server.flows.preApiCallFlow.push(call => { - call.error('You need login'); - return undefined; - }); - - let ret = await server.inputJSON('Test', { name: 'xxx' }); - assert.deepStrictEqual(ret, { - isSucc: false, - err: { - ...new TsrpcError('You need login') - } - }) - - - }); - - it('ApiCall flow error', async function () { - let server = new HttpServer(getProto(), { - logger: serverLogger - }); - - const flowExecResult: { [K in (keyof BaseServer['flows'])]?: boolean } = {}; - - server.implementApi('Test', async call => { - call.succ({ reply: 'asdgasdgasdgasdg' }); - }); - - server.flows.preApiCallFlow.push(call => { - throw new Error('ASDFASDF') - }); - - let ret = await server.inputJSON('Test', { name: 'xxx' }); - assert.deepStrictEqual(ret, { - isSucc: false, - err: { - ...new TsrpcError('Internal Server Error', { - type: TsrpcErrorType.ServerError, - innerErr: 'ASDFASDF', - code: 'INTERNAL_ERR' - }) - } - }) - - - }); - - it('server ApiReturn flow', async function () { - let server = new HttpServer(getProto(), { - logger: serverLogger - }); - - const flowExecResult: { [K in (keyof BaseServer['flows'])]?: boolean } = {}; - - server.implementApi('Test', async call => { - call.succ({ reply: 'xxxxxxxxxxxxxxxxxxxx' }); - }); - - server.flows.preApiReturnFlow.push(v => { - flowExecResult.preApiReturnFlow = true; - v.return = { - isSucc: false, - err: { ...new TsrpcError('Ret changed') } - } - return v; - }); - - let ret = await server.inputJSON('Test', { name: 'xxx' }); - assert.strictEqual(flowExecResult.preApiReturnFlow, true); - assert.deepStrictEqual(ret, { - isSucc: false, - err: { ...new TsrpcError('Ret changed') } - }) - - - }); - - it('Extended JSON Types', async function () { - let server = new HttpServer(getProto(), { - logger: serverLogger - }); - await server.autoImplementApi(path.resolve(__dirname, '../api')) - - let buf = new Uint8Array([0, 1, 2, 3, 255, 254, 253, 252]); - let date = new Date('2021/11/17'); - - // ObjectId - let objId1 = new ObjectId(); - let ret = await server.inputJSON('ObjId', { - id1: objId1, - buf: buf, - date: date - }); - assert.deepStrictEqual(ret, { - isSucc: true, - res: { - id2: objId1.toHexString(), - buf: Base64Util.bufferToBase64(buf), - date: date.toJSON() - } - }); - }) -}) \ No newline at end of file diff --git a/test/cases/ws.test.ts b/test/cases/ws.test.ts deleted file mode 100644 index 1f94d1c..0000000 --- a/test/cases/ws.test.ts +++ /dev/null @@ -1,1051 +0,0 @@ -import { ObjectId } from 'bson'; -import { assert } from 'chai'; -import chalk from 'chalk'; -import * as path from "path"; -import { ServiceProto, TsrpcError, TsrpcErrorType } from 'tsrpc-proto'; -import { BaseServer, TerminalColorLogger, TransportDataUtil, WsClientStatus, WsConnection } from '../../src'; -import { WsClient } from '../../src/client/ws/WsClient'; -import { PrefixLogger } from '../../src/server/models/PrefixLogger'; -import { WsServer } from '../../src/server/ws/WsServer'; -import { ApiTest as ApiAbcTest } from '../api/a/b/c/ApiTest'; -import { ApiTest } from '../api/ApiTest'; -import { MsgChat } from '../proto/MsgChat'; -import { serviceProto, ServiceType } from '../proto/serviceProto'; - -const serverLogger = new PrefixLogger({ - prefixs: [chalk.bgGreen.white(' Server ')], - logger: new TerminalColorLogger({ pid: 'Server' }) -}); -const clientLogger = new PrefixLogger({ - prefixs: [chalk.bgBlue.white(' Client ')], - logger: new TerminalColorLogger({ pid: 'Client' }) -}) - -const getProto = () => Object.merge({}, serviceProto) as ServiceProto; - -async function testApi(server: WsServer, client: WsClient) { - // Succ - assert.deepStrictEqual(await client.callApi('Test', { - name: 'Req1' - }), { - isSucc: true, - res: { - reply: 'Test reply: Req1' - } - }); - assert.deepStrictEqual(await client.callApi('a/b/c/Test', { - name: 'Req2' - }), { - isSucc: true, - res: { - reply: 'a/b/c/Test reply: Req2' - } - }); - - // Inner error - for (let v of ['Test', 'a/b/c/Test']) { - let ret = await client.callApi(v as any, { - name: 'InnerError' - }); - delete ret.err!.innerErr.stack; - - assert.deepStrictEqual(ret, { - isSucc: false, - err: new TsrpcError('Internal Server Error', { - code: 'INTERNAL_ERR', - type: TsrpcErrorType.ServerError, - innerErr: `${v} InnerError` - }) - }); - } - - // TsrpcError - for (let v of ['Test', 'a/b/c/Test']) { - let ret = await client.callApi(v as any, { - name: 'TsrpcError' - }); - assert.deepStrictEqual(ret, { - isSucc: false, - err: new TsrpcError(`${v} TsrpcError`, { - code: 'CODE_TEST', - type: TsrpcErrorType.ApiError, - info: 'ErrInfo ' + v - }) - }); - } - - // call.error - for (let v of ['Test', 'a/b/c/Test']) { - let ret = await client.callApi(v as any, { - name: 'error' - }); - assert.deepStrictEqual(ret, { - isSucc: false, - err: new TsrpcError('Got an error', { - type: TsrpcErrorType.ApiError - }) - }); - } -} - -describe('WS Server & Client basic', function () { - it('cannot callApi before connect', async function () { - let client = new WsClient(getProto(), { - logger: clientLogger, - debugBuf: true - }) - let res = await client.callApi('Test', { name: 'xxx' }); - assert.deepStrictEqual(res, { - isSucc: false, - err: new TsrpcError('WebSocket is not connected', { - code: 'WS_NOT_OPEN', - type: TsrpcErrorType.ClientError - }) - }) - }) - - it('implement API manually', async function () { - let server = new WsServer(getProto(), { - logger: serverLogger, - debugBuf: true - }); - await server.start(); - - server.implementApi('Test', ApiTest); - server.implementApi('a/b/c/Test', ApiAbcTest); - - let client = new WsClient(getProto(), { - logger: clientLogger, - debugBuf: true - }) - await client.connect(); - - await testApi(server, client); - - await server.stop(); - }) - - it('extend conn', function () { - let server = new WsServer(getProto(), { - logger: serverLogger, - debugBuf: true - }); - type MyConn = WsConnection & { - sessionData: { - value: string; - } - } - server.flows.postConnectFlow.push((conn: MyConn) => { - conn.sessionData.value = 'zxcdv'; - return conn; - }) - }) - - it('autoImplementApi', async function () { - let server = new WsServer(getProto(), { - logger: serverLogger, - apiTimeout: 5000 - }); - await server.start(); - - server.autoImplementApi(path.resolve(__dirname, '../api')) - - let client = new WsClient(getProto(), { - logger: clientLogger - }); - await client.connect(); - - await testApi(server, client); - - await server.stop(); - }); - - it('sendMsg', async function () { - let server = new WsServer(getProto(), { - port: 3001, - logger: serverLogger, - // debugBuf: true - }); - - await server.start(); - - let client = new WsClient(getProto(), { - server: 'ws://127.0.0.1:3001', - logger: clientLogger, - // debugBuf: true - }); - await client.connect(); - - return new Promise(rs => { - let msg: MsgChat = { - channel: 123, - userName: 'fff', - content: '666', - time: Date.now() - }; - - server.listenMsg('Chat', async v => { - assert.deepStrictEqual(v.msg, msg); - await server.stop(); - rs(); - }); - - client.sendMsg('Chat', msg); - }) - }); - - it('server send msg', async function () { - let server = new WsServer(getProto(), { - port: 3001, - logger: serverLogger, - // debugBuf: true - }); - - await server.start(); - - let client = new WsClient(getProto(), { - server: 'ws://127.0.0.1:3001', - logger: clientLogger, - // debugBuf: true - }); - await client.connect(); - - return new Promise(rs => { - let msg: MsgChat = { - channel: 123, - userName: 'fff', - content: '666', - time: Date.now() - }; - - client.listenMsg('Chat', async msg1 => { - assert.deepStrictEqual(msg1, msg); - await server.stop(); - rs(); - }); - - server.connections[0].sendMsg('Chat', msg); - }) - }); - - it('listen msg by regexp', async function () { - let server = new WsServer(getProto(), { - port: 3001, - logger: serverLogger, - // debugBuf: true - }); - - await server.start(); - - let client = new WsClient(getProto(), { - server: 'ws://127.0.0.1:3001', - logger: clientLogger, - // debugBuf: true - }); - await client.connect(); - - return new Promise(rs => { - let msg: MsgChat = { - channel: 123, - userName: 'fff', - content: '666', - time: Date.now() - }; - - client.listenMsg(/.*/, async (msg1, msgName: string) => { - assert.deepStrictEqual(msg1, msg); - assert.deepStrictEqual(msgName, 'Chat'); - await server.stop(); - rs(); - }); - - server.connections[0].sendMsg('Chat', msg); - }) - }); - - it('server broadcast msg', async function () { - let server = new WsServer(getProto(), { - port: 3001, - logger: serverLogger, - // debugBuf: true - }); - - await server.start(); - - let client1 = new WsClient(getProto(), { - server: 'ws://127.0.0.1:3001', - logger: clientLogger, - // debugBuf: true - }); - let client2 = new WsClient(getProto(), { - server: 'ws://127.0.0.1:3001', - logger: clientLogger, - // debugBuf: true - }); - await client1.connect(); - await client2.connect(); - - let msg: MsgChat = { - channel: 123, - userName: 'fff', - content: '666', - time: Date.now() - }; - - await new Promise(rs => { - let recvClients: WsClient[] = []; - let msgHandler = async (client: WsClient, msg1: MsgChat, msgName: string) => { - recvClients.push(client); - assert.deepStrictEqual(msg1, msg); - assert.deepStrictEqual(msgName, 'Chat') - if (recvClients.some(v => v === client1) && recvClients.some(v => v === client2)) { - client1.unlistenMsgAll('Chat'); - client2.unlistenMsgAll('Chat'); - rs(); - } - } - - client1.listenMsg('Chat', msgHandler.bind(null, client1)); - client2.listenMsg('Chat', msgHandler.bind(null, client2)); - - server.broadcastMsg('Chat', msg); - }) - - await new Promise(rs => { - let recvClients: WsClient[] = []; - let msgHandler = async (client: WsClient, msg1: MsgChat, msgName: string) => { - recvClients.push(client); - assert.deepStrictEqual(msg1, msg); - assert.deepStrictEqual(msgName, 'Chat'); - if (recvClients.some(v => v === client1) && recvClients.some(v => v === client2)) { - await server.stop(); - rs(); - } - } - - client1.listenMsg('Chat', msgHandler.bind(null, client1)); - client2.listenMsg('Chat', msgHandler.bind(null, client2)); - - server.broadcastMsg('Chat', msg, server.connections.slice()); - }) - }) - - it('abort', async function () { - let server = new WsServer(getProto(), { - logger: serverLogger - }); - await server.start(); - - server.autoImplementApi(path.resolve(__dirname, '../api')) - - let client = new WsClient(getProto(), { - logger: clientLogger - }); - await client.connect(); - - let result: any | undefined; - let promise = client.callApi('Test', { name: 'aaaaaaaa' }); - let sn = client.lastSN; - setTimeout(() => { - client.abort(sn) - }, 10); - promise.then(v => { - result = v; - }); - - await new Promise(rs => { - setTimeout(() => { - assert.strictEqual(result, undefined); - rs(); - }, 150) - }) - - await server.stop(); - }); - - it('pendingApis', async function () { - let server = new WsServer(getProto(), { - logger: serverLogger - }); - await server.start(); - - server.autoImplementApi(path.resolve(__dirname, '../api')) - - let client = new WsClient(getProto(), { - logger: clientLogger - }); - await client.connect(); - - for (let i = 0; i < 10; ++i) { - let promise = Promise.all(Array.from({ length: 10 }, () => new Promise(rs => { - let name = ['Req', 'InnerError', 'TsrpcError', 'error'][Math.random() * 4 | 0]; - let ret: any | undefined; - let promise = client.callApi('Test', { name: name }); - let sn = client.lastSN; - let abort = Math.random() > 0.5; - if (abort) { - setTimeout(() => { - client.abort(sn) - }, 0); - } - promise.then(v => { - ret = v; - }); - - setTimeout(() => { - client.logger?.log('sn', sn, name, abort, ret) - if (abort) { - assert.strictEqual(ret, undefined); - } - else { - assert.notEqual(ret, undefined); - if (name === 'Req') { - assert.strictEqual(ret.isSucc, true); - } - else { - assert.strictEqual(ret.isSucc, false) - } - } - rs(); - }, 300) - }))); - assert.strictEqual(client['_pendingApis'].length, 10); - await promise; - assert.strictEqual(client['_pendingApis'].length, 0); - } - - await server.stop(); - }) - - it('error', async function () { - let server = new WsServer(getProto(), { - logger: serverLogger - }); - await server.start(); - - let client1 = new WsClient(getProto(), { - server: 'ws://localhost:80', - logger: clientLogger - }) - let res = await client1.connect(); - assert.strictEqual(res.isSucc, false); - - let ret = await client1.callApi('Test', { name: 'xx' }); - console.log(ret); - assert.strictEqual(ret.isSucc, false); - assert.strictEqual(ret.err?.code, 'WS_NOT_OPEN'); - assert.strictEqual(ret.err?.type, TsrpcErrorType.ClientError); - - await server.stop(); - }) - - it('server timeout', async function () { - let server = new WsServer(getProto(), { - logger: serverLogger, - apiTimeout: 100 - }); - server.implementApi('Test', call => { - return new Promise(rs => { - setTimeout(() => { - call.req && call.succ({ - reply: 'Hi, ' + call.req.name - }); - rs(); - }, 200) - }) - }) - await server.start(); - - let client = new WsClient(getProto(), { - logger: clientLogger - }); - await client.connect(); - let ret = await client.callApi('Test', { name: 'Jack' }); - assert.deepStrictEqual(ret, { - isSucc: false, - err: new TsrpcError('Server Timeout', { - code: 'SERVER_TIMEOUT', - type: TsrpcErrorType.ServerError - }) - }); - - await server.stop(); - }); - - it('client timeout', async function () { - let server1 = new WsServer(getProto(), { - logger: serverLogger - }); - server1.implementApi('Test', call => { - return new Promise(rs => { - setTimeout(() => { - call.succ({ - reply: 'Hello, ' + call.req.name - }); - rs(); - }, 2000) - }) - }) - await server1.start(); - - let client = new WsClient(getProto(), { - timeout: 100, - logger: clientLogger - }); - await client.connect(); - - let ret = await client.callApi('Test', { name: 'Jack123' }); - // SERVER TIMEOUT的call还没执行完,但是call却被放入Pool了,导致这个BUG - assert.deepStrictEqual(ret, { - isSucc: false, - err: new TsrpcError({ - message: 'Request Timeout', - code: 'TIMEOUT', - type: TsrpcErrorType.NetworkError - }) - }); - await server1.stop(); - }); - - it('Graceful stop', async function () { - let server = new WsServer(getProto(), { - logger: serverLogger - }); - - let reqNum = 0; - server.implementApi('Test', async call => { - if (++reqNum === 10) { - server.gracefulStop(); - } - await new Promise(rs => setTimeout(rs, parseInt(call.req.name))); - call.succ({ reply: 'OK' }); - }); - - await server.start(); - let isStopped = false; - - let client = new WsClient(getProto(), { - logger: clientLogger - }); - await client.connect(); - - let succNum = 0; - await Promise.all(Array.from({ length: 10 }, (v, i) => client.callApi('Test', { name: '' + (i * 100) }).then(v => { - console.log('xxx', v) - if (v.res?.reply === 'OK') { - ++succNum; - } - }))) - assert.strictEqual(succNum, 10); - }) - - it('Client heartbeat works', async function () { - let server = new WsServer(getProto(), { - port: 3001, - logger: serverLogger, - debugBuf: true - }); - await server.start(); - - let client = new WsClient(getProto(), { - server: 'ws://127.0.0.1:3001', - logger: clientLogger, - heartbeat: { - interval: 1000, - timeout: 1000 - }, - debugBuf: true - }); - await client.connect(); - - await new Promise(rs => { setTimeout(rs, 2000) }); - client.logger?.log('lastHeartbeatLatency', client.lastHeartbeatLatency); - assert.strictEqual(client.status, WsClientStatus.Opened) - assert.ok(client.lastHeartbeatLatency > 0); - - await client.disconnect(); - await server.stop(); - }) - - it('Client heartbeat error', async function () { - let server = new WsServer(getProto(), { - port: 3001, - logger: serverLogger, - debugBuf: true - }); - await server.start(); - - let client = new WsClient(getProto(), { - server: 'ws://127.0.0.1:3001', - logger: clientLogger, - heartbeat: { - interval: 1000, - timeout: 1000 - }, - debugBuf: true - }); - - let disconnectFlowData: { isManual?: boolean } | undefined; - client.flows.postDisconnectFlow.push(v => { - disconnectFlowData = {} - return v; - }) - - await client.connect(); - - const temp = TransportDataUtil.HeartbeatPacket; - (TransportDataUtil as any).HeartbeatPacket = new Uint8Array([0, 0]); - - await new Promise(rs => { setTimeout(rs, 2000) }); - client.logger?.log('lastHeartbeatLatency', client.lastHeartbeatLatency); - assert.strictEqual(client.status, WsClientStatus.Closed) - assert.deepStrictEqual(disconnectFlowData, {}) - - await client.disconnect(); - await server.stop(); - (TransportDataUtil as any).HeartbeatPacket = temp; - }) - - it('Server heartbeat kick', async function () { - let server = new WsServer(getProto(), { - port: 3001, - logger: serverLogger, - debugBuf: true, - heartbeatWaitTime: 1000 - }); - await server.start(); - - let client = new WsClient(getProto(), { - server: 'ws://127.0.0.1:3001', - logger: clientLogger, - debugBuf: true - }); - - let disconnectFlowData: { isManual?: boolean } | undefined; - client.flows.postDisconnectFlow.push(v => { - disconnectFlowData = {} - return v; - }) - - await client.connect(); - - await new Promise(rs => { setTimeout(rs, 2000) }); - assert.strictEqual(client.status, WsClientStatus.Closed) - assert.deepStrictEqual(disconnectFlowData, {}) - - await client.disconnect(); - await server.stop(); - }) -}) - -describe('WS Flows', function () { - it('Server conn flow', async function () { - let server = new WsServer(getProto(), { - logger: serverLogger - }); - - const flowExecResult: { [K in (keyof BaseServer['flows'])]?: boolean } = {}; - - server.implementApi('Test', async call => { - assert.strictEqual((call.conn as any).xxxx, 'asdfasdf') - assert.strictEqual(flowExecResult.postConnectFlow, true); - assert.strictEqual(flowExecResult.postDisconnectFlow, undefined); - call.succ({ reply: 'ok' }); - assert.strictEqual(flowExecResult.postDisconnectFlow, undefined); - }); - - server.flows.postConnectFlow.push(v => { - flowExecResult.postConnectFlow = true; - (v as any).xxxx = 'asdfasdf'; - return v; - }); - server.flows.postDisconnectFlow.push(v => { - server.logger.log('server postDisconnectFlow') - flowExecResult.postDisconnectFlow = true; - return v; - }) - - await server.start(); - - assert.strictEqual(flowExecResult.postConnectFlow, undefined); - assert.strictEqual(flowExecResult.postDisconnectFlow, undefined); - - let client = new WsClient(getProto(), { - logger: clientLogger - }); - await client.connect(); - await client.callApi('Test', { name: 'xxx' }); - assert.strictEqual(flowExecResult.postConnectFlow, true); - await server.stop(); - assert.strictEqual(flowExecResult.postDisconnectFlow, true); - }) - - it('Buffer enc/dec flow', async function () { - let server = new WsServer(getProto(), { - logger: serverLogger, - debugBuf: true - }); - - const flowExecResult: { [key: string]: boolean } = {}; - - server.implementApi('Test', async call => { - call.succ({ reply: 'Enc&Dec' }); - }); - - server.flows.preRecvBufferFlow.push(v => { - flowExecResult.preRecvBufferFlow = true; - for (let i = 0; i < v.buf.length; ++i) { - v.buf[i] ^= 128; - } - return v; - }); - server.flows.preSendBufferFlow.push(v => { - flowExecResult.preSendBufferFlow = true; - for (let i = 0; i < v.buf.length; ++i) { - v.buf[i] ^= 128; - } - return v; - }) - - await server.start(); - - let client = new WsClient(getProto(), { - logger: clientLogger, - debugBuf: true - }); - await client.connect(); - - client.flows.preSendBufferFlow.push(v => { - flowExecResult.client_preSendBufferFlow = true; - for (let i = 0; i < v.buf.length; ++i) { - v.buf[i] ^= 128; - } - return v; - }); - - client.flows.preRecvBufferFlow.push(v => { - flowExecResult.client_preRecvBufferFlow = true; - for (let i = 0; i < v.buf.length; ++i) { - v.buf[i] ^= 128; - } - return v; - }); - - let ret = await client.callApi('Test', { name: 'xxx' }); - assert.strictEqual(flowExecResult.client_preSendBufferFlow, true); - assert.strictEqual(flowExecResult.client_preRecvBufferFlow, true); - assert.strictEqual(flowExecResult.preRecvBufferFlow, true); - assert.strictEqual(flowExecResult.preSendBufferFlow, true); - assert.deepStrictEqual(ret, { - isSucc: true, - res: { - reply: 'Enc&Dec' - } - }) - - await server.stop(); - }); - - it('ApiCall flow', async function () { - let server = new WsServer(getProto(), { - logger: serverLogger - }); - - const flowExecResult: { [K in (keyof BaseServer['flows'])]?: boolean } = {}; - - server.implementApi('Test', async call => { - call.succ({ reply: 'asdgasdgasdgasdg' }); - }); - - server.flows.preApiCallFlow.push(call => { - assert.strictEqual(call.req.name, 'Changed') - call.error('You need login'); - return call; - }); - server.flows.postApiCallFlow.push(v => { - flowExecResult.postApiCallFlow = true; - return v; - }) - - await server.start(); - - let client = new WsClient(getProto(), { - logger: clientLogger - }); - await client.connect(); - - client.flows.preCallApiFlow.push(v => { - if (v.apiName !== 'ObjId') { - v.req.name = 'Changed' - } - return v; - }); - - let ret = await client.callApi('Test', { name: 'xxx' }); - assert.strictEqual(flowExecResult.postApiCallFlow, true); - assert.deepStrictEqual(ret, { - isSucc: false, - err: new TsrpcError('You need login') - }) - - await server.stop(); - }); - - it('ApiCall flow break', async function () { - let server = new WsServer(getProto(), { - logger: serverLogger - }); - - const flowExecResult: { [K in (keyof BaseServer['flows'])]?: boolean } = {}; - - server.implementApi('Test', async call => { - call.succ({ reply: 'asdgasdgasdgasdg' }); - }); - - server.flows.preApiCallFlow.push(call => { - assert.strictEqual(call.req.name, 'Changed') - call.error('You need login'); - return undefined; - }); - server.flows.postApiCallFlow.push(v => { - flowExecResult.postApiCallFlow = true; - return v; - }) - - await server.start(); - - let client = new WsClient(getProto(), { - logger: clientLogger - }); - await client.connect(); - - client.flows.preCallApiFlow.push(v => { - if (v.apiName !== 'ObjId') { - v.req.name = 'Changed' - } - return v; - }); - - let ret = await client.callApi('Test', { name: 'xxx' }); - assert.strictEqual(flowExecResult.postApiCallFlow, undefined); - assert.deepStrictEqual(ret, { - isSucc: false, - err: new TsrpcError('You need login') - }) - - await server.stop(); - }); - - it('ApiCall flow error', async function () { - let server = new WsServer(getProto(), { - logger: serverLogger - }); - - const flowExecResult: { [K in (keyof BaseServer['flows'])]?: boolean } = {}; - - server.implementApi('Test', async call => { - call.succ({ reply: 'asdgasdgasdgasdg' }); - }); - - server.flows.preApiCallFlow.push(call => { - assert.strictEqual(call.req.name, 'Changed') - throw new Error('ASDFASDF') - }); - server.flows.postApiCallFlow.push(v => { - flowExecResult.postApiCallFlow = true; - return v; - }) - - await server.start(); - - let client = new WsClient(getProto(), { - logger: clientLogger - }); - await client.connect(); - - client.flows.preCallApiFlow.push(v => { - if (v.apiName !== 'ObjId') { - v.req.name = 'Changed' - } - return v; - }); - - let ret = await client.callApi('Test', { name: 'xxx' }); - assert.strictEqual(flowExecResult.postApiCallFlow, undefined); - assert.deepStrictEqual(ret, { - isSucc: false, - err: new TsrpcError('Internal Server Error', { - type: TsrpcErrorType.ServerError, - innerErr: 'ASDFASDF', - code: 'INTERNAL_ERR' - }) - }) - - await server.stop(); - }); - - it('server ApiReturn flow', async function () { - let server = new WsServer(getProto(), { - logger: serverLogger - }); - - const flowExecResult: { [K in (keyof BaseServer['flows'])]?: boolean } = {}; - - server.implementApi('Test', async call => { - call.succ({ reply: 'xxxxxxxxxxxxxxxxxxxx' }); - }); - - server.flows.preApiReturnFlow.push(v => { - flowExecResult.preApiReturnFlow = true; - v.return = { - isSucc: false, - err: new TsrpcError('Ret changed') - } - return v; - }); - server.flows.postApiReturnFlow.push(v => { - flowExecResult.postApiReturnFlow = true; - v.call.logger.log('RETTT', v.return); - return v; - }) - - await server.start(); - - let client = new WsClient(getProto(), { - logger: clientLogger - }); - await client.connect(); - - let ret = await client.callApi('Test', { name: 'xxx' }); - assert.strictEqual(flowExecResult.preApiReturnFlow, true); - assert.strictEqual(flowExecResult.postApiReturnFlow, true); - assert.deepStrictEqual(ret, { - isSucc: false, - err: new TsrpcError('Ret changed') - }) - - await server.stop(); - }); - - it('client ApiReturn flow', async function () { - let server = new WsServer(getProto(), { - logger: serverLogger - }); - - const flowExecResult: { [K in (keyof WsClient['flows'])]?: boolean } = {}; - - server.implementApi('Test', async call => { - call.succ({ reply: 'xxxxxxxxxxxxxxxxxxxx' }); - }); - - await server.start(); - - let client = new WsClient(getProto(), { - logger: clientLogger - }); - await client.connect(); - - client.flows.preApiReturnFlow.push(v => { - flowExecResult.preApiReturnFlow = true; - v.return = { - isSucc: false, - err: new TsrpcError('Ret changed') - } - return v; - }); - client.flows.postApiReturnFlow.push(v => { - flowExecResult.postApiReturnFlow = true; - client.logger?.log('RETTT', v.return); - return v; - }) - - let ret = await client.callApi('Test', { name: 'xxx' }); - assert.strictEqual(flowExecResult.preApiReturnFlow, true); - assert.strictEqual(flowExecResult.postApiReturnFlow, true); - assert.deepStrictEqual(ret, { - isSucc: false, - err: new TsrpcError('Ret changed') - }) - - await server.stop(); - }); - - it('client SendBufferFlow prevent', async function () { - let server = new WsServer(getProto(), { - logger: serverLogger - }); - - // const flowExecResult: { [K in (keyof BaseClient['flows'])]?: boolean } = {}; - - server.implementApi('Test', async call => { - call.succ({ reply: 'xxxxxxxxxxxxxxxxxxxx' }); - }); - - await server.start(); - - let client = new WsClient(getProto(), { - logger: clientLogger - }); - await client.connect(); - - client.flows.preSendBufferFlow.push(v => { - return undefined - }); - - let ret: any; - client.callApi('Test', { name: 'xxx' }).then(v => { ret = v }); - await new Promise(rs => { setTimeout(rs, 200) }); - assert.strictEqual(ret, undefined) - - await server.stop(); - }); - - it('onInputBufferError', async function () { - let server = new WsServer(getProto(), { - logger: serverLogger - }); - await server.start(); - - let client = new WsClient(getProto(), { - logger: clientLogger - }); - await client.connect(); - client.flows.preSendBufferFlow.push(v => { - for (let i = 0; i < v.buf.length; ++i) { - v.buf[i] += 1; - } - return v; - }); - - let ret = await client.callApi('Test', { name: 'XXX' }); - assert.deepStrictEqual(ret, { - isSucc: false, - err: new TsrpcError('Invalid request buffer, please check the version of service proto.', { type: TsrpcErrorType.NetworkError, code: 'LOST_CONN' }) - }) - - await server.stop(); - }) - - it('ObjectId', async function () { - let server = new WsServer(getProto(), { - logger: serverLogger - }); - server.autoImplementApi(path.resolve(__dirname, '../api')) - await server.start(); - - let client = new WsClient(getProto(), { - logger: clientLogger - }); - await client.connect(); - - // ObjectId - let objId1 = new ObjectId(); - let ret = await client.callApi('ObjId', { - id1: objId1 - }); - assert.strictEqual(ret.isSucc, true, ret.err?.message); - assert.strictEqual(objId1.toString(), ret.res!.id2.toString()); - - await server.stop(); - }) -}) \ No newline at end of file diff --git a/test/cases/wsJSON.test.ts b/test/cases/wsJSON.test.ts deleted file mode 100644 index 3afe27b..0000000 --- a/test/cases/wsJSON.test.ts +++ /dev/null @@ -1,1278 +0,0 @@ -import { ObjectId } from 'bson'; -import { assert } from 'chai'; -import chalk from 'chalk'; -import * as path from "path"; -import { ServiceProto, TsrpcError, TsrpcErrorType } from 'tsrpc-proto'; -import { BaseServer, TerminalColorLogger, TransportDataUtil, WsClientStatus, WsConnection } from '../../src'; -import { WsClient } from '../../src/client/ws/WsClient'; -import { PrefixLogger } from '../../src/server/models/PrefixLogger'; -import { WsServer } from '../../src/server/ws/WsServer'; -import { ApiTest as ApiAbcTest } from '../api/a/b/c/ApiTest'; -import { ApiTest } from '../api/ApiTest'; -import { MsgChat } from '../proto/MsgChat'; -import { serviceProto, ServiceType } from '../proto/serviceProto'; - -const serverLogger = new PrefixLogger({ - prefixs: [chalk.bgGreen.white(' Server ')], - logger: new TerminalColorLogger({ pid: 'Server' }) -}); -const clientLogger = new PrefixLogger({ - prefixs: [chalk.bgBlue.white(' Client ')], - logger: new TerminalColorLogger({ pid: 'Client' }) -}) - -const getProto = () => Object.merge({}, serviceProto) as ServiceProto; - -async function testApi(server: WsServer, client: WsClient) { - // Succ - assert.deepStrictEqual(await client.callApi('Test', { - name: 'Req1' - }), { - isSucc: true, - res: { - reply: 'Test reply: Req1' - } - }); - assert.deepStrictEqual(await client.callApi('a/b/c/Test', { - name: 'Req2' - }), { - isSucc: true, - res: { - reply: 'a/b/c/Test reply: Req2' - } - }); - - // Inner error - for (let v of ['Test', 'a/b/c/Test']) { - let ret = await client.callApi(v as any, { - name: 'InnerError' - }); - delete ret.err!.innerErr.stack; - - assert.deepStrictEqual(ret, { - isSucc: false, - err: new TsrpcError('Internal Server Error', { - code: 'INTERNAL_ERR', - type: TsrpcErrorType.ServerError, - innerErr: `${v} InnerError` - }) - }); - } - - // TsrpcError - for (let v of ['Test', 'a/b/c/Test']) { - let ret = await client.callApi(v as any, { - name: 'TsrpcError' - }); - assert.deepStrictEqual(ret, { - isSucc: false, - err: new TsrpcError(`${v} TsrpcError`, { - code: 'CODE_TEST', - type: TsrpcErrorType.ApiError, - info: 'ErrInfo ' + v - }) - }); - } - - // call.error - for (let v of ['Test', 'a/b/c/Test']) { - let ret = await client.callApi(v as any, { - name: 'error' - }); - assert.deepStrictEqual(ret, { - isSucc: false, - err: new TsrpcError('Got an error', { - type: TsrpcErrorType.ApiError - }) - }); - } -} - -describe('WS Server & Client basic', function () { - it('cannot callApi before connect', async function () { - let client = new WsClient(getProto(), { - json: true, - logger: clientLogger, - debugBuf: true - }) - let res = await client.callApi('Test', { name: 'xxx' }); - assert.deepStrictEqual(res, { - isSucc: false, - err: new TsrpcError('WebSocket is not connected', { - code: 'WS_NOT_OPEN', - type: TsrpcErrorType.ClientError - }) - }) - }) - - it('implement API manually', async function () { - let server = new WsServer(getProto(), { - json: true, - logger: serverLogger, - debugBuf: true - }); - await server.start(); - - server.implementApi('Test', ApiTest); - server.implementApi('a/b/c/Test', ApiAbcTest); - - let client = new WsClient(getProto(), { - json: true, - logger: clientLogger, - debugBuf: true - }) - assert.ok((await client.connect()).isSucc); - - await testApi(server, client); - - await server.stop(); - }) - - it('extend conn', function () { - let server = new WsServer(getProto(), { - json: true, - logger: serverLogger, - debugBuf: true - }); - type MyConn = WsConnection & { - sessionData: { - value: string; - } - } - server.flows.postConnectFlow.push((conn: MyConn) => { - conn.sessionData.value = 'zxcdv'; - return conn; - }) - }) - - it('autoImplementApi', async function () { - let server = new WsServer(getProto(), { - json: true, - logger: serverLogger, - apiTimeout: 5000 - }); - await server.start(); - - server.autoImplementApi(path.resolve(__dirname, '../api')) - - let client = new WsClient(getProto(), { - json: true, - logger: clientLogger - }); - await client.connect(); - - await testApi(server, client); - - await server.stop(); - }); - - it('Client use buffer when server is `json: true`', async function () { - let server = new WsServer(getProto(), { - json: true, - logger: serverLogger, - apiTimeout: 5000 - }); - await server.start(); - - server.autoImplementApi(path.resolve(__dirname, '../api')) - - let client = new WsClient(getProto(), { - json: false, - logger: clientLogger - }); - await client.connect(); - - await testApi(server, client); - - await server.stop(); - }) - - it('Client use JSON when server is `json: false`', async function () { - let server = new WsServer(getProto(), { - json: false, - logger: serverLogger, - apiTimeout: 5000 - }); - await server.start(); - - server.autoImplementApi(path.resolve(__dirname, '../api')) - - let client = new WsClient(getProto(), { - json: true, - logger: clientLogger - }); - await client.connect(); - - let isErr = false; - await testApi(server, client).catch(() => { isErr = true }); - assert.strictEqual(isErr, true); - - await server.stop(); - }) - - it('sendMsg', async function () { - let server = new WsServer(getProto(), { - json: true, - port: 3001, - logger: serverLogger, - // debugBuf: true - }); - - await server.start(); - - let client = new WsClient(getProto(), { - json: true, - server: 'ws://127.0.0.1:3001', - logger: clientLogger, - // debugBuf: true - }); - await client.connect(); - - return new Promise(rs => { - let msg: MsgChat = { - channel: 123, - userName: 'fff', - content: '666', - time: Date.now() - }; - - server.listenMsg('Chat', async v => { - assert.deepStrictEqual(v.msg, msg); - await server.stop(); - rs(); - }); - - client.sendMsg('Chat', msg); - }) - }); - - it('server send msg', async function () { - let server = new WsServer(getProto(), { - json: true, - port: 3001, - logger: serverLogger, - // debugBuf: true - }); - - await server.start(); - - let client = new WsClient(getProto(), { - json: true, - server: 'ws://127.0.0.1:3001', - logger: clientLogger, - // debugBuf: true - }); - await client.connect(); - - return new Promise(rs => { - let msg: MsgChat = { - channel: 123, - userName: 'fff', - content: '666', - time: Date.now() - }; - - client.listenMsg('Chat', async msg1 => { - assert.deepStrictEqual(msg1, msg); - await server.stop(); - rs(); - }); - - server.connections[0].sendMsg('Chat', msg); - }) - }); - - it('listen msg by regexp', async function () { - let server = new WsServer(getProto(), { - json: true, - port: 3001, - logger: serverLogger, - // debugBuf: true - }); - - await server.start(); - - let client = new WsClient(getProto(), { - json: true, - server: 'ws://127.0.0.1:3001', - logger: clientLogger, - // debugBuf: true - }); - await client.connect(); - - return new Promise(rs => { - let msg: MsgChat = { - channel: 123, - userName: 'fff', - content: '666', - time: Date.now() - }; - - client.listenMsg(/.*/, async (msg1, msgName: string) => { - assert.deepStrictEqual(msg1, msg); - assert.deepStrictEqual(msgName, 'Chat'); - await server.stop(); - rs(); - }); - - server.connections[0].sendMsg('Chat', msg); - }) - }); - - it('server broadcast msg', async function () { - let server = new WsServer(getProto(), { - json: true, - port: 3001, - logger: serverLogger, - // debugBuf: true - }); - - await server.start(); - - let client1 = new WsClient(getProto(), { - json: true, - server: 'ws://127.0.0.1:3001', - logger: clientLogger, - // debugBuf: true - }); - let client2 = new WsClient(getProto(), { - json: true, - server: 'ws://127.0.0.1:3001', - logger: clientLogger, - // debugBuf: true - }); - await client1.connect(); - await client2.connect(); - - let msg: MsgChat = { - channel: 123, - userName: 'fff', - content: '666', - time: Date.now() - }; - - await new Promise(rs => { - let recvClients: WsClient[] = []; - let msgHandler = async (client: WsClient, msg1: MsgChat, msgName: string) => { - recvClients.push(client); - assert.deepStrictEqual(msg1, msg); - assert.deepStrictEqual(msgName, 'Chat') - if (recvClients.some(v => v === client1) && recvClients.some(v => v === client2)) { - client1.unlistenMsgAll('Chat'); - client2.unlistenMsgAll('Chat'); - rs(); - } - } - - client1.listenMsg('Chat', msgHandler.bind(null, client1)); - client2.listenMsg('Chat', msgHandler.bind(null, client2)); - - server.broadcastMsg('Chat', msg); - }) - - await new Promise(rs => { - let recvClients: WsClient[] = []; - let msgHandler = async (client: WsClient, msg1: MsgChat, msgName: string) => { - recvClients.push(client); - assert.deepStrictEqual(msg1, msg); - assert.deepStrictEqual(msgName, 'Chat'); - if (recvClients.some(v => v === client1) && recvClients.some(v => v === client2)) { - await server.stop(); - rs(); - } - } - - client1.listenMsg('Chat', msgHandler.bind(null, client1)); - client2.listenMsg('Chat', msgHandler.bind(null, client2)); - - server.broadcastMsg('Chat', msg, server.connections.slice()); - }) - }) - - it('broadcast to both text and buffer client (server: json)', async function () { - let server = new WsServer(getProto(), { - json: true, - port: 3001, - logger: serverLogger, - debugBuf: true - }); - - await server.start(); - - let client1 = new WsClient(getProto(), { - json: true, - server: 'ws://127.0.0.1:3001', - logger: clientLogger, - debugBuf: true - }); - let client2 = new WsClient(getProto(), { - json: false, - server: 'ws://127.0.0.1:3001', - logger: clientLogger, - debugBuf: true - }); - await client1.connect(); - await client2.connect(); - - let msg: MsgChat = { - channel: 123, - userName: 'fff', - content: '666', - time: Date.now() - }; - - await new Promise(rs => { - let recvClients: WsClient[] = []; - let msgHandler = async (client: WsClient, msg1: MsgChat, msgName: string) => { - recvClients.push(client); - assert.deepStrictEqual(msg1, msg); - assert.deepStrictEqual(msgName, 'Chat') - if (recvClients.some(v => v === client1) && recvClients.some(v => v === client2)) { - client1.unlistenMsgAll('Chat'); - client2.unlistenMsgAll('Chat'); - rs(); - } - } - - client1.listenMsg('Chat', msgHandler.bind(null, client1)); - client2.listenMsg('Chat', msgHandler.bind(null, client2)); - - server.broadcastMsg('Chat', msg); - }) - - await new Promise(rs => { - let recvClients: WsClient[] = []; - let msgHandler = async (client: WsClient, msg1: MsgChat, msgName: string) => { - recvClients.push(client); - assert.deepStrictEqual(msg1, msg); - assert.deepStrictEqual(msgName, 'Chat'); - if (recvClients.some(v => v === client1) && recvClients.some(v => v === client2)) { - await server.stop(); - rs(); - } - } - - client1.listenMsg('Chat', msgHandler.bind(null, client1)); - client2.listenMsg('Chat', msgHandler.bind(null, client2)); - - server.broadcastMsg('Chat', msg, server.connections.slice()); - }) - }) - - it('broadcast to both text and buffer client (server: buffer)', async function () { - let server = new WsServer(getProto(), { - json: false, - port: 3001, - logger: serverLogger, - debugBuf: true - }); - - await server.start(); - - let client1 = new WsClient(getProto(), { - json: true, - server: 'ws://127.0.0.1:3001', - logger: clientLogger, - debugBuf: true - }); - let client2 = new WsClient(getProto(), { - json: false, - server: 'ws://127.0.0.1:3001', - logger: clientLogger, - debugBuf: true - }); - await client1.connect(); - await client2.connect(); - - let msg: MsgChat = { - channel: 123, - userName: 'fff', - content: '666', - time: Date.now() - }; - - await new Promise(rs => { - let recvClients: WsClient[] = []; - let msgHandler = async (client: WsClient, msg1: MsgChat, msgName: string) => { - recvClients.push(client); - assert.deepStrictEqual(msg1, msg); - assert.deepStrictEqual(msgName, 'Chat') - if (recvClients.some(v => v === client1) && recvClients.some(v => v === client2)) { - client1.unlistenMsgAll('Chat'); - client2.unlistenMsgAll('Chat'); - rs(); - } - } - - client1.listenMsg('Chat', msgHandler.bind(null, client1)); - client2.listenMsg('Chat', msgHandler.bind(null, client2)); - - server.broadcastMsg('Chat', msg); - }) - - await new Promise(rs => { - let recvClients: WsClient[] = []; - let msgHandler = async (client: WsClient, msg1: MsgChat, msgName: string) => { - recvClients.push(client); - assert.deepStrictEqual(msg1, msg); - assert.deepStrictEqual(msgName, 'Chat'); - if (recvClients.some(v => v === client1) && recvClients.some(v => v === client2)) { - await server.stop(); - rs(); - } - } - - client1.listenMsg('Chat', msgHandler.bind(null, client1)); - client2.listenMsg('Chat', msgHandler.bind(null, client2)); - - server.broadcastMsg('Chat', msg, server.connections.slice()); - }) - }) - - it('abort', async function () { - let server = new WsServer(getProto(), { - json: true, - logger: serverLogger - }); - await server.start(); - - server.autoImplementApi(path.resolve(__dirname, '../api')) - - let client = new WsClient(getProto(), { - json: true, - logger: clientLogger - }); - await client.connect(); - - let result: any | undefined; - let promise = client.callApi('Test', { name: 'aaaaaaaa' }); - let sn = client.lastSN; - setTimeout(() => { - client.abort(sn) - }, 10); - promise.then(v => { - result = v; - }); - - await new Promise(rs => { - setTimeout(() => { - assert.strictEqual(result, undefined); - rs(); - }, 150) - }) - - await server.stop(); - }); - - it('pendingApis', async function () { - let server = new WsServer(getProto(), { - json: true, - logger: serverLogger - }); - await server.start(); - - server.autoImplementApi(path.resolve(__dirname, '../api')) - - let client = new WsClient(getProto(), { - json: true, - logger: clientLogger - }); - await client.connect(); - - for (let i = 0; i < 10; ++i) { - let promise = Promise.all(Array.from({ length: 10 }, () => new Promise(rs => { - let name = ['Req', 'InnerError', 'TsrpcError', 'error'][Math.random() * 4 | 0]; - let ret: any | undefined; - let promise = client.callApi('Test', { name: name }); - let sn = client.lastSN; - let abort = Math.random() > 0.5; - if (abort) { - setTimeout(() => { - client.abort(sn) - }, 0); - } - promise.then(v => { - ret = v; - }); - - setTimeout(() => { - client.logger?.log('sn', sn, name, abort, ret) - if (abort) { - assert.strictEqual(ret, undefined); - } - else { - assert.notEqual(ret, undefined); - if (name === 'Req') { - assert.strictEqual(ret.isSucc, true); - } - else { - assert.strictEqual(ret.isSucc, false) - } - } - rs(); - }, 300) - }))); - assert.strictEqual(client['_pendingApis'].length, 10); - await promise; - assert.strictEqual(client['_pendingApis'].length, 0); - } - - await server.stop(); - }) - - it('error', async function () { - let server = new WsServer(getProto(), { - json: true, - logger: serverLogger - }); - await server.start(); - - let client1 = new WsClient(getProto(), { - json: true, - server: 'ws://localhost:80', - logger: clientLogger - }) - let res = await client1.connect(); - assert.strictEqual(res.isSucc, false); - - let ret = await client1.callApi('Test', { name: 'xx' }); - console.log(ret); - assert.strictEqual(ret.isSucc, false); - assert.strictEqual(ret.err?.code, 'WS_NOT_OPEN'); - assert.strictEqual(ret.err?.type, TsrpcErrorType.ClientError); - - await server.stop(); - }) - - it('server timeout', async function () { - let server = new WsServer(getProto(), { - json: true, - logger: serverLogger, - apiTimeout: 100 - }); - server.implementApi('Test', call => { - return new Promise(rs => { - setTimeout(() => { - call.req && call.succ({ - reply: 'Hi, ' + call.req.name - }); - rs(); - }, 200) - }) - }) - await server.start(); - - let client = new WsClient(getProto(), { - json: true, - logger: clientLogger - }); - await client.connect(); - let ret = await client.callApi('Test', { name: 'Jack' }); - assert.deepStrictEqual(ret, { - isSucc: false, - err: new TsrpcError('Server Timeout', { - code: 'SERVER_TIMEOUT', - type: TsrpcErrorType.ServerError - }) - }); - - await server.stop(); - }); - - it('client timeout', async function () { - let server1 = new WsServer(getProto(), { - json: true, - logger: serverLogger - }); - server1.implementApi('Test', call => { - return new Promise(rs => { - setTimeout(() => { - call.succ({ - reply: 'Hello, ' + call.req.name - }); - rs(); - }, 2000) - }) - }) - await server1.start(); - - let client = new WsClient(getProto(), { - json: true, - timeout: 100, - logger: clientLogger - }); - await client.connect(); - - let ret = await client.callApi('Test', { name: 'Jack123' }); - // SERVER TIMEOUT的call还没执行完,但是call却被放入Pool了,导致这个BUG - assert.deepStrictEqual(ret, { - isSucc: false, - err: new TsrpcError({ - message: 'Request Timeout', - code: 'TIMEOUT', - type: TsrpcErrorType.NetworkError - }) - }); - await server1.stop(); - }); - - it('Graceful stop', async function () { - let server = new WsServer(getProto(), { - json: true, - logger: serverLogger - }); - - let reqNum = 0; - server.implementApi('Test', async call => { - if (++reqNum === 10) { - server.gracefulStop(); - } - await new Promise(rs => setTimeout(rs, parseInt(call.req.name))); - call.succ({ reply: 'OK' }); - }); - - await server.start(); - let isStopped = false; - - let client = new WsClient(getProto(), { - json: true, - logger: clientLogger - }); - await client.connect(); - - let succNum = 0; - await Promise.all(Array.from({ length: 10 }, (v, i) => client.callApi('Test', { name: '' + (i * 100) }).then(v => { - console.log('xxx', v) - if (v.res?.reply === 'OK') { - ++succNum; - } - }))) - assert.strictEqual(succNum, 10); - }) - - it('Client heartbeat works', async function () { - let server = new WsServer(getProto(), { - port: 3001, - logger: serverLogger, - debugBuf: true, - json: true - }); - await server.start(); - - let client = new WsClient(getProto(), { - server: 'ws://127.0.0.1:3001', - logger: clientLogger, - heartbeat: { - interval: 1000, - timeout: 1000 - }, - debugBuf: true, - json: true - }); - await client.connect(); - - await new Promise(rs => { setTimeout(rs, 2000) }); - client.logger?.log('lastHeartbeatLatency', client.lastHeartbeatLatency); - assert.strictEqual(client.status, WsClientStatus.Opened) - assert.ok(client.lastHeartbeatLatency > 0); - - await client.disconnect(); - await server.stop(); - }) - - it('Client heartbeat error', async function () { - let server = new WsServer(getProto(), { - port: 3001, - logger: serverLogger, - debugBuf: true, - json: true - }); - await server.start(); - - let client = new WsClient(getProto(), { - server: 'ws://127.0.0.1:3001', - logger: clientLogger, - heartbeat: { - interval: 1000, - timeout: 1000 - }, - debugBuf: true, - json: true - }); - - let disconnectFlowData: { isManual?: boolean } | undefined; - client.flows.postDisconnectFlow.push(v => { - disconnectFlowData = {} - return v; - }) - - await client.connect(); - - const temp = TransportDataUtil.HeartbeatPacket; - (TransportDataUtil as any).HeartbeatPacket = new Uint8Array([0, 0]); - - await new Promise(rs => { setTimeout(rs, 2000) }); - client.logger?.log('lastHeartbeatLatency', client.lastHeartbeatLatency); - assert.strictEqual(client.status, WsClientStatus.Closed) - assert.deepStrictEqual(disconnectFlowData, {}) - - await client.disconnect(); - await server.stop(); - (TransportDataUtil as any).HeartbeatPacket = temp; - }) - - it('Server heartbeat kick', async function () { - let server = new WsServer(getProto(), { - port: 3001, - logger: serverLogger, - debugBuf: true, - heartbeatWaitTime: 1000, - json: true - }); - await server.start(); - - let client = new WsClient(getProto(), { - server: 'ws://127.0.0.1:3001', - logger: clientLogger, - debugBuf: true, - json: true - }); - - let disconnectFlowData: { isManual?: boolean } | undefined; - client.flows.postDisconnectFlow.push(v => { - disconnectFlowData = {} - return v; - }) - - await client.connect(); - - await new Promise(rs => { setTimeout(rs, 2000) }); - assert.strictEqual(client.status, WsClientStatus.Closed) - assert.deepStrictEqual(disconnectFlowData, {}) - - await client.disconnect(); - await server.stop(); - }) -}) - -describe('WS Flows', function () { - it('Server conn flow', async function () { - let server = new WsServer(getProto(), { - json: true, - logger: serverLogger - }); - - const flowExecResult: { [K in (keyof BaseServer['flows'])]?: boolean } = {}; - - server.implementApi('Test', async call => { - assert.strictEqual((call.conn as any).xxxx, 'asdfasdf') - assert.strictEqual(flowExecResult.postConnectFlow, true); - assert.strictEqual(flowExecResult.postDisconnectFlow, undefined); - call.succ({ reply: 'ok' }); - assert.strictEqual(flowExecResult.postDisconnectFlow, undefined); - }); - - server.flows.postConnectFlow.push(v => { - flowExecResult.postConnectFlow = true; - (v as any).xxxx = 'asdfasdf'; - return v; - }); - server.flows.postDisconnectFlow.push(v => { - server.logger.log('server postDisconnectFlow') - flowExecResult.postDisconnectFlow = true; - return v; - }) - - await server.start(); - - assert.strictEqual(flowExecResult.postConnectFlow, undefined); - assert.strictEqual(flowExecResult.postDisconnectFlow, undefined); - - let client = new WsClient(getProto(), { - json: true, - logger: clientLogger - }); - await client.connect(); - await client.callApi('Test', { name: 'xxx' }); - assert.strictEqual(flowExecResult.postConnectFlow, true); - await server.stop(); - assert.strictEqual(flowExecResult.postDisconnectFlow, true); - }) - - it('Buffer enc/dec flow', async function () { - let server = new WsServer(getProto(), { - json: true, - logger: serverLogger, - debugBuf: true - }); - - const flowExecResult: { [key: string]: boolean } = {}; - - server.implementApi('Test', async call => { - call.succ({ reply: 'Enc&Dec' }); - }); - - server.flows.preRecvDataFlow.push(v => { - flowExecResult.preRecvDataFlow = true; - v.data = (v.data as string).split('').reverse().join(''); - return v; - }); - server.flows.preSendDataFlow.push(v => { - flowExecResult.preSendDataFlow = true; - v.data = (v.data as string).split('').reverse().join(''); - return v; - }) - - await server.start(); - - let client = new WsClient(getProto(), { - json: true, - logger: clientLogger, - debugBuf: true - }); - await client.connect(); - - client.flows.preSendDataFlow.push(v => { - flowExecResult.client_preSendDataFlow = true; - v.data = (v.data as string).split('').reverse().join(''); - return v; - }); - - client.flows.preRecvDataFlow.push(v => { - flowExecResult.client_preRecvDataFlow = true; - v.data = (v.data as string).split('').reverse().join(''); - return v; - }); - - let ret = await client.callApi('Test', { name: 'xxx' }); - assert.strictEqual(flowExecResult.client_preSendDataFlow, true); - assert.strictEqual(flowExecResult.client_preRecvDataFlow, true); - assert.strictEqual(flowExecResult.preRecvDataFlow, true); - assert.strictEqual(flowExecResult.preSendDataFlow, true); - assert.deepStrictEqual(ret, { - isSucc: true, - res: { - reply: 'Enc&Dec' - } - }) - - await server.stop(); - }); - - it('ApiCall flow', async function () { - let server = new WsServer(getProto(), { - json: true, - logger: serverLogger - }); - - const flowExecResult: { [K in (keyof BaseServer['flows'])]?: boolean } = {}; - - server.implementApi('Test', async call => { - call.succ({ reply: 'asdgasdgasdgasdg' }); - }); - - server.flows.preApiCallFlow.push(call => { - assert.strictEqual(call.req.name, 'Changed') - call.error('You need login'); - return call; - }); - server.flows.postApiCallFlow.push(v => { - flowExecResult.postApiCallFlow = true; - return v; - }) - - await server.start(); - - let client = new WsClient(getProto(), { - json: true, - logger: clientLogger - }); - await client.connect(); - - client.flows.preCallApiFlow.push(v => { - if (v.apiName !== 'ObjId') { - v.req.name = 'Changed' - } - return v; - }); - - let ret = await client.callApi('Test', { name: 'xxx' }); - assert.strictEqual(flowExecResult.postApiCallFlow, true); - assert.deepStrictEqual(ret, { - isSucc: false, - err: new TsrpcError('You need login') - }) - - await server.stop(); - }); - - it('ApiCall flow break', async function () { - let server = new WsServer(getProto(), { - json: true, - logger: serverLogger - }); - - const flowExecResult: { [K in (keyof BaseServer['flows'])]?: boolean } = {}; - - server.implementApi('Test', async call => { - call.succ({ reply: 'asdgasdgasdgasdg' }); - }); - - server.flows.preApiCallFlow.push(call => { - assert.strictEqual(call.req.name, 'Changed') - call.error('You need login'); - return undefined; - }); - server.flows.postApiCallFlow.push(v => { - flowExecResult.postApiCallFlow = true; - return v; - }) - - await server.start(); - - let client = new WsClient(getProto(), { - json: true, - logger: clientLogger - }); - await client.connect(); - - client.flows.preCallApiFlow.push(v => { - if (v.apiName !== 'ObjId') { - v.req.name = 'Changed' - } - return v; - }); - - let ret = await client.callApi('Test', { name: 'xxx' }); - assert.strictEqual(flowExecResult.postApiCallFlow, undefined); - assert.deepStrictEqual(ret, { - isSucc: false, - err: new TsrpcError('You need login') - }) - - await server.stop(); - }); - - it('ApiCall flow error', async function () { - let server = new WsServer(getProto(), { - json: true, - logger: serverLogger - }); - - const flowExecResult: { [K in (keyof BaseServer['flows'])]?: boolean } = {}; - - server.implementApi('Test', async call => { - call.succ({ reply: 'asdgasdgasdgasdg' }); - }); - - server.flows.preApiCallFlow.push(call => { - assert.strictEqual(call.req.name, 'Changed') - throw new Error('ASDFASDF') - }); - server.flows.postApiCallFlow.push(v => { - flowExecResult.postApiCallFlow = true; - return v; - }) - - await server.start(); - - let client = new WsClient(getProto(), { - json: true, - logger: clientLogger - }); - await client.connect(); - - client.flows.preCallApiFlow.push(v => { - if (v.apiName !== 'ObjId') { - v.req.name = 'Changed' - } - return v; - }); - - let ret = await client.callApi('Test', { name: 'xxx' }); - assert.strictEqual(flowExecResult.postApiCallFlow, undefined); - assert.deepStrictEqual(ret, { - isSucc: false, - err: new TsrpcError('Internal Server Error', { - type: TsrpcErrorType.ServerError, - innerErr: 'ASDFASDF', - code: 'INTERNAL_ERR' - }) - }) - - await server.stop(); - }); - - it('server ApiReturn flow', async function () { - let server = new WsServer(getProto(), { - json: true, - logger: serverLogger - }); - - const flowExecResult: { [K in (keyof BaseServer['flows'])]?: boolean } = {}; - - server.implementApi('Test', async call => { - call.succ({ reply: 'xxxxxxxxxxxxxxxxxxxx' }); - }); - - server.flows.preApiReturnFlow.push(v => { - flowExecResult.preApiReturnFlow = true; - v.return = { - isSucc: false, - err: new TsrpcError('Ret changed') - } - return v; - }); - server.flows.postApiReturnFlow.push(v => { - flowExecResult.postApiReturnFlow = true; - v.call.logger.log('RETTT', v.return); - return v; - }) - - await server.start(); - - let client = new WsClient(getProto(), { - json: true, - logger: clientLogger - }); - await client.connect(); - - let ret = await client.callApi('Test', { name: 'xxx' }); - assert.strictEqual(flowExecResult.preApiReturnFlow, true); - assert.strictEqual(flowExecResult.postApiReturnFlow, true); - assert.deepStrictEqual(ret, { - isSucc: false, - err: new TsrpcError('Ret changed') - }) - - await server.stop(); - }); - - it('client ApiReturn flow', async function () { - let server = new WsServer(getProto(), { - json: true, - logger: serverLogger - }); - - const flowExecResult: { [K in (keyof WsClient['flows'])]?: boolean } = {}; - - server.implementApi('Test', async call => { - call.succ({ reply: 'xxxxxxxxxxxxxxxxxxxx' }); - }); - - await server.start(); - - let client = new WsClient(getProto(), { - json: true, - logger: clientLogger - }); - await client.connect(); - - client.flows.preApiReturnFlow.push(v => { - flowExecResult.preApiReturnFlow = true; - v.return = { - isSucc: false, - err: new TsrpcError('Ret changed') - } - return v; - }); - client.flows.postApiReturnFlow.push(v => { - flowExecResult.postApiReturnFlow = true; - client.logger?.log('RETTT', v.return); - return v; - }) - - let ret = await client.callApi('Test', { name: 'xxx' }); - assert.strictEqual(flowExecResult.preApiReturnFlow, true); - assert.strictEqual(flowExecResult.postApiReturnFlow, true); - assert.deepStrictEqual(ret, { - isSucc: false, - err: new TsrpcError('Ret changed') - }) - - await server.stop(); - }); - - it('client SendBufferFlow prevent', async function () { - let server = new WsServer(getProto(), { - json: true, - logger: serverLogger - }); - - // const flowExecResult: { [K in (keyof BaseClient['flows'])]?: boolean } = {}; - - server.implementApi('Test', async call => { - call.succ({ reply: 'xxxxxxxxxxxxxxxxxxxx' }); - }); - - await server.start(); - - let client = new WsClient(getProto(), { - json: true, - logger: clientLogger - }); - await client.connect(); - - client.flows.preSendDataFlow.push(v => { - return undefined - }); - - let ret: any; - client.callApi('Test', { name: 'xxx' }).then(v => { ret = v }); - await new Promise(rs => { setTimeout(rs, 200) }); - assert.strictEqual(ret, undefined) - - await server.stop(); - }); - - it('onInputBufferError', async function () { - let server = new WsServer(getProto(), { - json: true, - logger: serverLogger - }); - await server.start(); - - let client = new WsClient(getProto(), { - json: true, - logger: clientLogger - }); - await client.connect(); - client.flows.preSendDataFlow.push(v => { - v.data = (v.data as string).split('').reverse().join(''); - return v; - }); - - let ret = await client.callApi('Test', { name: 'XXX' }); - assert.deepStrictEqual(ret, { - isSucc: false, - err: new TsrpcError('Input is not a valid JSON string: Unexpected token ] in JSON at position 0', { type: TsrpcErrorType.NetworkError, code: 'LOST_CONN' }) - }) - - await server.stop(); - }) - - it('ObjectId', async function () { - let server = new WsServer(getProto(), { - json: true, - logger: serverLogger - }); - server.autoImplementApi(path.resolve(__dirname, '../api')) - await server.start(); - - let client = new WsClient(getProto(), { - json: true, - logger: clientLogger - }); - await client.connect(); - - // ObjectId - let objId1 = new ObjectId(); - let ret = await client.callApi('ObjId', { - id1: objId1 - }); - assert.strictEqual(ret.isSucc, true, ret.err?.message); - assert.strictEqual(objId1.toString(), ret.res!.id2.toString()); - - await server.stop(); - }) -}) \ No newline at end of file diff --git a/test/proto/MsgChat.ts b/test/proto/MsgChat.ts deleted file mode 100644 index 7616d8a..0000000 --- a/test/proto/MsgChat.ts +++ /dev/null @@ -1,6 +0,0 @@ -export interface MsgChat { - channel: number, - userName: string, - content: string, - time: number -} \ No newline at end of file diff --git a/test/proto/PtlObjId.ts b/test/proto/PtlObjId.ts deleted file mode 100644 index 3fd26eb..0000000 --- a/test/proto/PtlObjId.ts +++ /dev/null @@ -1,14 +0,0 @@ -// @ts-ignore -import { ObjectId } from "mongodb"; - -export interface ReqObjId { - id1: ObjectId; - buf?: Uint8Array, - date?: Date -} - -export interface ResObjId { - id2: ObjectId; - buf?: Uint8Array, - date?: Date -} \ No newline at end of file diff --git a/test/proto/PtlTest.ts b/test/proto/PtlTest.ts deleted file mode 100644 index 71c859d..0000000 --- a/test/proto/PtlTest.ts +++ /dev/null @@ -1,7 +0,0 @@ -export interface ReqTest { - name: string -}; - -export type ResTest = { - reply: string -}; \ No newline at end of file diff --git a/test/proto/a/b/c/PtlTest.ts b/test/proto/a/b/c/PtlTest.ts deleted file mode 100644 index f3a1146..0000000 --- a/test/proto/a/b/c/PtlTest.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { MsgChat } from '../../../MsgChat'; - -export interface ReqTest { - name: string -}; - -export type ResTest = { - reply: string, - chat?: MsgChat -}; \ No newline at end of file diff --git a/test/proto/serviceProto.ts b/test/proto/serviceProto.ts deleted file mode 100644 index ee82feb..0000000 --- a/test/proto/serviceProto.ts +++ /dev/null @@ -1,203 +0,0 @@ -import { ServiceProto } from 'tsrpc-proto'; -import { ReqTest, ResTest } from './a/b/c/PtlTest'; -import { MsgChat } from './MsgChat'; -import { ReqObjId, ResObjId } from './PtlObjId'; -import { ReqTest as ReqTest_1, ResTest as ResTest_1 } from './PtlTest'; - -export interface ServiceType { - api: { - "a/b/c/Test": { - req: ReqTest, - res: ResTest - }, - "ObjId": { - req: ReqObjId, - res: ResObjId - }, - "Test": { - req: ReqTest_1, - res: ResTest_1 - } - }, - msg: { - "Chat": MsgChat - } -} - -export const serviceProto: ServiceProto = { - "version": 1, - "services": [ - { - "id": 0, - "name": "a/b/c/Test", - "type": "api" - }, - { - "id": 1, - "name": "Chat", - "type": "msg" - }, - { - "id": 2, - "name": "ObjId", - "type": "api" - }, - { - "id": 3, - "name": "Test", - "type": "api" - } - ], - "types": { - "a/b/c/PtlTest/ReqTest": { - "type": "Interface", - "properties": [ - { - "id": 0, - "name": "name", - "type": { - "type": "String" - } - } - ] - }, - "a/b/c/PtlTest/ResTest": { - "type": "Interface", - "properties": [ - { - "id": 0, - "name": "reply", - "type": { - "type": "String" - } - }, - { - "id": 1, - "name": "chat", - "type": { - "type": "Reference", - "target": "MsgChat/MsgChat" - }, - "optional": true - } - ] - }, - "MsgChat/MsgChat": { - "type": "Interface", - "properties": [ - { - "id": 0, - "name": "channel", - "type": { - "type": "Number" - } - }, - { - "id": 1, - "name": "userName", - "type": { - "type": "String" - } - }, - { - "id": 2, - "name": "content", - "type": { - "type": "String" - } - }, - { - "id": 3, - "name": "time", - "type": { - "type": "Number" - } - } - ] - }, - "PtlObjId/ReqObjId": { - "type": "Interface", - "properties": [ - { - "id": 0, - "name": "id1", - "type": { - "type": "Reference", - "target": "?mongodb/ObjectId" - } - }, - { - "id": 1, - "name": "buf", - "type": { - "type": "Buffer", - "arrayType": "Uint8Array" - }, - "optional": true - }, - { - "id": 2, - "name": "date", - "type": { - "type": "Date" - }, - "optional": true - } - ] - }, - "PtlObjId/ResObjId": { - "type": "Interface", - "properties": [ - { - "id": 0, - "name": "id2", - "type": { - "type": "Reference", - "target": "?mongodb/ObjectId" - } - }, - { - "id": 1, - "name": "buf", - "type": { - "type": "Buffer", - "arrayType": "Uint8Array" - }, - "optional": true - }, - { - "id": 2, - "name": "date", - "type": { - "type": "Date" - }, - "optional": true - } - ] - }, - "PtlTest/ReqTest": { - "type": "Interface", - "properties": [ - { - "id": 0, - "name": "name", - "type": { - "type": "String" - } - } - ] - }, - "PtlTest/ResTest": { - "type": "Interface", - "properties": [ - { - "id": 0, - "name": "reply", - "type": { - "type": "String" - } - } - ] - } - } -}; \ No newline at end of file diff --git a/test/test.ts b/test/test.ts deleted file mode 100644 index 5729add..0000000 --- a/test/test.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { HttpServer } from '../src/server/http/HttpServer'; -import { serviceProto } from './proto/serviceProto'; - -let server = new HttpServer(serviceProto, { - jsonEnabled: true, - jsonRootPath: 'api' -}); - -server.implementApi('a/b/c/Test', call => { - call.logger.log('xxx', call.req); - call.succ({ - reply: 'xxxxxxxxxxx', - aasdg: 'd', - b: 'asdg' - } as any) -}); - -server.start(); \ No newline at end of file diff --git a/test/try/client/http.ts b/test/try/client/http.ts deleted file mode 100644 index f78f28a..0000000 --- a/test/try/client/http.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { HttpClient } from '../../src/client/http/HttpClient'; -import { serviceProto, ServiceType } from '../proto/serviceProto'; -let client = new HttpClient({ - server: 'http://localhost:3000', - proto: serviceProto -}); - -async function main() { - const P = 50, N = 1000; - let max = 0; - console.time(`test ${P}/${N}`); - for (let i = 0, len = N / P; i < len; ++i) { - let res = await Promise.all(Array.from({ length: P }, () => { - let start = Date.now(); - return client.callApi('a/b/c/Test', { name: '123' }).then(() => Date.now() - start); - })); - max = Math.max(res.max(), max) - } - console.timeEnd(`test ${P}/${N}`); - console.log('max', max) -} -main(); \ No newline at end of file diff --git a/test/try/client/ws.ts b/test/try/client/ws.ts deleted file mode 100644 index 286b4f2..0000000 --- a/test/try/client/ws.ts +++ /dev/null @@ -1,82 +0,0 @@ -import { serviceProto, ServiceType } from '../proto/serviceProto'; -import { WsClient } from '../../src/client/ws/WsClient'; -import SuperPromise from 'k8w-super-promise'; -import { Func } from 'mocha'; - -async function main() { - let client = new WsClient({ - server: 'ws://127.0.0.1:3000', - proto: serviceProto, - onStatusChange: v => { - console.log('StatusChange', v); - }, - // onLostConnection: () => { - // console.log('连接断开,2秒后重连'); - // setTimeout(() => { - // client.connect().catch(() => { }); - // }, 2000) - // } - }); - - await client.connect(); - - let cancel = client.callApi('Test', { name: 'XXXXXXXXXXXXX' }).catch(e => e); - cancel.cancel(); - - let res = await client.callApi('Test', { name: '小明同学' }).catch(e => e); - console.log('Test Res', res); - - res = await client.callApi('a/b/c/Test', { name: '小明同学' }).catch(e => e); - console.log('Test1 Res', res); - - // setInterval(async () => { - // try { - // let res = await client.callApi('Test', { name: '小明同学' }); - // console.log('收到回复', res); - // } - // catch (e) { - // if (e.info === 'NETWORK_ERR') { - // return; - // } - // console.log('API错误', e) - // } - // }, 1000); - - // client.listenMsg('Chat', msg => { - // console.log('收到MSG', msg); - // }); - - // setInterval(() => { - // try { - // client.sendMsg('Chat', { - // channel: 123, - // userName: '王小明', - // content: '你好', - // time: Date.now() - // }).catch(e => { - // console.log('SendMsg Failed', e.message) - // }) - // } - // catch{ } - // }, 1000) - - // #region Benchmark - // let maxTime = 0; - // let done = 0; - // let startTime = Date.now(); - - // setTimeout(() => { - // console.log('done', maxTime, done); - // process.exit(); - // }, 3000); - - // for (let i = 0; i < 10000; ++i) { - // client.callApi('Test', { name: '小明同学' }).then(() => { - // ++done; - // maxTime = Math.max(maxTime, Date.now() - startTime) - // }) - // } - // #endregion -} - -main(); \ No newline at end of file diff --git a/test/try/massive.ts b/test/try/massive.ts deleted file mode 100644 index fb10630..0000000 --- a/test/try/massive.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { TSRPCClient } from ".."; -import { serviceProto, ServiceType } from './proto/serviceProto'; - -async function main() { - setInterval(() => { - for (let i = 0; i < 100; ++i) { - let client = new TSRPCClient({ - server: 'ws://127.0.0.1:3000', - proto: serviceProto - }); - - client.connect().then(() => { - client.callApi('a/b/c/Test1', { name: '小明同学' }).then(v => { - // console.log('成功', v) - }).catch(e => { - console.error('错误', e.message) - }).then(() => { - client.disconnect(); - }); - }).catch(e => { - console.error('连接错误', e) - }) - } - }, 1000) -} - -main(); \ No newline at end of file diff --git a/test/try/no-res-issue/client/index.ts b/test/try/no-res-issue/client/index.ts deleted file mode 100644 index 114d653..0000000 --- a/test/try/no-res-issue/client/index.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { TsrpcClient } from "../../.."; -import { serviceProto } from '../server/protocols/proto'; - -let client = new TsrpcClient({ - proto: serviceProto -}); - -client.callApi('Test', { name: 'ssss' }).then(v => { - console.log('then', v) -}).catch(e => { - console.log('catch', e) -}) \ No newline at end of file diff --git a/test/try/no-res-issue/server/index.ts b/test/try/no-res-issue/server/index.ts deleted file mode 100644 index f772abd..0000000 --- a/test/try/no-res-issue/server/index.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { TsrpcServer } from '../../../index'; -import { serviceProto } from './protocols/proto'; - -let server = new TsrpcServer({ - proto: serviceProto, -}); - -server.autoImplementApi('src/api'); - -server.start(); \ No newline at end of file diff --git a/test/try/no-res-issue/server/protocols/PtlTest.ts b/test/try/no-res-issue/server/protocols/PtlTest.ts deleted file mode 100644 index ce7579b..0000000 --- a/test/try/no-res-issue/server/protocols/PtlTest.ts +++ /dev/null @@ -1,7 +0,0 @@ -export interface ReqTest { - name: string -} - -export interface ResTest { - reply: string -} \ No newline at end of file diff --git a/test/try/no-res-issue/server/protocols/proto.ts b/test/try/no-res-issue/server/protocols/proto.ts deleted file mode 100644 index 89df20c..0000000 --- a/test/try/no-res-issue/server/protocols/proto.ts +++ /dev/null @@ -1,52 +0,0 @@ -import { ServiceProto } from 'tsrpc-proto'; -import { ReqTest, ResTest } from './PtlTest' - -export interface ServiceType { - req: { - "Test": ReqTest - }, - res: { - "Test": ResTest - }, - msg: { - - } -} - -export const serviceProto: ServiceProto = { - "services": [ - { - "id": 0, - "name": "Test", - "type": "api", - "req": "PtlTest/ReqTest", - "res": "PtlTest/ResTest" - } - ], - "types": { - "PtlTest/ReqTest": { - "type": "Interface", - "properties": [ - { - "id": 0, - "name": "name", - "type": { - "type": "String" - } - } - ] - }, - "PtlTest/ResTest": { - "type": "Interface", - "properties": [ - { - "id": 0, - "name": "reply", - "type": { - "type": "String" - } - } - ] - } - } -}; \ No newline at end of file diff --git a/test/try/no-res-issue/server/src/api/ApiTest.ts b/test/try/no-res-issue/server/src/api/ApiTest.ts deleted file mode 100644 index c71d2e9..0000000 --- a/test/try/no-res-issue/server/src/api/ApiTest.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { ReqTest, ResTest } from "../../protocols/PtlTest"; -import { ApiCall } from "../../../../.."; - -export async function ApiTest(call: ApiCall) { - await new Promise(rs => { - let i = 5; - call.logger.log(i); - let interval = setInterval(() => { - call.logger.log(--i); - if (i === 0) { - clearInterval(interval); - rs(); - } - }, 1000); - }); - - call.error('asdfasdf', { a: 1, b: 2 }) -} \ No newline at end of file diff --git a/test/try/package-lock.json b/test/try/package-lock.json deleted file mode 100644 index d4c87c3..0000000 --- a/test/try/package-lock.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "name": "try", - "version": "1.0.0", - "lockfileVersion": 2, - "requires": true, - "packages": { - "": { - "version": "1.0.0", - "license": "ISC" - } - } -} diff --git a/test/try/package.json b/test/try/package.json deleted file mode 100644 index 36e8cd2..0000000 --- a/test/try/package.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "name": "try", - "version": "1.0.0", - "description": "", - "main": "index.js", - "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" - }, - "author": "", - "license": "ISC" -} diff --git a/test/try/proto/MsgChat.ts b/test/try/proto/MsgChat.ts deleted file mode 100644 index 7616d8a..0000000 --- a/test/try/proto/MsgChat.ts +++ /dev/null @@ -1,6 +0,0 @@ -export interface MsgChat { - channel: number, - userName: string, - content: string, - time: number -} \ No newline at end of file diff --git a/test/try/proto/PtlTest.ts b/test/try/proto/PtlTest.ts deleted file mode 100644 index 71c859d..0000000 --- a/test/try/proto/PtlTest.ts +++ /dev/null @@ -1,7 +0,0 @@ -export interface ReqTest { - name: string -}; - -export type ResTest = { - reply: string -}; \ No newline at end of file diff --git a/test/try/proto/a/b/c/PtlTest.ts b/test/try/proto/a/b/c/PtlTest.ts deleted file mode 100644 index f3a1146..0000000 --- a/test/try/proto/a/b/c/PtlTest.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { MsgChat } from '../../../MsgChat'; - -export interface ReqTest { - name: string -}; - -export type ResTest = { - reply: string, - chat?: MsgChat -}; \ No newline at end of file diff --git a/test/try/proto/serviceProto.ts b/test/try/proto/serviceProto.ts deleted file mode 100644 index ce24e8f..0000000 --- a/test/try/proto/serviceProto.ts +++ /dev/null @@ -1,135 +0,0 @@ -import { ServiceProto } from 'tsrpc-proto'; -import { ReqTest, ResTest } from './a/b/c/PtlTest' -import { MsgChat } from './MsgChat' -import { ReqTest as ReqTest_1, ResTest as ResTest_1 } from './PtlTest' - -export interface ServiceType { - req: { - "a/b/c/Test": ReqTest, - "Test": ReqTest_1 - }, - res: { - "a/b/c/Test": ResTest, - "Test": ResTest_1 - }, - msg: { - "Chat": MsgChat - } -} - -export const serviceProto: ServiceProto = { - "services": [ - { - "id": 0, - "name": "a/b/c/Test", - "type": "api", - "req": "a/b/c/PtlTest/ReqTest", - "res": "a/b/c/PtlTest/ResTest" - }, - { - "id": 1, - "name": "Chat", - "type": "msg", - "msg": "MsgChat/MsgChat" - }, - { - "id": 2, - "name": "Test", - "type": "api", - "req": "PtlTest/ReqTest", - "res": "PtlTest/ResTest" - } - ], - "types": { - "a/b/c/PtlTest/ReqTest": { - "type": "Interface", - "properties": [ - { - "id": 0, - "name": "name", - "type": { - "type": "String" - } - } - ] - }, - "a/b/c/PtlTest/ResTest": { - "type": "Interface", - "properties": [ - { - "id": 0, - "name": "reply", - "type": { - "type": "String" - } - }, - { - "id": 1, - "name": "chat", - "type": { - "type": "Reference", - "target": "MsgChat/MsgChat" - }, - "optional": true - } - ] - }, - "MsgChat/MsgChat": { - "type": "Interface", - "properties": [ - { - "id": 0, - "name": "channel", - "type": { - "type": "Number" - } - }, - { - "id": 1, - "name": "userName", - "type": { - "type": "String" - } - }, - { - "id": 2, - "name": "content", - "type": { - "type": "String" - } - }, - { - "id": 3, - "name": "time", - "type": { - "type": "Number" - } - } - ] - }, - "PtlTest/ReqTest": { - "type": "Interface", - "properties": [ - { - "id": 0, - "name": "name", - "type": { - "type": "String" - } - } - ] - }, - "PtlTest/ResTest": { - "type": "Interface", - "properties": [ - { - "id": 0, - "name": "reply", - "type": { - "type": "String" - } - } - ] - } - } -}; \ No newline at end of file diff --git a/test/try/proto/typeProto.json b/test/try/proto/typeProto.json deleted file mode 100644 index a8f9060..0000000 --- a/test/try/proto/typeProto.json +++ /dev/null @@ -1,59 +0,0 @@ -{ - "MsgChat/MsgChat": { - "type": "Interface", - "properties": [ - { - "id": 0, - "name": "channel", - "type": { - "type": "String" - } - }, - { - "id": 1, - "name": "userName", - "type": { - "type": "String" - } - }, - { - "id": 2, - "name": "content", - "type": { - "type": "String" - } - }, - { - "id": 3, - "name": "time", - "type": { - "type": "Number" - } - } - ] - }, - "PtlTest/ReqTest": { - "type": "Interface", - "properties": [ - { - "id": 0, - "name": "name", - "type": { - "type": "String" - } - } - ] - }, - "PtlTest/ResTest": { - "type": "Interface", - "properties": [ - { - "id": 0, - "name": "reply", - "type": { - "type": "String" - } - } - ] - } -} \ No newline at end of file diff --git a/test/try/server/api/ApiTest.ts b/test/try/server/api/ApiTest.ts deleted file mode 100644 index 2d5e24a..0000000 --- a/test/try/server/api/ApiTest.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { TsrpcError } from "tsrpc-proto"; -import { ApiCallHttp } from '../../../src/server/http/HttpCall'; -import { ReqTest } from "../../proto/PtlTest"; -import { ResTest } from '../../proto/a/b/c/PtlTest'; - -export async function ApiTest(call: ApiCallHttp) { - if (Math.random() > 0.75) { - call.succ({ - reply: 'Hello, ' + call.req.name - }) - } - else if (Math.random() > 0.5) { - call.error('What the fuck??', { msg: '哈哈哈哈' }) - } - else if (Math.random() > 0.25) { - throw new Error('这应该是InternalERROR') - } - else { - throw new TsrpcError('返回到前台的错误', 'ErrInfo'); - } -} \ No newline at end of file diff --git a/test/try/server/api/a/b/c/ApiTest.ts b/test/try/server/api/a/b/c/ApiTest.ts deleted file mode 100644 index dcfb075..0000000 --- a/test/try/server/api/a/b/c/ApiTest.ts +++ /dev/null @@ -1,5 +0,0 @@ -export async function ApiTest(call: any) { - call.succ({ - reply: 'Api Test1 Succ' - }) -} \ No newline at end of file diff --git a/test/try/server/http.ts b/test/try/server/http.ts deleted file mode 100644 index 243f270..0000000 --- a/test/try/server/http.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { serviceProto } from '../proto/serviceProto'; -import * as path from "path"; -import { TsrpcServer } from '../../index'; - -let server = new TsrpcServer({ - proto: serviceProto -}); - -server.dataFlow.push((data, conn) => { - let httpReq = conn.options.httpReq; - if (httpReq.method === 'GET') { - conn.logger.log('url', httpReq.url); - conn.logger.log('host', httpReq.headers.host); - conn.options.httpRes.end('Hello~~~'); - return false; - } - - return true; -}) - -server.autoImplementApi(path.resolve(__dirname, 'api')); -server.start(); \ No newline at end of file diff --git a/test/try/server/ws.ts b/test/try/server/ws.ts deleted file mode 100644 index 4aad514..0000000 --- a/test/try/server/ws.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { serviceProto, ServiceType } from '../proto/serviceProto'; -import * as path from "path"; -import { TsrpcServerWs } from '../../index'; - -let server = new TsrpcServerWs({ - proto: serviceProto -}); -server.start(); - -server.autoImplementApi(path.resolve(__dirname, 'api')); -server.listenMsg('Chat', v => { - v.conn.sendMsg('Chat', { - channel: v.msg.channel, - userName: 'SYSTEM', - content: '收到', - time: Date.now() - }) -}) \ No newline at end of file diff --git a/test/try/tsconfig.json b/test/try/tsconfig.json deleted file mode 100644 index 2b032d8..0000000 --- a/test/try/tsconfig.json +++ /dev/null @@ -1,59 +0,0 @@ -{ - "compilerOptions": { - /* Basic Options */ - // "incremental": true, /* Enable incremental compilation */ - "target": "es6", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */ - "module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */ - // "lib": [], /* Specify library files to be included in the compilation. */ - // "allowJs": true, /* Allow javascript files to be compiled. */ - // "checkJs": true, /* Report errors in .js files. */ - // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */ - // "declaration": true, /* Generates corresponding '.d.ts' file. */ - // "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */ - // "sourceMap": true, /* Generates corresponding '.map' file. */ - // "outFile": "./", /* Concatenate and emit output to single file. */ - "outDir": "./dist", /* Redirect output structure to the directory. */ - // "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */ - // "composite": true, /* Enable project compilation */ - // "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */ - // "removeComments": true, /* Do not emit comments to output. */ - // "noEmit": true, /* Do not emit outputs. */ - // "importHelpers": true, /* Import emit helpers from 'tslib'. */ - // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */ - // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ - /* Strict Type-Checking Options */ - "strict": true, /* Enable all strict type-checking options. */ - // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ - // "strictNullChecks": true, /* Enable strict null checks. */ - // "strictFunctionTypes": true, /* Enable strict checking of function types. */ - // "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */ - // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ - // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ - // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ - /* Additional Checks */ - // "noUnusedLocals": true, /* Report errors on unused locals. */ - // "noUnusedParameters": true, /* Report errors on unused parameters. */ - // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ - // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ - /* Module Resolution Options */ - // "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */ - // "baseUrl": "./", /* Base directory to resolve non-absolute module names. */ - // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ - // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ - // "typeRoots": [], /* List of folders to include type definitions from. */ - // "types": [], /* Type declaration files to be included in compilation. */ - // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ - "esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */ - // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ - // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ - /* Source Map Options */ - // "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */ - // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ - // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */ - // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ - /* Experimental Options */ - // "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */ - // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ - "useUnknownInCatchVariables": false - } -} \ No newline at end of file diff --git a/test/tsconfig.json b/test/tsconfig.json new file mode 100644 index 0000000..a7112a3 --- /dev/null +++ b/test/tsconfig.json @@ -0,0 +1,19 @@ +{ + "compilerOptions": { + "lib": [ + "es2018" + ], + "module": "commonjs", + "target": "es2018", + "outDir": "dist", + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true, + "moduleResolution": "node" + }, + "include": [ + ".", + "../src" + ] +} \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json index 8b77b41..fe3ca33 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,66 +1,18 @@ -{ - "compilerOptions": { - /* Basic Options */ - "target": "es2018", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */ - "module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */ - // "lib": [ - // "es5", - // "dom" - // ], /* Specify library files to be included in the compilation. */ - // "allowJs": true, /* Allow javascript files to be compiled. */ - // "checkJs": true, /* Report errors in .js files. */ - // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */ - "declaration": true, /* Generates corresponding '.d.ts' file. */ - "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */ - // "sourceMap": true, /* Generates corresponding '.map' file. */ - // "outFile": "./", /* Concatenate and emit output to single file. */ - "outDir": "./lib", /* Redirect output structure to the directory. */ - // "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */ - // "composite": true, /* Enable project compilation */ - // "incremental": true, /* Enable incremental compilation */ - // "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */ - // "removeComments": true, /* Do not emit comments to output. */ - // "noEmit": true, /* Do not emit outputs. */ - // "importHelpers": true, /* Import emit helpers from 'tslib'. */ - // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */ - // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ - /* Strict Type-Checking Options */ - "strict": true, /* Enable all strict type-checking options. */ - // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ - // "strictNullChecks": true, /* Enable strict null checks. */ - // "strictFunctionTypes": true, /* Enable strict checking of function types. */ - // "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */ - // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ - // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ - // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ - /* Additional Checks */ - // "noUnusedLocals": true, /* Report errors on unused locals. */ - // "noUnusedParameters": true, /* Report errors on unused parameters. */ - // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ - // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ - /* Module Resolution Options */ - "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */ - // "baseUrl": "./", /* Base directory to resolve non-absolute module names. */ - // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ - // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ - // "typeRoots": [], /* List of folders to include type definitions from. */ - // "types": [], /* Type declaration files to be included in compilation. */ - // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ - "esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */ - // "preserveSymlinks": true /* Do not resolve the real path of symlinks. */ - /* Source Map Options */ - // "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */ - // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ - // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */ - // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ - /* Experimental Options */ - // "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */ - // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ - "useUnknownInCatchVariables": false - }, - "include": [ - "src" - // "test" - // "benchmark" - ] +{ + "compilerOptions": { + "lib": [ + "es2018" + ], + "module": "commonjs", + "target": "es2018", + "outDir": "dist", + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true, + "moduleResolution": "node" + }, + "include": [ + "src" + ] } \ No newline at end of file diff --git a/tsrpc.config.ts b/tsrpc.config.ts new file mode 100644 index 0000000..0bbf318 --- /dev/null +++ b/tsrpc.config.ts @@ -0,0 +1,39 @@ +import { CodeTemplate, TsrpcConfig } from 'tsrpc-cli'; + +const tsrpcConf: TsrpcConfig = { + // Generate ServiceProto + proto: [ + { + ptlDir: 'src/shared/protocols', // Protocol dir + output: 'src/shared/protocols/serviceProto.ts', // Path for generated ServiceProto + apiDir: 'src/api', // API dir + docDir: 'docs', // API documents dir + ptlTemplate: CodeTemplate.getExtendedPtl(), + // msgTemplate: CodeTemplate.getExtendedMsg(), + } + ], + // Sync shared code + sync: [ + // { + // from: 'src/shared', + // to: '../frontend/src/shared', + // type: 'symlink' // Change this to 'copy' if your environment not support symlink + // } + ], + // Dev server + dev: { + autoProto: true, // Auto regenerate proto + autoSync: true, // Auto sync when file changed + autoApi: true, // Auto create API when ServiceProto updated + watch: 'src', // Restart dev server when these files changed + entry: 'src/index.ts', // Dev server command: node -r ts-node/register {entry} + }, + // Build config + build: { + autoProto: true, // Auto generate proto before build + autoSync: true, // Auto sync before build + autoApi: true, // Auto generate API before build + outDir: 'dist', // Clean this dir before build + } +} +export default tsrpcConf; \ No newline at end of file