wok-server 0.5.0 → 0.7.0

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 (380) hide show
  1. package/README.en.md +61 -0
  2. package/README.md +44 -29
  3. package/dist/cache/cache.js +98 -98
  4. package/dist/cache/config.js +19 -19
  5. package/dist/cache/index.js +27 -27
  6. package/dist/cache/purge-task.js +46 -46
  7. package/dist/cache/stat.js +47 -47
  8. package/dist/config/convert.js +36 -36
  9. package/dist/config/exception.js +14 -14
  10. package/dist/config/index.js +81 -81
  11. package/dist/http-client/index.js +136 -136
  12. package/dist/i18n/ar.js +17 -17
  13. package/dist/i18n/de.js +17 -17
  14. package/dist/i18n/en-us.js +17 -17
  15. package/dist/i18n/es.js +17 -17
  16. package/dist/i18n/fr.js +17 -17
  17. package/dist/i18n/i18n.js +231 -231
  18. package/dist/i18n/index.js +52 -52
  19. package/dist/i18n/ja.js +17 -17
  20. package/dist/i18n/ko.js +17 -17
  21. package/dist/i18n/msg.js +2 -2
  22. package/dist/i18n/pt.js +17 -17
  23. package/dist/i18n/ru.js +17 -17
  24. package/dist/i18n/tag.js +18 -18
  25. package/dist/i18n/zh-HK.js +17 -17
  26. package/dist/i18n/zh-TW.js +17 -17
  27. package/dist/i18n/zh-cn.js +17 -17
  28. package/dist/index.js +14 -14
  29. package/dist/lock/index.js +114 -114
  30. package/dist/log/config.js +35 -35
  31. package/dist/log/date.js +21 -21
  32. package/dist/log/file.js +198 -198
  33. package/dist/log/index.js +135 -135
  34. package/dist/log/level.js +33 -33
  35. package/dist/log/log.js +56 -56
  36. package/dist/log/store.js +19 -19
  37. package/dist/mongodb/collection.js +2 -2
  38. package/dist/mongodb/config.js +34 -34
  39. package/dist/mongodb/doc.js +2 -2
  40. package/dist/mongodb/exception.js +14 -14
  41. package/dist/mongodb/index.js +58 -58
  42. package/dist/mongodb/manager/base.js +563 -563
  43. package/dist/mongodb/manager/index.js +63 -63
  44. package/dist/mongodb/manager/tx-strict.js +84 -84
  45. package/dist/mongodb/manager/tx.js +30 -30
  46. package/dist/mongodb/migration.js +52 -52
  47. package/dist/mvc/access-log.js +33 -33
  48. package/dist/mvc/config.js +27 -27
  49. package/dist/mvc/exchange.js +113 -113
  50. package/dist/mvc/handler/index.js +7 -6
  51. package/dist/mvc/handler/json.js +65 -65
  52. package/dist/mvc/handler/restful.js +35 -35
  53. package/dist/mvc/handler/sse.js +65 -0
  54. package/dist/mvc/handler/upload.js +31 -31
  55. package/dist/mvc/index.js +50 -50
  56. package/dist/mvc/interceptor.js +2 -2
  57. package/dist/mvc/query.js +43 -43
  58. package/dist/mvc/render/file.js +132 -132
  59. package/dist/mvc/render/html/html.js +90 -90
  60. package/dist/mvc/render/html/index.js +18 -18
  61. package/dist/mvc/render/html/style.js +2 -2
  62. package/dist/mvc/render/index.js +7 -7
  63. package/dist/mvc/render/json.js +26 -26
  64. package/dist/mvc/render/text.js +16 -16
  65. package/dist/mvc/router.js +2 -2
  66. package/dist/mvc/server.js +272 -272
  67. package/dist/mvc/static/header.js +67 -67
  68. package/dist/mvc/static/index.js +6 -6
  69. package/dist/mvc/static/mime-type.js +84 -84
  70. package/dist/mvc/static/server-cache-config.js +66 -66
  71. package/dist/mvc/static/server-cache.js +133 -133
  72. package/dist/mvc/static/static-handler.js +372 -372
  73. package/dist/mysql/config.js +51 -51
  74. package/dist/mysql/exception.js +14 -14
  75. package/dist/mysql/index.js +87 -87
  76. package/dist/mysql/manager/base.js +278 -239
  77. package/dist/mysql/manager/index.js +107 -107
  78. package/dist/mysql/manager/ops/count.js +20 -20
  79. package/dist/mysql/manager/ops/criteria.js +381 -356
  80. package/dist/mysql/manager/ops/delete.js +59 -65
  81. package/dist/mysql/manager/ops/exist.js +26 -26
  82. package/dist/mysql/manager/ops/find.js +149 -169
  83. package/dist/mysql/manager/ops/index.js +16 -14
  84. package/dist/mysql/manager/ops/insert.js +132 -106
  85. package/dist/mysql/manager/ops/modify.js +10 -10
  86. package/dist/mysql/manager/ops/order-by.js +28 -0
  87. package/dist/mysql/manager/ops/paginate.js +48 -23
  88. package/dist/mysql/manager/ops/query.js +9 -9
  89. package/dist/mysql/manager/ops/update.js +222 -216
  90. package/dist/mysql/manager/ops/upsert.js +178 -0
  91. package/dist/mysql/manager/ops/utils.js +28 -24
  92. package/dist/mysql/manager/tx-strict.js +103 -103
  93. package/dist/mysql/manager/tx.js +30 -30
  94. package/dist/mysql/manager/utils.js +56 -56
  95. package/dist/mysql/migration.js +136 -136
  96. package/dist/mysql/table-info.js +8 -8
  97. package/dist/task/daily.js +59 -59
  98. package/dist/task/fixed-delay.js +38 -38
  99. package/dist/task/fixed-rate.js +42 -42
  100. package/dist/task/index.js +9 -9
  101. package/dist/task/task.js +56 -56
  102. package/dist/validation/exception.js +36 -36
  103. package/dist/validation/index.js +40 -40
  104. package/dist/validation/validator/array.js +34 -34
  105. package/dist/validation/validator/enum.js +28 -28
  106. package/dist/validation/validator/index.js +14 -14
  107. package/dist/validation/validator/length.js +40 -40
  108. package/dist/validation/validator/max-length.js +35 -35
  109. package/dist/validation/validator/max.js +29 -29
  110. package/dist/validation/validator/min-length.js +33 -33
  111. package/dist/validation/validator/min.js +29 -29
  112. package/dist/validation/validator/not-blank.js +33 -33
  113. package/dist/validation/validator/not-null.js +21 -21
  114. package/dist/validation/validator/plain-obj.js +32 -32
  115. package/dist/validation/validator/regexp.js +34 -34
  116. package/documentation/en/cache.md +56 -0
  117. package/documentation/en/config.md +96 -0
  118. package/documentation/en/engineering.md +256 -0
  119. package/documentation/en/http-client.md +32 -0
  120. package/documentation/en/i18n.md +143 -0
  121. package/documentation/en/index.md +24 -0
  122. package/documentation/en/lock.md +51 -0
  123. package/documentation/en/log.md +109 -0
  124. package/documentation/en/mongodb.md +256 -0
  125. package/documentation/en/mvc.md +688 -0
  126. package/documentation/en/mysql.md +682 -0
  127. package/documentation/en/task.md +45 -0
  128. package/documentation/en/test.md +56 -0
  129. package/documentation/en/validate.md +130 -0
  130. package/documentation/zh-cn/mvc.md +66 -24
  131. package/documentation/zh-cn/mysql.md +146 -17
  132. package/package.json +4 -1
  133. package/skills/wok-server-api-rules/SKILL.md +350 -0
  134. package/skills/wok-server-cache/SKILL.md +216 -0
  135. package/skills/wok-server-code-navigation/SKILL.md +153 -0
  136. package/skills/wok-server-config/SKILL.md +200 -0
  137. package/skills/wok-server-getting-started/SKILL.md +123 -0
  138. package/skills/wok-server-getting-started/references/engineering.md +169 -0
  139. package/skills/wok-server-http-client/SKILL.md +164 -0
  140. package/skills/wok-server-i18n/SKILL.md +214 -0
  141. package/skills/wok-server-lock/SKILL.md +144 -0
  142. package/skills/wok-server-log/SKILL.md +218 -0
  143. package/skills/wok-server-mongodb/SKILL.md +235 -0
  144. package/skills/wok-server-mvc/SKILL.md +251 -0
  145. package/skills/wok-server-mvc/references/respond-html.md +157 -0
  146. package/skills/wok-server-mvc/references/sse.md +121 -0
  147. package/skills/wok-server-mvc/references/static-files.md +47 -0
  148. package/skills/wok-server-mvc/references/upload.md +62 -0
  149. package/skills/wok-server-mvc/references/websocket.md +30 -0
  150. package/skills/wok-server-mysql/SKILL.md +388 -0
  151. package/skills/wok-server-mysql/references/multi-datasource.md +76 -0
  152. package/skills/wok-server-mysql/references/version-control.md +22 -0
  153. package/skills/wok-server-task/SKILL.md +158 -0
  154. package/skills/wok-server-validate/SKILL.md +167 -0
  155. package/src/cache/cache.ts +118 -0
  156. package/src/cache/config.ts +53 -0
  157. package/src/cache/index.ts +27 -0
  158. package/src/cache/purge-task.ts +53 -0
  159. package/src/cache/stat.ts +47 -0
  160. package/src/config/convert.ts +27 -0
  161. package/src/config/exception.ts +8 -0
  162. package/src/config/index.ts +92 -0
  163. package/src/http-client/index.ts +202 -0
  164. package/src/i18n/ar.ts +16 -0
  165. package/src/i18n/de.ts +16 -0
  166. package/src/i18n/en-us.ts +16 -0
  167. package/src/i18n/es.ts +16 -0
  168. package/src/i18n/fr.ts +16 -0
  169. package/src/i18n/i18n.ts +230 -0
  170. package/src/i18n/index.ts +50 -0
  171. package/src/i18n/ja.ts +16 -0
  172. package/src/i18n/ko.ts +16 -0
  173. package/src/i18n/msg.ts +50 -0
  174. package/src/i18n/pt.ts +16 -0
  175. package/src/i18n/ru.ts +16 -0
  176. package/src/i18n/tag.ts +18 -0
  177. package/src/i18n/zh-HK.ts +16 -0
  178. package/src/i18n/zh-TW.ts +16 -0
  179. package/src/i18n/zh-cn.ts +16 -0
  180. package/src/index.ts +11 -0
  181. package/src/lock/index.ts +164 -0
  182. package/src/log/config.ts +71 -0
  183. package/src/log/date.ts +19 -0
  184. package/src/log/file.ts +215 -0
  185. package/src/log/index.ts +136 -0
  186. package/src/log/level.ts +29 -0
  187. package/src/log/log.ts +77 -0
  188. package/src/log/store.ts +31 -0
  189. package/src/mongodb/collection.ts +25 -0
  190. package/src/mongodb/config.ts +69 -0
  191. package/src/mongodb/doc.ts +12 -0
  192. package/src/mongodb/exception.ts +8 -0
  193. package/src/mongodb/index.ts +71 -0
  194. package/src/mongodb/manager/base.ts +674 -0
  195. package/src/mongodb/manager/index.ts +80 -0
  196. package/src/mongodb/manager/tx-strict.ts +153 -0
  197. package/src/mongodb/manager/tx.ts +34 -0
  198. package/src/mongodb/migration.ts +66 -0
  199. package/src/mvc/access-log.ts +33 -0
  200. package/src/mvc/config.ts +70 -0
  201. package/src/mvc/exchange.ts +126 -0
  202. package/src/mvc/handler/index.ts +4 -0
  203. package/src/mvc/handler/json.ts +96 -0
  204. package/src/mvc/handler/restful.ts +39 -0
  205. package/src/mvc/handler/sse.ts +90 -0
  206. package/src/mvc/handler/upload.ts +54 -0
  207. package/src/mvc/index.ts +48 -0
  208. package/src/mvc/interceptor.ts +12 -0
  209. package/src/mvc/query.ts +36 -0
  210. package/src/mvc/render/file.ts +148 -0
  211. package/src/mvc/render/html/html.ts +187 -0
  212. package/src/mvc/render/html/index.ts +16 -0
  213. package/src/mvc/render/html/style.ts +1201 -0
  214. package/src/mvc/render/index.ts +4 -0
  215. package/src/mvc/render/json.ts +24 -0
  216. package/src/mvc/render/text.ts +14 -0
  217. package/src/mvc/router.ts +13 -0
  218. package/src/mvc/server.ts +315 -0
  219. package/src/mvc/static/header.ts +86 -0
  220. package/src/mvc/static/index.ts +3 -0
  221. package/src/mvc/static/mime-type.ts +81 -0
  222. package/src/mvc/static/server-cache-config.ts +92 -0
  223. package/src/mvc/static/server-cache.ts +171 -0
  224. package/src/mvc/static/static-handler.ts +445 -0
  225. package/src/mysql/config.ts +130 -0
  226. package/src/mysql/exception.ts +8 -0
  227. package/src/mysql/index.ts +88 -0
  228. package/src/mysql/manager/base.ts +332 -0
  229. package/src/mysql/manager/index.ts +112 -0
  230. package/src/mysql/manager/ops/count.ts +30 -0
  231. package/src/mysql/manager/ops/criteria.ts +446 -0
  232. package/src/mysql/manager/ops/delete.ts +91 -0
  233. package/src/mysql/manager/ops/exist.ts +41 -0
  234. package/src/mysql/manager/ops/find.ts +209 -0
  235. package/src/mysql/manager/ops/index.ts +13 -0
  236. package/src/mysql/manager/ops/insert.ts +158 -0
  237. package/src/mysql/manager/ops/modify.ts +14 -0
  238. package/src/mysql/manager/ops/order-by.ts +58 -0
  239. package/src/mysql/manager/ops/paginate.ts +100 -0
  240. package/src/mysql/manager/ops/query.ts +13 -0
  241. package/src/mysql/manager/ops/update.ts +318 -0
  242. package/src/mysql/manager/ops/upsert.ts +224 -0
  243. package/src/mysql/manager/ops/utils.ts +24 -0
  244. package/src/mysql/manager/tx-strict.ts +138 -0
  245. package/src/mysql/manager/tx.ts +31 -0
  246. package/src/mysql/manager/utils.ts +75 -0
  247. package/src/mysql/migration.ts +149 -0
  248. package/src/mysql/table-info.ts +41 -0
  249. package/src/task/daily.ts +70 -0
  250. package/src/task/fixed-delay.ts +45 -0
  251. package/src/task/fixed-rate.ts +49 -0
  252. package/src/task/index.ts +4 -0
  253. package/src/task/task.ts +70 -0
  254. package/src/validation/exception.ts +27 -0
  255. package/src/validation/index.ts +61 -0
  256. package/src/validation/validator/array.ts +32 -0
  257. package/src/validation/validator/enum.ts +25 -0
  258. package/src/validation/validator/index.ts +11 -0
  259. package/src/validation/validator/length.ts +42 -0
  260. package/src/validation/validator/max-length.ts +33 -0
  261. package/src/validation/validator/max.ts +26 -0
  262. package/src/validation/validator/min-length.ts +31 -0
  263. package/src/validation/validator/min.ts +26 -0
  264. package/src/validation/validator/not-blank.ts +31 -0
  265. package/src/validation/validator/not-null.ts +19 -0
  266. package/src/validation/validator/plain-obj.ts +30 -0
  267. package/src/validation/validator/regexp.ts +32 -0
  268. package/types/cache/cache.d.ts +52 -52
  269. package/types/cache/config.d.ts +32 -32
  270. package/types/cache/index.d.ts +2 -2
  271. package/types/cache/purge-task.d.ts +11 -11
  272. package/types/cache/stat.d.ts +26 -26
  273. package/types/config/convert.d.ts +6 -6
  274. package/types/config/exception.d.ts +7 -7
  275. package/types/config/index.d.ts +25 -25
  276. package/types/http-client/index.d.ts +71 -71
  277. package/types/i18n/ar.d.ts +2 -2
  278. package/types/i18n/de.d.ts +2 -2
  279. package/types/i18n/en-us.d.ts +2 -2
  280. package/types/i18n/es.d.ts +2 -2
  281. package/types/i18n/fr.d.ts +2 -2
  282. package/types/i18n/i18n.d.ts +102 -102
  283. package/types/i18n/index.d.ts +9 -9
  284. package/types/i18n/ja.d.ts +2 -2
  285. package/types/i18n/ko.d.ts +2 -2
  286. package/types/i18n/msg.d.ts +50 -50
  287. package/types/i18n/pt.d.ts +2 -2
  288. package/types/i18n/ru.d.ts +2 -2
  289. package/types/i18n/tag.d.ts +11 -11
  290. package/types/i18n/zh-HK.d.ts +2 -2
  291. package/types/i18n/zh-TW.d.ts +2 -2
  292. package/types/i18n/zh-cn.d.ts +2 -2
  293. package/types/index.d.ts +11 -11
  294. package/types/lock/index.d.ts +64 -64
  295. package/types/log/config.d.ts +35 -35
  296. package/types/log/date.d.ts +2 -2
  297. package/types/log/file.d.ts +13 -13
  298. package/types/log/index.d.ts +53 -53
  299. package/types/log/level.d.ts +14 -14
  300. package/types/log/log.d.ts +40 -40
  301. package/types/log/store.d.ts +19 -19
  302. package/types/mongodb/collection.d.ts +25 -25
  303. package/types/mongodb/config.d.ts +45 -45
  304. package/types/mongodb/doc.d.ts +11 -11
  305. package/types/mongodb/exception.d.ts +7 -7
  306. package/types/mongodb/index.d.ts +29 -29
  307. package/types/mongodb/manager/base.d.ts +188 -188
  308. package/types/mongodb/manager/index.d.ts +38 -38
  309. package/types/mongodb/manager/tx-strict.d.ts +41 -41
  310. package/types/mongodb/manager/tx.d.ts +21 -21
  311. package/types/mongodb/migration.d.ts +12 -12
  312. package/types/mvc/access-log.d.ts +7 -7
  313. package/types/mvc/config.d.ts +42 -42
  314. package/types/mvc/exchange.d.ts +72 -72
  315. package/types/mvc/handler/index.d.ts +4 -3
  316. package/types/mvc/handler/json.d.ts +44 -44
  317. package/types/mvc/handler/restful.d.ts +11 -11
  318. package/types/mvc/handler/sse.d.ts +34 -0
  319. package/types/mvc/handler/upload.d.ts +36 -36
  320. package/types/mvc/index.d.ts +22 -22
  321. package/types/mvc/interceptor.d.ts +11 -11
  322. package/types/mvc/query.d.ts +13 -13
  323. package/types/mvc/render/file.d.ts +10 -10
  324. package/types/mvc/render/html/html.d.ts +98 -98
  325. package/types/mvc/render/html/index.d.ts +11 -11
  326. package/types/mvc/render/html/style.d.ts +1201 -1201
  327. package/types/mvc/render/index.d.ts +4 -4
  328. package/types/mvc/render/json.d.ts +17 -17
  329. package/types/mvc/render/text.d.ts +10 -10
  330. package/types/mvc/router.d.ts +11 -11
  331. package/types/mvc/server.d.ts +90 -90
  332. package/types/mvc/static/header.d.ts +27 -27
  333. package/types/mvc/static/index.d.ts +3 -3
  334. package/types/mvc/static/mime-type.d.ts +2 -2
  335. package/types/mvc/static/server-cache-config.d.ts +30 -30
  336. package/types/mvc/static/server-cache.d.ts +76 -76
  337. package/types/mvc/static/static-handler.d.ts +77 -77
  338. package/types/mysql/config.d.ts +90 -90
  339. package/types/mysql/exception.d.ts +7 -7
  340. package/types/mysql/index.d.ts +16 -16
  341. package/types/mysql/manager/base.d.ts +196 -165
  342. package/types/mysql/manager/index.d.ts +36 -36
  343. package/types/mysql/manager/ops/count.d.ts +13 -13
  344. package/types/mysql/manager/ops/criteria.d.ts +144 -134
  345. package/types/mysql/manager/ops/delete.d.ts +47 -46
  346. package/types/mysql/manager/ops/exist.d.ts +6 -6
  347. package/types/mysql/manager/ops/find.d.ts +87 -86
  348. package/types/mysql/manager/ops/index.d.ts +12 -10
  349. package/types/mysql/manager/ops/insert.d.ts +32 -18
  350. package/types/mysql/manager/ops/modify.d.ts +3 -3
  351. package/types/mysql/manager/ops/order-by.d.ts +38 -0
  352. package/types/mysql/manager/ops/paginate.d.ts +53 -36
  353. package/types/mysql/manager/ops/query.d.ts +3 -3
  354. package/types/mysql/manager/ops/update.d.ts +99 -76
  355. package/types/mysql/manager/ops/upsert.d.ts +36 -0
  356. package/types/mysql/manager/ops/utils.d.ts +5 -5
  357. package/types/mysql/manager/tx-strict.d.ts +36 -36
  358. package/types/mysql/manager/tx.d.ts +15 -15
  359. package/types/mysql/manager/utils.d.ts +17 -17
  360. package/types/mysql/migration.d.ts +8 -8
  361. package/types/mysql/table-info.d.ts +36 -36
  362. package/types/task/daily.d.ts +16 -16
  363. package/types/task/fixed-delay.d.ts +9 -9
  364. package/types/task/fixed-rate.d.ts +9 -9
  365. package/types/task/index.d.ts +4 -4
  366. package/types/task/task.d.ts +34 -34
  367. package/types/validation/exception.d.ts +38 -38
  368. package/types/validation/index.d.ts +32 -32
  369. package/types/validation/validator/array.d.ts +5 -5
  370. package/types/validation/validator/enum.d.ts +8 -8
  371. package/types/validation/validator/index.d.ts +11 -11
  372. package/types/validation/validator/length.d.ts +10 -10
  373. package/types/validation/validator/max-length.d.ts +8 -8
  374. package/types/validation/validator/max.d.ts +7 -7
  375. package/types/validation/validator/min-length.d.ts +6 -6
  376. package/types/validation/validator/min.d.ts +7 -7
  377. package/types/validation/validator/not-blank.d.ts +7 -7
  378. package/types/validation/validator/not-null.d.ts +6 -6
  379. package/types/validation/validator/plain-obj.d.ts +7 -7
  380. package/types/validation/validator/regexp.d.ts +8 -8
