@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,182 @@
1
+ import { InvalidValueException } from '@lakutata/core';
2
+ import { ServiceContext } from '../../context/ServiceContext.js';
3
+ import { ServiceResponseCodec } from '../../lib/ServiceResponseCodec.js';
4
+ import { ControllerActionNotFoundException } from '../../exceptions/ControllerActionNotFoundException.js';
5
+ import { EntrypointStoppedException } from '../../exceptions/EntrypointStoppedException.js';
6
+ /**
7
+ * The error codes of the JSON-RPC 2.0 responses sent by {@link jsonRPCServiceEntrypoint}.
8
+ */
9
+ export const JSONRPCErrorCode = {
10
+ /**
11
+ * The message is not valid JSON.
12
+ */
13
+ PARSE_ERROR: -32700,
14
+ /**
15
+ * The message is not a JSON-RPC 2.0 request (or is an empty batch, or the HTTP request is not a `POST` to the path).
16
+ */
17
+ INVALID_REQUEST: -32600,
18
+ /**
19
+ * No service action matches the request (`ControllerActionNotFoundException`).
20
+ */
21
+ METHOD_NOT_FOUND: -32601,
22
+ /**
23
+ * The params are given by position without the `positionalParams` option, or fail the action's input validation
24
+ * (`InvalidValueException`).
25
+ */
26
+ INVALID_PARAMS: -32602,
27
+ /**
28
+ * Reserved by the specification for the internal errors; the adapter does not send it.
29
+ */
30
+ INTERNAL_ERROR: -32603,
31
+ /**
32
+ * Any other error thrown by an action (in the server error range, -32000 to -32099), with the whole error object as
33
+ * the error's `data`.
34
+ */
35
+ SERVER_ERROR: -32000,
36
+ /**
37
+ * The entrypoint is stopping and refuses the new requests (`EntrypointStoppedException`).
38
+ */
39
+ STOPPING: -32001
40
+ };
41
+ /**
42
+ * Get the JSON-RPC request behind a service action's request, when {@link jsonRPCServiceEntrypoint} serves it (to
43
+ * tell a notification from a request, or read the transport).
44
+ * @param context The service action's context (`this.context` in a controller).
45
+ * @returns The request's method, id and transport, or `undefined` when another adapter serves the request.
46
+ * @example
47
+ * ```typescript
48
+ * import {Controller, ServiceContext} from 'lakutata/com/entrypoint'
49
+ * import {ServiceAction} from 'lakutata/decorator/ctrl'
50
+ * import {jsonRPCRequestOfContext, type JSONRPCRequestInfo} from 'lakutata/adapter/jsonrpc'
51
+ *
52
+ * class LogController extends Controller {
53
+ * //{"jsonrpc": "2.0", "method": "log.write", "params": {"line": "started"}}: a notification, no id
54
+ * @ServiceAction({method: 'log.write'})
55
+ * public async write(input: {line: string}): Promise<void> {
56
+ * const request: JSONRPCRequestInfo | undefined = jsonRPCRequestOfContext(this.context as ServiceContext)
57
+ * console.log(`${request?.transport}: ${input.line}`)
58
+ * }
59
+ * }
60
+ * ```
61
+ */
62
+ export function jsonRPCRequestOfContext(context) {
63
+ return context.jsonrpc;
64
+ }
65
+ /**
66
+ * An error of JSON-RPC
67
+ * @param id
68
+ * @param code
69
+ * @param message
70
+ * @param data
71
+ */
72
+ function errorResponse(id, code, message, data) {
73
+ return { jsonrpc: '2.0', id: id, error: { code: code, message: message, ...data === undefined ? {} : { data: data } } };
74
+ }
75
+ /**
76
+ * The code of an error of an action
77
+ * @param error
78
+ */
79
+ function errorCode(error) {
80
+ if (error instanceof ControllerActionNotFoundException)
81
+ return JSONRPCErrorCode.METHOD_NOT_FOUND;
82
+ if (error instanceof InvalidValueException)
83
+ return JSONRPCErrorCode.INVALID_PARAMS;
84
+ if (error instanceof EntrypointStoppedException)
85
+ return JSONRPCErrorCode.STOPPING;
86
+ return JSONRPCErrorCode.SERVER_ERROR;
87
+ }
88
+ /**
89
+ * The requests of JSON-RPC 2.0 dispatched to the service actions: the single ones, the batches, the notifications (no
90
+ * response); their methods given to the patterns of the actions
91
+ */
92
+ export class JSONRPCProtocol {
93
+ constructor(options = {}) {
94
+ this.options = options;
95
+ }
96
+ /**
97
+ * The pattern and the input of the action of a request
98
+ * @param request
99
+ * @protected
100
+ */
101
+ pattern(request) {
102
+ if (this.options.toPattern)
103
+ return this.options.toPattern(request.method, request.params);
104
+ const field = this.options.methodField ?? 'method';
105
+ if (Array.isArray(request.params)) {
106
+ if (!this.options.positionalParams)
107
+ throw Object.assign(new Error('The params by position are not accepted: give them by name (an object)'), { jsonrpcCode: JSONRPCErrorCode.INVALID_PARAMS });
108
+ return { [this.options.positionalParams]: request.params, [field]: request.method };
109
+ }
110
+ return { ...request.params ?? {}, [field]: request.method };
111
+ }
112
+ /**
113
+ * The response of a request (none for a notification)
114
+ * @param request
115
+ * @param dispatch
116
+ * @protected
117
+ */
118
+ async one(request, dispatch) {
119
+ const candidate = request;
120
+ const id = typeof candidate?.id === 'string' || typeof candidate?.id === 'number' ? candidate.id : null;
121
+ if (!candidate || typeof candidate !== 'object' || Array.isArray(candidate) || candidate.jsonrpc !== '2.0' || typeof candidate.method !== 'string'
122
+ || (candidate.params !== undefined && (candidate.params === null || typeof candidate.params !== 'object'))
123
+ || (candidate.id !== undefined && candidate.id !== null && typeof candidate.id !== 'string' && typeof candidate.id !== 'number')) {
124
+ return errorResponse(id, JSONRPCErrorCode.INVALID_REQUEST, 'The request is not a request of JSON-RPC 2.0');
125
+ }
126
+ const notification = !('id' in candidate);
127
+ const respond = (response) => notification ? undefined : response;
128
+ if (dispatch.stopping())
129
+ return respond(errorResponse(id, JSONRPCErrorCode.STOPPING, 'The entrypoint is stopping'));
130
+ let data;
131
+ try {
132
+ data = this.pattern(candidate);
133
+ }
134
+ catch (error) {
135
+ return respond(errorResponse(id, error.jsonrpcCode ?? JSONRPCErrorCode.INVALID_PARAMS, error.message));
136
+ }
137
+ try {
138
+ const context = new ServiceContext({
139
+ data: data,
140
+ clientId: dispatch.clientId,
141
+ jsonrpc: { method: candidate.method, id: candidate.id, transport: dispatch.transport },
142
+ ...dispatch.extra ?? {}
143
+ });
144
+ //A StatusResult sent as its data (a file or an event stream cannot be sent: an error)
145
+ const result = ServiceResponseCodec.payload(await dispatch.runtime.dispatch(context, { signal: dispatch.signal }));
146
+ return respond({ jsonrpc: '2.0', id: id, result: result === undefined ? null : result });
147
+ }
148
+ catch (error) {
149
+ //The error of the action: its message, the whole error as its data (as the other service adapters give it)
150
+ return respond(errorResponse(id, errorCode(error), error?.message || String(error), ServiceResponseCodec.encodeError(error).error));
151
+ }
152
+ }
153
+ /**
154
+ * The response of a message (a request, a batch): undefined when there is none (notifications)
155
+ * @param message its text
156
+ * @param dispatch
157
+ */
158
+ async handle(message, dispatch) {
159
+ let parsed;
160
+ try {
161
+ parsed = JSON.parse(message);
162
+ }
163
+ catch {
164
+ return errorResponse(null, JSONRPCErrorCode.PARSE_ERROR, 'The message is not JSON');
165
+ }
166
+ if (!Array.isArray(parsed))
167
+ return await this.one(parsed, dispatch);
168
+ if (!parsed.length)
169
+ return errorResponse(null, JSONRPCErrorCode.INVALID_REQUEST, 'The batch is empty');
170
+ const responses = await Promise.all(parsed.map((request) => this.one(request, dispatch)));
171
+ const answered = responses.filter((response) => !!response);
172
+ return answered.length ? answered : undefined;
173
+ }
174
+ /**
175
+ * A notification sent to a client (an event pushed)
176
+ * @param event
177
+ * @param args
178
+ */
179
+ static notification(event, args) {
180
+ return JSON.stringify({ jsonrpc: '2.0', method: event, params: args });
181
+ }
182
+ }
@@ -0,0 +1,361 @@
1
+ import { randomUUID } from 'node:crypto';
2
+ import { createServer } from 'node:http';
3
+ import { ServiceChannel } from '../../channel/BuiltinChannels.js';
4
+ import { JSONRPCErrorCode, JSONRPCProtocol } from './JSONRPCProtocol.js';
5
+ import { applicationOf } from '../../lib/ApplicationOf.js';
6
+ /**
7
+ * The headers of the responses of HTTP: the tools of the browsers may call the adapter
8
+ */
9
+ const CORS_HEADERS = {
10
+ 'Access-Control-Allow-Origin': '*',
11
+ 'Access-Control-Allow-Methods': 'POST, OPTIONS',
12
+ 'Access-Control-Allow-Headers': 'Content-Type, id'
13
+ };
14
+ /**
15
+ * The id of the client of a request of HTTP (its header id, its query id)
16
+ * @param request
17
+ */
18
+ function clientIdOf(request) {
19
+ const url = new URL(request.url ?? '/', 'http://localhost');
20
+ const given = request.headers.id ?? url.searchParams.get('id');
21
+ const id = Array.isArray(given) ? given[0] : given ?? undefined;
22
+ return id && id.length <= 200 ? id : undefined;
23
+ }
24
+ /**
25
+ * The body of a request, up to a limit
26
+ * @param request
27
+ * @param limit
28
+ */
29
+ async function readBody(request, limit) {
30
+ const chunks = [];
31
+ let size = 0;
32
+ for await (const chunk of request) {
33
+ size += chunk.length;
34
+ if (size > limit)
35
+ throw Object.assign(new Error(`The body of the request is larger than ${limit} bytes`), { status: 413 });
36
+ chunks.push(chunk);
37
+ }
38
+ return Buffer.concat(chunks).toString('utf8');
39
+ }
40
+ /**
41
+ * The messages of a stream framed by lines, or by their Content-Length headers. A message larger than the limit is
42
+ * skipped (the rest of its line, or the length its header declares, keeping the framing) and reported
43
+ * @param input
44
+ * @param framing
45
+ * @param limit
46
+ * @param receive
47
+ * @param ended
48
+ * @param oversized
49
+ */
50
+ function readMessages(input, framing, limit, receive, ended, oversized) {
51
+ let buffer = Buffer.alloc(0);
52
+ //The bytes of an oversized message still to skip (content-length), or its line being skipped (newline)
53
+ let skipping = 0;
54
+ let skippingLine = false;
55
+ const onData = (chunk) => {
56
+ buffer = Buffer.concat([buffer, typeof chunk === 'string' ? Buffer.from(chunk) : chunk]);
57
+ for (;;) {
58
+ if (skipping) {
59
+ const skipped = Math.min(skipping, buffer.length);
60
+ buffer = buffer.subarray(skipped);
61
+ skipping -= skipped;
62
+ if (skipping)
63
+ break;
64
+ }
65
+ if (framing === 'newline') {
66
+ const end = buffer.indexOf(0x0a);
67
+ if (end < 0) {
68
+ //A line growing over the limit: skipped up to its end
69
+ if (buffer.length > limit) {
70
+ buffer = Buffer.alloc(0);
71
+ if (!skippingLine)
72
+ oversized();
73
+ skippingLine = true;
74
+ }
75
+ break;
76
+ }
77
+ const tooLarge = skippingLine || end > limit;
78
+ const line = tooLarge ? '' : buffer.subarray(0, end).toString('utf8').trim();
79
+ buffer = buffer.subarray(end + 1);
80
+ if (tooLarge && !skippingLine)
81
+ oversized();
82
+ skippingLine = false;
83
+ if (line)
84
+ receive(line);
85
+ continue;
86
+ }
87
+ const headerEnd = buffer.indexOf('\r\n\r\n');
88
+ if (headerEnd < 0) {
89
+ //No header of a message: what is not one is dropped, its end kept (a part of the next header)
90
+ if (buffer.length > limit)
91
+ buffer = buffer.subarray(buffer.length - 3);
92
+ break;
93
+ }
94
+ const length = Number(buffer.subarray(0, headerEnd).toString('ascii').match(/content-length:\s*(\d+)/i)?.[1] ?? NaN);
95
+ if (!Number.isFinite(length)) {
96
+ //Not a header of a message: skipped
97
+ buffer = buffer.subarray(headerEnd + 4);
98
+ continue;
99
+ }
100
+ if (length > limit) {
101
+ //Its content skipped as it arrives
102
+ buffer = buffer.subarray(headerEnd + 4);
103
+ skipping = length;
104
+ oversized();
105
+ continue;
106
+ }
107
+ if (buffer.length < headerEnd + 4 + length)
108
+ break;
109
+ receive(buffer.subarray(headerEnd + 4, headerEnd + 4 + length).toString('utf8'));
110
+ buffer = buffer.subarray(headerEnd + 4 + length);
111
+ }
112
+ };
113
+ input.on('data', onData);
114
+ input.once('end', ended);
115
+ return () => {
116
+ input.off('data', onData);
117
+ input.off('end', ended);
118
+ };
119
+ }
120
+ /**
121
+ * Create a service adapter of an entrypoint served over JSON-RPC 2.0, on HTTP, WebSocket or stdio. Only the WebSocket
122
+ * transport needs an optional peer dependency, `ws`; without it, the entrypoint fails to start.
123
+ *
124
+ * A request's method and named params become the service action's pattern and input: by default
125
+ * `{"method": "user.get", "params": {"id": 1}}` is dispatched as `{method: 'user.get', id: 1}` (see
126
+ * {@link JSONRPCMappingOptions} for the other mappings). The batches are answered with an array of responses, the
127
+ * notifications (no `id`) run without a response. The action's result is the response's `result` (`null` for none);
128
+ * its error becomes a JSON-RPC error (see {@link JSONRPCErrorCode}): `METHOD_NOT_FOUND`, `INVALID_PARAMS` for a failed
129
+ * validation, otherwise `SERVER_ERROR` with the whole error object as its `data`.
130
+ *
131
+ * Over HTTP, a message is the body of a `POST` to the path, answered with 200 and the JSON response (204 when it held
132
+ * only notifications); any other method or path is answered with 404, and the CORS headers allow any origin. Over
133
+ * WebSocket and stdio, the events pushed by `Entrypoint.notify` and `Entrypoint.broadcast` are sent as notifications,
134
+ * `{"jsonrpc": "2.0", "method": event, "params": args}`. The client id carried by `ServiceContext.clientId` is the `id`
135
+ * header or `id` query parameter of the HTTP request or of the WebSocket connection (at most 200 characters; a random
136
+ * one for a WebSocket connection without it), and `'stdio'` on stdio.
137
+ *
138
+ * When an HTTP client disconnects before its response, the action's abort signal fires. When the entrypoint stops,
139
+ * stdio stops reading, the new requests are answered with `STOPPING`, and once the requests in progress are answered
140
+ * the WebSocket connections are closed (code 1001) and the server shuts down.
141
+ * @param options The adapter options; by default it serves HTTP on port 3000 of all the interfaces, on the path `/`.
142
+ * @returns The adapter, to give to the `service` option of `buildEntrypoints`.
143
+ * @example
144
+ * ```typescript
145
+ * import {Application} from 'lakutata'
146
+ * import {buildEntrypoints, Controller} from 'lakutata/com/entrypoint'
147
+ * import {ServiceAction} from 'lakutata/decorator/ctrl'
148
+ * import {jsonRPCServiceEntrypoint} from 'lakutata/adapter/jsonrpc'
149
+ * import WebSocket from 'ws'
150
+ *
151
+ * class UserController extends Controller {
152
+ * @ServiceAction({method: 'user.get'})
153
+ * public async get(input: {id: number}): Promise<{id: number, name: string}> {
154
+ * return {id: input.id, name: 'Ada'}
155
+ * }
156
+ * }
157
+ *
158
+ * Application.run({
159
+ * id: 'user.service',
160
+ * name: 'Users',
161
+ * components: {
162
+ * entrypoint: buildEntrypoints({
163
+ * controllers: [UserController],
164
+ * service: [
165
+ * //POST http://localhost:3000/rpc
166
+ * jsonRPCServiceEntrypoint({name: 'rpc-http', port: 3000, path: '/rpc'}),
167
+ * //ws://localhost:3001/rpc, with the events pushed
168
+ * jsonRPCServiceEntrypoint({name: 'rpc-ws', transport: 'websocket', port: 3001, path: '/rpc'})
169
+ * ]
170
+ * })
171
+ * }
172
+ * })
173
+ *
174
+ * //An HTTP client: {"jsonrpc": "2.0", "id": 1, "result": {"id": 1, "name": "Ada"}}
175
+ * const response: Response = await fetch('http://localhost:3000/rpc', {
176
+ * method: 'POST',
177
+ * headers: {'Content-Type': 'application/json'},
178
+ * body: JSON.stringify({jsonrpc: '2.0', id: 1, method: 'user.get', params: {id: 1}})
179
+ * })
180
+ * console.log(await response.json())
181
+ *
182
+ * //A WebSocket client, identified as client-1: the responses and the notifications arrive as messages
183
+ * const socket: WebSocket = new WebSocket('ws://localhost:3001/rpc?id=client-1')
184
+ * socket.on('open', (): void => socket.send(JSON.stringify({jsonrpc: '2.0', id: 2, method: 'user.get', params: {id: 2}})))
185
+ * socket.on('message', (data: WebSocket.RawData): void => console.log(JSON.parse(data.toString())))
186
+ * ```
187
+ */
188
+ export function jsonRPCServiceEntrypoint(options = {}) {
189
+ const transport = options.transport ?? 'http';
190
+ const protocol = new JSONRPCProtocol(options);
191
+ const limit = options.limit ?? 10 * 1024 * 1024;
192
+ const path = (options.path ?? '/').replace(/(.)\/+$/, '$1');
193
+ let stopping = false;
194
+ let server;
195
+ let webSocketServer;
196
+ let stopReading;
197
+ let heartbeat;
198
+ //The connections of each client (WebSocket), the output of stdio
199
+ const clients = new Map();
200
+ const inProgress = new Set();
201
+ const addClient = (clientId, send) => {
202
+ if (!clients.has(clientId))
203
+ clients.set(clientId, new Set());
204
+ clients.get(clientId).add(send);
205
+ return () => {
206
+ clients.get(clientId)?.delete(send);
207
+ if (!clients.get(clientId)?.size)
208
+ clients.delete(clientId);
209
+ };
210
+ };
211
+ /**
212
+ * Answer a message
213
+ * @param runtime
214
+ * @param message
215
+ * @param dispatch
216
+ * @param send
217
+ */
218
+ const answer = (runtime, message, dispatch, send) => {
219
+ const handled = protocol.handle(message, { ...dispatch, runtime: runtime, transport: transport, stopping: () => stopping })
220
+ .then((response) => {
221
+ if (response)
222
+ send(JSON.stringify(response));
223
+ })
224
+ .catch(() => undefined);
225
+ inProgress.add(handled);
226
+ void handled.finally(() => inProgress.delete(handled));
227
+ return handled;
228
+ };
229
+ const listen = async (target) => {
230
+ await new Promise((resolve, reject) => {
231
+ target.once('error', reject).listen(options.port ?? 3000, options.host, () => {
232
+ target.off('error', reject);
233
+ resolve();
234
+ });
235
+ });
236
+ await options.listening?.(target);
237
+ };
238
+ return {
239
+ channel: 'service',
240
+ definition: ServiceChannel,
241
+ name: options.name,
242
+ middlewares: options.middlewares,
243
+ start: async (runtime) => {
244
+ if (transport === 'stdio') {
245
+ const output = options.output ?? process.stdout;
246
+ const write = (message) => output.write(options.framing === 'content-length' ? `Content-Length: ${Buffer.byteLength(message)}\r\n\r\n${message}` : `${message}\n`);
247
+ addClient('stdio', write);
248
+ const ended = () => {
249
+ const mode = options.end ?? 'application';
250
+ //The requests in progress answered first
251
+ void Promise.allSettled([...inProgress]).then(async () => {
252
+ if (typeof mode === 'function')
253
+ return await mode();
254
+ if (mode === 'application')
255
+ applicationOf(runtime.module)?.exit(0);
256
+ });
257
+ };
258
+ //A message over the limit: an Invalid Request error, without id (it is not read)
259
+ const oversized = () => write(JSON.stringify({ jsonrpc: '2.0', id: null, error: { code: JSONRPCErrorCode.INVALID_REQUEST, message: `The message is larger than ${limit} bytes` } }));
260
+ stopReading = readMessages(options.input ?? process.stdin, options.framing ?? 'newline', limit, (message) => void answer(runtime, message, { clientId: 'stdio' }, write), ended, oversized);
261
+ return;
262
+ }
263
+ if (transport === 'http') {
264
+ server = createServer((request, response) => {
265
+ const url = new URL(request.url ?? '/', 'http://localhost');
266
+ if (request.method === 'OPTIONS')
267
+ return void response.writeHead(204, CORS_HEADERS).end();
268
+ if (request.method !== 'POST' || url.pathname !== path) {
269
+ return void response.writeHead(404, { ...CORS_HEADERS, 'Content-Type': 'application/json' }).end(JSON.stringify({ jsonrpc: '2.0', id: null, error: { code: -32600, message: `POST ${path} receives the requests of JSON-RPC 2.0` } }));
270
+ }
271
+ const aborted = new AbortController();
272
+ response.once('close', () => {
273
+ if (!response.writableFinished)
274
+ aborted.abort();
275
+ });
276
+ readBody(request, limit).then((body) => {
277
+ void answer(runtime, body, { clientId: clientIdOf(request), extra: { request: request }, signal: aborted.signal }, (message) => {
278
+ response.writeHead(200, { ...CORS_HEADERS, 'Content-Type': 'application/json; charset=utf-8' }).end(message);
279
+ }).then(() => {
280
+ //Only notifications: no content
281
+ if (!response.headersSent)
282
+ response.writeHead(204, CORS_HEADERS).end();
283
+ });
284
+ }, (error) => {
285
+ response.writeHead(error.status ?? 400, { ...CORS_HEADERS, 'Content-Type': 'application/json' }).end(JSON.stringify({ jsonrpc: '2.0', id: null, error: { code: -32600, message: error.message } }));
286
+ });
287
+ });
288
+ return await listen(server);
289
+ }
290
+ //WebSocket: the server of ws (an optional dependency)
291
+ let ws;
292
+ try {
293
+ ws = await import('ws');
294
+ }
295
+ catch {
296
+ throw new Error('The WebSocket transport of jsonRPCServiceEntrypoint needs the package ws (npm install ws)');
297
+ }
298
+ server = createServer((_request, response) => void response.writeHead(426, { 'Content-Type': 'text/plain' }).end('A WebSocket connection is expected'));
299
+ webSocketServer = new ws.WebSocketServer({ server: server, path: path, maxPayload: limit });
300
+ //Whether each connection answered the last ping
301
+ const alive = new WeakMap();
302
+ webSocketServer.on('connection', (socket, request) => {
303
+ const clientId = clientIdOf(request) ?? randomUUID();
304
+ const send = (message) => {
305
+ if (socket.readyState === 1)
306
+ socket.send(message);
307
+ };
308
+ const remove = addClient(clientId, send);
309
+ socket.on('message', (data, isBinary) => {
310
+ if (isBinary)
311
+ return;
312
+ void answer(runtime, Buffer.isBuffer(data) ? data.toString('utf8') : Array.isArray(data) ? Buffer.concat(data).toString('utf8') : Buffer.from(data).toString('utf8'), { clientId: clientId, extra: { socket: socket, request: request } }, send);
313
+ });
314
+ socket.on('close', remove);
315
+ socket.on('error', () => undefined);
316
+ socket.on('pong', () => alive.set(socket, true));
317
+ alive.set(socket, true);
318
+ });
319
+ //The connections which do not answer the pings closed (the ones a proxy dropped)
320
+ const interval = options.heartbeat ?? 30000;
321
+ if (interval > 0) {
322
+ heartbeat = setInterval(() => webSocketServer?.clients.forEach((socket) => {
323
+ if (!alive.get(socket))
324
+ return socket.terminate();
325
+ alive.set(socket, false);
326
+ socket.ping();
327
+ }), interval);
328
+ heartbeat.unref();
329
+ }
330
+ await listen(server);
331
+ },
332
+ stop: () => {
333
+ //The new requests are refused, the requests in progress end
334
+ stopping = true;
335
+ stopReading?.();
336
+ },
337
+ close: async () => {
338
+ clearInterval(heartbeat);
339
+ await Promise.allSettled([...inProgress]);
340
+ clients.clear();
341
+ if (webSocketServer) {
342
+ webSocketServer.clients.forEach((socket) => socket.close(1001, 'The service stops'));
343
+ await new Promise((resolve) => webSocketServer.close(() => resolve()));
344
+ }
345
+ if (!server)
346
+ return;
347
+ const closing = new Promise((resolve) => void server.close(() => resolve()));
348
+ server.closeAllConnections();
349
+ await closing;
350
+ },
351
+ notify: (clientId, event, args) => {
352
+ const connections = clients.get(clientId);
353
+ connections?.forEach((send) => send(JSONRPCProtocol.notification(event, args)));
354
+ return !!connections?.size;
355
+ },
356
+ broadcast: (event, args) => {
357
+ clients.forEach((connections) => connections.forEach((send) => send(JSONRPCProtocol.notification(event, args))));
358
+ return clients.size;
359
+ }
360
+ };
361
+ }