@lakutata/entrypoint 3.0.0-beta.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 (325) hide show
  1. package/LICENSE +23 -0
  2. package/README.md +183 -0
  3. package/THIRD_PARTY_NOTICES.md +206 -0
  4. package/dist/cjs/Entrypoint.d.ts +868 -0
  5. package/dist/cjs/Entrypoint.js +998 -0
  6. package/dist/cjs/adapter/commander/CommanderCLIEntrypoint.d.ts +192 -0
  7. package/dist/cjs/adapter/commander/CommanderCLIEntrypoint.js +439 -0
  8. package/dist/cjs/adapter/commander/Prompt.d.ts +22 -0
  9. package/dist/cjs/adapter/commander/Prompt.js +164 -0
  10. package/dist/cjs/adapter/commander/Width.d.ts +12 -0
  11. package/dist/cjs/adapter/commander/Width.js +67 -0
  12. package/dist/cjs/adapter/electron/ElectronIPCServiceEntrypoint.d.ts +203 -0
  13. package/dist/cjs/adapter/electron/ElectronIPCServiceEntrypoint.js +249 -0
  14. package/dist/cjs/adapter/express/ExpressHTTPEntrypoint.d.ts +172 -0
  15. package/dist/cjs/adapter/express/ExpressHTTPEntrypoint.js +301 -0
  16. package/dist/cjs/adapter/express/Responders.d.ts +89 -0
  17. package/dist/cjs/adapter/express/Responders.js +71 -0
  18. package/dist/cjs/adapter/express/StaticUI.d.ts +83 -0
  19. package/dist/cjs/adapter/express/StaticUI.js +104 -0
  20. package/dist/cjs/adapter/fastify/FastifyHTTPEntrypoint.d.ts +156 -0
  21. package/dist/cjs/adapter/fastify/FastifyHTTPEntrypoint.js +339 -0
  22. package/dist/cjs/adapter/fastify/Responders.d.ts +88 -0
  23. package/dist/cjs/adapter/fastify/Responders.js +77 -0
  24. package/dist/cjs/adapter/http/HTTPServiceEntrypoint.d.ts +117 -0
  25. package/dist/cjs/adapter/http/HTTPServiceEntrypoint.js +257 -0
  26. package/dist/cjs/adapter/jsonrpc/JSONRPCProtocol.d.ts +194 -0
  27. package/dist/cjs/adapter/jsonrpc/JSONRPCProtocol.js +187 -0
  28. package/dist/cjs/adapter/jsonrpc/JSONRPCServiceEntrypoint.d.ts +154 -0
  29. package/dist/cjs/adapter/jsonrpc/JSONRPCServiceEntrypoint.js +397 -0
  30. package/dist/cjs/adapter/schedule/ScheduleEntrypoint.d.ts +86 -0
  31. package/dist/cjs/adapter/schedule/ScheduleEntrypoint.js +275 -0
  32. package/dist/cjs/adapter/socket.io/SocketIOServiceEntrypoint.d.ts +138 -0
  33. package/dist/cjs/adapter/socket.io/SocketIOServiceEntrypoint.js +216 -0
  34. package/dist/cjs/channel/BuiltinChannels.d.ts +18 -0
  35. package/dist/cjs/channel/BuiltinChannels.js +128 -0
  36. package/dist/cjs/channel/Channel.d.ts +196 -0
  37. package/dist/cjs/channel/Channel.js +106 -0
  38. package/dist/cjs/channel/EntrypointAdapter.d.ts +195 -0
  39. package/dist/cjs/channel/EntrypointAdapter.js +43 -0
  40. package/dist/cjs/context/BaseContext.d.ts +75 -0
  41. package/dist/cjs/context/BaseContext.js +90 -0
  42. package/dist/cjs/context/CLIContext.d.ts +38 -0
  43. package/dist/cjs/context/CLIContext.js +53 -0
  44. package/dist/cjs/context/HTTPContext.d.ts +52 -0
  45. package/dist/cjs/context/HTTPContext.js +78 -0
  46. package/dist/cjs/context/ScheduleContext.d.ts +47 -0
  47. package/dist/cjs/context/ScheduleContext.js +65 -0
  48. package/dist/cjs/context/ServiceContext.d.ts +47 -0
  49. package/dist/cjs/context/ServiceContext.js +62 -0
  50. package/dist/cjs/decorators/CLIAction.d.ts +120 -0
  51. package/dist/cjs/decorators/CLIAction.js +13 -0
  52. package/dist/cjs/decorators/HTTPAction.d.ts +178 -0
  53. package/dist/cjs/decorators/HTTPAction.js +14 -0
  54. package/dist/cjs/decorators/Prefix.d.ts +44 -0
  55. package/dist/cjs/decorators/Prefix.js +48 -0
  56. package/dist/cjs/decorators/Schedule.d.ts +120 -0
  57. package/dist/cjs/decorators/Schedule.js +64 -0
  58. package/dist/cjs/decorators/ServiceAction.d.ts +116 -0
  59. package/dist/cjs/decorators/ServiceAction.js +12 -0
  60. package/dist/cjs/decorators/UseMiddlewares.d.ts +52 -0
  61. package/dist/cjs/decorators/UseMiddlewares.js +58 -0
  62. package/dist/cjs/decorators/http/DELETE.d.ts +87 -0
  63. package/dist/cjs/decorators/http/DELETE.js +7 -0
  64. package/dist/cjs/decorators/http/GET.d.ts +89 -0
  65. package/dist/cjs/decorators/http/GET.js +7 -0
  66. package/dist/cjs/decorators/http/HEAD.d.ts +84 -0
  67. package/dist/cjs/decorators/http/HEAD.js +7 -0
  68. package/dist/cjs/decorators/http/OPTIONS.d.ts +80 -0
  69. package/dist/cjs/decorators/http/OPTIONS.js +7 -0
  70. package/dist/cjs/decorators/http/PATCH.d.ts +90 -0
  71. package/dist/cjs/decorators/http/PATCH.js +7 -0
  72. package/dist/cjs/decorators/http/POST.d.ts +91 -0
  73. package/dist/cjs/decorators/http/POST.js +7 -0
  74. package/dist/cjs/decorators/http/PUT.d.ts +92 -0
  75. package/dist/cjs/decorators/http/PUT.js +7 -0
  76. package/dist/cjs/exceptions/AccessDeniedException.d.ts +10 -0
  77. package/dist/cjs/exceptions/AccessDeniedException.js +17 -0
  78. package/dist/cjs/exceptions/ControllerActionNotFoundException.d.ts +9 -0
  79. package/dist/cjs/exceptions/ControllerActionNotFoundException.js +16 -0
  80. package/dist/cjs/exceptions/DuplicateActionNameException.d.ts +8 -0
  81. package/dist/cjs/exceptions/DuplicateActionNameException.js +15 -0
  82. package/dist/cjs/exceptions/EntrypointStoppedException.d.ts +9 -0
  83. package/dist/cjs/exceptions/EntrypointStoppedException.js +16 -0
  84. package/dist/cjs/exceptions/InvalidActionGroupException.d.ts +4 -0
  85. package/dist/cjs/exceptions/InvalidActionGroupException.js +11 -0
  86. package/dist/cjs/exceptions/InvalidChannelException.d.ts +8 -0
  87. package/dist/cjs/exceptions/InvalidChannelException.js +15 -0
  88. package/dist/cjs/exceptions/InvalidEntrypointAdapterException.d.ts +9 -0
  89. package/dist/cjs/exceptions/InvalidEntrypointAdapterException.js +16 -0
  90. package/dist/cjs/exceptions/InvalidMiddlewareException.d.ts +8 -0
  91. package/dist/cjs/exceptions/InvalidMiddlewareException.js +15 -0
  92. package/dist/cjs/exceptions/InvalidPrefixException.d.ts +8 -0
  93. package/dist/cjs/exceptions/InvalidPrefixException.js +15 -0
  94. package/dist/cjs/exceptions/MiddlewareNextCalledException.d.ts +8 -0
  95. package/dist/cjs/exceptions/MiddlewareNextCalledException.js +15 -0
  96. package/dist/cjs/exceptions/RouteNotFoundException.d.ts +9 -0
  97. package/dist/cjs/exceptions/RouteNotFoundException.js +16 -0
  98. package/dist/cjs/exceptions/ServiceInvokeException.d.ts +11 -0
  99. package/dist/cjs/exceptions/ServiceInvokeException.js +14 -0
  100. package/dist/cjs/exports/CTRLDecorators.d.ts +13 -0
  101. package/dist/cjs/exports/CTRLDecorators.js +38 -0
  102. package/dist/cjs/exports/Channel.d.ts +14 -0
  103. package/dist/cjs/exports/Channel.js +33 -0
  104. package/dist/cjs/exports/CommanderAdapter.d.ts +1 -0
  105. package/dist/cjs/exports/CommanderAdapter.js +8 -0
  106. package/dist/cjs/exports/ElectronAdapter.d.ts +1 -0
  107. package/dist/cjs/exports/ElectronAdapter.js +9 -0
  108. package/dist/cjs/exports/Entrypoint.d.ts +24 -0
  109. package/dist/cjs/exports/Entrypoint.js +55 -0
  110. package/dist/cjs/exports/ExpressAdapter.d.ts +4 -0
  111. package/dist/cjs/exports/ExpressAdapter.js +15 -0
  112. package/dist/cjs/exports/FastifyAdapter.d.ts +4 -0
  113. package/dist/cjs/exports/FastifyAdapter.js +14 -0
  114. package/dist/cjs/exports/JSONRPCAdapter.d.ts +2 -0
  115. package/dist/cjs/exports/JSONRPCAdapter.js +11 -0
  116. package/dist/cjs/exports/SocketIOAdapter.d.ts +1 -0
  117. package/dist/cjs/exports/SocketIOAdapter.js +9 -0
  118. package/dist/cjs/lib/AccessControl.d.ts +118 -0
  119. package/dist/cjs/lib/AccessControl.js +208 -0
  120. package/dist/cjs/lib/AccessControlRule.d.ts +91 -0
  121. package/dist/cjs/lib/AccessControlRule.js +76 -0
  122. package/dist/cjs/lib/ActionOptions.d.ts +67 -0
  123. package/dist/cjs/lib/ActionOptions.js +67 -0
  124. package/dist/cjs/lib/ActionResult.d.ts +28 -0
  125. package/dist/cjs/lib/ActionResult.js +28 -0
  126. package/dist/cjs/lib/ApplicationOf.d.ts +6 -0
  127. package/dist/cjs/lib/ApplicationOf.js +14 -0
  128. package/dist/cjs/lib/Controller.d.ts +59 -0
  129. package/dist/cjs/lib/Controller.js +64 -0
  130. package/dist/cjs/lib/ControllerEntrypoint.d.ts +168 -0
  131. package/dist/cjs/lib/ControllerEntrypoint.js +239 -0
  132. package/dist/cjs/lib/GetActionDTOAndOptions.d.ts +29 -0
  133. package/dist/cjs/lib/GetActionDTOAndOptions.js +49 -0
  134. package/dist/cjs/lib/HTTPErrors.d.ts +55 -0
  135. package/dist/cjs/lib/HTTPErrors.js +52 -0
  136. package/dist/cjs/lib/Middleware.d.ts +146 -0
  137. package/dist/cjs/lib/Middleware.js +144 -0
  138. package/dist/cjs/lib/Prefix.d.ts +98 -0
  139. package/dist/cjs/lib/Prefix.js +151 -0
  140. package/dist/cjs/lib/Result.d.ts +173 -0
  141. package/dist/cjs/lib/Result.js +153 -0
  142. package/dist/cjs/lib/ServiceResponseCodec.d.ts +82 -0
  143. package/dist/cjs/lib/ServiceResponseCodec.js +117 -0
  144. package/dist/cjs/lib/StringifyPattern.d.ts +7 -0
  145. package/dist/cjs/lib/StringifyPattern.js +58 -0
  146. package/dist/cjs/lib/UnsetValue.d.ts +12 -0
  147. package/dist/cjs/lib/UnsetValue.js +216 -0
  148. package/dist/cjs/lib/pattern/GlobPattern.d.ts +34 -0
  149. package/dist/cjs/lib/pattern/GlobPattern.js +68 -0
  150. package/dist/cjs/lib/pattern/PatternManager.d.ts +103 -0
  151. package/dist/cjs/lib/pattern/PatternManager.js +233 -0
  152. package/dist/cjs/lib/schedule/Cron.d.ts +56 -0
  153. package/dist/cjs/lib/schedule/Cron.js +282 -0
  154. package/dist/cjs/package.json +1 -0
  155. package/dist/cjs/types/CLIContextParams.d.ts +14 -0
  156. package/dist/cjs/types/CLIContextParams.js +2 -0
  157. package/dist/cjs/types/ErrorDescription.d.ts +14 -0
  158. package/dist/cjs/types/ErrorDescription.js +2 -0
  159. package/dist/cjs/types/HTTPContextParams.d.ts +27 -0
  160. package/dist/cjs/types/HTTPContextParams.js +2 -0
  161. package/dist/cjs/types/ScheduleContextParams.d.ts +21 -0
  162. package/dist/cjs/types/ScheduleContextParams.js +2 -0
  163. package/dist/cjs/types/ServiceContextParams.d.ts +16 -0
  164. package/dist/cjs/types/ServiceContextParams.js +2 -0
  165. package/dist/esm/Entrypoint.js +985 -0
  166. package/dist/esm/adapter/commander/CommanderCLIEntrypoint.js +433 -0
  167. package/dist/esm/adapter/commander/Prompt.js +127 -0
  168. package/dist/esm/adapter/commander/Width.js +63 -0
  169. package/dist/esm/adapter/electron/ElectronIPCServiceEntrypoint.js +212 -0
  170. package/dist/esm/adapter/express/ExpressHTTPEntrypoint.js +295 -0
  171. package/dist/esm/adapter/express/Responders.js +66 -0
  172. package/dist/esm/adapter/express/StaticUI.js +96 -0
  173. package/dist/esm/adapter/fastify/FastifyHTTPEntrypoint.js +333 -0
  174. package/dist/esm/adapter/fastify/Responders.js +73 -0
  175. package/dist/esm/adapter/http/HTTPServiceEntrypoint.js +253 -0
  176. package/dist/esm/adapter/jsonrpc/JSONRPCProtocol.js +182 -0
  177. package/dist/esm/adapter/jsonrpc/JSONRPCServiceEntrypoint.js +361 -0
  178. package/dist/esm/adapter/schedule/ScheduleEntrypoint.js +272 -0
  179. package/dist/esm/adapter/socket.io/SocketIOServiceEntrypoint.js +212 -0
  180. package/dist/esm/channel/BuiltinChannels.js +125 -0
  181. package/dist/esm/channel/Channel.js +100 -0
  182. package/dist/esm/channel/EntrypointAdapter.js +39 -0
  183. package/dist/esm/context/BaseContext.js +87 -0
  184. package/dist/esm/context/CLIContext.js +49 -0
  185. package/dist/esm/context/HTTPContext.js +74 -0
  186. package/dist/esm/context/ScheduleContext.js +61 -0
  187. package/dist/esm/context/ServiceContext.js +58 -0
  188. package/dist/esm/decorators/CLIAction.js +10 -0
  189. package/dist/esm/decorators/HTTPAction.js +11 -0
  190. package/dist/esm/decorators/Prefix.js +45 -0
  191. package/dist/esm/decorators/Schedule.js +61 -0
  192. package/dist/esm/decorators/ServiceAction.js +9 -0
  193. package/dist/esm/decorators/UseMiddlewares.js +55 -0
  194. package/dist/esm/decorators/http/DELETE.js +4 -0
  195. package/dist/esm/decorators/http/GET.js +4 -0
  196. package/dist/esm/decorators/http/HEAD.js +4 -0
  197. package/dist/esm/decorators/http/OPTIONS.js +4 -0
  198. package/dist/esm/decorators/http/PATCH.js +4 -0
  199. package/dist/esm/decorators/http/POST.js +4 -0
  200. package/dist/esm/decorators/http/PUT.js +4 -0
  201. package/dist/esm/exceptions/AccessDeniedException.js +13 -0
  202. package/dist/esm/exceptions/ControllerActionNotFoundException.js +12 -0
  203. package/dist/esm/exceptions/DuplicateActionNameException.js +11 -0
  204. package/dist/esm/exceptions/EntrypointStoppedException.js +12 -0
  205. package/dist/esm/exceptions/InvalidActionGroupException.js +7 -0
  206. package/dist/esm/exceptions/InvalidChannelException.js +11 -0
  207. package/dist/esm/exceptions/InvalidEntrypointAdapterException.js +12 -0
  208. package/dist/esm/exceptions/InvalidMiddlewareException.js +11 -0
  209. package/dist/esm/exceptions/InvalidPrefixException.js +11 -0
  210. package/dist/esm/exceptions/MiddlewareNextCalledException.js +11 -0
  211. package/dist/esm/exceptions/RouteNotFoundException.js +12 -0
  212. package/dist/esm/exceptions/ServiceInvokeException.js +10 -0
  213. package/dist/esm/exports/CTRLDecorators.js +19 -0
  214. package/dist/esm/exports/Channel.js +11 -0
  215. package/dist/esm/exports/CommanderAdapter.js +1 -0
  216. package/dist/esm/exports/ElectronAdapter.js +1 -0
  217. package/dist/esm/exports/Entrypoint.js +22 -0
  218. package/dist/esm/exports/ExpressAdapter.js +3 -0
  219. package/dist/esm/exports/FastifyAdapter.js +3 -0
  220. package/dist/esm/exports/JSONRPCAdapter.js +2 -0
  221. package/dist/esm/exports/SocketIOAdapter.js +1 -0
  222. package/dist/esm/lib/AccessControl.js +204 -0
  223. package/dist/esm/lib/AccessControlRule.js +72 -0
  224. package/dist/esm/lib/ActionOptions.js +63 -0
  225. package/dist/esm/lib/ActionResult.js +24 -0
  226. package/dist/esm/lib/ApplicationOf.js +11 -0
  227. package/dist/esm/lib/Controller.js +61 -0
  228. package/dist/esm/lib/ControllerEntrypoint.js +229 -0
  229. package/dist/esm/lib/GetActionDTOAndOptions.js +46 -0
  230. package/dist/esm/lib/HTTPErrors.js +48 -0
  231. package/dist/esm/lib/Middleware.js +134 -0
  232. package/dist/esm/lib/Prefix.js +143 -0
  233. package/dist/esm/lib/Result.js +147 -0
  234. package/dist/esm/lib/ServiceResponseCodec.js +113 -0
  235. package/dist/esm/lib/StringifyPattern.js +55 -0
  236. package/dist/esm/lib/UnsetValue.js +213 -0
  237. package/dist/esm/lib/pattern/GlobPattern.js +64 -0
  238. package/dist/esm/lib/pattern/PatternManager.js +229 -0
  239. package/dist/esm/lib/schedule/Cron.js +277 -0
  240. package/dist/esm/types/CLIContextParams.js +1 -0
  241. package/dist/esm/types/ErrorDescription.js +1 -0
  242. package/dist/esm/types/HTTPContextParams.js +1 -0
  243. package/dist/esm/types/ScheduleContextParams.js +1 -0
  244. package/dist/esm/types/ServiceContextParams.js +1 -0
  245. package/dist/types/Entrypoint.d.ts +868 -0
  246. package/dist/types/adapter/commander/CommanderCLIEntrypoint.d.ts +192 -0
  247. package/dist/types/adapter/commander/Prompt.d.ts +22 -0
  248. package/dist/types/adapter/commander/Width.d.ts +12 -0
  249. package/dist/types/adapter/electron/ElectronIPCServiceEntrypoint.d.ts +203 -0
  250. package/dist/types/adapter/express/ExpressHTTPEntrypoint.d.ts +172 -0
  251. package/dist/types/adapter/express/Responders.d.ts +89 -0
  252. package/dist/types/adapter/express/StaticUI.d.ts +83 -0
  253. package/dist/types/adapter/fastify/FastifyHTTPEntrypoint.d.ts +156 -0
  254. package/dist/types/adapter/fastify/Responders.d.ts +88 -0
  255. package/dist/types/adapter/http/HTTPServiceEntrypoint.d.ts +117 -0
  256. package/dist/types/adapter/jsonrpc/JSONRPCProtocol.d.ts +194 -0
  257. package/dist/types/adapter/jsonrpc/JSONRPCServiceEntrypoint.d.ts +154 -0
  258. package/dist/types/adapter/schedule/ScheduleEntrypoint.d.ts +86 -0
  259. package/dist/types/adapter/socket.io/SocketIOServiceEntrypoint.d.ts +138 -0
  260. package/dist/types/channel/BuiltinChannels.d.ts +18 -0
  261. package/dist/types/channel/Channel.d.ts +196 -0
  262. package/dist/types/channel/EntrypointAdapter.d.ts +195 -0
  263. package/dist/types/context/BaseContext.d.ts +75 -0
  264. package/dist/types/context/CLIContext.d.ts +38 -0
  265. package/dist/types/context/HTTPContext.d.ts +52 -0
  266. package/dist/types/context/ScheduleContext.d.ts +47 -0
  267. package/dist/types/context/ServiceContext.d.ts +47 -0
  268. package/dist/types/decorators/CLIAction.d.ts +120 -0
  269. package/dist/types/decorators/HTTPAction.d.ts +178 -0
  270. package/dist/types/decorators/Prefix.d.ts +44 -0
  271. package/dist/types/decorators/Schedule.d.ts +120 -0
  272. package/dist/types/decorators/ServiceAction.d.ts +116 -0
  273. package/dist/types/decorators/UseMiddlewares.d.ts +52 -0
  274. package/dist/types/decorators/http/DELETE.d.ts +87 -0
  275. package/dist/types/decorators/http/GET.d.ts +89 -0
  276. package/dist/types/decorators/http/HEAD.d.ts +84 -0
  277. package/dist/types/decorators/http/OPTIONS.d.ts +80 -0
  278. package/dist/types/decorators/http/PATCH.d.ts +90 -0
  279. package/dist/types/decorators/http/POST.d.ts +91 -0
  280. package/dist/types/decorators/http/PUT.d.ts +92 -0
  281. package/dist/types/exceptions/AccessDeniedException.d.ts +10 -0
  282. package/dist/types/exceptions/ControllerActionNotFoundException.d.ts +9 -0
  283. package/dist/types/exceptions/DuplicateActionNameException.d.ts +8 -0
  284. package/dist/types/exceptions/EntrypointStoppedException.d.ts +9 -0
  285. package/dist/types/exceptions/InvalidActionGroupException.d.ts +4 -0
  286. package/dist/types/exceptions/InvalidChannelException.d.ts +8 -0
  287. package/dist/types/exceptions/InvalidEntrypointAdapterException.d.ts +9 -0
  288. package/dist/types/exceptions/InvalidMiddlewareException.d.ts +8 -0
  289. package/dist/types/exceptions/InvalidPrefixException.d.ts +8 -0
  290. package/dist/types/exceptions/MiddlewareNextCalledException.d.ts +8 -0
  291. package/dist/types/exceptions/RouteNotFoundException.d.ts +9 -0
  292. package/dist/types/exceptions/ServiceInvokeException.d.ts +11 -0
  293. package/dist/types/exports/CTRLDecorators.d.ts +13 -0
  294. package/dist/types/exports/Channel.d.ts +14 -0
  295. package/dist/types/exports/CommanderAdapter.d.ts +1 -0
  296. package/dist/types/exports/ElectronAdapter.d.ts +1 -0
  297. package/dist/types/exports/Entrypoint.d.ts +24 -0
  298. package/dist/types/exports/ExpressAdapter.d.ts +4 -0
  299. package/dist/types/exports/FastifyAdapter.d.ts +4 -0
  300. package/dist/types/exports/JSONRPCAdapter.d.ts +2 -0
  301. package/dist/types/exports/SocketIOAdapter.d.ts +1 -0
  302. package/dist/types/lib/AccessControl.d.ts +118 -0
  303. package/dist/types/lib/AccessControlRule.d.ts +91 -0
  304. package/dist/types/lib/ActionOptions.d.ts +67 -0
  305. package/dist/types/lib/ActionResult.d.ts +28 -0
  306. package/dist/types/lib/ApplicationOf.d.ts +6 -0
  307. package/dist/types/lib/Controller.d.ts +59 -0
  308. package/dist/types/lib/ControllerEntrypoint.d.ts +168 -0
  309. package/dist/types/lib/GetActionDTOAndOptions.d.ts +29 -0
  310. package/dist/types/lib/HTTPErrors.d.ts +55 -0
  311. package/dist/types/lib/Middleware.d.ts +146 -0
  312. package/dist/types/lib/Prefix.d.ts +98 -0
  313. package/dist/types/lib/Result.d.ts +173 -0
  314. package/dist/types/lib/ServiceResponseCodec.d.ts +82 -0
  315. package/dist/types/lib/StringifyPattern.d.ts +7 -0
  316. package/dist/types/lib/UnsetValue.d.ts +12 -0
  317. package/dist/types/lib/pattern/GlobPattern.d.ts +34 -0
  318. package/dist/types/lib/pattern/PatternManager.d.ts +103 -0
  319. package/dist/types/lib/schedule/Cron.d.ts +56 -0
  320. package/dist/types/types/CLIContextParams.d.ts +14 -0
  321. package/dist/types/types/ErrorDescription.d.ts +14 -0
  322. package/dist/types/types/HTTPContextParams.d.ts +27 -0
  323. package/dist/types/types/ScheduleContextParams.d.ts +21 -0
  324. package/dist/types/types/ServiceContextParams.d.ts +16 -0
  325. package/package.json +152 -0
