@zhin.js/http 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +9 -0
- package/LICENSE +21 -0
- package/README.md +261 -0
- package/lib/index.d.ts +12 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +200 -0
- package/lib/index.js.map +1 -0
- package/lib/router.d.ts +17 -0
- package/lib/router.d.ts.map +1 -0
- package/lib/router.js +46 -0
- package/lib/router.js.map +1 -0
- package/package.json +36 -0
- package/src/index.ts +227 -0
- package/src/router.ts +55 -0
- package/tsconfig.json +23 -0
package/CHANGELOG.md
ADDED
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 凉菜
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
# @zhin.js/http
|
|
2
|
+
|
|
3
|
+
基于 Koa 的 HTTP 服务器插件,为 Zhin 机器人框架提供 HTTP API 和 WebSocket 支持。
|
|
4
|
+
|
|
5
|
+
## 功能特性
|
|
6
|
+
|
|
7
|
+
- 🌐 基于 Koa.js 的 HTTP 服务器
|
|
8
|
+
- 🔐 Basic Auth 身份验证
|
|
9
|
+
- 🛠️ RESTful API 支持
|
|
10
|
+
- 📡 WebSocket 实时通信
|
|
11
|
+
- 🔄 请求体解析 (JSON)
|
|
12
|
+
- 🌍 可配置的服务器设置
|
|
13
|
+
- 📊 路由管理和中间件支持
|
|
14
|
+
- 📋 内置 API 端点 (系统状态、插件管理、适配器信息)
|
|
15
|
+
- 📝 上下文描述信息支持
|
|
16
|
+
|
|
17
|
+
## 技术架构
|
|
18
|
+
|
|
19
|
+
- **HTTP框架**: Koa.js
|
|
20
|
+
- **路由**: 自定义Router类扩展@koa/router
|
|
21
|
+
- **WebSocket**: ws 库
|
|
22
|
+
- **身份验证**: koa-basic-auth
|
|
23
|
+
- **请求解析**: koa-bodyparser
|
|
24
|
+
|
|
25
|
+
## 安装
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
npm install @zhin.js/http
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## 使用
|
|
32
|
+
|
|
33
|
+
### 基本使用
|
|
34
|
+
|
|
35
|
+
```javascript
|
|
36
|
+
// 插件会自动启动HTTP服务器
|
|
37
|
+
import '@zhin.js/http'
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### 环境变量配置
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
# 服务器端口 (默认: 8086)
|
|
44
|
+
port=8086
|
|
45
|
+
|
|
46
|
+
# 路由前缀 (可选)
|
|
47
|
+
routerPrefix=/api
|
|
48
|
+
|
|
49
|
+
# 基础认证用户名 (默认: admin)
|
|
50
|
+
username=admin
|
|
51
|
+
|
|
52
|
+
# 基础认证密码 (默认: 123456)
|
|
53
|
+
password=123456
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## 核心组件
|
|
57
|
+
|
|
58
|
+
### Router 类
|
|
59
|
+
|
|
60
|
+
扩展了 `@koa/router` 的功能:
|
|
61
|
+
|
|
62
|
+
```typescript
|
|
63
|
+
class Router extends KoaRouter {
|
|
64
|
+
// WebSocket服务器管理
|
|
65
|
+
ws(path: string, options?: ServerOptions): WebSocketServer
|
|
66
|
+
|
|
67
|
+
// 销毁路由
|
|
68
|
+
destroy(layer: Layer): void
|
|
69
|
+
|
|
70
|
+
// 销毁WebSocket服务器
|
|
71
|
+
destroyWs(wsServer: WebSocketServer): void
|
|
72
|
+
|
|
73
|
+
// 白名单管理(用于历史API排除)
|
|
74
|
+
whiteList: Path[]
|
|
75
|
+
}
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### 全局上下文
|
|
79
|
+
|
|
80
|
+
```typescript
|
|
81
|
+
declare module '@zhin.js/types' {
|
|
82
|
+
interface GlobalContext {
|
|
83
|
+
koa: Koa, // Koa应用实例
|
|
84
|
+
router: Router, // 路由器实例
|
|
85
|
+
server: Server // HTTP服务器实例
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## API 使用
|
|
91
|
+
|
|
92
|
+
### 内置 API 端点
|
|
93
|
+
|
|
94
|
+
插件提供以下内置 API:
|
|
95
|
+
|
|
96
|
+
#### 适配器管理 API
|
|
97
|
+
- `GET /api/adapters` - 获取所有上下文列表
|
|
98
|
+
|
|
99
|
+
**响应格式:**
|
|
100
|
+
```json
|
|
101
|
+
{
|
|
102
|
+
"success": true,
|
|
103
|
+
"data": [
|
|
104
|
+
{
|
|
105
|
+
"name": "icqq-adapter",
|
|
106
|
+
"desc": "ICQQ适配器,用于连接QQ平台"
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
"name": "web-console",
|
|
110
|
+
"desc": "Web控制台服务,提供管理界面"
|
|
111
|
+
}
|
|
112
|
+
]
|
|
113
|
+
}
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
#### 其他 API
|
|
117
|
+
- `GET /api/system/status` - 系统状态信息
|
|
118
|
+
- `GET /api/plugins` - 插件列表
|
|
119
|
+
- `GET /api/config` - 配置信息
|
|
120
|
+
- `POST /api/message/send` - 发送消息
|
|
121
|
+
- `POST /api/plugins/:name/reload` - 重载插件
|
|
122
|
+
- `GET /api/health` - 健康检查
|
|
123
|
+
|
|
124
|
+
### 自定义 HTTP 路由
|
|
125
|
+
|
|
126
|
+
```javascript
|
|
127
|
+
import { useContext } from 'zhin.js'
|
|
128
|
+
|
|
129
|
+
useContext('router', async (router) => {
|
|
130
|
+
// GET 请求
|
|
131
|
+
router.get('/api/status', async (ctx) => {
|
|
132
|
+
ctx.body = { status: 'ok' }
|
|
133
|
+
})
|
|
134
|
+
|
|
135
|
+
// POST 请求
|
|
136
|
+
router.post('/api/message', async (ctx) => {
|
|
137
|
+
const { message } = ctx.request.body
|
|
138
|
+
// 处理消息...
|
|
139
|
+
ctx.body = { success: true }
|
|
140
|
+
})
|
|
141
|
+
})
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### WebSocket 连接
|
|
145
|
+
|
|
146
|
+
```javascript
|
|
147
|
+
import { useContext } from 'zhin.js'
|
|
148
|
+
|
|
149
|
+
useContext('router', async (router) => {
|
|
150
|
+
const ws = router.ws('/api/realtime')
|
|
151
|
+
|
|
152
|
+
ws.on('connection', (socket) => {
|
|
153
|
+
socket.send('连接成功')
|
|
154
|
+
|
|
155
|
+
socket.on('message', (data) => {
|
|
156
|
+
console.log('收到消息:', data)
|
|
157
|
+
})
|
|
158
|
+
})
|
|
159
|
+
})
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
### Koa 中间件
|
|
163
|
+
|
|
164
|
+
```javascript
|
|
165
|
+
import { useContext } from 'zhin.js'
|
|
166
|
+
|
|
167
|
+
useContext('koa', async (koa) => {
|
|
168
|
+
koa.use(async (ctx, next) => {
|
|
169
|
+
console.log('请求:', ctx.method, ctx.url)
|
|
170
|
+
await next()
|
|
171
|
+
})
|
|
172
|
+
})
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
## 服务器配置
|
|
176
|
+
|
|
177
|
+
### 启动配置
|
|
178
|
+
|
|
179
|
+
```javascript
|
|
180
|
+
{
|
|
181
|
+
host: '0.0.0.0', // 监听地址
|
|
182
|
+
port: 8086 // 监听端口
|
|
183
|
+
}
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
### 身份验证
|
|
187
|
+
|
|
188
|
+
默认启用 Basic Auth:
|
|
189
|
+
- 用户名: `admin` (可通过环境变量修改)
|
|
190
|
+
- 密码: `123456` (可通过环境变量修改)
|
|
191
|
+
|
|
192
|
+
## WebSocket 功能
|
|
193
|
+
|
|
194
|
+
### 路径管理
|
|
195
|
+
|
|
196
|
+
- 支持多个WebSocket端点
|
|
197
|
+
- 自动路径匹配
|
|
198
|
+
- 连接升级处理
|
|
199
|
+
|
|
200
|
+
### 连接处理
|
|
201
|
+
|
|
202
|
+
```javascript
|
|
203
|
+
// 创建WebSocket服务器
|
|
204
|
+
const wsServer = router.ws('/chat')
|
|
205
|
+
|
|
206
|
+
// 处理连接
|
|
207
|
+
wsServer.on('connection', (ws, request) => {
|
|
208
|
+
ws.send('欢迎连接')
|
|
209
|
+
})
|
|
210
|
+
|
|
211
|
+
// 销毁服务器
|
|
212
|
+
router.destroyWs(wsServer)
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
## 开发
|
|
216
|
+
|
|
217
|
+
### 项目结构
|
|
218
|
+
|
|
219
|
+
```
|
|
220
|
+
src/
|
|
221
|
+
├── index.ts # 主入口,服务器初始化
|
|
222
|
+
└── router.ts # Router类实现
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
### 构建
|
|
226
|
+
|
|
227
|
+
```bash
|
|
228
|
+
npm run build # 构建插件
|
|
229
|
+
npm run clean # 清理构建文件
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
## 依赖项
|
|
233
|
+
|
|
234
|
+
### 核心依赖
|
|
235
|
+
- `@koa/router` - Koa路由器
|
|
236
|
+
- `koa` - Koa.js框架
|
|
237
|
+
- `ws` - WebSocket库
|
|
238
|
+
- `koa-basic-auth` - 基础认证中间件
|
|
239
|
+
- `koa-bodyparser` - 请求体解析中间件
|
|
240
|
+
|
|
241
|
+
### 对等依赖
|
|
242
|
+
- `zhin.js` - Zhin核心框架
|
|
243
|
+
|
|
244
|
+
## 安全考虑
|
|
245
|
+
|
|
246
|
+
- 🔐 默认启用身份验证
|
|
247
|
+
- 🛡️ 请求体大小限制
|
|
248
|
+
- 🔒 WebSocket连接验证
|
|
249
|
+
- 📝 访问日志记录
|
|
250
|
+
|
|
251
|
+
## 使用场景
|
|
252
|
+
|
|
253
|
+
- 🌐 HTTP API服务
|
|
254
|
+
- 📊 管理后台接口
|
|
255
|
+
- 📡 实时数据推送
|
|
256
|
+
- 🔧 Webhook接收
|
|
257
|
+
- 📱 移动应用后端
|
|
258
|
+
|
|
259
|
+
## 许可证
|
|
260
|
+
|
|
261
|
+
MIT License
|
package/lib/index.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { Server } from 'http';
|
|
2
|
+
import Koa from 'koa';
|
|
3
|
+
import { Router } from './router.js';
|
|
4
|
+
export * from './router.js';
|
|
5
|
+
declare module '@zhin.js/types' {
|
|
6
|
+
interface GlobalContext {
|
|
7
|
+
koa: Koa;
|
|
8
|
+
router: Router;
|
|
9
|
+
server: Server;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAgB,MAAM,EAAE,MAAM,MAAM,CAAC;AAC5C,OAAO,GAAG,MAAM,KAAK,CAAC;AAGtB,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAGrC,cAAc,aAAa,CAAC;AAE5B,OAAO,QAAQ,gBAAgB,CAAA;IAC7B,UAAU,aAAa;QACrB,GAAG,EAAE,GAAG,CAAC;QACT,MAAM,EAAE,MAAM,CAAC;QACf,MAAM,EAAE,MAAM,CAAA;KACf;CACF"}
|
package/lib/index.js
ADDED
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
import { register, useApp } from '@zhin.js/core';
|
|
2
|
+
import { createServer } from 'http';
|
|
3
|
+
import Koa from 'koa';
|
|
4
|
+
import auth from 'koa-basic-auth';
|
|
5
|
+
import KoaBodyParser from 'koa-bodyparser';
|
|
6
|
+
import { Router } from './router.js';
|
|
7
|
+
import * as process from 'process';
|
|
8
|
+
export * from './router.js';
|
|
9
|
+
const koa = new Koa();
|
|
10
|
+
const server = createServer(koa.callback());
|
|
11
|
+
const router = new Router(server, { prefix: process.env.routerPrefix || '' });
|
|
12
|
+
const username = process.env.username || 'admin';
|
|
13
|
+
const password = process.env.password || '123456';
|
|
14
|
+
const app = useApp();
|
|
15
|
+
koa.use(auth({
|
|
16
|
+
name: username,
|
|
17
|
+
pass: password,
|
|
18
|
+
}));
|
|
19
|
+
// ============================================================================
|
|
20
|
+
// API 路由
|
|
21
|
+
// ============================================================================
|
|
22
|
+
// 系统状态 API
|
|
23
|
+
router.get('/api/system/status', async (ctx) => {
|
|
24
|
+
try {
|
|
25
|
+
ctx.body = {
|
|
26
|
+
success: true,
|
|
27
|
+
data: {
|
|
28
|
+
uptime: process.uptime(),
|
|
29
|
+
memory: process.memoryUsage(),
|
|
30
|
+
cpu: process.cpuUsage(),
|
|
31
|
+
platform: process.platform,
|
|
32
|
+
nodeVersion: process.version,
|
|
33
|
+
pid: process.pid,
|
|
34
|
+
timestamp: new Date().toISOString()
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
catch (error) {
|
|
39
|
+
ctx.status = 500;
|
|
40
|
+
ctx.body = { success: false, error: error.message };
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
// 健康检查 API
|
|
44
|
+
router.get('/api/health', async (ctx) => {
|
|
45
|
+
ctx.body = {
|
|
46
|
+
success: true,
|
|
47
|
+
status: 'ok',
|
|
48
|
+
timestamp: new Date().toISOString()
|
|
49
|
+
};
|
|
50
|
+
});
|
|
51
|
+
// 插件管理 API
|
|
52
|
+
router.get('/api/plugins', async (ctx) => {
|
|
53
|
+
try {
|
|
54
|
+
// 获取详细的插件数据
|
|
55
|
+
const plugins = app.dependencyList.map(dep => {
|
|
56
|
+
return {
|
|
57
|
+
name: dep.name,
|
|
58
|
+
command_count: dep.commands.length,
|
|
59
|
+
component_count: dep.components.size,
|
|
60
|
+
middleware_count: dep.middlewares.length,
|
|
61
|
+
context_count: dep.contexts.size,
|
|
62
|
+
};
|
|
63
|
+
});
|
|
64
|
+
ctx.body = { success: true, data: plugins };
|
|
65
|
+
}
|
|
66
|
+
catch (error) {
|
|
67
|
+
ctx.status = 500;
|
|
68
|
+
ctx.body = { success: false, error: error.message };
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
// 适配器管理 API
|
|
72
|
+
router.get('/api/adapters', async (ctx) => {
|
|
73
|
+
try {
|
|
74
|
+
// 模拟适配器数据
|
|
75
|
+
const adapters = app.contextList.map(ctx => {
|
|
76
|
+
return {
|
|
77
|
+
name: ctx.name,
|
|
78
|
+
desc: ctx.description,
|
|
79
|
+
};
|
|
80
|
+
});
|
|
81
|
+
ctx.body = { success: true, data: adapters };
|
|
82
|
+
}
|
|
83
|
+
catch (error) {
|
|
84
|
+
ctx.status = 500;
|
|
85
|
+
ctx.body = { success: false, error: error.message };
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
// 框架配置信息 API
|
|
89
|
+
router.get('/api/config', async (ctx) => {
|
|
90
|
+
try {
|
|
91
|
+
const config = app.getConfig();
|
|
92
|
+
ctx.body = { success: true, data: config };
|
|
93
|
+
}
|
|
94
|
+
catch (error) {
|
|
95
|
+
ctx.status = 500;
|
|
96
|
+
ctx.body = { success: false, error: error.message };
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
// 消息发送 API
|
|
100
|
+
router.post('/api/message/send', async (ctx) => {
|
|
101
|
+
try {
|
|
102
|
+
const body = ctx.request.body;
|
|
103
|
+
const { context, bot, id, type, content } = body;
|
|
104
|
+
if (!context || !bot || !id || !type || !content) {
|
|
105
|
+
ctx.status = 400;
|
|
106
|
+
ctx.body = {
|
|
107
|
+
success: false,
|
|
108
|
+
error: 'Missing required fields: context, bot, id, type, content'
|
|
109
|
+
};
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
// 模拟发送消息(实际环境中会调用应用实例的sendMessage方法)
|
|
113
|
+
// console.log 已替换为注释
|
|
114
|
+
ctx.body = {
|
|
115
|
+
success: true,
|
|
116
|
+
message: 'Message sent successfully',
|
|
117
|
+
data: { context, bot, id, type, content, timestamp: new Date().toISOString() }
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
catch (error) {
|
|
121
|
+
ctx.status = 500;
|
|
122
|
+
ctx.body = { success: false, error: error.message };
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
// 日志 API
|
|
126
|
+
router.get('/api/logs', async (ctx) => {
|
|
127
|
+
try {
|
|
128
|
+
// 模拟日志数据
|
|
129
|
+
const logs = [
|
|
130
|
+
{
|
|
131
|
+
level: 'info',
|
|
132
|
+
message: 'HTTP服务器启动成功',
|
|
133
|
+
timestamp: new Date(Date.now() - 60000).toISOString(),
|
|
134
|
+
source: 'http'
|
|
135
|
+
},
|
|
136
|
+
{
|
|
137
|
+
level: 'info',
|
|
138
|
+
message: 'Web控制台已就绪',
|
|
139
|
+
timestamp: new Date(Date.now() - 50000).toISOString(),
|
|
140
|
+
source: 'console'
|
|
141
|
+
},
|
|
142
|
+
{
|
|
143
|
+
level: 'warn',
|
|
144
|
+
message: 'KOOK适配器连接不稳定',
|
|
145
|
+
timestamp: new Date(Date.now() - 30000).toISOString(),
|
|
146
|
+
source: 'kook'
|
|
147
|
+
},
|
|
148
|
+
{
|
|
149
|
+
level: 'error',
|
|
150
|
+
message: 'ICQQ登录失败',
|
|
151
|
+
timestamp: new Date(Date.now() - 20000).toISOString(),
|
|
152
|
+
source: 'icqq'
|
|
153
|
+
}
|
|
154
|
+
];
|
|
155
|
+
ctx.body = { success: true, data: logs };
|
|
156
|
+
}
|
|
157
|
+
catch (error) {
|
|
158
|
+
ctx.status = 500;
|
|
159
|
+
ctx.body = { success: false, error: error.message };
|
|
160
|
+
}
|
|
161
|
+
});
|
|
162
|
+
// ============================================================================
|
|
163
|
+
// 上下文注册
|
|
164
|
+
// ============================================================================
|
|
165
|
+
register({
|
|
166
|
+
name: 'server',
|
|
167
|
+
description: "http server",
|
|
168
|
+
mounted(p) {
|
|
169
|
+
return new Promise((resolve) => {
|
|
170
|
+
server.listen({
|
|
171
|
+
host: '0.0.0.0',
|
|
172
|
+
port: Number((process.env.port ||= '8086')),
|
|
173
|
+
}, () => {
|
|
174
|
+
const address = server.address();
|
|
175
|
+
if (!address)
|
|
176
|
+
return;
|
|
177
|
+
const visitAddress = typeof address === 'string' ? address : `${address.address}:${address.port}`;
|
|
178
|
+
p.logger.info(`server is running at http://${visitAddress}`);
|
|
179
|
+
p.logger.info('your username is:', username);
|
|
180
|
+
p.logger.info('your password is:', password);
|
|
181
|
+
resolve(server);
|
|
182
|
+
});
|
|
183
|
+
});
|
|
184
|
+
},
|
|
185
|
+
dispose(s) {
|
|
186
|
+
s.close();
|
|
187
|
+
}
|
|
188
|
+
});
|
|
189
|
+
register({
|
|
190
|
+
name: "koa",
|
|
191
|
+
description: "koa instance",
|
|
192
|
+
value: koa
|
|
193
|
+
});
|
|
194
|
+
register({
|
|
195
|
+
name: 'router',
|
|
196
|
+
description: "koa router",
|
|
197
|
+
value: router
|
|
198
|
+
});
|
|
199
|
+
koa.use(KoaBodyParser()).use(router.routes()).use(router.allowedMethods());
|
|
200
|
+
//# sourceMappingURL=index.js.map
|
package/lib/index.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/lib/router.d.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { Layer, RouterOptions } from '@koa/router';
|
|
2
|
+
import KoaRouter from "@koa/router";
|
|
3
|
+
import * as http from 'http';
|
|
4
|
+
import { ServerOptions, WebSocketServer } from 'ws';
|
|
5
|
+
type Path = string | RegExp;
|
|
6
|
+
export declare class Router extends KoaRouter {
|
|
7
|
+
server: http.Server;
|
|
8
|
+
wsStack: WebSocketServer[];
|
|
9
|
+
whiteList: Path[];
|
|
10
|
+
constructor(server: http.Server, options?: RouterOptions);
|
|
11
|
+
register(...args: Parameters<KoaRouter['register']>): Layer;
|
|
12
|
+
destroy(layer: Layer): void;
|
|
13
|
+
destroyWs(wsServer: WebSocketServer): void;
|
|
14
|
+
ws(path: string, options?: Omit<ServerOptions, 'noServer' | 'path'>): WebSocketServer;
|
|
15
|
+
}
|
|
16
|
+
export {};
|
|
17
|
+
//# sourceMappingURL=router.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"router.d.ts","sourceRoot":"","sources":["../src/router.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACnD,OAAO,SAAS,MAAM,aAAa,CAAC;AACpC,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAC7B,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,IAAI,CAAC;AAGpD,KAAK,IAAI,GAAG,MAAM,GAAG,MAAM,CAAC;AAE5B,qBAAa,MAAO,SAAQ,SAAS;IAI1B,MAAM,EAAE,IAAI,CAAC,MAAM;IAH5B,OAAO,EAAE,eAAe,EAAE,CAAM;IAChC,SAAS,EAAE,IAAI,EAAE,CAAM;gBAEd,MAAM,EAAE,IAAI,CAAC,MAAM,EAC1B,OAAO,CAAC,EAAE,aAAa;IAKzB,QAAQ,CAAC,GAAG,IAAI,EAAE,UAAU,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC;IAMnD,OAAO,CAAC,KAAK,EAAE,KAAK;IAIpB,SAAS,CAAC,QAAQ,EAAE,eAAe;IAKnC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,IAAI,CAAC,aAAa,EAAE,UAAU,GAAG,MAAM,CAAM,GAAG,eAAe;CAoB1F"}
|
package/lib/router.js
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { remove } from '@zhin.js/core';
|
|
2
|
+
import KoaRouter from "@koa/router";
|
|
3
|
+
import { WebSocketServer } from 'ws';
|
|
4
|
+
import { parse } from 'url';
|
|
5
|
+
export class Router extends KoaRouter {
|
|
6
|
+
server;
|
|
7
|
+
wsStack = [];
|
|
8
|
+
whiteList = []; //用于historyApi排除
|
|
9
|
+
constructor(server, options) {
|
|
10
|
+
super(options);
|
|
11
|
+
this.server = server;
|
|
12
|
+
}
|
|
13
|
+
register(...args) {
|
|
14
|
+
const path = args[0];
|
|
15
|
+
this.whiteList.push(path);
|
|
16
|
+
return super.register(...args);
|
|
17
|
+
}
|
|
18
|
+
destroy(layer) {
|
|
19
|
+
remove(this.stack, layer);
|
|
20
|
+
}
|
|
21
|
+
destroyWs(wsServer) {
|
|
22
|
+
wsServer.close();
|
|
23
|
+
remove(this.wsStack, wsServer);
|
|
24
|
+
}
|
|
25
|
+
ws(path, options = {}) {
|
|
26
|
+
const wsServer = new WebSocketServer({
|
|
27
|
+
noServer: true,
|
|
28
|
+
path,
|
|
29
|
+
...options,
|
|
30
|
+
});
|
|
31
|
+
this.wsStack.push(wsServer);
|
|
32
|
+
this.server.on('upgrade', (request, socket, head) => {
|
|
33
|
+
const { pathname } = parse(request.url);
|
|
34
|
+
if (this.wsStack.findIndex(wss => wss.options.path === path) === -1) {
|
|
35
|
+
socket.destroy();
|
|
36
|
+
}
|
|
37
|
+
else if (pathname === path) {
|
|
38
|
+
wsServer.handleUpgrade(request, socket, head, ws => {
|
|
39
|
+
wsServer.emit('connection', ws, request);
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
return wsServer;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=router.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"router.js","sourceRoot":"","sources":["../src/router.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAEvC,OAAO,SAAS,MAAM,aAAa,CAAC;AAEpC,OAAO,EAAiB,eAAe,EAAE,MAAM,IAAI,CAAC;AACpD,OAAO,EAAE,KAAK,EAAE,MAAM,KAAK,CAAC;AAI5B,MAAM,OAAO,MAAO,SAAQ,SAAS;IAI1B;IAHT,OAAO,GAAsB,EAAE,CAAC;IAChC,SAAS,GAAW,EAAE,CAAC,CAAC,gBAAgB;IACxC,YACS,MAAmB,EAC1B,OAAuB;QAEvB,KAAK,CAAC,OAAO,CAAC,CAAC;QAHR,WAAM,GAAN,MAAM,CAAa;IAI5B,CAAC;IAED,QAAQ,CAAC,GAAG,IAAuC;QACjD,MAAM,IAAI,GAAS,IAAI,CAAC,CAAC,CAAQ,CAAC;QAClC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC1B,OAAO,KAAK,CAAC,QAAQ,CAAC,GAAG,IAAI,CAAC,CAAC;IACjC,CAAC;IAED,OAAO,CAAC,KAAY;QAClB,MAAM,CAAC,IAAI,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;IAC5B,CAAC;IAED,SAAS,CAAC,QAAyB;QACjC,QAAQ,CAAC,KAAK,EAAE,CAAC;QACjB,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;IACjC,CAAC;IAED,EAAE,CAAC,IAAY,EAAE,UAAoD,EAAE;QACrE,MAAM,QAAQ,GAAG,IAAI,eAAe,CAAC;YACnC,QAAQ,EAAE,IAAI;YACd,IAAI;YACJ,GAAG,OAAO;SACX,CAAC,CAAC;QACH,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAE5B,IAAI,CAAC,MAAO,CAAC,EAAE,CAAC,SAAS,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE;YACnD,MAAM,EAAE,QAAQ,EAAE,GAAG,KAAK,CAAC,OAAO,CAAC,GAAI,CAAC,CAAC;YACzC,IAAI,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,KAAK,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC;gBACpE,MAAM,CAAC,OAAO,EAAE,CAAC;YACnB,CAAC;iBAAM,IAAI,QAAQ,KAAK,IAAI,EAAE,CAAC;gBAC7B,QAAQ,CAAC,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,CAAC,EAAE;oBACjD,QAAQ,CAAC,IAAI,CAAC,YAAY,EAAE,EAAE,EAAE,OAAO,CAAC,CAAC;gBAC3C,CAAC,CAAC,CAAC;YACL,CAAC;QACH,CAAC,CAAC,CAAC;QACH,OAAO,QAAQ,CAAC;IAClB,CAAC;CACF"}
|
package/package.json
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@zhin.js/http",
|
|
3
|
+
"version": "1.0.1",
|
|
4
|
+
"description": "Zhin机器人框架HTTP工具",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./lib/index.js",
|
|
7
|
+
"types": "./lib/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./lib/index.d.ts",
|
|
11
|
+
"import": "./lib/index.js"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"dependencies": {
|
|
15
|
+
"@koa/router": "latest",
|
|
16
|
+
"koa": "latest",
|
|
17
|
+
"ws": "^8.18.3",
|
|
18
|
+
"koa-basic-auth": "latest",
|
|
19
|
+
"koa-bodyparser": "latest"
|
|
20
|
+
},
|
|
21
|
+
"peerDependencies": {
|
|
22
|
+
"@zhin.js/core": "^1.0.1"
|
|
23
|
+
},
|
|
24
|
+
"devDependencies": {
|
|
25
|
+
"@types/koa": "latest",
|
|
26
|
+
"@types/koa-basic-auth": "latest",
|
|
27
|
+
"@types/koa-bodyparser": "latest",
|
|
28
|
+
"@types/koa__router": "latest",
|
|
29
|
+
"@types/ws": "latest",
|
|
30
|
+
"@zhin.js/types": "^1.0.1"
|
|
31
|
+
},
|
|
32
|
+
"scripts": {
|
|
33
|
+
"build": "tsc",
|
|
34
|
+
"clean": "rm -rf lib"
|
|
35
|
+
}
|
|
36
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
import {register, useApp} from '@zhin.js/core';
|
|
2
|
+
import { createServer, Server } from 'http';
|
|
3
|
+
import Koa from 'koa';
|
|
4
|
+
import auth from 'koa-basic-auth';
|
|
5
|
+
import KoaBodyParser from 'koa-bodyparser';
|
|
6
|
+
import { Router } from './router.js';
|
|
7
|
+
import * as process from 'process';
|
|
8
|
+
|
|
9
|
+
export * from './router.js';
|
|
10
|
+
|
|
11
|
+
declare module '@zhin.js/types'{
|
|
12
|
+
interface GlobalContext {
|
|
13
|
+
koa: Koa,
|
|
14
|
+
router: Router,
|
|
15
|
+
server: Server
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const koa = new Koa();
|
|
20
|
+
const server = createServer(koa.callback())
|
|
21
|
+
const router = new Router(server, { prefix: process.env.routerPrefix || '' });
|
|
22
|
+
const username = process.env.username || 'admin';
|
|
23
|
+
const password = process.env.password || '123456';
|
|
24
|
+
const app=useApp()
|
|
25
|
+
koa.use(
|
|
26
|
+
auth({
|
|
27
|
+
name: username,
|
|
28
|
+
pass: password,
|
|
29
|
+
}),
|
|
30
|
+
);
|
|
31
|
+
|
|
32
|
+
// ============================================================================
|
|
33
|
+
// API 路由
|
|
34
|
+
// ============================================================================
|
|
35
|
+
|
|
36
|
+
// 系统状态 API
|
|
37
|
+
router.get('/api/system/status', async (ctx) => {
|
|
38
|
+
try {
|
|
39
|
+
ctx.body = {
|
|
40
|
+
success: true,
|
|
41
|
+
data: {
|
|
42
|
+
uptime: process.uptime(),
|
|
43
|
+
memory: process.memoryUsage(),
|
|
44
|
+
cpu: process.cpuUsage(),
|
|
45
|
+
platform: process.platform,
|
|
46
|
+
nodeVersion: process.version,
|
|
47
|
+
pid: process.pid,
|
|
48
|
+
timestamp: new Date().toISOString()
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
} catch (error) {
|
|
52
|
+
ctx.status = 500
|
|
53
|
+
ctx.body = { success: false, error: (error as Error).message }
|
|
54
|
+
}
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
// 健康检查 API
|
|
58
|
+
router.get('/api/health', async (ctx) => {
|
|
59
|
+
ctx.body = {
|
|
60
|
+
success: true,
|
|
61
|
+
status: 'ok',
|
|
62
|
+
timestamp: new Date().toISOString()
|
|
63
|
+
}
|
|
64
|
+
})
|
|
65
|
+
|
|
66
|
+
// 插件管理 API
|
|
67
|
+
router.get('/api/plugins', async (ctx) => {
|
|
68
|
+
try {
|
|
69
|
+
// 获取详细的插件数据
|
|
70
|
+
const plugins = app.dependencyList.map(dep => {
|
|
71
|
+
return {
|
|
72
|
+
name:dep.name,
|
|
73
|
+
command_count:dep.commands.length,
|
|
74
|
+
component_count:dep.components.size,
|
|
75
|
+
middleware_count:dep.middlewares.length,
|
|
76
|
+
context_count:dep.contexts.size,
|
|
77
|
+
}
|
|
78
|
+
})
|
|
79
|
+
|
|
80
|
+
ctx.body = { success: true, data: plugins }
|
|
81
|
+
} catch (error) {
|
|
82
|
+
ctx.status = 500
|
|
83
|
+
ctx.body = { success: false, error: (error as Error).message }
|
|
84
|
+
}
|
|
85
|
+
})
|
|
86
|
+
|
|
87
|
+
// 适配器管理 API
|
|
88
|
+
router.get('/api/adapters', async (ctx) => {
|
|
89
|
+
try {
|
|
90
|
+
// 模拟适配器数据
|
|
91
|
+
const adapters = app.contextList.map(ctx=>{
|
|
92
|
+
return {
|
|
93
|
+
name:ctx.name,
|
|
94
|
+
desc:ctx.description,
|
|
95
|
+
}
|
|
96
|
+
})
|
|
97
|
+
|
|
98
|
+
ctx.body = { success: true, data: adapters }
|
|
99
|
+
} catch (error) {
|
|
100
|
+
ctx.status = 500
|
|
101
|
+
ctx.body = { success: false, error: (error as Error).message }
|
|
102
|
+
}
|
|
103
|
+
})
|
|
104
|
+
|
|
105
|
+
// 框架配置信息 API
|
|
106
|
+
router.get('/api/config', async (ctx) => {
|
|
107
|
+
try {
|
|
108
|
+
const config = app.getConfig()
|
|
109
|
+
|
|
110
|
+
ctx.body = { success: true, data: config }
|
|
111
|
+
} catch (error) {
|
|
112
|
+
ctx.status = 500
|
|
113
|
+
ctx.body = { success: false, error: (error as Error).message }
|
|
114
|
+
}
|
|
115
|
+
})
|
|
116
|
+
|
|
117
|
+
// 消息发送 API
|
|
118
|
+
router.post('/api/message/send', async (ctx) => {
|
|
119
|
+
try {
|
|
120
|
+
const body = ctx.request.body as any
|
|
121
|
+
const { context, bot, id, type, content } = body
|
|
122
|
+
|
|
123
|
+
if (!context || !bot || !id || !type || !content) {
|
|
124
|
+
ctx.status = 400
|
|
125
|
+
ctx.body = {
|
|
126
|
+
success: false,
|
|
127
|
+
error: 'Missing required fields: context, bot, id, type, content'
|
|
128
|
+
}
|
|
129
|
+
return
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// 模拟发送消息(实际环境中会调用应用实例的sendMessage方法)
|
|
133
|
+
// console.log 已替换为注释
|
|
134
|
+
|
|
135
|
+
ctx.body = {
|
|
136
|
+
success: true,
|
|
137
|
+
message: 'Message sent successfully',
|
|
138
|
+
data: { context, bot, id, type, content, timestamp: new Date().toISOString() }
|
|
139
|
+
}
|
|
140
|
+
} catch (error) {
|
|
141
|
+
ctx.status = 500
|
|
142
|
+
ctx.body = { success: false, error: (error as Error).message }
|
|
143
|
+
}
|
|
144
|
+
})
|
|
145
|
+
|
|
146
|
+
// 日志 API
|
|
147
|
+
router.get('/api/logs', async (ctx) => {
|
|
148
|
+
try {
|
|
149
|
+
// 模拟日志数据
|
|
150
|
+
const logs = [
|
|
151
|
+
{
|
|
152
|
+
level: 'info',
|
|
153
|
+
message: 'HTTP服务器启动成功',
|
|
154
|
+
timestamp: new Date(Date.now() - 60000).toISOString(),
|
|
155
|
+
source: 'http'
|
|
156
|
+
},
|
|
157
|
+
{
|
|
158
|
+
level: 'info',
|
|
159
|
+
message: 'Web控制台已就绪',
|
|
160
|
+
timestamp: new Date(Date.now() - 50000).toISOString(),
|
|
161
|
+
source: 'console'
|
|
162
|
+
},
|
|
163
|
+
{
|
|
164
|
+
level: 'warn',
|
|
165
|
+
message: 'KOOK适配器连接不稳定',
|
|
166
|
+
timestamp: new Date(Date.now() - 30000).toISOString(),
|
|
167
|
+
source: 'kook'
|
|
168
|
+
},
|
|
169
|
+
{
|
|
170
|
+
level: 'error',
|
|
171
|
+
message: 'ICQQ登录失败',
|
|
172
|
+
timestamp: new Date(Date.now() - 20000).toISOString(),
|
|
173
|
+
source: 'icqq'
|
|
174
|
+
}
|
|
175
|
+
]
|
|
176
|
+
|
|
177
|
+
ctx.body = { success: true, data: logs }
|
|
178
|
+
} catch (error) {
|
|
179
|
+
ctx.status = 500
|
|
180
|
+
ctx.body = { success: false, error: (error as Error).message }
|
|
181
|
+
}
|
|
182
|
+
})
|
|
183
|
+
|
|
184
|
+
// ============================================================================
|
|
185
|
+
// 上下文注册
|
|
186
|
+
// ============================================================================
|
|
187
|
+
|
|
188
|
+
register({
|
|
189
|
+
name: 'server',
|
|
190
|
+
description:"http server",
|
|
191
|
+
mounted(p) {
|
|
192
|
+
return new Promise<Server>((resolve) => {
|
|
193
|
+
server.listen(
|
|
194
|
+
{
|
|
195
|
+
host: '0.0.0.0',
|
|
196
|
+
port: Number((process.env.port ||= '8086')),
|
|
197
|
+
},
|
|
198
|
+
() => {
|
|
199
|
+
const address = server.address();
|
|
200
|
+
if (!address) return;
|
|
201
|
+
const visitAddress = typeof address === 'string' ? address : `${address.address}:${address.port}`;
|
|
202
|
+
p.logger.info(`server is running at http://${visitAddress}`);
|
|
203
|
+
p.logger.info('your username is:', username);
|
|
204
|
+
p.logger.info('your password is:', password);
|
|
205
|
+
resolve(server)
|
|
206
|
+
},
|
|
207
|
+
)
|
|
208
|
+
})
|
|
209
|
+
},
|
|
210
|
+
dispose(s) {
|
|
211
|
+
s.close()
|
|
212
|
+
}
|
|
213
|
+
})
|
|
214
|
+
|
|
215
|
+
register({
|
|
216
|
+
name: "koa",
|
|
217
|
+
description:"koa instance",
|
|
218
|
+
value: koa
|
|
219
|
+
})
|
|
220
|
+
|
|
221
|
+
register({
|
|
222
|
+
name: 'router',
|
|
223
|
+
description:"koa router",
|
|
224
|
+
value: router
|
|
225
|
+
})
|
|
226
|
+
|
|
227
|
+
koa.use(KoaBodyParser()).use(router.routes()).use(router.allowedMethods());
|
package/src/router.ts
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { remove } from '@zhin.js/core';
|
|
2
|
+
import { Layer, RouterOptions } from '@koa/router';
|
|
3
|
+
import KoaRouter from "@koa/router";
|
|
4
|
+
import * as http from 'http';
|
|
5
|
+
import { ServerOptions, WebSocketServer } from 'ws';
|
|
6
|
+
import { parse } from 'url';
|
|
7
|
+
|
|
8
|
+
type Path = string | RegExp;
|
|
9
|
+
|
|
10
|
+
export class Router extends KoaRouter {
|
|
11
|
+
wsStack: WebSocketServer[] = [];
|
|
12
|
+
whiteList: Path[] = []; //用于historyApi排除
|
|
13
|
+
constructor(
|
|
14
|
+
public server: http.Server,
|
|
15
|
+
options?: RouterOptions,
|
|
16
|
+
) {
|
|
17
|
+
super(options);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
register(...args: Parameters<KoaRouter['register']>) {
|
|
21
|
+
const path: Path = args[0] as any;
|
|
22
|
+
this.whiteList.push(path);
|
|
23
|
+
return super.register(...args);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
destroy(layer: Layer) {
|
|
27
|
+
remove(this.stack, layer);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
destroyWs(wsServer: WebSocketServer) {
|
|
31
|
+
wsServer.close();
|
|
32
|
+
remove(this.wsStack, wsServer);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
ws(path: string, options: Omit<ServerOptions, 'noServer' | 'path'> = {}): WebSocketServer {
|
|
36
|
+
const wsServer = new WebSocketServer({
|
|
37
|
+
noServer: true,
|
|
38
|
+
path,
|
|
39
|
+
...options,
|
|
40
|
+
});
|
|
41
|
+
this.wsStack.push(wsServer);
|
|
42
|
+
|
|
43
|
+
this.server!.on('upgrade', (request, socket, head) => {
|
|
44
|
+
const { pathname } = parse(request.url!);
|
|
45
|
+
if (this.wsStack.findIndex(wss => wss.options.path === path) === -1) {
|
|
46
|
+
socket.destroy();
|
|
47
|
+
} else if (pathname === path) {
|
|
48
|
+
wsServer.handleUpgrade(request, socket, head, ws => {
|
|
49
|
+
wsServer.emit('connection', ws, request);
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
return wsServer;
|
|
54
|
+
}
|
|
55
|
+
}
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "ESNext",
|
|
5
|
+
"moduleResolution": "bundler",
|
|
6
|
+
"outDir": "./lib",
|
|
7
|
+
"rootDir": "./src",
|
|
8
|
+
"strict": true,
|
|
9
|
+
"esModuleInterop": true,
|
|
10
|
+
"skipLibCheck": true,
|
|
11
|
+
"forceConsistentCasingInFileNames": true,
|
|
12
|
+
"resolveJsonModule": true,
|
|
13
|
+
"isolatedModules": true,
|
|
14
|
+
"allowSyntheticDefaultImports": true,
|
|
15
|
+
"experimentalDecorators": true,
|
|
16
|
+
"emitDecoratorMetadata": true,
|
|
17
|
+
"declaration": true,
|
|
18
|
+
"declarationMap": true,
|
|
19
|
+
"sourceMap": true
|
|
20
|
+
},
|
|
21
|
+
"include": ["src/**/*"],
|
|
22
|
+
"exclude": ["lib", "node_modules"]
|
|
23
|
+
}
|