jfexmd 0.0.1

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 (114) hide show
  1. package/.prompt +13 -0
  2. package/CHANGELOG.md +7 -0
  3. package/README.MD +649 -0
  4. package/bin/build-aux.sh +10 -0
  5. package/bin/build.sh +11 -0
  6. package/bin/check-node.sh +17 -0
  7. package/bin/copy-to-publish.sh +8 -0
  8. package/bin/feature.sh +3 -0
  9. package/bin/generate-changelog.js +47 -0
  10. package/bin/publish-auxiliary.sh +2 -0
  11. package/bin/publish-exmd.sh +2 -0
  12. package/bin/push.js +30 -0
  13. package/bin/replace-aux.sh +8 -0
  14. package/bin/replace-to-test.sh +26 -0
  15. package/docs/readme.md +7 -0
  16. package/package.json +61 -0
  17. package/resource-pack/auxiliary/README.MD +22 -0
  18. package/resource-pack/auxiliary/package.json +14 -0
  19. package/resource-pack/readme.md +0 -0
  20. package/resources/index.d.ts +1 -0
  21. package/src/api-server/auth-api.js +204 -0
  22. package/src/api-server/graceful-shutdown.js +95 -0
  23. package/src/api-server/health.js +57 -0
  24. package/src/api-server/index.js +553 -0
  25. package/src/api-server/init-email.js +8 -0
  26. package/src/api-server/readme.md +4 -0
  27. package/src/api-server/swagger-data.js +33 -0
  28. package/src/authorization/auth-controller.js +378 -0
  29. package/src/authorization/auth-service/query-by-username.js +35 -0
  30. package/src/authorization/db-ope.js +29 -0
  31. package/src/authorization/default-user-model.js +63 -0
  32. package/src/authorization/readme.md +10 -0
  33. package/src/authorization/util-password.js +33 -0
  34. package/src/authorization/util-time.js +29 -0
  35. package/src/authorization/util-token.js +65 -0
  36. package/src/auxiliary/aux-db-server.js +58 -0
  37. package/src/auxiliary/index.js +56 -0
  38. package/src/auxiliary/readme.md +6 -0
  39. package/src/auxiliary/views-utils.js +46 -0
  40. package/src/db-server/base-model-fun/add.js +66 -0
  41. package/src/db-server/base-model-fun/common-fun.js +209 -0
  42. package/src/db-server/base-model-fun/delete.js +57 -0
  43. package/src/db-server/base-model-fun/get.js +58 -0
  44. package/src/db-server/base-model-fun/modify.js +53 -0
  45. package/src/db-server/base-model-fun/query.js +107 -0
  46. package/src/db-server/base-model-fun/readme.md +9 -0
  47. package/src/db-server/base-model.js +64 -0
  48. package/src/db-server/datasource-registry.js +36 -0
  49. package/src/db-server/db-Adapter.js +9 -0
  50. package/src/db-server/db-client-runtime.js +71 -0
  51. package/src/db-server/db-connect/postgresql-connect.js +13 -0
  52. package/src/db-server/index.js +73 -0
  53. package/src/db-server/readme.md +5 -0
  54. package/src/email/index.js +5 -0
  55. package/src/email/tencenmail.js +45 -0
  56. package/src/index.js +192 -0
  57. package/src/lib/multer/LICENSE +17 -0
  58. package/src/lib/multer/README.md +333 -0
  59. package/src/lib/multer/index.js +106 -0
  60. package/src/lib/multer/lib/counter.js +28 -0
  61. package/src/lib/multer/lib/file-appender.js +67 -0
  62. package/src/lib/multer/lib/make-middleware.js +173 -0
  63. package/src/lib/multer/lib/multer-error.js +31 -0
  64. package/src/lib/multer/lib/remove-uploaded-files.js +28 -0
  65. package/src/lib/multer/package.json +95 -0
  66. package/src/lib/multer/storage/disk.js +66 -0
  67. package/src/lib/multer/storage/memory.js +21 -0
  68. package/src/lib/readme.md +0 -0
  69. package/src/migrate/asyncdb.js +20 -0
  70. package/src/migrate/build-model.js +75 -0
  71. package/src/migrate/build-table.js +245 -0
  72. package/src/migrate/file-handle.js +66 -0
  73. package/src/migrate/index.js +20 -0
  74. package/src/migrate/postgresql-migrate.js +102 -0
  75. package/src/plugin/builtin/request-log-plugin.js +23 -0
  76. package/src/plugin/plugin-manager.js +111 -0
  77. package/src/readme.md +13 -0
  78. package/src/release/changelog.js +56 -0
  79. package/src/security/auth-middlewares.js +83 -0
  80. package/src/security/cors.js +53 -0
  81. package/src/security/helmet-config.js +39 -0
  82. package/src/upload/init.js +52 -0
  83. package/src/upload/upload-controller.js +47 -0
  84. package/src/utils/RequestTypeUtil.js +59 -0
  85. package/src/utils/cache-utils.js +51 -0
  86. package/src/utils/config-migration.js +52 -0
  87. package/src/utils/config-validator.js +48 -0
  88. package/src/utils/deprecation.js +24 -0
  89. package/src/utils/json-to-model.js +36 -0
  90. package/src/utils/logger.js +58 -0
  91. package/src/utils/md5.js +365 -0
  92. package/src/utils/metrics.js +42 -0
  93. package/src/utils/model-util.js +17 -0
  94. package/src/utils/moment.js +33 -0
  95. package/src/utils/promise.js +32 -0
  96. package/src/utils/rate-limit.js +72 -0
  97. package/src/utils/readme.md +10 -0
  98. package/src/utils/string-utils.js +17 -0
  99. package/src/utils/validate-request.js +22 -0
  100. package/src/vo/HttpStatus.js +80 -0
  101. package/src/vo/ResultVo.js +24 -0
  102. package/src/vo/objectToVo.js +53 -0
  103. package/test/line1.js +8 -0
  104. package/test/line2.js +8 -0
  105. package/test/test-lines.js +11 -0
  106. package/test/timer.js +17 -0
  107. package/test/v02-engineering.js +71 -0
  108. package/test/v03-reliability.js +107 -0
  109. package/test/v04-extensibility.js +165 -0
  110. package/test/v05-release-quality.js +82 -0
  111. package/test/v06-observability.js +69 -0
  112. package/test/v07-operations.js +73 -0
  113. package/test/v08-security.js +104 -0
  114. package/webpack.config.js +70 -0
