@ismael1361/router 1.2.91 → 2.0.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 (290) hide show
  1. package/README.md +956 -505
  2. package/dist/1.0/Doc/index.d.ts.map +1 -0
  3. package/dist/1.0/Doc/type.d.ts.map +1 -0
  4. package/dist/1.0/HandleError.d.ts.map +1 -0
  5. package/dist/1.0/Layer.d.ts.map +1 -0
  6. package/dist/1.0/Middlewares.d.ts.map +1 -0
  7. package/dist/1.0/handler.d.ts.map +1 -0
  8. package/dist/1.0/index.d.ts +150 -0
  9. package/dist/1.0/index.d.ts.map +1 -0
  10. package/dist/1.0/middleware.d.ts.map +1 -0
  11. package/dist/1.0/redocUi/index.d.ts.map +1 -0
  12. package/dist/1.0/router.d.ts.map +1 -0
  13. package/dist/1.0/swagger-markdown/index.d.ts.map +1 -0
  14. package/dist/1.0/swagger-markdown/lib/anchor.d.ts.map +1 -0
  15. package/dist/1.0/swagger-markdown/lib/inArray.d.ts.map +1 -0
  16. package/dist/1.0/swagger-markdown/models/schema.d.ts.map +1 -0
  17. package/dist/1.0/swagger-markdown/transformers/contact.d.ts.map +1 -0
  18. package/dist/1.0/swagger-markdown/transformers/dataTypes.d.ts.map +1 -0
  19. package/dist/1.0/swagger-markdown/transformers/definitions.d.ts.map +1 -0
  20. package/dist/1.0/swagger-markdown/transformers/externalDocs.d.ts.map +1 -0
  21. package/dist/1.0/swagger-markdown/transformers/info.d.ts.map +1 -0
  22. package/dist/1.0/swagger-markdown/transformers/license.d.ts.map +1 -0
  23. package/dist/1.0/swagger-markdown/transformers/path.d.ts.map +1 -0
  24. package/dist/1.0/swagger-markdown/transformers/pathParameters.d.ts.map +1 -0
  25. package/dist/1.0/swagger-markdown/transformers/pathResponses.d.ts.map +1 -0
  26. package/dist/1.0/swagger-markdown/transformers/security.d.ts.map +1 -0
  27. package/dist/1.0/swagger-markdown/transformers/securityDefinitions.d.ts.map +1 -0
  28. package/dist/{type.d.ts → 1.0/type.d.ts} +1 -1
  29. package/dist/1.0/type.d.ts.map +1 -0
  30. package/dist/1.0/utils.d.ts.map +1 -0
  31. package/dist/2.0/HandleError.d.ts +127 -0
  32. package/dist/2.0/HandleError.d.ts.map +1 -0
  33. package/dist/2.0/HandleError.esm.js.map +1 -0
  34. package/dist/2.0/HandleError.js.map +1 -0
  35. package/dist/2.0/Middlewares.d.ts +178 -0
  36. package/dist/2.0/Middlewares.d.ts.map +1 -0
  37. package/dist/{Middlewares.esm.js → 2.0/Middlewares.esm.js} +5 -5
  38. package/dist/2.0/Middlewares.esm.js.map +1 -0
  39. package/dist/{Middlewares.js → 2.0/Middlewares.js} +5 -5
  40. package/dist/2.0/Middlewares.js.map +1 -0
  41. package/dist/2.0/analyzeSwagger.d.ts +7 -0
  42. package/dist/2.0/analyzeSwagger.d.ts.map +1 -0
  43. package/dist/2.0/analyzeSwagger.esm.js +432 -0
  44. package/dist/2.0/analyzeSwagger.esm.js.map +1 -0
  45. package/dist/2.0/analyzeSwagger.js +435 -0
  46. package/dist/2.0/analyzeSwagger.js.map +1 -0
  47. package/dist/2.0/create.d.ts +75 -0
  48. package/dist/2.0/create.d.ts.map +1 -0
  49. package/dist/2.0/create.esm.js +321 -0
  50. package/dist/2.0/create.esm.js.map +1 -0
  51. package/dist/2.0/create.js +323 -0
  52. package/dist/2.0/create.js.map +1 -0
  53. package/dist/2.0/handler.d.ts +149 -0
  54. package/dist/2.0/handler.d.ts.map +1 -0
  55. package/dist/2.0/handler.esm.js +188 -0
  56. package/dist/2.0/handler.esm.js.map +1 -0
  57. package/dist/2.0/handler.js +191 -0
  58. package/dist/2.0/handler.js.map +1 -0
  59. package/dist/2.0/index.d.ts +7 -0
  60. package/dist/2.0/index.d.ts.map +1 -0
  61. package/dist/2.0/redocUi/index.d.ts +4 -0
  62. package/dist/2.0/redocUi/index.d.ts.map +1 -0
  63. package/dist/{redocUi → 2.0/redocUi}/index.esm.js +1 -1
  64. package/dist/2.0/redocUi/index.esm.js.map +1 -0
  65. package/dist/{redocUi → 2.0/redocUi}/index.js +1 -1
  66. package/dist/2.0/redocUi/index.js.map +1 -0
  67. package/dist/2.0/renderChainDocs.d.ts +3 -0
  68. package/dist/2.0/renderChainDocs.d.ts.map +1 -0
  69. package/dist/2.0/renderChainDocs.esm.js +118 -0
  70. package/dist/2.0/renderChainDocs.esm.js.map +1 -0
  71. package/dist/2.0/renderChainDocs.js +120 -0
  72. package/dist/2.0/renderChainDocs.js.map +1 -0
  73. package/dist/2.0/router.d.ts +73 -0
  74. package/dist/2.0/router.d.ts.map +1 -0
  75. package/dist/2.0/router.esm.js +302 -0
  76. package/dist/2.0/router.esm.js.map +1 -0
  77. package/dist/2.0/router.js +304 -0
  78. package/dist/2.0/router.js.map +1 -0
  79. package/dist/2.0/swagger-markdown/index.d.ts +10 -0
  80. package/dist/2.0/swagger-markdown/index.d.ts.map +1 -0
  81. package/dist/{swagger-markdown → 2.0/swagger-markdown}/index.esm.js +1 -1
  82. package/dist/2.0/swagger-markdown/index.esm.js.map +1 -0
  83. package/dist/{swagger-markdown → 2.0/swagger-markdown}/index.js +1 -1
  84. package/dist/2.0/swagger-markdown/index.js.map +1 -0
  85. package/dist/2.0/swagger-markdown/lib/anchor.d.ts +6 -0
  86. package/dist/2.0/swagger-markdown/lib/anchor.d.ts.map +1 -0
  87. package/dist/2.0/swagger-markdown/lib/anchor.esm.js.map +1 -0
  88. package/dist/2.0/swagger-markdown/lib/anchor.js.map +1 -0
  89. package/dist/2.0/swagger-markdown/lib/inArray.d.ts +9 -0
  90. package/dist/2.0/swagger-markdown/lib/inArray.d.ts.map +1 -0
  91. package/dist/2.0/swagger-markdown/lib/inArray.esm.js.map +1 -0
  92. package/dist/2.0/swagger-markdown/lib/inArray.js.map +1 -0
  93. package/dist/2.0/swagger-markdown/models/schema.d.ts +28 -0
  94. package/dist/2.0/swagger-markdown/models/schema.d.ts.map +1 -0
  95. package/dist/2.0/swagger-markdown/models/schema.esm.js.map +1 -0
  96. package/dist/2.0/swagger-markdown/models/schema.js.map +1 -0
  97. package/dist/2.0/swagger-markdown/transformers/contact.d.ts +8 -0
  98. package/dist/2.0/swagger-markdown/transformers/contact.d.ts.map +1 -0
  99. package/dist/2.0/swagger-markdown/transformers/contact.esm.js.map +1 -0
  100. package/dist/2.0/swagger-markdown/transformers/contact.js.map +1 -0
  101. package/dist/2.0/swagger-markdown/transformers/dataTypes.d.ts +9 -0
  102. package/dist/2.0/swagger-markdown/transformers/dataTypes.d.ts.map +1 -0
  103. package/dist/2.0/swagger-markdown/transformers/dataTypes.esm.js.map +1 -0
  104. package/dist/2.0/swagger-markdown/transformers/dataTypes.js.map +1 -0
  105. package/dist/2.0/swagger-markdown/transformers/definitions.d.ts +14 -0
  106. package/dist/2.0/swagger-markdown/transformers/definitions.d.ts.map +1 -0
  107. package/dist/2.0/swagger-markdown/transformers/definitions.esm.js.map +1 -0
  108. package/dist/2.0/swagger-markdown/transformers/definitions.js.map +1 -0
  109. package/dist/2.0/swagger-markdown/transformers/externalDocs.d.ts +4 -0
  110. package/dist/2.0/swagger-markdown/transformers/externalDocs.d.ts.map +1 -0
  111. package/dist/2.0/swagger-markdown/transformers/externalDocs.esm.js.map +1 -0
  112. package/dist/2.0/swagger-markdown/transformers/externalDocs.js.map +1 -0
  113. package/dist/2.0/swagger-markdown/transformers/info.d.ts +11 -0
  114. package/dist/2.0/swagger-markdown/transformers/info.d.ts.map +1 -0
  115. package/dist/2.0/swagger-markdown/transformers/info.esm.js.map +1 -0
  116. package/dist/2.0/swagger-markdown/transformers/info.js.map +1 -0
  117. package/dist/2.0/swagger-markdown/transformers/license.d.ts +8 -0
  118. package/dist/2.0/swagger-markdown/transformers/license.d.ts.map +1 -0
  119. package/dist/2.0/swagger-markdown/transformers/license.esm.js.map +1 -0
  120. package/dist/2.0/swagger-markdown/transformers/license.js.map +1 -0
  121. package/dist/2.0/swagger-markdown/transformers/path.d.ts +9 -0
  122. package/dist/2.0/swagger-markdown/transformers/path.d.ts.map +1 -0
  123. package/dist/2.0/swagger-markdown/transformers/path.esm.js.map +1 -0
  124. package/dist/2.0/swagger-markdown/transformers/path.js.map +1 -0
  125. package/dist/2.0/swagger-markdown/transformers/pathParameters.d.ts +4 -0
  126. package/dist/2.0/swagger-markdown/transformers/pathParameters.d.ts.map +1 -0
  127. package/dist/2.0/swagger-markdown/transformers/pathParameters.esm.js.map +1 -0
  128. package/dist/2.0/swagger-markdown/transformers/pathParameters.js.map +1 -0
  129. package/dist/2.0/swagger-markdown/transformers/pathResponses.d.ts +9 -0
  130. package/dist/2.0/swagger-markdown/transformers/pathResponses.d.ts.map +1 -0
  131. package/dist/2.0/swagger-markdown/transformers/pathResponses.esm.js.map +1 -0
  132. package/dist/2.0/swagger-markdown/transformers/pathResponses.js.map +1 -0
  133. package/dist/2.0/swagger-markdown/transformers/security.d.ts +4 -0
  134. package/dist/2.0/swagger-markdown/transformers/security.d.ts.map +1 -0
  135. package/dist/2.0/swagger-markdown/transformers/security.esm.js.map +1 -0
  136. package/dist/2.0/swagger-markdown/transformers/security.js.map +1 -0
  137. package/dist/2.0/swagger-markdown/transformers/securityDefinitions.d.ts +6 -0
  138. package/dist/2.0/swagger-markdown/transformers/securityDefinitions.d.ts.map +1 -0
  139. package/dist/2.0/swagger-markdown/transformers/securityDefinitions.esm.js.map +1 -0
  140. package/dist/2.0/swagger-markdown/transformers/securityDefinitions.js.map +1 -0
  141. package/dist/2.0/type.d.ts +654 -0
  142. package/dist/2.0/type.d.ts.map +1 -0
  143. package/dist/2.0/utils.d.ts +79 -0
  144. package/dist/2.0/utils.d.ts.map +1 -0
  145. package/dist/{utils.esm.js → 2.0/utils.esm.js} +61 -89
  146. package/dist/2.0/utils.esm.js.map +1 -0
  147. package/dist/{utils.js → 2.0/utils.js} +65 -94
  148. package/dist/2.0/utils.js.map +1 -0
  149. package/dist/index.d.ts +1 -149
  150. package/dist/index.d.ts.map +1 -1
  151. package/dist/index.esm.js +5 -163
  152. package/dist/index.esm.js.map +1 -1
  153. package/dist/index.js +9 -169
  154. package/dist/index.js.map +1 -1
  155. package/package.json +5 -3
  156. package/dist/Doc/index.d.ts.map +0 -1
  157. package/dist/Doc/type.d.ts.map +0 -1
  158. package/dist/HandleError.d.ts.map +0 -1
  159. package/dist/HandleError.esm.js.map +0 -1
  160. package/dist/HandleError.js.map +0 -1
  161. package/dist/Layer.d.ts.map +0 -1
  162. package/dist/Layer.esm.js +0 -274
  163. package/dist/Layer.esm.js.map +0 -1
  164. package/dist/Layer.js +0 -276
  165. package/dist/Layer.js.map +0 -1
  166. package/dist/Middlewares.d.ts.map +0 -1
  167. package/dist/Middlewares.esm.js.map +0 -1
  168. package/dist/Middlewares.js.map +0 -1
  169. package/dist/handler.d.ts.map +0 -1
  170. package/dist/handler.esm.js +0 -171
  171. package/dist/handler.esm.js.map +0 -1
  172. package/dist/handler.js +0 -174
  173. package/dist/handler.js.map +0 -1
  174. package/dist/middleware.d.ts.map +0 -1
  175. package/dist/middleware.esm.js +0 -152
  176. package/dist/middleware.esm.js.map +0 -1
  177. package/dist/middleware.js +0 -155
  178. package/dist/middleware.js.map +0 -1
  179. package/dist/redocUi/index.d.ts.map +0 -1
  180. package/dist/redocUi/index.esm.js.map +0 -1
  181. package/dist/redocUi/index.js.map +0 -1
  182. package/dist/router.d.ts.map +0 -1
  183. package/dist/router.esm.js +0 -719
  184. package/dist/router.esm.js.map +0 -1
  185. package/dist/router.js +0 -740
  186. package/dist/router.js.map +0 -1
  187. package/dist/swagger-markdown/index.d.ts.map +0 -1
  188. package/dist/swagger-markdown/index.esm.js.map +0 -1
  189. package/dist/swagger-markdown/index.js.map +0 -1
  190. package/dist/swagger-markdown/lib/anchor.d.ts.map +0 -1
  191. package/dist/swagger-markdown/lib/anchor.esm.js.map +0 -1
  192. package/dist/swagger-markdown/lib/anchor.js.map +0 -1
  193. package/dist/swagger-markdown/lib/inArray.d.ts.map +0 -1
  194. package/dist/swagger-markdown/lib/inArray.esm.js.map +0 -1
  195. package/dist/swagger-markdown/lib/inArray.js.map +0 -1
  196. package/dist/swagger-markdown/models/schema.d.ts.map +0 -1
  197. package/dist/swagger-markdown/models/schema.esm.js.map +0 -1
  198. package/dist/swagger-markdown/models/schema.js.map +0 -1
  199. package/dist/swagger-markdown/transformers/contact.d.ts.map +0 -1
  200. package/dist/swagger-markdown/transformers/contact.esm.js.map +0 -1
  201. package/dist/swagger-markdown/transformers/contact.js.map +0 -1
  202. package/dist/swagger-markdown/transformers/dataTypes.d.ts.map +0 -1
  203. package/dist/swagger-markdown/transformers/dataTypes.esm.js.map +0 -1
  204. package/dist/swagger-markdown/transformers/dataTypes.js.map +0 -1
  205. package/dist/swagger-markdown/transformers/definitions.d.ts.map +0 -1
  206. package/dist/swagger-markdown/transformers/definitions.esm.js.map +0 -1
  207. package/dist/swagger-markdown/transformers/definitions.js.map +0 -1
  208. package/dist/swagger-markdown/transformers/externalDocs.d.ts.map +0 -1
  209. package/dist/swagger-markdown/transformers/externalDocs.esm.js.map +0 -1
  210. package/dist/swagger-markdown/transformers/externalDocs.js.map +0 -1
  211. package/dist/swagger-markdown/transformers/info.d.ts.map +0 -1
  212. package/dist/swagger-markdown/transformers/info.esm.js.map +0 -1
  213. package/dist/swagger-markdown/transformers/info.js.map +0 -1
  214. package/dist/swagger-markdown/transformers/license.d.ts.map +0 -1
  215. package/dist/swagger-markdown/transformers/license.esm.js.map +0 -1
  216. package/dist/swagger-markdown/transformers/license.js.map +0 -1
  217. package/dist/swagger-markdown/transformers/path.d.ts.map +0 -1
  218. package/dist/swagger-markdown/transformers/path.esm.js.map +0 -1
  219. package/dist/swagger-markdown/transformers/path.js.map +0 -1
  220. package/dist/swagger-markdown/transformers/pathParameters.d.ts.map +0 -1
  221. package/dist/swagger-markdown/transformers/pathParameters.esm.js.map +0 -1
  222. package/dist/swagger-markdown/transformers/pathParameters.js.map +0 -1
  223. package/dist/swagger-markdown/transformers/pathResponses.d.ts.map +0 -1
  224. package/dist/swagger-markdown/transformers/pathResponses.esm.js.map +0 -1
  225. package/dist/swagger-markdown/transformers/pathResponses.js.map +0 -1
  226. package/dist/swagger-markdown/transformers/security.d.ts.map +0 -1
  227. package/dist/swagger-markdown/transformers/security.esm.js.map +0 -1
  228. package/dist/swagger-markdown/transformers/security.js.map +0 -1
  229. package/dist/swagger-markdown/transformers/securityDefinitions.d.ts.map +0 -1
  230. package/dist/swagger-markdown/transformers/securityDefinitions.esm.js.map +0 -1
  231. package/dist/swagger-markdown/transformers/securityDefinitions.js.map +0 -1
  232. package/dist/type.d.ts.map +0 -1
  233. package/dist/utils.d.ts.map +0 -1
  234. package/dist/utils.esm.js.map +0 -1
  235. package/dist/utils.js.map +0 -1
  236. /package/dist/{Doc → 1.0/Doc}/index.d.ts +0 -0
  237. /package/dist/{Doc → 1.0/Doc}/type.d.ts +0 -0
  238. /package/dist/{HandleError.d.ts → 1.0/HandleError.d.ts} +0 -0
  239. /package/dist/{Layer.d.ts → 1.0/Layer.d.ts} +0 -0
  240. /package/dist/{Middlewares.d.ts → 1.0/Middlewares.d.ts} +0 -0
  241. /package/dist/{handler.d.ts → 1.0/handler.d.ts} +0 -0
  242. /package/dist/{middleware.d.ts → 1.0/middleware.d.ts} +0 -0
  243. /package/dist/{redocUi → 1.0/redocUi}/index.d.ts +0 -0
  244. /package/dist/{router.d.ts → 1.0/router.d.ts} +0 -0
  245. /package/dist/{swagger-markdown → 1.0/swagger-markdown}/index.d.ts +0 -0
  246. /package/dist/{swagger-markdown → 1.0/swagger-markdown}/lib/anchor.d.ts +0 -0
  247. /package/dist/{swagger-markdown → 1.0/swagger-markdown}/lib/inArray.d.ts +0 -0
  248. /package/dist/{swagger-markdown → 1.0/swagger-markdown}/models/schema.d.ts +0 -0
  249. /package/dist/{swagger-markdown → 1.0/swagger-markdown}/transformers/contact.d.ts +0 -0
  250. /package/dist/{swagger-markdown → 1.0/swagger-markdown}/transformers/dataTypes.d.ts +0 -0
  251. /package/dist/{swagger-markdown → 1.0/swagger-markdown}/transformers/definitions.d.ts +0 -0
  252. /package/dist/{swagger-markdown → 1.0/swagger-markdown}/transformers/externalDocs.d.ts +0 -0
  253. /package/dist/{swagger-markdown → 1.0/swagger-markdown}/transformers/info.d.ts +0 -0
  254. /package/dist/{swagger-markdown → 1.0/swagger-markdown}/transformers/license.d.ts +0 -0
  255. /package/dist/{swagger-markdown → 1.0/swagger-markdown}/transformers/path.d.ts +0 -0
  256. /package/dist/{swagger-markdown → 1.0/swagger-markdown}/transformers/pathParameters.d.ts +0 -0
  257. /package/dist/{swagger-markdown → 1.0/swagger-markdown}/transformers/pathResponses.d.ts +0 -0
  258. /package/dist/{swagger-markdown → 1.0/swagger-markdown}/transformers/security.d.ts +0 -0
  259. /package/dist/{swagger-markdown → 1.0/swagger-markdown}/transformers/securityDefinitions.d.ts +0 -0
  260. /package/dist/{utils.d.ts → 1.0/utils.d.ts} +0 -0
  261. /package/dist/{HandleError.esm.js → 2.0/HandleError.esm.js} +0 -0
  262. /package/dist/{HandleError.js → 2.0/HandleError.js} +0 -0
  263. /package/dist/{swagger-markdown → 2.0/swagger-markdown}/lib/anchor.esm.js +0 -0
  264. /package/dist/{swagger-markdown → 2.0/swagger-markdown}/lib/anchor.js +0 -0
  265. /package/dist/{swagger-markdown → 2.0/swagger-markdown}/lib/inArray.esm.js +0 -0
  266. /package/dist/{swagger-markdown → 2.0/swagger-markdown}/lib/inArray.js +0 -0
  267. /package/dist/{swagger-markdown → 2.0/swagger-markdown}/models/schema.esm.js +0 -0
  268. /package/dist/{swagger-markdown → 2.0/swagger-markdown}/models/schema.js +0 -0
  269. /package/dist/{swagger-markdown → 2.0/swagger-markdown}/transformers/contact.esm.js +0 -0
  270. /package/dist/{swagger-markdown → 2.0/swagger-markdown}/transformers/contact.js +0 -0
  271. /package/dist/{swagger-markdown → 2.0/swagger-markdown}/transformers/dataTypes.esm.js +0 -0
  272. /package/dist/{swagger-markdown → 2.0/swagger-markdown}/transformers/dataTypes.js +0 -0
  273. /package/dist/{swagger-markdown → 2.0/swagger-markdown}/transformers/definitions.esm.js +0 -0
  274. /package/dist/{swagger-markdown → 2.0/swagger-markdown}/transformers/definitions.js +0 -0
  275. /package/dist/{swagger-markdown → 2.0/swagger-markdown}/transformers/externalDocs.esm.js +0 -0
  276. /package/dist/{swagger-markdown → 2.0/swagger-markdown}/transformers/externalDocs.js +0 -0
  277. /package/dist/{swagger-markdown → 2.0/swagger-markdown}/transformers/info.esm.js +0 -0
  278. /package/dist/{swagger-markdown → 2.0/swagger-markdown}/transformers/info.js +0 -0
  279. /package/dist/{swagger-markdown → 2.0/swagger-markdown}/transformers/license.esm.js +0 -0
  280. /package/dist/{swagger-markdown → 2.0/swagger-markdown}/transformers/license.js +0 -0
  281. /package/dist/{swagger-markdown → 2.0/swagger-markdown}/transformers/path.esm.js +0 -0
  282. /package/dist/{swagger-markdown → 2.0/swagger-markdown}/transformers/path.js +0 -0
  283. /package/dist/{swagger-markdown → 2.0/swagger-markdown}/transformers/pathParameters.esm.js +0 -0
  284. /package/dist/{swagger-markdown → 2.0/swagger-markdown}/transformers/pathParameters.js +0 -0
  285. /package/dist/{swagger-markdown → 2.0/swagger-markdown}/transformers/pathResponses.esm.js +0 -0
  286. /package/dist/{swagger-markdown → 2.0/swagger-markdown}/transformers/pathResponses.js +0 -0
  287. /package/dist/{swagger-markdown → 2.0/swagger-markdown}/transformers/security.esm.js +0 -0
  288. /package/dist/{swagger-markdown → 2.0/swagger-markdown}/transformers/security.js +0 -0
  289. /package/dist/{swagger-markdown → 2.0/swagger-markdown}/transformers/securityDefinitions.esm.js +0 -0
  290. /package/dist/{swagger-markdown → 2.0/swagger-markdown}/transformers/securityDefinitions.js +0 -0
