create-hest-app 0.1.6 → 0.1.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/package.json +1 -1
- package/templates/base/bun.lock +683 -0
- package/templates/base/package.json +2 -2
- package/templates/base/src/app.controller.ts +17 -13
- package/templates/base/src/common/middleware/index.ts +66 -0
- package/templates/base/src/index.ts +18 -19
- package/templates/base_scalar/bun.lock +1194 -0
- package/templates/base_scalar/package.json +3 -3
- package/templates/base_scalar/src/app.controller.ts +4 -2
- package/templates/base_scalar/src/common/middleware/index.ts +68 -0
- package/templates/base_scalar/src/index.ts +12 -13
- package/templates/cqrs/package.json +2 -2
- package/templates/cqrs/src/common/middleware/index.ts +73 -0
- package/templates/cqrs/src/index.ts +10 -13
- package/templates/cqrs_scalar/package.json +3 -3
- package/templates/cqrs_scalar/src/common/middleware/index.ts +59 -0
- package/templates/cqrs_scalar/src/index.ts +10 -13
- package/templates/base/src/common/filters/http-exception.filter.ts +0 -34
- package/templates/base/src/common/interceptors/response.interceptor.ts +0 -38
- package/templates/base_scalar/src/common/filters/http-exception.filter.ts +0 -34
- package/templates/base_scalar/src/common/interceptors/response.interceptor.ts +0 -38
- package/templates/cqrs/src/common/filters/http-exception.filter.ts +0 -34
- package/templates/cqrs/src/common/interceptors/response.interceptor.ts +0 -38
- package/templates/cqrs_scalar/src/common/filters/http-exception.filter.ts +0 -34
- package/templates/cqrs_scalar/src/common/interceptors/response.interceptor.ts +0 -37
@@ -30,10 +30,10 @@
|
|
30
30
|
"author": "aqz236",
|
31
31
|
"license": "MIT",
|
32
32
|
"dependencies": {
|
33
|
-
"@hestjs/core": "^0.
|
33
|
+
"@hestjs/core": "^0.2.0",
|
34
34
|
"@hestjs/logger": "^0.1.5",
|
35
35
|
"@hestjs/validation": "^0.1.5",
|
36
|
-
"hono": "^4.8.
|
36
|
+
"hono": "^4.8.10",
|
37
37
|
"reflect-metadata": "^0.2.2"
|
38
38
|
},
|
39
39
|
"devDependencies": {
|
@@ -1,39 +1,43 @@
|
|
1
|
-
import { Controller, Get,
|
1
|
+
import { Controller, Get, Param, Post } from '@hestjs/core';
|
2
2
|
|
3
|
-
import { Body } from
|
4
|
-
import { AppService } from
|
5
|
-
import { CreateUserDto } from
|
3
|
+
import { Body } from '@hestjs/validation';
|
4
|
+
import { AppService } from './app.service';
|
5
|
+
import { CreateUserDto } from './modules/users/dto/user.dto';
|
6
6
|
|
7
|
-
@Controller(
|
7
|
+
@Controller('/api')
|
8
8
|
export class AppController {
|
9
9
|
constructor(private readonly appService: AppService) {}
|
10
10
|
|
11
|
-
@Get(
|
11
|
+
@Get('/')
|
12
12
|
getHello() {
|
13
13
|
return { message: this.appService.getHello() };
|
14
14
|
}
|
15
15
|
|
16
|
-
@Get(
|
16
|
+
@Get('/users')
|
17
17
|
getUsers() {
|
18
18
|
return this.appService.getUsers();
|
19
19
|
}
|
20
20
|
|
21
|
-
@Get(
|
22
|
-
getUser(@Param(
|
21
|
+
@Get('/users/:id')
|
22
|
+
getUser(@Param('id') id: string) {
|
23
23
|
const user = this.appService.getUser(id);
|
24
24
|
if (!user) {
|
25
|
-
|
25
|
+
const error = new Error(`User with id ${id} not found`) as Error & {
|
26
|
+
status: number;
|
27
|
+
};
|
28
|
+
error.status = 404;
|
29
|
+
throw error;
|
26
30
|
}
|
27
31
|
return user;
|
28
32
|
}
|
29
33
|
|
30
|
-
@Post(
|
34
|
+
@Post('/users')
|
31
35
|
createUser(@Body(CreateUserDto) createUserDto: CreateUserDto) {
|
32
36
|
return this.appService.createUser(createUserDto);
|
33
37
|
}
|
34
38
|
|
35
|
-
@Get(
|
39
|
+
@Get('/error')
|
36
40
|
throwError() {
|
37
|
-
throw new Error(
|
41
|
+
throw new Error('This is a test error');
|
38
42
|
}
|
39
43
|
}
|
@@ -0,0 +1,66 @@
|
|
1
|
+
import type { Context, Next } from 'hono';
|
2
|
+
import { logger } from '@hestjs/logger';
|
3
|
+
|
4
|
+
/**
|
5
|
+
* Hono 异常处理中间件
|
6
|
+
*/
|
7
|
+
export const exceptionMiddleware = async (c: Context, next: Next) => {
|
8
|
+
try {
|
9
|
+
await next();
|
10
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
11
|
+
} catch (error: any) {
|
12
|
+
const status = error.status || 500;
|
13
|
+
const response = {
|
14
|
+
statusCode: status,
|
15
|
+
timestamp: new Date().toISOString(),
|
16
|
+
path: c.req.url,
|
17
|
+
message: error.message || 'Internal Server Error',
|
18
|
+
error: error.error || 'Exception',
|
19
|
+
};
|
20
|
+
|
21
|
+
logger.error(`🔥 HTTP Exception [${status}]: ${error.message}`, {
|
22
|
+
requestUrl: c.req.url,
|
23
|
+
stack: error.stack,
|
24
|
+
});
|
25
|
+
|
26
|
+
return c.json(response, status);
|
27
|
+
}
|
28
|
+
};
|
29
|
+
|
30
|
+
/**
|
31
|
+
* 响应包装中间件
|
32
|
+
*/
|
33
|
+
export const responseMiddleware = async (c: Context, next: Next) => {
|
34
|
+
const start = Date.now();
|
35
|
+
|
36
|
+
await next();
|
37
|
+
|
38
|
+
// 跳过文档相关的路径
|
39
|
+
if (c.req.path === '/openapi.json' || c.req.path === '/docs' || c.req.path.startsWith('/api-docs')) {
|
40
|
+
return;
|
41
|
+
}
|
42
|
+
|
43
|
+
// 只包装JSON响应,且响应状态为2xx
|
44
|
+
const contentType = c.res.headers.get('content-type');
|
45
|
+
if (contentType?.includes('application/json') && c.res.status >= 200 && c.res.status < 300) {
|
46
|
+
try {
|
47
|
+
const duration = Date.now() - start;
|
48
|
+
|
49
|
+
// 克隆响应以避免消耗原始响应体
|
50
|
+
const responseClone = c.res.clone();
|
51
|
+
const originalResponse = await responseClone.json();
|
52
|
+
|
53
|
+
const wrappedResponse = {
|
54
|
+
success: true,
|
55
|
+
data: originalResponse,
|
56
|
+
timestamp: new Date().toISOString(),
|
57
|
+
duration: `${duration}ms`,
|
58
|
+
};
|
59
|
+
|
60
|
+
return c.json(wrappedResponse);
|
61
|
+
} catch (error) {
|
62
|
+
// 如果无法解析JSON,就保持原响应
|
63
|
+
console.warn('Failed to wrap response:', error);
|
64
|
+
}
|
65
|
+
}
|
66
|
+
};
|
@@ -1,33 +1,32 @@
|
|
1
|
-
import { HestFactory } from
|
2
|
-
import { logger } from
|
3
|
-
import {
|
4
|
-
import { cors } from
|
5
|
-
import { AppModule } from
|
6
|
-
import {
|
7
|
-
import { ResponseInterceptor } from "./common/interceptors/response.interceptor";
|
1
|
+
import { HestFactory } from '@hestjs/core';
|
2
|
+
import { logger } from '@hestjs/logger';
|
3
|
+
import { Hono } from 'hono';
|
4
|
+
import { cors } from 'hono/cors';
|
5
|
+
import { AppModule } from './app.module';
|
6
|
+
import { exceptionMiddleware, responseMiddleware } from './common/middleware';
|
8
7
|
|
9
8
|
async function bootstrap() {
|
10
9
|
try {
|
11
|
-
logger.info(
|
10
|
+
logger.info('🚀 Starting HestJS application...');
|
12
11
|
|
13
|
-
|
14
|
-
|
15
|
-
|
12
|
+
// 创建 Hono 实例
|
13
|
+
const hono = new Hono();
|
14
|
+
hono.use(cors()); // 使用 Hono 的 CORS 中间件
|
15
|
+
hono.use('*', exceptionMiddleware); // 异常处理中间件
|
16
|
+
hono.use('*', responseMiddleware); // 响应包装中间件
|
17
|
+
// hono.use('*', log()); // 使用 Hono 的日志中间件
|
16
18
|
|
17
|
-
|
18
|
-
app.useGlobalInterceptors(new ValidationInterceptor());
|
19
|
-
app.useGlobalInterceptors(new ResponseInterceptor());
|
20
|
-
|
21
|
-
// 全局异常过滤器
|
22
|
-
app.useGlobalFilters(new HttpExceptionFilter());
|
19
|
+
await HestFactory.create(hono, AppModule);
|
23
20
|
|
24
21
|
Bun.serve({
|
25
22
|
port: 3002,
|
26
|
-
fetch:
|
23
|
+
fetch: hono.fetch,
|
27
24
|
reusePort: true, // 启用端口复用
|
28
25
|
});
|
26
|
+
|
27
|
+
logger.info(`🎉 Server is running on http://localhost:3002`);
|
29
28
|
} catch (error) {
|
30
|
-
logger.error(
|
29
|
+
logger.error('❌ Failed to start application:', error);
|
31
30
|
process.exit(1);
|
32
31
|
}
|
33
32
|
}
|