From 5e7a5782abb869bb21409704da572eeae0d309d9 Mon Sep 17 00:00:00 2001 From: k8w Date: Tue, 14 Dec 2021 23:20:38 +0800 Subject: [PATCH 1/5] update wechat code --- examples/cocos-creator-multiplayer/README.md | 19 +++++++++--------- .../README_assets/wechat.png | Bin 14043 -> 31098 bytes 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/examples/cocos-creator-multiplayer/README.md b/examples/cocos-creator-multiplayer/README.md index 174896a..df692f6 100644 --- a/examples/cocos-creator-multiplayer/README.md +++ b/examples/cocos-creator-multiplayer/README.md @@ -10,8 +10,15 @@ https://tsrpc.cn/fight/index.html (可浏览器多开体验多人效果) -**在线教程** -https://1drv.ms/p/s!AviSVsaYsolWnh7DCp2Y8g_NtDbA?e=67ZqqS +## 在线教程 +- 文章: + - [2 天做了个多人实时对战,200ms 延迟竟然也能丝滑流畅?](https://mp.weixin.qq.com/s/V1YWPF5LmY-l1L5LF2nR3A) +- 视频: + - [2021-12-04 Cocos Star Meeting 深圳站](https://www.bilibili.com/video/BV16F411z7iP) +- Github 源码地址 + - https://github.com/k8w/tsrpc-examples/tree/main/examples/cocos-creator-multiplayer + +![](README_assets/wechat.png) @@ -42,14 +49,6 @@ npm run dev **注意:前端项目需要先 `npm install` 后再打开 Cocos,如果报错,可以关闭 Cocos 后重启试一下。** -## 微信交流群 - -欢迎加入 TSRPC 和 TypeScript 全栈开发学习交流群: - -(请注明来意) - -![](README_assets/wechat.png) - ## 效果预览 https://user-images.githubusercontent.com/1681689/144695691-c8c556dd-68c4-44bf-8a38-5c37e203dbda.mp4 \ No newline at end of file diff --git a/examples/cocos-creator-multiplayer/README_assets/wechat.png b/examples/cocos-creator-multiplayer/README_assets/wechat.png index f0f7a30788cd2de4691068e32c1de68ef079e0b6..0e5c24dff79dac48d9aa3ef1acb586ffc76f055b 100644 GIT binary patch literal 31098 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 literal 14043 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 Date: Tue, 14 Dec 2021 23:22:07 +0800 Subject: [PATCH 2/5] wechat --- .../README_assets/{wechat.png => wechat1.png} | Bin 1 file changed, 0 insertions(+), 0 deletions(-) rename examples/cocos-creator-multiplayer/README_assets/{wechat.png => wechat1.png} (100%) diff --git a/examples/cocos-creator-multiplayer/README_assets/wechat.png b/examples/cocos-creator-multiplayer/README_assets/wechat1.png similarity index 100% rename from examples/cocos-creator-multiplayer/README_assets/wechat.png rename to examples/cocos-creator-multiplayer/README_assets/wechat1.png From ed409795d96c5a1461d4f3e6560342eadb1c0e23 Mon Sep 17 00:00:00 2001 From: k8w Date: Tue, 14 Dec 2021 23:22:13 +0800 Subject: [PATCH 3/5] wechat --- .../README_assets/{wechat1.png => wechat.png} | Bin 1 file changed, 0 insertions(+), 0 deletions(-) rename examples/cocos-creator-multiplayer/README_assets/{wechat1.png => wechat.png} (100%) diff --git a/examples/cocos-creator-multiplayer/README_assets/wechat1.png b/examples/cocos-creator-multiplayer/README_assets/wechat.png similarity index 100% rename from examples/cocos-creator-multiplayer/README_assets/wechat1.png rename to examples/cocos-creator-multiplayer/README_assets/wechat.png From 82663162b71333b1bdf3a38661317a96888f25e2 Mon Sep 17 00:00:00 2001 From: k8w Date: Thu, 23 Dec 2021 23:36:33 +0800 Subject: [PATCH 4/5] =?UTF-8?q?=E4=BA=91=E5=87=BD=E6=95=B0=20examples?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- examples/serverless-faas/README.md | 35 + examples/serverless-faas/backend/.gitignore | 3 + examples/serverless-faas/backend/.mocharc.js | 11 + .../backend/.vscode/launch.json | 30 + .../backend/.vscode/settings.json | 3 + examples/serverless-faas/backend/Dockerfile | 30 + examples/serverless-faas/backend/README.md | 31 + examples/serverless-faas/backend/package.json | 24 + .../serverless-faas/backend/src/aliyun-fc.ts | 26 + .../backend/src/api/ApiAddData.ts | 26 + .../backend/src/api/ApiGetData.ts | 13 + examples/serverless-faas/backend/src/index.ts | 8 + .../backend/src/models/server.ts | 19 + .../src/shared/protocols/PtlAddData.ts | 16 + .../src/shared/protocols/PtlGetData.ts | 19 + .../backend/src/shared/protocols/base.ts | 11 + .../src/shared/protocols/serviceProto.ts | 98 + .../backend/src/txcloud-scf.ts | 26 + .../backend/test/api/data.test.ts | 39 + .../backend/test/tsconfig.json | 15 + .../serverless-faas/backend/tsconfig.json | 18 + .../serverless-faas/backend/tsrpc.config.ts | 39 + examples/serverless-faas/backend/yarn.lock | 1315 ++++++ examples/serverless-faas/frontend/.gitignore | 3 + .../serverless-faas/frontend/package.json | 24 + .../frontend/public/favicon.ico | Bin 0 -> 4286 bytes .../serverless-faas/frontend/public/index.css | 83 + .../frontend/public/index.html | 29 + .../serverless-faas/frontend/src/client.ts | 10 + .../serverless-faas/frontend/src/env.d.ts | 9 + .../serverless-faas/frontend/src/index.ts | 50 + examples/serverless-faas/frontend/src/shared | 1 + .../serverless-faas/frontend/tsconfig.json | 23 + .../frontend/webpack.config.js | 56 + examples/serverless-faas/frontend/yarn.lock | 3624 +++++++++++++++++ 35 files changed, 5767 insertions(+) create mode 100644 examples/serverless-faas/README.md create mode 100644 examples/serverless-faas/backend/.gitignore create mode 100644 examples/serverless-faas/backend/.mocharc.js create mode 100644 examples/serverless-faas/backend/.vscode/launch.json create mode 100644 examples/serverless-faas/backend/.vscode/settings.json create mode 100644 examples/serverless-faas/backend/Dockerfile create mode 100644 examples/serverless-faas/backend/README.md create mode 100644 examples/serverless-faas/backend/package.json create mode 100644 examples/serverless-faas/backend/src/aliyun-fc.ts create mode 100644 examples/serverless-faas/backend/src/api/ApiAddData.ts create mode 100644 examples/serverless-faas/backend/src/api/ApiGetData.ts create mode 100644 examples/serverless-faas/backend/src/index.ts create mode 100644 examples/serverless-faas/backend/src/models/server.ts create mode 100644 examples/serverless-faas/backend/src/shared/protocols/PtlAddData.ts create mode 100644 examples/serverless-faas/backend/src/shared/protocols/PtlGetData.ts create mode 100644 examples/serverless-faas/backend/src/shared/protocols/base.ts create mode 100644 examples/serverless-faas/backend/src/shared/protocols/serviceProto.ts create mode 100644 examples/serverless-faas/backend/src/txcloud-scf.ts create mode 100644 examples/serverless-faas/backend/test/api/data.test.ts create mode 100644 examples/serverless-faas/backend/test/tsconfig.json create mode 100644 examples/serverless-faas/backend/tsconfig.json create mode 100644 examples/serverless-faas/backend/tsrpc.config.ts create mode 100644 examples/serverless-faas/backend/yarn.lock create mode 100644 examples/serverless-faas/frontend/.gitignore create mode 100644 examples/serverless-faas/frontend/package.json create mode 100644 examples/serverless-faas/frontend/public/favicon.ico create mode 100644 examples/serverless-faas/frontend/public/index.css create mode 100644 examples/serverless-faas/frontend/public/index.html create mode 100644 examples/serverless-faas/frontend/src/client.ts create mode 100644 examples/serverless-faas/frontend/src/env.d.ts create mode 100644 examples/serverless-faas/frontend/src/index.ts create mode 120000 examples/serverless-faas/frontend/src/shared create mode 100644 examples/serverless-faas/frontend/tsconfig.json create mode 100644 examples/serverless-faas/frontend/webpack.config.js create mode 100644 examples/serverless-faas/frontend/yarn.lock diff --git a/examples/serverless-faas/README.md b/examples/serverless-faas/README.md new file mode 100644 index 0000000..8997250 --- /dev/null +++ b/examples/serverless-faas/README.md @@ -0,0 +1,35 @@ +Serverless 云函数支持示例 +=== + +演示了示例项目中的留言板,同时支持阿里云函数计算(FC),腾讯云云函数(SCF),和原生 NodeJS 部署的支持。 + +主要方式是在后端项目中区分为 3 个不同的入口点: + +- `index.ts`:NodeJS 原生部署入口点 +- `aliyun-fc.ts`:阿里云函数计算 FC 入口点 + +- `txcloud-scf.ts`:腾讯云云函数 SCF 入口点 + +## 部署方式 + +### 阿里云 + +1. 创建 HTTP 函数,`npm run build` 然后将 `dist` 目录下的代码上传到阿里云根目录 +1. 在 Web IDE 终端执行命令: + ```shell + npm i + ``` +1. 配置 **函数入口** 为 `aliyun-fc.handler` +1. 配置 **初始化函数** 为 `aliyun-fc.initializer` +1. 测试运行 + +### 腾讯云 + +1. 创建 Event 函数,`npm run build` 然后将 `dist` 目录上传到腾讯云,并更名为 `src` 目录 +1. 在 Web IDE 终端执行命令: + ```shell + cd src + npm i + ``` +1. 配置 **执行函数** 为 `txcloud-scf.handler` +1. 测试运行 \ No newline at end of file diff --git a/examples/serverless-faas/backend/.gitignore b/examples/serverless-faas/backend/.gitignore new file mode 100644 index 0000000..d84f0da --- /dev/null +++ b/examples/serverless-faas/backend/.gitignore @@ -0,0 +1,3 @@ +node_modules +dist +.DS_STORE \ No newline at end of file diff --git a/examples/serverless-faas/backend/.mocharc.js b/examples/serverless-faas/backend/.mocharc.js new file mode 100644 index 0000000..108856a --- /dev/null +++ b/examples/serverless-faas/backend/.mocharc.js @@ -0,0 +1,11 @@ +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/examples/serverless-faas/backend/.vscode/launch.json b/examples/serverless-faas/backend/.vscode/launch.json new file mode 100644 index 0000000..9ba4218 --- /dev/null +++ b/examples/serverless-faas/backend/.vscode/launch.json @@ -0,0 +1,30 @@ +{ + "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/examples/serverless-faas/backend/.vscode/settings.json b/examples/serverless-faas/backend/.vscode/settings.json new file mode 100644 index 0000000..00ad71f --- /dev/null +++ b/examples/serverless-faas/backend/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "typescript.tsdk": "node_modules\\typescript\\lib" +} \ No newline at end of file diff --git a/examples/serverless-faas/backend/Dockerfile b/examples/serverless-faas/backend/Dockerfile new file mode 100644 index 0000000..1a3c7b5 --- /dev/null +++ b/examples/serverless-faas/backend/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/examples/serverless-faas/backend/README.md b/examples/serverless-faas/backend/README.md new file mode 100644 index 0000000..dbc7d25 --- /dev/null +++ b/examples/serverless-faas/backend/README.md @@ -0,0 +1,31 @@ +# 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/examples/serverless-faas/backend/package.json b/examples/serverless-faas/backend/package.json new file mode 100644 index 0000000..917347a --- /dev/null +++ b/examples/serverless-faas/backend/package.json @@ -0,0 +1,24 @@ +{ + "name": "serverless-faas-backend", + "version": "0.1.0", + "main": "index.js", + "private": true, + "scripts": { + "dev": "tsrpc-cli dev", + "build": "tsrpc-cli build", + "doc": "tsrpc-cli doc", + "test": "mocha test/**/*.test.ts" + }, + "devDependencies": { + "@types/mocha": "^8.2.3", + "@types/node": "^15.14.9", + "mocha": "^9.1.3", + "onchange": "^7.1.0", + "ts-node": "^10.4.0", + "tsrpc-cli": "^2.3.0", + "typescript": "^4.5.4" + }, + "dependencies": { + "tsrpc": "^3.1.4" + } +} \ No newline at end of file diff --git a/examples/serverless-faas/backend/src/aliyun-fc.ts b/examples/serverless-faas/backend/src/aliyun-fc.ts new file mode 100644 index 0000000..3370d5a --- /dev/null +++ b/examples/serverless-faas/backend/src/aliyun-fc.ts @@ -0,0 +1,26 @@ +// 阿里云 - 函数计算:FC +// https://cloud.tencent.com/product/scf + +import { init, server } from "./models/server"; + +// 阿里云函数计算 - HTTP函数 +export async function handler(req: any, res: any, context: any) { + // JSON 请求 + if (req.headers['content-type']?.includes('application/json')) { + let apiName = req.path.slice(1); // 去除开头的 "/" + let ret = await server.inputJSON(apiName, JSON.parse(req.body)); + res.setStatusCode(ret.isSucc ? 200 : 500); + res.send(JSON.stringify(ret)); + } + // 二进制请求 + else { + let output = await server.inputBuffer(req.body); + res.send(Buffer.from(output)); + } +} + +// 阿里云函数计算 - 初始化 +export async function initializer(context: unknown, callback: Function) { + await init(); + callback(); +} \ No newline at end of file diff --git a/examples/serverless-faas/backend/src/api/ApiAddData.ts b/examples/serverless-faas/backend/src/api/ApiAddData.ts new file mode 100644 index 0000000..c064789 --- /dev/null +++ b/examples/serverless-faas/backend/src/api/ApiAddData.ts @@ -0,0 +1,26 @@ +import { ApiCall } from "tsrpc"; +import { ReqAddData, ResAddData } from "../shared/protocols/PtlAddData"; +import { AllData } from "./ApiGetData"; + +// This is a demo code file +// Feel free to delete it + +export async function ApiAddData(call: ApiCall) { + // Error + if (call.req.content === '') { + call.error('Content is empty'); + return; + } + + let time = new Date(); + AllData.unshift({ + content: call.req.content, + time: time + }) + console.log('AllData', AllData) + + // Success + call.succ({ + time: time + }); +} \ No newline at end of file diff --git a/examples/serverless-faas/backend/src/api/ApiGetData.ts b/examples/serverless-faas/backend/src/api/ApiGetData.ts new file mode 100644 index 0000000..2996ee4 --- /dev/null +++ b/examples/serverless-faas/backend/src/api/ApiGetData.ts @@ -0,0 +1,13 @@ +import { ApiCall } from "tsrpc"; +import { ReqGetData, ResGetData } from "../shared/protocols/PtlGetData"; + +// This is a demo code file +// Feel free to delete it + +export async function ApiGetData(call: ApiCall) { + call.succ({ + data: AllData + }) +} + +export const AllData: { content: string, time: Date }[] = []; \ No newline at end of file diff --git a/examples/serverless-faas/backend/src/index.ts b/examples/serverless-faas/backend/src/index.ts new file mode 100644 index 0000000..9174103 --- /dev/null +++ b/examples/serverless-faas/backend/src/index.ts @@ -0,0 +1,8 @@ +import { init, server } from "./models/server"; + +// 普通 NodeJS 环境入口点 +async function main() { + await init(); + await server.start(); +}; +main(); \ No newline at end of file diff --git a/examples/serverless-faas/backend/src/models/server.ts b/examples/serverless-faas/backend/src/models/server.ts new file mode 100644 index 0000000..4ea6b65 --- /dev/null +++ b/examples/serverless-faas/backend/src/models/server.ts @@ -0,0 +1,19 @@ +import path from "path"; +import { HttpServer } from "tsrpc"; +import { serviceProto } from "../shared/protocols/serviceProto"; + +// Create the Server +export const server = new HttpServer(serviceProto, { + port: 3000, + // Remove this to use binary mode (remove from the client too) + json: true +}); + +// Initialize before server start +export async function init(delay?: boolean) { + // Auto implement APIs + await server.autoImplementApi(path.resolve(__dirname, '../api/'), delay); + + // TODO + // Prepare something... (e.g. connect the db) +}; \ No newline at end of file diff --git a/examples/serverless-faas/backend/src/shared/protocols/PtlAddData.ts b/examples/serverless-faas/backend/src/shared/protocols/PtlAddData.ts new file mode 100644 index 0000000..2aae061 --- /dev/null +++ b/examples/serverless-faas/backend/src/shared/protocols/PtlAddData.ts @@ -0,0 +1,16 @@ +// This is a demo code file +// Feel free to delete it + +/** + * 增加数据 + * 此处的注释将会自动附带到生成的 API 文档中 + */ +export interface ReqAddData { + /** 要增加的消息内容 */ + content: string; +} + +export interface ResAddData { + /** 服务端内容创建时间 */ + time: Date +} \ No newline at end of file diff --git a/examples/serverless-faas/backend/src/shared/protocols/PtlGetData.ts b/examples/serverless-faas/backend/src/shared/protocols/PtlGetData.ts new file mode 100644 index 0000000..a4ce9c9 --- /dev/null +++ b/examples/serverless-faas/backend/src/shared/protocols/PtlGetData.ts @@ -0,0 +1,19 @@ +// This is a demo code file +// Feel free to delete it + +/** + * 获取数据 + */ +export interface ReqGetData { + +} + +export interface ResGetData { + /** 返回所有数据列表 */ + data: { + /** 消息内容 */ + content: string, + /** 创建时间 */ + time: Date + }[] +} \ No newline at end of file diff --git a/examples/serverless-faas/backend/src/shared/protocols/base.ts b/examples/serverless-faas/backend/src/shared/protocols/base.ts new file mode 100644 index 0000000..cfbe28e --- /dev/null +++ b/examples/serverless-faas/backend/src/shared/protocols/base.ts @@ -0,0 +1,11 @@ +export interface BaseRequest { + +} + +export interface BaseResponse { + +} + +export interface BaseConf { + +} \ No newline at end of file diff --git a/examples/serverless-faas/backend/src/shared/protocols/serviceProto.ts b/examples/serverless-faas/backend/src/shared/protocols/serviceProto.ts new file mode 100644 index 0000000..e7207a9 --- /dev/null +++ b/examples/serverless-faas/backend/src/shared/protocols/serviceProto.ts @@ -0,0 +1,98 @@ +import { ServiceProto } from 'tsrpc-proto'; +import { ReqAddData, ResAddData } from './PtlAddData'; +import { ReqGetData, ResGetData } from './PtlGetData'; + +// This is a demo service proto file (auto generated) +// Feel free to delete it + +export interface ServiceType { + api: { + "AddData": { + req: ReqAddData, + res: ResAddData + }, + "GetData": { + req: ReqGetData, + res: ResGetData + } + }, + msg: { + + } +} + +export const serviceProto: ServiceProto = { + "version": 1, + "services": [ + { + "id": 0, + "name": "AddData", + "type": "api" + }, + { + "id": 1, + "name": "GetData", + "type": "api" + } + ], + "types": { + "PtlAddData/ReqAddData": { + "type": "Interface", + "properties": [ + { + "id": 0, + "name": "content", + "type": { + "type": "String" + } + } + ] + }, + "PtlAddData/ResAddData": { + "type": "Interface", + "properties": [ + { + "id": 0, + "name": "time", + "type": { + "type": "Date" + } + } + ] + }, + "PtlGetData/ReqGetData": { + "type": "Interface" + }, + "PtlGetData/ResGetData": { + "type": "Interface", + "properties": [ + { + "id": 0, + "name": "data", + "type": { + "type": "Array", + "elementType": { + "type": "Interface", + "properties": [ + { + "id": 0, + "name": "content", + "type": { + "type": "String" + } + }, + { + "id": 1, + "name": "time", + "type": { + "type": "Date" + } + } + ] + } + } + } + ] + } + } +}; \ No newline at end of file diff --git a/examples/serverless-faas/backend/src/txcloud-scf.ts b/examples/serverless-faas/backend/src/txcloud-scf.ts new file mode 100644 index 0000000..c2d1eb8 --- /dev/null +++ b/examples/serverless-faas/backend/src/txcloud-scf.ts @@ -0,0 +1,26 @@ +// 腾讯云 - 云函数:SCF +// https://cloud.tencent.com/product/scf + +import { init, server } from "./models/server"; + +export async function handler(event: any, context: any) { + // init + await ensureInit(); + + let apiName = event.path.slice(event.requestContext.path.length + 1); // 从 URL 中提取 ApiName + let ret = await server.inputJSON(apiName, JSON.parse(event.body)); + + return { + "statusCode": ret.isSucc ? 200 : 500, + "headers": { "Content-Type": "application/json" }, + "body": JSON.stringify(ret) + } +} + +let promiseInit: Promise | undefined; +async function ensureInit() { + if (!promiseInit) { + promiseInit = init(true); + } + return promiseInit; +} \ No newline at end of file diff --git a/examples/serverless-faas/backend/test/api/data.test.ts b/examples/serverless-faas/backend/test/api/data.test.ts new file mode 100644 index 0000000..99916f2 --- /dev/null +++ b/examples/serverless-faas/backend/test/api/data.test.ts @@ -0,0 +1,39 @@ +import assert from 'assert'; +import { HttpClient, TsrpcError } 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('ApiGetData', function () { + let client = new HttpClient(serviceProto, { + server: 'http://127.0.0.1:3000', + logger: console + }); + + it('AddData & GetData', async function () { + // Get data before add + let ret1 = await client.callApi('GetData', {}); + assert.strictEqual(ret1.isSucc, true); + + // AddData + let ret2 = await client.callApi('AddData', { content: 'AABBCC' }); + assert.strictEqual(ret2.isSucc, true); + + // Get data again, the new data should appear + let ret3 = await client.callApi('GetData', {}); + assert.strictEqual(ret3.isSucc, true); + assert.strictEqual(ret3.res!.data.length, ret1.res!.data.length + 1); + assert.strictEqual(ret3.res!.data[0].content, 'AABBCC'); + }); + + it('AddData: Check content is empty', async function () { + let ret = await client.callApi('AddData', { + content: '' + }); + assert.deepStrictEqual(ret, { + isSucc: false, + err: new TsrpcError('Content is empty') + }); + }) +}) \ No newline at end of file diff --git a/examples/serverless-faas/backend/test/tsconfig.json b/examples/serverless-faas/backend/test/tsconfig.json new file mode 100644 index 0000000..9fc6bcd --- /dev/null +++ b/examples/serverless-faas/backend/test/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "lib": [ + "es2018" + ], + "module": "commonjs", + "target": "es2018", + "outDir": "dist", + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true, + "moduleResolution": "node" + } +} \ No newline at end of file diff --git a/examples/serverless-faas/backend/tsconfig.json b/examples/serverless-faas/backend/tsconfig.json new file mode 100644 index 0000000..d18498f --- /dev/null +++ b/examples/serverless-faas/backend/tsconfig.json @@ -0,0 +1,18 @@ +{ + "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/examples/serverless-faas/backend/tsrpc.config.ts b/examples/serverless-faas/backend/tsrpc.config.ts new file mode 100644 index 0000000..32306a3 --- /dev/null +++ b/examples/serverless-faas/backend/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 diff --git a/examples/serverless-faas/backend/yarn.lock b/examples/serverless-faas/backend/yarn.lock new file mode 100644 index 0000000..cb3612f --- /dev/null +++ b/examples/serverless-faas/backend/yarn.lock @@ -0,0 +1,1315 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@blakeembrey/deque@^1.0.5": + version "1.0.5" + resolved "https://registry.npmmirror.com/@blakeembrey/deque/download/@blakeembrey/deque-1.0.5.tgz#f4fa17fc5ee18317ec01a763d355782c7b395eaf" + integrity sha1-9PoX/F7hgxfsAadj01V4LHs5Xq8= + +"@blakeembrey/template@^1.0.0": + version "1.0.0" + resolved "https://registry.npmmirror.com/@blakeembrey/template/download/@blakeembrey/template-1.0.0.tgz#bf8828bc3ae8004d97904d78f64e3cc2cd216438" + integrity sha1-v4govDroAE2XkE149k48ws0hZDg= + +"@cspotcode/source-map-consumer@0.8.0": + version "0.8.0" + resolved "https://registry.npmmirror.com/@cspotcode/source-map-consumer/download/@cspotcode/source-map-consumer-0.8.0.tgz#33bf4b7b39c178821606f669bbc447a6a629786b" + integrity sha1-M79LeznBeIIWBvZpu8RHpqYpeGs= + +"@cspotcode/source-map-support@0.7.0": + version "0.7.0" + resolved "https://registry.npmmirror.com/@cspotcode/source-map-support/download/@cspotcode/source-map-support-0.7.0.tgz#4789840aa859e46d2f3173727ab707c66bf344f5" + integrity sha1-R4mECqhZ5G0vMXNyercHxmvzRPU= + dependencies: + "@cspotcode/source-map-consumer" "0.8.0" + +"@tsconfig/node10@^1.0.7": + version "1.0.8" + resolved "https://registry.npmmirror.com/@tsconfig/node10/download/@tsconfig/node10-1.0.8.tgz#c1e4e80d6f964fbecb3359c43bd48b40f7cadad9" + integrity sha1-weToDW+WT77LM1nEO9SLQPfK2tk= + +"@tsconfig/node12@^1.0.7": + version "1.0.9" + resolved "https://registry.npmmirror.com/@tsconfig/node12/download/@tsconfig/node12-1.0.9.tgz#62c1f6dee2ebd9aead80dc3afa56810e58e1a04c" + integrity sha1-YsH23uLr2a6tgNw6+laBDljhoEw= + +"@tsconfig/node14@^1.0.0": + version "1.0.1" + resolved "https://registry.npmmirror.com/@tsconfig/node14/download/@tsconfig/node14-1.0.1.tgz#95f2d167ffb9b8d2068b0b235302fafd4df711f2" + integrity sha1-lfLRZ/+5uNIGiwsjUwL6/U33EfI= + +"@tsconfig/node16@^1.0.2": + version "1.0.2" + resolved "https://registry.npmmirror.com/@tsconfig/node16/download/@tsconfig/node16-1.0.2.tgz#423c77877d0569db20e1fc80885ac4118314010e" + integrity sha1-Qjx3h30Fadsg4fyAiFrEEYMUAQ4= + +"@types/mocha@^8.2.3": + version "8.2.3" + resolved "https://registry.npmmirror.com/@types/mocha/download/@types/mocha-8.2.3.tgz?cache=0&sync_timestamp=1637283988208&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2F%40types%2Fmocha%2Fdownload%2F%40types%2Fmocha-8.2.3.tgz#bbeb55fbc73f28ea6de601fbfa4613f58d785323" + integrity sha1-u+tV+8c/KOpt5gH7+kYT9Y14UyM= + +"@types/node@*": + version "17.0.4" + resolved "https://registry.npmmirror.com/@types/node/download/@types/node-17.0.4.tgz#fec0ce0526abb6062fd206d72a642811b887a111" + integrity sha512-6xwbrW4JJiJLgF+zNypN5wr2ykM9/jHcL7rQ8fZe2vuftggjzZeRSM4OwRc6Xk8qWjwJ99qVHo/JgOGmomWRog== + +"@types/node@^15.14.9": + version "15.14.9" + resolved "https://registry.npmmirror.com/@types/node/download/@types/node-15.14.9.tgz#bc43c990c3c9be7281868bbc7b8fdd6e2b57adfa" + integrity sha512-qjd88DrCxupx/kJD5yQgZdcYKZKSIGBVDIBE1/LTGcNm3d2Np/jxojkdePDdfnBHJc5W7vSMpbJ1aB7p/Py69A== + +"@types/ws@^7.4.7": + version "7.4.7" + resolved "https://registry.npmmirror.com/@types/ws/download/@types/ws-7.4.7.tgz#f7c390a36f7a0679aa69de2d501319f4f8d9b702" + integrity sha1-98OQo296Bnmqad4tUBMZ9PjZtwI= + dependencies: + "@types/node" "*" + +"@ungap/promise-all-settled@1.1.2": + version "1.1.2" + resolved "https://registry.npmmirror.com/@ungap/promise-all-settled/download/@ungap/promise-all-settled-1.1.2.tgz#aa58042711d6e3275dd37dc597e5d31e8c290a44" + integrity sha1-qlgEJxHW4ydd033Fl+XTHowpCkQ= + +acorn-walk@^8.1.1: + version "8.2.0" + resolved "https://registry.npmmirror.com/acorn-walk/download/acorn-walk-8.2.0.tgz#741210f2e2426454508853a2f44d0ab83b7f69c1" + integrity sha1-dBIQ8uJCZFRQiFOi9E0KuDt/acE= + +acorn@^8.4.1: + version "8.6.0" + resolved "https://registry.npmmirror.com/acorn/download/acorn-8.6.0.tgz?cache=0&sync_timestamp=1637225522161&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Facorn%2Fdownload%2Facorn-8.6.0.tgz#e3692ba0eb1a0c83eaa4f37f5fa7368dd7142895" + integrity sha512-U1riIR+lBSNi3IbxtaHOIKdH8sLFv3NYfNv8sg7ZsNhcfl4HF2++BfqqrNAxoCLQW1iiylOj76ecnaUxz+z9yw== + +ansi-colors@4.1.1: + version "4.1.1" + resolved "https://registry.npmmirror.com/ansi-colors/download/ansi-colors-4.1.1.tgz#cbb9ae256bf750af1eab344f229aa27fe94ba348" + integrity sha1-y7muJWv3UK8eqzRPIpqif+lLo0g= + +ansi-escapes@^4.2.1: + version "4.3.2" + resolved "https://registry.npmmirror.com/ansi-escapes/download/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e" + integrity sha1-ayKR0dt9mLZSHV8e+kLQ86n+tl4= + dependencies: + type-fest "^0.21.3" + +ansi-regex@^5.0.1: + version "5.0.1" + resolved "https://registry.npmmirror.com/ansi-regex/download/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" + integrity sha1-CCyyyJyf6GWaMRpTvWpNxTAdswQ= + +ansi-styles@^4.0.0, ansi-styles@^4.1.0: + version "4.3.0" + resolved "https://registry.npmmirror.com/ansi-styles/download/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" + integrity sha1-7dgDYornHATIWuegkG7a00tkiTc= + dependencies: + color-convert "^2.0.1" + +anymatch@~3.1.2: + version "3.1.2" + resolved "https://registry.npmmirror.com/anymatch/download/anymatch-3.1.2.tgz#c0557c096af32f106198f4f4e2a383537e378716" + integrity sha1-wFV8CWrzLxBhmPT04qODU343hxY= + dependencies: + normalize-path "^3.0.0" + picomatch "^2.0.4" + +arg@^4.1.0, arg@^4.1.3: + version "4.1.3" + resolved "https://registry.npmmirror.com/arg/download/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089" + integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA== + +argparse@^2.0.1: + version "2.0.1" + resolved "https://registry.npmmirror.com/argparse/download/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" + integrity sha1-JG9Q88p4oyQPbJl+ipvR6sSeSzg= + +balanced-match@^1.0.0: + version "1.0.2" + resolved "https://registry.npmmirror.com/balanced-match/download/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" + integrity sha1-6D46fj8wCzTLnYf2FfoMvzV2kO4= + +base64-js@^1.3.1: + version "1.5.1" + resolved "https://registry.npmmirror.com/base64-js/download/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" + integrity sha1-GxtEAWClv3rUC2UPCVljSBkDkwo= + +binary-extensions@^2.0.0: + version "2.2.0" + resolved "https://registry.npmmirror.com/binary-extensions/download/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d" + integrity sha1-dfUC7q+f/eQvyYgpZFvk6na9ni0= + +bl@^4.1.0: + version "4.1.0" + resolved "https://registry.npmmirror.com/bl/download/bl-4.1.0.tgz#451535264182bec2fbbc83a62ab98cf11d9f7b3a" + integrity sha1-RRU1JkGCvsL7vIOmKrmM8R2fezo= + dependencies: + buffer "^5.5.0" + inherits "^2.0.4" + readable-stream "^3.4.0" + +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.npmmirror.com/brace-expansion/download/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + integrity sha1-PH/L9SnYcibz0vUrlm/1Jx60Qd0= + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +braces@~3.0.2: + version "3.0.2" + resolved "https://registry.npmmirror.com/braces/download/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" + integrity sha1-NFThpGLujVmeI23zNs2epPiv4Qc= + dependencies: + fill-range "^7.0.1" + +browser-stdout@1.3.1: + version "1.3.1" + resolved "https://registry.npmmirror.com/browser-stdout/download/browser-stdout-1.3.1.tgz#baa559ee14ced73452229bad7326467c61fabd60" + integrity sha1-uqVZ7hTO1zRSIputcyZGfGH6vWA= + +bson@*: + version "4.6.0" + resolved "https://registry.npmmirror.com/bson/download/bson-4.6.0.tgz#15c3b39ba3940c3d915a0c44d51459f4b4fbf1b2" + integrity sha512-8jw1NU1hglS+Da1jDOUYuNcBJ4cNHCFIqzlwoFNnsTOg2R/ox0aTYcTiBN4dzRa9q7Cvy6XErh3L8ReTEb9AQQ== + dependencies: + buffer "^5.6.0" + +buffer@^5.5.0, buffer@^5.6.0: + version "5.7.1" + resolved "https://registry.npmmirror.com/buffer/download/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0" + integrity sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ== + dependencies: + base64-js "^1.3.1" + ieee754 "^1.1.13" + +camelcase@^6.0.0: + version "6.2.1" + resolved "https://registry.npmmirror.com/camelcase/download/camelcase-6.2.1.tgz?cache=0&sync_timestamp=1636945190375&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fcamelcase%2Fdownload%2Fcamelcase-6.2.1.tgz#250fd350cfd555d0d2160b1d51510eaf8326e86e" + integrity sha512-tVI4q5jjFV5CavAU8DXfza/TJcZutVKo/5Foskmsqcm0MsL91moHvwiGNnqaa2o6PF/7yT5ikDRcVcl8Rj6LCA== + +chalk@^4.1.0, chalk@^4.1.1, chalk@^4.1.2: + version "4.1.2" + resolved "https://registry.npmmirror.com/chalk/download/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" + integrity sha1-qsTit3NKdAhnrrFr8CqtVWoeegE= + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + +chardet@^0.7.0: + version "0.7.0" + resolved "https://registry.npmmirror.com/chardet/download/chardet-0.7.0.tgz?cache=0&sync_timestamp=1634639163489&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fchardet%2Fdownload%2Fchardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e" + integrity sha1-kAlISfCTfy7twkJdDSip5fDLrZ4= + +chokidar@3.5.2, chokidar@^3.3.1, chokidar@^3.5.2: + version "3.5.2" + resolved "https://registry.npmmirror.com/chokidar/download/chokidar-3.5.2.tgz#dba3976fcadb016f66fd365021d91600d01c1e75" + integrity sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ== + dependencies: + anymatch "~3.1.2" + braces "~3.0.2" + glob-parent "~5.1.2" + is-binary-path "~2.1.0" + is-glob "~4.0.1" + normalize-path "~3.0.0" + readdirp "~3.6.0" + optionalDependencies: + fsevents "~2.3.2" + +cli-cursor@^3.1.0: + version "3.1.0" + resolved "https://registry.npmmirror.com/cli-cursor/download/cli-cursor-3.1.0.tgz#264305a7ae490d1d03bf0c9ba7c925d1753af307" + integrity sha1-JkMFp65JDR0Dvwybp8kl0XU68wc= + dependencies: + restore-cursor "^3.1.0" + +cli-spinners@^2.5.0: + version "2.6.1" + resolved "https://registry.npmmirror.com/cli-spinners/download/cli-spinners-2.6.1.tgz?cache=0&sync_timestamp=1633109592807&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fcli-spinners%2Fdownload%2Fcli-spinners-2.6.1.tgz#adc954ebe281c37a6319bfa401e6dd2488ffb70d" + integrity sha1-rclU6+KBw3pjGb+kAebdJIj/tw0= + +cli-width@^3.0.0: + version "3.0.0" + resolved "https://registry.npmmirror.com/cli-width/download/cli-width-3.0.0.tgz#a2f48437a2caa9a22436e794bf071ec9e61cedf6" + integrity sha1-ovSEN6LKqaIkNueUvwceyeYc7fY= + +cliui@^7.0.2: + version "7.0.4" + resolved "https://registry.npmmirror.com/cliui/download/cliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f" + integrity sha1-oCZe5lVHb8gHrqnfPfjfd4OAi08= + dependencies: + string-width "^4.2.0" + strip-ansi "^6.0.0" + wrap-ansi "^7.0.0" + +clone@^1.0.2: + version "1.0.4" + resolved "https://registry.npmmirror.com/clone/download/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e" + integrity sha1-2jCcwmPfFZlMaIypAheco8fNfH4= + +color-convert@^2.0.1: + version "2.0.1" + resolved "https://registry.npmmirror.com/color-convert/download/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" + integrity sha1-ctOmjVmMm9s68q0ehPIdiWq9TeM= + dependencies: + color-name "~1.1.4" + +color-name@~1.1.4: + version "1.1.4" + resolved "https://registry.npmmirror.com/color-name/download/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" + integrity sha1-wqCah6y95pVD3m9j+jmVyCbFNqI= + +colors@^1.1.2: + version "1.4.0" + resolved "https://registry.npmmirror.com/colors/download/colors-1.4.0.tgz#c50491479d4c1bdaed2c9ced32cf7c7dc2360f78" + integrity sha1-xQSRR51MG9rtLJztMs98fcI2D3g= + +commander@^2.19.0: + version "2.20.3" + resolved "https://registry.npmmirror.com/commander/download/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" + integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== + +commandpost@^1.0.0: + version "1.4.0" + resolved "https://registry.npmmirror.com/commandpost/download/commandpost-1.4.0.tgz#89218012089dfc9b67a337ba162f15c88e0f1048" + integrity sha1-iSGAEgid/Jtnoze6Fi8VyI4PEEg= + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.npmmirror.com/concat-map/download/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= + +create-require@^1.1.0: + version "1.1.1" + resolved "https://registry.npmmirror.com/create-require/download/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333" + integrity sha1-wdfo8eX2z8n/ZfnNNS03NIdWwzM= + +cross-spawn@^7.0.0, cross-spawn@^7.0.1: + version "7.0.3" + resolved "https://registry.npmmirror.com/cross-spawn/download/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" + integrity sha1-9zqFudXUHQRVUcF34ogtSshXKKY= + dependencies: + path-key "^3.1.0" + shebang-command "^2.0.0" + which "^2.0.1" + +debug@4.3.2: + version "4.3.2" + resolved "https://registry.npmmirror.com/debug/download/debug-4.3.2.tgz#f0a49c18ac8779e31d4a0c6029dfb76873c7428b" + integrity sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw== + dependencies: + ms "2.1.2" + +decamelize@^4.0.0: + version "4.0.0" + resolved "https://registry.npmmirror.com/decamelize/download/decamelize-4.0.0.tgz?cache=0&sync_timestamp=1633055713394&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fdecamelize%2Fdownload%2Fdecamelize-4.0.0.tgz#aa472d7bf660eb15f3494efd531cab7f2a709837" + integrity sha1-qkcte/Zg6xXzSU79UxyrfypwmDc= + +defaults@^1.0.3: + version "1.0.3" + resolved "https://registry.npmmirror.com/defaults/download/defaults-1.0.3.tgz#c656051e9817d9ff08ed881477f3fe4019f3ef7d" + integrity sha1-xlYFHpgX2f8I7YgUd/P+QBnz730= + dependencies: + clone "^1.0.2" + +diff@5.0.0: + version "5.0.0" + resolved "https://registry.npmmirror.com/diff/download/diff-5.0.0.tgz#7ed6ad76d859d030787ec35855f5b1daf31d852b" + integrity sha1-ftatdthZ0DB4fsNYVfWx2vMdhSs= + +diff@^4.0.1: + version "4.0.2" + resolved "https://registry.npmmirror.com/diff/download/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" + integrity sha1-YPOuy4nV+uUgwRqhnvwruYKq3n0= + +editorconfig@^0.15.0: + version "0.15.3" + resolved "https://registry.npmmirror.com/editorconfig/download/editorconfig-0.15.3.tgz#bef84c4e75fb8dcb0ce5cee8efd51c15999befc5" + integrity sha1-vvhMTnX7jcsM5c7o79UcFZmb78U= + dependencies: + commander "^2.19.0" + lru-cache "^4.1.5" + semver "^5.6.0" + sigmund "^1.0.1" + +emoji-regex@^8.0.0: + version "8.0.0" + resolved "https://registry.npmmirror.com/emoji-regex/download/emoji-regex-8.0.0.tgz?cache=0&sync_timestamp=1632752198735&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Femoji-regex%2Fdownload%2Femoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" + integrity sha1-6Bj9ac5cz8tARZT4QpY79TFkzDc= + +end-of-stream@^1.1.0: + version "1.4.4" + resolved "https://registry.npmmirror.com/end-of-stream/download/end-of-stream-1.4.4.tgz?cache=0&sync_timestamp=1632469585035&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fend-of-stream%2Fdownload%2Fend-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" + integrity sha1-WuZKX0UFe682JuwU2gyl5LJDHrA= + dependencies: + once "^1.4.0" + +escalade@^3.1.1: + version "3.1.1" + resolved "https://registry.npmmirror.com/escalade/download/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" + integrity sha1-2M/ccACWXFoBdLSoLqpcBVJ0LkA= + +escape-string-regexp@4.0.0: + version "4.0.0" + resolved "https://registry.npmmirror.com/escape-string-regexp/download/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" + integrity sha1-FLqDpdNz49MR5a/KKc9b+tllvzQ= + +escape-string-regexp@^1.0.5: + version "1.0.5" + resolved "https://registry.npmmirror.com/escape-string-regexp/download/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= + +execa@^4.0.0: + version "4.1.0" + resolved "https://registry.npmmirror.com/execa/download/execa-4.1.0.tgz?cache=0&sync_timestamp=1637147236741&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fexeca%2Fdownload%2Fexeca-4.1.0.tgz#4e5491ad1572f2f17a77d388c6c857135b22847a" + integrity sha1-TlSRrRVy8vF6d9OIxshXE1sihHo= + 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" + +external-editor@^3.0.3: + version "3.1.0" + resolved "https://registry.npmmirror.com/external-editor/download/external-editor-3.1.0.tgz#cb03f740befae03ea4d283caed2741a83f335495" + integrity sha1-ywP3QL764D6k0oPK7SdBqD8zVJU= + dependencies: + chardet "^0.7.0" + iconv-lite "^0.4.24" + tmp "^0.0.33" + +figures@^3.0.0: + version "3.2.0" + resolved "https://registry.npmmirror.com/figures/download/figures-3.2.0.tgz#625c18bd293c604dc4a8ddb2febf0c88341746af" + integrity sha1-YlwYvSk8YE3EqN2y/r8MiDQXRq8= + dependencies: + escape-string-regexp "^1.0.5" + +fill-range@^7.0.1: + version "7.0.1" + resolved "https://registry.npmmirror.com/fill-range/download/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" + integrity sha1-GRmmp8df44ssfHflGYU12prN2kA= + dependencies: + to-regex-range "^5.0.1" + +find-up@5.0.0: + version "5.0.0" + resolved "https://registry.npmmirror.com/find-up/download/find-up-5.0.0.tgz?cache=0&sync_timestamp=1633618659233&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Ffind-up%2Fdownload%2Ffind-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc" + integrity sha1-TJKBnstwg1YeT0okCoa+UZj1Nvw= + dependencies: + locate-path "^6.0.0" + path-exists "^4.0.0" + +flat@^5.0.2: + version "5.0.2" + resolved "https://registry.npmmirror.com/flat/download/flat-5.0.2.tgz#8ca6fe332069ffa9d324c327198c598259ceb241" + integrity sha1-jKb+MyBp/6nTJMMnGYxZglnOskE= + +fs-extra@^10.0.0: + version "10.0.0" + resolved "https://registry.npmmirror.com/fs-extra/download/fs-extra-10.0.0.tgz#9ff61b655dde53fb34a82df84bb214ce802e17c1" + integrity sha1-n/YbZV3eU/s0qC34S7IUzoAuF8E= + dependencies: + graceful-fs "^4.2.0" + jsonfile "^6.0.1" + universalify "^2.0.0" + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.npmmirror.com/fs.realpath/download/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= + +fsevents@~2.3.2: + version "2.3.2" + resolved "https://registry.npmmirror.com/fsevents/download/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" + integrity sha1-ilJveLj99GI7cJ4Ll1xSwkwC/Ro= + +get-caller-file@^2.0.5: + version "2.0.5" + resolved "https://registry.npmmirror.com/get-caller-file/download/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" + integrity sha1-T5RBKoLbMvNuOwuXQfipf+sDH34= + +get-stream@^5.0.0: + version "5.2.0" + resolved "https://registry.npmmirror.com/get-stream/download/get-stream-5.2.0.tgz#4966a1795ee5ace65e706c4b7beb71257d6e22d3" + integrity sha1-SWaheV7lrOZecGxLe+txJX1uItM= + dependencies: + pump "^3.0.0" + +glob-parent@~5.1.2: + version "5.1.2" + resolved "https://registry.npmmirror.com/glob-parent/download/glob-parent-5.1.2.tgz?cache=0&sync_timestamp=1632953971963&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fglob-parent%2Fdownload%2Fglob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" + integrity sha1-hpgyxYA0/mikCTwX3BXoNA2EAcQ= + dependencies: + is-glob "^4.0.1" + +glob@7.1.7: + version "7.1.7" + resolved "https://registry.npmmirror.com/glob/download/glob-7.1.7.tgz#3b193e9233f01d42d0b3f78294bbeeb418f94a90" + integrity sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + +glob@^7.2.0: + version "7.2.0" + resolved "https://registry.npmmirror.com/glob/download/glob-7.2.0.tgz#d15535af7732e02e948f4c41628bd910293f6023" + integrity sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + +graceful-fs@^4.1.6, graceful-fs@^4.2.0: + version "4.2.8" + resolved "https://registry.npmmirror.com/graceful-fs/download/graceful-fs-4.2.8.tgz#e412b8d33f5e006593cbd3cee6df9f2cebbe802a" + integrity sha1-5BK40z9eAGWTy9PO5t+fLOu+gCo= + +growl@1.10.5: + version "1.10.5" + resolved "https://registry.npmmirror.com/growl/download/growl-1.10.5.tgz#f2735dc2283674fa67478b10181059355c369e5e" + integrity sha1-8nNdwig2dPpnR4sQGBBZNVw2nl4= + +has-flag@^4.0.0: + version "4.0.0" + resolved "https://registry.npmmirror.com/has-flag/download/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" + integrity sha1-lEdx/ZyByBJlxNaUGGDaBrtZR5s= + +he@1.2.0: + version "1.2.0" + resolved "https://registry.npmmirror.com/he/download/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" + integrity sha1-hK5l+n6vsWX922FWauFLrwVmTw8= + +human-signals@^1.1.1: + version "1.1.1" + resolved "https://registry.npmmirror.com/human-signals/download/human-signals-1.1.1.tgz#c5b1cd14f50aeae09ab6c59fe63ba3395fe4dfa3" + integrity sha1-xbHNFPUK6uCatsWf5jujOV/k36M= + +iconv-lite@^0.4.24: + version "0.4.24" + resolved "https://registry.npmmirror.com/iconv-lite/download/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" + integrity sha1-ICK0sl+93CHS9SSXSkdKr+czkIs= + dependencies: + safer-buffer ">= 2.1.2 < 3" + +ieee754@^1.1.13: + version "1.2.1" + resolved "https://registry.npmmirror.com/ieee754/download/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" + integrity sha1-jrehCmP/8l0VpXsAFYbRd9Gw01I= + +ignore@^5.1.4: + version "5.2.0" + resolved "https://registry.npmmirror.com/ignore/download/ignore-5.2.0.tgz#6d3bac8fa7fe0d45d9f9be7bac2fc279577e345a" + integrity sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ== + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.npmmirror.com/inflight/download/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2, inherits@^2.0.3, inherits@^2.0.4: + version "2.0.4" + resolved "https://registry.npmmirror.com/inherits/download/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha1-D6LGT5MpF8NDOg3tVTY6rjdBa3w= + +inquirer@^8.2.0: + version "8.2.0" + resolved "https://registry.npmmirror.com/inquirer/download/inquirer-8.2.0.tgz#f44f008dd344bbfc4b30031f45d984e034a3ac3a" + integrity sha512-0crLweprevJ02tTuA6ThpoAERAGyVILC4sS74uib58Xf/zSr1/ZWtmm7D5CI+bSQEaA04f0K7idaHpQbSWgiVQ== + 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.2.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + through "^2.3.6" + +invert-kv@^3.0.0: + version "3.0.1" + resolved "https://registry.npmmirror.com/invert-kv/download/invert-kv-3.0.1.tgz#a93c7a3d4386a1dc8325b97da9bb1620c0282523" + integrity sha1-qTx6PUOGodyDJbl9qbsWIMAoJSM= + +is-binary-path@~2.1.0: + version "2.1.0" + resolved "https://registry.npmmirror.com/is-binary-path/download/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" + integrity sha1-6h9/O4DwZCNug0cPhsCcJU+0Wwk= + dependencies: + binary-extensions "^2.0.0" + +is-extglob@^2.1.1: + version "2.1.1" + resolved "https://registry.npmmirror.com/is-extglob/download/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= + +is-fullwidth-code-point@^3.0.0: + version "3.0.0" + resolved "https://registry.npmmirror.com/is-fullwidth-code-point/download/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" + integrity sha1-8Rb4Bk/pCz94RKOJl8C3UFEmnx0= + +is-glob@^4.0.1, is-glob@~4.0.1: + version "4.0.3" + resolved "https://registry.npmmirror.com/is-glob/download/is-glob-4.0.3.tgz?cache=0&sync_timestamp=1632934382080&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fis-glob%2Fdownload%2Fis-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" + integrity sha1-ZPYeQsu7LuwgcanawLKLoeZdUIQ= + dependencies: + is-extglob "^2.1.1" + +is-interactive@^1.0.0: + version "1.0.0" + resolved "https://registry.npmmirror.com/is-interactive/download/is-interactive-1.0.0.tgz#cea6e6ae5c870a7b0a0004070b7b587e0252912e" + integrity sha1-zqbmrlyHCnsKAAQHC3tYfgJSkS4= + +is-number@^7.0.0: + version "7.0.0" + resolved "https://registry.npmmirror.com/is-number/download/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" + integrity sha1-dTU0W4lnNNX4DE0GxQlVUnoU8Ss= + +is-plain-obj@^2.1.0: + version "2.1.0" + resolved "https://registry.npmmirror.com/is-plain-obj/download/is-plain-obj-2.1.0.tgz#45e42e37fccf1f40da8e5f76ee21515840c09287" + integrity sha1-ReQuN/zPH0Dajl927iFRWEDAkoc= + +is-stream@^2.0.0: + version "2.0.1" + resolved "https://registry.npmmirror.com/is-stream/download/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077" + integrity sha1-+sHj1TuXrVqdCunO8jifWBClwHc= + +is-unicode-supported@^0.1.0: + version "0.1.0" + resolved "https://registry.npmmirror.com/is-unicode-supported/download/is-unicode-supported-0.1.0.tgz#3f26c76a809593b52bfa2ecb5710ed2779b522a7" + integrity sha1-PybHaoCVk7Ur+i7LVxDtJ3m1Iqc= + +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.npmmirror.com/isexe/download/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= + +js-yaml@4.1.0: + version "4.1.0" + resolved "https://registry.npmmirror.com/js-yaml/download/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" + integrity sha1-wftl+PUBeQHN0slRhkuhhFihBgI= + dependencies: + argparse "^2.0.1" + +jsonfile@^6.0.1: + version "6.1.0" + resolved "https://registry.npmmirror.com/jsonfile/download/jsonfile-6.1.0.tgz#bc55b2634793c679ec6403094eb13698a6ec0aae" + integrity sha1-vFWyY0eTxnnsZAMJTrE2mKbsCq4= + dependencies: + universalify "^2.0.0" + optionalDependencies: + graceful-fs "^4.1.6" + +k8w-crypto@^0.2.0: + version "0.2.0" + resolved "https://registry.npmmirror.com/k8w-crypto/download/k8w-crypto-0.2.0.tgz#00e6f3027832eeade06fd79c9c3a1ebfb76c964f" + integrity sha1-AObzAngy7q3gb9ecnDoev7dslk8= + +k8w-extend-native@^1.4.6: + version "1.4.6" + resolved "https://registry.npmmirror.com/k8w-extend-native/download/k8w-extend-native-1.4.6.tgz#d3008c60f3f85e5b2f2bd8617ff4a5bc9cf743a6" + integrity sha1-0wCMYPP4XlsvK9hhf/SlvJz3Q6Y= + dependencies: + k8w-linq-array "*" + k8w-super-date "*" + k8w-super-object "*" + +k8w-linq-array@*: + version "0.2.8" + resolved "https://registry.npmmirror.com/k8w-linq-array/download/k8w-linq-array-0.2.8.tgz#1ef4d4a2943552cbd5f633a5d9b8e831dc8abd6e" + integrity sha1-HvTUopQ1UsvV9jOl2bjoMdyKvW4= + +k8w-super-date@*: + version "0.1.3" + resolved "https://registry.npmmirror.com/k8w-super-date/download/k8w-super-date-0.1.3.tgz#4f53a39f2b74e21b11268926b710e5a7c27f8848" + integrity sha1-T1Ojnyt04hsRJokmtxDlp8J/iEg= + +k8w-super-object@*: + version "0.3.0" + resolved "https://registry.npmmirror.com/k8w-super-object/download/k8w-super-object-0.3.0.tgz#6430d14956aaf3a936fda7776b0897a04db331dd" + integrity sha1-ZDDRSVaq86k2/ad3awiXoE2zMd0= + +lcid@^3.0.0: + version "3.1.1" + resolved "https://registry.npmmirror.com/lcid/download/lcid-3.1.1.tgz#9030ec479a058fc36b5e8243ebaac8b6ac582fd0" + integrity sha1-kDDsR5oFj8NrXoJD66rItqxYL9A= + dependencies: + invert-kv "^3.0.0" + +locate-path@^6.0.0: + version "6.0.0" + resolved "https://registry.npmmirror.com/locate-path/download/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286" + integrity sha1-VTIeswn+u8WcSAHZMackUqaB0oY= + dependencies: + p-locate "^5.0.0" + +lodash@^4.17.21: + version "4.17.21" + resolved "https://registry.npmmirror.com/lodash/download/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" + integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== + +log-symbols@4.1.0, log-symbols@^4.1.0: + version "4.1.0" + resolved "https://registry.npmmirror.com/log-symbols/download/log-symbols-4.1.0.tgz#3fbdbb95b4683ac9fc785111e792e558d4abd503" + integrity sha1-P727lbRoOsn8eFER55LlWNSr1QM= + dependencies: + chalk "^4.1.0" + is-unicode-supported "^0.1.0" + +lru-cache@^4.1.5: + version "4.1.5" + resolved "https://registry.npmmirror.com/lru-cache/download/lru-cache-4.1.5.tgz#8bbe50ea85bed59bc9e33dcab8235ee9bcf443cd" + integrity sha1-i75Q6oW+1ZvJ4z3KuCNe6bz0Q80= + dependencies: + pseudomap "^1.0.2" + yallist "^2.1.2" + +make-error@^1.1.1: + version "1.3.6" + resolved "https://registry.npmmirror.com/make-error/download/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" + integrity sha1-LrLjfqm2fEiR9oShOUeZr0hM96I= + +map-age-cleaner@^0.1.3: + version "0.1.3" + resolved "https://registry.npmmirror.com/map-age-cleaner/download/map-age-cleaner-0.1.3.tgz#7d583a7306434c055fe474b0f45078e6e1b4b92a" + integrity sha1-fVg6cwZDTAVf5HSw9FB45uG0uSo= + dependencies: + p-defer "^1.0.0" + +mem@^5.0.0: + version "5.1.1" + resolved "https://registry.npmmirror.com/mem/download/mem-5.1.1.tgz#7059b67bf9ac2c924c9f1cff7155a064394adfb3" + integrity sha1-cFm2e/msLJJMnxz/cVWgZDlK37M= + dependencies: + map-age-cleaner "^0.1.3" + mimic-fn "^2.1.0" + p-is-promise "^2.1.0" + +merge-stream@^2.0.0: + version "2.0.0" + resolved "https://registry.npmmirror.com/merge-stream/download/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" + integrity sha1-UoI2KaFN0AyXcPtq1H3GMQ8sH2A= + +mimic-fn@^2.1.0: + version "2.1.0" + resolved "https://registry.npmmirror.com/mimic-fn/download/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" + integrity sha1-ftLCzMyvhNP/y3pptXcR/CCDQBs= + +minimatch@3.0.4, minimatch@^3.0.4: + version "3.0.4" + resolved "https://registry.npmmirror.com/minimatch/download/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" + integrity sha1-UWbihkV/AzBgZL5Ul+jbsMPTIIM= + dependencies: + brace-expansion "^1.1.7" + +minimist@^1.2.5: + version "1.2.5" + resolved "https://registry.npmmirror.com/minimist/download/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" + integrity sha1-Z9ZgFLZqaoqqDAg8X9WN9OTpdgI= + +mocha@^9.1.3: + version "9.1.3" + resolved "https://registry.npmmirror.com/mocha/download/mocha-9.1.3.tgz?cache=0&sync_timestamp=1634283119059&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fmocha%2Fdownload%2Fmocha-9.1.3.tgz#8a623be6b323810493d8c8f6f7667440fa469fdb" + integrity sha1-imI75rMjgQST2Mj292Z0QPpGn9s= + dependencies: + "@ungap/promise-all-settled" "1.1.2" + ansi-colors "4.1.1" + browser-stdout "1.3.1" + chokidar "3.5.2" + debug "4.3.2" + diff "5.0.0" + escape-string-regexp "4.0.0" + find-up "5.0.0" + glob "7.1.7" + growl "1.10.5" + he "1.2.0" + js-yaml "4.1.0" + log-symbols "4.1.0" + minimatch "3.0.4" + ms "2.1.3" + nanoid "3.1.25" + serialize-javascript "6.0.0" + strip-json-comments "3.1.1" + supports-color "8.1.1" + which "2.0.2" + workerpool "6.1.5" + yargs "16.2.0" + yargs-parser "20.2.4" + yargs-unparser "2.0.0" + +ms@2.1.2: + version "2.1.2" + resolved "https://registry.npmmirror.com/ms/download/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" + integrity sha1-0J0fNXtEP0kzgqjrPM0YOHKuYAk= + +ms@2.1.3: + version "2.1.3" + resolved "https://registry.npmmirror.com/ms/download/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" + integrity sha1-V0yBOM4dK1hh8LRFedut1gxmFbI= + +mute-stream@0.0.8: + version "0.0.8" + resolved "https://registry.npmmirror.com/mute-stream/download/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d" + integrity sha1-FjDEKyJR/4HiooPelqVJfqkuXg0= + +nanoid@3.1.25: + version "3.1.25" + resolved "https://registry.npmmirror.com/nanoid/download/nanoid-3.1.25.tgz#09ca32747c0e543f0e1814b7d3793477f9c8e152" + integrity sha512-rdwtIXaXCLFAQbnfqDRnI6jaRHp9fTcYBjtFKE8eezcZ7LuLjhUaQGNeMXf1HmRoCH32CLz6XwX0TtxEOS/A3Q== + +node-json-color-stringify@^1.1.0: + version "1.1.0" + resolved "https://registry.npmmirror.com/node-json-color-stringify/download/node-json-color-stringify-1.1.0.tgz#8bb124f913859591058026513121d6609d6ef5b7" + integrity sha1-i7Ek+ROFlZEFgCZRMSHWYJ1u9bc= + dependencies: + colors "^1.1.2" + +normalize-path@^3.0.0, normalize-path@~3.0.0: + version "3.0.0" + resolved "https://registry.npmmirror.com/normalize-path/download/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" + integrity sha1-Dc1p/yOhybEf0JeDFmRKA4ghamU= + +npm-run-path@^4.0.0: + version "4.0.1" + resolved "https://registry.npmmirror.com/npm-run-path/download/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea" + integrity sha1-t+zR5e1T2o43pV4cImnguX7XSOo= + dependencies: + path-key "^3.0.0" + +once@^1.3.0, once@^1.3.1, once@^1.4.0: + version "1.4.0" + resolved "https://registry.npmmirror.com/once/download/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= + dependencies: + wrappy "1" + +onchange@^7.1.0: + version "7.1.0" + resolved "https://registry.npmmirror.com/onchange/download/onchange-7.1.0.tgz#a6f0f7733e4d47014b4cd70aa1ad36c2b4cf3804" + integrity sha1-pvD3cz5NRwFLTNcKoa02wrTPOAQ= + 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" + +onetime@^5.1.0: + version "5.1.2" + resolved "https://registry.npmmirror.com/onetime/download/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" + integrity sha1-0Oluu1awdHbfHdnEgG5SN5hcpF4= + dependencies: + mimic-fn "^2.1.0" + +ora@^5.4.1: + version "5.4.1" + resolved "https://registry.npmmirror.com/ora/download/ora-5.4.1.tgz#1b2678426af4ac4a509008e5e4ac9e9959db9e18" + integrity sha1-GyZ4Qmr0rEpQkAjl5KyemVnbnhg= + 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" + +os-locale@^5.0.0: + version "5.0.0" + resolved "https://registry.npmmirror.com/os-locale/download/os-locale-5.0.0.tgz#6d26c1d95b6597c5d5317bf5fba37eccec3672e0" + integrity sha1-bSbB2Vtll8XVMXv1+6N+zOw2cuA= + dependencies: + execa "^4.0.0" + lcid "^3.0.0" + mem "^5.0.0" + +os-tmpdir@~1.0.2: + version "1.0.2" + resolved "https://registry.npmmirror.com/os-tmpdir/download/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" + integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ= + +p-defer@^1.0.0: + version "1.0.0" + resolved "https://registry.npmmirror.com/p-defer/download/p-defer-1.0.0.tgz#9f6eb182f6c9aa8cd743004a7d4f96b196b0fb0c" + integrity sha1-n26xgvbJqozXQwBKfU+WsZaw+ww= + +p-is-promise@^2.1.0: + version "2.1.0" + resolved "https://registry.npmmirror.com/p-is-promise/download/p-is-promise-2.1.0.tgz#918cebaea248a62cf7ffab8e3bca8c5f882fc42e" + integrity sha1-kYzrrqJIpiz3/6uOO8qMX4gvxC4= + +p-limit@^3.0.2: + version "3.1.0" + resolved "https://registry.npmmirror.com/p-limit/download/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" + integrity sha1-4drMvnjQ0TiMoYxk/qOOPlfjcGs= + dependencies: + yocto-queue "^0.1.0" + +p-locate@^5.0.0: + version "5.0.0" + resolved "https://registry.npmmirror.com/p-locate/download/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834" + integrity sha1-g8gxXGeFAF470CGDlBHJ4RDm2DQ= + dependencies: + p-limit "^3.0.2" + +path-exists@^4.0.0: + version "4.0.0" + resolved "https://registry.npmmirror.com/path-exists/download/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" + integrity sha1-UTvb4tO5XXdi6METfvoZXGxhtbM= + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.npmmirror.com/path-is-absolute/download/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= + +path-key@^3.0.0, path-key@^3.1.0: + version "3.1.1" + resolved "https://registry.npmmirror.com/path-key/download/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" + integrity sha1-WB9q3mWMu6ZaDTOA3ndTKVBU83U= + +picomatch@^2.0.4, picomatch@^2.2.1: + version "2.3.0" + resolved "https://registry.npmmirror.com/picomatch/download/picomatch-2.3.0.tgz#f1f061de8f6a4bf022892e2d128234fb98302972" + integrity sha1-8fBh3o9qS/AiiS4tEoI0+5gwKXI= + +pseudomap@^1.0.2: + version "1.0.2" + resolved "https://registry.npmmirror.com/pseudomap/download/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" + integrity sha1-8FKijacOYYkX7wqKw0wa5aaChrM= + +pump@^3.0.0: + version "3.0.0" + resolved "https://registry.npmmirror.com/pump/download/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64" + integrity sha1-tKIRaBW94vTh6mAjVOjHVWUQemQ= + dependencies: + end-of-stream "^1.1.0" + once "^1.3.1" + +randombytes@^2.1.0: + version "2.1.0" + resolved "https://registry.npmmirror.com/randombytes/download/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" + integrity sha1-32+ENy8CcNxlzfYpE0mrekc9Tyo= + dependencies: + safe-buffer "^5.1.0" + +readable-stream@^3.4.0: + version "3.6.0" + resolved "https://registry.npmmirror.com/readable-stream/download/readable-stream-3.6.0.tgz?cache=0&sync_timestamp=1632380409088&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Freadable-stream%2Fdownload%2Freadable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198" + integrity sha1-M3u9o63AcGvT4CRCaihtS0sskZg= + dependencies: + inherits "^2.0.3" + string_decoder "^1.1.1" + util-deprecate "^1.0.1" + +readdirp@~3.6.0: + version "3.6.0" + resolved "https://registry.npmmirror.com/readdirp/download/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" + integrity sha1-dKNwvYVxFuJFspzJc0DNQxoCpsc= + dependencies: + picomatch "^2.2.1" + +require-directory@^2.1.1: + version "2.1.1" + resolved "https://registry.npmmirror.com/require-directory/download/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" + integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I= + +restore-cursor@^3.1.0: + version "3.1.0" + resolved "https://registry.npmmirror.com/restore-cursor/download/restore-cursor-3.1.0.tgz#39f67c54b3a7a58cea5236d95cf0034239631f7e" + integrity sha1-OfZ8VLOnpYzqUjbZXPADQjljH34= + dependencies: + onetime "^5.1.0" + signal-exit "^3.0.2" + +run-async@^2.4.0: + version "2.4.1" + resolved "https://registry.npmmirror.com/run-async/download/run-async-2.4.1.tgz#8440eccf99ea3e70bd409d49aab88e10c189a455" + integrity sha1-hEDsz5nqPnC9QJ1JqriOEMGJpFU= + +rxjs@^7.2.0: + version "7.4.0" + resolved "https://registry.npmmirror.com/rxjs/download/rxjs-7.4.0.tgz#a12a44d7eebf016f5ff2441b87f28c9a51cebc68" + integrity sha1-oSpE1+6/AW9f8kQbh/KMmlHOvGg= + dependencies: + tslib "~2.1.0" + +safe-buffer@^5.1.0, safe-buffer@~5.2.0: + version "5.2.1" + resolved "https://registry.npmmirror.com/safe-buffer/download/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" + integrity sha1-Hq+fqb2x/dTsdfWPnNtOa3gn7sY= + +"safer-buffer@>= 2.1.2 < 3": + version "2.1.2" + resolved "https://registry.npmmirror.com/safer-buffer/download/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + integrity sha1-RPoWGwGHuVSd2Eu5GAL5vYOFzWo= + +semver@^5.6.0: + version "5.7.1" + resolved "https://registry.npmmirror.com/semver/download/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" + integrity sha1-qVT5Ma66UI0we78Gnv8MAclhFvc= + +serialize-javascript@6.0.0: + version "6.0.0" + resolved "https://registry.npmmirror.com/serialize-javascript/download/serialize-javascript-6.0.0.tgz#efae5d88f45d7924141da8b5c3a7a7e663fefeb8" + integrity sha1-765diPRdeSQUHai1w6en5mP+/rg= + dependencies: + randombytes "^2.1.0" + +shebang-command@^2.0.0: + version "2.0.0" + resolved "https://registry.npmmirror.com/shebang-command/download/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" + integrity sha1-zNCvT4g1+9wmW4JGGq8MNmY/NOo= + dependencies: + shebang-regex "^3.0.0" + +shebang-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.npmmirror.com/shebang-regex/download/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" + integrity sha1-rhbxZE2HPsrYQ7AwexQzYtTEIXI= + +sigmund@^1.0.1: + version "1.0.1" + resolved "https://registry.npmmirror.com/sigmund/download/sigmund-1.0.1.tgz#3ff21f198cad2175f9f3b781853fd94d0d19b590" + integrity sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA= + +signal-exit@^3.0.2: + version "3.0.6" + resolved "https://registry.npmmirror.com/signal-exit/download/signal-exit-3.0.6.tgz#24e630c4b0f03fea446a2bd299e62b4a6ca8d0af" + integrity sha512-sDl4qMFpijcGw22U5w63KmD3cZJfBuFlVNbVMKje2keoKML7X2UzWbc4XrmEbDwg0NXJc3yv4/ox7b+JWb57kQ== + +string-width@^4.1.0, string-width@^4.2.0: + version "4.2.3" + resolved "https://registry.npmmirror.com/string-width/download/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha1-JpxxF9J7Ba0uU2gwqOyJXvnG0BA= + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + +string_decoder@^1.1.1: + version "1.3.0" + resolved "https://registry.npmmirror.com/string_decoder/download/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" + integrity sha1-QvEUWUpGzxqOMLCoT1bHjD7awh4= + dependencies: + safe-buffer "~5.2.0" + +strip-ansi@^6.0.0, strip-ansi@^6.0.1: + version "6.0.1" + resolved "https://registry.npmmirror.com/strip-ansi/download/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha1-nibGPTD1NEPpSJSVshBdN7Z6hdk= + dependencies: + ansi-regex "^5.0.1" + +strip-final-newline@^2.0.0: + version "2.0.0" + resolved "https://registry.npmmirror.com/strip-final-newline/download/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad" + integrity sha1-ibhS+y/L6Tb29LMYevsKEsGrWK0= + +strip-json-comments@3.1.1: + version "3.1.1" + resolved "https://registry.npmmirror.com/strip-json-comments/download/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" + integrity sha1-MfEoGzgyYwQ0gxwxDAHMzajL4AY= + +supports-color@8.1.1: + version "8.1.1" + resolved "https://registry.npmmirror.com/supports-color/download/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c" + integrity sha1-zW/BfihQDP9WwbhsCn/UpUpzAFw= + dependencies: + has-flag "^4.0.0" + +supports-color@^7.1.0: + version "7.2.0" + resolved "https://registry.npmmirror.com/supports-color/download/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" + integrity sha1-G33NyzK4E4gBs+R4umpRyqiWSNo= + dependencies: + has-flag "^4.0.0" + +through@^2.3.6: + version "2.3.8" + resolved "https://registry.npmmirror.com/through/download/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" + integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= + +tmp@^0.0.33: + version "0.0.33" + resolved "https://registry.npmmirror.com/tmp/download/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" + integrity sha1-bTQzWIl2jSGyvNoKonfO07G/rfk= + dependencies: + os-tmpdir "~1.0.2" + +to-regex-range@^5.0.1: + version "5.0.1" + resolved "https://registry.npmmirror.com/to-regex-range/download/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" + integrity sha1-FkjESq58jZiKMmAY7XL1tN0DkuQ= + dependencies: + is-number "^7.0.0" + +tree-kill@^1.2.2: + version "1.2.2" + resolved "https://registry.npmmirror.com/tree-kill/download/tree-kill-1.2.2.tgz#4ca09a9092c88b73a7cdc5e8a01b507b0790a0cc" + integrity sha1-TKCakJLIi3OnzcXooBtQeweQoMw= + +ts-node@^10.4.0: + version "10.4.0" + resolved "https://registry.npmmirror.com/ts-node/download/ts-node-10.4.0.tgz#680f88945885f4e6cf450e7f0d6223dd404895f7" + integrity sha1-aA+IlFiF9ObPRQ5/DWIj3UBIlfc= + dependencies: + "@cspotcode/source-map-support" "0.7.0" + "@tsconfig/node10" "^1.0.7" + "@tsconfig/node12" "^1.0.7" + "@tsconfig/node14" "^1.0.0" + "@tsconfig/node16" "^1.0.2" + acorn "^8.4.1" + acorn-walk "^8.1.1" + arg "^4.1.0" + create-require "^1.1.0" + diff "^4.0.1" + make-error "^1.1.1" + yn "3.1.1" + +tsbuffer-proto-generator@^1.6.0: + version "1.6.0" + resolved "https://registry.npmmirror.com/tsbuffer-proto-generator/download/tsbuffer-proto-generator-1.6.0.tgz#c8708cb47e30bbd083f9d47a9444e40c9cc1a63d" + integrity sha512-sjP9Qo8RbBYjkM78yzfoES/mJa3KH+UHPJ2UJ4MYOH0RuCZoYL27Wbtb7So4axLZKi4PoULRuUf8DV1bBjfBEQ== + dependencies: + k8w-crypto "^0.2.0" + k8w-extend-native "^1.4.6" + tsbuffer-schema "^2.1.1" + tslib "^2.3.1" + typescript "^4.5.4" + +tsbuffer-schema@^2.0.8, tsbuffer-schema@^2.1.1: + version "2.1.1" + resolved "https://registry.npmmirror.com/tsbuffer-schema/download/tsbuffer-schema-2.1.1.tgz#638a05f728a8ec5c0ed036e126f4f5b350f86cb9" + integrity sha512-c76TmiIJKHTdkByAXsLZ+Oin85y41CBOiGfrrPtBOTxh2pg80bN8wpF79N4teZA/B/u6SF47tsq2XR9Ef8/6kA== + +tsbuffer-validator@^2.0.7: + version "2.0.7" + resolved "https://registry.npmmirror.com/tsbuffer-validator/download/tsbuffer-validator-2.0.7.tgz#733a1d3074437af13acf8c26b6df0c703940d7f5" + integrity sha512-iffKO4LmbZ1l7SZsQB5oRXl58xKqwuGFEUzWzKvwT4ambLaI2jLICVTBmBIYJDrF5hI0ZJm282YmRi4QleR7SA== + dependencies: + k8w-extend-native "^1.4.6" + tsbuffer-schema "^2.0.8" + tslib "^2.3.1" + +tsbuffer@^2.1.5: + version "2.1.5" + resolved "https://registry.npmmirror.com/tsbuffer/download/tsbuffer-2.1.5.tgz#1bdb44ece499685a836564b3f087b261c0e2112c" + integrity sha512-xlZjiz7LgteL66orgYKn4FTBadPyEwkUrdSYztGDNcLV9Hlp8tIK3/4vhDYkHqa9n/usX8beCrp6atRwfwVDnw== + dependencies: + k8w-extend-native "^1.4.6" + tsbuffer-validator "^2.0.7" + tslib "^2.3.1" + +tslib@*, tslib@^2.3.1: + version "2.3.1" + resolved "https://registry.npmmirror.com/tslib/download/tslib-2.3.1.tgz#e8a335add5ceae51aa261d32a490158ef042ef01" + integrity sha1-6KM1rdXOrlGqJh0ypJAVjvBC7wE= + +tslib@~2.1.0: + version "2.1.0" + resolved "https://registry.npmmirror.com/tslib/download/tslib-2.1.0.tgz#da60860f1c2ecaa5703ab7d39bc05b6bf988b97a" + integrity sha1-2mCGDxwuyqVwOrfTm8Bba/mIuXo= + +tsrpc-base-client@^1.2.4: + version "1.2.4" + resolved "https://registry.npmmirror.com/tsrpc-base-client/download/tsrpc-base-client-1.2.4.tgz#f418c6590c646dd120c7da65f7133690ce0c0693" + integrity sha512-Z/Npf0Yzj2qtjnJAlYZKseRZx25HvZ9wagzmGnioUEXvUHsD7WD7njyks8MDlyVyKezRkLsXIlehcW7uNVmeXQ== + dependencies: + k8w-extend-native "^1.4.6" + tsbuffer "^2.1.5" + tslib "^2.3.1" + tsrpc-proto "^1.3.10" + +tsrpc-cli@^2.3.0: + version "2.3.0" + resolved "https://registry.npmmirror.com/tsrpc-cli/download/tsrpc-cli-2.3.0.tgz#b0218ddaf82f871a30cb2518cfbad6f3a44a86c1" + integrity sha512-NDJ7caHaDEN6l/U8z+9fJFPpsRvloKChYbxc6ZB6j8TKLhkgiDR0T1kjyUe1yFyWICRkpKGg/GXMrkOV+NdcNw== + dependencies: + chalk "^4.1.2" + chokidar "^3.5.2" + fs-extra "^10.0.0" + glob "^7.2.0" + inquirer "^8.2.0" + k8w-extend-native "^1.4.6" + minimist "^1.2.5" + node-json-color-stringify "^1.1.0" + ora "^5.4.1" + os-locale "^5.0.0" + ts-node "^10.4.0" + tsbuffer "^2.1.5" + tsbuffer-proto-generator "^1.6.0" + tsbuffer-schema "^2.1.1" + tsrpc-proto "^1.3.10" + typescript "^4.5.4" + typescript-formatter "^7.2.2" + +tsrpc-proto@^1.3.10: + version "1.3.10" + resolved "https://registry.npmmirror.com/tsrpc-proto/download/tsrpc-proto-1.3.10.tgz#4a748546a0500362235a1469017e36f3f6a259b2" + integrity sha512-YavKKcOMSs80ev44gqHpSx6Z7UFQYmxItDTuaktiKQmstRbW9D/qK1b0lJltAj4ihPU06OOXePcg0CGEch6kYQ== + dependencies: + tsbuffer-schema "^2.1.1" + tslib "*" + +tsrpc@^3.1.4: + version "3.1.4" + resolved "https://registry.npmmirror.com/tsrpc/download/tsrpc-3.1.4.tgz#9dd3d2db94e7be0b7fb22fa566ca7e23edef4135" + integrity sha512-LNzU8E46QJAWINf6rlyvgLgxvd3x976No4nPq9lLkZd2MH1ecP9L1KJDT2eiehDHcmFzFNRGqNjzOyh5teviaw== + dependencies: + "@types/ws" "^7.4.7" + bson "*" + chalk "^4.1.2" + tsbuffer "^2.1.5" + tsrpc-base-client "^1.2.4" + tsrpc-proto "^1.3.10" + uuid "^8.3.2" + ws "^7.5.6" + +type-fest@^0.21.3: + version "0.21.3" + resolved "https://registry.npmmirror.com/type-fest/download/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37" + integrity sha1-0mCiSwGYQ24TP6JqUkptZfo7Ljc= + +typescript-formatter@^7.2.2: + version "7.2.2" + resolved "https://registry.npmmirror.com/typescript-formatter/download/typescript-formatter-7.2.2.tgz#a147181839b7bb09c2377b072f20f6336547c00a" + integrity sha1-oUcYGDm3uwnCN3sHLyD2M2VHwAo= + dependencies: + commandpost "^1.0.0" + editorconfig "^0.15.0" + +typescript@^4.5.4: + version "4.5.4" + resolved "https://registry.npmmirror.com/typescript/download/typescript-4.5.4.tgz#a17d3a0263bf5c8723b9c52f43c5084edf13c2e8" + integrity sha512-VgYs2A2QIRuGphtzFV7aQJduJ2gyfTljngLzjpfW9FoYZF6xuw1W0vW9ghCKLfcWrCFxK81CSGRAvS1pn4fIUg== + +universalify@^2.0.0: + version "2.0.0" + resolved "https://registry.npmmirror.com/universalify/download/universalify-2.0.0.tgz#75a4984efedc4b08975c5aeb73f530d02df25717" + integrity sha1-daSYTv7cSwiXXFrrc/Uw0C3yVxc= + +util-deprecate@^1.0.1: + version "1.0.2" + resolved "https://registry.npmmirror.com/util-deprecate/download/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= + +uuid@^8.3.2: + version "8.3.2" + resolved "https://registry.npmmirror.com/uuid/download/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" + integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== + +wcwidth@^1.0.1: + version "1.0.1" + resolved "https://registry.npmmirror.com/wcwidth/download/wcwidth-1.0.1.tgz#f0b0dcf915bc5ff1528afadb2c0e17b532da2fe8" + integrity sha1-8LDc+RW8X/FSivrbLA4XtTLaL+g= + dependencies: + defaults "^1.0.3" + +which@2.0.2, which@^2.0.1: + version "2.0.2" + resolved "https://registry.npmmirror.com/which/download/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" + integrity sha1-fGqN0KY2oDJ+ELWckobu6T8/UbE= + dependencies: + isexe "^2.0.0" + +workerpool@6.1.5: + version "6.1.5" + resolved "https://registry.npmmirror.com/workerpool/download/workerpool-6.1.5.tgz#0f7cf076b6215fd7e1da903ff6f22ddd1886b581" + integrity sha1-D3zwdrYhX9fh2pA/9vIt3RiGtYE= + +wrap-ansi@^7.0.0: + version "7.0.0" + resolved "https://registry.npmmirror.com/wrap-ansi/download/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha1-Z+FFz/UQpqaYS98RUpEdadLrnkM= + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + +wrappy@1: + version "1.0.2" + resolved "https://registry.npmmirror.com/wrappy/download/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= + +ws@^7.5.6: + version "7.5.6" + resolved "https://registry.npmmirror.com/ws/download/ws-7.5.6.tgz#e59fc509fb15ddfb65487ee9765c5a51dec5fe7b" + integrity sha512-6GLgCqo2cy2A2rjCNFlxQS6ZljG/coZfZXclldI8FB/1G3CCI36Zd8xy2HrFVACi8tfk5XrgLQEk+P0Tnz9UcA== + +y18n@^5.0.5: + version "5.0.8" + resolved "https://registry.npmmirror.com/y18n/download/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" + integrity sha1-f0k00PfKjFb5UxSTndzS3ZHOHVU= + +yallist@^2.1.2: + version "2.1.2" + resolved "https://registry.npmmirror.com/yallist/download/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" + integrity sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI= + +yargs-parser@20.2.4: + version "20.2.4" + resolved "https://registry.npmmirror.com/yargs-parser/download/yargs-parser-20.2.4.tgz?cache=0&sync_timestamp=1637031026741&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fyargs-parser%2Fdownload%2Fyargs-parser-20.2.4.tgz#b42890f14566796f85ae8e3a25290d205f154a54" + integrity sha1-tCiQ8UVmeW+Fro46JSkNIF8VSlQ= + +yargs-parser@^20.2.2: + version "20.2.9" + resolved "https://registry.npmmirror.com/yargs-parser/download/yargs-parser-20.2.9.tgz?cache=0&sync_timestamp=1637031026741&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fyargs-parser%2Fdownload%2Fyargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee" + integrity sha1-LrfcOwKJcY/ClfNidThFxBoMlO4= + +yargs-unparser@2.0.0: + version "2.0.0" + resolved "https://registry.npmmirror.com/yargs-unparser/download/yargs-unparser-2.0.0.tgz#f131f9226911ae5d9ad38c432fe809366c2325eb" + integrity sha1-8TH5ImkRrl2a04xDL+gJNmwjJes= + dependencies: + camelcase "^6.0.0" + decamelize "^4.0.0" + flat "^5.0.2" + is-plain-obj "^2.1.0" + +yargs@16.2.0: + version "16.2.0" + resolved "https://registry.npmmirror.com/yargs/download/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66" + integrity sha1-HIK/D2tqZur85+8w43b0mhJHf2Y= + dependencies: + cliui "^7.0.2" + escalade "^3.1.1" + get-caller-file "^2.0.5" + require-directory "^2.1.1" + string-width "^4.2.0" + y18n "^5.0.5" + yargs-parser "^20.2.2" + +yn@3.1.1: + version "3.1.1" + resolved "https://registry.npmmirror.com/yn/download/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50" + integrity sha1-HodAGgnXZ8HV6rJqbkwYUYLS61A= + +yocto-queue@^0.1.0: + version "0.1.0" + resolved "https://registry.npmmirror.com/yocto-queue/download/yocto-queue-0.1.0.tgz?cache=0&sync_timestamp=1632753523520&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fyocto-queue%2Fdownload%2Fyocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" + integrity sha1-ApTrPe4FAo0x7hpfosVWpqrxChs= diff --git a/examples/serverless-faas/frontend/.gitignore b/examples/serverless-faas/frontend/.gitignore new file mode 100644 index 0000000..ae16b5a --- /dev/null +++ b/examples/serverless-faas/frontend/.gitignore @@ -0,0 +1,3 @@ +.DS_STORE +node_modules +dist \ No newline at end of file diff --git a/examples/serverless-faas/frontend/package.json b/examples/serverless-faas/frontend/package.json new file mode 100644 index 0000000..f0a25fa --- /dev/null +++ b/examples/serverless-faas/frontend/package.json @@ -0,0 +1,24 @@ +{ + "name": "serverless-faas-frontend", + "version": "0.1.0", + "private": true, + "scripts": { + "dev": "webpack serve --mode=development --open", + "build": "webpack --mode=production" + }, + "devDependencies": { + "copy-webpack-plugin": "^9.1.0", + "html-webpack-plugin": "^5.5.0", + "ts-loader": "^9.2.6", + "typescript": "^4.5.4", + "webpack": "^5.65.0", + "webpack-cli": "^4.9.1", + "webpack-dev-server": "^3.11.3" + }, + "dependencies": { + "tsrpc-browser": "^3.1.4" + }, + "browserslist": [ + "defaults" + ] +} \ No newline at end of file diff --git a/examples/serverless-faas/frontend/public/favicon.ico b/examples/serverless-faas/frontend/public/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..361535cb26507b388a0341c772f36f536f7f24be GIT binary patch literal 4286 zcmb`JYfMvT7{`xu*%o7_S(be;%k;yNxy6uW$;{@Q;3W*Npl%Az#Tkv;2t(%_UJ)n- zLBtGi(=aXq1r@mq=)6#Y&^rf!!XQb6do}FC_3j}_?fS->RR=f|||sH&}>Tu@$RAvP&NzQZGb{STp#5Wf`;{IL&mjva@i`2~=k zmF1Kyemg9f?YF@jKGuBviOMq?o=t0f+!hyp`05adjot`p`}RPVA`fzppMdo2Y$s31 zrhRnuCRjS}GcD%e6;B?jmFicEPM@n5vU&ctsBlP4O@u$QGcl(pA>(L{B=1H3=BNk= z3kiUE0Ut^B0rgwy*_xE2Cri1U6F0xC3NBvP!HxT7s8p)F<_Y;3Ik~VtVil}hItLa9 zeOe+FfBE^kmAS>`9GiOnOnoEV?yy2@4}jim1KkrVC>yUqR$iV@KByPgtzOFUmoJ=d z#~Qr%qK8W5rKyV2N-M=&a#jh=ZI8gv&2ns7_2y@sS~{P?zj`C&7nOMJfok>LvOtdi z?ULEBXwJt8LO%A}gku$_+Y8F8q5h^G^p-)6OL3EgeBOt~)CCpimFPjb=lB}r7Zt;@ zh0{4c)!^&-pPMiTukjvA|Ef`+z1#%aNBu6`VZOr|KhLLC_oN@{nr>h{6drStm9K#1 zi@tR7S1g_d^Jh*8<@wjzJDs`anZni3HRzU49;hBoh6hkkQYPu)a7H?W2Kzhtl!GO6 zr>cSiKHw|}S?>0Fi(Qh>=R@3}E#?8l1E9GFpEWZe2KWw<$ z_k7k|*b=iR&9@1id<)+9>5&zL=U3* z_cVJ#j?3O+gIgWF(AfG2)d72xlOQD_UZmY}nGH3a<6Gfv%tQCR7wTZ>8hQ3OHpZ#L z-n(kFz~ws+p#HXzlj^Eg#O1um(T`mABeD4x<{$+HZN0;J7;*N7V!eW~@=W1cRikpt z$GFo|WHKJjt;n8$Ie03pgC4K%l3RKXVXSvL`!QBC#(Li^mprJoMkpveDdHnrjj_A^ zzZpFop&Z~$VlNCo_xK#&eAok53>}h8VeIt1gZuZn^5rrUvfp(HT<`|j?_&<^{3Y4 zxzWm2^xB{E$%E4eZd#u7K|_mYALKJLGn3q? z&O}|4hS+p}n<2$`nRE0o7Ln8JEE|dYT=b|x*{y>t+_m&OXS4ErEg(DmWf;Ex4f=Q! zH3PK~>r!AaTeYW^s*IF)@A?gP0cLw5iiu$v#(xm?jA15rq1qT`97)MAug9X8=NgSG mX%w$m+>n%bh8j(3!|$TT(REOCO;QYAA0T!Vz~E>Ex5Ix+)2V6z literal 0 HcmV?d00001 diff --git a/examples/serverless-faas/frontend/public/index.css b/examples/serverless-faas/frontend/public/index.css new file mode 100644 index 0000000..bdef476 --- /dev/null +++ b/examples/serverless-faas/frontend/public/index.css @@ -0,0 +1,83 @@ +* { + margin: 0; + padding: 0; + box-sizing: border-box; +} + +body { + text-align: center; +} + +body>* { + margin: 20px auto; +} + +.send, +.list { + width: 370px; +} + +.send>* { + display: block; + width: 100%; + margin: 10px auto; + padding: 10px; + border-radius: 5px; + font-size: 16px; + border: none; + outline: none; +} + +.send>textarea { + height: 80px; + background: #f7f7f7; + border: #eeeeee 1px solid; +} + +.send>textarea:focus { + background: #fff; + border-color: #ccc; +} + +.send>button { + background: #215fa4; + color: white; + cursor: pointer; +} + +.send>button:hover { + background: #4b80bb; +} + +.list { + list-style: none; + border-radius: 5px; + padding: 10px; + background: #f2f2f2; +} + +.list>li { + margin-bottom: 10px; + padding: 10px; + background: #fff; + line-height: 1.5em; + border-radius: 5px; +} + +.list>li>.content { + font-size: 14px; + text-align: left; + white-space: pre-wrap; + word-wrap: break-word; +} + +.list>li>.time { + font-size: 12px; + color: #4b80bb; + text-align: right; +} + +.list>li:last-child { + border-bottom: none; + margin-bottom: 0; +} \ No newline at end of file diff --git a/examples/serverless-faas/frontend/public/index.html b/examples/serverless-faas/frontend/public/index.html new file mode 100644 index 0000000..0f9e027 --- /dev/null +++ b/examples/serverless-faas/frontend/public/index.html @@ -0,0 +1,29 @@ + + + + + + + + + TSRPC Browser + + + + +

