create-skweb 2.1.0 → 3.0.3

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.
Files changed (43) hide show
  1. package/{dist/cli.cjs → .rollup.cache/Users/stayknight/projects/skweb-mono/tools/create-skweb/dist/cli.js} +7 -125
  2. package/.rollup.cache/Users/stayknight/projects/skweb-mono/tools/create-skweb/dist/index.js +106 -0
  3. package/.rollup.cache/Users/stayknight/projects/skweb-mono/tools/create-skweb/tsconfig.tsbuildinfo +1 -0
  4. package/.turbo/turbo-build.log +9 -10
  5. package/.turbo/turbo-check.log +5 -4
  6. package/.turbo/turbo-lint.log +12 -4
  7. package/CHANGELOG.md +48 -0
  8. package/dist/cli.d.ts +0 -1
  9. package/dist/cli.js +109 -2
  10. package/dist/cli.js.map +1 -1
  11. package/dist/index.d.ts +0 -1
  12. package/dist/index.js +4 -5
  13. package/dist/index.js.map +1 -1
  14. package/package.json +10 -18
  15. package/rollup.config.mjs +23 -22
  16. package/scripts/inject-shebang.mjs +1 -1
  17. package/src/cli.ts +7 -7
  18. package/src/index.ts +2 -2
  19. package/templates/cjs/package.json +18 -18
  20. package/templates/cjs/src/app.js +16 -11
  21. package/templates/cjs/src/controllers/hello.js +43 -31
  22. package/templates/cjs/src/controllers/user.js +199 -86
  23. package/templates/cjs/src/cronWorker.js +7 -9
  24. package/templates/mjs/package.json +18 -18
  25. package/templates/mjs/src/app.js +8 -10
  26. package/templates/mjs/src/controllers/hello.js +43 -31
  27. package/templates/mjs/src/controllers/user.js +199 -86
  28. package/templates/mjs/src/cronWorker.js +7 -9
  29. package/templates/ts/package.json +24 -24
  30. package/templates/ts/rollup.config.mjs +2 -0
  31. package/templates/ts/src/app.ts +9 -10
  32. package/templates/ts/src/controllers/hello.ts +43 -31
  33. package/templates/ts/src/controllers/user.ts +199 -86
  34. package/templates/ts/src/cronWorker.ts +7 -9
  35. package/templates/ts/tsconfig.json +4 -5
  36. package/test/index.mjs +24 -13
  37. package/tsconfig.json +6 -6
  38. package/tsconfig.tsbuildinfo +1 -0
  39. package/dist/cli.cjs.map +0 -1
  40. package/dist/cli.d.ts.map +0 -1
  41. package/dist/index.cjs +0 -123
  42. package/dist/index.cjs.map +0 -1
  43. package/dist/index.d.ts.map +0 -1
@@ -16,6 +16,21 @@
16
16
  * message: { type: string, example: 'Welcome to SKWeb!' }
17
17
  * version: { type: string, example: '1.0.0' }
18
18
  * timestamp: { type: string, format: date-time }
19
+ */
20
+ const helloIndex = {
21
+ method: 'get',
22
+ path: '/',
23
+ async handler() {
24
+ return {
25
+ message: 'Welcome to SKWeb!',
26
+ version: '1.0.0',
27
+ timestamp: new Date().toISOString()
28
+ }
29
+ }
30
+ }
31
+
32
+ /**
33
+ * @swagger
19
34
  * /health:
20
35
  * get:
21
36
  * summary: 健康检查
@@ -30,6 +45,20 @@
30
45
  * properties:
31
46
  * status: { type: string, example: 'ok' }
32
47
  * timestamp: { type: string, format: date-time }
48
+ */
49
+ const helloHealth = {
50
+ method: 'get',
51
+ path: '/health',
52
+ async handler() {
53
+ return {
54
+ status: 'ok',
55
+ timestamp: new Date().toISOString()
56
+ }
57
+ }
58
+ }
59
+
60
+ /**
61
+ * @swagger
33
62
  * /echo:
34
63
  * post:
35
64
  * summary: 回显请求体
@@ -44,36 +73,19 @@
44
73
  * 200:
45
74
  * description: OK
46
75
  */