@@ -0,0 +1,998 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.Entrypoint = exports.buildEntrypoints = exports.buildServiceEntrypoint = exports.buildHTTPEntrypoint = exports.buildCLIEntrypoint = exports.ScheduleContext = exports.ServiceContext = exports.HTTPContext = exports.CLIContext = exports.BaseContext = exports.ContextType = void 0;
13
+ const core_1 = require("@lakutata/core");
14
+ const di_1 = require("@lakutata/core/decorator/di");
15
+ const ControllerEntrypoint_js_1 = require("./lib/ControllerEntrypoint.js");
16
+ const Controller_js_1 = require("./lib/Controller.js");
17
+ const utils_1 = require("@lakutata/utils");
18
+ const dto_1 = require("@lakutata/core/decorator/dto");
19
+ const DuplicateActionNameException_js_1 = require("./exceptions/DuplicateActionNameException.js");
20
+ const AccessControl_js_1 = require("./lib/AccessControl.js");
21
+ const AccessControlRule_js_1 = require("./lib/AccessControlRule.js");
22
+ const InvalidActionGroupException_js_1 = require("./exceptions/InvalidActionGroupException.js");
23
+ const Middleware_js_1 = require("./lib/Middleware.js");
24
+ const Channel_js_1 = require("./channel/Channel.js");
25
+ const EntrypointAdapter_js_1 = require("./channel/EntrypointAdapter.js");
26
+ const InvalidEntrypointAdapterException_js_1 = require("./exceptions/InvalidEntrypointAdapterException.js");
27
+ const EntrypointStoppedException_js_1 = require("./exceptions/EntrypointStoppedException.js");
28
+ require("./channel/BuiltinChannels.js");
29
+ var BaseContext_js_1 = require("./context/BaseContext.js");
30
+ Object.defineProperty(exports, "ContextType", { enumerable: true, get: function () { return BaseContext_js_1.ContextType; } });
31
+ Object.defineProperty(exports, "BaseContext", { enumerable: true, get: function () { return BaseContext_js_1.BaseContext; } });
32
+ var CLIContext_js_1 = require("./context/CLIContext.js");
33
+ Object.defineProperty(exports, "CLIContext", { enumerable: true, get: function () { return CLIContext_js_1.CLIContext; } });
34
+ var HTTPContext_js_1 = require("./context/HTTPContext.js");
35
+ Object.defineProperty(exports, "HTTPContext", { enumerable: true, get: function () { return HTTPContext_js_1.HTTPContext; } });
36
+ var ServiceContext_js_1 = require("./context/ServiceContext.js");
37
+ Object.defineProperty(exports, "ServiceContext", { enumerable: true, get: function () { return ServiceContext_js_1.ServiceContext; } });
38
+ var ScheduleContext_js_1 = require("./context/ScheduleContext.js");
39
+ Object.defineProperty(exports, "ScheduleContext", { enumerable: true, get: function () { return ScheduleContext_js_1.ScheduleContext; } });
40
+ /**
41
+ * Type a CLI entrypoint in the style of lakutata 2.x; the function is returned as it is.
42
+ * @param entrypoint The function the entrypoint calls when it starts, with the module, the commands, the request
43
+ * handler and the destroyer registrar.
44
+ * @returns The same function, to give to the `cli` option of {@link buildEntrypoints}.
45
+ * @example
46
+ * ```typescript
47
+ * import {Application} from 'lakutata'
48
+ * import {buildCLIEntrypoint, buildEntrypoints, CLIContext, Controller} from 'lakutata/com/entrypoint'
49
+ * import {CLIAction} from 'lakutata/decorator/ctrl'
50
+ *
51
+ * class VersionController extends Controller {
52
+ * @CLIAction('version')
53
+ * public async version(): Promise<string> {
54
+ * return '1.0.0'
55
+ * }
56
+ * }
57
+ *
58
+ * Application.run(() => ({
59
+ * id: 'tool.app',
60
+ * name: 'Tool',
61
+ * components: {
62
+ * entrypoint: buildEntrypoints({
63
+ * controllers: [VersionController],
64
+ * //Run the command given as the first argument once the entrypoint starts
65
+ * cli: buildCLIEntrypoint(async (module, cliMap, handler): Promise<void> => {
66
+ * const command: string = process.argv[2] ?? 'version'
67
+ * if (cliMap.has(command)) console.log(await handler(new CLIContext({command: command, data: {}})))
68
+ * })
69
+ * })
70
+ * }
71
+ * }))
72
+ * ```
73
+ */
74
+ const buildCLIEntrypoint = (entrypoint) => entrypoint;
75
+ exports.buildCLIEntrypoint = buildCLIEntrypoint;
76
+ /**
77
+ * Type an HTTP entrypoint in the style of lakutata 2.x; the function is returned as it is.
78
+ * @param entrypoint The function the entrypoint calls when it starts, with the module, the routes, the request handler
79
+ * and the destroyer registrar.
80
+ * @returns The same function, to give to the `http` option of {@link buildEntrypoints}.
81
+ * @example
82
+ * ```typescript
83
+ * import {createServer, type Server} from 'node:http'
84
+ * import {Application} from 'lakutata'
85
+ * import {buildEntrypoints, buildHTTPEntrypoint, Controller, HTTPContext} from 'lakutata/com/entrypoint'
86
+ * import {GET} from 'lakutata/decorator/ctrl'
87
+ *
88
+ * class HealthController extends Controller {
89
+ * @GET('/health')
90
+ * public async health(): Promise<{status: string}> {
91
+ * return {status: 'ok'}
92
+ * }
93
+ * }
94
+ *
95
+ * Application.run(() => ({
96
+ * id: 'api.app',
97
+ * name: 'API',
98
+ * components: {
99
+ * entrypoint: buildEntrypoints({
100
+ * controllers: [HealthController],
101
+ * http: buildHTTPEntrypoint((module, routeMap, handler, registerDestroy): void => {
102
+ * const server: Server = createServer(async (request, response): Promise<void> => {
103
+ * const route: string = (request.url ?? '/').split('?')[0]
104
+ * const method: string = request.method ?? 'GET'
105
+ * if (!routeMap.get(route)?.has(method)) {
106
+ * response.writeHead(404).end()
107
+ * return
108
+ * }
109
+ * const abortController: AbortController = new AbortController()
110
+ * response.on('close', (): void => abortController.abort())
111
+ * try {
112
+ * const context: HTTPContext = new HTTPContext({route, method, request, response, data: {}})
113
+ * response.end(JSON.stringify(await handler(context, abortController)))
114
+ * } catch (error) {
115
+ * response.writeHead(500).end((error as Error).message)
116
+ * }
117
+ * }).listen(3000)
118
+ * registerDestroy((): Promise<void> => new Promise((resolve): void => void server.close((): void => resolve())))
119
+ * })
120
+ * })
121
+ * }
122
+ * }))
123
+ * ```
124
+ */
125
+ const buildHTTPEntrypoint = (entrypoint) => entrypoint;
126
+ exports.buildHTTPEntrypoint = buildHTTPEntrypoint;
127
+ /**
128
+ * Type a service entrypoint in the style of lakutata 2.x; the function is returned as it is.
129
+ * @param entrypoint The function the entrypoint calls when it starts, with the module, the request handler and the
130
+ * destroyer registrar.
131
+ * @returns The same function, to give to the `service` option of {@link buildEntrypoints}.
132
+ * @example
133
+ * ```typescript
134
+ * import {EventEmitter} from 'node:events'
135
+ * import {Application} from 'lakutata'
136
+ * import {buildEntrypoints, buildServiceEntrypoint, Controller, ServiceContext} from 'lakutata/com/entrypoint'
137
+ * import {ServiceAction} from 'lakutata/decorator/ctrl'
138
+ *
139
+ * declare const bus: EventEmitter
140
+ *
141
+ * class MathController extends Controller {
142
+ * @ServiceAction({ctrl: 'math', act: 'add'})
143
+ * public async add(input: {a: number, b: number}): Promise<number> {
144
+ * return input.a + input.b
145
+ * }
146
+ * }
147
+ *
148
+ * Application.run(() => ({
149
+ * id: 'math.app',
150
+ * name: 'Math',
151
+ * components: {
152
+ * entrypoint: buildEntrypoints({
153
+ * controllers: [MathController],
154
+ * //Each message of the bus is a request: its data matched against the patterns of the actions
155
+ * service: buildServiceEntrypoint((module, handler, registerDestroy): void => {
156
+ * const listener = async (data: Record<string, any>, reply: (result: unknown) => void): Promise<void> => {
157
+ * reply(await handler(new ServiceContext({data: data})))
158
+ * }
159
+ * bus.on('request', listener)
160
+ * registerDestroy((): void => void bus.off('request', listener))
161
+ * })
162
+ * })
163
+ * }
164
+ * }))
165
+ * ```
166
+ */
167
+ const buildServiceEntrypoint = (entrypoint) => entrypoint;
168
+ exports.buildServiceEntrypoint = buildServiceEntrypoint;
169
+ /**
170
+ * Type the options of the {@link Entrypoint} component; they are returned as they are. The applications of the
171
+ * `lakutata` package declare the entrypoint as the component `entrypoint`: give these options to it.
172
+ * @param options The controllers, middlewares, access rules and the adapters of each channel.
173
+ * @returns The same options, to declare as the `entrypoint` component.
174
+ * @example
175
+ * ```typescript
176
+ * import {Application, DTO} from 'lakutata'
177
+ * import {buildEntrypoints, Controller, scheduleEntrypoint} from 'lakutata/com/entrypoint'
178
+ * import {GET, POST, Schedule} from 'lakutata/decorator/ctrl'
179
+ * import {Expect} from 'lakutata/decorator/dto'
180
+ * import {expressHTTPEntrypoint} from 'lakutata/adapter/express'
181
+ *
182
+ * class CreateOrderDTO extends DTO {
183
+ * @Expect(DTO.String().required())
184
+ * public product: string
185
+ * }
186
+ *
187
+ * class OrderController extends Controller {
188
+ * @GET('/orders', {name: 'listOrders', groups: ['orders']})
189
+ * public async list(): Promise<string[]> {
190
+ * return []
191
+ * }
192
+ *
193
+ * @POST('/orders', CreateOrderDTO, {name: 'createOrder', groups: ['orders']})
194
+ * public async create(input: CreateOrderDTO): Promise<{product: string}> {
195
+ * return {product: input.product}
196
+ * }
197
+ *
198
+ * @Schedule('0 * * * *')
199
+ * public async purge(): Promise<void> {
200
+ * }
201
+ * }
202
+ *
203
+ * Application.run(() => ({
204
+ * id: 'shop.app',
205
+ * name: 'Shop',
206
+ * components: {
207
+ * entrypoint: buildEntrypoints({
208
+ * controllers: [OrderController],
209
+ * httpActionGroups: {orders: 'Orders'},
210
+ * shutdownTimeout: 10000,
211
+ * http: expressHTTPEntrypoint({port: 3000}),
212
+ * schedule: scheduleEntrypoint()
213
+ * })
214
+ * }
215
+ * }))
216
+ * ```
217
+ */
218
+ const buildEntrypoints = (options) => options;
219
+ exports.buildEntrypoints = buildEntrypoints;
220
+ /**
221
+ * The promises of the requests in progress (a request is in progress before its promise is created)
222
+ * @param requests
223
+ */
224
+ function promises(requests) {
225
+ return [...requests].map((request) => request.promise).filter((promise) => !!promise);
226
+ }
227
+ //The settlement of an aborted request
228
+ const ABORTED = Symbol('ABORTED');
229
+ //The options of the entrypoint which are not adapters
230
+ const ENTRYPOINT_OPTIONS = new Set(['class', 'id', 'controllers', 'middlewares', 'rules', 'shutdownTimeout', 'cliActionGroups', 'httpActionGroups', 'serviceActionGroups']);
231
+ //The channels accepting the callbacks of 2.x
232
+ const LEGACY_CHANNELS = new Set(['cli', 'http', 'service']);
233
+ /**
234
+ * The entrypoint component: it serves the controllers' actions to the requests of every channel (HTTP, CLI, service,
235
+ * schedule, and the channels of other packages), each received by the adapters configured for its channel.
236
+ *
237
+ * The applications of the `lakutata` package declare it as the component `entrypoint`: configure it with
238
+ * {@link buildEntrypoints}. When it initializes, it registers the controllers and checks their actions (their groups and
239
+ * the uniqueness of their names); then, in its startup, it starts the adapters in order (the objects their hooks get may
240
+ * inject the entrypoint; the objects getting the entrypoint wait for its adapters); it is ready (the adapters acting on
241
+ * their own, such as the schedules, begin) once the application has launched. Each request runs in a scope of its own: its middlewares,
242
+ * then a new controller instance receiving its context and signal, the validation of its input, the access control
243
+ * and the action; the scope is destroyed when the request ends.
244
+ *
245
+ * When it is destroyed, it stops the adapters in reverse order: each stops receiving requests, the requests in progress
246
+ * get `shutdownTimeout` milliseconds to complete and are then aborted (failing with an `EntrypointStoppedException`),
247
+ * and the adapter is closed.
248
+ * @example
249
+ * ```typescript
250
+ * import {Application, Component} from 'lakutata'
251
+ * import {buildEntrypoints, Controller, Entrypoint, ServiceContext} from 'lakutata/com/entrypoint'
252
+ * import {GET, ServiceAction} from 'lakutata/decorator/ctrl'
253
+ * import {Inject} from 'lakutata/decorator/di'
254
+ * import {expressHTTPEntrypoint} from 'lakutata/adapter/express'
255
+ * import {socketIOServiceEntrypoint} from 'lakutata/adapter/socket.io'
256
+ *
257
+ * class ChatController extends Controller {
258
+ * @Inject('entrypoint')
259
+ * protected readonly entrypoint: Entrypoint
260
+ *
261
+ * //Served over HTTP: GET /rooms
262
+ * @GET('/rooms')
263
+ * public async rooms(): Promise<string[]> {
264
+ * return ['general']
265
+ * }
266
+ *
267
+ * //Served over Socket.IO, the message pushed to every client
268
+ * @ServiceAction({act: 'say'})
269
+ * public async say(input: {text: string}): Promise<number> {
270
+ * const from: string | undefined = (this.context as ServiceContext).clientId
271
+ * return this.entrypoint.broadcast('message', from, input.text)
272
+ * }
273
+ * }
274
+ *
275
+ * Application
276
+ * .run(() => ({
277
+ * id: 'chat.app',
278
+ * name: 'Chat',
279
+ * components: {
280
+ * entrypoint: buildEntrypoints({
281
+ * controllers: [ChatController],
282
+ * http: expressHTTPEntrypoint({port: 3000}),
283
+ * service: socketIOServiceEntrypoint({port: 3001})
284
+ * })
285
+ * }
286
+ * }))
287
+ * .onLaunched(async (app: Application): Promise<void> => {
288
+ * const entrypoint: Entrypoint = await app.getObject<Entrypoint>('entrypoint')
289
+ * console.log(entrypoint.getHttpActions().actions.map(action => action.route)) //['/rooms']
290
+ * })
291
+ * ```
292
+ */
293
+ let Entrypoint = class Entrypoint extends core_1.Component {
294
+ constructor() {
295
+ super(...arguments);
296
+ /**
297
+ * The class running the access control of the actions declared with `acl: true` or a `rule`; a subclass of the
298
+ * entrypoint may replace it with a subclass of {@link AccessControl}.
299
+ * @protected
300
+ */
301
+ this.accessControl = AccessControl_js_1.AccessControl;
302
+ this.#channels = new Map();
303
+ this.#started = [];
304
+ this.#resolveReady = () => undefined;
305
+ /**
306
+ * Resolved once the adapters started and the application launched
307
+ */
308
+ this.#ready = new Promise((resolve) => {
309
+ this.#resolveReady = resolve;
310
+ });
311
+ /**
312
+ * The adapters to start, once the entrypoint is initialized
313
+ */
314
+ this.#adapters = [];
315
+ }
316
+ /**
317
+ * Whether an option which is not a configurable property is accepted: the adapters given under a channel's key,
318
+ * and the 2.x entrypoint functions under `cli`, `http` and `service`. The container calls it when it checks the
319
+ * component's options.
320
+ * @param name The option's key.
321
+ * @param value The option's value: one item or an array.
322
+ * @returns `true` when every item is an adapter, or a function under a 2.x channel's key.
323
+ */
324
+ static acceptsOption(name, value) {
325
+ const items = Array.isArray(value) ? value : [value];
326
+ return items.every((item) => (0, EntrypointAdapter_js_1.isEntrypointAdapter)(item) || (typeof item === 'function' && LEGACY_CHANNELS.has(name)));
327
+ }
328
+ #channels;
329
+ #started;
330
+ #stopping;
331
+ #resolveReady;
332
+ /**
333
+ * Resolved once the adapters started and the application launched
334
+ */
335
+ #ready;
336
+ /**
337
+ * The adapters to start, once the entrypoint is initialized
338
+ */
339
+ #adapters;
340
+ /**
341
+ * Register the controllers and the middleware classes and check the actions: once initialized, the entrypoint can be
342
+ * got by the other objects (its actions listed by `getHttpActions()`…), the adapters start in {@link startup}.
343
+ * @throws {InvalidMiddlewareException} When a middleware is neither a function nor a {@link Middleware} subclass.
344
+ * @throws {InvalidEntrypointAdapterException} When an option is neither an entrypoint option nor an adapter of its
345
+ * channel.
346
+ * @throws {InvalidActionGroupException} When an action is in a group missing from its channel's action groups.
347
+ * @throws {DuplicateActionNameException} When two actions of a channel have the same name.
348
+ * @protected
349
+ */
350
+ async init() {
351
+ (0, Middleware_js_1.validateMiddlewares)(this.middlewares);
352
+ const adapters = this.#adapters = this.configuredAdapters();
353
+ await Promise.all(this.controllers.map((controllerConstructor) => {
354
+ (0, ControllerEntrypoint_js_1.bindControllerToComponent)(this, controllerConstructor);
355
+ return this.container.register(controllerConstructor);
356
+ }));
357
+ (0, ControllerEntrypoint_js_1.getComponentControllerActionMap)(this).forEach((actions, channel) => this.#channels.set(channel, this.createChannelState((0, Channel_js_1.getChannel)(channel), actions)));
358
+ this.checkActions('CLI', this.#channels.get('cli')?.infos, this.cliActionGroups, 'cliActionGroups');
359
+ this.checkActions('HTTP', this.#channels.get('http')?.infos, this.httpActionGroups, 'httpActionGroups');
360
+ this.checkActions('Service', this.#channels.get('service')?.infos, this.serviceActionGroups, 'serviceActionGroups');
361
+ for (const [name, state] of this.#channels)
362
+ if (!LEGACY_CHANNELS.has(name))
363
+ this.checkActions(name, state.infos);
364
+ //The middleware classes are created in the container of each request
365
+ const middlewareClasses = new Set();
366
+ const addMiddlewareClasses = (middlewares) => middlewares.filter(Middleware_js_1.isMiddlewareClass).forEach((middlewareClass) => middlewareClasses.add(middlewareClass));
367
+ addMiddlewareClasses(this.middlewares);
368
+ this.#channels.forEach((state) => state.entries.forEach((entry) => addMiddlewareClasses(entry.middlewares)));
369
+ adapters.forEach((adapter) => addMiddlewareClasses((0, Middleware_js_1.validateMiddlewares)(adapter.middlewares ?? [])));
370
+ await Promise.all([...middlewareClasses].map((middlewareClass) => this.container.register(middlewareClass)));
371
+ }
372
+ /**
373
+ * Start the adapters in order, once the entrypoint is initialized: the objects their hooks get (an authenticator of
374
+ * the requests adding its middleware to an HTTP server) may inject the entrypoint. The objects getting the
375
+ * entrypoint wait for the adapters, and fail when one fails to start (a port in use).
376
+ * @protected
377
+ */
378
+ async startup() {
379
+ for (const adapter of this.#adapters)
380
+ await this.startAdapter(adapter);
381
+ }
382
+ /**
383
+ * Mark the entrypoint ready: the application has launched (in a bare container, once its adapters started).
384
+ * @protected
385
+ */
386
+ async launched() {
387
+ this.#resolveReady();
388
+ }
389
+ /**
390
+ * Stop the adapters, before the scopes of the requests in progress and the controllers are destroyed (see
391
+ * {@link Entrypoint.stopAdapters}).
392
+ * @protected
393
+ */
394
+ async beforeDestroy() {
395
+ await this.stopAdapters();
396
+ }
397
+ /**
398
+ * Stop the adapters in reverse order, once (a second call returns the same promise): each adapter stops receiving
399
+ * requests, its requests in progress get `shutdownTimeout` milliseconds before they are aborted, then it is closed.
400
+ * Every adapter is stopped even when another fails.
401
+ * @returns Resolves once every adapter is closed.
402
+ * @throws {AggregateError} When several adapters failed to stop or close; a single failure is thrown as it is.
403
+ * @protected
404
+ */
405
+ stopAdapters() {
406
+ this.#stopping ??= (async () => {
407
+ const errors = [];
408
+ for (const started of [...this.#started].reverse()) {
409
+ try {
410
+ await started.adapter.stop?.();
411
+ }
412
+ catch (e) {
413
+ errors.push(e);
414
+ }
415
+ await this.drain(started);
416
+ try {
417
+ await started.adapter.close?.();
418
+ }
419
+ catch (e) {
420
+ errors.push(e);
421
+ }
422
+ }
423
+ this.#started = [];
424
+ if (errors.length === 1)
425
+ throw errors[0];
426
+ if (errors.length)
427
+ throw new AggregateError(errors, 'Failed to stop the entrypoint adapters');
428
+ })();
429
+ return this.#stopping;
430
+ }
431
+ /**
432
+ * The adapters of the options: every option which is not an entrypoint option is a channel's key; a 2.x entrypoint
433
+ * function is wrapped in an adapter, the channel of an adapter carrying its definition is defined.
434
+ * @returns The adapters, in the order of the options.
435
+ * @throws {InvalidEntrypointAdapterException} When an adapter is given under another channel's key, its channel is
436
+ * not defined, or the option is neither an adapter nor a 2.x function of `cli`, `http` or `service`.
437
+ * @protected
438
+ */
439
+ configuredAdapters() {
440
+ const records = this.getConfigurableRecords();
441
+ const adapters = [];
442
+ for (const [key, value] of Object.entries(records)) {
443
+ if (ENTRYPOINT_OPTIONS.has(key) || value === undefined || value === null)
444
+ continue;
445
+ for (const item of Array.isArray(value) ? value : [value]) {
446
+ if (typeof item === 'function' && LEGACY_CHANNELS.has(key)) {
447
+ adapters.push(this.legacyAdapter(key, item));
448
+ }
449
+ else if ((0, EntrypointAdapter_js_1.isEntrypointAdapter)(item)) {
450
+ if (item.channel !== key)
451
+ throw new InvalidEntrypointAdapterException_js_1.InvalidEntrypointAdapterException('The option "{key}" is given an adapter of the channel "{channel}"', { key: key, channel: item.channel });
452
+ if (item.definition)
453
+ (0, Channel_js_1.defineChannel)(item.definition);
454
+ if (!(0, Channel_js_1.hasChannel)(key))
455
+ throw new InvalidEntrypointAdapterException_js_1.InvalidEntrypointAdapterException('The channel "{key}" of an adapter is not defined', { key: key });
456
+ adapters.push(item);
457
+ }
458
+ else {
459
+ throw new InvalidEntrypointAdapterException_js_1.InvalidEntrypointAdapterException('The option "{key}" is not an entrypoint option nor an adapter', { key: key });
460
+ }
461
+ }
462
+ }
463
+ return adapters;
464
+ }
465
+ /**
466
+ * Wrap a 2.x entrypoint function in an adapter: it is called when the adapter starts, in the entrypoint's
467
+ * {@link startup} (the entrypoint initialized: the objects it gets may inject the entrypoint, as in 2.x), and the
468
+ * promise of an asynchronous builder is awaited — its failure fails the entrypoint's startup, so the application's
469
+ * launch (2.x did not await it: the application launched without its server, the failure an unhandled rejection).
470
+ * Its registered destroyers run when the adapter stops.
471
+ * @param channel The channel: `cli`, `http` or `service`.
472
+ * @param callback The {@link CLIEntrypoint}, {@link HTTPEntrypoint} or {@link ServiceEntrypoint}.
473
+ * @returns The adapter.
474
+ * @protected
475
+ */
476
+ legacyAdapter(channel, callback) {
477
+ const destroyers = [];
478
+ const registerDestroy = (destroyer) => destroyers.push(destroyer);
479
+ return {
480
+ channel: channel,
481
+ start: async (runtime) => {
482
+ const handler = (context, abortController) => runtime.dispatch(context, { signal: abortController?.signal });
483
+ const run = () => {
484
+ switch (channel) {
485
+ case 'http': {
486
+ const routeMap = new Map();
487
+ for (const action of runtime.actions) {
488
+ const methods = routeMap.get(action.address.route) ?? new Set();
489
+ routeMap.set(action.address.route, methods.add(action.address.method));
490
+ }
491
+ return callback(runtime.module, routeMap, handler, registerDestroy);
492
+ }
493
+ case 'cli':
494
+ return callback(runtime.module, (0, EntrypointAdapter_js_1.commandMap)(runtime.actions), handler, registerDestroy);
495
+ default:
496
+ return callback(runtime.module, handler, registerDestroy);
497
+ }
498
+ };
499
+ await run();
500
+ },
501
+ stop: async () => {
502
+ await Promise.all(destroyers.map((destroyer) => Promise.resolve(destroyer())));
503
+ }
504
+ };
505
+ }
506
+ /**
507
+ * Collect the actions of a channel: their descriptions, their middlewares and the channel's lookup.
508
+ * @param definition The channel.
509
+ * @param actions The actions bound to the entrypoint for the channel, by address.
510
+ * @returns The channel's state.
511
+ * @protected
512
+ */
513
+ createChannelState(definition, actions) {
514
+ const entries = [];
515
+ const infos = new Map();
516
+ actions.forEach((details) => {
517
+ const info = {
518
+ id: details.id,
519
+ acl: details.acl,
520
+ name: details.name,
521
+ description: details.description,
522
+ groups: details.groups,
523
+ controller: details.constructor.className,
524
+ method: details.method.toString(),
525
+ jsonSchema: details.jsonSchema,
526
+ ...definition.describe(details.pattern)
527
+ };
528
+ infos.set(details.id, info);
529
+ entries.push({
530
+ details: details,
531
+ info: info,
532
+ address: { ...info, address: details.pattern, dto: details.dtoConstructor, returnSchema: (0, dto_1.getMethodReturnSchema)(details.constructor.prototype, (0, utils_1.As)(details.method)) },
533
+ middlewares: [
534
+ ...(0, Middleware_js_1.getClassMiddlewares)(details.constructor),
535
+ ...details.middlewares,
536
+ ...(0, Middleware_js_1.getMethodMiddlewares)(details.constructor, (0, utils_1.As)(details.method))
537
+ ]
538
+ });
539
+ });
540
+ return { definition: definition, entries: entries, infos: infos, matcher: definition.createMatcher(entries) };
541
+ }
542
+ /**
543
+ * Check a channel's actions: their groups are defined (when the channel has action groups) and their names unique.
544
+ * @param type The channel's name used in the error messages (`HTTP`, `CLI`…).
545
+ * @param actionInfoMap The channel's action descriptions by id; nothing is checked when it is `undefined`.
546
+ * @param actionGroups The channel's action groups; the groups are not checked without them.
547
+ * @param option The option holding the action groups, named in the error message.
548
+ * @throws {InvalidActionGroupException} When an action is in a group missing from `actionGroups`.
549
+ * @throws {DuplicateActionNameException} When two actions have the same name.
550
+ * @protected
551
+ */
552
+ checkActions(type, actionInfoMap, actionGroups, option) {
553
+ if (!actionInfoMap)
554
+ return;
555
+ if (actionGroups) {
556
+ const invalidGroupIds = this.findInvalidActionGroupIds(actionInfoMap, actionGroups);
557
+ if (invalidGroupIds.length)
558
+ throw new InvalidActionGroupException_js_1.InvalidActionGroupException('Found {type} action groups are not defined in {option}: {groupIds}', {
559
+ type: type,
560
+ option: option,
561
+ groupIds: invalidGroupIds
562
+ });
563
+ }
564
+ const duplicateNames = this.findDuplicateActionNames(actionInfoMap);
565
+ if (duplicateNames.length)
566
+ throw new DuplicateActionNameException_js_1.DuplicateActionNameException('Duplicate {type} action names found: {names}', {
567
+ type: type,
568
+ names: duplicateNames
569
+ });
570
+ }
571
+ /**
572
+ * Start an adapter, giving it the runtime of its channel (its actions and the dispatch functions).
573
+ * @param adapter The adapter.
574
+ * @throws {InvalidChannelException} When the adapter's channel is not defined.
575
+ * @protected
576
+ */
577
+ async startAdapter(adapter) {
578
+ const definition = (0, Channel_js_1.getChannel)(adapter.channel);
579
+ let state = this.#channels.get(definition.name);
580
+ if (!state) {
581
+ state = this.createChannelState(definition, new Map());
582
+ this.#channels.set(definition.name, state);
583
+ }
584
+ const started = { adapter: adapter, inflight: new Set() };
585
+ const channelState = state;
586
+ const runners = new Map();
587
+ const outerMiddlewares = [...this.middlewares, ...(adapter.middlewares ?? [])];
588
+ const runnerOf = (entry) => {
589
+ let runner = runners.get(entry);
590
+ if (!runner) {
591
+ runner = (0, Middleware_js_1.composeMiddlewares)([...outerMiddlewares, ...entry.middlewares], (invocation) => this.runAction(entry.details, invocation));
592
+ runners.set(entry, runner);
593
+ }
594
+ return runner;
595
+ };
596
+ const entriesByAddress = new Map(channelState.entries.map((entry) => [entry.address, entry]));
597
+ const runtime = {
598
+ channel: definition,
599
+ module: this.getModule(),
600
+ actions: channelState.entries.map((entry) => entry.address),
601
+ ready: this.#ready,
602
+ controllers: [...this.controllers],
603
+ getObject: (target) => this.getObject(target),
604
+ dispatch: async (context, options = {}) => {
605
+ const match = channelState.matcher.match(context);
606
+ if (!match)
607
+ throw definition.notFound(context);
608
+ const entry = (0, utils_1.As)(match.entry);
609
+ definition.prepare?.(entry, context);
610
+ return this.dispatch(started, entry, runnerOf(entry), context, { ...options, params: { ...match.params, ...options.params } });
611
+ },
612
+ dispatchTo: async (action, context, options = {}) => {
613
+ const entry = entriesByAddress.get(action);
614
+ if (!entry)
615
+ throw definition.notFound(context);
616
+ return this.dispatch(started, entry, runnerOf(entry), context, options);
617
+ }
618
+ };
619
+ await adapter.start(runtime);
620
+ this.#started.push(started);
621
+ }
622
+ /**
623
+ * Wait for a stopped adapter's requests in progress; abort the ones still running after `shutdownTimeout`
624
+ * milliseconds with an {@link EntrypointStoppedException}.
625
+ * @param started The adapter and its requests in progress.
626
+ * @protected
627
+ */
628
+ async drain(started) {
629
+ if (!started.inflight.size)
630
+ return;
631
+ let timer;
632
+ const timeout = new Promise((resolve) => {
633
+ timer = setTimeout(resolve, this.shutdownTimeout);
634
+ });
635
+ await Promise.race([Promise.allSettled(promises(started.inflight)), timeout]);
636
+ clearTimeout(timer);
637
+ const pending = [...started.inflight];
638
+ pending.forEach((request) => request.abortController.abort(new EntrypointStoppedException_js_1.EntrypointStoppedException('The entrypoint stopped before the request completed')));
639
+ //The aborted requests settle at once
640
+ await Promise.allSettled(promises(pending));
641
+ }
642
+ /**
643
+ * Run an action in its request's container: create the controller with the request's context and signal, validate
644
+ * the input (the request's data, overridden by the address parameters), check the access and call the action
645
+ * method with the validated input.
646
+ * @param details The action.
647
+ * @param invocation The request.
648
+ * @returns The action's result.
649
+ * @throws {Error} The input validation error, the access control's denial ({@link AccessDeniedException} or the
650
+ * rule's error), or the action's error.
651
+ * @protected
652
+ */
653
+ async runAction(details, invocation) {
654
+ const { context, container, params } = invocation;
655
+ //The controller of the request, shared by the objects of the request
656
+ const controller = await container.getShared(details.constructor, { context: context, signal: invocation.signal });
657
+ //The parameters of the address take precedence over the data of the request
658
+ const data = params && Object.keys(params).length ? { ...context.data, ...params } : context.data;
659
+ //The input is detached from the context, whose values are proxies validating their changes
660
+ const input = (0, utils_1.cloneDeep)(await this.validateInput(details.dtoConstructor, data, context.locale));
661
+ await this.runAccessControl(this.rules, container, (0, utils_1.As)(context), input, details);
662
+ return await controller.getMethod((0, utils_1.As)(details.method))(input);
663
+ }
664
+ /**
665
+ * Validate an action's input. An invalid input of a request with a language is validated again in it, so the
666
+ * error is in that language (a valid input is validated once, with the default settings).
667
+ * @param dtoConstructor The action's DTO.
668
+ * @param data The input to validate.
669
+ * @param locale The request's language (`context.locale`).
670
+ * @returns The validated input, with its defaults and conversions applied.
671
+ * @throws {Error} The validation error.
672
+ * @protected
673
+ */
674
+ async validateInput(dtoConstructor, data, locale) {
675
+ try {
676
+ return await dtoConstructor.validateAsync(data);
677
+ }
678
+ catch (error) {
679
+ if (!locale)
680
+ throw error;
681
+ return await dtoConstructor.validateAsync(data, { errors: { language: locale } });
682
+ }
683
+ }
684
+ /**
685
+ * Dispatch a request to an action in a new request container, tracked as in progress for its adapter until it
686
+ * ends. A request whose signal is already aborted is not run and resolves to `undefined`.
687
+ * @param started The adapter receiving the request.
688
+ * @param entry The action.
689
+ * @param runner The action's middleware pipeline.
690
+ * @param context The request's context.
691
+ * @param options The request's abort signal and address parameters.
692
+ * @returns The action's result, `undefined` when the request is aborted by its client.
693
+ * @protected
694
+ */
695
+ async dispatch(started, entry, runner, context, options) {
696
+ //An already aborted request is not executed at all
697
+ if (options.signal?.aborted)
698
+ return;
699
+ const request = { abortController: new AbortController() };
700
+ const abortRequest = () => request.abortController.abort();
701
+ options.signal?.addEventListener('abort', abortRequest, { once: true });
702
+ started.inflight.add(request);
703
+ try {
704
+ request.promise = this.execute(entry, runner, context, request.abortController.signal, options.params);
705
+ return await request.promise;
706
+ }
707
+ finally {
708
+ options.signal?.removeEventListener('abort', abortRequest);
709
+ started.inflight.delete(request);
710
+ }
711
+ }
712
+ /**
713
+ * Execute a request in a new request container, destroyed when it ends. An aborted request settles at once: its
714
+ * container is destroyed and its result or error dropped.
715
+ * @param entry The action.
716
+ * @param runner The action's middleware pipeline.
717
+ * @param context The request's context.
718
+ * @param signal The request's abort signal.
719
+ * @param params The parameters taken from the request's address.
720
+ * @returns The action's result, `undefined` when the request is aborted by its client.
721
+ * @throws {EntrypointStoppedException} When the request is aborted because the entrypoint stopped.
722
+ * @protected
723
+ */
724
+ async execute(entry, runner, context, signal, params) {
725
+ const runtimeContainer = this.createScope();
726
+ let isAborted = false;
727
+ let settleAborted = utils_1.DevNull;
728
+ const aborted = new Promise((resolve) => {
729
+ settleAborted = () => resolve(ABORTED);
730
+ });
731
+ //Aborting destroys the request scope right away (container destruction is idempotent) and settles the request
732
+ const abortHandler = () => {
733
+ isAborted = true;
734
+ runtimeContainer.destroy().catch(utils_1.DevNull);
735
+ settleAborted();
736
+ };
737
+ signal.addEventListener('abort', abortHandler, { once: true });
738
+ try {
739
+ const running = runner({
740
+ context: (0, utils_1.As)(context),
741
+ action: (0, utils_1.As)(entry.info),
742
+ container: runtimeContainer,
743
+ signal: signal,
744
+ params: params
745
+ });
746
+ //The action of an aborted request may still fail, its error is dropped
747
+ running.catch(utils_1.DevNull);
748
+ const result = await Promise.race([running, aborted]);
749
+ if (!isAborted)
750
+ return result;
751
+ }
752
+ catch (e) {
753
+ if (!isAborted)
754
+ throw e;
755
+ }
756
+ finally {
757
+ //The request scope is always destroyed once the dispatch ends, its destruction never rejects
758
+ signal.removeEventListener('abort', abortHandler);
759
+ runtimeContainer.destroy().catch(utils_1.DevNull);
760
+ }
761
+ //A request aborted by the stop of the entrypoint fails, a request aborted by its client has no result
762
+ if (signal.reason instanceof EntrypointStoppedException_js_1.EntrypointStoppedException)
763
+ throw signal.reason;
764
+ return undefined;
765
+ }
766
+ /**
767
+ * The descriptions of a channel's actions.
768
+ * @param channel The channel's name.
769
+ * @returns The descriptions, empty when the channel has no actions.
770
+ * @protected
771
+ */
772
+ actionInfos(channel) {
773
+ return (0, utils_1.As)([...(this.#channels.get(channel)?.infos.values() ?? [])]);
774
+ }
775
+ /**
776
+ * The descriptions of the HTTP actions.
777
+ * @protected
778
+ */
779
+ get HTTP_ACTIONS() {
780
+ return this.actionInfos('http');
781
+ }
782
+ /**
783
+ * The descriptions of the service actions.
784
+ * @protected
785
+ */
786
+ get SERVICE_ACTIONS() {
787
+ return this.actionInfos('service');
788
+ }
789
+ /**
790
+ * The descriptions of the CLI actions.
791
+ * @protected
792
+ */
793
+ get CLI_ACTIONS() {
794
+ return this.actionInfos('cli');
795
+ }
796
+ /**
797
+ * The actions of a channel, with the groups they belong to.
798
+ * @param channel The channel's name.
799
+ * @param actionGroups The group names by id.
800
+ * @returns The actions and their groups.
801
+ * @protected
802
+ */
803
+ getEntrypointActions(channel, actionGroups = {}) {
804
+ const groupMap = new Map();
805
+ const actions = this.actionInfos(channel);
806
+ actions.forEach((action) => {
807
+ action.groups.forEach((groupId) => {
808
+ if (!groupMap.has(groupId))
809
+ groupMap.set(groupId, {
810
+ id: groupId,
811
+ name: actionGroups[groupId],
812
+ actions: []
813
+ });
814
+ groupMap.get(groupId)?.actions.push(action);
815
+ });
816
+ });
817
+ return {
818
+ groups: [...groupMap.values()],
819
+ actions: actions
820
+ };
821
+ }
822
+ /**
823
+ * The group ids used by the actions but missing from the action groups.
824
+ * @param actionInfoMap The action descriptions by id.
825
+ * @param actionGroups The group names by id.
826
+ * @returns The missing group ids, each once.
827
+ * @protected
828
+ */
829
+ findInvalidActionGroupIds(actionInfoMap, actionGroups) {
830
+ const notfoundGroupIdSet = new Set();
831
+ actionInfoMap.forEach((action) => action.groups.forEach((groupId) => {
832
+ if (actionGroups[groupId] === undefined)
833
+ notfoundGroupIdSet.add(groupId);
834
+ }));
835
+ return [...notfoundGroupIdSet];
836
+ }
837
+ /**
838
+ * The names shared by the actions of several controller methods (the addresses of one method, such as its two
839
+ * routes, share its name).
840
+ * @param actionInfoMap The action descriptions by id.
841
+ * @returns The duplicate names, each once.
842
+ * @protected
843
+ */
844
+ findDuplicateActionNames(actionInfoMap) {
845
+ const methods = new Map();
846
+ const duplicates = new Set();
847
+ actionInfoMap.forEach((action) => {
848
+ const method = `${action.controller}:${action.method}`;
849
+ const seen = methods.get(action.name);
850
+ if (seen === undefined)
851
+ methods.set(action.name, method);
852
+ else if (seen !== method)
853
+ duplicates.add(action.name);
854
+ });
855
+ return [...duplicates];
856
+ }
857
+ /**
858
+ * Check the access to an action with {@link Entrypoint.accessControl}.
859
+ * @param rules The access control rule classes.
860
+ * @param runtimeContainer The request's container, where the rules are created.
861
+ * @param context The request's context.
862
+ * @param input The validated input.
863
+ * @param details The action.
864
+ * @throws {AccessDeniedException} When a rule denies the access (or the error a rule throws).
865
+ * @protected
866
+ */
867
+ async runAccessControl(rules, runtimeContainer, context, input, details) {
868
+ const [allowed, exception] = await this.accessControl.run(rules, runtimeContainer, context, input, details, (type) => {
869
+ const channel = (0, Channel_js_1.getChannelByContextType)(type);
870
+ return channel ? this.actionInfos(channel.name) : [];
871
+ });
872
+ if (!allowed)
873
+ throw exception;
874
+ }
875
+ /**
876
+ * Push an event to a client of the adapters which have clients (an Electron window's renderer, a Socket.IO
877
+ * socket); its listeners receive the arguments. The client of a service request is its `context.clientId`.
878
+ * @param clientId The client's id.
879
+ * @param event The event's name.
880
+ * @param args The arguments given to the client's listeners.
881
+ * @returns Whether an adapter has the client; `false` when it is gone or no adapter has clients.
882
+ */
883
+ notify(clientId, event, ...args) {
884
+ let notified = false;
885
+ for (const { adapter } of this.#started)
886
+ if (adapter.notify?.(clientId, event, args))
887
+ notified = true;
888
+ return notified;
889
+ }
890
+ /**
891
+ * Push an event to every client of the adapters which have clients (Electron windows, Socket.IO sockets); their
892
+ * listeners receive the arguments.
893
+ * @param event The event's name.
894
+ * @param args The arguments given to the clients' listeners.
895
+ * @returns The number of clients the event was pushed to.
896
+ */
897
+ broadcast(event, ...args) {
898
+ let clients = 0;
899
+ for (const { adapter } of this.#started)
900
+ clients += adapter.broadcast?.(event, args) ?? 0;
901
+ return clients;
902
+ }
903
+ /**
904
+ * The HTTP action groups configured by the `httpActionGroups` option.
905
+ * @returns The group names by id.
906
+ */
907
+ getHttpActionGroups() {
908
+ return this.httpActionGroups;
909
+ }
910
+ /**
911
+ * The service action groups configured by the `serviceActionGroups` option.
912
+ * @returns The group names by id.
913
+ */
914
+ getServiceActionGroups() {
915
+ return this.serviceActionGroups;
916
+ }
917
+ /**
918
+ * The CLI action groups configured by the `cliActionGroups` option.
919
+ * @returns The group names by id.
920
+ */
921
+ getCliActionGroups() {
922
+ return this.cliActionGroups;
923
+ }
924
+ /**
925
+ * The HTTP actions, with the groups they belong to (named after `httpActionGroups`).
926
+ * @returns The actions and their groups.
927
+ */
928
+ getHttpActions() {
929
+ return this.getEntrypointActions('http', this.httpActionGroups);
930
+ }
931
+ /**
932
+ * The service actions, with the groups they belong to (named after `serviceActionGroups`).
933
+ * @returns The actions and their groups.
934
+ */
935
+ getServiceActions() {
936
+ return this.getEntrypointActions('service', this.serviceActionGroups);
937
+ }
938
+ /**
939
+ * The CLI actions, with the groups they belong to (named after `cliActionGroups`).
940
+ * @returns The actions and their groups.
941
+ */
942
+ getCliActions() {
943
+ return this.getEntrypointActions('cli', this.cliActionGroups);
944
+ }
945
+ /**
946
+ * The actions of any channel, with the groups they belong to; the groups have no name (use the methods of the
947
+ * built-in channels, such as {@link Entrypoint.getHttpActions}, for named groups).
948
+ * @param channel The channel's name (`http`, `cli`, `service`, `schedule`, or a channel of another package).
949
+ * @returns The actions and their groups, empty when the channel has no actions.
950
+ */
951
+ getActions(channel) {
952
+ return this.getEntrypointActions(channel);
953
+ }
954
+ };
955
+ exports.Entrypoint = Entrypoint;
956
+ __decorate([
957
+ (0, di_1.Configurable)(core_1.DTO.Array(core_1.DTO.Class(Controller_js_1.Controller)).optional().default([])),
958
+ __metadata("design:type", Array)
959
+ ], Entrypoint.prototype, "controllers", void 0);
960
+ __decorate([
961
+ (0, di_1.Configurable)(core_1.DTO.Array(core_1.DTO.Function()).optional().default([])),
962
+ __metadata("design:type", Array)
963
+ ], Entrypoint.prototype, "middlewares", void 0);
964
+ __decorate([
965
+ (0, di_1.Configurable)(core_1.DTO.Array(core_1.DTO.Class(AccessControlRule_js_1.AccessControlRule)).optional().default([])),
966
+ __metadata("design:type", Array)
967
+ ], Entrypoint.prototype, "rules", void 0);
968
+ __decorate([
969
+ (0, di_1.Configurable)(core_1.DTO.Number().integer().min(0).optional().default(30000)),
970
+ __metadata("design:type", Number)
971
+ ], Entrypoint.prototype, "shutdownTimeout", void 0);
972
+ __decorate([
973
+ (0, di_1.Configurable)(core_1.DTO.Object().pattern(core_1.DTO.String(), core_1.DTO.String()).optional().default({})),
974
+ __metadata("design:type", Object)
975
+ ], Entrypoint.prototype, "cliActionGroups", void 0);
976
+ __decorate([
977
+ (0, di_1.Configurable)(core_1.DTO.Object().pattern(core_1.DTO.String(), core_1.DTO.String()).optional().default({})),
978
+ __metadata("design:type", Object)
979
+ ], Entrypoint.prototype, "httpActionGroups", void 0);
980
+ __decorate([
981
+ (0, di_1.Configurable)(core_1.DTO.Object().pattern(core_1.DTO.String(), core_1.DTO.String()).optional().default({})),
982
+ __metadata("design:type", Object)
983
+ ], Entrypoint.prototype, "serviceActionGroups", void 0);
984
+ __decorate([
985
+ (0, di_1.Configurable)(),
986
+ __metadata("design:type", Object)
987
+ ], Entrypoint.prototype, "cli", void 0);
988
+ __decorate([
989
+ (0, di_1.Configurable)(),
990
+ __metadata("design:type", Object)
991
+ ], Entrypoint.prototype, "http", void 0);
992
+ __decorate([
993
+ (0, di_1.Configurable)(),
994
+ __metadata("design:type", Object)
995
+ ], Entrypoint.prototype, "service", void 0);
996
+ exports.Entrypoint = Entrypoint = __decorate([
997
+ (0, di_1.Singleton)()
998
+ ], Entrypoint);