├── .gitignore ├── LICENSE ├── README.md ├── demo.js ├── package.json ├── src ├── callable.js └── main.js └── yarn.lock /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules/ 3 | dist/ 4 | npm-debug.log 5 | yarn-error.log 6 | 7 | # Editor directories and files 8 | .idea 9 | *.suo 10 | *.ntvs* 11 | *.njsproj 12 | *.sln -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | Copyright (c) 2017 Richard Chien 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of 5 | this software and associated documentation files (the "Software"), to deal in 6 | the Software without restriction, including without limitation the rights to 7 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 8 | the Software, and to permit persons to whom the Software is furnished to do so, 9 | subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 16 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 17 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 18 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 19 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 本项目已停止维护,你仍可以继续使用本项目,但建议尽快迁移至功能更丰富、文档更完善的 [koishijs/koishi](https://github.com/koishijs/koishi)、[momocow/node-cq-websocket](https://github.com/momocow/node-cq-websocket) 等框架 2 | 3 | # CQHTTP Node SDK 4 | 5 | [![License](https://img.shields.io/npm/l/cqhttp.svg)](LICENSE) 6 | [![NPM](https://img.shields.io/npm/v/cqhttp.svg)](https://www.npmjs.com/package/cqhttp) 7 | [![NPM Downloads](https://img.shields.io/npm/dt/cqhttp.svg)](https://www.npmjs.com/package/cqhttp) 8 | [![QQ 版本发布群](https://img.shields.io/badge/%E7%89%88%E6%9C%AC%E5%8F%91%E5%B8%83%E7%BE%A4-218529254-green.svg)](https://jq.qq.com/?_wv=1027&k=5Nl0zhE) 9 | [![Telegram 版本发布频道](https://img.shields.io/badge/%E7%89%88%E6%9C%AC%E5%8F%91%E5%B8%83%E9%A2%91%E9%81%93-join-green.svg)](https://t.me/cqhttp_release) 10 | 11 | 本项目为 酷Q 的 CQHTTP 插件的 Node SDK,封装了 web server 相关的代码,让使用 Node.js 的开发者能方便地开发插件。仅支持插件 4.0.0 或更新版本。 12 | 13 | 关于 CQHTTP 插件,见 [richardchien/coolq-http-api](https://github.com/richardchien/coolq-http-api)。 14 | 15 | ## 用法 16 | 17 | 首先安装 `cqhttp` 模块: 18 | 19 | ```bash 20 | npm install --save cqhttp 21 | ``` 22 | 23 | 然后在程序中使用: 24 | 25 | ```es6 26 | const CQHttp = require('cqhttp'); 27 | 28 | const bot = new CQHttp({ 29 | apiRoot: 'http://127.0.0.1:5700/', 30 | accessToken: '123', 31 | secret: 'abc' 32 | }); 33 | 34 | bot.on('message', context => { 35 | bot('send_msg', { 36 | ...context, 37 | message: '哈喽~' 38 | }); 39 | }); 40 | 41 | bot.listen(8080, '127.0.0.1'); 42 | ``` 43 | 44 | 更详细的示例请参考 [`demo.js`](demo.js)。 45 | 46 | ### 创建实例 47 | 48 | 首先创建 `CQHttp` 类的实例,传入 `apiRoot`,即为 CQHTTP 插件的监听地址,如果你不需要调用 API,也可以不传入。Access token 和签名密钥也在这里传入,如果没有配置 CQHTTP 插件的 `access_token` 或 `secret` 项,则不传。 49 | 50 | ### 事件处理 51 | 52 | `on()` 方法用于添加对应上报类型(`post_type`)的回调函数,目前有三个上报类型 `message`、`notice`、`request`,一个上报类型可以有多个回调,收到上报时按添加顺序来调用。 53 | 54 | 回调函数接受一个参数 `context`,即为上报的数据,打印可查看其内容,具体数据字段含义见 [事件上报](https://cqhttp.cc/docs/#/Post)。 55 | 56 | 函数可以不返回值,也可以返回一个对象,会被自动作为 JSON 响应返回给 CQHTTP 插件,具体见 [上报请求的响应数据格式](https://cqhttp.cc/docs/#/Post?id=%E4%B8%8A%E6%8A%A5%E6%95%B0%E6%8D%AE%E6%A0%BC%E5%BC%8F)。如果同一个上报类型添加了多个回调,只有最后一个有返回值的回调的返回值会被返回给插件。 57 | 58 | ### API 调用 59 | 60 | 在设置了 `api_root` 的情况下,直接在 `CQHttp` 类的实例上就可以调用 API,第一个参数为要调用的接口(或者称为 action),第二个可选参数为一个对象用于传入参数,例如 `bot('send_private_msg', { user_id: 123456, message: 'hello' })`,这里的 `send_private_msg` 即为 [`/send_private_msg` 发送私聊消息](https://cqhttp.cc/docs/#/API?id=send_private_msg-%E5%8F%91%E9%80%81%E7%A7%81%E8%81%8A%E6%B6%88%E6%81%AF) 中的 `/send_private_msg`。其它 API 见 [API 描述](https://cqhttp.cc/docs/#/API)。 61 | 62 | 每个 API 调用最后都会由 `axios` 库来发出请求,如果网络无法连接,它可能会抛出一个异常,见 [Handling Errors](https://github.com/axios/axios#handling-errors)。而一旦请求成功,本 SDK 会判断 HTTP 响应状态码,只有当状态码为 200,且 `status` 字段为 `ok` 或 `async` 时,会返回 `data` 字段的内容,否则也抛出一个异常(是一个简单对象),在这个异常中你可以通过 `status` 和 `retcode` 属性来获取 HTTP 状态码和插件的 `retcode`(如果状态码不为 200,则 `retcode` 为 undefined),具体响应状态码和 `retcode` 的含义,见 [响应说明](https://cqhttp.cc/docs/#/API?id=%E5%93%8D%E5%BA%94%E8%AF%B4%E6%98%8E)。 63 | 64 | ### 运行实例 65 | 66 | 使用装饰器定义好处理函数之后,调用 `bot.listen()` 即可运行。这个方法第一个参数为监听端口,第二个参数为监听的 host,来指定服务端需要运行在哪个地址,然后在 CQHTTP 插件的配置文件中,在 `post_url` 项中配置此地址(`http://host:port/`)。 67 | 68 | ## 遇到问题 69 | 70 | 本 SDK 的代码非常简单,如果发现有问题可以参考下源码,可以自行做一些修复,也欢迎提交 pull request 或 issue。 71 | -------------------------------------------------------------------------------- /demo.js: -------------------------------------------------------------------------------- 1 | const CQHttp = require('./'); 2 | 3 | const bot = new CQHttp({ 4 | apiRoot: 'http://127.0.0.1:5700/', 5 | accessToken: '123', 6 | secret: 'abc' 7 | }); 8 | 9 | const SUPERUSER = 123456; 10 | 11 | const msg_cb = bot.on('message', context => { 12 | bot('send_msg', { 13 | ...context, 14 | message: '哈喽~\n你发了:' + context.message 15 | }); 16 | 17 | // 下面演示运行中删除事件回调 18 | if (context.user_id === SUPERUSER && context.message === 'delete callback') { 19 | bot.delete('message', msg_cb); 20 | } 21 | }); 22 | 23 | bot.on('notice', context => { 24 | if (context.notice_type === 'group_increase') { 25 | // 处理群成员添加事件 26 | bot('get_group_member_info', { 27 | group_id: context.group_id, 28 | user_id: context.user_id 29 | }).then(data => { 30 | const name = data.nickname || '新人'; 31 | bot('send_group_msg_async', { 32 | group_id: context.group_id, 33 | message: `欢迎${name}~` 34 | }).catch(err => { }); 35 | }).catch(err => { 36 | console.log(err); 37 | }); 38 | } 39 | // 忽略其它事件 40 | }); 41 | 42 | bot.on('request', context => { 43 | if (context.request_type === 'group') { 44 | // 处理加群请求 45 | if (context.message !== 'some-secret') { 46 | return { approve: false, reason: '口令不对' }; 47 | } 48 | return { approve: true }; 49 | } 50 | // 忽略其它类型的请求 51 | }); 52 | 53 | console.log('Start listening at http://127.0.0.1:8080/') 54 | bot.listen(8080, '127.0.0.1'); 55 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "cqhttp", 3 | "version": "1.2.0", 4 | "description": "A Node SDK for CQHTTP.", 5 | "main": "src/main.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "Richard Chien ", 10 | "license": "MIT", 11 | "dependencies": { 12 | "axios": "^0.18.1", 13 | "koa": "^2.3.0", 14 | "koa-bodyparser": "^4.2.0", 15 | "koa-route": "^3.2.0" 16 | }, 17 | "repository": "cqmoe/cqhttp-node-sdk" 18 | } -------------------------------------------------------------------------------- /src/callable.js: -------------------------------------------------------------------------------- 1 | function CallableInstance (property) { 2 | const func = this.constructor.prototype[property]; 3 | const apply = function () { return func.apply(apply, arguments); } 4 | Object.setPrototypeOf(apply, this.constructor.prototype); 5 | Object.getOwnPropertyNames(func).forEach(function (p) { 6 | Object.defineProperty(apply, p, Object.getOwnPropertyDescriptor(func, p)); 7 | }); 8 | return apply; 9 | } 10 | CallableInstance.prototype = Object.create(Function.prototype); 11 | 12 | module.exports = CallableInstance; 13 | -------------------------------------------------------------------------------- /src/main.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const Callable = require('./callable'); 4 | const Koa = require('koa'); 5 | const bodyParser = require('koa-bodyparser') 6 | const route = require('koa-route'); 7 | const crypto = require('crypto'); 8 | const axios = require('axios'); 9 | 10 | module.exports = class CQHttp extends Callable { 11 | constructor({ apiRoot, accessToken, secret }) { 12 | super('__call__'); 13 | if (apiRoot) { 14 | const headers = { 'Content-Type': 'application/json' } 15 | if (accessToken) headers['Authorization'] = `Token ${accessToken}`; 16 | this.apiClient = axios.create({ baseURL: apiRoot, headers: headers }); 17 | } 18 | 19 | this.secret = secret; 20 | this.app = new Koa(); 21 | this.app.use(bodyParser()); 22 | this.app.use(route.post('/', this.handle.bind(this))); 23 | this.callbacks = { message: [], event: [], notice: [], request: [] }; 24 | } 25 | 26 | handle(ctx) { 27 | if (this.secret) { 28 | // check signature 29 | ctx.assert(ctx.request.headers['x-signature'] !== undefined, 401); 30 | const hmac = crypto.createHmac('sha1', this.secret); 31 | hmac.update(ctx.request.rawBody); 32 | const sig = hmac.digest('hex'); 33 | ctx.assert(ctx.request.headers['x-signature'] === `sha1=${sig}`, 403); 34 | } 35 | 36 | ctx.assert(ctx.request.body.post_type !== undefined, 400); 37 | 38 | let result = {}; 39 | const callbacks = this.callbacks[ctx.request.body.post_type]; 40 | if (callbacks) { 41 | for (const cb of callbacks) { 42 | // only the result of the last callback matters 43 | const res = cb(ctx.request.body); 44 | if (res) { 45 | result = res; 46 | } 47 | } 48 | } 49 | ctx.response.body = JSON.stringify(result); 50 | } 51 | 52 | on(post_type, callback) { 53 | this.callbacks[post_type].push(callback); 54 | return callback; 55 | } 56 | 57 | delete(post_type, callback) { 58 | let idx = this.callbacks[post_type].indexOf(callback); 59 | while (idx > -1) { 60 | this.callbacks[post_type].splice(idx, 1); 61 | idx = this.callbacks[post_type].indexOf(callback); 62 | } 63 | } 64 | 65 | __call__(action, params = {}) { 66 | if (this.apiClient) { 67 | return this.apiClient.post(`/${action}`, params).then(response => { 68 | let err = { 69 | status: response.status 70 | }; 71 | if (response.status === 200) { 72 | const data = response.data; 73 | if (data.status === 'failed') { 74 | err.retcode = data.retcode; 75 | return Promise.reject(err); 76 | } 77 | return Promise.resolve(data.data); 78 | } else { 79 | return Promise.reject(err); 80 | } 81 | }); 82 | } 83 | } 84 | 85 | listen(...args) { 86 | this.app.listen(...args); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | accepts@^1.3.5: 6 | version "1.3.5" 7 | resolved "http://registry.npm.taobao.org/accepts/download/accepts-1.3.5.tgz#eb777df6011723a3b14e8a72c0805c8e86746bd2" 8 | dependencies: 9 | mime-types "~2.1.18" 10 | negotiator "0.6.1" 11 | 12 | any-promise@^1.1.0: 13 | version "1.3.0" 14 | resolved "http://registry.npm.taobao.org/any-promise/download/any-promise-1.3.0.tgz#abc6afeedcea52e809cdc0376aed3ce39635d17f" 15 | 16 | axios@^0.18.1: 17 | version "0.18.1" 18 | resolved "https://registry.yarnpkg.com/axios/-/axios-0.18.1.tgz#ff3f0de2e7b5d180e757ad98000f1081b87bcea3" 19 | dependencies: 20 | follow-redirects "1.5.10" 21 | is-buffer "^2.0.2" 22 | 23 | bytes@3.0.0: 24 | version "3.0.0" 25 | resolved "http://registry.npm.taobao.org/bytes/download/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048" 26 | 27 | cache-content-type@^1.0.0: 28 | version "1.0.1" 29 | resolved "http://registry.npm.taobao.org/cache-content-type/download/cache-content-type-1.0.1.tgz#035cde2b08ee2129f4a8315ea8f00a00dba1453c" 30 | dependencies: 31 | mime-types "^2.1.18" 32 | ylru "^1.2.0" 33 | 34 | co-body@^6.0.0: 35 | version "6.0.0" 36 | resolved "http://registry.npm.taobao.org/co-body/download/co-body-6.0.0.tgz#965b9337d7f5655480787471f4237664820827e3" 37 | dependencies: 38 | inflation "^2.0.0" 39 | qs "^6.5.2" 40 | raw-body "^2.3.3" 41 | type-is "^1.6.16" 42 | 43 | co@^4.6.0: 44 | version "4.6.0" 45 | resolved "http://registry.npm.taobao.org/co/download/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" 46 | 47 | content-disposition@~0.5.2: 48 | version "0.5.2" 49 | resolved "http://registry.npm.taobao.org/content-disposition/download/content-disposition-0.5.2.tgz#0cf68bb9ddf5f2be7961c3a85178cb85dba78cb4" 50 | 51 | content-type@^1.0.4: 52 | version "1.0.4" 53 | resolved "http://registry.npm.taobao.org/content-type/download/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" 54 | 55 | cookies@~0.7.1: 56 | version "0.7.2" 57 | resolved "http://registry.npm.taobao.org/cookies/download/cookies-0.7.2.tgz#52736976126658af7713d7f858f7d21f99dab486" 58 | dependencies: 59 | depd "~1.1.2" 60 | keygrip "~1.0.2" 61 | 62 | copy-to@^2.0.1: 63 | version "2.0.1" 64 | resolved "http://registry.npm.taobao.org/copy-to/download/copy-to-2.0.1.tgz#2680fbb8068a48d08656b6098092bdafc906f4a5" 65 | 66 | debug@*: 67 | version "4.0.1" 68 | resolved "http://registry.npm.taobao.org/debug/download/debug-4.0.1.tgz#f9bb36d439b8d1f0dd52d8fb6b46e4ebb8c1cd5b" 69 | dependencies: 70 | ms "^2.1.1" 71 | 72 | debug@=3.1.0, debug@~3.1.0: 73 | version "3.1.0" 74 | resolved "http://registry.npm.taobao.org/debug/download/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" 75 | dependencies: 76 | ms "2.0.0" 77 | 78 | deep-equal@~1.0.1: 79 | version "1.0.1" 80 | resolved "http://registry.npm.taobao.org/deep-equal/download/deep-equal-1.0.1.tgz#f5d260292b660e084eff4cdbc9f08ad3247448b5" 81 | 82 | delegates@^1.0.0: 83 | version "1.0.0" 84 | resolved "http://registry.npm.taobao.org/delegates/download/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" 85 | 86 | depd@^1.1.2, depd@~1.1.2: 87 | version "1.1.2" 88 | resolved "http://registry.npm.taobao.org/depd/download/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" 89 | 90 | destroy@^1.0.4: 91 | version "1.0.4" 92 | resolved "http://registry.npm.taobao.org/destroy/download/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" 93 | 94 | ee-first@1.1.1: 95 | version "1.1.1" 96 | resolved "http://registry.npm.taobao.org/ee-first/download/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" 97 | 98 | error-inject@^1.0.0: 99 | version "1.0.0" 100 | resolved "http://registry.npm.taobao.org/error-inject/download/error-inject-1.0.0.tgz#e2b3d91b54aed672f309d950d154850fa11d4f37" 101 | 102 | escape-html@^1.0.3: 103 | version "1.0.3" 104 | resolved "http://registry.npm.taobao.org/escape-html/download/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" 105 | 106 | follow-redirects@1.5.10: 107 | version "1.5.10" 108 | resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.5.10.tgz#7b7a9f9aea2fdff36786a94ff643ed07f4ff5e2a" 109 | dependencies: 110 | debug "=3.1.0" 111 | 112 | fresh@~0.5.2: 113 | version "0.5.2" 114 | resolved "http://registry.npm.taobao.org/fresh/download/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" 115 | 116 | http-assert@^1.3.0: 117 | version "1.4.0" 118 | resolved "http://registry.npm.taobao.org/http-assert/download/http-assert-1.4.0.tgz#0e550b4fca6adf121bbeed83248c17e62f593a9a" 119 | dependencies: 120 | deep-equal "~1.0.1" 121 | http-errors "~1.7.1" 122 | 123 | http-errors@1.6.3: 124 | version "1.6.3" 125 | resolved "http://registry.npm.taobao.org/http-errors/download/http-errors-1.6.3.tgz#8b55680bb4be283a0b5bf4ea2e38580be1d9320d" 126 | dependencies: 127 | depd "~1.1.2" 128 | inherits "2.0.3" 129 | setprototypeof "1.1.0" 130 | statuses ">= 1.4.0 < 2" 131 | 132 | http-errors@^1.6.3, http-errors@~1.7.1: 133 | version "1.7.1" 134 | resolved "http://registry.npm.taobao.org/http-errors/download/http-errors-1.7.1.tgz#6a4ffe5d35188e1c39f872534690585852e1f027" 135 | dependencies: 136 | depd "~1.1.2" 137 | inherits "2.0.3" 138 | setprototypeof "1.1.0" 139 | statuses ">= 1.5.0 < 2" 140 | toidentifier "1.0.0" 141 | 142 | iconv-lite@0.4.23: 143 | version "0.4.23" 144 | resolved "http://registry.npm.taobao.org/iconv-lite/download/iconv-lite-0.4.23.tgz#297871f63be507adcfbfca715d0cd0eed84e9a63" 145 | dependencies: 146 | safer-buffer ">= 2.1.2 < 3" 147 | 148 | inflation@^2.0.0: 149 | version "2.0.0" 150 | resolved "http://registry.npm.taobao.org/inflation/download/inflation-2.0.0.tgz#8b417e47c28f925a45133d914ca1fd389107f30f" 151 | 152 | inherits@2.0.3: 153 | version "2.0.3" 154 | resolved "http://registry.npm.taobao.org/inherits/download/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" 155 | 156 | is-buffer@^2.0.2: 157 | version "2.0.4" 158 | resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-2.0.4.tgz#3e572f23c8411a5cfd9557c849e3665e0b290623" 159 | 160 | is-generator-function@^1.0.7: 161 | version "1.0.7" 162 | resolved "http://registry.npm.taobao.org/is-generator-function/download/is-generator-function-1.0.7.tgz#d2132e529bb0000a7f80794d4bdf5cd5e5813522" 163 | 164 | isarray@0.0.1: 165 | version "0.0.1" 166 | resolved "http://registry.npm.taobao.org/isarray/download/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" 167 | 168 | keygrip@~1.0.2: 169 | version "1.0.3" 170 | resolved "http://registry.npm.taobao.org/keygrip/download/keygrip-1.0.3.tgz#399d709f0aed2bab0a059e0cdd3a5023a053e1dc" 171 | 172 | koa-bodyparser@^4.2.0: 173 | version "4.2.1" 174 | resolved "http://registry.npm.taobao.org/koa-bodyparser/download/koa-bodyparser-4.2.1.tgz#4d7dacb5e6db1106649b595d9e5ccb158b6f3b29" 175 | dependencies: 176 | co-body "^6.0.0" 177 | copy-to "^2.0.1" 178 | 179 | koa-compose@^3.0.0: 180 | version "3.2.1" 181 | resolved "http://registry.npm.taobao.org/koa-compose/download/koa-compose-3.2.1.tgz#a85ccb40b7d986d8e5a345b3a1ace8eabcf54de7" 182 | dependencies: 183 | any-promise "^1.1.0" 184 | 185 | koa-compose@^4.1.0: 186 | version "4.1.0" 187 | resolved "http://registry.npm.taobao.org/koa-compose/download/koa-compose-4.1.0.tgz#507306b9371901db41121c812e923d0d67d3e877" 188 | 189 | koa-convert@^1.2.0: 190 | version "1.2.0" 191 | resolved "http://registry.npm.taobao.org/koa-convert/download/koa-convert-1.2.0.tgz#da40875df49de0539098d1700b50820cebcd21d0" 192 | dependencies: 193 | co "^4.6.0" 194 | koa-compose "^3.0.0" 195 | 196 | koa-is-json@^1.0.0: 197 | version "1.0.0" 198 | resolved "http://registry.npm.taobao.org/koa-is-json/download/koa-is-json-1.0.0.tgz#273c07edcdcb8df6a2c1ab7d59ee76491451ec14" 199 | 200 | koa-route@^3.2.0: 201 | version "3.2.0" 202 | resolved "http://registry.npm.taobao.org/koa-route/download/koa-route-3.2.0.tgz#76298b99a6bcfa9e38cab6fe5c79a8733e758bce" 203 | dependencies: 204 | debug "*" 205 | methods "~1.1.0" 206 | path-to-regexp "^1.2.0" 207 | 208 | koa@^2.3.0: 209 | version "2.5.3" 210 | resolved "http://registry.npm.taobao.org/koa/download/koa-2.5.3.tgz#0b0c37eee3aac807a0a6ad36bc0b8660f12d83f1" 211 | dependencies: 212 | accepts "^1.3.5" 213 | cache-content-type "^1.0.0" 214 | content-disposition "~0.5.2" 215 | content-type "^1.0.4" 216 | cookies "~0.7.1" 217 | debug "~3.1.0" 218 | delegates "^1.0.0" 219 | depd "^1.1.2" 220 | destroy "^1.0.4" 221 | error-inject "^1.0.0" 222 | escape-html "^1.0.3" 223 | fresh "~0.5.2" 224 | http-assert "^1.3.0" 225 | http-errors "^1.6.3" 226 | is-generator-function "^1.0.7" 227 | koa-compose "^4.1.0" 228 | koa-convert "^1.2.0" 229 | koa-is-json "^1.0.0" 230 | on-finished "^2.3.0" 231 | only "~0.0.2" 232 | parseurl "^1.3.2" 233 | statuses "^1.5.0" 234 | type-is "^1.6.16" 235 | vary "^1.1.2" 236 | 237 | media-typer@0.3.0: 238 | version "0.3.0" 239 | resolved "http://registry.npm.taobao.org/media-typer/download/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" 240 | 241 | methods@~1.1.0: 242 | version "1.1.2" 243 | resolved "http://registry.npm.taobao.org/methods/download/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" 244 | 245 | mime-db@~1.36.0: 246 | version "1.36.0" 247 | resolved "http://registry.npm.taobao.org/mime-db/download/mime-db-1.36.0.tgz#5020478db3c7fe93aad7bbcc4dcf869c43363397" 248 | 249 | mime-types@^2.1.18, mime-types@~2.1.18: 250 | version "2.1.20" 251 | resolved "http://registry.npm.taobao.org/mime-types/download/mime-types-2.1.20.tgz#930cb719d571e903738520f8470911548ca2cc19" 252 | dependencies: 253 | mime-db "~1.36.0" 254 | 255 | ms@2.0.0: 256 | version "2.0.0" 257 | resolved "http://registry.npm.taobao.org/ms/download/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" 258 | 259 | ms@^2.1.1: 260 | version "2.1.1" 261 | resolved "http://registry.npm.taobao.org/ms/download/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a" 262 | 263 | negotiator@0.6.1: 264 | version "0.6.1" 265 | resolved "http://registry.npm.taobao.org/negotiator/download/negotiator-0.6.1.tgz#2b327184e8992101177b28563fb5e7102acd0ca9" 266 | 267 | on-finished@^2.3.0: 268 | version "2.3.0" 269 | resolved "http://registry.npm.taobao.org/on-finished/download/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" 270 | dependencies: 271 | ee-first "1.1.1" 272 | 273 | only@~0.0.2: 274 | version "0.0.2" 275 | resolved "http://registry.npm.taobao.org/only/download/only-0.0.2.tgz#2afde84d03e50b9a8edc444e30610a70295edfb4" 276 | 277 | parseurl@^1.3.2: 278 | version "1.3.2" 279 | resolved "http://registry.npm.taobao.org/parseurl/download/parseurl-1.3.2.tgz#fc289d4ed8993119460c156253262cdc8de65bf3" 280 | 281 | path-to-regexp@^1.2.0: 282 | version "1.7.0" 283 | resolved "http://registry.npm.taobao.org/path-to-regexp/download/path-to-regexp-1.7.0.tgz#59fde0f435badacba103a84e9d3bc64e96b9937d" 284 | dependencies: 285 | isarray "0.0.1" 286 | 287 | qs@^6.5.2: 288 | version "6.5.2" 289 | resolved "http://registry.npm.taobao.org/qs/download/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36" 290 | 291 | raw-body@^2.3.3: 292 | version "2.3.3" 293 | resolved "http://registry.npm.taobao.org/raw-body/download/raw-body-2.3.3.tgz#1b324ece6b5706e153855bc1148c65bb7f6ea0c3" 294 | dependencies: 295 | bytes "3.0.0" 296 | http-errors "1.6.3" 297 | iconv-lite "0.4.23" 298 | unpipe "1.0.0" 299 | 300 | "safer-buffer@>= 2.1.2 < 3": 301 | version "2.1.2" 302 | resolved "http://registry.npm.taobao.org/safer-buffer/download/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" 303 | 304 | setprototypeof@1.1.0: 305 | version "1.1.0" 306 | resolved "http://registry.npm.taobao.org/setprototypeof/download/setprototypeof-1.1.0.tgz#d0bd85536887b6fe7c0d818cb962d9d91c54e656" 307 | 308 | "statuses@>= 1.4.0 < 2", "statuses@>= 1.5.0 < 2", statuses@^1.5.0: 309 | version "1.5.0" 310 | resolved "http://registry.npm.taobao.org/statuses/download/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" 311 | 312 | toidentifier@1.0.0: 313 | version "1.0.0" 314 | resolved "http://registry.npm.taobao.org/toidentifier/download/toidentifier-1.0.0.tgz#7e1be3470f1e77948bc43d94a3c8f4d7752ba553" 315 | 316 | type-is@^1.6.16: 317 | version "1.6.16" 318 | resolved "http://registry.npm.taobao.org/type-is/download/type-is-1.6.16.tgz#f89ce341541c672b25ee7ae3c73dee3b2be50194" 319 | dependencies: 320 | media-typer "0.3.0" 321 | mime-types "~2.1.18" 322 | 323 | unpipe@1.0.0: 324 | version "1.0.0" 325 | resolved "http://registry.npm.taobao.org/unpipe/download/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" 326 | 327 | vary@^1.1.2: 328 | version "1.1.2" 329 | resolved "http://registry.npm.taobao.org/vary/download/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" 330 | 331 | ylru@^1.2.0: 332 | version "1.2.1" 333 | resolved "http://registry.npm.taobao.org/ylru/download/ylru-1.2.1.tgz#f576b63341547989c1de7ba288760923b27fe84f" 334 | --------------------------------------------------------------------------------