package/README.md CHANGED
@@ -4,33 +4,49 @@
4
4
  [![License](https://img.shields.io/npm/l/@ismael1361/router.svg)](https://github.com/ismael1361/router/blob/main/MIT)
5
5
  [![TypeScript](https://img.shields.io/badge/TypeScript-Ready-blue.svg)](https://www.typescriptlang.org/)
6
6
 
7
- Um módulo moderno e robusto para criar e gerenciar rotas em Express.js com tipagem encadeada forte, útil para tipar conteúdo de escopo e propriedades de requisição como `body`, `params` e `query`. Oferece geração automática de documentação OpenAPI/Swagger integrada.
7
+ Módulo para Express.js com tipagem encadeada forte para `body`, `params`, `query` e propriedades customizadas de `Request`/`Response`. Gera automaticamente documentação OpenAPI 3.0 (Swagger UI, ReDoc e Markdown), code snippets multi-linguagem e oferece sistema de logging por stacks integrado.
8
8
 
9
9
  ## 📋 Índice
10
10
 
11
11
  - [Características](#-características)
12
12
  - [Instalação](#-instalação)
13
13
  - [Início Rápido](#-início-rápido)
14
- - [API Completa](#-api-completa)
15
- - [create](#create)
16
- - [middleware](#middleware)
17
- - [route](#route)
18
- - [Classe Router](#classe-router)
19
- - [Exemplos Avançados](#-exemplos-avançados)
14
+ - [API](#-api)
15
+ - [`create()`](#create)
16
+ - [`router()`](#router)
17
+ - [`handler()`](#handler)
18
+ - [`middleware()`](#middleware)
19
+ - [`HandleError`](#handleerror)
20
+ - [`Middlewares`](#middlewares)
21
+ - [Interfaces e Tipos](#-interfaces-e-tipos)
22
+ - [`IApplication`](#iapplication)
23
+ - [`IRouter`](#irouter)
24
+ - [`IHandler`](#ihandler)
25
+ - [`IMiddleware`](#imiddleware)
26
+ - [`Request`](#request)
27
+ - [`Response`](#response)
28
+ - [`SwaggerOptions`](#swaggeroptions)
29
+ - [Métodos HTTP](#-métodos-http)
30
+ - [Rotas e Sub-routers](#-rotas-e-sub-routers)
20
31
  - [Documentação OpenAPI/Swagger](#-documentação-openapiswagger)
21
- - [TypeScript](#-typescript)
32
+ - [Sistema de Stacks (Logging)](#-sistema-de-stacks-logging)
33
+ - [Exemplos Avançados](#-exemplos-avançados)
22
34
  - [Contribuindo](#-contribuindo)
23
35
  - [Licença](#-licença)
24
36
 
25
37
  ## ✨ Características
26
38
 
27
- - 🔒 **Tipagem Forte**: Suporte completo a TypeScript com tipos encadeados
28
- - 📚 **Documentação Automática**: Geração de documentação OpenAPI/Swagger integrada
29
- - 🔗 **API Fluente**: Interface encadeável e intuitiva para definição de rotas
30
- - 🛡️ **Middlewares Documentados**: Middlewares com documentação automática
31
- - 🎯 **Organização Modular**: Suporte a sub-roteadores e rotas agrupadas
32
- - **Performance**: Construído sobre Express.js, mantendo sua eficiência
33
- - 🧩 **Extensível**: Fácil de estender com tipos personalizados
39
+ - **Tipagem Forte Encadeada** tipos de `Request` e `Response` acumulados automaticamente a cada `.handler()` encadeado via `JoinRequest`/`JoinResponse`
40
+ - **Inferência de Parâmetros de Rota** `req.params` tipado diretamente a partir da string de rota (ex.: `"/users/:id"` → `req.params.id: string`)
41
+ - **Documentação OpenAPI 3.0 Automática** geração de spec, Swagger UI, ReDoc e Markdown a partir de `.doc()` em handlers, middlewares e rotas
42
+ - **Code Snippets** geração automática de exemplos de código em 20+ linguagens (cURL, Python, Node.js, C#, Go, etc.)
43
+ - **Middlewares Tipados com `.doc()`** middlewares criados via `middleware()` carregam documentação OpenAPI que é mesclada automaticamente na spec
44
+ - **Sub-routers Modulares** `router()` e `.route()` permitem compor APIs em módulos independentes com prefixos
45
+ - **Tratamento de Erros Centralizado** `HandleError` com código HTTP, nível de log e integração automática com o sistema de stacks
46
+ - **Sistema de Stacks** — logging automatizado de erros, warnings e informações em arquivo, com UI HTML acessível por rota
47
+ - **CORS Configurável** — middleware `Middlewares.cors()` com controle granular de origens, métodos, headers e credenciais
48
+ - **Upload de Arquivos** — middleware `Middlewares.files()` com parsing de `multipart/form-data` e filtragem por MIME type
49
+ - **Execução Única de Middleware** — `req.executeOnce()` impede re-execução de middlewares em rotas aninhadas
34
50
 
35
51
  ## 📦 Instalação
36
52
 
@@ -38,8 +54,6 @@ Um módulo moderno e robusto para criar e gerenciar rotas em Express.js com tipa
38
54
  npm install @ismael1361/router
39
55
  ```
40
56
 
41
- ou
42
-
43
57
  ```bash
44
58
  yarn add @ismael1361/router
45
59
  ```
@@ -47,680 +61,1123 @@ yarn add @ismael1361/router
47
61
  ## 🚀 Início Rápido
48
62
 
49
63
  ```typescript
50
- import { create, Middlewares } from '@ismael1361/router';
64
+ import { create, router, middleware, Middlewares, Request } from "@ismael1361/router";
51
65
 
52
66
  const app = create();
53
67
 
54
- app.middleware(Middlewares.json());
55
-
56
- // Crie o roteador com middleware JSON
57
- const router = app.route();
68
+ // Middlewares globais
69
+ app.use(Middlewares.json());
70
+ app.use(Middlewares.cors({ allowOrigin: "*" }));
58
71
 
59
- // Defina rotas com documentação
60
- router
61
- .get('/users/:id')
62
- .handle((req, res) => {
63
- res.json({
64
- id: req.params.id,
65
- name: 'John Doe'
66
- });
72
+ // Rota simples com inferência de parâmetros
73
+ app.get("/users/:id")
74
+ .handler((req, res) => {
75
+ // req.params.id é automaticamente inferido como string
76
+ res.json({ id: req.params.id, name: "John Doe" });
67
77
  })
68
78
  .doc({
69
- summary: 'Obter usuário por ID',
70
- description: 'Retorna os detalhes de um usuário específico',
71
- tags: ['Users'],
72
- params: {
73
- id: {
74
- description: 'ID do usuário',
75
- type: 'string',
76
- required: true
77
- }
78
- },
79
+ tags: ["Users"],
80
+ summary: "Obter usuário por ID",
81
+ parameters: [
82
+ { name: "id", in: "path", required: true, schema: { type: "string" } },
83
+ ],
79
84
  responses: {
80
- 200: { description: 'Usuário encontrado' },
81
- 404: { description: 'Usuário não encontrado' }
82
- }
85
+ 200: { description: "Usuário encontrado" },
86
+ 404: { description: "Usuário não encontrado" },
87
+ },
83
88
  });
84
89
 
90
+ // Documentação Swagger
91
+ app.defineSwagger({
92
+ openapi: "3.0.0",
93
+ info: { title: "Minha API", version: "1.0.0" },
94
+ });
95
+
85
96
  app.listen(3000, () => {
86
- console.log('🚀 Servidor rodando na porta 3000');
97
+ console.log("Servidor: http://localhost:3000");
98
+ console.log("Swagger: http://localhost:3000/doc/swagger");
99
+ console.log("ReDoc: http://localhost:3000/doc/redoc");
87
100
  });
88
101
  ```
89
102
 
90
- ## 📖 API Completa
103
+ ---
104
+
105
+ ## 📖 API
91
106
 
92
- ### create
107
+ ### `create()`
93
108
 
94
- Cria uma nova instância do roteador aprimorado.
109
+ Cria uma instância de `IApplication`, que encapsula uma aplicação Express com roteamento tipado, documentação OpenAPI e sistema de stacks.
95
110
 
96
111
  ```typescript
97
- create<Req extends Request, Res extends Response>(): Router<Req, Res>
112
+ function create(): IApplication;
98
113
  ```
99
114
 
100
- **Retorno:** Nova instância do Router com métodos encadeáveis
101
-
102
- **Exemplo:**
115
+ **Retorno:** `IApplication` herda todos os métodos de `IRouter` (`.get()`, `.post()`, `.route()`, `.use()`, `.defineSwagger()`) e métodos do Express (`listen`, `enable`, `disable`, etc.).
103
116
 
104
117
  ```typescript
105
- import { create, Request, Response } from '@ismael1361/router';
118
+ import { create } from "@ismael1361/router";
106
119
 
107
- interface CustomRequest extends Request {
108
- user?: { id: string; name: string };
109
- }
120
+ const app = create();
110
121
 
111
- const router = create<CustomRequest>()
112
- .middleware(express.json());
122
+ app.get("/hello/:name")
123
+ .handler((req, res) => {
124
+ res.send(`Hello, ${req.params.name}!`);
125
+ });
126
+
127
+ app.listen(3000, () => {
128
+ console.log("Server is running on http://localhost:3000");
129
+ });
113
130
  ```
114
131
 
115
- ### middleware
132
+ ---
133
+
134
+ ### `router()`
116
135
 
117
- Cria middlewares reutilizáveis com documentação integrada.
136
+ Cria uma instância independente de `IRouter` para modularizar a API. Pode ser montado em outro router ou aplicação via `.route()` ou `.use()`.
137
+
138
+ ```typescript
139
+ function router(): IRouter;
140
+ ```
118
141
 
119
142
  ```typescript
120
- middleware<Req extends Request, Res extends Response>(
121
- callback: MiddlewareFC<Req, Res>,
122
- doc?: MiddlewareFCDoc
123
- ): MiddlewareFC<Req, Res>
143
+ import { create, router } from "@ismael1361/router";
144
+
145
+ const app = create();
146
+
147
+ const usersRouter = router();
148
+
149
+ usersRouter.get("/")
150
+ .handler((req, res) => {
151
+ res.json([{ id: "1", name: "Alice" }]);
152
+ })
153
+ .doc({ tags: ["Users"], summary: "Listar usuários" });
154
+
155
+ usersRouter.post("/")
156
+ .handler((req, res) => {
157
+ res.status(201).json({ id: "2", ...req.body });
158
+ })
159
+ .doc({ tags: ["Users"], summary: "Criar usuário" });
160
+
161
+ // Montar com prefixo
162
+ app.route("/users", usersRouter);
124
163
  ```
125
164
 
126
- **Parâmetros:**
127
- - `callback`: Função de middleware padrão do Express `(req, res, next)`
128
- - `doc` (opcional): Objeto com metadados para documentação OpenAPI
165
+ ---
129
166
 
130
- **Retorno:** Função de middleware com metadados de documentação anexados
167
+ ### `handler()`
131
168
 
132
- **Exemplo:**
169
+ Cria um handler encadeável que combina execução de middlewares com documentação OpenAPI. Cada chamada a `.handler()` adiciona um middleware à cadeia e mescla os tipos de `Request` e `Response` via `JoinRequest`/`JoinResponse`.
133
170
 
134
171
  ```typescript
135
- import { middleware, Request } from '@ismael1361/router';
172
+ function handler<Rq extends Request, Rs extends Response>(
173
+ fn: RequestHandler<Rq, Rs>
174
+ ): IHandler<Rq, Rs>;
175
+ ```
136
176
 
137
- interface AuthRequest extends Request<
138
- "api_key" | "token",
139
- {
140
- api_key?: string;
141
- token?: string
142
- }
143
- > {
144
- user: { id: string; roles: string[] };
145
- }
177
+ ```typescript
178
+ import { handler } from "@ismael1361/router";
146
179
 
147
- const isAuthenticated = middleware<AuthRequest>(
148
- (req, res, next) => {
149
- const token = req.headers.authorization;
150
-
151
- if (token === 'Bearer meu-token-secreto') {
152
- req.user = { id: '123', roles: ['admin', 'user'] };
153
- return next();
154
- }
155
-
156
- res.status(401).json({ message: 'Não autorizado' });
157
- },
158
- {
159
- security: [{ bearerAuth: [] }],
160
- responses: {
161
- 401: {
162
- description: 'Token de autenticação inválido ou não fornecido'
163
- }
164
- }
165
- }
166
- );
167
-
168
- // Usar o middleware
169
- router
170
- .get('/profile')
171
- .middleware(isAuthenticated)
172
- .handle((req, res) => {
173
- res.json({ user: req.user });
180
+ const myHandler = handler((req, res, next) => {
181
+ console.log("Primeiro middleware");
182
+ next();
183
+ })
184
+ .handler((req, res) => {
185
+ res.json({ status: "ok" });
186
+ })
187
+ .doc({
188
+ tags: ["Health"],
189
+ summary: "Health check",
174
190
  });
175
191
  ```
176
192
 
177
- ### route
193
+ > Na maioria dos casos, `handler()` é usado internamente pelo router ao registrar rotas (`.get()`, `.post()`, etc.). O uso direto é raro.
194
+
195
+ ---
178
196
 
179
- Cria uma instância de rota para agrupar múltiplos métodos HTTP sob o mesmo caminho.
197
+ ### `middleware()`
198
+
199
+ Cria um middleware reutilizável com suporte a documentação OpenAPI. Os tipos genéricos do middleware são mesclados automaticamente quando encadeado via `.handler()`.
180
200
 
181
201
  ```typescript
182
- route<Req extends Request, Res extends Response>(
183
- path?: string
184
- ): Router<Req, Res>
202
+ function middleware<Req extends Request, Res extends Response>(
203
+ fn: RequestHandler<Req, Res>
204
+ ): IMiddleware<Req, Res>;
185
205
  ```
186
206
 
187
- **Parâmetros:**
188
- - `path`: Caminho da URL para a rota
189
-
190
- **Retorno:** Nova instância do Router "travada" no path especificado
207
+ O middleware retornado **não** possui o método `.handler()` — apenas `.doc()`. Ele deve ser encadeado via `.handler()` de um `IHandler`.
191
208
 
192
- **Exemplo:**
209
+ #### Middleware simples
193
210
 
194
211
  ```typescript
195
- import { route } from '@ismael1361/router';
212
+ import { middleware } from "@ismael1361/router";
196
213
 
197
- const tasksRouter = route('/tasks');
214
+ const logMiddleware = middleware((req, res, next) => {
215
+ console.log(`${req.method} ${req.url}`);
216
+ next();
217
+ });
198
218
 
199
- // GET /tasks/items
200
- tasksRouter
201
- .get('/items')
202
- .handle((req, res) => {
203
- res.json([{ id: 1, title: 'Aprender @ismael1361/router' }]);
204
- })
205
- .doc({
206
- summary: 'Listar todas as tarefas',
207
- tags: ['Tasks'],
208
- responses: { 200: { description: 'Lista de tarefas' } }
219
+ app.get("/users")
220
+ .handler(logMiddleware)
221
+ .handler((req, res) => {
222
+ res.json([]);
209
223
  });
224
+ ```
210
225
 
211
- // POST /tasks/item
212
- tasksRouter
213
- .post('/item')
214
- .handle((req, res) => {
215
- const newTask = req.body;
216
- res.status(201).json({ id: 2, ...newTask });
217
- })
218
- .doc({
219
- summary: 'Criar nova tarefa',
220
- tags: ['Tasks'],
221
- body: { description: 'Dados da nova tarefa' },
222
- responses: { 201: { description: 'Tarefa criada' } }
226
+ #### Middleware com tipo customizado e documentação
227
+
228
+ ```typescript
229
+ import { middleware, Request } from "@ismael1361/router";
230
+
231
+ interface AuthRequest extends Request {
232
+ user: { userId: string; roles: string[] };
233
+ }
234
+
235
+ const authMiddleware = middleware((req: AuthRequest, res, next) => {
236
+ const token = req.headers.authorization?.replace("Bearer ", "");
237
+ if (!token) {
238
+ res.status(401).json({ error: "Token ausente" });
239
+ return;
240
+ }
241
+ req.user = { userId: "123", roles: ["admin"] };
242
+ next();
243
+ }).doc({
244
+ security: [{ bearerAuth: [] }],
245
+ components: {
246
+ securitySchemes: {
247
+ bearerAuth: { type: "http", scheme: "bearer" },
248
+ },
249
+ },
250
+ });
251
+
252
+ // Ao encadear, req.user é inferido automaticamente
253
+ app.get("/profile")
254
+ .handler(authMiddleware)
255
+ .handler((req, res) => {
256
+ // req.user.userId está disponível com tipagem
257
+ res.json({ userId: req.user.userId });
223
258
  });
259
+ ```
224
260
 
225
- // Adicionar ao roteador principal
226
- mainRouter.by(tasksRouter);
261
+ #### Middleware de validação de body
262
+
263
+ ```typescript
264
+ interface BodyRequest extends Request<string, { name: string; email: string }> {}
265
+
266
+ const validateBody = middleware((req: BodyRequest, res, next) => {
267
+ if (!req.body.name || !req.body.email) {
268
+ res.status(400).json({ error: "name e email são obrigatórios" });
269
+ return;
270
+ }
271
+ next();
272
+ }).doc({
273
+ requestBody: {
274
+ required: true,
275
+ content: {
276
+ "application/json": {
277
+ schema: {
278
+ type: "object",
279
+ required: ["name", "email"],
280
+ properties: {
281
+ name: { type: "string" },
282
+ email: { type: "string", format: "email" },
283
+ },
284
+ },
285
+ },
286
+ },
287
+ },
288
+ });
289
+
290
+ app.post("/users")
291
+ .handler(validateBody)
292
+ .handler((req, res) => {
293
+ // req.body.name e req.body.email inferidos como string
294
+ res.status(201).json({ name: req.body.name, email: req.body.email });
295
+ });
227
296
  ```
228
297
 
229
- ### Classe Router
298
+ ---
230
299
 
231
- A classe principal que encapsula o roteador do Express com API fluente e tipada.
300
+ ### `HandleError`
232
301
 
233
- #### Propriedades
302
+ Classe de erro para tratamento padronizado de erros HTTP. Integra-se automaticamente com o sistema de stacks e o tratamento centralizado de erros do router.
234
303
 
235
- ##### `.app`
236
304
  ```typescript
237
- router: express.Express
305
+ class HandleError extends Error {
306
+ constructor(
307
+ message: string,
308
+ name?: string, // default: "DEFAULT"
309
+ cause?: number | Error | string, // código HTTP ou causa
310
+ level?: "ERROR" | "WARN" | "INFO" | "NONE", // default: "ERROR"
311
+ source?: string,
312
+ duration?: number,
313
+ );
314
+
315
+ get code(): number; // código HTTP extraído de cause
316
+ get status(): { code: number; message: string };
317
+ get meta(): any;
318
+ }
238
319
  ```
239
- Instância do Express subjacente.
240
320
 
241
- ##### `.routes`
242
321
  ```typescript
243
- routes: Array<{
244
- path: string;
245
- methods: string[];
246
- type: "ROUTE" | "MIDDLEWARE";
247
- swagger?: Pick<swaggerJSDoc.OAS3Definition, "paths" | "components">;
248
- }>
249
- ```
250
- Array de rotas e middlewares registrados para geração de documentação.
322
+ import { HandleError } from "@ismael1361/router";
251
323
 
252
- #### Métodos HTTP
324
+ // Erro 404
325
+ throw new HandleError("Recurso não encontrado", "NOT_FOUND", 404);
253
326
 
254
- ##### `.get(path: string, doc?: MiddlewareFCDoc)`
255
- Registra uma rota GET.
327
+ // Erro de validação (nível WARN, não polui logs de erro)
328
+ throw new HandleError("Campo email inválido", "VALIDATION_ERROR", 400, "WARN");
256
329
 
257
- ```typescript
258
- router
259
- .get('/status')
260
- .handle((req, res) => {
261
- res.json({ status: 'ok' });
262
- })
263
- .doc({
264
- summary: 'Verificar status da API',
265
- tags: ['Health'],
266
- responses: { 200: { description: 'API funcionando' } }
330
+ // Uso em handler
331
+ app.get("/users/:id")
332
+ .handler((req, res) => {
333
+ const user = findUser(req.params.id);
334
+ if (!user) {
335
+ throw new HandleError("Usuário não encontrado", "NOT_FOUND", 404);
336
+ }
337
+ res.json(user);
267
338
  });
268
339
  ```
269
340
 
270
- ##### `.post(path: string, doc?: MiddlewareFCDoc)`
271
- Registra uma rota POST.
341
+ O erro é capturado automaticamente pelo sistema interno (`tryHandler`) e retorna resposta JSON padronizada:
272
342
 
273
- ```typescript
274
- router
275
- .post('/users')
276
- .handle((req, res) => {
277
- const newUser = req.body;
278
- res.status(201).json({ id: Date.now(), ...newUser });
279
- })
280
- .doc({
281
- summary: 'Criar novo usuário',
282
- tags: ['Users'],
283
- body: {
284
- description: 'Dados do usuário',
285
- schema: {
286
- type: 'object',
287
- properties: {
288
- name: { type: 'string' },
289
- email: { type: 'string' }
290
- }
291
- }
292
- },
293
- responses: { 201: { description: 'Usuário criado' } }
294
- });
343
+ ```json
344
+ { "message": "Usuário não encontrado", "name": "NOT_FOUND", "code": 404 }
295
345
  ```
296
346
 
297
- ##### `.put(path: string, doc?: MiddlewareFCDoc)`
298
- Registra uma rota PUT para substituição completa de recursos.
347
+ ---
299
348
 
300
- ##### `.patch(path: string, doc?: MiddlewareFCDoc)`
301
- Registra uma rota PATCH para atualizações parciais.
349
+ ### `Middlewares`
302
350
 
303
- ##### `.delete(path: string, doc?: MiddlewareFCDoc)`
304
- Registra uma rota DELETE para remoção de recursos.
351
+ Namespace com middlewares prontos para uso, importável via `Middlewares`.
305
352
 
306
- ##### `.options(path: string, doc?: MiddlewareFCDoc)`
307
- Registra uma rota OPTIONS para requisições de pré-voo CORS.
353
+ ```typescript
354
+ import { Middlewares } from "@ismael1361/router";
355
+ ```
356
+
357
+ #### `Middlewares.json(options?)`
308
358
 
309
- ##### `.head(path: string, doc?: MiddlewareFCDoc)`
310
- Registra uma rota HEAD para obter metadados sem corpo de resposta.
359
+ Analisa corpos de requisição JSON. Wrapper de `body-parser.json()`.
311
360
 
312
- ##### `.all(path: string, doc?: MiddlewareFCDoc)`
313
- Registra uma rota que responde a todos os métodos HTTP.
361
+ ```typescript
362
+ app.use(Middlewares.json());
363
+ app.use(Middlewares.json({ limit: "10mb" }));
364
+ ```
314
365
 
315
- #### Métodos de Configuração
366
+ #### `Middlewares.raw(options?)`
316
367
 
317
- ##### `.use(path?: string, doc?: MiddlewareFCDoc)`
318
- Monta middlewares em um caminho específico.
368
+ Analisa corpos de requisição como `Buffer`.
319
369
 
320
370
  ```typescript
321
- router.use('/api').handle((req, res, next) => {
322
- console.log(`[${new Date().toISOString()}] ${req.method} ${req.originalUrl}`);
323
- next();
324
- });
371
+ app.use(Middlewares.raw({ type: "application/octet-stream", limit: "10mb" }));
325
372
  ```
326
373
 
327
- ##### `.route(path?: string)`
328
- Cria um sub-roteador com prefixo.
374
+ #### `Middlewares.text(options?)`
375
+
376
+ Analisa corpos de requisição como texto.
329
377
 
330
378
  ```typescript
331
- const usersRouter = mainRouter.route('/users');
379
+ app.use(Middlewares.text({ type: "text/plain" }));
380
+ ```
332
381
 
333
- usersRouter
334
- .get('/')
335
- .handle((req, res) => {
336
- res.json([{ id: '1', name: 'Alice' }]);
337
- });
382
+ #### `Middlewares.urlencoded(options?)`
383
+
384
+ Analisa dados de formulário `application/x-www-form-urlencoded`.
385
+
386
+ ```typescript
387
+ app.use(Middlewares.urlencoded({ extended: true }));
338
388
  ```
339
389
 
340
- ##### `.middleware(callback: MiddlewareFC, doc?: MiddlewareFCDoc)`
341
- Aplica middleware a todas as rotas subsequentes.
390
+ #### `Middlewares.cors(options?)`
391
+
392
+ Configura CORS com controle granular.
342
393
 
343
394
  ```typescript
344
- const router = create(app)
345
- .middleware(express.json())
346
- .middleware(authMiddleware);
395
+ // Permitir todas as origens
396
+ app.use(Middlewares.cors({ allowOrigin: "*" }));
397
+
398
+ // Origem específica com opções
399
+ app.use(Middlewares.cors({
400
+ allowOrigin: "https://meusite.com",
401
+ allowedMethods: ["GET", "POST", "PUT", "DELETE"],
402
+ allowedHeaders: ["Content-Type", "Authorization"],
403
+ credentials: true,
404
+ exposeHeaders: ["Content-Length"],
405
+ }));
406
+
407
+ // Sintaxe alternativa: string + objeto
408
+ app.use(Middlewares.cors("https://meusite.com", {
409
+ allowedMethods: ["GET", "POST"],
410
+ credentials: true,
411
+ }));
347
412
  ```
348
413
 
349
- ##### `.handler(callback: HandlerFC, doc?: MiddlewareFCDoc)`
350
- Define a função controladora para processar requisições.
414
+ **`CorsOptions`:**
415
+
416
+ | Propriedade | Tipo | Descrição |
417
+ |------------------|-----------------------------|------------------------------------------------------------------|
418
+ | `allowOrigin` | `string` | Origem permitida (`"*"` para todas) |
419
+ | `allowedMethods` | `string[] \| string` | Métodos HTTP permitidos |
420
+ | `allowedHeaders` | `string[] \| string` | Headers que o cliente pode enviar |
421
+ | `credentials` | `boolean` | Permite cookies e headers de autenticação |
422
+ | `exposeHeaders` | `string[] \| string` | Headers adicionais legíveis pelo cliente |
423
+
424
+ #### `Middlewares.files(...allowedMimes)`
425
+
426
+ Parsing de arquivos `multipart/form-data`. Os arquivos ficam disponíveis em `req.file` (primeiro) e `req.files` (todos).
351
427
 
352
428
  ```typescript
353
- router
354
- .get('/status')
429
+ import { Middlewares } from "@ismael1361/router";
430
+
431
+ // Aceitar qualquer tipo de arquivo
432
+ app.post("/upload")
433
+ .handler(Middlewares.files())
355
434
  .handler((req, res) => {
356
- res.json({ status: 'ok' });
435
+ // req.file: FileInfo (primeiro arquivo)
436
+ // req.files: FileInfo[] (todos os arquivos)
437
+ res.json({
438
+ filename: req.file.originalname,
439
+ size: req.file.size,
440
+ mimetype: req.file.mimetype,
441
+ });
442
+ });
443
+
444
+ // Aceitar apenas imagens e PDFs
445
+ app.post("/upload-docs")
446
+ .handler(Middlewares.files("image/jpeg", "image/png", "application/pdf"))
447
+ .handler((req, res) => {
448
+ res.json({ count: req.files.length });
357
449
  });
358
450
  ```
359
451
 
360
- ##### `.by(router: ExpressRouter | Router)`
361
- Anexa um roteador existente ao atual.
452
+ **`FileInfo`:**
362
453
 
363
- ```typescript
364
- const productsRouter = route('/products');
365
- // ... definir rotas
454
+ | Propriedade | Tipo | Descrição |
455
+ |----------------|------------|-----------------------------|
456
+ | `fieldname` | `string` | Nome do campo do formulário |
457
+ | `originalname` | `string` | Nome original do arquivo |
458
+ | `mimetype` | `string` | Tipo MIME do arquivo |
459
+ | `size` | `number` | Tamanho em bytes |
460
+ | `buffer` | `Buffer` | Conteúdo do arquivo |
461
+ | `stream` | `Readable` | Stream legível |
366
462
 
367
- mainRouter.by(productsRouter);
463
+ ---
464
+
465
+ ## 🔷 Interfaces e Tipos
466
+
467
+ ### `IApplication`
468
+
469
+ Estende `IRouter` com capacidades de servidor HTTP e sistema de stacks.
470
+
471
+ ```typescript
472
+ interface IApplication extends IRouter {
473
+ listen: express.Application["listen"];
474
+ disable: express.Application["disable"];
475
+ enable: express.Application["enable"];
476
+ disabled: express.Application["disabled"];
477
+ enabled: express.Application["enabled"];
478
+ engine: express.Application["engine"];
479
+ param: express.Application["param"];
480
+ render: express.Application["render"];
481
+
482
+ getStacks(): IStackLog[];
483
+ defineStacks(options?: IStacksOptions): { stacksPath: string };
484
+ }
368
485
  ```
369
486
 
370
- ##### `.defineSwagger(options: SwaggerOptions)`
371
- Gera as rotas de documentação para a especificação OpenAPI completa.
487
+ ---
488
+
489
+ ### `IRouter`
490
+
491
+ Interface principal do router. Expõe métodos HTTP, sub-rotas, middlewares e configuração Swagger.
372
492
 
373
493
  ```typescript
374
- import { create } from '@ismael1361/router';
494
+ interface IRouter extends RequestHandler {
495
+ // Métodos HTTP — retornam IHandler com parâmetros inferidos da rota
496
+ all: IRouterMatcher<"all">;
497
+ get: IRouterMatcher<"get">;
498
+ post: IRouterMatcher<"post">;
499
+ put: IRouterMatcher<"put">;
500
+ delete: IRouterMatcher<"delete">;
501
+ patch: IRouterMatcher<"patch">;
502
+ options: IRouterMatcher<"options">;
503
+ head: IRouterMatcher<"head">;
504
+
505
+ parent: IRouter | null;
506
+ path: string;
375
507
 
376
- const router = create();
508
+ param: express.Application["param"];
377
509
 
378
- const swaggerDefinition = {
379
- openapi: '3.0.0',
380
- info: {
381
- title: 'Minha API',
382
- version: '1.0.0',
383
- description: 'API com documentação automática'
384
- },
385
- servers: [{ url: 'http://localhost:3000' }],
386
- components: {
387
- securitySchemes: {
388
- bearerAuth: {
389
- type: 'http',
390
- scheme: 'bearer',
391
- bearerFormat: 'JWT'
392
- }
393
- }
394
- },
395
- defaultResponses: {
396
- 400: { description: "Dados inválidos" },
397
- 401: {
398
- description: "Falha na autenticação",
399
- },
400
- 403: { description: "Acesso negado" },
401
- 500: { description: "Erro interno do servidor" },
402
- },
403
- };
510
+ route(prefix: string, doc?: MiddlewareFCDoc): IRouter;
511
+ route(prefix: string, router: IRouter, doc?: MiddlewareFCDoc): IRouter;
512
+ route(router: IRouter, doc?: MiddlewareFCDoc): IRouter;
404
513
 
405
- router.defineSwagger(swaggerDefinition);
406
- // By swagger json -> /doc/swagger/definition.json
407
- // By swagger -> /doc/swagger
408
- // By redoc -> /doc/redoc
514
+ use(prefix: string, doc?: MiddlewareFCDoc): IHandler;
515
+ use(prefix: string, handler: IRouter | RequestHandler, doc?: MiddlewareFCDoc): void;
516
+ use(handler: IRouter | RequestHandler, doc?: MiddlewareFCDoc): void;
517
+
518
+ defineSwagger(options: SwaggerOptions): void;
519
+ getSwagger(): swaggerJSDoc.Options;
520
+ }
409
521
  ```
410
522
 
411
- ## 🎯 Exemplos Avançados
523
+ ---
412
524
 
413
- ### Autenticação e Autorização
525
+ ### `IHandler`
526
+
527
+ Handler encadeável que combina execução de middlewares com documentação OpenAPI. Cada `.handler()` mescla tipos cumulativamente.
414
528
 
415
529
  ```typescript
416
- import { create, middleware, Middlewares, Request } from '@ismael1361/router';
530
+ interface IHandler<Rq extends Request, Rs extends Response> extends RequestHandler<Rq, Rs> {
531
+ handler<Req extends Request, Res extends Response>(
532
+ fn: RequestHandler<Req & Rq, Res & Rs> | IHandler<Req & Rq, Res & Rs>
533
+ ): IHandler<JoinRequest<Rq, Req>, JoinResponse<Rs, Res>>;
534
+
535
+ doc(
536
+ operation: MiddlewareFCDoc | swaggerJSDoc.Operation,
537
+ components?: swaggerJSDoc.Components
538
+ ): IHandler<Rq, Rs>;
539
+ }
540
+ ```
541
+
542
+ **Encadeamento e mesclagem de tipos:**
417
543
 
544
+ ```typescript
418
545
  interface AuthRequest extends Request {
419
546
  user: { id: string; roles: string[] };
420
547
  }
421
548
 
422
- // Middleware de autenticação
423
- const authenticate = middleware<AuthRequest>(
424
- (req, res, next) => {
425
- const token = req.headers.authorization?.replace('Bearer ', '');
426
-
427
- if (!token) {
428
- return res.status(401).json({ message: 'Token não fornecido' });
429
- }
430
-
431
- // Validar token (exemplo simplificado)
432
- req.user = { id: '123', roles: ['user'] };
433
- next();
434
- },
435
- {
436
- security: [{ bearerAuth: [] }],
437
- responses: {
438
- 401: { description: 'Não autorizado' }
439
- }
440
- }
441
- );
442
-
443
- // Middleware de autorização
444
- const authorize = (...roles: string[]) =>
445
- middleware<AuthRequest>(
446
- (req, res, next) => {
447
- if (!req.user.roles.some(role => roles.includes(role))) {
448
- return res.status(403).json({ message: 'Acesso negado' });
449
- }
450
- next();
451
- },
452
- {
453
- responses: {
454
- 403: { description: 'Acesso negado' }
455
- }
456
- }
457
- );
458
-
459
- const app = create<AuthRequest>()
460
- .middleware(Middlewares.json());
549
+ interface PaginatedRequest extends Request<string, any, { page: number; limit: number }> {}
461
550
 
462
- // Rota protegida
463
- app
464
- .get('/admin/users')
465
- .middleware(authenticate)
466
- .middleware(authorize('admin'))
467
- .handle((req, res) => {
468
- res.json({ users: [] });
469
- })
470
- .doc({
471
- summary: 'Listar usuários (Admin)',
472
- tags: ['Admin'],
473
- responses: { 200: { description: 'Lista de usuários' } }
551
+ app.get("/items")
552
+ .handler(authMiddleware) // req agora tem .user
553
+ .handler(paginationMiddleware) // req agora tem .user + .query.page + .query.limit
554
+ .handler((req, res) => {
555
+ // Todos os tipos estão disponíveis simultaneamente
556
+ console.log(req.user.id); // string
557
+ console.log(req.query.page); // number
558
+ res.json([]);
474
559
  });
475
560
  ```
476
561
 
477
- ### Validação de Dados
562
+ ---
563
+
564
+ ### `IMiddleware`
565
+
566
+ Middleware sem `.handler()`, apenas `.doc()`. Deve ser encadeado dentro de um `IHandler`.
478
567
 
479
568
  ```typescript
480
- import { middleware, Request } from '@ismael1361/router';
569
+ interface IMiddleware<Rq extends Request, Rs extends Response> extends RequestHandler<Rq, Rs> {
570
+ doc(
571
+ operation: MiddlewareFCDoc | swaggerJSDoc.Operation,
572
+ components?: swaggerJSDoc.Components
573
+ ): IMiddleware<Rq, Rs>;
574
+ }
575
+ ```
481
576
 
482
- interface ValidatedRequest extends Request {
483
- validated: {
484
- body?: any;
485
- params?: any;
486
- query?: any;
487
- };
577
+ ---
578
+
579
+ ### `Request`
580
+
581
+ Estende `express.Request` com parâmetros genéricos tipados.
582
+
583
+ ```typescript
584
+ interface Request<
585
+ P extends string = string, // Parâmetros de rota
586
+ ReqBody = {}, // Corpo da requisição
587
+ ReqQuery = core.Query, // Query string
588
+ ResBody = any // Corpo da resposta
589
+ > extends core.Request<ParamsDictionary<P>, ResBody, ReqBody, ReqQuery> {
590
+ clientIp?: string;
591
+ executeOnce?: (isOnce?: boolean) => void;
488
592
  }
593
+ ```
489
594
 
490
- const validate = (schema: any) =>
491
- middleware<ValidatedRequest>(
492
- (req, res, next) => {
493
- // Implementar validação (ex: usando Zod, Joi, etc)
494
- const result = schema.safeParse(req.body);
495
-
496
- if (!result.success) {
497
- return res.status(400).json({
498
- message: 'Dados inválidos',
499
- errors: result.error.errors
500
- });
501
- }
502
-
503
- req.validated = { body: result.data };
504
- next();
505
- },
506
- {
507
- responses: {
508
- 400: { description: 'Dados de entrada inválidos' }
509
- }
510
- }
511
- );
595
+ ```typescript
596
+ // Parâmetros inferidos da rota
597
+ app.get("/users/:userId/posts/:postId")
598
+ .handler((req, res) => {
599
+ req.params.userId; // string ✓
600
+ req.params.postId; // string ✓
601
+ });
512
602
 
513
- router
514
- .post('/users')
515
- .middleware(validate(userSchema))
516
- .handle((req, res) => {
517
- const validatedData = req.validated.body;
518
- res.status(201).json(validatedData);
603
+ // Tipo explícito de body
604
+ interface CreateUser extends Request<string, { name: string; email: string }> {}
605
+
606
+ app.post("/users")
607
+ .handler((req: CreateUser, res) => {
608
+ req.body.name; // string ✓
609
+ req.body.email; // string ✓
519
610
  });
520
611
  ```
521
612
 
522
- ### Organização Modular
613
+ ---
614
+
615
+ ### `Response`
616
+
617
+ Estende `express.Response`.
523
618
 
524
619
  ```typescript
525
- // routes/users.routes.ts
526
- import { route } from '@ismael1361/router';
620
+ interface Response<ResBody = any> extends core.Response<ResBody> {}
621
+ ```
527
622
 
528
- export const usersRouter = route('/users');
623
+ ---
529
624
 
530
- usersRouter
531
- .get('/')
532
- .handle((req, res) => {
533
- res.json([]);
625
+ ### `SwaggerOptions`
626
+
627
+ Configuração para geração de documentação OpenAPI.
628
+
629
+ ```typescript
630
+ interface SwaggerOptions extends swaggerJSDoc.OAS3Definition {
631
+ path?: string; // Prefixo das rotas de doc (default: "/doc")
632
+ defaultResponses?: Responses; // Respostas padrão para todas as rotas
633
+ targets?: SnippetTargets[]; // Linguagens para code snippets
634
+ }
635
+ ```
636
+
637
+ **`SnippetTargets` disponíveis:**
638
+
639
+ `c_libcurl`, `csharp_restsharp`, `csharp_httpclient`, `go_native`, `java_okhttp`, `java_unirest`, `javascript_jquery`, `javascript_xhr`, `node_native`, `node_request`, `node_unirest`, `objc_nsurlsession`, `ocaml_cohttp`, `php_curl`, `php_http1`, `php_http2`, `python_python3`, `python_requests`, `ruby_native`, `shell_curl`, `shell_httpie`, `shell_wget`, `swift_nsurlsession`
640
+
641
+ ---
642
+
643
+ ## 🔀 Métodos HTTP
644
+
645
+ Todos os métodos HTTP retornam um `IHandler` com inferência automática de parâmetros de rota.
646
+
647
+ ```typescript
648
+ // Assinatura
649
+ app.get<Path extends string>(path: Path, doc?: MiddlewareFCDoc): IHandler<Request<ExtractRouteParameters<Path>>>;
650
+ ```
651
+
652
+ **Métodos disponíveis:** `get`, `post`, `put`, `delete`, `patch`, `options`, `head`, `all`
653
+
654
+ ```typescript
655
+ // GET — leitura de recursos
656
+ app.get("/status")
657
+ .handler((req, res) => {
658
+ res.json({ status: "ok" });
659
+ })
660
+ .doc({ tags: ["Health"], summary: "Status da API" });
661
+
662
+ // POST — criação de recursos
663
+ app.post("/users")
664
+ .handler((req, res) => {
665
+ res.status(201).json({ id: Date.now(), ...req.body });
534
666
  })
535
667
  .doc({
536
- summary: 'Listar usuários',
537
- tags: ['Users']
668
+ tags: ["Users"],
669
+ summary: "Criar usuário",
670
+ requestBody: {
671
+ required: true,
672
+ content: {
673
+ "application/json": {
674
+ schema: {
675
+ type: "object",
676
+ required: ["name", "email"],
677
+ properties: {
678
+ name: { type: "string" },
679
+ email: { type: "string", format: "email" },
680
+ },
681
+ },
682
+ },
683
+ },
684
+ },
685
+ responses: { 201: { description: "Usuário criado" } },
538
686
  });
539
687
 
540
- usersRouter
541
- .post('/')
542
- .handle((req, res) => {
543
- res.status(201).json(req.body);
688
+ // PUT — substituição completa
689
+ app.put("/users/:id")
690
+ .handler((req, res) => {
691
+ res.json({ id: req.params.id, ...req.body });
544
692
  })
545
- .doc({
546
- summary: 'Criar usuário',
547
- tags: ['Users']
693
+ .doc({ tags: ["Users"], summary: "Substituir usuário" });
694
+
695
+ // PATCH — atualização parcial
696
+ app.patch("/users/:id")
697
+ .handler((req, res) => {
698
+ res.json({ id: req.params.id, updated: true });
699
+ })
700
+ .doc({ tags: ["Users"], summary: "Atualizar usuário parcialmente" });
701
+
702
+ // DELETE — remoção
703
+ app.delete("/users/:id")
704
+ .handler((req, res) => {
705
+ res.sendStatus(204);
706
+ })
707
+ .doc({ tags: ["Users"], summary: "Remover usuário" });
708
+
709
+ // ALL — responde a qualquer método
710
+ app.all("/proxy/*")
711
+ .handler((req, res) => {
712
+ res.json({ method: req.method, url: req.url });
548
713
  });
714
+ ```
715
+
716
+ **Documentação inline via segundo argumento:**
717
+
718
+ ```typescript
719
+ app.post("/items", { tags: ["Items"], summary: "Criar item" })
720
+ .handler((req, res) => {
721
+ res.status(201).json({ id: 1 });
722
+ });
723
+ ```
724
+
725
+ ---
726
+
727
+ ## 🔗 Rotas e Sub-routers
728
+
729
+ ### `.route()` — Sub-router com prefixo
730
+
731
+ ```typescript
732
+ // Criar sub-router inline
733
+ const usersRoute = app.route("/users");
734
+ usersRoute.get("/").handler((req, res) => res.json([]));
735
+ usersRoute.get("/:id").handler((req, res) => res.json({ id: req.params.id }));
736
+
737
+ // Anexar router existente com documentação global
738
+ const v1 = router();
739
+
740
+ v1.get("/items")
741
+ .handler((req, res) => res.json([]))
742
+ .doc({ tags: ["Items"], summary: "Listar itens" });
743
+
744
+ v1.post("/items")
745
+ .handler((req, res) => res.status(201).json(req.body))
746
+ .doc({ tags: ["Items"], summary: "Criar item" });
747
+
748
+ // Documentação aplicada a todas as rotas do sub-router
749
+ app.route("/v1", v1, {
750
+ security: [{ bearerAuth: [] }],
751
+ responses: {
752
+ 400: { description: "Dados inválidos" },
753
+ 404: { description: "Não encontrado" },
754
+ },
755
+ });
756
+ ```
757
+
758
+ ### `.use()` — Middleware ou sub-router
759
+
760
+ ```typescript
761
+ // Middleware global
762
+ app.use((req, res, next) => {
763
+ console.log(`${req.method} ${req.url}`);
764
+ next();
765
+ });
766
+
767
+ // Middleware em prefixo (retorna IHandler encadeável)
768
+ app.use("/api")
769
+ .handler((req, res, next) => {
770
+ console.log("Requisição na /api");
771
+ next();
772
+ });
773
+
774
+ // Sub-router via use
775
+ const adminRouter = router();
776
+ app.use("/admin", adminRouter);
777
+ ```
778
+
779
+ ### Organização modular
780
+
781
+ ```typescript
782
+ // routes/users.ts
783
+ import { router } from "@ismael1361/router";
784
+
785
+ export const usersRouter = router();
786
+
787
+ usersRouter.get("/")
788
+ .handler((req, res) => res.json([]))
789
+ .doc({ tags: ["Users"], summary: "Listar usuários" });
790
+
791
+ usersRouter.post("/")
792
+ .handler((req, res) => res.status(201).json(req.body))
793
+ .doc({ tags: ["Users"], summary: "Criar usuário" });
549
794
 
550
- // routes/products.routes.ts
551
- export const productsRouter = route('/products');
552
- // ... definir rotas
795
+ // routes/products.ts
796
+ import { router } from "@ismael1361/router";
797
+
798
+ export const productsRouter = router();
799
+
800
+ productsRouter.get("/")
801
+ .handler((req, res) => res.json([]))
802
+ .doc({ tags: ["Products"], summary: "Listar produtos" });
553
803
 
554
804
  // app.ts
555
- import { create } from '@ismael1361/router';
556
- import { usersRouter } from './routes/users.routes';
557
- import { productsRouter } from './routes/products.routes';
805
+ import { create, Middlewares } from "@ismael1361/router";
806
+ import { usersRouter } from "./routes/users";
807
+ import { productsRouter } from "./routes/products";
808
+
809
+ const app = create();
810
+ app.use(Middlewares.json());
558
811
 
559
- const app = express();
560
- const router = create(app)
561
- .middleware(express.json());
812
+ app.route("/users", usersRouter);
813
+ app.route("/products", productsRouter);
814
+
815
+ app.defineSwagger({
816
+ openapi: "3.0.0",
817
+ info: { title: "API Modular", version: "1.0.0" },
818
+ });
562
819
 
563
- router
564
- .by(usersRouter)
565
- .by(productsRouter);
820
+ app.listen(3000);
566
821
  ```
567
822
 
823
+ ---
824
+
568
825
  ## 📚 Documentação OpenAPI/Swagger
569
826
 
570
- O módulo gera automaticamente documentação OpenAPI 3.0 compatível com Swagger UI.
827
+ ### `.doc()` Documentação em handlers e middlewares
571
828
 
572
- ### Configuração Completa
829
+ Anexa metadados OpenAPI sem alterar o fluxo de execução. Pode ser chamado em qualquer ponto da cadeia.
573
830
 
574
831
  ```typescript
575
- import { create, Middlewares } from '@ismael1361/router';
832
+ app.get("/users/:userId")
833
+ .handler(authMiddleware)
834
+ .doc({
835
+ tags: ["Users"],
836
+ summary: "Buscar usuário por ID",
837
+ parameters: [
838
+ { name: "userId", in: "path", required: true, schema: { type: "string" } },
839
+ ],
840
+ })
841
+ .handler((req, res) => {
842
+ res.json({ userId: req.params.userId });
843
+ });
844
+ ```
576
845
 
577
- const app = create().middleware(Middlewares.json());
846
+ **`.doc()` com componentes:**
578
847
 
579
- // Definir rotas com documentação
580
- app
581
- .get('/users/:id')
582
- .handle((req, res) => {
583
- res.json({ id: req.params.id, name: 'John Doe' });
584
- })
585
- .doc({
586
- summary: 'Obter usuário',
587
- description: 'Retorna um usuário pelo ID',
588
- tags: ['Users'],
589
- params: {
590
- id: {
591
- description: 'ID do usuário',
592
- type: 'string',
593
- required: true,
594
- example: '123'
595
- }
848
+ ```typescript
849
+ app.delete("/users/:id")
850
+ .handler(authMiddleware)
851
+ .doc(
852
+ {
853
+ tags: ["Users"],
854
+ summary: "Remover usuário",
855
+ security: [{ bearerAuth: [] }],
596
856
  },
597
- responses: {
598
- 200: {
599
- description: 'Usuário encontrado',
600
- content: {
601
- 'application/json': {
602
- schema: {
603
- type: 'object',
604
- properties: {
605
- id: { type: 'string' },
606
- name: { type: 'string' }
607
- }
608
- }
609
- }
610
- }
857
+ {
858
+ securitySchemes: {
859
+ bearerAuth: { type: "http", scheme: "bearer" },
611
860
  },
612
- 404: { description: 'Usuário não encontrado' }
613
- }
861
+ },
862
+ )
863
+ .handler((req, res) => {
864
+ res.sendStatus(204);
614
865
  });
866
+ ```
867
+
868
+ ### `.defineSwagger()` — Configuração completa
869
+
870
+ Habilita a geração de documentação e cria automaticamente as seguintes rotas:
871
+
872
+ | Rota | Descrição |
873
+ |-------------------------------|----------------------------------|
874
+ | `/doc/swagger` | Interface Swagger UI |
875
+ | `/doc/swagger/definition.json`| Spec OpenAPI JSON |
876
+ | `/doc/redoc` | Interface ReDoc |
877
+ | `/doc/markdown` | Documentação em Markdown |
878
+ | `/doc/.md` | Markdown raw |
615
879
 
616
- // Configurar Swagger
880
+ ```typescript
617
881
  app.defineSwagger({
618
- openapi: '3.0.0',
882
+ openapi: "3.0.0",
619
883
  info: {
620
- title: 'API de Exemplo',
621
- version: '1.0.0',
622
- description: 'Documentação automática gerada com @ismael1361/router',
623
- contact: {
624
- name: 'Suporte',
625
- email: 'suporte@exemplo.com'
626
- }
884
+ title: "API de Exemplo",
885
+ version: "1.0.0",
886
+ description: "Documentação completa da API",
887
+ contact: { name: "Suporte", email: "suporte@example.com" },
627
888
  },
628
889
  servers: [
629
- {
630
- url: 'http://localhost:3000',
631
- description: 'Servidor de desenvolvimento'
632
- },
633
- {
634
- url: 'https://api.exemplo.com',
635
- description: 'Servidor de produção'
636
- }
890
+ { url: "http://localhost:3000", description: "Desenvolvimento" },
891
+ { url: "https://api.exemplo.com", description: "Produção" },
637
892
  ],
638
893
  components: {
639
894
  securitySchemes: {
640
895
  bearerAuth: {
641
- type: 'http',
642
- scheme: 'bearer',
643
- bearerFormat: 'JWT',
644
- description: 'Token JWT no formato Bearer'
896
+ type: "http",
897
+ scheme: "bearer",
898
+ bearerFormat: "JWT",
645
899
  },
646
- apiKey: {
647
- type: 'apiKey',
648
- in: 'header',
649
- name: 'X-API-Key'
650
- }
651
- }
900
+ },
652
901
  },
902
+ // Respostas de erro aplicadas a todas as rotas
653
903
  defaultResponses: {
654
- 500: { description: 'Erro interno do servidor' },
655
- 429: { description: 'Muitas requisições' }
656
- }
904
+ 400: { description: "Dados inválidos" },
905
+ 401: { description: "Falha na autenticação" },
906
+ 403: { description: "Acesso negado" },
907
+ 500: { description: "Erro interno do servidor" },
908
+ },
909
+ // Linguagens de code snippets (opcional)
910
+ targets: ["shell_curl", "javascript_xhr", "node_native", "python_python3"],
657
911
  });
912
+ ```
658
913
 
659
- app.listen(3000, () => {
660
- console.log('🚀 Servidor: http://localhost:3000');
661
- console.log('📚 Docs-swagger: http://localhost:3000/docs/swagger');
662
- console.log('📚 Docs-redoc: http://localhost:3000/docs/redoc');
914
+ ### `.getSwagger()` Obter spec programaticamente
915
+
916
+ ```typescript
917
+ const spec = app.getSwagger();
918
+ console.log(JSON.stringify(spec.definition, null, 2));
919
+ ```
920
+
921
+ ---
922
+
923
+ ## 📊 Sistema de Stacks (Logging)
924
+
925
+ Disponível apenas em `IApplication` (criado via `create()`). Registra erros, warnings e informações em arquivo de log, com UI HTML acessível por rota.
926
+
927
+ ### `.defineStacks(options?)`
928
+
929
+ ```typescript
930
+ interface IStacksOptions {
931
+ path?: string; // Rota da UI (default: "/stacks")
932
+ limit?: number; // Máximo de registros no arquivo (default: 100)
933
+ filePath?: string; // Caminho do arquivo de log (default: "./stacks.log")
934
+ beforeStack?(...stacks: IStackLog[]): Array<IStackLog | string | Error>;
935
+ }
936
+ ```
937
+
938
+ ```typescript
939
+ const { stacksPath } = app.defineStacks({
940
+ path: "/stacks",
941
+ limit: 200,
942
+ filePath: "./logs/stacks.log",
943
+ beforeStack(...stacks) {
944
+ // Filtrar ou transformar antes de salvar
945
+ return stacks.filter((s) => typeof s !== "string" && s.level === "ERROR");
946
+ },
663
947
  });
948
+
949
+ console.log(`Stacks UI: http://localhost:3000${stacksPath}`);
664
950
  ```
665
951
 
666
- ## 🔷 TypeScript
952
+ Ao ativar stacks, `console.error()`, `console.warn()` e `console.info()` são interceptados automaticamente e registrados no arquivo de log. Erros não capturados (`unhandledRejection`, `uncaughtException`) também são registrados.
667
953
 
668
- O módulo é totalmente tipado e oferece excelente suporte ao TypeScript.
954
+ ### `.getStacks()`
669
955
 
670
- ### Tipos Personalizados
956
+ ```typescript
957
+ const logs: IStackLog[] = app.getStacks();
958
+ logs.forEach((log) => {
959
+ console.log(`[${log.level}] ${log.name}: ${log.message} (${log.duration}ms)`);
960
+ });
961
+ ```
962
+
963
+ **`IStackLog`:**
964
+
965
+ | Propriedade | Tipo | Descrição |
966
+ |--------------|---------------------------------------------|--------------------------------|
967
+ | `time` | `Date` | Timestamp do registro |
968
+ | `level` | `"ERROR" \| "WARN" \| "INFO" \| "DEBUG"` | Nível de severidade |
969
+ | `name` | `string` | Nome/categoria do log |
970
+ | `message` | `string` | Mensagem descritiva |
971
+ | `source` | `string` | Origem do log |
972
+ | `statusCode` | `number` | Código HTTP associado |
973
+ | `duration` | `number` | Duração em ms |
974
+ | `meta` | `string` | Metadados adicionais |
975
+
976
+ ---
977
+
978
+ ## 🎯 Exemplos Avançados
979
+
980
+ ### Autenticação e Autorização
671
981
 
672
982
  ```typescript
673
- import { Request, Response } from '@ismael1361/router';
983
+ import { create, middleware, Middlewares, Request } from "@ismael1361/router";
674
984
 
675
- // Estender Request
676
- interface CustomRequest extends Request {
677
- user?: {
678
- id: string;
679
- email: string;
680
- roles: string[];
681
- };
682
- requestId: string;
683
- startTime: number;
985
+ interface AuthRequest extends Request {
986
+ user: { id: string; roles: string[] };
684
987
  }
685
988
 
686
- // Estender Response
687
- interface CustomResponse extends Response {
688
- sendSuccess: (data: any) => void;
689
- sendError: (message: string, code?: number) => void;
989
+ const authenticate = middleware((req: AuthRequest, res, next) => {
990
+ const token = req.headers.authorization?.replace("Bearer ", "");
991
+ if (!token) {
992
+ res.status(401).json({ error: "Token não fornecido" });
993
+ return;
994
+ }
995
+ req.user = { id: "123", roles: ["admin"] };
996
+ next();
997
+ }).doc({
998
+ security: [{ bearerAuth: [] }],
999
+ components: {
1000
+ securitySchemes: {
1001
+ bearerAuth: { type: "http", scheme: "bearer" },
1002
+ },
1003
+ },
1004
+ });
1005
+
1006
+ const authorize = (...roles: string[]) =>
1007
+ middleware((req: AuthRequest, res, next) => {
1008
+ if (!req.user.roles.some((r) => roles.includes(r))) {
1009
+ res.status(403).json({ error: "Acesso negado" });
1010
+ return;
1011
+ }
1012
+ next();
1013
+ });
1014
+
1015
+ const app = create();
1016
+ app.use(Middlewares.json());
1017
+
1018
+ app.get("/admin/users")
1019
+ .handler(authenticate)
1020
+ .handler(authorize("admin"))
1021
+ .handler((req, res) => {
1022
+ // req.user está tipado
1023
+ res.json({ adminId: req.user.id, users: [] });
1024
+ })
1025
+ .doc({
1026
+ tags: ["Admin"],
1027
+ summary: "Listar usuários (Admin)",
1028
+ responses: { 200: { description: "Lista de usuários" } },
1029
+ });
1030
+ ```
1031
+
1032
+ ### Encadeamento de múltiplos handlers com tipos acumulados
1033
+
1034
+ ```typescript
1035
+ interface AuthRequest extends Request {
1036
+ user: { userId: string; id: string; roles: string[] };
690
1037
  }
691
1038
 
692
- // Usar tipos personalizados
693
- const router = create<CustomRequest, CustomResponse>(app);
1039
+ const authMiddleware = middleware((req: AuthRequest, res, next) => {
1040
+ req.user = { userId: "123", id: "abc", roles: ["admin"] };
1041
+ next();
1042
+ }).doc({
1043
+ security: [{ bearerAuth: [] }],
1044
+ });
1045
+
1046
+ app.get("/hello/:userId/:id")
1047
+ .handler(authMiddleware) // req ganha .user
1048
+ .handler((req, res, next) => {
1049
+ // req.user e req.params.userId/id estão disponíveis
1050
+ console.log(`Usuário: ${req.user.userId}`);
1051
+ next();
1052
+ })
1053
+ .doc({
1054
+ tags: ["Users"],
1055
+ summary: "Saudação personalizada",
1056
+ parameters: [
1057
+ { name: "userId", in: "path", required: true, schema: { type: "string" } },
1058
+ { name: "id", in: "path", required: true, schema: { type: "string" } },
1059
+ ],
1060
+ })
1061
+ .handler((req, res) => {
1062
+ res.send(`Hello, ${req.params.userId}! ID: ${req.user.id}`);
1063
+ });
1064
+ ```
1065
+
1066
+ ### Execução única de middleware
1067
+
1068
+ ```typescript
1069
+ const expensiveMiddleware = middleware((req, res, next) => {
1070
+ req.executeOnce?.(); // Garante uma única execução por requisição
1071
+ console.log("Operação custosa executada uma vez");
1072
+ next();
1073
+ });
1074
+
1075
+ // Mesmo aplicado em vários níveis, executa apenas uma vez
1076
+ app.use("/api")
1077
+ .handler(expensiveMiddleware)
1078
+ .handler((req, res, next) => { next(); });
694
1079
 
695
- router
696
- .get('/profile')
697
- .handle((req, res) => {
698
- // req.user está totalmente tipado
699
- // res.sendSuccess está disponível
700
- res.sendSuccess({ user: req.user });
1080
+ app.get("/api/data")
1081
+ .handler(expensiveMiddleware) // Não executa novamente
1082
+ .handler((req, res) => {
1083
+ res.json({ data: [] });
701
1084
  });
702
1085
  ```
703
1086
 
704
- ### Inferência de Tipos
1087
+ ### Aplicação completa com sub-routers, Swagger e stacks
705
1088
 
706
1089
  ```typescript
707
- import { Request } from '@ismael1361/router';
1090
+ import { create, router, middleware, Middlewares, Request } from "@ismael1361/router";
1091
+
1092
+ const app = create();
708
1093
 
709
- // Os tipos são inferidos automaticamente
710
- router
711
- .get('/users/:id')
712
- .handle<Request<any, any, "id">>((req, res) => {
713
- // req.params é Record<"id", any>
714
- // req.params.id é any
715
- // req.query é Record<string, any>
716
- // req.body é any (pode ser tipado com middleware)
717
- const userId: string = req.params.id;
1094
+ app.use(Middlewares.json());
1095
+ app.use(Middlewares.cors({ allowOrigin: "*" }));
1096
+
1097
+ // --- Middleware de autenticação ---
1098
+ interface AuthRequest extends Request<"userId" | "id"> {
1099
+ user: { userId: string; id: string; roles: string[] };
1100
+ }
1101
+
1102
+ const authMiddleware = middleware((req: AuthRequest, res, next) => {
1103
+ const { userId = "", id = "" } = req.params;
1104
+ req.user = { userId, id, roles: ["admin"] };
1105
+ next();
1106
+ }).doc({
1107
+ security: [{ bearerAuth: [] }],
1108
+ components: {
1109
+ securitySchemes: {
1110
+ bearerAuth: { type: "http", scheme: "bearer" },
1111
+ },
1112
+ },
1113
+ });
1114
+
1115
+ // --- Rota direta na aplicação ---
1116
+ app.get("/hello/:userId/:id")
1117
+ .handler(authMiddleware)
1118
+ .handler((req, res, next) => {
1119
+ console.log(`Hello, ${req.user.id}!`);
1120
+ next();
1121
+ })
1122
+ .doc({ tags: ["Users"] })
1123
+ .handler((req, res) => {
1124
+ res.send(`Hello, ${req.params.userId}! ID: ${req.user.userId}`);
1125
+ })
1126
+ .doc({
1127
+ summary: "Saudação com autenticação",
1128
+ parameters: [
1129
+ { name: "userId", in: "path", required: true, schema: { type: "string" } },
1130
+ { name: "id", in: "path", required: true, schema: { type: "string" } },
1131
+ ],
718
1132
  });
1133
+
1134
+ // --- Sub-router v1 ---
1135
+ const v1 = router();
1136
+
1137
+ v1.get("/test/route")
1138
+ .handler((req, res) => {
1139
+ res.send("Hello from route!");
1140
+ })
1141
+ .doc({ tags: ["V1"], summary: "Rota de teste v1" });
1142
+
1143
+ app.route("/v1", v1, {
1144
+ security: [{ bearerAuth: [] }],
1145
+ responses: {
1146
+ 400: { description: "Account not found" },
1147
+ 404: { description: "Not found" },
1148
+ },
1149
+ });
1150
+
1151
+ // --- Swagger ---
1152
+ app.defineSwagger({
1153
+ openapi: "3.0.0",
1154
+ info: { title: "My API", version: "1.0.0" },
1155
+ defaultResponses: {
1156
+ 400: { description: "Dados inválidos" },
1157
+ 401: { description: "Falha na autenticação" },
1158
+ 403: { description: "Acesso negado" },
1159
+ 500: { description: "Erro interno do servidor" },
1160
+ },
1161
+ });
1162
+
1163
+ // --- Stacks ---
1164
+ app.defineStacks({
1165
+ path: "/stacks",
1166
+ limit: 100,
1167
+ filePath: "./stacks.log",
1168
+ });
1169
+
1170
+ app.listen(8080, () => {
1171
+ console.log("Server: http://localhost:8080");
1172
+ console.log("Swagger: http://localhost:8080/doc/swagger");
1173
+ console.log("ReDoc: http://localhost:8080/doc/redoc");
1174
+ console.log("Stacks: http://localhost:8080/stacks");
1175
+ });
719
1176
  ```
720
1177
 
721
- ## 🤝 Contribuindo
1178
+ ---
722
1179
 
723
- Contribuições são bem-vindas! Por favor, siga estas etapas:
1180
+ ## 🤝 Contribuindo
724
1181
 
725
1182
  1. Faça um fork do projeto
726
1183
  2. Crie uma branch para sua feature (`git checkout -b feature/MinhaFeature`)
@@ -732,12 +1189,6 @@ Contribuições são bem-vindas! Por favor, siga estas etapas:
732
1189
 
733
1190
  Este projeto está sob a licença MIT. Veja o arquivo [LICENSE](MIT) para mais detalhes.
734
1191
 
735
- ## 🙏 Agradecimentos
736
-
737
- - Express.js pela base sólida
738
- - Swagger/OpenAPI pela especificação de documentação
739
- - A comunidade TypeScript
740
-
741
1192
  ---
742
1193
 
743
- Desenvolvido com ❤️ por [Ismael Souza Silva](https://github.com/ismael1361)
1194
+ Desenvolvido com ❤️ por [Ismael Souza Silva](https://github.com/ismael1361)