@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,156 @@
1
+ import { type FastifyInstance, type FastifyReply, type FastifyRequest, type FastifyServerOptions } from 'fastify';
2
+ import type { Server } from 'node:http';
3
+ import type { Module } from '@lakutata/core';
4
+ import type { EntrypointAdapter } from '../../channel/EntrypointAdapter.js';
5
+ import type { MiddlewareDefinition } from '../../lib/Middleware.js';
6
+ import { HTTPContext } from '../../context/HTTPContext.js';
7
+ import { type FastifyResponder } from './Responders.js';
8
+ /**
9
+ * What the `before` hook of {@link fastifyHTTPEntrypoint} receives besides the fastify instance: the entrypoint's
10
+ * module, the HTTP server (not listening yet) and the routes the actions will occupy.
11
+ */
12
+ export type FastifyHookContext = {
13
+ /**
14
+ * The module owning the entrypoint, to get the application's objects from (`await module.getObject('db')`).
15
+ */
16
+ readonly module: Module;
17
+ /**
18
+ * The HTTP server of the fastify instance. It does not listen yet when the hook runs; attach other servers to it
19
+ * there (such as a socket.io server, see the `server` option of `socketIOServiceEntrypoint`).
20
+ */
21
+ readonly server: Server;
22
+ /**
23
+ * Each action route mapped to its HTTP methods, in upper case (`'/users/:id'` → `{'GET', 'DELETE'}`).
24
+ */
25
+ readonly routes: Map<string, Set<string>>;
26
+ /**
27
+ * The first segment of each action route (`'/device'`, `'/user'`…). A route starting with a parameter (`/:id`)
28
+ * adds none.
29
+ */
30
+ readonly actionPrefixes: string[];
31
+ /**
32
+ * Tell whether a request path belongs to the actions: it equals one of the action prefixes or starts with one
33
+ * followed by `/`.
34
+ */
35
+ readonly isActionPath: (requestPath: string) => boolean;
36
+ };
37
+ /**
38
+ * The options of {@link fastifyHTTPEntrypoint}.
39
+ */
40
+ export type FastifyHTTPEntrypointOptions = {
41
+ /**
42
+ * The adapter name, to tell apart several HTTP adapters of one entrypoint.
43
+ */
44
+ name?: string;
45
+ /**
46
+ * The port the server listens on; 0 picks a random free port. The entrypoint fails to start when the port is in use.
47
+ * @default 80
48
+ */
49
+ port?: number;
50
+ /**
51
+ * The host or address the server listens on.
52
+ * @default every interface, as the other HTTP adapters (`::`, or `0.0.0.0` without IPv6)
53
+ */
54
+ host?: string;
55
+ /**
56
+ * An existing fastify instance to add the action routes to, or the options of the instance to create (`bodyLimit`,
57
+ * `trustProxy`, `logger`…). The adapter closes the instance when it stops, a given one included.
58
+ * @default a new fastify instance with its default options (a body limit of 1 MiB)
59
+ */
60
+ fastify?: FastifyInstance | FastifyServerOptions;
61
+ /**
62
+ * Build an action's input from a request. The route parameters are always merged over its result.
63
+ * @default the query parameters, then the properties of an object body over them (an array body is ignored)
64
+ */
65
+ input?: (request: FastifyRequest) => Record<string, unknown>;
66
+ /**
67
+ * How the results and the errors of the actions are written.
68
+ * @default FastifyJSONResponder
69
+ */
70
+ respond?: FastifyResponder;
71
+ /**
72
+ * The middlewares of this adapter's actions, run after the entrypoint's global middlewares.
73
+ */
74
+ middlewares?: MiddlewareDefinition[];
75
+ /**
76
+ * Run before the action routes are added, to register the application's own plugins, hooks and routes. A failure
77
+ * fails the entrypoint start.
78
+ */
79
+ before?: (app: FastifyInstance, context: FastifyHookContext) => void | Promise<void>;
80
+ /**
81
+ * The handler of the requests that match no route and whose path is outside the action prefixes, such as the pages
82
+ * of a web application. The unmatched requests inside the action prefixes, and all of them without a fallback, are
83
+ * answered with a `RouteNotFoundException` (404).
84
+ */
85
+ fallback?: (request: FastifyRequest, reply: FastifyReply) => unknown;
86
+ /**
87
+ * Run when the adapter stops, after the server is closed.
88
+ */
89
+ stop?: () => void | Promise<void>;
90
+ /**
91
+ * The interval between the comments keeping the event streams (`EventsResult`) alive through the proxies, in
92
+ * milliseconds.
93
+ * @default 15000
94
+ */
95
+ heartbeat?: number;
96
+ };
97
+ /**
98
+ * Create the HTTP adapter of an entrypoint served by a fastify instance: each HTTP action (`@GET`, `@POST`,
99
+ * `@HTTPAction`…) becomes a fastify route. It needs the optional peer dependency `fastify`.
100
+ *
101
+ * An action's input is the request's query and body (see the `input` option) with the route parameters merged over
102
+ * them. Its result is written by the responder (JSON by default, 204 for no result); a `StatusResult` sets the status
103
+ * and the headers, a `FileResult` sends a file, a buffer or a stream (its content type guessed from the extension of
104
+ * its file name, 304 when its ETag matches `If-None-Match`), and an `EventsResult` streams Server-Sent Events. An action
105
+ * that writes the response itself (through `HTTPContext.response`) is left alone. The errors, those of fastify included
106
+ * (a body too large: 413, a malformed JSON body: 400), are written by the responder with their status (500 by default).
107
+ * A GET action also answers HEAD, unless a HEAD action is declared for its route.
108
+ *
109
+ * When the client disconnects before the response, the action's abort signal fires and nothing is written. When the
110
+ * entrypoint stops, fastify stops accepting connections and answers the new requests with 503, the event streams end,
111
+ * and the requests in progress are given up to one second after they settle to send their responses before the
112
+ * remaining connections are closed.
113
+ * @param options The adapter options; by default it listens on port 80 with a new fastify instance.
114
+ * @returns The adapter, to give to the `http` option of `buildEntrypoints`.
115
+ * @example
116
+ * ```typescript
117
+ * import {Application} from 'lakutata'
118
+ * import {buildEntrypoints, Controller} from 'lakutata/com/entrypoint'
119
+ * import {GET, POST} from 'lakutata/decorator/ctrl'
120
+ * import {fastifyHTTPEntrypoint} from 'lakutata/adapter/fastify'
121
+ *
122
+ * class UserController extends Controller {
123
+ * //GET /users/1?verbose=true: the route parameter id merged over the query
124
+ * @GET('/users/:id')
125
+ * public async get(input: {id: string, verbose?: string}): Promise<{id: string}> {
126
+ * return {id: input.id}
127
+ * }
128
+ *
129
+ * //POST /users with the JSON body {"name": "Ada"}
130
+ * @POST('/users')
131
+ * public async create(input: {name: string}): Promise<{name: string}> {
132
+ * return {name: input.name}
133
+ * }
134
+ * }
135
+ *
136
+ * Application.run({
137
+ * id: 'web.app',
138
+ * name: 'Web',
139
+ * components: {
140
+ * entrypoint: buildEntrypoints({
141
+ * controllers: [UserController],
142
+ * http: fastifyHTTPEntrypoint({
143
+ * port: 8080,
144
+ * host: '0.0.0.0',
145
+ * fastify: {bodyLimit: 5 * 1024 * 1024, trustProxy: true},
146
+ * //The application's own routes
147
+ * before: (app): void => {
148
+ * app.get('/health', async (): Promise<string> => 'ok')
149
+ * }
150
+ * })
151
+ * })
152
+ * }
153
+ * })
154
+ * ```
155
+ */
156
+ export declare function fastifyHTTPEntrypoint(options?: FastifyHTTPEntrypointOptions): EntrypointAdapter<HTTPContext>;
@@ -0,0 +1,339 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.fastifyHTTPEntrypoint = fastifyHTTPEntrypoint;
7
+ const fastify_1 = __importDefault(require("fastify"));
8
+ const node_fs_1 = require("node:fs");
9
+ const node_path_1 = __importDefault(require("node:path"));
10
+ const HTTPContext_js_1 = require("../../context/HTTPContext.js");
11
+ const BuiltinChannels_js_1 = require("../../channel/BuiltinChannels.js");
12
+ const Result_js_1 = require("../../lib/Result.js");
13
+ const RouteNotFoundException_js_1 = require("../../exceptions/RouteNotFoundException.js");
14
+ const Responders_js_1 = require("./Responders.js");
15
+ /**
16
+ * The content types of the common file extensions
17
+ */
18
+ const CONTENT_TYPES = {
19
+ '.txt': 'text/plain; charset=utf-8',
20
+ '.html': 'text/html; charset=utf-8',
21
+ '.css': 'text/css; charset=utf-8',
22
+ '.js': 'text/javascript; charset=utf-8',
23
+ '.json': 'application/json; charset=utf-8',
24
+ '.csv': 'text/csv; charset=utf-8',
25
+ '.xml': 'application/xml; charset=utf-8',
26
+ '.png': 'image/png',
27
+ '.jpg': 'image/jpeg',
28
+ '.jpeg': 'image/jpeg',
29
+ '.gif': 'image/gif',
30
+ '.svg': 'image/svg+xml',
31
+ '.webp': 'image/webp',
32
+ '.pdf': 'application/pdf',
33
+ '.zip': 'application/zip'
34
+ };
35
+ /**
36
+ * The first segments of the routes
37
+ * @param routes
38
+ */
39
+ function actionPrefixesOf(routes) {
40
+ const prefixes = new Set();
41
+ for (const route of routes) {
42
+ const segment = route.split('/').find((part) => !!part);
43
+ //A route starting with a parameter matches every path
44
+ if (segment && !/^[:*]/.test(segment))
45
+ prefixes.add(`/${segment}`);
46
+ }
47
+ return [...prefixes];
48
+ }
49
+ /**
50
+ * The data of an event of a stream
51
+ * @param data
52
+ * @param event
53
+ * @param id
54
+ */
55
+ function eventFrame(data, event, id) {
56
+ let frame = '';
57
+ if (id !== undefined)
58
+ frame += `id: ${id}\n`;
59
+ if (event !== undefined)
60
+ frame += `event: ${event}\n`;
61
+ const text = typeof data === 'string' ? data : JSON.stringify(data);
62
+ for (const line of text.split(/\r?\n/))
63
+ frame += `data: ${line}\n`;
64
+ return `${frame}\n`;
65
+ }
66
+ /**
67
+ * Whether a value is a fastify instance
68
+ * @param value
69
+ */
70
+ function isFastifyInstance(value) {
71
+ return !!value && typeof value.route === 'function' && typeof value.listen === 'function';
72
+ }
73
+ /**
74
+ * Create the HTTP adapter of an entrypoint served by a fastify instance: each HTTP action (`@GET`, `@POST`,
75
+ * `@HTTPAction`…) becomes a fastify route. It needs the optional peer dependency `fastify`.
76
+ *
77
+ * An action's input is the request's query and body (see the `input` option) with the route parameters merged over
78
+ * them. Its result is written by the responder (JSON by default, 204 for no result); a `StatusResult` sets the status
79
+ * and the headers, a `FileResult` sends a file, a buffer or a stream (its content type guessed from the extension of
80
+ * its file name, 304 when its ETag matches `If-None-Match`), and an `EventsResult` streams Server-Sent Events. An action
81
+ * that writes the response itself (through `HTTPContext.response`) is left alone. The errors, those of fastify included
82
+ * (a body too large: 413, a malformed JSON body: 400), are written by the responder with their status (500 by default).
83
+ * A GET action also answers HEAD, unless a HEAD action is declared for its route.
84
+ *
85
+ * When the client disconnects before the response, the action's abort signal fires and nothing is written. When the
86
+ * entrypoint stops, fastify stops accepting connections and answers the new requests with 503, the event streams end,
87
+ * and the requests in progress are given up to one second after they settle to send their responses before the
88
+ * remaining connections are closed.
89
+ * @param options The adapter options; by default it listens on port 80 with a new fastify instance.
90
+ * @returns The adapter, to give to the `http` option of `buildEntrypoints`.
91
+ * @example
92
+ * ```typescript
93
+ * import {Application} from 'lakutata'
94
+ * import {buildEntrypoints, Controller} from 'lakutata/com/entrypoint'
95
+ * import {GET, POST} from 'lakutata/decorator/ctrl'
96
+ * import {fastifyHTTPEntrypoint} from 'lakutata/adapter/fastify'
97
+ *
98
+ * class UserController extends Controller {
99
+ * //GET /users/1?verbose=true: the route parameter id merged over the query
100
+ * @GET('/users/:id')
101
+ * public async get(input: {id: string, verbose?: string}): Promise<{id: string}> {
102
+ * return {id: input.id}
103
+ * }
104
+ *
105
+ * //POST /users with the JSON body {"name": "Ada"}
106
+ * @POST('/users')
107
+ * public async create(input: {name: string}): Promise<{name: string}> {
108
+ * return {name: input.name}
109
+ * }
110
+ * }
111
+ *
112
+ * Application.run({
113
+ * id: 'web.app',
114
+ * name: 'Web',
115
+ * components: {
116
+ * entrypoint: buildEntrypoints({
117
+ * controllers: [UserController],
118
+ * http: fastifyHTTPEntrypoint({
119
+ * port: 8080,
120
+ * host: '0.0.0.0',
121
+ * fastify: {bodyLimit: 5 * 1024 * 1024, trustProxy: true},
122
+ * //The application's own routes
123
+ * before: (app): void => {
124
+ * app.get('/health', async (): Promise<string> => 'ok')
125
+ * }
126
+ * })
127
+ * })
128
+ * }
129
+ * })
130
+ * ```
131
+ */
132
+ function fastifyHTTPEntrypoint(options = {}) {
133
+ const respond = options.respond ?? Responders_js_1.FastifyJSONResponder;
134
+ const input = options.input ?? ((request) => ({
135
+ ...(request.query && typeof request.query === 'object' ? request.query : {}),
136
+ ...(request.body && typeof request.body === 'object' && !Array.isArray(request.body) ? request.body : {})
137
+ }));
138
+ const streams = new Set();
139
+ let app;
140
+ let closed;
141
+ let stopping = false;
142
+ //The responses not sent yet
143
+ const responding = new Set();
144
+ /**
145
+ * Stream the events of a result
146
+ * @param result
147
+ * @param reply
148
+ */
149
+ const streamEvents = async (result, reply) => {
150
+ const abortController = new AbortController();
151
+ streams.add(abortController);
152
+ reply.hijack();
153
+ const response = reply.raw;
154
+ response.writeHead(200, {
155
+ ...reply.getHeaders(),
156
+ 'Content-Type': 'text/event-stream; charset=utf-8',
157
+ 'Cache-Control': 'no-cache, no-transform',
158
+ 'Connection': 'keep-alive',
159
+ 'X-Accel-Buffering': 'no'
160
+ });
161
+ response.flushHeaders();
162
+ const heartbeat = setInterval(() => response.write(': ping\n\n'), options.heartbeat ?? 15000);
163
+ const close = () => abortController.abort();
164
+ response.on('close', close);
165
+ try {
166
+ await result.producer((data, event, id) => {
167
+ if (!abortController.signal.aborted)
168
+ response.write(eventFrame(data, event, id));
169
+ }, abortController.signal);
170
+ }
171
+ catch {
172
+ //The stream is already started, its error ends it
173
+ }
174
+ finally {
175
+ clearInterval(heartbeat);
176
+ response.off('close', close);
177
+ streams.delete(abortController);
178
+ if (!response.writableEnded)
179
+ response.end();
180
+ }
181
+ };
182
+ /**
183
+ * Send a file
184
+ * @param result
185
+ * @param request
186
+ * @param reply
187
+ */
188
+ const sendFile = async (result, request, reply) => {
189
+ const { contentType, filename, etag, headers } = result.options;
190
+ if (headers)
191
+ reply.headers(headers);
192
+ if (etag) {
193
+ reply.header('ETag', `"${etag}"`);
194
+ if (request.headers['if-none-match'] === `"${etag}"`) {
195
+ await reply.code(304).send();
196
+ return;
197
+ }
198
+ }
199
+ const source = result.source;
200
+ const name = filename ?? (typeof source === 'string' ? node_path_1.default.basename(source) : undefined);
201
+ if (filename)
202
+ reply.header('Content-Disposition', `attachment; filename="${encodeURIComponent(filename)}"`);
203
+ reply.type(contentType ?? (name && CONTENT_TYPES[node_path_1.default.extname(name).toLowerCase()]) ?? 'application/octet-stream');
204
+ await reply.send(typeof source === 'string' ? (0, node_fs_1.createReadStream)(node_path_1.default.resolve(source)) : source);
205
+ };
206
+ /**
207
+ * Write the result of an action
208
+ * @param result
209
+ * @param request
210
+ * @param reply
211
+ */
212
+ const output = async (result, request, reply) => {
213
+ //The action wrote the response itself
214
+ if (reply.sent || reply.raw.headersSent)
215
+ return;
216
+ if (result instanceof Result_js_1.EventsResult)
217
+ return await streamEvents(result, reply);
218
+ if (result instanceof Result_js_1.FileResult)
219
+ return await sendFile(result, request, reply);
220
+ if (result instanceof Result_js_1.StatusResult) {
221
+ reply.code(result.status).headers(result.headers);
222
+ return respond.success(reply, result.data, request);
223
+ }
224
+ respond.success(reply, result, request);
225
+ };
226
+ /**
227
+ * The handler of the requests of an action
228
+ * @param runtime
229
+ * @param action
230
+ */
231
+ const actionHandler = (runtime, action) => async (request, reply) => {
232
+ const abortController = new AbortController();
233
+ //The client left before the response was sent
234
+ reply.raw.once('close', () => {
235
+ if (!reply.raw.writableFinished)
236
+ abortController.abort();
237
+ });
238
+ const context = new HTTPContext_js_1.HTTPContext({
239
+ route: action.address.route,
240
+ method: action.address.method,
241
+ request: request.raw,
242
+ response: reply.raw,
243
+ data: input(request)
244
+ });
245
+ try {
246
+ const result = await runtime.dispatchTo(action, context, { signal: abortController.signal, params: { ...request.params } });
247
+ if (!abortController.signal.aborted)
248
+ await output(result, request, reply);
249
+ }
250
+ catch (error) {
251
+ if (!reply.sent && !reply.raw.headersSent && !abortController.signal.aborted)
252
+ respond.error(reply, error, request, 'action');
253
+ }
254
+ //The client left: nothing is sent, the request is done for fastify (it is not waited for when fastify closes)
255
+ if (abortController.signal.aborted && !reply.sent) {
256
+ reply.hijack();
257
+ reply.raw.destroy();
258
+ }
259
+ return reply;
260
+ };
261
+ return {
262
+ channel: 'http',
263
+ definition: BuiltinChannels_js_1.HTTPChannel,
264
+ name: options.name,
265
+ middlewares: options.middlewares,
266
+ start: async (runtime) => {
267
+ const fastify = isFastifyInstance(options.fastify) ? options.fastify : (0, fastify_1.default)(options.fastify ?? {});
268
+ app = fastify;
269
+ const routes = new Map();
270
+ for (const action of runtime.actions)
271
+ routes.set(action.address.route, (routes.get(action.address.route) ?? new Set()).add(String(action.address.method).toUpperCase()));
272
+ const actionPrefixes = actionPrefixesOf(routes.keys());
273
+ const isActionPath = (requestPath) => actionPrefixes.some((prefix) => requestPath === prefix || requestPath.startsWith(`${prefix}/`));
274
+ await options.before?.(fastify, { module: runtime.module, server: fastify.server, routes: routes, actionPrefixes: actionPrefixes, isActionPath: isActionPath });
275
+ for (const action of runtime.actions) {
276
+ const method = String(action.address.method).toUpperCase();
277
+ fastify.route({
278
+ method: method,
279
+ url: action.address.route,
280
+ //A HEAD action of the route replaces the HEAD route fastify adds to a GET route
281
+ exposeHeadRoute: method === 'GET' && !routes.get(action.address.route).has('HEAD'),
282
+ handler: actionHandler(runtime, action)
283
+ });
284
+ }
285
+ fastify.setNotFoundHandler((request, reply) => {
286
+ const requestPath = request.url.split('?')[0];
287
+ if (options.fallback && !isActionPath(requestPath))
288
+ return options.fallback(request, reply);
289
+ return respond.error(reply, new RouteNotFoundException_js_1.RouteNotFoundException('Route {route} not found', { route: requestPath }), request, 'request');
290
+ });
291
+ //The responses in progress are waited for when the adapter closes
292
+ fastify.addHook('onRequest', async (request, reply) => {
293
+ const responded = new Promise((resolve) => void reply.raw.once('close', resolve));
294
+ responding.add(responded);
295
+ //Only resolved
296
+ void responded.then(() => responding.delete(responded));
297
+ });
298
+ //While the adapter stops, the connections are closed once their response is sent
299
+ fastify.addHook('onResponse', async () => {
300
+ if (stopping)
301
+ setImmediate(() => fastify.server.closeIdleConnections());
302
+ });
303
+ fastify.setErrorHandler((error, request, reply) => respond.error(reply, error, request, 'request'));
304
+ //The adapter starts once the server listens (an occupied port fails the start)
305
+ //Every interface by default, as the other adapters (fastify listens on localhost only)
306
+ if (options.host !== undefined) {
307
+ await fastify.listen({ port: options.port ?? 80, host: options.host });
308
+ }
309
+ else {
310
+ try {
311
+ await fastify.listen({ port: options.port ?? 80, host: '::' });
312
+ }
313
+ catch (error) {
314
+ if (!['EAFNOSUPPORT', 'EADDRNOTAVAIL'].includes(error.code ?? ''))
315
+ throw error;
316
+ await fastify.listen({ port: options.port ?? 80, host: '0.0.0.0' });
317
+ }
318
+ }
319
+ },
320
+ stop: () => {
321
+ //The event streams end; fastify stops accepting connections, closes the idle ones and answers 503 to the new requests
322
+ stopping = true;
323
+ streams.forEach((stream) => stream.abort());
324
+ closed = app?.close();
325
+ },
326
+ close: async () => {
327
+ //The requests in progress ended or were aborted: their responses are given a second to be sent, then the remaining connections are closed
328
+ //(a connection opened without a request would hold the close of the server)
329
+ let timer;
330
+ await Promise.race([Promise.all(responding), new Promise((resolve) => {
331
+ timer = setTimeout(resolve, 1000);
332
+ })]);
333
+ clearTimeout(timer);
334
+ app?.server.closeAllConnections();
335
+ await closed;
336
+ await options.stop?.();
337
+ }
338
+ };
339
+ }
@@ -0,0 +1,88 @@
1
+ import type { FastifyReply, FastifyRequest } from 'fastify';
2
+ import { type HTTPErrorOrigin } from '../../lib/HTTPErrors.js';
3
+ /**
4
+ * How {@link fastifyHTTPEntrypoint} writes the results and the errors of the actions (its `respond` option). Implement
5
+ * it to give the responses another shape; {@link FastifyJSONResponder} is the default, {@link fastifyJSONEnvelope}
6
+ * wraps them in an envelope. The file results and the event streams are not written by the responder.
7
+ */
8
+ export interface FastifyResponder {
9
+ /**
10
+ * Write the result of an action. For a `StatusResult`, its status and headers are already set on the reply and
11
+ * `data` is its payload.
12
+ * @param reply The fastify reply to send.
13
+ * @param data The action's result, `undefined` when it returned nothing.
14
+ * @param request The fastify request being answered.
15
+ */
16
+ success(reply: FastifyReply, data: unknown, request: FastifyRequest): void;
17
+ /**
18
+ * Write an error: a failed action (validation, access control, its own exception), an error of fastify (a hook such
19
+ * as an authenticator, a body too large), or a request matching no route (`RouteNotFoundException`). Not called for
20
+ * an action once the reply is sent, nor after the client left.
21
+ * @param reply The fastify reply to send.
22
+ * @param error The thrown error.
23
+ * @param request The fastify request being answered.
24
+ * @param origin Where the error comes from: `'action'` (the dispatch of an action failed) or `'request'` (a hook,
25
+ * an error of fastify, a route not found); see `HTTPErrorOrigin`.
26
+ */
27
+ error(reply: FastifyReply, error: unknown, request: FastifyRequest, origin?: HTTPErrorOrigin): void;
28
+ }
29
+ /**
30
+ * The default responder of {@link fastifyHTTPEntrypoint}: a result is sent as JSON, no result as an empty 204 (or the
31
+ * status set by a `StatusResult`); an error is sent as `{errno, errMsg}` (see `describeError`) with its HTTP status
32
+ * (see `statusOfError`: the first 4xx status in its cause chain, its own status, or 500).
33
+ */
34
+ export declare const FastifyJSONResponder: FastifyResponder;
35
+ /**
36
+ * The options of {@link fastifyJSONEnvelope}.
37
+ */
38
+ export type FastifyJSONEnvelopeOptions = {
39
+ /**
40
+ * The HTTP status of every error response, such as 200 for the clients that read the errors from the envelope.
41
+ * @default the error's own status (see `statusOfError`)
42
+ */
43
+ errorStatus?: number;
44
+ /**
45
+ * The HTTP status of the errors of the actions only (their dispatch failed: validation, access control, their own
46
+ * exceptions), over `errorStatus`; the errors of the hooks (an authenticator's 401), of fastify and the routes not
47
+ * found keep theirs. 200 answers as the applications of lakutata 2.x usually did.
48
+ * @default `errorStatus`
49
+ */
50
+ actionErrorStatus?: number;
51
+ };
52
+ /**
53
+ * Create a responder for {@link fastifyHTTPEntrypoint} that wraps every response in the envelope
54
+ * `{errno, errMsg, data}`: a result as `{errno: null, errMsg: null, data}` (`data` is `null` when the action returned
55
+ * nothing, and its status is not turned into 204), an error as `{errno, errMsg, data: null}` with the error's status,
56
+ * the `errorStatus` option, or for the errors of the actions the `actionErrorStatus` option.
57
+ * @param options The envelope options.
58
+ * @returns The responder, to give to the `respond` option of `fastifyHTTPEntrypoint`.
59
+ * @example
60
+ * ```typescript
61
+ * import {Application} from 'lakutata'
62
+ * import {buildEntrypoints, Controller} from 'lakutata/com/entrypoint'
63
+ * import {GET} from 'lakutata/decorator/ctrl'
64
+ * import {fastifyHTTPEntrypoint, fastifyJSONEnvelope} from 'lakutata/adapter/fastify'
65
+ *
66
+ * class PingController extends Controller {
67
+ * //GET /ping answers {"errno": null, "errMsg": null, "data": "pong"}
68
+ * @GET('/ping')
69
+ * public async ping(): Promise<string> {
70
+ * return 'pong'
71
+ * }
72
+ * }
73
+ *
74
+ * Application.run({
75
+ * id: 'web.app',
76
+ * name: 'Web',
77
+ * components: {
78
+ * entrypoint: buildEntrypoints({
79
+ * controllers: [PingController],
80
+ * //The errors of the actions answered with 200 too (as the applications of lakutata 2.x), the routes not
81
+ * //found and the errors of the hooks with their status (404, 401…)
82
+ * http: fastifyHTTPEntrypoint({port: 8080, respond: fastifyJSONEnvelope({actionErrorStatus: 200})})
83
+ * })
84
+ * }
85
+ * })
86
+ * ```
87
+ */
88
+ export declare function fastifyJSONEnvelope(options?: FastifyJSONEnvelopeOptions): FastifyResponder;
@@ -0,0 +1,77 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.FastifyJSONResponder = void 0;
4
+ exports.fastifyJSONEnvelope = fastifyJSONEnvelope;
5
+ const HTTPErrors_js_1 = require("../../lib/HTTPErrors.js");
6
+ /**
7
+ * Send JSON
8
+ * @param reply
9
+ * @param data
10
+ */
11
+ function sendJSON(reply, data) {
12
+ reply.type('application/json; charset=utf-8').send(JSON.stringify(data));
13
+ }
14
+ /**
15
+ * The default responder of {@link fastifyHTTPEntrypoint}: a result is sent as JSON, no result as an empty 204 (or the
16
+ * status set by a `StatusResult`); an error is sent as `{errno, errMsg}` (see `describeError`) with its HTTP status
17
+ * (see `statusOfError`: the first 4xx status in its cause chain, its own status, or 500).
18
+ */
19
+ exports.FastifyJSONResponder = {
20
+ success: (reply, data) => {
21
+ if (data === undefined) {
22
+ reply.code(reply.statusCode === 200 ? 204 : reply.statusCode).send();
23
+ return;
24
+ }
25
+ sendJSON(reply, data);
26
+ },
27
+ error: (reply, error) => {
28
+ reply.code((0, HTTPErrors_js_1.statusOfError)(error));
29
+ sendJSON(reply, (0, HTTPErrors_js_1.describeError)(error));
30
+ }
31
+ };
32
+ /**
33
+ * Create a responder for {@link fastifyHTTPEntrypoint} that wraps every response in the envelope
34
+ * `{errno, errMsg, data}`: a result as `{errno: null, errMsg: null, data}` (`data` is `null` when the action returned
35
+ * nothing, and its status is not turned into 204), an error as `{errno, errMsg, data: null}` with the error's status,
36
+ * the `errorStatus` option, or for the errors of the actions the `actionErrorStatus` option.
37
+ * @param options The envelope options.
38
+ * @returns The responder, to give to the `respond` option of `fastifyHTTPEntrypoint`.
39
+ * @example
40
+ * ```typescript
41
+ * import {Application} from 'lakutata'
42
+ * import {buildEntrypoints, Controller} from 'lakutata/com/entrypoint'
43
+ * import {GET} from 'lakutata/decorator/ctrl'
44
+ * import {fastifyHTTPEntrypoint, fastifyJSONEnvelope} from 'lakutata/adapter/fastify'
45
+ *
46
+ * class PingController extends Controller {
47
+ * //GET /ping answers {"errno": null, "errMsg": null, "data": "pong"}
48
+ * @GET('/ping')
49
+ * public async ping(): Promise<string> {
50
+ * return 'pong'
51
+ * }
52
+ * }
53
+ *
54
+ * Application.run({
55
+ * id: 'web.app',
56
+ * name: 'Web',
57
+ * components: {
58
+ * entrypoint: buildEntrypoints({
59
+ * controllers: [PingController],
60
+ * //The errors of the actions answered with 200 too (as the applications of lakutata 2.x), the routes not
61
+ * //found and the errors of the hooks with their status (404, 401…)
62
+ * http: fastifyHTTPEntrypoint({port: 8080, respond: fastifyJSONEnvelope({actionErrorStatus: 200})})
63
+ * })
64
+ * }
65
+ * })
66
+ * ```
67
+ */
68
+ function fastifyJSONEnvelope(options = {}) {
69
+ return {
70
+ success: (reply, data) => sendJSON(reply, { errno: null, errMsg: null, data: data === undefined ? null : data }),
71
+ error: (reply, error, _request, origin) => {
72
+ const status = origin === 'action' ? options.actionErrorStatus ?? options.errorStatus : options.errorStatus;
73
+ reply.code(status ?? (0, HTTPErrors_js_1.statusOfError)(error));
74
+ sendJSON(reply, { ...(0, HTTPErrors_js_1.describeError)(error), data: null });
75
+ }
76
+ };
77
+ }