TSRPC Guestbook

+ +
+ + +
+ +
    + +
+ + + \ No newline at end of file diff --git a/examples/serverless-faas/frontend/src/client.ts b/examples/serverless-faas/frontend/src/client.ts new file mode 100644 index 0000000..e387f38 --- /dev/null +++ b/examples/serverless-faas/frontend/src/client.ts @@ -0,0 +1,10 @@ +import { HttpClient } from "tsrpc-browser"; +import { serviceProto } from "./shared/protocols/serviceProto"; + +// Create Client +export const client = new HttpClient(serviceProto, { + server: "https://service-23pfz6cm-1253954497.gz.apigw.tencentcs.com/release/helloworld-1634897828/", + // Remove this to use binary mode (remove from the server too) + json: true, + logger: console, +}); \ No newline at end of file diff --git a/examples/serverless-faas/frontend/src/env.d.ts b/examples/serverless-faas/frontend/src/env.d.ts new file mode 100644 index 0000000..95a50dc --- /dev/null +++ b/examples/serverless-faas/frontend/src/env.d.ts @@ -0,0 +1,9 @@ +// TSRPC would decode ObjectId as string in frontend. +declare module 'mongodb' { + export type ObjectId = string; + export type ObjectID = string; +} +declare module 'bson' { + export type ObjectId = string; + export type ObjectID = string; +} \ No newline at end of file diff --git a/examples/serverless-faas/frontend/src/index.ts b/examples/serverless-faas/frontend/src/index.ts new file mode 100644 index 0000000..bfb33e1 --- /dev/null +++ b/examples/serverless-faas/frontend/src/index.ts @@ -0,0 +1,50 @@ +import { client } from './client'; + +// This is a demo code file +// Feel free to modify or clear it + +// Reload message list +async function loadList() { + let ret = await client.callApi('GetData', {}); + + // Error + if (!ret.isSucc) { + alert(ret.err.message); + return; + } + + // Success + const list = document.querySelector('.list')!; + list.innerHTML = ''; + ret.res.data.forEach(v => { + let li = document.createElement('li'); + li.innerHTML = `
`; + (li.querySelector('.content') as HTMLDivElement).innerText = v.content; + (li.querySelector('.time') as HTMLDivElement).innerText = v.time.toLocaleTimeString(); + list.appendChild(li); + }) +} + +// Send Message +async function send() { + const textarea = document.querySelector('.send>textarea') as HTMLTextAreaElement; + let ret = await client.callApi('AddData', { + content: textarea.value + }); + + // Error + if (!ret.isSucc) { + alert(ret.err.message); + return; + } + + // Success + textarea.value = ''; + loadList(); +} + +// Bind Events +(document.querySelector('.send>button') as HTMLButtonElement).onclick = send; + +// Load list after page load +loadList(); \ No newline at end of file diff --git a/examples/serverless-faas/frontend/src/shared b/examples/serverless-faas/frontend/src/shared new file mode 120000 index 0000000..6c36ac1 --- /dev/null +++ b/examples/serverless-faas/frontend/src/shared @@ -0,0 +1 @@ +E:/Projects/tsrpc-examples/examples/serverless-faas/backend/src/shared \ No newline at end of file diff --git a/examples/serverless-faas/frontend/tsconfig.json b/examples/serverless-faas/frontend/tsconfig.json new file mode 100644 index 0000000..f7f1d7c --- /dev/null +++ b/examples/serverless-faas/frontend/tsconfig.json @@ -0,0 +1,23 @@ +{ + "compilerOptions": { + "lib": [ + "dom", + "es2015" + ], + "module": "esnext", + "target": "es5", + "allowSyntheticDefaultImports": true, + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "moduleResolution": "node", + "outDir": "dist", + "skipLibCheck": true, + "strict": true, + "jsx": "react-jsx", + "sourceMap": true, + "isolatedModules": true + }, + "include": [ + "src" + ] +} \ No newline at end of file diff --git a/examples/serverless-faas/frontend/webpack.config.js b/examples/serverless-faas/frontend/webpack.config.js new file mode 100644 index 0000000..b0d3703 --- /dev/null +++ b/examples/serverless-faas/frontend/webpack.config.js @@ -0,0 +1,56 @@ +const webpack = require('webpack'); +const path = require('path'); +const HtmlWebpackPlugin = require('html-webpack-plugin'); +const CopyWebpackPlugin = require('copy-webpack-plugin'); + +const isProduction = process.argv.indexOf('--mode=production') > -1; + +module.exports = { + entry: './src/index.ts', + output: { + filename: 'bundle.[contenthash].js', + path: path.resolve(__dirname, 'dist'), + clean: true + }, + resolve: { + extensions: ['.ts', '.tsx', '.js', '.mjs', '.cjs'] + }, + module: { + rules: [ + { + test: /\.tsx?$/, + use: [{ + loader: 'ts-loader', + options: { + // Compile to ES5 in production mode for better compatibility + // Compile to ES2018 in development for better debugging (like async/await) + compilerOptions: !isProduction ? { + "target": "es2018", + } : undefined + } + }], + exclude: /node_modules/ + }, + ] + }, + plugins: [ + // Copy "public" to "dist" + new CopyWebpackPlugin({ + patterns: [{ + from: 'public', + to: '.', + toType: 'dir', + globOptions: { + gitignore: true, + ignore: [path.resolve(__dirname, 'public/index.html').replace(/\\/g, '/')] + }, + noErrorOnMissing: true + }] + }), + // Auto add