@signal24/dk-server-foundation 26.213.615

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 (666) hide show
  1. package/.gitattributes +2 -0
  2. package/.gitlab-ci.yml +49 -0
  3. package/.oxlintrc.json +40 -0
  4. package/.prettierignore +3 -0
  5. package/.prettierrc.json +15 -0
  6. package/.serena/project.yml +111 -0
  7. package/.vscode/launch.json +15 -0
  8. package/.vscode/settings.json +12 -0
  9. package/.yarnrc.yml +5 -0
  10. package/CLAUDE.md +279 -0
  11. package/LICENSE +21 -0
  12. package/README.md +439 -0
  13. package/TEST_MIGRATION_GUIDE.md +348 -0
  14. package/dist/resources/proto/generated/test/test.d.ts +224 -0
  15. package/dist/resources/proto/generated/test/test.d.ts.map +1 -0
  16. package/dist/resources/proto/generated/test/test.js +2376 -0
  17. package/dist/resources/proto/generated/test/test.js.map +1 -0
  18. package/dist/src/app/base.d.ts +37 -0
  19. package/dist/src/app/base.d.ts.map +1 -0
  20. package/dist/src/app/base.js +244 -0
  21. package/dist/src/app/base.js.map +1 -0
  22. package/dist/src/app/config.d.ts +91 -0
  23. package/dist/src/app/config.d.ts.map +1 -0
  24. package/dist/src/app/config.js +33 -0
  25. package/dist/src/app/config.js.map +1 -0
  26. package/dist/src/app/config.loader.d.ts +14 -0
  27. package/dist/src/app/config.loader.d.ts.map +1 -0
  28. package/dist/src/app/config.loader.js +67 -0
  29. package/dist/src/app/config.loader.js.map +1 -0
  30. package/dist/src/app/const.d.ts +3 -0
  31. package/dist/src/app/const.d.ts.map +1 -0
  32. package/dist/src/app/const.js +6 -0
  33. package/dist/src/app/const.js.map +1 -0
  34. package/dist/src/app/dev.d.ts +6 -0
  35. package/dist/src/app/dev.d.ts.map +1 -0
  36. package/dist/src/app/dev.js +78 -0
  37. package/dist/src/app/dev.js.map +1 -0
  38. package/dist/src/app/index.d.ts +7 -0
  39. package/dist/src/app/index.d.ts.map +1 -0
  40. package/dist/src/app/index.js +12 -0
  41. package/dist/src/app/index.js.map +1 -0
  42. package/dist/src/app/openapi.d.ts +4 -0
  43. package/dist/src/app/openapi.d.ts.map +1 -0
  44. package/dist/src/app/openapi.js +6 -0
  45. package/dist/src/app/openapi.js.map +1 -0
  46. package/dist/src/app/resolver.d.ts +11 -0
  47. package/dist/src/app/resolver.d.ts.map +1 -0
  48. package/dist/src/app/resolver.js +60 -0
  49. package/dist/src/app/resolver.js.map +1 -0
  50. package/dist/src/app/shutdown.d.ts +12 -0
  51. package/dist/src/app/shutdown.d.ts.map +1 -0
  52. package/dist/src/app/shutdown.js +63 -0
  53. package/dist/src/app/shutdown.js.map +1 -0
  54. package/dist/src/app/state.d.ts +16 -0
  55. package/dist/src/app/state.d.ts.map +1 -0
  56. package/dist/src/app/state.js +12 -0
  57. package/dist/src/app/state.js.map +1 -0
  58. package/dist/src/auth/index.d.ts +3 -0
  59. package/dist/src/auth/index.d.ts.map +1 -0
  60. package/dist/src/auth/index.js +6 -0
  61. package/dist/src/auth/index.js.map +1 -0
  62. package/dist/src/auth/jwt.d.ts +76 -0
  63. package/dist/src/auth/jwt.d.ts.map +1 -0
  64. package/dist/src/auth/jwt.js +218 -0
  65. package/dist/src/auth/jwt.js.map +1 -0
  66. package/dist/src/auth/provider.d.ts +15 -0
  67. package/dist/src/auth/provider.d.ts.map +1 -0
  68. package/dist/src/auth/provider.js +50 -0
  69. package/dist/src/auth/provider.js.map +1 -0
  70. package/dist/src/cli/dksf-dev.d.ts +3 -0
  71. package/dist/src/cli/dksf-dev.d.ts.map +1 -0
  72. package/dist/src/cli/dksf-dev.js +359 -0
  73. package/dist/src/cli/dksf-dev.js.map +1 -0
  74. package/dist/src/cli/dksf-gen-proto.d.ts +3 -0
  75. package/dist/src/cli/dksf-gen-proto.d.ts.map +1 -0
  76. package/dist/src/cli/dksf-gen-proto.js +164 -0
  77. package/dist/src/cli/dksf-gen-proto.js.map +1 -0
  78. package/dist/src/cli/dksf-install.d.ts +3 -0
  79. package/dist/src/cli/dksf-install.d.ts.map +1 -0
  80. package/dist/src/cli/dksf-install.js +10 -0
  81. package/dist/src/cli/dksf-install.js.map +1 -0
  82. package/dist/src/cli/dksf-test.d.ts +3 -0
  83. package/dist/src/cli/dksf-test.d.ts.map +1 -0
  84. package/dist/src/cli/dksf-test.js +91 -0
  85. package/dist/src/cli/dksf-test.js.map +1 -0
  86. package/dist/src/cli/dksf-update.d.ts +3 -0
  87. package/dist/src/cli/dksf-update.d.ts.map +1 -0
  88. package/dist/src/cli/dksf-update.js +86 -0
  89. package/dist/src/cli/dksf-update.js.map +1 -0
  90. package/dist/src/database/common.d.ts +84 -0
  91. package/dist/src/database/common.d.ts.map +1 -0
  92. package/dist/src/database/common.js +380 -0
  93. package/dist/src/database/common.js.map +1 -0
  94. package/dist/src/database/dialect.d.ts +10 -0
  95. package/dist/src/database/dialect.d.ts.map +1 -0
  96. package/dist/src/database/dialect.js +56 -0
  97. package/dist/src/database/dialect.js.map +1 -0
  98. package/dist/src/database/entity.d.ts +62 -0
  99. package/dist/src/database/entity.d.ts.map +1 -0
  100. package/dist/src/database/entity.js +198 -0
  101. package/dist/src/database/entity.js.map +1 -0
  102. package/dist/src/database/index.d.ts +8 -0
  103. package/dist/src/database/index.d.ts.map +1 -0
  104. package/dist/src/database/index.js +15 -0
  105. package/dist/src/database/index.js.map +1 -0
  106. package/dist/src/database/migration/MigrationResetCommand.d.ts +11 -0
  107. package/dist/src/database/migration/MigrationResetCommand.d.ts.map +1 -0
  108. package/dist/src/database/migration/MigrationResetCommand.js +149 -0
  109. package/dist/src/database/migration/MigrationResetCommand.js.map +1 -0
  110. package/dist/src/database/migration/MigrationRunCommand.d.ts +11 -0
  111. package/dist/src/database/migration/MigrationRunCommand.d.ts.map +1 -0
  112. package/dist/src/database/migration/MigrationRunCommand.js +118 -0
  113. package/dist/src/database/migration/MigrationRunCommand.js.map +1 -0
  114. package/dist/src/database/migration/characters.d.ts +14 -0
  115. package/dist/src/database/migration/characters.d.ts.map +1 -0
  116. package/dist/src/database/migration/characters.js +56 -0
  117. package/dist/src/database/migration/characters.js.map +1 -0
  118. package/dist/src/database/migration/create/MigrationCreateCommand.d.ts +11 -0
  119. package/dist/src/database/migration/create/MigrationCreateCommand.d.ts.map +1 -0
  120. package/dist/src/database/migration/create/MigrationCreateCommand.js +104 -0
  121. package/dist/src/database/migration/create/MigrationCreateCommand.js.map +1 -0
  122. package/dist/src/database/migration/create/comparator.d.ts +3 -0
  123. package/dist/src/database/migration/create/comparator.d.ts.map +1 -0
  124. package/dist/src/database/migration/create/comparator.js +408 -0
  125. package/dist/src/database/migration/create/comparator.js.map +1 -0
  126. package/dist/src/database/migration/create/db-reader.d.ts +5 -0
  127. package/dist/src/database/migration/create/db-reader.d.ts.map +1 -0
  128. package/dist/src/database/migration/create/db-reader.js +473 -0
  129. package/dist/src/database/migration/create/db-reader.js.map +1 -0
  130. package/dist/src/database/migration/create/ddl-generator.d.ts +3 -0
  131. package/dist/src/database/migration/create/ddl-generator.d.ts.map +1 -0
  132. package/dist/src/database/migration/create/ddl-generator.js +725 -0
  133. package/dist/src/database/migration/create/ddl-generator.js.map +1 -0
  134. package/dist/src/database/migration/create/entity-reader.d.ts +4 -0
  135. package/dist/src/database/migration/create/entity-reader.d.ts.map +1 -0
  136. package/dist/src/database/migration/create/entity-reader.js +408 -0
  137. package/dist/src/database/migration/create/entity-reader.js.map +1 -0
  138. package/dist/src/database/migration/create/file-generator.d.ts +2 -0
  139. package/dist/src/database/migration/create/file-generator.d.ts.map +1 -0
  140. package/dist/src/database/migration/create/file-generator.js +55 -0
  141. package/dist/src/database/migration/create/file-generator.js.map +1 -0
  142. package/dist/src/database/migration/create/prompt.d.ts +4 -0
  143. package/dist/src/database/migration/create/prompt.d.ts.map +1 -0
  144. package/dist/src/database/migration/create/prompt.js +55 -0
  145. package/dist/src/database/migration/create/prompt.js.map +1 -0
  146. package/dist/src/database/migration/create/schema-model.d.ts +109 -0
  147. package/dist/src/database/migration/create/schema-model.d.ts.map +1 -0
  148. package/dist/src/database/migration/create/schema-model.js +24 -0
  149. package/dist/src/database/migration/create/schema-model.js.map +1 -0
  150. package/dist/src/database/migration/helpers.d.ts +2 -0
  151. package/dist/src/database/migration/helpers.d.ts.map +1 -0
  152. package/dist/src/database/migration/helpers.js +8 -0
  153. package/dist/src/database/migration/helpers.js.map +1 -0
  154. package/dist/src/database/migration/index.d.ts +9 -0
  155. package/dist/src/database/migration/index.d.ts.map +1 -0
  156. package/dist/src/database/migration/index.js +43 -0
  157. package/dist/src/database/migration/index.js.map +1 -0
  158. package/dist/src/database/migration/migration.entity.d.ts +8 -0
  159. package/dist/src/database/migration/migration.entity.d.ts.map +1 -0
  160. package/dist/src/database/migration/migration.entity.js +16 -0
  161. package/dist/src/database/migration/migration.entity.js.map +1 -0
  162. package/dist/src/database/mysql.d.ts +16 -0
  163. package/dist/src/database/mysql.d.ts.map +1 -0
  164. package/dist/src/database/mysql.js +140 -0
  165. package/dist/src/database/mysql.js.map +1 -0
  166. package/dist/src/database/postgres.d.ts +16 -0
  167. package/dist/src/database/postgres.d.ts.map +1 -0
  168. package/dist/src/database/postgres.js +91 -0
  169. package/dist/src/database/postgres.js.map +1 -0
  170. package/dist/src/database/types.d.ts +21 -0
  171. package/dist/src/database/types.d.ts.map +1 -0
  172. package/dist/src/database/types.js +27 -0
  173. package/dist/src/database/types.js.map +1 -0
  174. package/dist/src/health/health.module.d.ts +6 -0
  175. package/dist/src/health/health.module.d.ts.map +1 -0
  176. package/dist/src/health/health.module.js +32 -0
  177. package/dist/src/health/health.module.js.map +1 -0
  178. package/dist/src/health/healthcheck.controller.d.ts +10 -0
  179. package/dist/src/health/healthcheck.controller.d.ts.map +1 -0
  180. package/dist/src/health/healthcheck.controller.js +30 -0
  181. package/dist/src/health/healthcheck.controller.js.map +1 -0
  182. package/dist/src/health/healthcheck.service.d.ts +8 -0
  183. package/dist/src/health/healthcheck.service.d.ts.map +1 -0
  184. package/dist/src/health/healthcheck.service.js +20 -0
  185. package/dist/src/health/healthcheck.service.js.map +1 -0
  186. package/dist/src/health/index.d.ts +3 -0
  187. package/dist/src/health/index.d.ts.map +1 -0
  188. package/dist/src/health/index.js +6 -0
  189. package/dist/src/health/index.js.map +1 -0
  190. package/dist/src/helpers/async/context.d.ts +11 -0
  191. package/dist/src/helpers/async/context.d.ts.map +1 -0
  192. package/dist/src/helpers/async/context.js +75 -0
  193. package/dist/src/helpers/async/context.js.map +1 -0
  194. package/dist/src/helpers/async/process.d.ts +16 -0
  195. package/dist/src/helpers/async/process.d.ts.map +1 -0
  196. package/dist/src/helpers/async/process.js +44 -0
  197. package/dist/src/helpers/async/process.js.map +1 -0
  198. package/dist/src/helpers/async/promise.d.ts +5 -0
  199. package/dist/src/helpers/async/promise.d.ts.map +1 -0
  200. package/dist/src/helpers/async/promise.js +27 -0
  201. package/dist/src/helpers/async/promise.js.map +1 -0
  202. package/dist/src/helpers/data/array.d.ts +3 -0
  203. package/dist/src/helpers/data/array.d.ts.map +1 -0
  204. package/dist/src/helpers/data/array.js +17 -0
  205. package/dist/src/helpers/data/array.js.map +1 -0
  206. package/dist/src/helpers/data/objects.d.ts +12 -0
  207. package/dist/src/helpers/data/objects.d.ts.map +1 -0
  208. package/dist/src/helpers/data/objects.js +75 -0
  209. package/dist/src/helpers/data/objects.js.map +1 -0
  210. package/dist/src/helpers/data/serialization.d.ts +4 -0
  211. package/dist/src/helpers/data/serialization.d.ts.map +1 -0
  212. package/dist/src/helpers/data/serialization.js +15 -0
  213. package/dist/src/helpers/data/serialization.js.map +1 -0
  214. package/dist/src/helpers/data/transformer.d.ts +13 -0
  215. package/dist/src/helpers/data/transformer.d.ts.map +1 -0
  216. package/dist/src/helpers/data/transformer.js +55 -0
  217. package/dist/src/helpers/data/transformer.js.map +1 -0
  218. package/dist/src/helpers/framework/decorators.d.ts +5 -0
  219. package/dist/src/helpers/framework/decorators.d.ts.map +1 -0
  220. package/dist/src/helpers/framework/decorators.js +39 -0
  221. package/dist/src/helpers/framework/decorators.js.map +1 -0
  222. package/dist/src/helpers/framework/event.d.ts +3 -0
  223. package/dist/src/helpers/framework/event.d.ts.map +1 -0
  224. package/dist/src/helpers/framework/event.js +20 -0
  225. package/dist/src/helpers/framework/event.js.map +1 -0
  226. package/dist/src/helpers/framework/injection.d.ts +7 -0
  227. package/dist/src/helpers/framework/injection.d.ts.map +1 -0
  228. package/dist/src/helpers/framework/injection.js +52 -0
  229. package/dist/src/helpers/framework/injection.js.map +1 -0
  230. package/dist/src/helpers/index.d.ts +22 -0
  231. package/dist/src/helpers/index.d.ts.map +1 -0
  232. package/dist/src/helpers/index.js +32 -0
  233. package/dist/src/helpers/index.js.map +1 -0
  234. package/dist/src/helpers/io/package.d.ts +5 -0
  235. package/dist/src/helpers/io/package.d.ts.map +1 -0
  236. package/dist/src/helpers/io/package.js +31 -0
  237. package/dist/src/helpers/io/package.js.map +1 -0
  238. package/dist/src/helpers/io/stream.d.ts +18 -0
  239. package/dist/src/helpers/io/stream.d.ts.map +1 -0
  240. package/dist/src/helpers/io/stream.js +91 -0
  241. package/dist/src/helpers/io/stream.js.map +1 -0
  242. package/dist/src/helpers/redis/broadcast.d.ts +12 -0
  243. package/dist/src/helpers/redis/broadcast.d.ts.map +1 -0
  244. package/dist/src/helpers/redis/broadcast.js +99 -0
  245. package/dist/src/helpers/redis/broadcast.js.map +1 -0
  246. package/dist/src/helpers/redis/cache.d.ts +7 -0
  247. package/dist/src/helpers/redis/cache.d.ts.map +1 -0
  248. package/dist/src/helpers/redis/cache.js +28 -0
  249. package/dist/src/helpers/redis/cache.js.map +1 -0
  250. package/dist/src/helpers/redis/mutex.d.ts +24 -0
  251. package/dist/src/helpers/redis/mutex.d.ts.map +1 -0
  252. package/dist/src/helpers/redis/mutex.js +240 -0
  253. package/dist/src/helpers/redis/mutex.js.map +1 -0
  254. package/dist/src/helpers/redis/redis.d.ts +11 -0
  255. package/dist/src/helpers/redis/redis.d.ts.map +1 -0
  256. package/dist/src/helpers/redis/redis.js +59 -0
  257. package/dist/src/helpers/redis/redis.js.map +1 -0
  258. package/dist/src/helpers/security/crypto.d.ts +26 -0
  259. package/dist/src/helpers/security/crypto.d.ts.map +1 -0
  260. package/dist/src/helpers/security/crypto.js +121 -0
  261. package/dist/src/helpers/security/crypto.js.map +1 -0
  262. package/dist/src/helpers/security/validation.d.ts +4 -0
  263. package/dist/src/helpers/security/validation.d.ts.map +1 -0
  264. package/dist/src/helpers/security/validation.js +25 -0
  265. package/dist/src/helpers/security/validation.js.map +1 -0
  266. package/dist/src/helpers/utils/date.d.ts +4 -0
  267. package/dist/src/helpers/utils/date.d.ts.map +1 -0
  268. package/dist/src/helpers/utils/date.js +23 -0
  269. package/dist/src/helpers/utils/date.js.map +1 -0
  270. package/dist/src/helpers/utils/error.d.ts +24 -0
  271. package/dist/src/helpers/utils/error.d.ts.map +1 -0
  272. package/dist/src/helpers/utils/error.js +168 -0
  273. package/dist/src/helpers/utils/error.js.map +1 -0
  274. package/dist/src/helpers/utils/jsx.d.ts +3 -0
  275. package/dist/src/helpers/utils/jsx.d.ts.map +1 -0
  276. package/dist/src/helpers/utils/jsx.js +13 -0
  277. package/dist/src/helpers/utils/jsx.js.map +1 -0
  278. package/dist/src/helpers/utils/uuid.d.ts +3 -0
  279. package/dist/src/helpers/utils/uuid.d.ts.map +1 -0
  280. package/dist/src/helpers/utils/uuid.js +14 -0
  281. package/dist/src/helpers/utils/uuid.js.map +1 -0
  282. package/dist/src/http/auth.d.ts +46 -0
  283. package/dist/src/http/auth.d.ts.map +1 -0
  284. package/dist/src/http/auth.js +162 -0
  285. package/dist/src/http/auth.js.map +1 -0
  286. package/dist/src/http/context.d.ts +5 -0
  287. package/dist/src/http/context.d.ts.map +1 -0
  288. package/dist/src/http/context.js +22 -0
  289. package/dist/src/http/context.js.map +1 -0
  290. package/dist/src/http/cors.d.ts +36 -0
  291. package/dist/src/http/cors.d.ts.map +1 -0
  292. package/dist/src/http/cors.js +171 -0
  293. package/dist/src/http/cors.js.map +1 -0
  294. package/dist/src/http/errors.d.ts +3 -0
  295. package/dist/src/http/errors.d.ts.map +1 -0
  296. package/dist/src/http/errors.js +10 -0
  297. package/dist/src/http/errors.js.map +1 -0
  298. package/dist/src/http/index.d.ts +24 -0
  299. package/dist/src/http/index.d.ts.map +1 -0
  300. package/dist/src/http/index.js +25 -0
  301. package/dist/src/http/index.js.map +1 -0
  302. package/dist/src/http/kernel.d.ts +17 -0
  303. package/dist/src/http/kernel.d.ts.map +1 -0
  304. package/dist/src/http/kernel.js +133 -0
  305. package/dist/src/http/kernel.js.map +1 -0
  306. package/dist/src/http/middleware.d.ts +12 -0
  307. package/dist/src/http/middleware.d.ts.map +1 -0
  308. package/dist/src/http/middleware.js +61 -0
  309. package/dist/src/http/middleware.js.map +1 -0
  310. package/dist/src/http/overrides.d.ts +2 -0
  311. package/dist/src/http/overrides.d.ts.map +1 -0
  312. package/dist/src/http/overrides.js +19 -0
  313. package/dist/src/http/overrides.js.map +1 -0
  314. package/dist/src/http/store.d.ts +33 -0
  315. package/dist/src/http/store.d.ts.map +1 -0
  316. package/dist/src/http/store.js +102 -0
  317. package/dist/src/http/store.js.map +1 -0
  318. package/dist/src/http/uploads.d.ts +7 -0
  319. package/dist/src/http/uploads.d.ts.map +1 -0
  320. package/dist/src/http/uploads.js +8 -0
  321. package/dist/src/http/uploads.js.map +1 -0
  322. package/dist/src/http/workflow.d.ts +18 -0
  323. package/dist/src/http/workflow.d.ts.map +1 -0
  324. package/dist/src/http/workflow.js +181 -0
  325. package/dist/src/http/workflow.js.map +1 -0
  326. package/dist/src/index.d.ts +13 -0
  327. package/dist/src/index.d.ts.map +1 -0
  328. package/dist/src/index.js +25 -0
  329. package/dist/src/index.js.map +1 -0
  330. package/dist/src/services/cli/invoke.d.ts +5 -0
  331. package/dist/src/services/cli/invoke.d.ts.map +1 -0
  332. package/dist/src/services/cli/invoke.js +45 -0
  333. package/dist/src/services/cli/invoke.js.map +1 -0
  334. package/dist/src/services/cli/repl.d.ts +5 -0
  335. package/dist/src/services/cli/repl.d.ts.map +1 -0
  336. package/dist/src/services/cli/repl.js +71 -0
  337. package/dist/src/services/cli/repl.js.map +1 -0
  338. package/dist/src/services/cli.d.ts +12 -0
  339. package/dist/src/services/cli.d.ts.map +1 -0
  340. package/dist/src/services/cli.js +76 -0
  341. package/dist/src/services/cli.js.map +1 -0
  342. package/dist/src/services/index.d.ts +7 -0
  343. package/dist/src/services/index.d.ts.map +1 -0
  344. package/dist/src/services/index.js +10 -0
  345. package/dist/src/services/index.js.map +1 -0
  346. package/dist/src/services/leader.d.ts +32 -0
  347. package/dist/src/services/leader.d.ts.map +1 -0
  348. package/dist/src/services/leader.js +174 -0
  349. package/dist/src/services/leader.js.map +1 -0
  350. package/dist/src/services/logger.d.ts +35 -0
  351. package/dist/src/services/logger.d.ts.map +1 -0
  352. package/dist/src/services/logger.js +245 -0
  353. package/dist/src/services/logger.js.map +1 -0
  354. package/dist/src/services/mail/index.d.ts +61 -0
  355. package/dist/src/services/mail/index.d.ts.map +1 -0
  356. package/dist/src/services/mail/index.js +90 -0
  357. package/dist/src/services/mail/index.js.map +1 -0
  358. package/dist/src/services/mail/postmark.d.ts +11 -0
  359. package/dist/src/services/mail/postmark.d.ts.map +1 -0
  360. package/dist/src/services/mail/postmark.js +42 -0
  361. package/dist/src/services/mail/postmark.js.map +1 -0
  362. package/dist/src/services/mail/smtp.d.ts +11 -0
  363. package/dist/src/services/mail/smtp.d.ts.map +1 -0
  364. package/dist/src/services/mail/smtp.js +61 -0
  365. package/dist/src/services/mail/smtp.js.map +1 -0
  366. package/dist/src/services/mesh.d.ts +65 -0
  367. package/dist/src/services/mesh.d.ts.map +1 -0
  368. package/dist/src/services/mesh.js +422 -0
  369. package/dist/src/services/mesh.js.map +1 -0
  370. package/dist/src/services/worker/bootstrap.d.ts +3 -0
  371. package/dist/src/services/worker/bootstrap.d.ts.map +1 -0
  372. package/dist/src/services/worker/bootstrap.js +70 -0
  373. package/dist/src/services/worker/bootstrap.js.map +1 -0
  374. package/dist/src/services/worker/cli.d.ts +23 -0
  375. package/dist/src/services/worker/cli.d.ts.map +1 -0
  376. package/dist/src/services/worker/cli.js +81 -0
  377. package/dist/src/services/worker/cli.js.map +1 -0
  378. package/dist/src/services/worker/entity.d.ts +18 -0
  379. package/dist/src/services/worker/entity.d.ts.map +1 -0
  380. package/dist/src/services/worker/entity.js +16 -0
  381. package/dist/src/services/worker/entity.js.map +1 -0
  382. package/dist/src/services/worker/index.d.ts +9 -0
  383. package/dist/src/services/worker/index.d.ts.map +1 -0
  384. package/dist/src/services/worker/index.js +40 -0
  385. package/dist/src/services/worker/index.js.map +1 -0
  386. package/dist/src/services/worker/observer.d.ts +18 -0
  387. package/dist/src/services/worker/observer.d.ts.map +1 -0
  388. package/dist/src/services/worker/observer.js +172 -0
  389. package/dist/src/services/worker/observer.js.map +1 -0
  390. package/dist/src/services/worker/queue.d.ts +8 -0
  391. package/dist/src/services/worker/queue.d.ts.map +1 -0
  392. package/dist/src/services/worker/queue.js +31 -0
  393. package/dist/src/services/worker/queue.js.map +1 -0
  394. package/dist/src/services/worker/runner.d.ts +17 -0
  395. package/dist/src/services/worker/runner.d.ts.map +1 -0
  396. package/dist/src/services/worker/runner.js +131 -0
  397. package/dist/src/services/worker/runner.js.map +1 -0
  398. package/dist/src/services/worker/types.d.ts +26 -0
  399. package/dist/src/services/worker/types.d.ts.map +1 -0
  400. package/dist/src/services/worker/types.js +29 -0
  401. package/dist/src/services/worker/types.js.map +1 -0
  402. package/dist/src/srpc/SrpcByteStream.d.ts +67 -0
  403. package/dist/src/srpc/SrpcByteStream.d.ts.map +1 -0
  404. package/dist/src/srpc/SrpcByteStream.js +319 -0
  405. package/dist/src/srpc/SrpcByteStream.js.map +1 -0
  406. package/dist/src/srpc/SrpcClient.d.ts +75 -0
  407. package/dist/src/srpc/SrpcClient.d.ts.map +1 -0
  408. package/dist/src/srpc/SrpcClient.js +445 -0
  409. package/dist/src/srpc/SrpcClient.js.map +1 -0
  410. package/dist/src/srpc/SrpcServer.d.ts +54 -0
  411. package/dist/src/srpc/SrpcServer.d.ts.map +1 -0
  412. package/dist/src/srpc/SrpcServer.js +456 -0
  413. package/dist/src/srpc/SrpcServer.js.map +1 -0
  414. package/dist/src/srpc/index.d.ts +7 -0
  415. package/dist/src/srpc/index.d.ts.map +1 -0
  416. package/dist/src/srpc/index.js +12 -0
  417. package/dist/src/srpc/index.js.map +1 -0
  418. package/dist/src/srpc/types.d.ts +129 -0
  419. package/dist/src/srpc/types.d.ts.map +1 -0
  420. package/dist/src/srpc/types.js +65 -0
  421. package/dist/src/srpc/types.js.map +1 -0
  422. package/dist/src/telemetry/index.d.ts +2 -0
  423. package/dist/src/telemetry/index.d.ts.map +1 -0
  424. package/dist/src/telemetry/index.js +5 -0
  425. package/dist/src/telemetry/index.js.map +1 -0
  426. package/dist/src/telemetry/otel/MariaDBInstrumentation.d.ts +22 -0
  427. package/dist/src/telemetry/otel/MariaDBInstrumentation.d.ts.map +1 -0
  428. package/dist/src/telemetry/otel/MariaDBInstrumentation.js +248 -0
  429. package/dist/src/telemetry/otel/MariaDBInstrumentation.js.map +1 -0
  430. package/dist/src/telemetry/otel/helpers.d.ts +27 -0
  431. package/dist/src/telemetry/otel/helpers.d.ts.map +1 -0
  432. package/dist/src/telemetry/otel/helpers.js +126 -0
  433. package/dist/src/telemetry/otel/helpers.js.map +1 -0
  434. package/dist/src/telemetry/otel/index.d.ts +14 -0
  435. package/dist/src/telemetry/otel/index.d.ts.map +1 -0
  436. package/dist/src/telemetry/otel/index.js +132 -0
  437. package/dist/src/telemetry/otel/index.js.map +1 -0
  438. package/dist/src/telemetry/otel/metrics.controller.d.ts +6 -0
  439. package/dist/src/telemetry/otel/metrics.controller.d.ts.map +1 -0
  440. package/dist/src/telemetry/otel/metrics.controller.js +63 -0
  441. package/dist/src/telemetry/otel/metrics.controller.js.map +1 -0
  442. package/dist/src/telemetry/sentry.d.ts +9 -0
  443. package/dist/src/telemetry/sentry.d.ts.map +1 -0
  444. package/dist/src/telemetry/sentry.js +62 -0
  445. package/dist/src/telemetry/sentry.js.map +1 -0
  446. package/dist/src/testapp/bootstrap.d.ts +1 -0
  447. package/dist/src/testapp/bootstrap.d.ts.map +1 -0
  448. package/dist/src/testapp/bootstrap.js +18 -0
  449. package/dist/src/testapp/bootstrap.js.map +1 -0
  450. package/dist/src/testapp/sample.d.ts +6 -0
  451. package/dist/src/testapp/sample.d.ts.map +1 -0
  452. package/dist/src/testapp/sample.js +228 -0
  453. package/dist/src/testapp/sample.js.map +1 -0
  454. package/dist/src/testapp/srpc-test.d.ts +27 -0
  455. package/dist/src/testapp/srpc-test.d.ts.map +1 -0
  456. package/dist/src/testapp/srpc-test.js +570 -0
  457. package/dist/src/testapp/srpc-test.js.map +1 -0
  458. package/dist/src/testing/expect.d.ts +25 -0
  459. package/dist/src/testing/expect.d.ts.map +1 -0
  460. package/dist/src/testing/expect.js +151 -0
  461. package/dist/src/testing/expect.js.map +1 -0
  462. package/dist/src/testing/fixtures.d.ts +19 -0
  463. package/dist/src/testing/fixtures.d.ts.map +1 -0
  464. package/dist/src/testing/fixtures.js +69 -0
  465. package/dist/src/testing/fixtures.js.map +1 -0
  466. package/dist/src/testing/index.d.ts +260 -0
  467. package/dist/src/testing/index.d.ts.map +1 -0
  468. package/dist/src/testing/index.js +345 -0
  469. package/dist/src/testing/index.js.map +1 -0
  470. package/dist/src/testing/requests.d.ts +10 -0
  471. package/dist/src/testing/requests.d.ts.map +1 -0
  472. package/dist/src/testing/requests.js +56 -0
  473. package/dist/src/testing/requests.js.map +1 -0
  474. package/dist/src/testing/sql.d.ts +11 -0
  475. package/dist/src/testing/sql.d.ts.map +1 -0
  476. package/dist/src/testing/sql.js +55 -0
  477. package/dist/src/testing/sql.js.map +1 -0
  478. package/dist/src/types/index.d.ts +57 -0
  479. package/dist/src/types/index.d.ts.map +1 -0
  480. package/dist/src/types/index.js +73 -0
  481. package/dist/src/types/index.js.map +1 -0
  482. package/dist/src/types/phone.d.ts +11 -0
  483. package/dist/src/types/phone.d.ts.map +1 -0
  484. package/dist/src/types/phone.js +73 -0
  485. package/dist/src/types/phone.js.map +1 -0
  486. package/dist/tsconfig.tsbuildinfo +1 -0
  487. package/docs/README.md +38 -0
  488. package/docs/authentication.md +215 -0
  489. package/docs/cli.md +302 -0
  490. package/docs/configuration.md +176 -0
  491. package/docs/database.md +422 -0
  492. package/docs/getting-started.md +154 -0
  493. package/docs/health.md +53 -0
  494. package/docs/helpers.md +436 -0
  495. package/docs/http.md +253 -0
  496. package/docs/leader-service.md +98 -0
  497. package/docs/logging.md +150 -0
  498. package/docs/mail.md +161 -0
  499. package/docs/mesh-service.md +204 -0
  500. package/docs/srpc.md +261 -0
  501. package/docs/telemetry.md +166 -0
  502. package/docs/testing.md +222 -0
  503. package/docs/types.md +215 -0
  504. package/docs/worker.md +174 -0
  505. package/lefthook.yml +12 -0
  506. package/openapi.yaml +109 -0
  507. package/package.json +133 -0
  508. package/patches/@deepkit+type+1.0.19.patch +38 -0
  509. package/resources/proto/generated/test/test.ts +2721 -0
  510. package/resources/proto/sample.proto +85 -0
  511. package/resources/proto/test.proto +178 -0
  512. package/src/app/base.ts +257 -0
  513. package/src/app/config.loader.ts +66 -0
  514. package/src/app/config.ts +120 -0
  515. package/src/app/const.ts +4 -0
  516. package/src/app/dev.ts +70 -0
  517. package/src/app/index.ts +6 -0
  518. package/src/app/openapi.ts +3 -0
  519. package/src/app/resolver.ts +49 -0
  520. package/src/app/shutdown.ts +55 -0
  521. package/src/app/state.ts +19 -0
  522. package/src/auth/index.ts +2 -0
  523. package/src/auth/jwt.ts +275 -0
  524. package/src/auth/provider.ts +57 -0
  525. package/src/cli/dksf-dev.ts +363 -0
  526. package/src/cli/dksf-gen-proto.ts +176 -0
  527. package/src/cli/dksf-install.ts +11 -0
  528. package/src/cli/dksf-test.ts +95 -0
  529. package/src/cli/dksf-update.ts +101 -0
  530. package/src/database/CLAUDE.md +390 -0
  531. package/src/database/common.ts +385 -0
  532. package/src/database/dialect.ts +43 -0
  533. package/src/database/entity.ts +285 -0
  534. package/src/database/index.ts +7 -0
  535. package/src/database/migration/MigrationResetCommand.ts +152 -0
  536. package/src/database/migration/MigrationRunCommand.ts +118 -0
  537. package/src/database/migration/characters.ts +53 -0
  538. package/src/database/migration/create/MigrationCreateCommand.ts +94 -0
  539. package/src/database/migration/create/comparator.ts +467 -0
  540. package/src/database/migration/create/db-reader.ts +510 -0
  541. package/src/database/migration/create/ddl-generator.ts +755 -0
  542. package/src/database/migration/create/entity-reader.ts +462 -0
  543. package/src/database/migration/create/file-generator.ts +52 -0
  544. package/src/database/migration/create/prompt.ts +49 -0
  545. package/src/database/migration/create/schema-model.ts +102 -0
  546. package/src/database/migration/helpers.ts +3 -0
  547. package/src/database/migration/index.ts +35 -0
  548. package/src/database/migration/migration.entity.ts +10 -0
  549. package/src/database/mysql.ts +140 -0
  550. package/src/database/postgres.ts +97 -0
  551. package/src/database/types.ts +18 -0
  552. package/src/health/health.module.ts +30 -0
  553. package/src/health/healthcheck.controller.ts +17 -0
  554. package/src/health/healthcheck.service.ts +15 -0
  555. package/src/health/index.ts +2 -0
  556. package/src/helpers/CLAUDE.md +71 -0
  557. package/src/helpers/async/context.ts +67 -0
  558. package/src/helpers/async/process.ts +49 -0
  559. package/src/helpers/async/promise.ts +16 -0
  560. package/src/helpers/data/array.ts +11 -0
  561. package/src/helpers/data/objects.ts +64 -0
  562. package/src/helpers/data/serialization.ts +11 -0
  563. package/src/helpers/data/transformer.ts +54 -0
  564. package/src/helpers/framework/decorators.ts +27 -0
  565. package/src/helpers/framework/event.ts +11 -0
  566. package/src/helpers/framework/injection.ts +47 -0
  567. package/src/helpers/index.ts +34 -0
  568. package/src/helpers/io/package.ts +26 -0
  569. package/src/helpers/io/stream.ts +79 -0
  570. package/src/helpers/redis/broadcast.ts +94 -0
  571. package/src/helpers/redis/cache.ts +28 -0
  572. package/src/helpers/redis/mutex.ts +260 -0
  573. package/src/helpers/redis/redis.ts +60 -0
  574. package/src/helpers/security/crypto.ts +133 -0
  575. package/src/helpers/security/validation.ts +16 -0
  576. package/src/helpers/utils/date.ts +13 -0
  577. package/src/helpers/utils/error.ts +155 -0
  578. package/src/helpers/utils/jsx.ts +8 -0
  579. package/src/helpers/utils/uuid.ts +8 -0
  580. package/src/http/auth.ts +156 -0
  581. package/src/http/context.ts +15 -0
  582. package/src/http/cors.ts +159 -0
  583. package/src/http/errors.ts +9 -0
  584. package/src/http/index.ts +19 -0
  585. package/src/http/kernel.ts +138 -0
  586. package/src/http/middleware.ts +59 -0
  587. package/src/http/overrides.ts +20 -0
  588. package/src/http/store.ts +86 -0
  589. package/src/http/uploads.ts +6 -0
  590. package/src/http/workflow.ts +167 -0
  591. package/src/index.ts +19 -0
  592. package/src/services/cli/invoke.ts +39 -0
  593. package/src/services/cli/repl.ts +67 -0
  594. package/src/services/cli.ts +74 -0
  595. package/src/services/index.ts +6 -0
  596. package/src/services/leader.ts +201 -0
  597. package/src/services/logger.ts +258 -0
  598. package/src/services/mail/index.ts +117 -0
  599. package/src/services/mail/postmark.ts +37 -0
  600. package/src/services/mail/smtp.ts +46 -0
  601. package/src/services/mesh.ts +508 -0
  602. package/src/services/worker/CLAUDE.md +77 -0
  603. package/src/services/worker/bootstrap.ts +58 -0
  604. package/src/services/worker/cli.ts +63 -0
  605. package/src/services/worker/entity.ts +22 -0
  606. package/src/services/worker/index.ts +30 -0
  607. package/src/services/worker/observer.ts +180 -0
  608. package/src/services/worker/queue.ts +34 -0
  609. package/src/services/worker/runner.ts +146 -0
  610. package/src/services/worker/types.ts +32 -0
  611. package/src/srpc/CLAUDE.md +194 -0
  612. package/src/srpc/SRPC_MIGRATION_GUIDE.md +348 -0
  613. package/src/srpc/SrpcByteStream.ts +382 -0
  614. package/src/srpc/SrpcClient.ts +512 -0
  615. package/src/srpc/SrpcServer.ts +575 -0
  616. package/src/srpc/index.ts +15 -0
  617. package/src/srpc/types.ts +144 -0
  618. package/src/telemetry/index.ts +1 -0
  619. package/src/telemetry/otel/MariaDBInstrumentation.ts +297 -0
  620. package/src/telemetry/otel/helpers.ts +117 -0
  621. package/src/telemetry/otel/index.ts +150 -0
  622. package/src/telemetry/otel/metrics.controller.ts +50 -0
  623. package/src/telemetry/sentry.ts +58 -0
  624. package/src/testapp/bootstrap.ts +17 -0
  625. package/src/testapp/sample.ts +220 -0
  626. package/src/testapp/srpc-test.ts +684 -0
  627. package/src/testing/expect.ts +148 -0
  628. package/src/testing/fixtures.ts +62 -0
  629. package/src/testing/index.ts +355 -0
  630. package/src/testing/requests.ts +68 -0
  631. package/src/testing/sql.ts +50 -0
  632. package/src/types/index.ts +64 -0
  633. package/src/types/phone.ts +64 -0
  634. package/tests/app/app.spec.ts +53 -0
  635. package/tests/app/type.spec.ts +22 -0
  636. package/tests/auth/jwt.spec.ts +90 -0
  637. package/tests/database/entity.spec.ts +382 -0
  638. package/tests/database/locks.spec.ts +142 -0
  639. package/tests/database/migration-create-integration.spec.ts +234 -0
  640. package/tests/database/migration-create-unit.spec.ts +3896 -0
  641. package/tests/helpers/array.spec.ts +80 -0
  642. package/tests/helpers/cache.spec.ts +202 -0
  643. package/tests/helpers/crypto.spec.ts +236 -0
  644. package/tests/helpers/date.spec.ts +94 -0
  645. package/tests/helpers/error.spec.ts +233 -0
  646. package/tests/helpers/mutex.spec.ts +354 -0
  647. package/tests/helpers/objects.spec.ts +212 -0
  648. package/tests/helpers/package.spec.ts +90 -0
  649. package/tests/helpers/promise.spec.ts +119 -0
  650. package/tests/helpers/redis.spec.ts +50 -0
  651. package/tests/helpers/serialization.spec.ts +150 -0
  652. package/tests/helpers/stream.spec.ts +225 -0
  653. package/tests/helpers/validation.spec.ts +133 -0
  654. package/tests/services/leader.spec.ts +257 -0
  655. package/tests/services/logger.spec.ts +269 -0
  656. package/tests/services/mesh.spec.ts +814 -0
  657. package/tests/shared/db.ts +105 -0
  658. package/tests/shared/globalSetup.ts +48 -0
  659. package/tests/shared/helpers.ts +40 -0
  660. package/tests/srpc/SrpcByteStream.spec.ts +542 -0
  661. package/tests/tsconfig.json +4 -0
  662. package/tests/types/index.spec.ts +60 -0
  663. package/tests/types/phone.spec.ts +140 -0
  664. package/tsconfig.json +106 -0
  665. package/tsconfig.test.json +8 -0
  666. package/types.d.ts +6 -0
