FullStack Devtool Kits
面向 NestJS 全栈项目的综合工具包,提供开箱即用的开发中间件、工具函数和辅助功能,帮助您快速搭建高效的开发环境。
本 SDK 导出三大核心模块,让您可以快速集成到项目中:
``bash`
npm install @apaas/fullstack-toolkits或
yarn add @apaas/fullstack-toolkits
只需三步,即可为您的项目添加强大的开发工具:
`typescript
import {
registerMiddlewares,
createDevLogsMiddleware,
createCollectLogsMiddleware,
createOpenapiMiddleware
} from '@apaas/fullstack-toolkits';
// 在 rspack/webpack 或 Vite 开发服务器中注册
registerMiddlewares(devServer.app, [
createDevLogsMiddleware({ logDir: './logs' }),
createCollectLogsMiddleware({ logDir: './logs' }),
createOpenapiMiddleware({ openapiFilePath: './openapi.json' }),
], {
basePath: '/api',
isDev: true,
rootDir: __dirname
});
`
完成!现在您可以:
- 📊 访问 GET /api/dev/logs/trace/recent 查看最近的 API 调用POST /api/dev/logs/collect
- 📝 通过 收集客户端日志GET /api/dev/openapi.json
- 📚 访问 获取增强的 API 文档
typescript
import {
createDevLogsMiddleware, // 日志查询中间件
createCollectLogsMiddleware, // 日志收集中间件
createOpenapiMiddleware, // OpenAPI 增强中间件
} from '@apaas/fullstack-toolkits';
`$3
`typescript
import {
matchesPathPattern, // 路径模式匹配
extractPathParams, // 提取路径参数
normalizeBasePath, // 路径规范化
} from '@apaas/fullstack-toolkits';
`$3
`typescript
import {
registerMiddlewares, // 统一注册中间件
postprocessDrizzleSchema, // 后处理 Drizzle Schema 文件
handleDevProxyError, // HTTP 代理错误处理器
} from '@apaas/fullstack-toolkits';
`$3
`typescript
import {
sendJson, // 发送 JSON 响应(兼容 Express/Connect)
sendError, // 发送错误响应
sendSuccess, // 发送成功响应
getQuery, // 获取所有查询参数
getQueryParam, // 获取单个查询参数
} from '@apaas/fullstack-toolkits';
`$3
`typescript
import type {
Middleware, // 中间件联合类型
RouteMiddleware, // 路由中间件类型
GlobalMiddleware, // 全局中间件类型
MiddlewareContext, // 中间件上下文类型
} from '@apaas/fullstack-toolkits';
`详细使用
$3
工具包支持两种类型的中间件:
- 路由中间件:挂载到特定路径(例如
/dev/logs、/dev/openapi.json)
- 全局中间件:应用于所有请求,无需挂载路径用于 Rspack / Webpack 开发服务器:
`typescript
import {
registerMiddlewares,
createDevLogsMiddleware,
createOpenapiMiddleware
} from '@apaas/fullstack-toolkits';export default {
devServer: {
setupMiddlewares: (middlewares, devServer) => {
if (devServer.app) {
registerMiddlewares(devServer.app, [
createDevLogsMiddleware({ logDir: './logs' }),
createOpenapiMiddleware({
openapiFilePath: './openapi.json',
enableEnhancement: true
}),
], {
basePath: '/api',
isDev: true,
rootDir: __dirname
});
}
return middlewares;
}
}
}
`用于 Vite 开发服务器:
`typescript
export default {
plugins: [
{
name: 'dev-middlewares',
configureServer: (server) => {
registerMiddlewares(server.middlewares, [
createDevLogsMiddleware({ logDir: './logs' }),
createOpenapiMiddleware({
openapiFilePath: './openapi.json',
enableEnhancement: true
}),
], {
basePath: '/',
isDev: true,
rootDir: __dirname
});
}
}
]
}
`重要提示:
- 中间件执行顺序与数组顺序一致
- 全局中间件应放在路由中间件之前
- 路由中间件仅处理匹配其挂载路径的请求
$3
本工具包原生支持 Vite 开发服务器。
registerMiddlewares 会自动检测 Vite/Connect 环境,并添加必要的 Express API 兼容层:-
res.status() - 设置响应状态码
- res.json() - 发送 JSON 响应
- res.send() - 发送响应
- req.query - 解析后的查询参数这意味着您可以直接在 Vite 中使用本工具包,无需额外配置。
兼容工具函数(可选):
如果您正在编写自定义中间件并希望同时支持 Express 和 Vite,可以使用导出的兼容工具函数:
`typescript
import { sendJson, sendError, sendSuccess, getQuery, getQueryParam } from '@lark-apaas/devtool-kits';// 发送 JSON 响应(自动检测 Express/Connect)
sendJson(res, { data: 'value' }, 200);
// 发送错误响应
sendError(res, 'Not found', error, 404);
// 发送成功响应
sendSuccess(res, { id: 123 });
// 获取查询参数(自动解析 URL 或使用 req.query)
const query = getQuery(req);
const page = getQueryParam(req, 'page');
`中间件详细说明
$3
查看和查询带 Trace ID 支持的应用日志。
功能特性:
- 根据 Trace ID 查询日志条目
- 分页浏览最近的追踪调用
- 按 API 路径模式和 HTTP 方法过滤日志
- 支持 OpenAPI/Swagger 路径模式
- 分页读取日志文件
路由:
-
GET /dev/logs/app/trace/:traceId - 根据 Trace ID 获取日志条目
- GET /dev/logs/trace/recent - 获取最近的追踪调用(支持分页和过滤)
- GET /dev/logs/files/:fileName - 分页获取日志文件内容查询参数:
用于
/app/trace/:traceId:
- limit - 返回条目的最大数量(默认:200,最大:1000)用于
/trace/recent:
- page - 页码(默认:1)
- pageSize - 每页条目数(默认:10,最大:100)
- path - 按 API 路径模式过滤(支持通配符)
- method - 按 HTTP 方法过滤(GET、POST 等)用于
/files/:fileName:
- page - 页码(默认:1)
- pageSize - 每页行数(默认:200,最大:2000)响应示例:
`typescript
// GET /dev/logs/app/trace/abc123?limit=100
{
file: "logs/app.log",
traceId: "abc123",
count: 5,
entries: [
{ / 日志条目 1 / },
{ / 日志条目 2 / }
]
}// GET /dev/logs/trace/recent?page=1&pageSize=10&path=/api/users/*&method=POST
{
file: "logs/trace.log",
page: 1,
pageSize: 10,
total: 150,
totalPages: 15,
path: "/api/users/*",
method: "POST",
count: 10,
calls: [
{ / 追踪调用 1 / },
{ / 追踪调用 2 / }
]
}
// GET /dev/logs/files/app.log?page=1&pageSize=200
{
file: "logs/app.log",
page: 1,
pageSize: 200,
total: 5000,
totalPages: 25,
lines: [
"日志行 1",
"日志行 2"
]
}
`使用示例:
`typescript
// 注册中间件
createDevLogsMiddleware({
logDir: './logs', // 可选,默认为 'logs' 或 context.logDir
})// 客户端使用示例
// 获取指定 Trace ID 的日志
fetch('/dev/logs/app/trace/abc123?limit=100')
.then(res => res.json())
.then(data => console.log(data.entries));
// 按路径和方法过滤获取最近的 API 调用
fetch('/dev/logs/trace/recent?page=1&pageSize=20&path=/api/users/*&method=POST')
.then(res => res.json())
.then(data => console.log(data.calls));
// 分页读取日志文件
fetch('/dev/logs/files/app.log?page=1&pageSize=200')
.then(res => res.json())
.then(data => console.log(data.lines));
`
$3
从客户端收集日志并存储到日志文件中。
功能特性:
- 通过 HTTP POST 收集客户端日志
- 以 JSON Lines 格式存储日志
- 自动创建日志目录
- 可自定义日志文件名
路由:
-
POST /dev/logs/collect - 从客户端收集日志请求体:
`typescript
{
level: string; // 日志级别(info、warn、error 等)
message: string; // 日志消息
time: string; // ISO 时间戳字符串
source?: string; // 可选的日志来源标识
user_id: string; // 用户 ID
tenant_id: string; // 租户 ID
app_id: string; // 应用 ID
}
`响应:
`typescript
// 成功
{
success: true
}// 错误
{
message: string;
error: { name?: string; message: string }
}
`使用示例:
`typescript
// 注册中间件
createCollectLogsMiddleware({
logDir: './logs', // 可选,默认为 'logs'
fileName: 'client.log', // 可选,默认为 'client.log'
})// 客户端使用示例
fetch('/dev/logs/collect', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
level: 'error',
message: 'Something went wrong',
time: new Date().toISOString(),
source: 'frontend',
user_id: 'user123',
tenant_id: 'tenant456',
app_id: 'app789'
})
});
`日志文件格式:
日志以 JSON Lines 格式存储(每行一个 JSON 对象):
`
{"level":"error","message":"Something went wrong","time":"2025-10-23T10:30:00.000Z","source":"frontend","user_id":"user123","tenant_id":"tenant456","app_id":"app789"}
{"level":"info","message":"User logged in","time":"2025-10-23T10:31:00.000Z","user_id":"user123","tenant_id":"tenant456","app_id":"app789"}
`
$3
提供带源代码引用的增强版 OpenAPI/Swagger 文档。
功能特性:
- 自动为 OpenAPI 路径添加控制器源代码位置
- 为每个端点添加文件路径和行号
- 根据上下文转换路径以包含 basePath
- 内置缓存以提升性能
- 支持静态和动态 OpenAPI 规范
路由:
-
GET /dev/openapi.json - 获取增强版 OpenAPI 规范响应结构:
`typescript
{
openapi: "3.0.0",
info: { / OpenAPI 信息 / },
paths: {
"/api/users": {
get: {
// ... 原始 OpenAPI 定义
"x-source": {
file: "src/controllers/user.controller.ts",
line: 42,
method: "getUsers",
controllerPath: "/users",
routePath: "/api/users"
}
}
}
}
}
`使用示例:
`typescript
// 注册中间件
createOpenapiMiddleware({
openapiFilePath: './openapi.json', // 必需 - OpenAPI 文件路径
enableEnhancement: true, // 可选 - 启用源码信息(默认:true)
serverDir: './src', // 可选 - 服务端目录用于扫描(默认为 context.rootDir)
})// 客户端使用
fetch('/dev/openapi.json')
.then(res => res.json())
.then(spec => {
// 使用增强后的 OpenAPI 规范
console.log(spec.paths);
// 访问源代码信息
const getUsersSource = spec.paths['/api/users'].get['x-source'];
console.log(
端点定义在 ${getUsersSource.file}:${getUsersSource.line});
});
`增强详情:
中间件会扫描服务端代码库中的 NestJS 控制器,并为每个端点添加
x-source 元数据:
- file - 控制器文件的相对路径
- line - 定义端点处理器的行号
- method - 处理器方法名
- controllerPath - 来自 @Controller() 装饰器的基础路径
- routePath - 包含 basePath 的完整路径缓存机制:
增强后的 OpenAPI 规范基于文件哈希进行缓存。当源 OpenAPI 文件发生变化时,缓存会自动失效。
$3
#### Drizzle Schema 后处理
自动优化 Drizzle Kit 生成的 PostgreSQL schema 文件,解决常见的代码质量问题。
主要功能:
- 中文表名处理 - 自动将中文表名转换为拼音标识符(如:用户表 → yonghu_biao)
- 自定义类型替换 - 将
unknown() 类型自动替换为 userProfile() 或 fileAttachment()
- 系统字段注释 - 为 _created_at、_created_by、_updated_at、_updated_by 添加注释
- Schema 转换 - 移除 pgSchema 声明,将 schema.table() 转换为 pgTable()
- Import 优化 - 自动添加缺失的导入,移除未使用的导入
- 代码格式化 - 统一换行符、合并多余空行、添加文件头注释使用示例:
`typescript
import { postprocessDrizzleSchema } from '@apaas/fullstack-toolkits';// 在 Drizzle Kit generate 之后调用
const stats = postprocessDrizzleSchema('./src/db/schema.ts');
if (stats) {
console.log(
处理完成:);
console.log(- 替换了 ${stats.replacedUnknown} 个未知类型);
console.log(- 未匹配的自定义类型: ${stats.unmatchedUnknown.length});
}
`配合 Drizzle Kit 使用:
`json
// package.json
{
"scripts": {
"db:generate": "drizzle-kit generate && node -e \"require('@apaas/fullstack-toolkits').postprocessDrizzleSchema('./src/db/schema.ts')\""
}
}
`处理前后对比:
`typescript
// 处理前
export const 用户表 = workspace_xxx.table("user_table", {
// TODO: failed to parse database type 'user_profile'
profile: unknown("profile"),
_created_at: timestamp("_created_at"),
});// 处理后
/* auto generated, do not edit /
import { pgTable, timestamp } from "drizzle-orm/pg-core"
import { userProfile } from "./types"
export const yonghu_biao = pgTable("user_table", {
profile: userProfile("profile"),
// System field: Creation time (auto-filled, do not modify)
_created_at: timestamp("_created_at"),
});
`#### 路径匹配
强大的路径模式匹配功能,适用于 OpenAPI/Swagger/NestJS 路由。
支持的模式:
- 精确匹配:
/api/users === /api/users
- 路径参数:/api/users/{id} 匹配 /api/users/123
- 单层通配符:/api/*/users 匹配 /api/v1/users
- 递归通配符:/files/** 匹配 /files/a/b/c
- 前缀匹配:/api/users 匹配 /api/users/123使用示例:
`typescript
import { matchesPathPattern, extractPathParams } from '@apaas/fullstack-toolkits';// 匹配路径模式
matchesPathPattern('/api/users/123', '/api/users/{id}'); // true
matchesPathPattern('/api/v1/users', '/api/*/users'); // true
// 提取路径参数
extractPathParams('/api/users/123', '/api/users/{id}');
// 返回:{ id: '123' }
extractPathParams('/api/users/123/posts/456', '/api/users/{userId}/posts/{postId}');
// 返回:{ userId: '123', postId: '456' }
`#### 路径规范化
`typescript
import { normalizeBasePath } from '@apaas/fullstack-toolkits';// 规范化基础路径(添加前导斜杠,移除尾部斜杠)
normalizeBasePath('api'); // '/api'
normalizeBasePath('/api/'); // '/api'
normalizeBasePath('api/v1'); // '/api/v1'
``MIT