diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d3b2f357..5ae597b4 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -765,6 +765,7 @@ importers: '@types/oidc-provider': ^7.8.1 '@types/send': ^0.17.1 '@types/serve-static': ^1.15.0 + '@types/swagger-jsdoc': ^6.0.1 accepts: ^1.3.8 bcryptjs: ^2.4.3 bluebird: ^3.7.2 @@ -806,6 +807,7 @@ importers: serve-static: ^1.15.0 socket.io: ^4.2.0 socket.io-client: ^4.1.3 + swagger-jsdoc: ^6.2.8 tailchat-server-sdk: workspace:* ts-jest: 27.1.4 ts-node: ^10.0.0 @@ -871,6 +873,7 @@ importers: '@types/oidc-provider': 7.11.1 '@types/send': 0.17.1 '@types/serve-static': 1.15.0 + '@types/swagger-jsdoc': 6.0.1 fs-extra: 10.1.0 gulp-sort: 2.0.0 i18next-scanner: 3.3.0 @@ -883,6 +886,7 @@ importers: ora: 5.4.1 prettier: 2.7.1 socket.io-client: 4.5.1 + swagger-jsdoc: 6.2.8 ts-jest: 27.1.4_r5n7iohbfbguzk5ispbdybm75m vinyl-fs: 3.0.3 @@ -1452,6 +1456,38 @@ packages: leven: 3.1.0 dev: true + /@apidevtools/json-schema-ref-parser/9.1.1: + resolution: {integrity: sha512-Qx3hKlS1bNLQKLKJF90gb4t9C5mzvoIwL6SwchZUg25qi64yL9POVbtZYNxhnBX8ToXw3hASbHbhMJ0w3m+HYQ==} + engines: {node: '>= 17'} + dependencies: + '@jsdevtools/ono': 7.1.3 + '@types/json-schema': 7.0.11 + call-me-maybe: 1.0.1 + js-yaml: 4.1.0 + dev: true + + /@apidevtools/openapi-schemas/2.1.0: + resolution: {integrity: sha512-Zc1AlqrJlX3SlpupFGpiLi2EbteyP7fXmUOGup6/DnkRgjP9bgMM/ag+n91rsv0U1Gpz0H3VILA/o3bW7Ua6BQ==} + engines: {node: '>=10'} + dev: true + + /@apidevtools/swagger-methods/3.0.2: + resolution: {integrity: sha512-QAkD5kK2b1WfjDS/UQn/qQkbwF31uqRjPTrsCs5ZG9BQGAkjwvqGFjjPqAuzac/IYzpPtRzjCP1WrTuAIjMrXg==} + dev: true + + /@apidevtools/swagger-parser/10.0.3: + resolution: {integrity: sha512-sNiLY51vZOmSPFZA5TF35KZ2HbgYklQnTSDnkghamzLb3EkNtcQnrBQEj5AOCxHpTtXpqMCRM1CrmV2rG6nw4g==} + peerDependencies: + openapi-types: '>=7' + dependencies: + '@apidevtools/json-schema-ref-parser': 9.1.1 + '@apidevtools/openapi-schemas': 2.1.0 + '@apidevtools/swagger-methods': 3.0.2 + '@jsdevtools/ono': 7.1.3 + call-me-maybe: 1.0.1 + z-schema: 5.0.5 + dev: true + /@arco-design/color/0.4.0: resolution: {integrity: sha512-s7p9MSwJgHeL8DwcATaXvWT3m2SigKpxx4JA1BGPHL4gfvaQsmQfrLBDpjOJFJuJ2jG2dMt3R3P8Pm9E65q18g==} dependencies: @@ -6063,6 +6099,10 @@ packages: '@jridgewell/resolve-uri': 3.1.0 '@jridgewell/sourcemap-codec': 1.4.14 + /@jsdevtools/ono/7.1.3: + resolution: {integrity: sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg==} + dev: true + /@koa/cors/3.4.1: resolution: {integrity: sha512-/sG9NlpGZ/aBpnRamIlGs+wX+C/IJ5DodNK7iPQIVCG4eUQdGeshGhWQ6JCi7tpnD9sCtFXcS04iTimuaJfh4Q==} engines: {node: '>= 8.0.0'} @@ -11684,6 +11724,10 @@ packages: csstype: 3.1.1 dev: true + /@types/swagger-jsdoc/6.0.1: + resolution: {integrity: sha512-+MUpcbyxD528dECUBCEVm6abNuORdbuGjbrUdHDeAQ+rkPuo2a+L4N02WJHF3bonSSE6SJ3dUJwF2V6+cHnf0w==} + dev: true + /@types/tapable/1.0.8: resolution: {integrity: sha512-ipixuVrh2OdNmauvtT51o3d8z12p6LtFW9in7U79der/kwejjdNchQC5UMn5u/KxNoM7VHHOs/l8KS8uHxhODQ==} dev: true @@ -15042,6 +15086,11 @@ packages: resolution: {integrity: sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==} engines: {node: '>= 6'} + /commander/6.2.0: + resolution: {integrity: sha512-zP4jEKbe8SHzKJYQmq8Y9gYjtO/POJLgIdKgV7B9qNmABVFVc+ctqSX6iXh4mCpJfRBOabiZ2YKPg8ciDw6C+Q==} + engines: {node: '>= 6'} + dev: true + /commander/6.2.1: resolution: {integrity: sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==} engines: {node: '>= 6'} @@ -15058,6 +15107,13 @@ packages: resolution: {integrity: sha512-sRPT+umqkz90UA8M1yqYfnHlZA7fF6nSphDtxeywPZ49ysjxDQybzk13CL+mXekDRG92skbcqCLVovuCusNmFw==} engines: {node: ^12.20.0 || >=14} + /commander/9.5.0: + resolution: {integrity: sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==} + engines: {node: ^12.20.0 || >=14} + requiresBuild: true + dev: true + optional: true + /common-path-prefix/3.0.0: resolution: {integrity: sha512-QE33hToZseCH3jS0qN96O/bSh3kaw/h+Tq7ngyY9eWDUnTlTNUyqfqvCXioLe5Na5jFsL78ra/wuBU4iuEgd4w==} dev: true @@ -19811,6 +19867,17 @@ packages: /glob-to-regexp/0.4.1: resolution: {integrity: sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==} + /glob/7.1.6: + resolution: {integrity: sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==} + dependencies: + fs.realpath: 1.0.0 + inflight: 1.0.6 + inherits: 2.0.4 + minimatch: 3.1.2 + once: 1.4.0 + path-is-absolute: 1.0.1 + dev: true + /glob/7.2.3: resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} dependencies: @@ -22111,7 +22178,7 @@ packages: pretty-format: 27.5.1 slash: 3.0.0 strip-json-comments: 3.1.1 - ts-node: 10.9.1_k2dsl7zculo2nmh5s33pladmoa + ts-node: 10.9.1_t4lrjbt3sxauai4t5o275zsepa transitivePeerDependencies: - bufferutil - canvas @@ -23465,7 +23532,6 @@ packages: /lodash.get/4.4.2: resolution: {integrity: sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==} - dev: false /lodash.includes/4.3.0: resolution: {integrity: sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==} @@ -23478,6 +23544,10 @@ packages: resolution: {integrity: sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==} dev: false + /lodash.isequal/4.5.0: + resolution: {integrity: sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==} + dev: true + /lodash.isinteger/4.0.4: resolution: {integrity: sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==} dev: false @@ -23505,6 +23575,10 @@ packages: resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} dev: true + /lodash.mergewith/4.6.2: + resolution: {integrity: sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ==} + dev: true + /lodash.once/4.1.1: resolution: {integrity: sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==} dev: false @@ -33170,6 +33244,30 @@ packages: stable: 0.1.8 dev: false + /swagger-jsdoc/6.2.8: + resolution: {integrity: sha512-VPvil1+JRpmJ55CgAtn8DIcpBs0bL5L3q5bVQvF4tAW/k/9JYSj7dCpaYCAv5rufe0vcCbBRQXGvzpkWjvLklQ==} + engines: {node: '>=12.0.0'} + hasBin: true + dependencies: + commander: 6.2.0 + doctrine: 3.0.0 + glob: 7.1.6 + lodash.mergewith: 4.6.2 + swagger-parser: 10.0.3 + yaml: 2.0.0-1 + transitivePeerDependencies: + - openapi-types + dev: true + + /swagger-parser/10.0.3: + resolution: {integrity: sha512-nF7oMeL4KypldrQhac8RyHerJeGPD1p2xDh900GPvc+Nk7nWP6jX2FcC7WmkinMoAmoO774+AFXcWsW8gMWEIg==} + engines: {node: '>=10'} + dependencies: + '@apidevtools/swagger-parser': 10.0.3 + transitivePeerDependencies: + - openapi-types + dev: true + /swap-case/1.1.2: resolution: {integrity: sha512-BAmWG6/bx8syfc6qXPprof3Mn5vQgf5dwdUNJhsNqU9WdPt5P+ES/wQ5bxfijy8zwZgZZHslC3iAsxsuQMCzJQ==} dependencies: @@ -34201,7 +34299,6 @@ packages: typescript: 4.7.4 v8-compile-cache-lib: 3.0.1 yn: 3.1.1 - dev: false /ts-node/10.9.1_typescript@4.7.4: resolution: {integrity: sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==} @@ -36624,6 +36721,11 @@ packages: resolution: {integrity: sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==} engines: {node: '>= 6'} + /yaml/2.0.0-1: + resolution: {integrity: sha512-W7h5dEhywMKenDJh2iX/LABkbFnBxasD27oyXWDS/feDsxiw0dD5ncXdYXgkvAsXIY2MpW/ZKkr9IU30DBdMNQ==} + engines: {node: '>= 6'} + dev: true + /yaml/2.1.1: resolution: {integrity: sha512-o96x3OPo8GjWeSLF+wOAbrPfhFOGY0W00GNaxCDv+9hkcDJEnev1yh8S7pgHF0ik6zc8sQLuL8hjHjJULZp8bw==} engines: {node: '>= 14'} @@ -36737,6 +36839,18 @@ packages: toposort: 2.0.2 dev: false + /z-schema/5.0.5: + resolution: {integrity: sha512-D7eujBWkLa3p2sIpJA0d1pr7es+a7m0vFAnZLlCEKq/Ij2k0MLi9Br2UPxoxdYystm5K1yeBGzub0FlYUEWj2Q==} + engines: {node: '>=8.0.0'} + hasBin: true + dependencies: + lodash.get: 4.4.2 + lodash.isequal: 4.5.0 + validator: 13.7.0 + optionalDependencies: + commander: 9.5.0 + dev: true + /zustand/4.1.2_react@18.2.0: resolution: {integrity: sha512-gcRaKchcxFPbImrBb/BKgujOhHhik9YhVpIeP87ETT7uokEe2Szu7KkuZ9ghjtD+/KKkcrRNktR2AiLXPIbKIQ==} engines: {node: '>=12.7.0'} diff --git a/server/.gitignore b/server/.gitignore index 385bead9..8cf25450 100644 --- a/server/.gitignore +++ b/server/.gitignore @@ -2,6 +2,9 @@ config/local.* data/ __uploads/ +# Swagger +public/swagger.json + # 插件 public/plugins/ public/registry.json diff --git a/server/package.json b/server/package.json index cf61d3b8..787b3bcc 100644 --- a/server/package.json +++ b/server/package.json @@ -22,7 +22,8 @@ "docker:build": "node ./scripts/buildDocker.js", "dashboard": "ts-node ./scripts/dashboard.ts", "plugin:install": "node ./scripts/installPlugin.js", - "protobuf": "proto-loader-gen-types --longs=String --enums=String --defaults --oneofs --grpcLib=@grpc/grpc-js --outDir=proto/ proto/*.proto" + "protobuf": "proto-loader-gen-types --longs=String --enums=String --defaults --oneofs --grpcLib=@grpc/grpc-js --outDir=proto/ proto/*.proto", + "gen:swagger": "ts-node ./scripts/swagger.ts" }, "pnpm": { "peerDependencyRules": { @@ -95,6 +96,7 @@ "@types/oidc-provider": "^7.8.1", "@types/send": "^0.17.1", "@types/serve-static": "^1.15.0", + "@types/swagger-jsdoc": "^6.0.1", "fs-extra": "^10.0.0", "gulp-sort": "^2.0.0", "i18next-scanner": "^3.0.0", @@ -107,6 +109,7 @@ "ora": "5", "prettier": "^2.3.2", "socket.io-client": "^4.1.3", + "swagger-jsdoc": "^6.2.8", "ts-jest": "27.1.4", "vinyl-fs": "^3.0.3" }, diff --git a/server/scripts/swagger.ts b/server/scripts/swagger.ts new file mode 100644 index 00000000..92d4da98 --- /dev/null +++ b/server/scripts/swagger.ts @@ -0,0 +1,34 @@ +import swaggerJsdoc from 'swagger-jsdoc'; +import path from 'path'; +import fs from 'fs-extra'; + +/** + * Checkout editor online with https://editor.swagger.io/ + */ + +const options: swaggerJsdoc.Options = { + definition: { + openapi: '3.0.0', + info: { + title: 'Tailchat API', + license: { + name: 'Apache 2.0', + url: 'https://www.apache.org/licenses/LICENSE-2.0.html', + }, + version: '1.0.0', + }, + tags: [ + { + name: 'user', + description: '用户服务', + }, + ], + }, + apis: [path.resolve(__dirname, '../services/**/*.ts')], // files containing annotations as above +}; + +const openapiSpecification = swaggerJsdoc(options); + +const targetPath = path.resolve(__dirname, '../public/swagger.json'); +fs.writeFileSync(targetPath, JSON.stringify(openapiSpecification)); +console.log('接口配置已写入');