@@ -0,0 +1,256 @@
1
+ # Engineering Practices
2
+
3
+ As the program grows in size, we need to split and better organize code files to manage large projects conveniently.
4
+
5
+ The following are recommended practices.
6
+
7
+ ## Directory Structure
8
+
9
+ The recommended approach is to organize by feature rather than by traditional layers (service layer, controller layer). This keeps highly related files together, making them easier to find and better for encapsulation.
10
+
11
+ Suppose there are two business functions: user and tag. Here is the project structure:
12
+
13
+ ```
14
+ Root Directory
15
+ ├── db-migration Database migration files, only needed when using MySQL
16
+ ├── src Source directory
17
+ │ ├── auth Authorization
18
+ │ │ ├── auth.ts Authorization entity configuration
19
+ │ │ ├── auth-interceptor.ts Authorization interceptor
20
+ │ │ ├── create-auth.ts Create authorization endpoint (/auth/create)
21
+ │ │ ├── ccu-task.ts Online user count task
22
+ │ │ └── index.ts Package entry file, exports needed modules
23
+ │ ├── user User business function directory
24
+ │ │ ├── user.ts User entity configuration
25
+ │ │ ├── create-user.ts Create user endpoint (/user/create)
26
+ │ │ ├── delete-user.ts Delete user endpoint (/user/delete)
27
+ │ │ ├── update-user.ts Update user endpoint (/user/update)
28
+ │ │ └── index.ts Package entry file, exports needed modules
29
+ │ ├── tag Tag business function directory
30
+ │ │ ├── tag.ts Tag entity configuration
31
+ │ │ ├── create-tag.ts Create tag endpoint (/tag/create)
32
+ │ │ ├── delete-tag.ts Delete tag endpoint (/tag/delete)
33
+ │ │ └── index.ts Package entry file, exports needed modules
34
+ │ ├── exception.ts Global exceptions
35
+ │ └── main.ts Entry file, starts server, configures routes
36
+ ├── .env Development environment variable configuration
37
+ ├── package.json
38
+ ├── tsconfig.json
39
+ └── .gitignore
40
+ ```
41
+
42
+ ## File Description
43
+
44
+ The exception.ts file contains custom business exceptions and exception handling interceptors.
45
+
46
+ ```ts
47
+ /**
48
+ * Custom business exception.
49
+ */
50
+ export class BusinessException {
51
+ constructor(
52
+ /**
53
+ * Message.
54
+ */
55
+ readonly message: string,
56
+ /**
57
+ * Custom status code, default 400
58
+ */
59
+ readonly status?: number
60
+ ) {}
61
+ }
62
+
63
+ /**
64
+ * Global exception interceptor that handles specific exceptions and provides appropriate response messages.
65
+ * @param exchange
66
+ * @param next
67
+ */
68
+ export async function globalErrorInterceptor(
69
+ exchange: ServerExchange,
70
+ next: () => Promise<void>
71
+ ): Promise<void> {
72
+ try {
73
+ await next()
74
+ } catch (e) {
75
+ // Handle custom business exceptions
76
+ if (e instanceof BusinessException) {
77
+ const status = typeof e.status === 'number' ? e.status : 400
78
+ const message = e.message || ''
79
+ exchange.respondErrMsg(message, status)
80
+ return
81
+ }
82
+ // Handle validation exceptions
83
+ if (e instanceof ValidationException) {
84
+ exchange.respondErrMsg(`${e.propertyPath}: ${e.errMsg}`, 400)
85
+ return
86
+ }
87
+ // Other exceptions are thrown directly, framework responds with 500 status code by default
88
+ throw e
89
+ }
90
+ }
91
+ ```
92
+
93
+ Using custom business exceptions to abort request processing when business logic cannot proceed. Transactions will also rollback when exceptions occur during processing. This is the recommended approach.
94
+
95
+ main.ts example:
96
+
97
+ ```ts
98
+ import { createAuth, authInterceptor, ccuTask } from './auth'
99
+ import { createUser, updateUser, deleteUser } from './user'
100
+ import { createTag, deleteTag } from './tag'
101
+ import { globalErrorInterceptor } from './exception'
102
+
103
+ async function main() {
104
+ // Override Date prototype to serialize dates as numbers
105
+ // Optional, typically done for internationalization
106
+ Date.prototype.toJSON = function () {
107
+ return this.getTime() as any
108
+ }
109
+ // Activate MySQL
110
+ await enableMysql()
111
+ // Start server
112
+ await startWebServer({
113
+ // Static file configuration
114
+ static: {
115
+ // Frontend files
116
+ '/': { dir: 'fe', cacheAge: 600 }
117
+ },
118
+ // If there are many endpoints, it's recommended to write this configuration separately
119
+ // or split further into a separate router directory
120
+ // However, route configuration must be centralized and cannot be placed in individual business function directories
121
+ // Centralization makes it easier to find
122
+ routers: {
123
+ '/auth/create': createAuth,
124
+ '/user/create': createUser,
125
+ '/user/update': updateUser,
126
+ '/user/delete': deleteUser,
127
+ '/tag/create': createTag,
128
+ '/tag/delete': deleteTag
129
+ },
130
+ // Interceptors
131
+ interceptors: [globalErrorInterceptor, authInterceptor]
132
+ })
133
+ // Periodic task
134
+ // Count online users every 60 seconds
135
+ scheduleWithFixedDelay(60, 60, ccuTask)
136
+ }
137
+
138
+ main().catch(console.error)
139
+ ```
140
+
141
+ Taking the user function as an example, let's explain entity configuration and endpoint writing.
142
+
143
+ user/user.ts file example:
144
+
145
+ ```ts
146
+ import { Table } from 'wok-server'
147
+
148
+ /**
149
+ * User
150
+ */
151
+ export interface User {
152
+ id: string
153
+ /**
154
+ * Code.
155
+ */
156
+ code: string
157
+ /**
158
+ * Nickname
159
+ */
160
+ nickname: string
161
+ /**
162
+ * Password
163
+ */
164
+ pwd: string
165
+ /**
166
+ * Status.
167
+ */
168
+ status: 'ACTIVATED' | 'DISABLED'
169
+ /**
170
+ * Create time.
171
+ */
172
+ create_at?: Date
173
+ /**
174
+ * Update time.
175
+ */
176
+ update_at?: Date
177
+ }
178
+
179
+ /**
180
+ * User table
181
+ */
182
+ export const tableUser: Table<User> = {
183
+ tableName: 'user',
184
+ id: 'id',
185
+ columns: ['code', 'nickname', 'pwd', 'status'],
186
+ createdDate: {
187
+ type: 'date',
188
+ column: 'create_at'
189
+ },
190
+ updatedDate: {
191
+ type: 'date',
192
+ column: 'update_at'
193
+ }
194
+ }
195
+ ```
196
+
197
+ The user.ts file contains the entity type declaration and table configuration information. The example above is for MySQL; MongoDB is slightly different.
198
+
199
+ Our recommendation is to write each endpoint in a separate file, putting all request and response information related to the endpoint in the file, and only exporting the endpoint handler function.
200
+
201
+ user/create-user.ts example:
202
+
203
+ ```ts
204
+ import { createJsonHandler, getMysqlManager, notBlank, length } from 'wok-server'
205
+ import { User, tableUser } from './user'
206
+
207
+ /**
208
+ * Request form information
209
+ */
210
+ interface Form {
211
+ /**
212
+ * Code.
213
+ */
214
+ code: string
215
+ /**
216
+ * Nickname
217
+ */
218
+ nickname: string
219
+ /**
220
+ * Password
221
+ */
222
+ pwd: string
223
+ }
224
+ /**
225
+ * Response information
226
+ */
227
+ interface Resp {
228
+ /**
229
+ * User id
230
+ */
231
+ id: string
232
+ }
233
+
234
+ /**
235
+ * Create user endpoint /user/create
236
+ */
237
+ export const createUser = createJsonHandler<Form, Resp>({
238
+ // Validation
239
+ validation: {
240
+ code: [notBlank(), length({ max: 64 })],
241
+ nickname: [notBlank(), length({ max: 64 })],
242
+ pwd: [notBlank(), length({ max: 20 })]
243
+ },
244
+ // Business handling
245
+ async handle(body, exchange) {
246
+ const manager = getMysqlManager()
247
+ if (await manager.existsBy(tableUser, { code: body.code })) {
248
+ // Throw exception to abort processing
249
+ // Exception will be handled by interceptor and responded
250
+ throw new BusinessException('Code already exists')
251
+ }
252
+ const newUser = await manager.insert(tableUser, body)
253
+ return { id: newUser.id }
254
+ }
255
+ })
256
+ ```
@@ -0,0 +1,32 @@
1
+ # HTTP Client
2
+
3
+ The HTTP client is an HTTP request tool built on top of Node.js's built-in http and https modules, providing three functions.
4
+
5
+ | Function | Description |
6
+ | :--------- | :---------------------------------------------- |
7
+ | doRequest | Generic HTTP request with customizable options |
8
+ | postJson | Send POST request and get JSON response |
9
+ | getJson | Send GET request and get JSON response |
10
+
11
+ ## Usage Examples
12
+
13
+ ```ts
14
+ // GET request for JSON
15
+ const list = await getJson<User[]>({
16
+ url: '/users'
17
+ })
18
+
19
+ // POST request for JSON
20
+ const res = await postJson<Result>({
21
+ url: '/data/save',
22
+ body: { name: 'jack', age: 33 }
23
+ })
24
+
25
+ // Use doRequest with more custom options
26
+ await doRequest({
27
+ url: '/users/001',
28
+ method: 'DELETE',
29
+ timeout: 5000,
30
+ followRedirect: true
31
+ })
32
+ ```
@@ -0,0 +1,143 @@
1
+ # Internationalization
2
+
3
+ The internationalization component provides support for multilingual environments, allows extending new internationalization content, and automatically maintains language consistency.
4
+
5
+ The i18n object is global. During request processing with asynchronous operations, you can use binding to maintain consistent language throughout a single request.
6
+
7
+ ## No Internationalization Handling
8
+
9
+ By default, the internationalization component automatically updates the language based on the environment. However, when using containers or virtual machines, the image may default to English.
10
+
11
+ If the project doesn't need internationalization and must ensure the framework's prompt messages are in Chinese, you can set the environment variable LANG in the program.
12
+
13
+ ```ts
14
+ // Change environment variable LANG via process to specify Simplified Chinese
15
+ // Must be written before framework import
16
+ process.env.LANG = 'zh-CN'
17
+ // After changing the variable, then import
18
+ import {...} from 'wok-server'
19
+ ```
20
+
21
+ If using containers, you can directly set the environment variable for the container, eliminating the need to modify code.
22
+
23
+ ## Usage Examples
24
+
25
+ ```ts
26
+ // Get i18n object through getI18n function
27
+ const i18n = getI18n()
28
+ // getLang method gets current language
29
+ const currentLang = i18n.getLang()
30
+ // setLang method switches language, returns boolean indicating success
31
+ // Only supported language tags can be switched successfully
32
+ i18n.setLang('en')
33
+ // buildMsg method builds message based on current language
34
+ // First parameter is key (with type constraints), followed by 0 to multiple template parameters
35
+ // More details in the configuration section below
36
+ const msg = i18n.buildMsg('validate-err-max', '7')
37
+ ```
38
+
39
+ ## Language Tags and Matching Rules
40
+
41
+ Currently only language + region format is supported, e.g., en-US, where en represents English and US represents the United States. The region is optional, and you can configure just the language, such as en. Matching is case-insensitive.
42
+
43
+ If only "en-US" is configured but the language is set to "en-GB", it will still succeed. This is because during matching, if no exact language and region match is found, it looks for the language default (i.e., "en"). If the default is also not found, it finds the first configuration from the same language, ultimately using "en-US".
44
+
45
+ If matching fails when switching languages, the switch is not performed and the language remains unchanged. **The default language is not used**. The default language is always en, and any extended i18n object must have English as the default for consistency and to ensure proper program operation.
46
+
47
+ However, during program initialization, the language is automatically switched based on the current environment variables. If LANG or LC_CTYPE variables are set, the switch is performed accordingly. Extended internationalization content needs to be handled separately. See the extension section below for details.
48
+
49
+ ## Configure New Languages
50
+
51
+ The following languages are built into the framework:
52
+
53
+ | Language Tag | Language |
54
+ | :----------- | :--------------- |
55
+ | en | English (default)|
56
+ | zh-CN | Simplified Chinese|
57
+ | zh-TW | Traditional Chinese (Taiwan)|
58
+ | zh-HK | Traditional Chinese (Hong Kong)|
59
+ | ja | Japanese |
60
+ | ko | Korean |
61
+ | ru | Russian |
62
+ | es | Spanish |
63
+ | de | German |
64
+ | fr | French |
65
+ | ar | Arabic |
66
+ | pt | Portuguese |
67
+
68
+ If the language you need is not built-in, you need to configure it yourself. Here is example code:
69
+
70
+ ```ts
71
+ const i18n = getI18n()
72
+ // Call setMsgs to configure language. First parameter is language tag, second is message templates
73
+ i18n.setMsgs('ja', {
74
+ 'validate-err-array': '値が配列ではありません',
75
+ 'validate-err-enum': '値は {} の中のいずれかでなければなりません',
76
+ 'validate-err-numer': '値が数字ではありません',
77
+ 'validate-err-max': '{} 以下である必要があります',
78
+ 'validate-err-min': '{} 以上である必要があります',
79
+ 'validate-err-empty': '空であってはいけません',
80
+ 'validate-err-string': '値が文字列のタイプではありません',
81
+ 'validate-err-incorrect-format': '形式が正しくありません',
82
+ 'validate-err-no-length': 'length属性が見当たりません',
83
+ 'validate-err-length-not-number': 'lengthプロパティは数値ではありません',
84
+ 'validate-err-min-length': '長さは {} 以上でなければりません',
85
+ 'validate-err-max-length': '長さは {} 以下でなければなりません'
86
+ })
87
+ // After setting, you can successfully switch to the custom language
88
+ i18n.setLang('ja')
89
+ ```
90
+
91
+ ## Extend New Content
92
+
93
+ The above are the framework's built-in internationalization contents. In actual project development, there are many business-related internationalization requirements. You can extend new content based on the framework's i18n object. The extended object will maintain the same language as the global i18n object. When you need to change the language, simply call the global i18n object's setLang method.
94
+
95
+ ```ts
96
+ // Get i18n object
97
+ const i18n = getI18n()
98
+ // New language template definition
99
+ interface ExtMsgs {
100
+ hello: string
101
+ world: string
102
+ }
103
+ // Extend new content. Parameter is English template, always use English as default (explained earlier)
104
+ // Returns an I18n type object with methods basically the same as the global i18n object, except without the extend method
105
+ const extI18n = i18n.extend<ExtMsgs>({ hello: 'hello', world: 'world' })
106
+ // Add Chinese to extended content
107
+ extI18n.setMsgs('zh-cn', { hello: '你好', world: '世界' })
108
+
109
+ // When the global i18n object changes language, extI18n also changes
110
+ // In actual development, you can switch to the appropriate language after extension
111
+ i18n.setLang('zh')
112
+
113
+ i18n.getLang() // zh
114
+ extI18n.getLang() // zh
115
+ ```
116
+
117
+ In actual development, you can export the extI18n object for use by other modules.
118
+
119
+ Note that for new language templates, values must all be string type, otherwise an error will be thrown. Template content supports 0 to multiple placeholders. For example, `{accountNotExist:"Account {} does not exist"}`, calling `buildMsg('accountNotExist','jack')` returns `"Account jack does not exist"`.
120
+
121
+ ## Bind Language
122
+
123
+ Since the i18n object is global and shared, during request processing with asynchronous operations, it's possible that one request changes the language, executes an async operation, then another request changes the language again. When the async operation completes, the language may be incorrect.
124
+
125
+ You can use the language binding feature in this case.
126
+
127
+ ```ts
128
+ // Handle request, simplified demonstration, see MVC chapter for details
129
+ async function handleReq(exchange: RouterExchange): Promise<void> {
130
+ // Headers, type is IncomingHttpHeaders, native type from Node.js http module
131
+ const headers = exchange.headers
132
+ // Bind to get a language-fixed i18n object. extI18n is the business internationalization object extended in the above demonstration
133
+ // bindByRequest generates a fixed-language i18n object based on the 'accept-language' header value
134
+ const boundI18n = extI18n.bindByRequest(headers)
135
+ await query1()
136
+ await query2()
137
+ await query3()
138
+ // Built messages are always related to the request's accepted language
139
+ const hello = boundI18n.buildMsg('hello')
140
+ }
141
+ ```
142
+
143
+ In addition, the i18n object has a switchByRequest method, which also takes IncomingHttpHeaders as a parameter and switches the language based on the headers.
@@ -1 +1,25 @@
1
1
  # node-server