@@ -0,0 +1,77 @@
1
+ # Worker System
2
+
3
+ The worker system integrates BullMQ to queue background jobs and Deepkit services to run them. Enabling workers wires together the queue registry, runner, observer, CLI commands, and the `_jobs` audit table.
4
+
5
+ ## Enabling Workers
6
+
7
+ ```ts
8
+ import { createApp } from '../app';
9
+
10
+ const app = createApp({
11
+ config: MyConfig,
12
+ enableWorker: true
13
+ // …
14
+ });
15
+ ```
16
+
17
+ When `enableWorker` is set:
18
+
19
+ - `WorkerService` becomes injectable for queueing jobs.
20
+ - `WorkerRunnerService` and `WorkerObserverService` are registered (but only started when appropriate).
21
+ - CLI controllers (`worker:start`, `worker:runner`, `worker:observer`, `worker:queue`) become available.
22
+ - `JobEntity` is added to the database schema to persist job lifecycle data.
23
+
24
+ At runtime, the runner/observer auto-start in non-production environments. In production, toggle them with configuration flags (`ENABLE_JOB_RUNNER`, `ENABLE_JOB_OBSERVER`). They can also be launched explicitly through the CLI commands listed above.
25
+
26
+ ## Defining Jobs
27
+
28
+ Jobs extend `BaseJob` and are annotated with the `@WorkerJob()` decorator so the runner can discover them:
29
+
30
+ ```ts
31
+ import { BaseJob, WorkerJob } from '../services/worker';
32
+
33
+ @WorkerJob()
34
+ class SendEmailJob extends BaseJob<{ to: string; subject: string }, void> {
35
+ constructor(private mailer: MailService) {
36
+ super();
37
+ }
38
+
39
+ async handle(data: { to: string; subject: string }) {
40
+ await this.mailer.send(data.to, data.subject);
41
+ }
42
+ }
43
+ ```
44
+
45
+ Optional static configuration:
46
+
47
+ - `QUEUE_NAME` – assign the job to a named queue (defaults to the app's `BULL_QUEUE`).
48
+ - `CRON_SCHEDULE` – schedule recurring execution using a cron pattern (registered automatically when the runner starts).
49
+
50
+ The job instance receives dependencies via Deepkit's injector. There is no BullMQ `Job` object injected—log additional context yourself if needed.
51
+
52
+ ## Queueing Jobs
53
+
54
+ Use `WorkerService.queueJob()` from request handlers or other services:
55
+
56
+ ```ts
57
+ class NotificationController {
58
+ constructor(private worker: WorkerService) {}
59
+
60
+ async sendWelcome(to: string) {
61
+ await this.worker.queueJob(SendEmailJob, { to, subject: 'Welcome!' });
62
+ }
63
+ }
64
+ ```
65
+
66
+ `queueJob` accepts an optional `{ delay?: number }` option. When running in test environment (`APP_ENV=test`), the method simply logs a warning and skips queueing to keep tests deterministic.
67
+
68
+ ## Runner & Observer
69
+
70
+ - **WorkerRunnerService** pulls jobs from the configured BullMQ queue and invokes the `handle()` method. It resolves job classes registered with `@WorkerJob()` and honours `CRON_SCHEDULE`.
71
+ - **WorkerObserverService** listens for BullMQ lifecycle events, writes entries to the `_jobs` table via `JobEntity`, and clears completed/failed jobs from Redis after logging. It also wires into the health-check system to ensure Redis remains reachable.
72
+
73
+ Both services close BullMQ resources during shutdown and support graceful termination through the Deepkit event system.
74
+
75
+ ## Redis & Configuration
76
+
77
+ All worker components share Redis connection settings derived from `BaseAppConfig` (e.g. `BULL_QUEUE`, `REDIS_HOST` or sentinel configuration). Ensure these values are populated before starting the app or dedicated worker processes.
@@ -0,0 +1,58 @@
1
+ import { App } from '@deepkit/app';
2
+ import { eventDispatcher } from '@deepkit/event';
3
+ import { onServerMainBootstrapDone, onServerShutdown } from '@deepkit/framework';
4
+ import { Redis } from 'ioredis';
5
+
6
+ import { getAppConfig } from '../../app/resolver';
7
+ import { isDevelopment } from '../../app/const';
8
+ import { globalState } from '../../app/state';
9
+ import { WorkerQueueJobCommand, WorkerStartCommand, WorkerStartObserverCommand, WorkerStartRunnerCommand } from './cli';
10
+ import { JobEntity } from './entity';
11
+ import { WorkerObserverService } from './observer';
12
+ import { WorkerQueueRegistry } from './queue';
13
+ import { WorkerRunnerService } from './runner';
14
+
15
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
16
+ export function installWorkerComponents(app: App<any>) {
17
+ globalState.enableWorker = true;
18
+ globalState.additionalEntities.push(JobEntity);
19
+
20
+ app.appModule.addProvider(WorkerObserverService);
21
+ app.appModule.addProvider(WorkerRunnerService);
22
+
23
+ app.appModule.addController(WorkerStartCommand);
24
+ app.appModule.addController(WorkerStartRunnerCommand);
25
+ app.appModule.addController(WorkerStartObserverCommand);
26
+ app.appModule.addController(WorkerQueueJobCommand);
27
+
28
+ class WorkerListener {
29
+ constructor(private runner: WorkerRunnerService) {}
30
+
31
+ @eventDispatcher.listen(onServerShutdown)
32
+ async shutdownRunner() {
33
+ await this.runner.shutdown();
34
+
35
+ // prevent new Redis connections from being created after shutdown
36
+ // some issue in dev keeping processes alive forever
37
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
38
+ (Redis.prototype as any).connect = () => {};
39
+ }
40
+
41
+ // we want this to run very late in the process, after the worker and observer have shut down
42
+ @eventDispatcher.listen(onServerShutdown, 1000)
43
+ async closeQueues() {
44
+ await WorkerQueueRegistry.closeQueues();
45
+ }
46
+ }
47
+ app.appModule.addListener(WorkerListener);
48
+
49
+ app.listen(onServerMainBootstrapDone, () => {
50
+ if (!globalState.isCliService) {
51
+ setTimeout(() => {
52
+ const config = getAppConfig();
53
+ if (config.ENABLE_JOB_OBSERVER ?? isDevelopment) app.get(WorkerObserverService).start();
54
+ if (config.ENABLE_JOB_RUNNER ?? isDevelopment) app.get(WorkerRunnerService).start();
55
+ }, 1000);
56
+ }
57
+ });
58
+ }
@@ -0,0 +1,63 @@
1
+ import { cli } from '@deepkit/app';
2
+
3
+ import { CliServiceCommand } from '../cli';
4
+ import { WorkerObserverService } from './observer';
5
+ import { WorkerQueueRegistry } from './queue';
6
+ import { WorkerRunnerService } from './runner';
7
+ import { BaseJob } from './types';
8
+
9
+ @cli.controller('worker:start', {
10
+ description: 'Start the worker runner and observer'
11
+ })
12
+ export class WorkerStartCommand extends CliServiceCommand {
13
+ constructor(
14
+ private runner: WorkerRunnerService,
15
+ private observer: WorkerObserverService
16
+ ) {
17
+ super();
18
+ }
19
+
20
+ async startService() {
21
+ await this.runner.start();
22
+ await this.observer.start();
23
+ }
24
+ }
25
+
26
+ @cli.controller('worker:runner', {
27
+ description: 'Start the worker runner'
28
+ })
29
+ export class WorkerStartRunnerCommand extends CliServiceCommand {
30
+ constructor(private runner: WorkerRunnerService) {
31
+ super();
32
+ }
33
+
34
+ async startService() {
35
+ await this.runner.start();
36
+ }
37
+ }
38
+
39
+ @cli.controller('worker:observer', {
40
+ description: 'Start the worker observer'
41
+ })
42
+ export class WorkerStartObserverCommand extends CliServiceCommand {
43
+ constructor(private observer: WorkerObserverService) {
44
+ super();
45
+ }
46
+
47
+ async startService() {
48
+ await this.observer.start();
49
+ }
50
+ }
51
+
52
+ @cli.controller('worker:queue', {
53
+ // todo: optional queue name?
54
+ description: 'Queue a job by name'
55
+ })
56
+ export class WorkerQueueJobCommand {
57
+ async execute(jobName: string, data?: string) {
58
+ data = data ? JSON.parse(data) : {};
59
+ const queue = WorkerQueueRegistry.getQueue(BaseJob.QUEUE_NAME);
60
+ await queue.add(jobName, data);
61
+ await queue.close();
62
+ }
63
+ }
@@ -0,0 +1,22 @@
1
+ import { entity, Index, PrimaryKey } from '@deepkit/type';
2
+
3
+ import { BaseEntity } from '../../database';
4
+
5
+ @entity.name('_jobs')
6
+ export class JobEntity extends BaseEntity {
7
+ id!: string & PrimaryKey;
8
+ queue!: string & Index;
9
+ queueId!: string;
10
+ attempt!: number;
11
+ name!: string;
12
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
13
+ data!: any;
14
+ traceId!: string | null;
15
+ status!: 'completed' | 'failed';
16
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
17
+ result!: any;
18
+ createdAt!: Date;
19
+ shouldExecuteAt!: Date;
20
+ executedAt!: Date;
21
+ completedAt!: Date;
22
+ }
@@ -0,0 +1,30 @@
1
+ import { ClassType } from '@deepkit/core';
2
+
3
+ import { isTest } from '../../app/const';
4
+ import { createLogger } from '../logger';
5
+ import { WorkerQueueRegistry } from './queue';
6
+ import { BaseJob, IJobOptions, InputDataSymbol, JobClass } from './types';
7
+
8
+ export * from './entity';
9
+ export { BaseJob, WorkerJob } from './types';
10
+
11
+ export class WorkerService {
12
+ private logger = createLogger(this);
13
+
14
+ async queueJob<I extends object, O, T extends BaseJob<I, O>>(jobClass: ClassType<T>, data: T[typeof InputDataSymbol], options?: IJobOptions) {
15
+ if (isTest) {
16
+ this.logger.warn('Not queueing job in test environment', { jobName: jobClass.name, data, options });
17
+ return;
18
+ }
19
+
20
+ try {
21
+ const typedJob = jobClass as unknown as JobClass;
22
+ const queue = WorkerQueueRegistry.getQueue(typedJob.QUEUE_NAME);
23
+ const job = await queue.add(jobClass.name, data, options);
24
+ this.logger.info('Queued job', { job: { name: jobClass.name, id: job.id } });
25
+ } catch (err) {
26
+ this.logger.error('Failed to queue job', err, { job: { name: jobClass.name } });
27
+ throw err;
28
+ }
29
+ }
30
+ }
@@ -0,0 +1,180 @@
1
+ import { UniqueConstraintFailure } from '@deepkit/orm';
2
+ import { SQLDatabaseAdapter } from '@deepkit/sql';
3
+ import { Job, QueueEvents } from 'bullmq';
4
+
5
+ import { getAppConfig } from '../../app/resolver';
6
+ import { DBProvider } from '../../app/state';
7
+ import { createPersistedEntity, getDialect, tableExistsSql } from '../../database';
8
+ import { HealthcheckService } from '../../health/healthcheck.service';
9
+ import { createRedisOptions } from '../../helpers/redis/redis';
10
+ import { createLogger, ExtendedLogger } from '../logger';
11
+ import { JobEntity } from './entity';
12
+ import { WorkerQueueRegistry } from './queue';
13
+ import { BaseAppConfig } from '../../app';
14
+
15
+ export class WorkerObserverService {
16
+ private appConfig: BaseAppConfig;
17
+ private queueName: string;
18
+ private logger: ExtendedLogger;
19
+ private observer?: QueueEvents;
20
+ private db = this.dbProvider.db;
21
+
22
+ constructor(
23
+ private hcSvc: HealthcheckService,
24
+ private dbProvider: DBProvider
25
+ ) {
26
+ this.appConfig = getAppConfig();
27
+ this.queueName = this.appConfig.BULL_QUEUE;
28
+ this.logger = createLogger(this, { queueName: this.queueName });
29
+ }
30
+
31
+ async start() {
32
+ await this.ensureTableExists();
33
+
34
+ const { options, prefix } = createRedisOptions('BULL');
35
+ this.observer = new QueueEvents(this.queueName, {
36
+ connection: options,
37
+ prefix: `${prefix}:bmq`
38
+ });
39
+
40
+ const queue = WorkerQueueRegistry.getQueue(this.appConfig.BULL_QUEUE);
41
+
42
+ this.observer.on('added', args => {
43
+ this.logger.info('Job added', {
44
+ jobId: args.jobId,
45
+ jobName: args.name
46
+ });
47
+ });
48
+ this.observer.on('active', args => {
49
+ this.logger.info('Job activated', { jobId: args.jobId });
50
+ });
51
+ this.observer.on('stalled', args => {
52
+ this.logger.warn('Job stalled', { jobId: args.jobId });
53
+ });
54
+ this.observer.on('delayed', args => {
55
+ this.logger.info('Job delayed', { jobId: args.jobId, delay: args.delay });
56
+ });
57
+ this.observer.on('completed', async args => {
58
+ this.logger.info('Job completed', { jobId: args.jobId });
59
+ const job = await queue.getJob(args.jobId);
60
+ if (job) {
61
+ await this.logJob(job, 'completed', args.returnvalue);
62
+ await queue.remove(job.id!);
63
+ }
64
+ });
65
+ this.observer.on('failed', async args => {
66
+ this.logger.info('Job failed', { jobId: args.jobId });
67
+ const job = await queue.getJob(args.jobId);
68
+ if (job) {
69
+ await this.logJob(job, 'failed', { reason: job.failedReason, stack: job.failedReason });
70
+ await queue.remove(job.id!);
71
+ }
72
+ });
73
+ this.observer.on('error', err => {
74
+ this.logger.error('Observer error:', err);
75
+ });
76
+
77
+ this.logger.info('Observer started');
78
+
79
+ const completedJobs = await queue.getCompleted();
80
+ for (const job of completedJobs) {
81
+ this.logger.info('Logging previously completed job', { jobId: job.id });
82
+ await this.logJob(job, 'completed', job.returnvalue);
83
+ await queue.remove(job.id!);
84
+ }
85
+
86
+ const failedJobs = await queue.getFailed();
87
+ for (const job of failedJobs) {
88
+ this.logger.error('Logging previously failed job', { jobId: job.id });
89
+ await this.logJob(job, 'failed', { reason: job.failedReason, stack: job.stacktrace });
90
+ await queue.remove(job.id!);
91
+ }
92
+
93
+ this.hcSvc.register(async () => {
94
+ if (!this.isRedisReady()) {
95
+ throw new Error('Observer Redis connection is not ready');
96
+ }
97
+ });
98
+ }
99
+
100
+ private isRedisReady() {
101
+ return this.observer?.['connection']['_client'].status === 'ready' || this.observer?.['connection']['_client'].status === 'wait';
102
+ }
103
+
104
+ private async ensureTableExists() {
105
+ const dialect = getDialect(this.db.adapter as SQLDatabaseAdapter);
106
+ const tableInfoRows = await this.db.rawQuery(tableExistsSql(dialect, '_jobs'));
107
+ if (tableInfoRows.length) return;
108
+
109
+ if (dialect === 'postgres') {
110
+ await this.db.rawExecute(`
111
+ CREATE TABLE "_jobs" (
112
+ "id" varchar(255) NOT NULL,
113
+ "queue" varchar(255) NOT NULL,
114
+ "queueId" varchar(255) NOT NULL,
115
+ "attempt" smallint NOT NULL,
116
+ "name" varchar(255) NOT NULL,
117
+ "data" jsonb DEFAULT NULL,
118
+ "traceId" char(32) DEFAULT NULL,
119
+ "status" varchar(20) NOT NULL CHECK ("status" IN ('completed','failed')),
120
+ "result" jsonb DEFAULT NULL,
121
+ "createdAt" timestamp NOT NULL,
122
+ "shouldExecuteAt" timestamp NOT NULL,
123
+ "executedAt" timestamp NOT NULL,
124
+ "completedAt" timestamp NOT NULL,
125
+ PRIMARY KEY ("id","attempt")
126
+ );
127
+ `);
128
+ } else {
129
+ await this.db.rawExecute(`
130
+ CREATE TABLE \`_jobs\` (
131
+ \`id\` varchar(255) NOT NULL,
132
+ \`queue\` varchar(255) NOT NULL,
133
+ \`queueId\` varchar(255) NOT NULL,
134
+ \`attempt\` tinyint unsigned NOT NULL,
135
+ \`name\` varchar(255) NOT NULL,
136
+ \`data\` json DEFAULT NULL,
137
+ \`traceId\` char(32) DEFAULT NULL,
138
+ \`status\` enum('completed','failed') NOT NULL,
139
+ \`result\` json DEFAULT NULL,
140
+ \`createdAt\` datetime NOT NULL,
141
+ \`shouldExecuteAt\` datetime NOT NULL,
142
+ \`executedAt\` datetime NOT NULL,
143
+ \`completedAt\` datetime NOT NULL,
144
+ PRIMARY KEY (\`id\`,\`attempt\`)
145
+ ) ENGINE=InnoDB;
146
+ `);
147
+ }
148
+ }
149
+
150
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
151
+ async logJob(job: Job, status: 'completed' | 'failed', result: any) {
152
+ try {
153
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
154
+ const traceparent = (job.opts as any).traceparent;
155
+ const traceId = traceparent ? traceparent.split('-')[1] : null;
156
+
157
+ await createPersistedEntity(JobEntity, {
158
+ id: `${this.queueName}:${job.id}`,
159
+ queue: this.queueName,
160
+ queueId: job.id!,
161
+ attempt: job.attemptsMade,
162
+ name: job.name,
163
+ data: job.data,
164
+ traceId,
165
+ status,
166
+ result,
167
+ createdAt: new Date(job.timestamp),
168
+ shouldExecuteAt: new Date(job.timestamp + (job.opts.delay ?? 0)),
169
+ executedAt: new Date(job.processedOn!),
170
+ completedAt: new Date(job.finishedOn!)
171
+ });
172
+ } catch (err) {
173
+ if (err instanceof UniqueConstraintFailure) {
174
+ this.logger.warn('Job already logged', { jobId: job.id });
175
+ } else {
176
+ throw err;
177
+ }
178
+ }
179
+ }
180
+ }
@@ -0,0 +1,34 @@
1
+ import { Queue } from 'bullmq';
2
+
3
+ import { getAppConfig } from '../../app/resolver';
4
+ import { createRedisOptions } from '../../helpers/redis/redis';
5
+
6
+ export class WorkerQueueRegistry {
7
+ static registry = new Map<string, Queue>();
8
+
9
+ static getDefaultQueue() {
10
+ const appConfig = getAppConfig();
11
+ return this.getQueue(appConfig.BULL_QUEUE);
12
+ }
13
+
14
+ static getQueue(name: string): Queue {
15
+ if (!this.registry.has(name)) {
16
+ const { options, prefix } = createRedisOptions('BULL');
17
+ this.registry.set(
18
+ name,
19
+ new Queue(name, {
20
+ connection: options,
21
+ prefix: `${prefix}:bmq`
22
+ })
23
+ );
24
+ }
25
+
26
+ return this.registry.get(name)!;
27
+ }
28
+
29
+ static async closeQueues() {
30
+ for (const queue of this.registry.values()) {
31
+ await queue.close();
32
+ }
33
+ }
34
+ }
@@ -0,0 +1,146 @@
1
+ import { SpanContext } from '@opentelemetry/api';
2
+ import { Job, Queue, Worker } from 'bullmq';
3
+
4
+ import { BaseAppConfig } from '../../app';
5
+ import { getAppConfig, resolveDeep } from '../../app/resolver';
6
+ import { HealthcheckService } from '../../health/healthcheck.service';
7
+ import { sleepSecs, withContextData } from '../../helpers';
8
+ import { getRegisteredClasses } from '../../helpers/framework/decorators';
9
+ import { createRedisOptions } from '../../helpers/redis/redis';
10
+ import { getTraceContext, setSpanAttributes, withRootSpan } from '../../telemetry';
11
+ import { createLogger, ExtendedLogger } from '../logger';
12
+ import { WorkerQueueRegistry } from './queue';
13
+ import { JobClass, WorkerSymbol } from './types';
14
+
15
+ export class WorkerRunnerService {
16
+ private appConfig: BaseAppConfig;
17
+ private queueName: string;
18
+ private logger: ExtendedLogger;
19
+ private worker?: Worker;
20
+ private queue?: Queue;
21
+ private jobHandlers = new Map<string, InstanceType<JobClass>>();
22
+ private runningJob?: Job;
23
+
24
+ constructor(private hcSvc: HealthcheckService) {
25
+ this.appConfig = getAppConfig();
26
+ this.queueName = this.appConfig.BULL_QUEUE;
27
+ this.logger = createLogger(this, { queue: this.queueName });
28
+ }
29
+
30
+ async start() {
31
+ this.queue = WorkerQueueRegistry.getQueue(this.queueName);
32
+
33
+ const allJobClasses = getRegisteredClasses<JobClass>(WorkerSymbol);
34
+
35
+ for (const jobClass of allJobClasses) {
36
+ if (jobClass.QUEUE_NAME === this.queueName) {
37
+ this.logger.info('Registering job', { id: { name: jobClass.name, schedule: jobClass.CRON_SCHEDULE } });
38
+
39
+ const handlerInstance = resolveDeep(jobClass);
40
+ if (!handlerInstance) throw new Error(`Cannot resolve job handler: ${jobClass.name}`);
41
+ this.jobHandlers.set(jobClass.name, handlerInstance);
42
+
43
+ if (jobClass.CRON_SCHEDULE) {
44
+ this.queue.add(jobClass.name, {}, { repeat: { pattern: jobClass.CRON_SCHEDULE } });
45
+ }
46
+ }
47
+ }
48
+
49
+ const { options, prefix } = createRedisOptions('BULL');
50
+
51
+ this.worker = new Worker(
52
+ this.queueName,
53
+ async job =>
54
+ this.withJobSpan(job, () =>
55
+ withContextData(
56
+ {
57
+ job: {
58
+ queue: this.queueName,
59
+ id: job.id,
60
+ name: job.name
61
+ },
62
+ traceId: getTraceContext()?.traceId
63
+ },
64
+ async () => {
65
+ const handler = this.jobHandlers.get(job.name);
66
+ if (!handler) {
67
+ throw new Error(`Job ${job.name} is not registered`);
68
+ }
69
+ try {
70
+ this.runningJob = job;
71
+ return await handler.handle(job.data);
72
+ } finally {
73
+ this.runningJob = undefined;
74
+ }
75
+ }
76
+ )
77
+ ),
78
+ {
79
+ concurrency: 1,
80
+ connection: options,
81
+ prefix: `${prefix}:bmq`
82
+ }
83
+ );
84
+
85
+ this.worker.on('active', job => {
86
+ this.logger.info('Job activated', { job: { name: job.name, id: job.id } });
87
+ });
88
+ this.worker.on('completed', job => {
89
+ this.logger.info('Job completed', { job: { name: job.name, id: job.id } });
90
+ });
91
+ this.worker.on('failed', (job, err) => {
92
+ this.logger.error(`Job failed: ${err.message}`, err, { job: job ? { name: job.name, id: job.id } : undefined });
93
+ });
94
+ this.worker.on('stalled', jobId => {
95
+ this.logger.warn('Job stalled', { jobId });
96
+ });
97
+ this.worker.on('error', err => {
98
+ this.logger.error('Worker error', err);
99
+ });
100
+ this.worker.on('ready', () => {
101
+ this.logger.info('Worker ready');
102
+ });
103
+ this.logger.info('Worker started');
104
+
105
+ this.hcSvc.register(async () => {
106
+ if (!this.isRedisReady()) {
107
+ throw new Error('Worker Redis connection is not ready');
108
+ }
109
+ });
110
+ }
111
+
112
+ private async withJobSpan<T>(job: Job, fn: () => Promise<T>) {
113
+ if (job.repeatJobKey) {
114
+ let innerSpan: SpanContext | undefined;
115
+ const result = await withRootSpan(`Job ${job.name}`, { jobId: job.id, schedulerTrace: getTraceContext()?.traceId }, () => {
116
+ innerSpan = getTraceContext();
117
+ return fn();
118
+ });
119
+ if (innerSpan) setSpanAttributes({ jobTraceId: innerSpan.traceId });
120
+ return result;
121
+ } else {
122
+ return fn();
123
+ }
124
+ }
125
+
126
+ private isRedisReady() {
127
+ return this.worker?.['blockingConnection']['_client'].status === 'ready' || this.worker?.['blockingConnection']['_client'].status === 'wait';
128
+ }
129
+
130
+ async shutdown() {
131
+ // there's something crazy going on with worker shutdown when it hasn't successfully connected to Redis
132
+ if (this.isRedisReady()) {
133
+ await this.worker?.pause(true);
134
+
135
+ while (this.runningJob) {
136
+ this.logger.warn('Waiting for job to finish', { job: { name: this.runningJob.name, id: this.runningJob.id } });
137
+ await sleepSecs(1);
138
+ }
139
+
140
+ await this.worker?.close();
141
+ } else {
142
+ this.worker?.close(true);
143
+ this.worker?.disconnect();
144
+ }
145
+ }
146
+ }
@@ -0,0 +1,32 @@
1
+ import { ClassType } from '@deepkit/core';
2
+
3
+ import { createRegistryClassDecorator } from '../../helpers/framework/decorators';
4
+
5
+ export const JobSymbol = Symbol('Job');
6
+ export const InputDataSymbol = Symbol('InputData');
7
+ export const OutputDataSymbol = Symbol('OutputData');
8
+
9
+ export const WorkerSymbol = Symbol('Worker');
10
+ export const WorkerJob = createRegistryClassDecorator(WorkerSymbol);
11
+
12
+ export abstract class BaseJob<I = void, O = void> {
13
+ [JobSymbol] = JobSymbol;
14
+ [InputDataSymbol]!: I;
15
+ [OutputDataSymbol]!: O;
16
+
17
+ static QUEUE_NAME = 'default';
18
+ static CRON_SCHEDULE: string | null = null;
19
+
20
+ abstract handle(data: I): Promise<O>;
21
+ }
22
+
23
+ export interface BaseJobClass {
24
+ QUEUE_NAME: string;
25
+ CRON_SCHEDULE: string | null;
26
+ }
27
+
28
+ export type JobClass = ClassType<BaseJob> & BaseJobClass;
29
+
30
+ export interface IJobOptions {
31
+ delay?: number;
32
+ }