@lark-apaas/devtool-kits 0.1.0-alpha.6 → 0.1.0-alpha.8
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/README.md +383 -185
- package/dist/index.cjs +151 -28
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +13 -3
- package/dist/index.d.ts +13 -3
- package/dist/index.js +147 -25
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,31 +1,110 @@
|
|
|
1
1
|
# Fullstack Toolkits
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
面向 NestJS 全栈项目的综合工具包,提供开箱即用的开发中间件、工具函数和辅助功能,帮助您快速搭建高效的开发环境。
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## 功能特性
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
- 📚 **OpenAPI Enhancement** - Enhanced OpenAPI/Swagger documentation with source code information
|
|
9
|
-
- 🛠️ **Utility Functions** - Common utilities for path normalization and more
|
|
10
|
-
- 🔍 **Path Matching** - Powerful path pattern matching for OpenAPI/Swagger/NestJS routes
|
|
7
|
+
本 SDK 导出三大核心模块,让您可以快速集成到项目中:
|
|
11
8
|
|
|
12
|
-
|
|
9
|
+
### 📦 开箱即用的中间件 (Middlewares)
|
|
10
|
+
- **Dev Logs 中间件** - 查看和查询应用日志,支持 Trace ID 追踪和路径过滤
|
|
11
|
+
- **Collect Logs 中间件** - 收集客户端日志并自动存储到文件
|
|
12
|
+
- **OpenAPI 中间件** - 增强 OpenAPI 文档,自动添加源代码引用信息
|
|
13
|
+
|
|
14
|
+
### 🛠️ 实用工具函数 (Utils)
|
|
15
|
+
- **路径规范化** - 自动处理路径格式,确保一致性
|
|
16
|
+
|
|
17
|
+
### 🔌 通用脚本 (Helpers)
|
|
18
|
+
- **Drizzle Schema 后处理** - 自动优化 Drizzle Kit 生成的 schema 文件
|
|
19
|
+
- 中文表名转拼音标识符
|
|
20
|
+
- 自动替换自定义类型(user_profile、file_attachment)
|
|
21
|
+
- 添加系统字段注释(_created_at、_updated_at 等)
|
|
22
|
+
- 优化 import 语句和代码格式
|
|
23
|
+
|
|
24
|
+
## 安装
|
|
13
25
|
|
|
14
26
|
```bash
|
|
15
27
|
npm install @apaas/fullstack-toolkits
|
|
16
|
-
#
|
|
28
|
+
# 或
|
|
17
29
|
yarn add @apaas/fullstack-toolkits
|
|
18
30
|
```
|
|
19
31
|
|
|
20
|
-
##
|
|
32
|
+
## 快速开始
|
|
33
|
+
|
|
34
|
+
只需三步,即可为您的项目添加强大的开发工具:
|
|
35
|
+
|
|
36
|
+
```typescript
|
|
37
|
+
import {
|
|
38
|
+
registerMiddlewares,
|
|
39
|
+
createDevLogsMiddleware,
|
|
40
|
+
createCollectLogsMiddleware,
|
|
41
|
+
createOpenapiMiddleware
|
|
42
|
+
} from '@apaas/fullstack-toolkits';
|
|
43
|
+
|
|
44
|
+
// 在 rspack/webpack 或 Vite 开发服务器中注册
|
|
45
|
+
registerMiddlewares(devServer.app, [
|
|
46
|
+
createDevLogsMiddleware({ logDir: './logs' }),
|
|
47
|
+
createCollectLogsMiddleware({ logDir: './logs' }),
|
|
48
|
+
createOpenapiMiddleware({ openapiFilePath: './openapi.json' }),
|
|
49
|
+
], {
|
|
50
|
+
basePath: '/api',
|
|
51
|
+
isDev: true,
|
|
52
|
+
rootDir: __dirname
|
|
53
|
+
});
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
完成!现在您可以:
|
|
57
|
+
- 📊 访问 `GET /api/dev/logs/trace/recent` 查看最近的 API 调用
|
|
58
|
+
- 📝 通过 `POST /api/dev/logs/collect` 收集客户端日志
|
|
59
|
+
- 📚 访问 `GET /api/dev/openapi.json` 获取增强的 API 文档
|
|
60
|
+
|
|
61
|
+
## 导出内容
|
|
62
|
+
|
|
63
|
+
### 中间件 (Middlewares)
|
|
64
|
+
```typescript
|
|
65
|
+
import {
|
|
66
|
+
createDevLogsMiddleware, // 日志查询中间件
|
|
67
|
+
createCollectLogsMiddleware, // 日志收集中间件
|
|
68
|
+
createOpenapiMiddleware, // OpenAPI 增强中间件
|
|
69
|
+
} from '@apaas/fullstack-toolkits';
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### 工具函数 (Utils)
|
|
73
|
+
```typescript
|
|
74
|
+
import {
|
|
75
|
+
matchesPathPattern, // 路径模式匹配
|
|
76
|
+
extractPathParams, // 提取路径参数
|
|
77
|
+
normalizeBasePath, // 路径规范化
|
|
78
|
+
} from '@apaas/fullstack-toolkits';
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### 辅助函数 (Helpers)
|
|
82
|
+
```typescript
|
|
83
|
+
import {
|
|
84
|
+
registerMiddlewares, // 统一注册中间件
|
|
85
|
+
postprocessDrizzleSchema, // 后处理 Drizzle Schema 文件
|
|
86
|
+
} from '@apaas/fullstack-toolkits';
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### 类型定义 (Types)
|
|
90
|
+
```typescript
|
|
91
|
+
import type {
|
|
92
|
+
Middleware, // 中间件联合类型
|
|
93
|
+
RouteMiddleware, // 路由中间件类型
|
|
94
|
+
GlobalMiddleware, // 全局中间件类型
|
|
95
|
+
MiddlewareContext, // 中间件上下文类型
|
|
96
|
+
} from '@apaas/fullstack-toolkits';
|
|
97
|
+
```
|
|
21
98
|
|
|
22
|
-
|
|
99
|
+
## 详细使用
|
|
23
100
|
|
|
24
|
-
|
|
25
|
-
- **Route Middlewares**: Mount at specific paths (e.g., `/dev/logs`, `/openapi.json`)
|
|
26
|
-
- **Global Middlewares**: Apply to all requests without path mounting
|
|
101
|
+
### 在不同开发服务器中集成
|
|
27
102
|
|
|
28
|
-
|
|
103
|
+
工具包支持两种类型的中间件:
|
|
104
|
+
- **路由中间件**:挂载到特定路径(例如 `/dev/logs`、`/dev/openapi.json`)
|
|
105
|
+
- **全局中间件**:应用于所有请求,无需挂载路径
|
|
106
|
+
|
|
107
|
+
**用于 Rspack / Webpack 开发服务器:**
|
|
29
108
|
|
|
30
109
|
```typescript
|
|
31
110
|
import {
|
|
@@ -34,17 +113,11 @@ import {
|
|
|
34
113
|
createOpenapiMiddleware
|
|
35
114
|
} from '@apaas/fullstack-toolkits';
|
|
36
115
|
|
|
37
|
-
// For rspack/webpack dev server
|
|
38
116
|
export default {
|
|
39
117
|
devServer: {
|
|
40
118
|
setupMiddlewares: (middlewares, devServer) => {
|
|
41
119
|
if (devServer.app) {
|
|
42
120
|
registerMiddlewares(devServer.app, [
|
|
43
|
-
// Global middlewares execute first (in array order)
|
|
44
|
-
createCorsMiddleware({ origin: '*' }),
|
|
45
|
-
createRequestLoggerMiddleware(),
|
|
46
|
-
|
|
47
|
-
// Route middlewares mount at specific paths
|
|
48
121
|
createDevLogsMiddleware({ logDir: './logs' }),
|
|
49
122
|
createOpenapiMiddleware({
|
|
50
123
|
openapiFilePath: './openapi.json',
|
|
@@ -60,8 +133,11 @@ export default {
|
|
|
60
133
|
}
|
|
61
134
|
}
|
|
62
135
|
}
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
**用于 Vite 开发服务器:**
|
|
63
139
|
|
|
64
|
-
|
|
140
|
+
```typescript
|
|
65
141
|
export default {
|
|
66
142
|
plugins: [
|
|
67
143
|
{
|
|
@@ -84,230 +160,352 @@ export default {
|
|
|
84
160
|
}
|
|
85
161
|
```
|
|
86
162
|
|
|
87
|
-
|
|
88
|
-
-
|
|
89
|
-
-
|
|
90
|
-
-
|
|
91
|
-
- Route middlewares only handle requests matching their mount path
|
|
163
|
+
**重要提示:**
|
|
164
|
+
- 中间件执行顺序与数组顺序一致
|
|
165
|
+
- 全局中间件应放在路由中间件之前
|
|
166
|
+
- 路由中间件仅处理匹配其挂载路径的请求
|
|
92
167
|
|
|
93
|
-
|
|
168
|
+
## 中间件详细说明
|
|
169
|
+
### Dev Logs 中间件
|
|
94
170
|
|
|
95
|
-
|
|
171
|
+
查看和查询带 Trace ID 支持的应用日志。
|
|
96
172
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
name: 'cors',
|
|
104
|
-
createHandler: () => {
|
|
105
|
-
return (req, res, next) => {
|
|
106
|
-
res.setHeader('Access-Control-Allow-Origin', options?.origin || '*');
|
|
107
|
-
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE');
|
|
108
|
-
next();
|
|
109
|
-
};
|
|
110
|
-
}
|
|
111
|
-
};
|
|
112
|
-
}
|
|
173
|
+
**功能特性:**
|
|
174
|
+
- 根据 Trace ID 查询日志条目
|
|
175
|
+
- 分页浏览最近的追踪调用
|
|
176
|
+
- 按 API 路径模式和 HTTP 方法过滤日志
|
|
177
|
+
- 支持 OpenAPI/Swagger 路径模式
|
|
178
|
+
- 分页读取日志文件
|
|
113
179
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
return (req, res, next) => {
|
|
121
|
-
console.log(`[${new Date().toISOString()}] ${req.method} ${req.path}`);
|
|
122
|
-
next();
|
|
123
|
-
};
|
|
124
|
-
}
|
|
125
|
-
};
|
|
126
|
-
}
|
|
127
|
-
```
|
|
180
|
+
**路由:**
|
|
181
|
+
- `GET /dev/logs/app/trace/:traceId` - 根据 Trace ID 获取日志条目
|
|
182
|
+
- `GET /dev/logs/trace/recent` - 获取最近的追踪调用(支持分页和过滤)
|
|
183
|
+
- `GET /dev/logs/files/:fileName` - 分页获取日志文件内容
|
|
184
|
+
|
|
185
|
+
**查询参数:**
|
|
128
186
|
|
|
129
|
-
|
|
187
|
+
**用于 `/app/trace/:traceId`:**
|
|
188
|
+
- `limit` - 返回条目的最大数量(默认:200,最大:1000)
|
|
130
189
|
|
|
131
|
-
|
|
190
|
+
**用于 `/trace/recent`:**
|
|
191
|
+
- `page` - 页码(默认:1)
|
|
192
|
+
- `pageSize` - 每页条目数(默认:10,最大:100)
|
|
193
|
+
- `path` - 按 API 路径模式过滤(支持通配符)
|
|
194
|
+
- `method` - 按 HTTP 方法过滤(GET、POST 等)
|
|
132
195
|
|
|
133
|
-
|
|
196
|
+
**用于 `/files/:fileName`:**
|
|
197
|
+
- `page` - 页码(默认:1)
|
|
198
|
+
- `pageSize` - 每页行数(默认:200,最大:2000)
|
|
134
199
|
|
|
135
|
-
|
|
136
|
-
- View log entries by trace ID
|
|
137
|
-
- Browse recent trace calls with pagination
|
|
138
|
-
- Filter logs by API path patterns
|
|
139
|
-
- Support for OpenAPI/Swagger path patterns
|
|
200
|
+
**响应示例:**
|
|
140
201
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
202
|
+
```typescript
|
|
203
|
+
// GET /dev/logs/app/trace/abc123?limit=100
|
|
204
|
+
{
|
|
205
|
+
file: "logs/app.log",
|
|
206
|
+
traceId: "abc123",
|
|
207
|
+
count: 5,
|
|
208
|
+
entries: [
|
|
209
|
+
{ /* 日志条目 1 */ },
|
|
210
|
+
{ /* 日志条目 2 */ }
|
|
211
|
+
]
|
|
212
|
+
}
|
|
145
213
|
|
|
146
|
-
|
|
214
|
+
// GET /dev/logs/trace/recent?page=1&pageSize=10&path=/api/users/*&method=POST
|
|
215
|
+
{
|
|
216
|
+
file: "logs/trace.log",
|
|
217
|
+
page: 1,
|
|
218
|
+
pageSize: 10,
|
|
219
|
+
total: 150,
|
|
220
|
+
totalPages: 15,
|
|
221
|
+
path: "/api/users/*",
|
|
222
|
+
method: "POST",
|
|
223
|
+
count: 10,
|
|
224
|
+
calls: [
|
|
225
|
+
{ /* 追踪调用 1 */ },
|
|
226
|
+
{ /* 追踪调用 2 */ }
|
|
227
|
+
]
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// GET /dev/logs/files/app.log?page=1&pageSize=200
|
|
231
|
+
{
|
|
232
|
+
file: "logs/app.log",
|
|
233
|
+
page: 1,
|
|
234
|
+
pageSize: 200,
|
|
235
|
+
total: 5000,
|
|
236
|
+
totalPages: 25,
|
|
237
|
+
lines: [
|
|
238
|
+
"日志行 1",
|
|
239
|
+
"日志行 2"
|
|
240
|
+
]
|
|
241
|
+
}
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
**使用示例:**
|
|
147
245
|
```typescript
|
|
246
|
+
// 注册中间件
|
|
148
247
|
createDevLogsMiddleware({
|
|
149
|
-
logDir: './logs',
|
|
248
|
+
logDir: './logs', // 可选,默认为 'logs' 或 context.logDir
|
|
150
249
|
})
|
|
250
|
+
|
|
251
|
+
// 客户端使用示例
|
|
252
|
+
// 获取指定 Trace ID 的日志
|
|
253
|
+
fetch('/dev/logs/app/trace/abc123?limit=100')
|
|
254
|
+
.then(res => res.json())
|
|
255
|
+
.then(data => console.log(data.entries));
|
|
256
|
+
|
|
257
|
+
// 按路径和方法过滤获取最近的 API 调用
|
|
258
|
+
fetch('/dev/logs/trace/recent?page=1&pageSize=20&path=/api/users/*&method=POST')
|
|
259
|
+
.then(res => res.json())
|
|
260
|
+
.then(data => console.log(data.calls));
|
|
261
|
+
|
|
262
|
+
// 分页读取日志文件
|
|
263
|
+
fetch('/dev/logs/files/app.log?page=1&pageSize=200')
|
|
264
|
+
.then(res => res.json())
|
|
265
|
+
.then(data => console.log(data.lines));
|
|
151
266
|
```
|
|
152
267
|
|
|
153
|
-
### OpenAPI Middleware
|
|
154
268
|
|
|
155
|
-
|
|
269
|
+
### Collect Logs 中间件
|
|
156
270
|
|
|
157
|
-
|
|
158
|
-
- Automatically enhance OpenAPI paths with controller source locations
|
|
159
|
-
- Transform paths to include basePath
|
|
160
|
-
- Caching support for better performance
|
|
271
|
+
从客户端收集日志并存储到日志文件中。
|
|
161
272
|
|
|
162
|
-
|
|
163
|
-
-
|
|
273
|
+
**功能特性:**
|
|
274
|
+
- 通过 HTTP POST 收集客户端日志
|
|
275
|
+
- 以 JSON Lines 格式存储日志
|
|
276
|
+
- 自动创建日志目录
|
|
277
|
+
- 可自定义日志文件名
|
|
164
278
|
|
|
165
|
-
|
|
279
|
+
**路由:**
|
|
280
|
+
- `POST /dev/logs/collect` - 从客户端收集日志
|
|
281
|
+
|
|
282
|
+
**请求体:**
|
|
166
283
|
```typescript
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
284
|
+
{
|
|
285
|
+
level: string; // 日志级别(info、warn、error 等)
|
|
286
|
+
message: string; // 日志消息
|
|
287
|
+
time: string; // ISO 时间戳字符串
|
|
288
|
+
source?: string; // 可选的日志来源标识
|
|
289
|
+
user_id: string; // 用户 ID
|
|
290
|
+
tenant_id: string; // 租户 ID
|
|
291
|
+
app_id: string; // 应用 ID
|
|
292
|
+
}
|
|
171
293
|
```
|
|
172
294
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
Powerful path pattern matching for OpenAPI/Swagger/NestJS routes.
|
|
176
|
-
|
|
177
|
-
**Supported Patterns:**
|
|
178
|
-
- Exact matching: `/api/users` === `/api/users`
|
|
179
|
-
- Path parameters: `/api/users/{id}` matches `/api/users/123`
|
|
180
|
-
- Single wildcard: `/api/*/users` matches `/api/v1/users`
|
|
181
|
-
- Recursive wildcard: `/files/**` matches `/files/a/b/c`
|
|
182
|
-
- Prefix matching: `/api/users` matches `/api/users/123`
|
|
183
|
-
|
|
184
|
-
**Example:**
|
|
295
|
+
**响应:**
|
|
185
296
|
```typescript
|
|
186
|
-
|
|
297
|
+
// 成功
|
|
298
|
+
{
|
|
299
|
+
success: true
|
|
300
|
+
}
|
|
187
301
|
|
|
188
|
-
//
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
302
|
+
// 错误
|
|
303
|
+
{
|
|
304
|
+
message: string;
|
|
305
|
+
error: { name?: string; message: string }
|
|
306
|
+
}
|
|
307
|
+
```
|
|
192
308
|
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
//
|
|
309
|
+
**使用示例:**
|
|
310
|
+
```typescript
|
|
311
|
+
// 注册中间件
|
|
312
|
+
createCollectLogsMiddleware({
|
|
313
|
+
logDir: './logs', // 可选,默认为 'logs'
|
|
314
|
+
fileName: 'client.log', // 可选,默认为 'client.log'
|
|
315
|
+
})
|
|
196
316
|
|
|
197
|
-
|
|
198
|
-
|
|
317
|
+
// 客户端使用示例
|
|
318
|
+
fetch('/dev/logs/collect', {
|
|
319
|
+
method: 'POST',
|
|
320
|
+
headers: { 'Content-Type': 'application/json' },
|
|
321
|
+
body: JSON.stringify({
|
|
322
|
+
level: 'error',
|
|
323
|
+
message: 'Something went wrong',
|
|
324
|
+
time: new Date().toISOString(),
|
|
325
|
+
source: 'frontend',
|
|
326
|
+
user_id: 'user123',
|
|
327
|
+
tenant_id: 'tenant456',
|
|
328
|
+
app_id: 'app789'
|
|
329
|
+
})
|
|
330
|
+
});
|
|
199
331
|
```
|
|
200
332
|
|
|
201
|
-
|
|
333
|
+
**日志文件格式:**
|
|
334
|
+
日志以 JSON Lines 格式存储(每行一个 JSON 对象):
|
|
335
|
+
```
|
|
336
|
+
{"level":"error","message":"Something went wrong","time":"2025-10-23T10:30:00.000Z","source":"frontend","user_id":"user123","tenant_id":"tenant456","app_id":"app789"}
|
|
337
|
+
{"level":"info","message":"User logged in","time":"2025-10-23T10:31:00.000Z","user_id":"user123","tenant_id":"tenant456","app_id":"app789"}
|
|
338
|
+
```
|
|
202
339
|
|
|
203
|
-
```typescript
|
|
204
|
-
import { normalizeBasePath } from '@apaas/fullstack-toolkits';
|
|
205
340
|
|
|
206
|
-
|
|
207
|
-
normalizeBasePath('api'); // '/api'
|
|
208
|
-
normalizeBasePath('/api/'); // '/api'
|
|
209
|
-
normalizeBasePath('api/v1'); // '/api/v1'
|
|
210
|
-
```
|
|
341
|
+
### OpenAPI 中间件
|
|
211
342
|
|
|
212
|
-
|
|
343
|
+
提供带源代码引用的增强版 OpenAPI/Swagger 文档。
|
|
213
344
|
|
|
214
|
-
|
|
345
|
+
**功能特性:**
|
|
346
|
+
- 自动为 OpenAPI 路径添加控制器源代码位置
|
|
347
|
+
- 为每个端点添加文件路径和行号
|
|
348
|
+
- 根据上下文转换路径以包含 basePath
|
|
349
|
+
- 内置缓存以提升性能
|
|
350
|
+
- 支持静态和动态 OpenAPI 规范
|
|
215
351
|
|
|
216
|
-
|
|
217
|
-
|
|
352
|
+
**路由:**
|
|
353
|
+
- `GET /dev/openapi.json` - 获取增强版 OpenAPI 规范
|
|
218
354
|
|
|
355
|
+
**响应结构:**
|
|
219
356
|
```typescript
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
357
|
+
{
|
|
358
|
+
openapi: "3.0.0",
|
|
359
|
+
info: { /* OpenAPI 信息 */ },
|
|
360
|
+
paths: {
|
|
361
|
+
"/api/users": {
|
|
362
|
+
get: {
|
|
363
|
+
// ... 原始 OpenAPI 定义
|
|
364
|
+
"x-source": {
|
|
365
|
+
file: "src/controllers/user.controller.ts",
|
|
366
|
+
line: 42,
|
|
367
|
+
method: "getUsers",
|
|
368
|
+
controllerPath: "/users",
|
|
369
|
+
routePath: "/api/users"
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
}
|
|
226
374
|
}
|
|
227
375
|
```
|
|
228
376
|
|
|
229
|
-
|
|
377
|
+
**使用示例:**
|
|
230
378
|
```typescript
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
379
|
+
// 注册中间件
|
|
380
|
+
createOpenapiMiddleware({
|
|
381
|
+
openapiFilePath: './openapi.json', // 必需 - OpenAPI 文件路径
|
|
382
|
+
enableEnhancement: true, // 可选 - 启用源码信息(默认:true)
|
|
383
|
+
serverDir: './src', // 可选 - 服务端目录用于扫描(默认为 context.rootDir)
|
|
384
|
+
})
|
|
385
|
+
|
|
386
|
+
// 客户端使用
|
|
387
|
+
fetch('/dev/openapi.json')
|
|
388
|
+
.then(res => res.json())
|
|
389
|
+
.then(spec => {
|
|
390
|
+
// 使用增强后的 OpenAPI 规范
|
|
391
|
+
console.log(spec.paths);
|
|
392
|
+
|
|
393
|
+
// 访问源代码信息
|
|
394
|
+
const getUsersSource = spec.paths['/api/users'].get['x-source'];
|
|
395
|
+
console.log(`端点定义在 ${getUsersSource.file}:${getUsersSource.line}`);
|
|
396
|
+
});
|
|
238
397
|
```
|
|
239
398
|
|
|
240
|
-
|
|
241
|
-
|
|
399
|
+
**增强详情:**
|
|
400
|
+
|
|
401
|
+
中间件会扫描服务端代码库中的 NestJS 控制器,并为每个端点添加 `x-source` 元数据:
|
|
402
|
+
- `file` - 控制器文件的相对路径
|
|
403
|
+
- `line` - 定义端点处理器的行号
|
|
404
|
+
- `method` - 处理器方法名
|
|
405
|
+
- `controllerPath` - 来自 `@Controller()` 装饰器的基础路径
|
|
406
|
+
- `routePath` - 包含 basePath 的完整路径
|
|
407
|
+
|
|
408
|
+
**缓存机制:**
|
|
409
|
+
增强后的 OpenAPI 规范基于文件哈希进行缓存。当源 OpenAPI 文件发生变化时,缓存会自动失效。
|
|
410
|
+
|
|
411
|
+
### 工具函数
|
|
242
412
|
|
|
413
|
+
#### Drizzle Schema 后处理
|
|
414
|
+
|
|
415
|
+
自动优化 Drizzle Kit 生成的 PostgreSQL schema 文件,解决常见的代码质量问题。
|
|
416
|
+
|
|
417
|
+
**主要功能:**
|
|
418
|
+
- **中文表名处理** - 自动将中文表名转换为拼音标识符(如:用户表 → yonghu_biao)
|
|
419
|
+
- **自定义类型替换** - 将 `unknown()` 类型自动替换为 `userProfile()` 或 `fileAttachment()`
|
|
420
|
+
- **系统字段注释** - 为 `_created_at`、`_created_by`、`_updated_at`、`_updated_by` 添加注释
|
|
421
|
+
- **Schema 转换** - 移除 `pgSchema` 声明,将 `schema.table()` 转换为 `pgTable()`
|
|
422
|
+
- **Import 优化** - 自动添加缺失的导入,移除未使用的导入
|
|
423
|
+
- **代码格式化** - 统一换行符、合并多余空行、添加文件头注释
|
|
424
|
+
|
|
425
|
+
**使用示例:**
|
|
243
426
|
```typescript
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
427
|
+
import { postprocessDrizzleSchema } from '@apaas/fullstack-toolkits';
|
|
428
|
+
|
|
429
|
+
// 在 Drizzle Kit generate 之后调用
|
|
430
|
+
const stats = postprocessDrizzleSchema('./src/db/schema.ts');
|
|
431
|
+
|
|
432
|
+
if (stats) {
|
|
433
|
+
console.log(`处理完成:`);
|
|
434
|
+
console.log(`- 替换了 ${stats.replacedUnknown} 个未知类型`);
|
|
435
|
+
console.log(`- 未匹配的自定义类型: ${stats.unmatchedUnknown.length}`);
|
|
249
436
|
}
|
|
250
437
|
```
|
|
251
438
|
|
|
252
|
-
|
|
253
|
-
```
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
next();
|
|
260
|
-
}
|
|
261
|
-
};
|
|
439
|
+
**配合 Drizzle Kit 使用:**
|
|
440
|
+
```json
|
|
441
|
+
// package.json
|
|
442
|
+
{
|
|
443
|
+
"scripts": {
|
|
444
|
+
"db:generate": "drizzle-kit generate && node -e \"require('@apaas/fullstack-toolkits').postprocessDrizzleSchema('./src/db/schema.ts')\""
|
|
445
|
+
}
|
|
262
446
|
}
|
|
263
447
|
```
|
|
264
448
|
|
|
265
|
-
|
|
266
|
-
Union type of route-based and global middlewares.
|
|
267
|
-
|
|
449
|
+
**处理前后对比:**
|
|
268
450
|
```typescript
|
|
269
|
-
|
|
270
|
-
|
|
451
|
+
// 处理前
|
|
452
|
+
export const 用户表 = workspace_xxx.table("user_table", {
|
|
453
|
+
// TODO: failed to parse database type 'user_profile'
|
|
454
|
+
profile: unknown("profile"),
|
|
455
|
+
_created_at: timestamp("_created_at"),
|
|
456
|
+
});
|
|
271
457
|
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
isDev: boolean;
|
|
277
|
-
rootDir: string;
|
|
278
|
-
[key: string]: any;
|
|
279
|
-
}
|
|
280
|
-
```
|
|
458
|
+
// 处理后
|
|
459
|
+
/** auto generated, do not edit */
|
|
460
|
+
import { pgTable, timestamp } from "drizzle-orm/pg-core"
|
|
461
|
+
import { userProfile } from "./types"
|
|
281
462
|
|
|
282
|
-
|
|
463
|
+
export const yonghu_biao = pgTable("user_table", {
|
|
464
|
+
profile: userProfile("profile"),
|
|
465
|
+
// System field: Creation time (auto-filled, do not modify)
|
|
466
|
+
_created_at: timestamp("_created_at"),
|
|
467
|
+
});
|
|
468
|
+
```
|
|
283
469
|
|
|
284
|
-
####
|
|
285
|
-
Register middlewares for Express-compatible servers or Vite dev server.
|
|
470
|
+
#### 路径匹配
|
|
286
471
|
|
|
287
|
-
|
|
288
|
-
- `server` - Express app or Vite middleware instance
|
|
289
|
-
- `middlewares` - Array of middleware objects (route or global)
|
|
290
|
-
- `options` - Optional context configuration
|
|
472
|
+
强大的路径模式匹配功能,适用于 OpenAPI/Swagger/NestJS 路由。
|
|
291
473
|
|
|
292
|
-
|
|
474
|
+
**支持的模式:**
|
|
475
|
+
- 精确匹配:`/api/users` === `/api/users`
|
|
476
|
+
- 路径参数:`/api/users/{id}` 匹配 `/api/users/123`
|
|
477
|
+
- 单层通配符:`/api/*/users` 匹配 `/api/v1/users`
|
|
478
|
+
- 递归通配符:`/files/**` 匹配 `/files/a/b/c`
|
|
479
|
+
- 前缀匹配:`/api/users` 匹配 `/api/users/123`
|
|
293
480
|
|
|
294
|
-
|
|
481
|
+
**使用示例:**
|
|
295
482
|
```typescript
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
});
|
|
483
|
+
import { matchesPathPattern, extractPathParams } from '@apaas/fullstack-toolkits';
|
|
484
|
+
|
|
485
|
+
// 匹配路径模式
|
|
486
|
+
matchesPathPattern('/api/users/123', '/api/users/{id}'); // true
|
|
487
|
+
matchesPathPattern('/api/v1/users', '/api/*/users'); // true
|
|
488
|
+
|
|
489
|
+
// 提取路径参数
|
|
490
|
+
extractPathParams('/api/users/123', '/api/users/{id}');
|
|
491
|
+
// 返回:{ id: '123' }
|
|
492
|
+
|
|
493
|
+
extractPathParams('/api/users/123/posts/456', '/api/users/{userId}/posts/{postId}');
|
|
494
|
+
// 返回:{ userId: '123', postId: '456' }
|
|
304
495
|
```
|
|
305
496
|
|
|
306
|
-
|
|
497
|
+
#### 路径规范化
|
|
307
498
|
|
|
308
|
-
|
|
309
|
-
|
|
499
|
+
```typescript
|
|
500
|
+
import { normalizeBasePath } from '@apaas/fullstack-toolkits';
|
|
501
|
+
|
|
502
|
+
// 规范化基础路径(添加前导斜杠,移除尾部斜杠)
|
|
503
|
+
normalizeBasePath('api'); // '/api'
|
|
504
|
+
normalizeBasePath('/api/'); // '/api'
|
|
505
|
+
normalizeBasePath('api/v1'); // '/api/v1'
|
|
506
|
+
```
|
|
310
507
|
|
|
311
|
-
##
|
|
508
|
+
## 许可证
|
|
312
509
|
|
|
313
510
|
MIT
|
|
511
|
+
|