@lark-apaas/devtool-kits
v1.2.18
Published
FullStack Devtool Kits
Readme
Fullstack Toolkits
面向 NestJS 全栈项目的综合工具包,提供开箱即用的开发中间件、工具函数和辅助功能,帮助您快速搭建高效的开发环境。
功能特性
本 SDK 导出三大核心模块,让您可以快速集成到项目中:
📦 开箱即用的中间件 (Middlewares)
- Dev Logs 中间件 - 查看和查询应用日志,支持 Trace ID 追踪和路径过滤
- Collect Logs 中间件 - 收集客户端日志并自动存储到文件
- OpenAPI 中间件 - 增强 OpenAPI 文档,自动添加源代码引用信息
🛠️ 实用工具函数 (Utils)
- 路径规范化 - 自动处理路径格式,确保一致性
🔌 通用脚本 (Helpers)
- Drizzle Schema 后处理 - 自动优化 Drizzle Kit 生成的 schema 文件
- 中文表名转拼音标识符
- 自动替换自定义类型(user_profile、file_attachment)
- 添加系统字段注释(_created_at、_updated_at 等)
- 优化 import 语句和代码格式
- Proxy Error Handler - HTTP 代理错误处理器
- 显示友好的错误页面
- 自动读取并展示服务端错误日志
- 智能提取编译/启动错误信息
- 支持一键复制和修复建议
安装
npm install @apaas/fullstack-toolkits
# 或
yarn add @apaas/fullstack-toolkits快速开始
只需三步,即可为您的项目添加强大的开发工具:
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 文档
导出内容
中间件 (Middlewares)
import {
createDevLogsMiddleware, // 日志查询中间件
createCollectLogsMiddleware, // 日志收集中间件
createOpenapiMiddleware, // OpenAPI 增强中间件
} from '@apaas/fullstack-toolkits';工具函数 (Utils)
import {
matchesPathPattern, // 路径模式匹配
extractPathParams, // 提取路径参数
normalizeBasePath, // 路径规范化
} from '@apaas/fullstack-toolkits';辅助函数 (Helpers)
import {
registerMiddlewares, // 统一注册中间件
postprocessDrizzleSchema, // 后处理 Drizzle Schema 文件
handleDevProxyError, // HTTP 代理错误处理器
} from '@apaas/fullstack-toolkits';兼容工具函数 (Compat)
import {
sendJson, // 发送 JSON 响应(兼容 Express/Connect)
sendError, // 发送错误响应
sendSuccess, // 发送成功响应
getQuery, // 获取所有查询参数
getQueryParam, // 获取单个查询参数
} from '@apaas/fullstack-toolkits';类型定义 (Types)
import type {
Middleware, // 中间件联合类型
RouteMiddleware, // 路由中间件类型
GlobalMiddleware, // 全局中间件类型
MiddlewareContext, // 中间件上下文类型
} from '@apaas/fullstack-toolkits';详细使用
在不同开发服务器中集成
工具包支持两种类型的中间件:
- 路由中间件:挂载到特定路径(例如
/dev/logs、/dev/openapi.json) - 全局中间件:应用于所有请求,无需挂载路径
用于 Rspack / Webpack 开发服务器:
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 开发服务器:
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
});
}
}
]
}重要提示:
- 中间件执行顺序与数组顺序一致
- 全局中间件应放在路由中间件之前
- 路由中间件仅处理匹配其挂载路径的请求
Vite/Connect 兼容性
本工具包原生支持 Vite 开发服务器。registerMiddlewares 会自动检测 Vite/Connect 环境,并添加必要的 Express API 兼容层:
res.status()- 设置响应状态码res.json()- 发送 JSON 响应res.send()- 发送响应req.query- 解析后的查询参数
这意味着您可以直接在 Vite 中使用本工具包,无需额外配置。
兼容工具函数(可选):
如果您正在编写自定义中间件并希望同时支持 Express 和 Vite,可以使用导出的兼容工具函数:
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');中间件详细说明
Dev Logs 中间件
查看和查询带 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)
响应示例:
// 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"
]
}使用示例:
// 注册中间件
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));Collect Logs 中间件
从客户端收集日志并存储到日志文件中。
功能特性:
- 通过 HTTP POST 收集客户端日志
- 以 JSON Lines 格式存储日志
- 自动创建日志目录
- 可自定义日志文件名
路由:
POST /dev/logs/collect- 从客户端收集日志
请求体:
{
level: string; // 日志级别(info、warn、error 等)
message: string; // 日志消息
time: string; // ISO 时间戳字符串
source?: string; // 可选的日志来源标识
user_id: string; // 用户 ID
tenant_id: string; // 租户 ID
app_id: string; // 应用 ID
}响应:
// 成功
{
success: true
}
// 错误
{
message: string;
error: { name?: string; message: string }
}使用示例:
// 注册中间件
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"}OpenAPI 中间件
提供带源代码引用的增强版 OpenAPI/Swagger 文档。
功能特性:
- 自动为 OpenAPI 路径添加控制器源代码位置
- 为每个端点添加文件路径和行号
- 根据上下文转换路径以包含 basePath
- 内置缓存以提升性能
- 支持静态和动态 OpenAPI 规范
路由:
GET /dev/openapi.json- 获取增强版 OpenAPI 规范
响应结构:
{
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"
}
}
}
}
}使用示例:
// 注册中间件
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 文件发生变化时,缓存会自动失效。
工具函数
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 优化 - 自动添加缺失的导入,移除未使用的导入
- 代码格式化 - 统一换行符、合并多余空行、添加文件头注释
使用示例:
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 使用:
// package.json
{
"scripts": {
"db:generate": "drizzle-kit generate && node -e \"require('@apaas/fullstack-toolkits').postprocessDrizzleSchema('./src/db/schema.ts')\""
}
}处理前后对比:
// 处理前
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
使用示例:
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' }路径规范化
import { normalizeBasePath } from '@apaas/fullstack-toolkits';
// 规范化基础路径(添加前导斜杠,移除尾部斜杠)
normalizeBasePath('api'); // '/api'
normalizeBasePath('/api/'); // '/api'
normalizeBasePath('api/v1'); // '/api/v1'许可证
MIT