2
+
3
+ A Node.js backend development framework that is simple, easy to use, and has sufficient functionality. Developed with TypeScript, it has complete type definitions and high development efficiency.
4
+
5
+ ## Documentation Conventions
6
+
7
+ All demonstration code in the documentation uses TypeScript. It is also recommended to use the framework only in TypeScript projects, as many features depend on type inference.
8
+
9
+ The documentation does not list every option's details, as this would be too much work. However, it will provide as many usage examples as possible. For specific parameters, you can use your editor's documentation preview and jump functions to view the definition files.
10
+
11
+ ## Features
12
+
13
+ - [Internationalization](./i18n.md)
14
+ - [Validation](./validate.md)
15
+ - [Configuration](./config.md)
16
+ - [Logging](./log.md)
17
+ - [Cache](./cache.md)
18
+ - [MySQL](./mysql.md)
19
+ - [MongoDB](./mongodb.md)
20
+ - [MVC](./mvc.md)
21
+ - [Task Scheduling](./task.md)
22
+ - [Lock](./lock.md)
23
+ - [HTTP Client](./http-client.md)
24
+ - [Unit Testing](./test.md)
25
+ - [Engineering Practices](./engineering.md)
@@ -0,0 +1,51 @@
1
+ # Lock
2
+
3
+ Locks coordinate multiple asynchronous operation flows, allowing these flows to execute sequentially. This is very useful in concurrent request scenarios. A request may have many asynchronous operations during processing. Under concurrent conditions, operations from different requests may interleave. If there are modification operations, errors may occur, such as inventory reduction and lottery draws.
4
+
5
+ ## Usage
6
+
7
+ Use the getLockManager function to get the lock manager object, and call the tryLock method to attempt to acquire a lock and execute logic upon successful acquisition.
8
+
9
+ Simple scenario example code:
10
+
11
+ ```ts
12
+ import { getLockManager } from 'wok-server'
13
+
14
+ interface Form {
15
+ id: string
16
+ quantity: number
17
+ }
18
+ // Create JSON handler, simulate inventory reduction request
19
+ createJsonHandler<Form>({
20
+ validation: {
21
+ id: [notBlank()],
22
+ quantity: [notNull(), min(1), max(10)]
23
+ },
24
+ async handle(body, exchange) {
25
+ const lock = getLockManager()
26
+ const res = lock.tryLock({
27
+ // Lock identifier, same identifiers create competition
28
+ key: `reduce-quantity-${body.id}`,
29
+ // Maximum wait time in seconds, tryLock returns false if lock not acquired within 2 seconds
30
+ waitSeconds: 2,
31
+ // Lock expiration time, set to hold lock for maximum 600 seconds to prevent deadlock
32
+ // If timeout occurs, other processes can acquire the lock regardless of whether run function completes
33
+ expiresInSeconds: 600,
34
+ // Execution function, executed if lock acquired successfully
35
+ // In concurrent request scenarios, requests that don't acquire the lock wait and execute in queue
36
+ async run() {
37
+ const product = await findProductById(body.id)
38
+ if (product.quantity < body.quantity) {
39
+ throw new BusinessException('Insufficient inventory')
40
+ }
41
+ await reduceQuantity(body.id, body.quantity)
42
+ }
43
+ })
44
+ // tryLock returns boolean indicating whether lock was acquired successfully
45
+ // If lock not acquired, provide business prompt
46
+ if (!res) {
47
+ throw new BusinessException('System busy, please try again later')
48
+ }
49
+ }
50
+ })
51
+ ```
@@ -0,0 +1,109 @@
1
+ # Logging
2
+
3
+ Logging is used to record information, supporting simple level control and file writing functionality.
4
+
5
+ ## Environment Variables
6
+
7
+ | Environment Variable | Default | Description |
8
+ | :--------------------- | :------ | :-------------------------------------------------------------------------- |
9
+ | LOG_LEVEL | info | Log level. Logs below the set level will not be output. Values: DEBUG, INFO, WARN, ERROR |
10
+ | LOG_FILE | false | true or false, indicating whether to enable file logging |
11
+ | LOG_FILE_MAX_DAYS | 30 | Number of days to keep log files |
12
+ | LOG_FILE_DIR | logs | Log file storage path, supports relative and absolute paths. Relative paths are relative to the process execution directory |
13
+ | LOG_CONSOLE | true | Whether to output logs to console, added in version 0.5 |
14
+ | LOG_FORMAT | text | Output log format, can be set to json or text, added in version 0.5. Note: console always outputs text |
15
+
16
+ ## Usage
17
+
18
+ Get the logger object through getLogger() function, then call its methods to output logs.
19
+
20
+ ```ts
21
+ const logger = getLogger()
22
+
23
+ logger.info('Normal log message')
24
+
25
+ const err = new Error('Error message test')
26
+ logger.error('Error log output', err)
27
+
28
+ if (logger.isDebugEnabled()) {
29
+ logger.debug(`Debug log output, args: ${JSON.stringify(args)}`)
30
+ }
31
+ ```
32
+
33
+ ## Check if a Log Level is Supported
34
+
35
+ The logger object provides isDebugEnabled, isInfoEnabled, isWarnEnabled, and isErrorEnabled methods to check if a log level is supported.
36
+
37
+ ```ts
38
+ if (logger.isDebugEnabled()) {
39
+ logger.debug('Debug log output')
40
+ }
41
+ ```
42
+
43
+ These methods determine whether the current level is supported before processing. If not supported, the log content is not built. In some cases, this avoids unnecessary overhead of building log messages.
44
+
45
+ ## Add Prefix to Logs
46
+
47
+ Starting from version 0.5, the getLogger function supports adding a prefix. For example:
48
+
49
+ ```ts
50
+ const logger = getLogger('my-module')
51
+ ```
52
+
53
+ This adds the prefix `[my-module]` to output logs, making it easier to distinguish logs from different modules.
54
+
55
+ For example, the default log without prefix is:
56
+
57
+ ```
58
+ [2024/08/19 16:27:18.214][INFO]Mysql migration
59
+ ```
60
+
61
+ With prefix added:
62
+
63
+ ```
64
+ [2024/08/19 16:27:18.214][INFO][my-module]Mysql migration
65
+ ```
66
+
67
+ ## Custom Log Storage
68
+
69
+ The setLogStore function allows customizing log storage. Once set, it overrides file storage. Even if file logging is enabled, logs will not be output to files.
70
+
71
+ Starting from version 0.5, logs are structured. The storage function parameters are log objects and configuration information, rather than a string.
72
+
73
+ ```ts
74
+ setLogStore((log: Log, config: LogConfig) => {
75
+ // log type is Log
76
+ // config type is LogConfig
77
+ // You can store log content in message queues or independent file storage systems as needed
78
+ messageQueue.push(log)
79
+ })
80
+ ```
81
+
82
+ Log definition:
83
+
84
+ ```ts
85
+ export interface Log {
86
+ /**
87
+ * Log time
88
+ */
89
+ time: Date
90
+ /**
91
+ * Log level
92
+ */
93
+ level: LogLevel
94
+ /**
95
+ * Log content
96
+ */
97
+ content: string
98
+ /**
99
+ * Error information
100
+ */
101
+ error?: any
102
+ /**
103
+ * Prefix information
104
+ */
105
+ prefix?: string
106
+ }
107
+ ```
108
+
109
+ LogConfig type contains the environment variable configuration information mentioned earlier, used to determine how to handle logs.