47
- module.exports = [
48
- {
49
- method: 'get',
50
- path: '/',
51
- async handler() {
52
- return {
53
- message: 'Welcome to SKWeb!',
54
- version: '1.0.0',
55
- timestamp: new Date().toISOString()
56
- }
57
- }
58
- },
59
- {
60
- method: 'get',
61
- path: '/health',
62
- async handler() {
63
- return {
64
- status: 'ok',
65
- timestamp: new Date().toISOString()
66
- }
67
- }
68
- },
69
- {
70
- method: 'post',
71
- path: '/echo',
72
- async handler(req) {
73
- return {
74
- message: 'Echo received',
75
- data: req.body
76
- }
76
+ const helloEcho = {
77
+ method: 'post',
78
+ path: '/echo',
79
+ async handler(req) {
80
+ return {
81
+ message: 'Echo received',
82
+ data: req.body
77
83
  }
78
84
  }
79
- ]
85
+ }
86
+
87
+ module.exports = {
88
+ helloIndex,
89
+ helloHealth,
90
+ helloEcho
91
+ }
@@ -3,99 +3,212 @@ const { db } = require('../services/database.js')
3
3
 
4
4
  const { SysUser } = db.sequelize.models
5
5
 
6
- module.exports = [
7
- {
8
- method: 'get',
9
- path: '/api/users',
10
- async handler(req) {
11
- const { page = 1, limit = 10 } = req.query
12
- const users = await SysUser.findAndCountAll({
13
- offset: (Number(page) - 1) * Number(limit),
14
- limit: Number(limit)
15
- })
16
- return {
17
- list: users.rows,
18
- total: users.count
19
- }
6
+ /**
7
+ * @swagger
8
+ * /api/users:
9
+ * get:
10
+ * summary: 获取用户列表
11
+ * tags: [Users]
12
+ * parameters:
13
+ * - in: query
14
+ * name: page
15
+ * schema: { type: integer, minimum: 1, default: 1 }
16
+ * description: 页码
17
+ * - in: query
18
+ * name: limit
19
+ * schema: { type: integer, minimum: 1, default: 10 }
20
+ * description: 每页条数
21
+ * responses:
22
+ * 200:
23
+ * description: OK
24
+ */
25
+ const userList = {
26
+ method: 'get',
27
+ path: '/api/users',
28
+ async handler(req) {
29
+ const { page = 1, limit = 10 } = req.query
30
+ const users = await SysUser.findAndCountAll({
31
+ offset: (Number(page) - 1) * Number(limit),
32
+ limit: Number(limit)
33
+ })
34
+ return {
35
+ list: users.rows,
36
+ total: users.count
20
37
  }
38
+ }
39
+ }
40
+
41
+ /**
42
+ * @swagger
43
+ * /api/users/{id}:
44
+ * get:
45
+ * summary: 获取单个用户
46
+ * tags: [Users]
47
+ * parameters:
48
+ * - in: path
49
+ * name: id
50
+ * required: true
51
+ * schema: { type: integer, minimum: 1 }
52
+ * responses:
53
+ * 200:
54
+ * description: OK
55
+ * 404:
56
+ * description: 用户不存在
57
+ */
58
+ const userGet = {
59
+ method: 'get',
60
+ path: '/api/users/:id',
61
+ paramsSchema: {
62
+ type: 'object',
63
+ required: ['id'],
64
+ properties: { id: { type: 'integer', minimum: 1 } }
21
65
  },
22
- {
23
- method: 'get',
24
- path: '/api/users/:id',
25
- paramsSchema: {
26
- type: 'object',
27
- required: ['id'],
28
- properties: { id: { type: 'integer', minimum: 1 } }
29
- },
30
- async handler(req) {
31
- const { id } = req.validatedParams
32
- const user = await SysUser.findByPk(id)
33
- if (!user) {
34
- throw new createHttpError.NotFound('User not found')
35
- }
36
- return user
66
+ async handler(req) {
67
+ const { id } = req.validatedParams
68
+ const user = await SysUser.findByPk(id)
69
+ if (!user) {
70
+ throw new createHttpError.NotFound('User not found')
71
+ }
72
+ return user
73
+ }
74
+ }
75
+
76
+ /**
77
+ * @swagger
78
+ * /api/users:
79
+ * post:
80
+ * summary: 创建用户
81
+ * tags: [Users]
82
+ * requestBody:
83
+ * required: true
84
+ * content:
85
+ * application/json:
86
+ * schema:
87
+ * type: object
88
+ * required: [username, password]
89
+ * properties:
90
+ * username: { type: string, minLength: 3 }
91
+ * password: { type: string, minLength: 6 }
92
+ * email: { type: string, format: email }
93
+ * phone: { type: string }
94
+ * responses:
95
+ * 200:
96
+ * description: 创建成功
97
+ */
98
+ const userCreate = {
99
+ method: 'post',
100
+ path: '/api/users',
101
+ bodySchema: {
102
+ type: 'object',
103
+ required: ['username', 'password'],
104
+ properties: {
105
+ username: { type: 'string', minLength: 3 },
106
+ password: { type: 'string', minLength: 6 },
107
+ email: { type: 'string', format: 'email' },
108
+ phone: { type: 'string' }
37
109
  }
38
110
  },
39
- {
40
- method: 'post',
41
- path: '/api/users',
42
- bodySchema: {
43
- type: 'object',
44
- required: ['username', 'password'],
45
- properties: {
46
- username: { type: 'string', minLength: 3 },
47
- password: { type: 'string', minLength: 6 },
48
- email: { type: 'string', format: 'email' },
49
- phone: { type: 'string' }
50
- }
51
- },
52
- async handler(req) {
53
- return await SysUser.create(req.validatedBody)
111
+ async handler(req) {
112
+ return await SysUser.create(req.validatedBody)
113
+ }
114
+ }
115
+
116
+ /**
117
+ * @swagger
118
+ * /api/users/{id}:
119
+ * put:
120
+ * summary: 更新用户
121
+ * tags: [Users]
122
+ * parameters:
123
+ * - in: path
124
+ * name: id
125
+ * required: true
126
+ * schema: { type: integer, minimum: 1 }
127
+ * requestBody:
128
+ * required: true
129
+ * content:
130
+ * application/json:
131
+ * schema:
132
+ * type: object
133
+ * properties:
134
+ * password: { type: string, minLength: 6 }
135
+ * email: { type: string, format: email }
136
+ * phone: { type: string }
137
+ * status: { type: integer }
138
+ * responses:
139
+ * 200:
140
+ * description: OK
141
+ * 404:
142
+ * description: 用户不存在
143
+ */
144
+ const userUpdate = {
145
+ method: 'put',
146
+ path: '/api/users/:id',
147
+ paramsSchema: {
148
+ type: 'object',
149
+ required: ['id'],
150
+ properties: { id: { type: 'integer', minimum: 1 } }
151
+ },
152
+ bodySchema: {
153
+ type: 'object',
154
+ properties: {
155
+ password: { type: 'string', minLength: 6 },
156
+ email: { type: 'string', format: 'email' },
157
+ phone: { type: 'string' },
158
+ status: { type: 'integer' }
54
159
  }
55
160
  },
56
- {
57
- method: 'put',
58
- path: '/api/users/:id',
59
- paramsSchema: {
60
- type: 'object',
61
- required: ['id'],
62
- properties: { id: { type: 'integer', minimum: 1 } }
63
- },
64
- bodySchema: {
65
- type: 'object',
66
- properties: {
67
- password: { type: 'string', minLength: 6 },
68
- email: { type: 'string', format: 'email' },
69
- phone: { type: 'string' },
70
- status: { type: 'integer' }
71
- }
72
- },
73
- async handler(req) {
74
- const { id } = req.validatedParams
75
- const user = await SysUser.findByPk(id)
76
- if (!user) {
77
- throw new createHttpError.NotFound('User not found')
78
- }
79
- await user.update(req.validatedBody)
80
- return user
161
+ async handler(req) {
162
+ const { id } = req.validatedParams
163
+ const user = await SysUser.findByPk(id)
164
+ if (!user) {
165
+ throw new createHttpError.NotFound('User not found')
81
166
  }
167
+ await user.update(req.validatedBody)
168
+ return user
169
+ }
170
+ }
171
+
172
+ /**
173
+ * @swagger
174
+ * /api/users/{id}:
175
+ * delete:
176
+ * summary: 删除用户
177
+ * tags: [Users]
178
+ * parameters:
179
+ * - in: path
180
+ * name: id
181
+ * required: true
182
+ * schema: { type: integer, minimum: 1 }
183
+ * responses:
184
+ * 200:
185
+ * description: OK
186
+ * 404:
187
+ * description: 用户不存在
188
+ */
189
+ const userDelete = {
190
+ method: 'delete',
191
+ path: '/api/users/:id',
192
+ paramsSchema: {
193
+ type: 'object',
194
+ required: ['id'],
195
+ properties: { id: { type: 'integer', minimum: 1 } }
82
196
  },
83
- {
84
- method: 'delete',
85
- path: '/api/users/:id',
86
- paramsSchema: {
87
- type: 'object',
88
- required: ['id'],
89
- properties: { id: { type: 'integer', minimum: 1 } }
90
- },
91
- async handler(req) {
92
- const { id } = req.validatedParams
93
- const user = await SysUser.findByPk(id)
94
- if (!user) {
95
- throw new createHttpError.NotFound('User not found')
96
- }
97
- await user.destroy()
98
- return { message: 'User deleted' }
197
+ async handler(req) {
198
+ const { id } = req.validatedParams
199
+ const user = await SysUser.findByPk(id)
200
+ if (!user) {
201
+ throw new createHttpError.NotFound('User not found')
99
202
  }
203
+ await user.destroy()
204
+ return { message: 'User deleted' }
100
205
  }
101
- ]
206
+ }
207
+
208
+ module.exports = {
209
+ userList,
210
+ userGet,
211
+ userCreate,
212
+ userUpdate,
213
+ userDelete
214
+ }
@@ -62,16 +62,14 @@ async function startCronWorker() {
62
62
  framework.start()
63
63
  logger.info('[cron-worker] Cron worker started')
64
64
 
65
- process.on('SIGINT', async () => {
66
- logger.info('[cron-worker] Received SIGINT, shutting down...')
67
- await framework.stop()
68
- process.exit(0)
65
+ // 未捕获异常:打印堆栈后直接退出。OS / 进程管理器负责回收资源。
66
+ process.on('uncaughtException', (err) => {
67
+ logger.error(`[cron-worker] uncaughtException: ${err.stack || err.message}`)
68
+ process.exit(1)
69
69
  })
70
-
71
- process.on('SIGTERM', async () => {
72
- logger.info('[cron-worker] Received SIGTERM, shutting down...')
73
- await framework.stop()
74
- process.exit(0)
70
+ process.on('unhandledRejection', (reason) => {
71
+ logger.error(`[cron-worker] unhandledRejection: ${reason instanceof Error ? reason.stack : String(reason)}`)
72
+ process.exit(1)
75
73
  })
76
74
  }
77
75
 
@@ -20,27 +20,27 @@
20
20
  "clean:temp": "rm -rf .rollup.cache"
21
21
  },
22
22
  "dependencies": {
23
- "@dotenvx/dotenvx": "^1.71.0",
24
- "http-errors": "^2.0.0",
25
- "skweb-express": "^1.1.0",
26
- "skweb-express-jwt": "^2.0.0",
27
- "skweb-express-logger": "^1.1.0",
28
- "skweb-sequelize": "^1.1.0",
29
- "skweb-redis": "^1.1.0",
30
- "skweb-cron": "^1.1.0",
31
- "skweb-framework": "^1.1.0",
32
- "skweb-plugin": "^1.1.0",
33
- "skweb-util": "^1.1.0",
34
- "winston": "^3.17.0",
35
- "sequelize": "^6.37.7",
36
- "swagger-jsdoc": "^6.2.8",
23
+ "@dotenvx/dotenvx": "^1.75.1",
24
+ "http-errors": "^2.0.1",
25
+ "skweb-express": "^2.0.0",
26
+ "skweb-express-jwt": "^3.0.0",
27
+ "skweb-express-logger": "^2.0.0",
28
+ "skweb-sequelize": "^2.0.0",
29
+ "skweb-redis": "^2.0.0",
30
+ "skweb-cron": "^2.0.0",
31
+ "skweb-framework": "^2.0.0",
32
+ "skweb-plugin": "^2.0.0",
33
+ "skweb-util": "^2.0.0",
34
+ "winston": "^3.19.0",
35
+ "sequelize": "^6.37.8",
36
+ "swagger-jsdoc": "^6.3.0",
37
37
  "swagger-ui-express": "^5.0.1"
38
38
  },
39
39
  "devDependencies": {
40
- "chai": "^6.2.1",
41
- "mocha": "^11.7.5",
42
- "eslint": "^9.39.1",
43
- "@eslint/js": "^9.39.1"
40
+ "chai": "^6.2.2",
41
+ "mocha": "^11.7.6",
42
+ "eslint": "^10.5.0",
43
+ "@eslint/js": "^10.0.1"
44
44
  },
45
45
  "engines": {
46
46
  "node": ">=20.18.1"
@@ -3,7 +3,7 @@ import 'dotenv/config'
3
3
  import path from 'path'
4
4
  import { fileURLToPath } from 'url'
5
5
  import express from 'skweb-express'
6
- import expressLogger from 'skweb-express-logger'
6
+ import expressLogger, { errorHandler as expressErrorHandler } from 'skweb-express-logger'
7
7
  import swaggerUi from 'swagger-ui-express'
8
8
  import logger from './utils/logger.js'
9
9
  import { checkRequiredEnv } from './utils/config.js'
@@ -135,16 +135,14 @@ async function bootstrap() {
135
135
 
136
136
  logger.info('[app] Initialization complete (web process)')
137
137
 
138
- process.on('SIGINT', async () => {
139
- logger.info('[app] Received SIGINT, shutting down gracefully...')
140
- await framework.stop()
141
- process.exit(0)
138
+ // 未捕获异常:打印堆栈后直接退出。OS / 进程管理器负责回收资源。
139
+ process.on('uncaughtException', (err) => {
140
+ logger.error(`[app] uncaughtException: ${err.stack || err.message}`)
141
+ process.exit(1)
142
142
  })
143
-
144
- process.on('SIGTERM', async () => {
145
- logger.info('[app] Received SIGTERM, shutting down gracefully...')
146
- await framework.stop()
147
- process.exit(0)
143
+ process.on('unhandledRejection', (reason) => {
144
+ logger.error(`[app] unhandledRejection: ${reason instanceof Error ? reason.stack : String(reason)}`)
145
+ process.exit(1)
148
146
  })
149
147
  }
150
148
 
@@ -16,6 +16,21 @@
16
16
  * message: { type: string, example: 'Welcome to SKWeb!' }
17
17
  * version: { type: string, example: '1.0.0' }
18
18
  * timestamp: { type: string, format: date-time }
19
+ */
20
+ const helloIndex = {
21
+ method: 'get',
22
+ path: '/',
23
+ async handler() {
24
+ return {
25
+ message: 'Welcome to SKWeb!',
26
+ version: '1.0.0',
27
+ timestamp: new Date().toISOString()
28
+ }
29
+ }
30
+ }
31
+
32
+ /**
33
+ * @swagger
19
34
  * /health:
20
35
  * get:
21
36
  * summary: 健康检查
@@ -30,6 +45,20 @@
30
45
  * properties:
31
46
  * status: { type: string, example: 'ok' }
32
47
  * timestamp: { type: string, format: date-time }
48
+ */
49
+ const helloHealth = {
50
+ method: 'get',
51
+ path: '/health',
52
+ async handler() {
53
+ return {
54
+ status: 'ok',
55
+ timestamp: new Date().toISOString()
56
+ }
57
+ }
58
+ }
59
+
60
+ /**
61
+ * @swagger
33
62
  * /echo:
34
63
  * post:
35
64
  * summary: 回显请求体
@@ -44,36 +73,19 @@
44
73
  * 200:
45
74
  * description: OK
46
75
  */
47
- export default [
48
- {
49
- method: 'get',
50
- path: '/',
51
- async handler() {
52
- return {
53
- message: 'Welcome to SKWeb!',
54
- version: '1.0.0',
55
- timestamp: new Date().toISOString()
56
- }
57
- }
58
- },
59
- {
60
- method: 'get',
61
- path: '/health',
62
- async handler() {
63
- return {
64
- status: 'ok',
65
- timestamp: new Date().toISOString()
66
- }
67
- }
68
- },
69
- {
70
- method: 'post',
71
- path: '/echo',
72
- async handler(req) {
73
- return {
74
- message: 'Echo received',
75
- data: req.body
76
- }
76
+ const helloEcho = {
77
+ method: 'post',
78
+ path: '/echo',
79
+ async handler(req) {
80
+ return {
81
+ message: 'Echo received',
82
+ data: req.body
77
83
  }
78
84
  }
79
- ]
85
+ }
86
+
87
+ export default {
88
+ helloIndex,
89
+ helloHealth,
90
+ helloEcho
91
+ }