package/.prompt ADDED
@@ -0,0 +1,13 @@
1
+ # 项目名称: exmd
2
+ # 用途: EXMD 核心后端服务与业务接口
3
+ # 主要技术: Node.js, Express/Koa (以项目实际依赖为准)
4
+ # 目录约定:
5
+ # - controller/: 请求入口与参数校验
6
+ # - services/: 业务逻辑与数据处理
7
+ # - models/: 数据模型/ORM
8
+ # - router/: 路由注册与中间件
9
+ # 开发建议:
10
+ # - 变更前先定位对应路由与服务层
11
+ # - 严格保留公共错误码与响应结构
12
+ # - 新增接口需补充单元/集成测试
13
+ # 运行与调试: 参考 README 或 package.json scripts
package/CHANGELOG.md ADDED
@@ -0,0 +1,7 @@
1
+ # Changelog
2
+
3
+ ## 1.0.38 - 2026-02-11
4
+
5
+ ### Baseline
6
+
7
+ - framework hardening and extensibility baseline completed through v0.4
package/README.MD ADDED
@@ -0,0 +1,649 @@
1
+ # exmd内核
2
+
3
+ ```exmd```的核心代码,包含以下功能:
4
+
5
+ **核心能力**
6
+ 1. ```startProject``` 启动项目(返回 Promise\<server\>,支持手动 shutdown)
7
+ 2. ```BaseModel``` model基类(含事务、参数化 SQL)
8
+ 3. ```migrate``` 数据库表转model
9
+ 4. ```asyncdb``` model转数据库表
10
+ 5. ```renderRequestType``` controller 方法请求配置(请求类型、swagger 描述、必填校验、限流、中间件、钩子)
11
+ 6. ```handleClientAdapter``` 持久层适配器,指定数据源并操作对应 model
12
+ 7. ```ResultVo``` 返回结果集合
13
+ 8. ```AuthController``` 内置登录注册 controller(bcrypt 密码、JWT、验证码)
14
+ 9. ```UploadController``` 内置文件上传控制器
15
+
16
+ **扩展与工具**
17
+ - 插件机制(```createPluginManager```、```createRequestLogPlugin```)
18
+ - 数据源注册中心(```createDatasourceRegistry```,支持扩展多数据库)
19
+ - 可观测性(```createMetricsRegistry```、/health、/ready、/metrics)
20
+ - 安全中间件(```createApiKeyMiddleware```、```createHmacSignatureMiddleware```)
21
+ - 配置迁移与弃用告警(```applyConfigMigrations```)
22
+
23
+ **业务层**
24
+
25
+ 获得可操作数据库的模型:
26
+
27
+ ```js
28
+ // 自定义的model:flow
29
+ const Flow = require('./models/flow')
30
+ let dataSourceKey = ogisticServiceData.authDataSourceKey
31
+ const client = handleClientAdapter(ogisticServiceData, dataSourceKey)
32
+ const flow = new Flow(client, ogisticServiceData)
33
+ ```
34
+
35
+ 简化使用也可以直接使用exmd引出的:
36
+
37
+ ```js
38
+ // 自定义的model:flow
39
+ const Flow = require('./models/flow')
40
+ const { getModelInstance } = require('../../exmd')
41
+ const flow = getModelInstance(ogisticServiceData)
42
+ ```
43
+
44
+
45
+
46
+ **数据源配置**
47
+
48
+ 默认支持 postgresql,可通过 `createDatasourceRegistry` 扩展其他数据库类型
49
+
50
+ ```javascript
51
+ module.exports = {
52
+ // 数据库1
53
+ postgresql1: {
54
+ type: 'postgresql',
55
+ data: {
56
+ user: 'bserverx',
57
+ database: 'bserver',
58
+ password: 'bserverx123',
59
+ host: 'localhost',
60
+ port: '5432',
61
+ poolSize: 5,
62
+ poolIdleTimeout: 30000,
63
+ reapIntervalMillis: 10000
64
+ }
65
+ }
66
+ }
67
+ ```
68
+
69
+ **启动项目**
70
+
71
+ ```javascript
72
+ startProject({
73
+ /**
74
+ * 是否开启调试模式
75
+ * 调试模式将会打印sql
76
+ * 调试模式下不会发送邮件
77
+ */
78
+ isDebugger: true,
79
+ /**
80
+ * api地址路由配置
81
+ */
82
+ router,
83
+ /**
84
+ * 数据源
85
+ */
86
+ Datasource,
87
+ /**
88
+ * 用户model
89
+ */
90
+ authUserModel: UserModel, // 可选, 不传使用内置默认model
91
+ /**
92
+ * 登录注册使用的数据源对应key
93
+ */
94
+ authDataSourceKey: 'postgresql1',
95
+ /**
96
+ * 注册邮箱使用的内容模板
97
+ * 没有配置将会使用默认模板
98
+ * @param {*} code
99
+ * @returns
100
+ */
101
+ authEmailContent: (code) => {
102
+ return `
103
+ <p>您好:</p>
104
+ <p>您的验证码是:<strong style="color:orangered;">${code}</strong></p>
105
+ <p>嘿嘿</p>
106
+ `
107
+ },
108
+ /**
109
+ * 登录注册验证码超时时间
110
+ */
111
+ authEmailCodeMaxTime: '1minute',
112
+ // 一个邮箱最多允许绑定多少个用户
113
+ authEmailBindUserMax: 3,
114
+ // token生成私钥(生产环境必填; 支持 EXMD_AUTH_PRIVATE_KEY 环境变量; 调试模式可缺省)
115
+ authPrivateKey: 'abc123',
116
+ // hour/minute/second
117
+ authTokenTime: '1minute',
118
+ /**
119
+ * 发邮件库,
120
+ * 目前只支持 tencenmail
121
+ */
122
+ emailLib: 'tencenmail',
123
+ /**
124
+ * 邮箱配置
125
+ */
126
+ emailConfig,
127
+ /**
128
+ * 返回数据的结果集合模板
129
+ */
130
+ ResultVo,
131
+ // swagger的路径配置
132
+ swaggerUrl: '/swagger/data',
133
+ // 文件上传的保存路径
134
+ uploadBaseUrl: '/Users/wujianfei/test-upload-files',
135
+ /**
136
+ * 文件上传模块划分, 必须传
137
+ * 上传的文件路径:基础路径下 文件名称: [模块名称_时间戳],
138
+ * 比如default下的文件名称:
139
+ * test1_1657007903331.mp4
140
+ */
141
+ uploadFileDirectorys: [{
142
+ name: 'test1'
143
+ }, {
144
+ name: 'default'
145
+ }],
146
+ // 文件限制配置
147
+ uploadLimits: {
148
+ fileSize: 10 * 1024 * 1024 * 1024
149
+ },
150
+ /**
151
+ * 全局中间件(按顺序执行)
152
+ * 签名: async (req, res, context) => {}
153
+ */
154
+ middlewares: [
155
+ async (req, res) => {
156
+ req.customMark = 'ok'
157
+ }
158
+ ],
159
+ /**
160
+ * 全局生命周期钩子
161
+ */
162
+ hooks: {
163
+ beforeAuth: [
164
+ async (req, res, context) => {
165
+ // 鉴权前
166
+ }
167
+ ],
168
+ afterAuth: [],
169
+ beforeHandler: [],
170
+ afterHandler: []
171
+ }
172
+ })
173
+ ```
174
+
175
+ **接口级校验/限流/中间件**
176
+
177
+ `renderRequestType` 支持更细粒度的接口配置:
178
+
179
+ ```javascript
180
+ exports.login = renderRequestType({
181
+ fun: login,
182
+ type: 'POST',
183
+ desc: '登录',
184
+ requiredFields: ['username', 'password'],
185
+ rateLimit: { max: 10, windowMs: 60 * 1000 },
186
+ middlewares: [
187
+ async (req, res) => {
188
+ // 路由级逻辑
189
+ }
190
+ ],
191
+ hooks: {
192
+ beforeHandler: [
193
+ async (req, res, context) => {
194
+ // 进入controller前
195
+ }
196
+ ],
197
+ afterHandler: [
198
+ async (req, res, context) => {
199
+ // controller执行后
200
+ }
201
+ ]
202
+ }
203
+ })
204
+ ```
205
+
206
+ **安全基线(v0.1)**
207
+
208
+ - **SQL 参数化**:BaseModel 增删改查统一使用参数化查询,避免 SQL 注入
209
+ - **密码哈希**:登录/注册使用 bcrypt,兼容历史 MD5 并自动升级
210
+ - **JWT 配置**:生产环境必须配置 `authPrivateKey` 或 `EXMD_AUTH_PRIVATE_KEY`
211
+ - **请求校验**:`renderRequestType` 支持 `requiredFields` 必填校验
212
+ - **限流**:登录/注册/验证码接口内置限流,可配置 `rateLimit`
213
+ - **全局错误处理**:统一异常中间件,返回 `ResultVo` 并记录日志
214
+ - **请求追踪**:每个请求自动注入 `X-Request-Id`,便于日志排查
215
+
216
+ **配置校验和日志**
217
+
218
+ 框架会在 `startProject` 启动时自动校验:
219
+ - `router` 必须是非空数组
220
+ - `Datasource` 必须是非空对象,且每个数据源都包含 `type/data`
221
+
222
+ 如果不传 `logger`,框架会默认创建结构化日志器;也可以通过 `createLogger` 自定义:
223
+
224
+ ```javascript
225
+ const { startProject, createLogger } = require('exmd')
226
+
227
+ startProject({
228
+ // ...
229
+ logger: createLogger({ level: 'info' }),
230
+ // 慢查询阈值(ms)
231
+ slowQueryThresholdMs: 200
232
+ })
233
+ ```
234
+
235
+ **插件机制(v0.4)**
236
+
237
+ `startProject` 支持 `plugins`,插件可实现这些生命周期:
238
+ - `setup({ config, datasourceRegistry })`
239
+ - `onConfig({ config, datasourceRegistry })`
240
+ - `onDbReady({ dbClient, datasourceRegistry })`
241
+ - `onServerReady({ app, server, port, swaggerUrl })`
242
+
243
+ 插件支持 `priority` 字段(数值越大越先执行)。
244
+
245
+ 插件错误策略通过 `pluginErrorStrategy` 配置:
246
+ - `fail-fast`(默认): 任一插件失败,启动流程中断
247
+ - `continue`: 记录错误并继续执行后续插件
248
+
249
+ ```javascript
250
+ const plugin = {
251
+ name: 'example-plugin',
252
+ setup({ datasourceRegistry }) {
253
+ datasourceRegistry.register('mockdb', (cfg) => {
254
+ return Promise.resolve({
255
+ query: () => Promise.resolve({ rowCount: 0, rows: [] })
256
+ })
257
+ })
258
+ },
259
+ onServerReady({ port }) {
260
+ console.log('server ready', port)
261
+ }
262
+ }
263
+
264
+ startProject({
265
+ // ...
266
+ plugins: [plugin],
267
+ pluginErrorStrategy: 'continue'
268
+ })
269
+ ```
270
+
271
+ 框架内置了一个官方插件模板 `createRequestLogPlugin`:
272
+
273
+ ```javascript
274
+ const { startProject, createRequestLogPlugin } = require('exmd')
275
+
276
+ startProject({
277
+ // ...
278
+ plugins: [
279
+ createRequestLogPlugin({
280
+ level: 'info',
281
+ priority: 10
282
+ })
283
+ ]
284
+ })
285
+ ```
286
+
287
+ 也可以直接手动创建并注入数据源注册器:
288
+
289
+ ```javascript
290
+ const { startProject, createDatasourceRegistry } = require('exmd')
291
+ const datasourceRegistry = createDatasourceRegistry()
292
+ datasourceRegistry.register('postgresql', postgresqlConnect)
293
+ datasourceRegistry.register('mockdb', connectMock)
294
+
295
+ startProject({
296
+ // ...
297
+ datasourceRegistry
298
+ })
299
+ ```
300
+
301
+ **事务能力**
302
+
303
+ `BaseModel` 支持事务执行:
304
+
305
+ ```javascript
306
+ const flow = new Flow(client, ogisticServiceData)
307
+ await flow.withTransaction(async (txFlow) => {
308
+ await txFlow.addItem({ name: 'a' })
309
+ await txFlow.updateItemById('id-1', { name: 'b' })
310
+ })
311
+ ```
312
+
313
+ **限流增强**
314
+
315
+ `rateLimit` 支持 `keyBy` 维度:
316
+ - `ip`(默认)
317
+ - `user`(优先取 `req.exmdAuth.username/id`)
318
+ - `ip_user`
319
+
320
+ ```javascript
321
+ exports.login = renderRequestType({
322
+ fun: login,
323
+ type: 'POST',
324
+ rateLimit: { max: 10, windowMs: 60 * 1000, keyBy: 'user' }
325
+ })
326
+ ```
327
+
328
+ `startProject` 还支持注入自定义限流存储:
329
+
330
+ ```javascript
331
+ const { startProject, createMemoryRateLimitStore } = require('exmd')
332
+
333
+ startProject({
334
+ // ...
335
+ rateLimitStore: createMemoryRateLimitStore()
336
+ })
337
+ ```
338
+
339
+ **发布质量(v0.5)**
340
+
341
+ 1) 配置迁移提示(含移除版本)
342
+
343
+ 当前支持自动迁移并告警的旧配置键:
344
+ - `middlewareList -> middlewares`
345
+ - `pluginErrorMode -> pluginErrorStrategy`
346
+ - `dbSlowQueryThreshold -> slowQueryThresholdMs`
347
+ - `datasourceAdapterRegistry -> datasourceRegistry`
348
+
349
+ 2) 弃用告警(warn once)
350
+
351
+ 同一个弃用键只会提示一次,避免刷屏。
352
+
353
+ 3) changelog 生成脚本
354
+
355
+ ```shell
356
+ npm run changelog:gen -- --version 1.0.39 --title "v0.5 发布" --changes "feat: 发布质量能力|docs: README更新"
357
+ ```
358
+
359
+ 默认会更新项目根目录 `CHANGELOG.md`,也可通过 `--file` 指定文件。
360
+
361
+ **可观测性(v0.6)**
362
+
363
+ 框架默认注入 `metrics` 注册器,包含计数指标:
364
+ - `http_request_total`
365
+ - `http_error_total`
366
+ - `db_slow_query_total`
367
+
368
+ 并内置端点(可在 `startProject` 自定义路径):
369
+ - `healthPath`,默认 `/health`
370
+ - `readinessPath`,默认 `/ready`
371
+ - `metricsPath`,默认 `/metrics`
372
+
373
+ 可选配置:
374
+ - `readinessDeepCheck: true` 时,`/ready` 会对所有数据源执行 `select 1`
375
+ - `enableMetricsEndpoint: false` 可关闭 `/metrics` 暴露
376
+
377
+ ```javascript
378
+ const { startProject, createMetricsRegistry } = require('exmd')
379
+
380
+ startProject({
381
+ // ...
382
+ metrics: createMetricsRegistry(),
383
+ healthPath: '/health',
384
+ readinessPath: '/ready',
385
+ metricsPath: '/metrics',
386
+ readinessDeepCheck: true
387
+ })
388
+ ```
389
+
390
+ **运维增强(v0.7)**
391
+
392
+ 1) readiness draining
393
+
394
+ 进入优雅停机后,`/ready` 会返回 `503`,并标记失败原因为 `draining`。
395
+
396
+ 2) graceful shutdown
397
+
398
+ 服务在 `SIGINT/SIGTERM` 下默认自动执行优雅停机:
399
+ - 停止接收新请求
400
+ - 关闭 DB 客户端
401
+ - 执行插件钩子 `onShutdown`
402
+
403
+ 可选配置:
404
+ - `autoHandleProcessSignals: false` 禁用自动信号处理
405
+ - `shutdownTimeoutMs` 优雅停机超时(默认 `10000ms`)
406
+
407
+ `startProject` 返回 `Promise<server>`,可手动触发停机:
408
+
409
+ ```javascript
410
+ const server = await startProject({
411
+ // ...
412
+ shutdownTimeoutMs: 15000
413
+ })
414
+
415
+ await server.shutdown('manual')
416
+ ```
417
+
418
+ **安全增强二期(v0.8)**
419
+
420
+ 1) CORS 白名单配置
421
+
422
+ ```javascript
423
+ startProject({
424
+ // ...
425
+ cors: {
426
+ allowOrigins: ['https://a.example.com', 'https://b.example.com'],
427
+ allowMethods: 'GET,POST,PUT,DELETE,OPTIONS',
428
+ allowHeaders: 'Content-Type, authorization, x-api-key, x-signature, x-timestamp',
429
+ allowCredentials: true
430
+ }
431
+ })
432
+ ```
433
+
434
+ 2) Helmet 可配置化
435
+
436
+ ```javascript
437
+ startProject({
438
+ // ...
439
+ helmetEnabled: true,
440
+ helmetOptions: {
441
+ contentSecurityPolicy: {
442
+ directives: {
443
+ scriptSrc: ["'self'"]
444
+ }
445
+ }
446
+ }
447
+ })
448
+ ```
449
+
450
+ 3) API Key / 签名中间件模板
451
+
452
+ ```javascript
453
+ const {
454
+ createApiKeyMiddleware,
455
+ createHmacSignatureMiddleware
456
+ } = require('exmd')
457
+
458
+ exports.createOrder = renderRequestType({
459
+ fun: createOrder,
460
+ type: 'POST',
461
+ middlewares: [
462
+ createApiKeyMiddleware({ keys: ['k1', 'k2'] }),
463
+ createHmacSignatureMiddleware({ secret: 'your-secret' })
464
+ ]
465
+ })
466
+ ```
467
+
468
+ **文件上传和登录模块使用**
469
+
470
+ 可参考提供的后端模板项目中的路由,看注释即可
471
+
472
+ ```javascript
473
+ const { AuthController, UploadController } = require('../../exmd')
474
+ const router = [
475
+ {
476
+ url: '/bserve/',
477
+ controller: UploadController
478
+ },
479
+ {
480
+ url: '/bserve/',
481
+ controller: AuthController
482
+ }
483
+ ...自己定义的controller
484
+ ]
485
+ ```
486
+
487
+ **ResultVo**
488
+
489
+ 可以根据该ResultVo自定义
490
+
491
+ ```javascript
492
+ /**
493
+ * 返回实体类
494
+ * @param {*} params
495
+ */
496
+ function ResultVo(params) {
497
+ const { status, data, message } = params
498
+ if (status === undefined) {
499
+ throw new Error('status is undefined')
500
+ }
501
+ if (data === undefined && message === undefined) {
502
+ throw new Error('both and data are undefined')
503
+ }
504
+ return {
505
+ status,
506
+ data,
507
+ message
508
+ }
509
+ }
510
+ ResultVo.prototype.swaggerDescription = {
511
+ status: '状态 0正常',
512
+ data: '',
513
+ message: '异常信息'
514
+ }
515
+ module.exports = ResultVo
516
+ ```
517
+
518
+ **UserModel**
519
+
520
+ 可以根据该model自定义模板放到models目录下
521
+
522
+ ```javascript
523
+ const { BaseModel } = require('../../exmd')
524
+ const fieldsMap = {
525
+ id: {
526
+ type: 'uuid',
527
+ length: 16,
528
+ lengthvar: -1,
529
+ notnull: true,
530
+ comment: null,
531
+ isPrimary: true,
532
+ pk_name: 'omuser_pkey'
533
+ },
534
+ username: {
535
+ type: 'text',
536
+ length: -1,
537
+ lengthvar: -1,
538
+ notnull: true,
539
+ comment: null
540
+ },
541
+ password: {
542
+ type: 'text',
543
+ length: -1,
544
+ lengthvar: -1,
545
+ notnull: true,
546
+ comment: null
547
+ },
548
+ email: {
549
+ type: 'text',
550
+ length: -1,
551
+ lengthvar: -1,
552
+ notnull: true,
553
+ comment: null
554
+ },
555
+ fullName: {
556
+ type: 'text',
557
+ length: -1,
558
+ lengthvar: -1,
559
+ notnull: true,
560
+ comment: null
561
+ },
562
+ isactive: {
563
+ type: 'int4',
564
+ length: 4,
565
+ lengthvar: -1,
566
+ notnull: true,
567
+ comment: null
568
+ },
569
+ realname: {
570
+ type: 'text',
571
+ length: -1,
572
+ lengthvar: -1,
573
+ notnull: false,
574
+ comment: null
575
+ }
576
+ }
577
+
578
+ function omuser() {
579
+ const vm = this
580
+ BaseModel.apply(vm, arguments)
581
+ vm.fields = fieldsMap
582
+ vm.tableName = 'omuser'
583
+ }
584
+
585
+ ;(function () {
586
+ const TempFun = function () {}
587
+ TempFun.prototype = BaseModel.prototype
588
+ omuser.prototype = new TempFun()
589
+ })()
590
+
591
+ module.exports = omuser
592
+
593
+ ```
594
+
595
+ **默认UserModel**
596
+
597
+ 未传`authUserModel`时,框架会使用内置默认模型`DefaultAuthUserModel`,
598
+ 表名为`omuser`,字段如下(仅`username/password/email`为必填):
599
+
600
+ ```javascript
601
+ {
602
+ id: { type: 'uuid', isPrimary: true },
603
+ username: { type: 'varchar', length: 64, notnull: true },
604
+ password: { type: 'varchar', length: 64, notnull: true },
605
+ email: { type: 'varchar', length: 128, notnull: true },
606
+ fullName: { type: 'varchar', length: 128 },
607
+ isactive: { type: 'int4' }
608
+ }
609
+ ```
610
+
611
+ **startProject 配置项汇总**
612
+
613
+ | 分类 | 配置项 | 说明 |
614
+ |------|--------|------|
615
+ | 基础 | router, Datasource, ResultVo | 必填 |
616
+ | 认证 | authUserModel, authDataSourceKey, authPrivateKey, authTokenTime | JWT 与用户模型 |
617
+ | 邮件 | emailLib, emailConfig, authEmailContent, authEmailCodeMaxTime, authEmailBindUserMax | 验证码与注册 |
618
+ | 上传 | uploadBaseUrl, uploadFileDirectorys, uploadLimits | 文件上传 |
619
+ | 工程化 | logger, middlewares, hooks, pluginErrorStrategy | 日志、中间件、钩子 |
620
+ | 插件 | plugins, datasourceRegistry | 插件与数据源扩展 |
621
+ | 安全 | rateLimitStore, cors, helmetEnabled, helmetOptions | 限流、CORS、Helmet |
622
+ | 可观测 | metrics, healthPath, readinessPath, metricsPath, readinessDeepCheck, enableMetricsEndpoint | 健康检查与指标 |
623
+ | 运维 | shutdownTimeoutMs, autoHandleProcessSignals | 优雅停机 |
624
+
625
+ **构建**
626
+ ```shell
627
+ npm run build
628
+ ```
629
+
630
+ **提交所有代码**
631
+ ```shell
632
+ npm run push:all
633
+ ```
634
+
635
+ **发布**
636
+ ```shell
637
+ npm run publish:exmd
638
+ npm run publish:aux
639
+ ```
640
+
641
+ **Changelog 生成**
642
+ ```shell
643
+ npm run changelog:gen -- --version 1.0.39 --title "发布说明" --changes "feat: 功能1|fix: 修复1"
644
+ ```
645
+
646
+ 源码仓库已提交申请中,请耐心等待
647
+
648
+
649
+
@@ -0,0 +1,10 @@
1
+ #!/bin/sh
2
+
3
+ targetFile_1="./dist/auxiliary/package.json"
4
+ targetFile_2="./dist/auxiliary//README.MD"
5
+ sourceFile="./resource-pack/auxiliary/*"
6
+ npm run build &&
7
+ if [ -f "${targetFile_1}" ]; then rm -rf "${targetFile_1}"; fi &&
8
+ if [ -f "${targetFile_2}" ]; then rm -rf "${targetFile_2}"; fi &&
9
+ cp ./resource-pack/auxiliary/* dist/auxiliary &&
10
+ echo "完成文件拷贝"
package/bin/build.sh ADDED
@@ -0,0 +1,11 @@
1
+ #!/bin/sh
2
+
3
+ # webpack打包
4
+ ./node_modules/.bin/webpack --mode=production &&
5
+ # 创建目录
6
+ if [ ! -d dist/auxiliary ]; then mkdir -p dist/auxiliary; fi &&
7
+ # 迁移辅文件
8
+ mv ./dist/exmd/src/auxiliary.js ./dist/auxiliary/index.js &&
9
+ # 拷贝package.json
10
+ cp ./package.json ./dist/exmd/package.json &&
11
+ cp ./resources/index.d.ts ./dist/exmd/index.d.ts
@@ -0,0 +1,17 @@
1
+ #!/bin/sh
2
+
3
+ NODE_VERSION="$(node -v 2>/dev/null)"
4
+ if [ $? -ne 0 ]; then
5
+ echo "只支持16版本"
6
+ exit 1
7
+ fi
8
+
9
+ case "$NODE_VERSION" in
10
+ v16.*)
11
+ exit 0
12
+ ;;
13
+ *)
14
+ echo "只支持16版本"
15
+ exit 1
16
+ ;;
17
+ esac
@@ -0,0 +1,8 @@
1
+ #!/bin/sh
2
+
3
+ name="~/发布包/exmd-dist"
4
+ if [ ! -d name ]; then rm -rf name; fi
5
+ cp -r ./dist ~/发布包
6
+ mv ~/发布包/dist ~/发布包/exmd-dist
7
+ echo "拷贝完成,发布路径是:${name}"
8
+ unset name