canxjs 1.3.5 → 1.4.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 (259) hide show
  1. package/bin/canx.ts +4 -0
  2. package/dist/Application.d.ts +23 -0
  3. package/dist/Application.d.ts.map +1 -1
  4. package/dist/Application.js +35 -0
  5. package/dist/bin/canx.d.ts +3 -0
  6. package/dist/bin/canx.d.ts.map +1 -0
  7. package/dist/bin/canx.js +3 -0
  8. package/dist/core/Middleware.d.ts +10 -0
  9. package/dist/core/Middleware.d.ts.map +1 -1
  10. package/dist/core/Middleware.js +71 -0
  11. package/dist/core/Router.d.ts +5 -0
  12. package/dist/core/Router.d.ts.map +1 -1
  13. package/dist/core/Router.js +61 -7
  14. package/dist/core/Server.d.ts.map +1 -1
  15. package/dist/core/Server.js +2 -1
  16. package/dist/index.d.ts +6 -4
  17. package/dist/index.d.ts.map +1 -1
  18. package/dist/index.js +8 -4
  19. package/dist/middlewares/CsrfMiddleware.d.ts +33 -0
  20. package/dist/middlewares/CsrfMiddleware.d.ts.map +1 -0
  21. package/dist/middlewares/CsrfMiddleware.js +82 -0
  22. package/dist/mvc/Controller.d.ts +20 -0
  23. package/dist/mvc/Controller.d.ts.map +1 -1
  24. package/dist/mvc/Controller.js +68 -0
  25. package/dist/mvc/Model.d.ts +14 -0
  26. package/dist/mvc/Model.d.ts.map +1 -1
  27. package/dist/mvc/Model.js +29 -0
  28. package/dist/src/Application.d.ts +75 -0
  29. package/dist/src/Application.d.ts.map +1 -0
  30. package/dist/src/Application.js +183 -0
  31. package/dist/src/auth/Auth.d.ts +81 -0
  32. package/dist/src/auth/Auth.d.ts.map +1 -0
  33. package/dist/src/auth/Auth.js +241 -0
  34. package/dist/src/auth/drivers/DatabaseSessionDriver.d.ts +13 -0
  35. package/dist/src/auth/drivers/DatabaseSessionDriver.d.ts.map +1 -0
  36. package/dist/src/auth/drivers/DatabaseSessionDriver.js +67 -0
  37. package/dist/src/cli/Command.d.ts +6 -0
  38. package/dist/src/cli/Command.d.ts.map +1 -0
  39. package/dist/src/cli/Command.js +1 -0
  40. package/dist/src/cli/commands/MakeCommand.d.ts +19 -0
  41. package/dist/src/cli/commands/MakeCommand.d.ts.map +1 -0
  42. package/dist/src/cli/commands/MakeCommand.js +140 -0
  43. package/dist/src/cli/commands/MigrateCommand.d.ts +7 -0
  44. package/dist/src/cli/commands/MigrateCommand.d.ts.map +1 -0
  45. package/dist/src/cli/commands/MigrateCommand.js +89 -0
  46. package/dist/src/cli/commands/OptimizeCommand.d.ts +7 -0
  47. package/dist/src/cli/commands/OptimizeCommand.d.ts.map +1 -0
  48. package/dist/src/cli/commands/OptimizeCommand.js +14 -0
  49. package/dist/src/cli/commands/QueueWorkCommand.d.ts +7 -0
  50. package/dist/src/cli/commands/QueueWorkCommand.d.ts.map +1 -0
  51. package/dist/src/cli/commands/QueueWorkCommand.js +52 -0
  52. package/dist/src/cli/commands/RouteListCommand.d.ts +8 -0
  53. package/dist/src/cli/commands/RouteListCommand.d.ts.map +1 -0
  54. package/dist/src/cli/commands/RouteListCommand.js +75 -0
  55. package/dist/src/cli/commands/ScheduleRunCommand.d.ts +7 -0
  56. package/dist/src/cli/commands/ScheduleRunCommand.d.ts.map +1 -0
  57. package/dist/src/cli/commands/ScheduleRunCommand.js +23 -0
  58. package/dist/src/cli/commands/TestCommand.d.ts +7 -0
  59. package/dist/src/cli/commands/TestCommand.d.ts.map +1 -0
  60. package/dist/src/cli/commands/TestCommand.js +19 -0
  61. package/dist/src/cli/index.d.ts +10 -0
  62. package/dist/src/cli/index.d.ts.map +1 -0
  63. package/dist/src/cli/index.js +78 -0
  64. package/dist/src/container/Container.d.ts +117 -0
  65. package/dist/src/container/Container.d.ts.map +1 -0
  66. package/dist/src/container/Container.js +290 -0
  67. package/dist/src/core/ErrorHandler.d.ts +20 -0
  68. package/dist/src/core/ErrorHandler.d.ts.map +1 -0
  69. package/dist/src/core/ErrorHandler.js +221 -0
  70. package/dist/src/core/Middleware.d.ts +34 -0
  71. package/dist/src/core/Middleware.d.ts.map +1 -0
  72. package/dist/src/core/Middleware.js +163 -0
  73. package/dist/src/core/Router.d.ts +44 -0
  74. package/dist/src/core/Router.d.ts.map +1 -0
  75. package/dist/src/core/Router.js +231 -0
  76. package/dist/src/core/Server.d.ts +35 -0
  77. package/dist/src/core/Server.d.ts.map +1 -0
  78. package/dist/src/core/Server.js +475 -0
  79. package/dist/src/core/exceptions/CanxException.d.ts +7 -0
  80. package/dist/src/core/exceptions/CanxException.d.ts.map +1 -0
  81. package/dist/src/core/exceptions/CanxException.js +13 -0
  82. package/dist/src/core/exceptions/HttpException.d.ts +5 -0
  83. package/dist/src/core/exceptions/HttpException.d.ts.map +1 -0
  84. package/dist/src/core/exceptions/HttpException.js +6 -0
  85. package/dist/src/core/exceptions/NotFoundException.d.ts +5 -0
  86. package/dist/src/core/exceptions/NotFoundException.d.ts.map +1 -0
  87. package/dist/src/core/exceptions/NotFoundException.js +6 -0
  88. package/dist/src/core/exceptions/ValidationException.d.ts +5 -0
  89. package/dist/src/core/exceptions/ValidationException.d.ts.map +1 -0
  90. package/dist/src/core/exceptions/ValidationException.js +6 -0
  91. package/dist/src/database/Migration.d.ts +78 -0
  92. package/dist/src/database/Migration.d.ts.map +1 -0
  93. package/dist/src/database/Migration.js +331 -0
  94. package/dist/src/database/Seeder.d.ts +47 -0
  95. package/dist/src/database/Seeder.d.ts.map +1 -0
  96. package/dist/src/database/Seeder.js +69 -0
  97. package/dist/src/database/migrations/20240114000000_create_sessions_table.d.ts +3 -0
  98. package/dist/src/database/migrations/20240114000000_create_sessions_table.d.ts.map +1 -0
  99. package/dist/src/database/migrations/20240114000000_create_sessions_table.js +14 -0
  100. package/dist/src/docs/ApiDoc.d.ts +102 -0
  101. package/dist/src/docs/ApiDoc.d.ts.map +1 -0
  102. package/dist/src/docs/ApiDoc.js +145 -0
  103. package/dist/src/events/EventEmitter.d.ts +88 -0
  104. package/dist/src/events/EventEmitter.d.ts.map +1 -0
  105. package/dist/src/events/EventEmitter.js +266 -0
  106. package/dist/src/features/AutoCache.d.ts +41 -0
  107. package/dist/src/features/AutoCache.d.ts.map +1 -0
  108. package/dist/src/features/AutoCache.js +200 -0
  109. package/dist/src/features/HotWire.d.ts +51 -0
  110. package/dist/src/features/HotWire.d.ts.map +1 -0
  111. package/dist/src/features/HotWire.js +179 -0
  112. package/dist/src/features/JITCompiler.d.ts +67 -0
  113. package/dist/src/features/JITCompiler.d.ts.map +1 -0
  114. package/dist/src/features/JITCompiler.js +126 -0
  115. package/dist/src/features/RequestBatcher.d.ts +47 -0
  116. package/dist/src/features/RequestBatcher.d.ts.map +1 -0
  117. package/dist/src/features/RequestBatcher.js +119 -0
  118. package/dist/src/features/Scheduler.d.ts +67 -0
  119. package/dist/src/features/Scheduler.d.ts.map +1 -0
  120. package/dist/src/features/Scheduler.js +205 -0
  121. package/dist/src/generator/ClientGenerator.d.ts +7 -0
  122. package/dist/src/generator/ClientGenerator.d.ts.map +1 -0
  123. package/dist/src/generator/ClientGenerator.js +109 -0
  124. package/dist/src/index.d.ts +67 -0
  125. package/dist/src/index.d.ts.map +1 -0
  126. package/dist/src/index.js +112 -0
  127. package/dist/src/jsx-runtime.d.ts +5 -0
  128. package/dist/src/jsx-runtime.d.ts.map +1 -0
  129. package/dist/src/jsx-runtime.js +4 -0
  130. package/dist/src/middlewares/CsrfMiddleware.d.ts +33 -0
  131. package/dist/src/middlewares/CsrfMiddleware.d.ts.map +1 -0
  132. package/dist/src/middlewares/CsrfMiddleware.js +82 -0
  133. package/dist/src/middlewares/RateLimitMiddleware.d.ts +10 -0
  134. package/dist/src/middlewares/RateLimitMiddleware.d.ts.map +1 -0
  135. package/dist/src/middlewares/RateLimitMiddleware.js +38 -0
  136. package/dist/src/middlewares/SecurityMiddleware.d.ts +14 -0
  137. package/dist/src/middlewares/SecurityMiddleware.d.ts.map +1 -0
  138. package/dist/src/middlewares/SecurityMiddleware.js +38 -0
  139. package/dist/src/middlewares/ValidationMiddleware.d.ts +4 -0
  140. package/dist/src/middlewares/ValidationMiddleware.d.ts.map +1 -0
  141. package/dist/src/middlewares/ValidationMiddleware.js +33 -0
  142. package/dist/src/mvc/Controller.d.ts +48 -0
  143. package/dist/src/mvc/Controller.d.ts.map +1 -0
  144. package/dist/src/mvc/Controller.js +153 -0
  145. package/dist/src/mvc/Model.d.ts +135 -0
  146. package/dist/src/mvc/Model.d.ts.map +1 -0
  147. package/dist/src/mvc/Model.js +514 -0
  148. package/dist/src/mvc/View.d.ts +33 -0
  149. package/dist/src/mvc/View.d.ts.map +1 -0
  150. package/dist/src/mvc/View.js +107 -0
  151. package/dist/src/mvc/jsx-runtime.d.ts +3 -0
  152. package/dist/src/mvc/jsx-runtime.d.ts.map +1 -0
  153. package/dist/src/mvc/jsx-runtime.js +4 -0
  154. package/dist/src/notifications/Mail.d.ts +101 -0
  155. package/dist/src/notifications/Mail.d.ts.map +1 -0
  156. package/dist/src/notifications/Mail.js +320 -0
  157. package/dist/src/notifications/Notification.d.ts +147 -0
  158. package/dist/src/notifications/Notification.d.ts.map +1 -0
  159. package/dist/src/notifications/Notification.js +212 -0
  160. package/dist/src/queue/Queue.d.ts +56 -0
  161. package/dist/src/queue/Queue.d.ts.map +1 -0
  162. package/dist/src/queue/Queue.js +159 -0
  163. package/dist/src/queue/drivers/MemoryDriver.d.ts +24 -0
  164. package/dist/src/queue/drivers/MemoryDriver.d.ts.map +1 -0
  165. package/dist/src/queue/drivers/MemoryDriver.js +120 -0
  166. package/dist/src/queue/drivers/RedisDriver.d.ts +27 -0
  167. package/dist/src/queue/drivers/RedisDriver.d.ts.map +1 -0
  168. package/dist/src/queue/drivers/RedisDriver.js +144 -0
  169. package/dist/src/queue/drivers/types.d.ts +51 -0
  170. package/dist/src/queue/drivers/types.d.ts.map +1 -0
  171. package/dist/src/queue/drivers/types.js +1 -0
  172. package/dist/src/queue/ui/Dashboard.d.ts +2 -0
  173. package/dist/src/queue/ui/Dashboard.d.ts.map +1 -0
  174. package/dist/src/queue/ui/Dashboard.js +51 -0
  175. package/dist/src/queue/ui/QueueController.d.ts +10 -0
  176. package/dist/src/queue/ui/QueueController.d.ts.map +1 -0
  177. package/dist/src/queue/ui/QueueController.js +81 -0
  178. package/dist/src/realtime/Channel.d.ts +69 -0
  179. package/dist/src/realtime/Channel.d.ts.map +1 -0
  180. package/dist/src/realtime/Channel.js +169 -0
  181. package/dist/src/realtime/WebSocket.d.ts +138 -0
  182. package/dist/src/realtime/WebSocket.d.ts.map +1 -0
  183. package/dist/src/realtime/WebSocket.js +326 -0
  184. package/dist/src/schema/Schema.d.ts +64 -0
  185. package/dist/src/schema/Schema.d.ts.map +1 -0
  186. package/dist/src/schema/Schema.js +248 -0
  187. package/dist/src/storage/Storage.d.ts +116 -0
  188. package/dist/src/storage/Storage.d.ts.map +1 -0
  189. package/dist/src/storage/Storage.js +246 -0
  190. package/dist/src/storage/drivers/LocalDriver.d.ts +27 -0
  191. package/dist/src/storage/drivers/LocalDriver.d.ts.map +1 -0
  192. package/dist/src/storage/drivers/LocalDriver.js +191 -0
  193. package/dist/src/storage/drivers/S3Driver.d.ts +33 -0
  194. package/dist/src/storage/drivers/S3Driver.d.ts.map +1 -0
  195. package/dist/src/storage/drivers/S3Driver.js +291 -0
  196. package/dist/src/storage/drivers/types.d.ts +94 -0
  197. package/dist/src/storage/drivers/types.d.ts.map +1 -0
  198. package/dist/src/storage/drivers/types.js +4 -0
  199. package/dist/src/testing/TestCase.d.ts +190 -0
  200. package/dist/src/testing/TestCase.d.ts.map +1 -0
  201. package/dist/src/testing/TestCase.js +350 -0
  202. package/dist/src/testing/TestClient.d.ts +32 -0
  203. package/dist/src/testing/TestClient.d.ts.map +1 -0
  204. package/dist/src/testing/TestClient.js +85 -0
  205. package/dist/src/types/index.d.ts +496 -0
  206. package/dist/src/types/index.d.ts.map +1 -0
  207. package/dist/src/types/index.js +5 -0
  208. package/dist/src/utils/Env.d.ts +28 -0
  209. package/dist/src/utils/Env.d.ts.map +1 -0
  210. package/dist/src/utils/Env.js +57 -0
  211. package/dist/src/utils/ErrorHandler.d.ts +92 -0
  212. package/dist/src/utils/ErrorHandler.d.ts.map +1 -0
  213. package/dist/src/utils/ErrorHandler.js +220 -0
  214. package/dist/src/utils/Health.d.ts +111 -0
  215. package/dist/src/utils/Health.d.ts.map +1 -0
  216. package/dist/src/utils/Health.js +371 -0
  217. package/dist/src/utils/Logger.d.ts +71 -0
  218. package/dist/src/utils/Logger.d.ts.map +1 -0
  219. package/dist/src/utils/Logger.js +237 -0
  220. package/dist/src/utils/Request.d.ts +33 -0
  221. package/dist/src/utils/Request.d.ts.map +1 -0
  222. package/dist/src/utils/Request.js +122 -0
  223. package/dist/src/utils/Response.d.ts +25 -0
  224. package/dist/src/utils/Response.d.ts.map +1 -0
  225. package/dist/src/utils/Response.js +103 -0
  226. package/dist/src/utils/Validator.d.ts +32 -0
  227. package/dist/src/utils/Validator.d.ts.map +1 -0
  228. package/dist/src/utils/Validator.js +220 -0
  229. package/dist/src/utils/i18n.d.ts +95 -0
  230. package/dist/src/utils/i18n.d.ts.map +1 -0
  231. package/dist/src/utils/i18n.js +264 -0
  232. package/dist/utils/Env.d.ts +28 -0
  233. package/dist/utils/Env.d.ts.map +1 -0
  234. package/dist/utils/Env.js +57 -0
  235. package/package.json +4 -4
  236. package/src/Application.ts +75 -26
  237. package/src/cli/Command.ts +5 -0
  238. package/src/cli/commands/MakeCommand.ts +159 -0
  239. package/src/cli/commands/MigrateCommand.ts +93 -0
  240. package/src/cli/commands/OptimizeCommand.ts +21 -0
  241. package/src/cli/commands/QueueWorkCommand.ts +58 -0
  242. package/src/cli/commands/RouteListCommand.ts +92 -0
  243. package/src/cli/commands/ScheduleRunCommand.ts +27 -0
  244. package/src/cli/commands/TestCommand.ts +25 -0
  245. package/src/cli/index.ts +90 -0
  246. package/src/core/Middleware.ts +85 -0
  247. package/src/core/Router.ts +84 -7
  248. package/src/core/Server.ts +2 -1
  249. package/src/features/Scheduler.ts +4 -0
  250. package/src/index.ts +9 -4
  251. package/src/middlewares/CsrfMiddleware.ts +113 -0
  252. package/src/middlewares/SecurityMiddleware.ts +16 -15
  253. package/src/mvc/Controller.ts +79 -0
  254. package/src/mvc/Model.ts +143 -82
  255. package/src/testing/TestClient.ts +8 -0
  256. package/src/types/index.ts +13 -1
  257. package/src/utils/Env.ts +67 -0
  258. package/src/utils/Logger.ts +39 -0
  259. package/src/utils/Validator.ts +2 -2
package/bin/canx.ts ADDED
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env bun
2
+ import { cli } from '../src/cli';
3
+
4
+ cli.run(process.argv.slice(2));
@@ -46,7 +46,30 @@ export declare class Canx implements CanxApplication {
46
46
  put(path: string, ...handlers: any[]): this;
47
47
  patch(path: string, ...handlers: any[]): this;
48
48
  delete(path: string, ...handlers: any[]): this;
49
+ all(path: string, ...handlers: any[]): this;
50
+ /**
51
+ * Register a resource controller with RESTful routes
52
+ */
53
+ resource(path: string, controller: any, ...middlewares: MiddlewareHandler[]): this;
54
+ /**
55
+ * Group routes with a common prefix
56
+ */
57
+ group(prefix: string, callback: (router: RouterInstance) => void): this;
58
+ /**
59
+ * Register routes under a versioned API path
60
+ * @param version - Version identifier (e.g., 'v1', 'v2')
61
+ * @param callback - Route registration callback
62
+ */
63
+ version(version: string, callback: (router: RouterInstance) => void): this;
49
64
  }
65
+ /**
66
+ * Create a new CanxJS application instance
67
+ */
50
68
  export declare function createApp(config?: ServerConfig): Canx;
69
+ /**
70
+ * Define configuration with type checking
71
+ * Helper for creating typed configuration objects
72
+ */
73
+ export declare function defineConfig<T extends Record<string, any>>(config: T): T;
51
74
  export default Canx;
52
75
  //# sourceMappingURL=Application.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"Application.d.ts","sourceRoot":"","sources":["../src/Application.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,iBAAiB,EAAc,eAAe,EAAE,cAAc,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAEpH,OAAO,EAAE,MAAM,EAAgB,MAAM,eAAe,CAAC;AAIrD,qBAAa,IAAK,YAAW,eAAe;IAC1C,MAAM,EAAE,YAAY,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,MAAM,CAAuB;IACrC,OAAO,CAAC,QAAQ,CAAqB;IACrC,OAAO,CAAC,OAAO,CAAgB;gBAEnB,MAAM,GAAE,YAAiB;IAWrC;;OAEG;IACH,GAAG,CAAC,UAAU,EAAE,iBAAiB,GAAG,IAAI;IAKxC;;OAEG;IACH,MAAM,CAAC,QAAQ,EAAE,CAAC,MAAM,EAAE,cAAc,KAAK,IAAI,GAAG,IAAI;IAKxD;;OAEG;IACH,UAAU,CAAC,eAAe,EAAE,UAAU,GAAG,GAAG,IAAI;IAoBhD;;OAEG;IACH,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAK5B;;OAEG;IACG,MAAM,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,CAAC,MAAM,IAAI,CAAC,EAAE,QAAQ,CAAC,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IAuBhF;;OAEG;IACG,MAAM,CAAC,MAAM,EAAE,OAAO,GAAG,OAAO,CAAC,QAAQ,CAAC;IAoChD;;OAEG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAW5B;;OAEG;IACH,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,QAAQ,EAAE,GAAG,EAAE,GAAG,IAAI;IAC3C,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,QAAQ,EAAE,GAAG,EAAE,GAAG,IAAI;IAC5C,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,QAAQ,EAAE,GAAG,EAAE,GAAG,IAAI;IAC3C,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,QAAQ,EAAE,GAAG,EAAE,GAAG,IAAI;IAC7C,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,QAAQ,EAAE,GAAG,EAAE,GAAG,IAAI;CAC/C;AAED,wBAAgB,SAAS,CAAC,MAAM,CAAC,EAAE,YAAY,GAAG,IAAI,CAErD;AAED,eAAe,IAAI,CAAC"}
1
+ {"version":3,"file":"Application.d.ts","sourceRoot":"","sources":["../src/Application.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,iBAAiB,EAAc,eAAe,EAAE,cAAc,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAEpH,OAAO,EAAE,MAAM,EAAgB,MAAM,eAAe,CAAC;AAIrD,qBAAa,IAAK,YAAW,eAAe;IAC1C,MAAM,EAAE,YAAY,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,MAAM,CAAuB;IACrC,OAAO,CAAC,QAAQ,CAAqB;IACrC,OAAO,CAAC,OAAO,CAAgB;gBAEnB,MAAM,GAAE,YAAiB;IAWrC;;OAEG;IACH,GAAG,CAAC,UAAU,EAAE,iBAAiB,GAAG,IAAI;IAKxC;;OAEG;IACH,MAAM,CAAC,QAAQ,EAAE,CAAC,MAAM,EAAE,cAAc,KAAK,IAAI,GAAG,IAAI;IAKxD;;OAEG;IACH,UAAU,CAAC,eAAe,EAAE,UAAU,GAAG,GAAG,IAAI;IAoBhD;;OAEG;IACH,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAK5B;;OAEG;IACG,MAAM,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,CAAC,MAAM,IAAI,CAAC,EAAE,QAAQ,CAAC,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IAuBhF;;OAEG;IACG,MAAM,CAAC,MAAM,EAAE,OAAO,GAAG,OAAO,CAAC,QAAQ,CAAC;IAoChD;;OAEG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAW5B;;OAEG;IACH,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,QAAQ,EAAE,GAAG,EAAE,GAAG,IAAI;IAC3C,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,QAAQ,EAAE,GAAG,EAAE,GAAG,IAAI;IAC5C,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,QAAQ,EAAE,GAAG,EAAE,GAAG,IAAI;IAC3C,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,QAAQ,EAAE,GAAG,EAAE,GAAG,IAAI;IAC7C,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,QAAQ,EAAE,GAAG,EAAE,GAAG,IAAI;IAC9C,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,QAAQ,EAAE,GAAG,EAAE,GAAG,IAAI;IAE3C;;OAEG;IACH,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,GAAG,EAAE,GAAG,WAAW,EAAE,iBAAiB,EAAE,GAAG,IAAI;IAKlF;;OAEG;IACH,KAAK,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,MAAM,EAAE,cAAc,KAAK,IAAI,GAAG,IAAI;IAKvE;;;;OAIG;IACH,OAAO,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,MAAM,EAAE,cAAc,KAAK,IAAI,GAAG,IAAI;CAK3E;AAED;;GAEG;AACH,wBAAgB,SAAS,CAAC,MAAM,CAAC,EAAE,YAAY,GAAG,IAAI,CAErD;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,EAAE,CAAC,GAAG,CAAC,CAExE;AAED,eAAe,IAAI,CAAC"}
@@ -132,8 +132,43 @@ export class Canx {
132
132
  put(path, ...handlers) { this.router.put(path, ...handlers); return this; }
133
133
  patch(path, ...handlers) { this.router.patch(path, ...handlers); return this; }
134
134
  delete(path, ...handlers) { this.router.delete(path, ...handlers); return this; }
135
+ all(path, ...handlers) { this.router.all(path, ...handlers); return this; }
136
+ /**
137
+ * Register a resource controller with RESTful routes
138
+ */
139
+ resource(path, controller, ...middlewares) {
140
+ this.router.resource(path, controller, ...middlewares);
141
+ return this;
142
+ }
143
+ /**
144
+ * Group routes with a common prefix
145
+ */
146
+ group(prefix, callback) {
147
+ this.router.group(prefix, callback);
148
+ return this;
149
+ }
150
+ /**
151
+ * Register routes under a versioned API path
152
+ * @param version - Version identifier (e.g., 'v1', 'v2')
153
+ * @param callback - Route registration callback
154
+ */
155
+ version(version, callback) {
156
+ const prefix = version.startsWith('/') ? version : '/api/' + version;
157
+ this.router.group(prefix, callback);
158
+ return this;
159
+ }
135
160
  }
161
+ /**
162
+ * Create a new CanxJS application instance
163
+ */
136
164
  export function createApp(config) {
137
165
  return new Canx(config);
138
166
  }
167
+ /**
168
+ * Define configuration with type checking
169
+ * Helper for creating typed configuration objects
170
+ */
171
+ export function defineConfig(config) {
172
+ return config;
173
+ }
139
174
  export default Canx;
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env bun
2
+ export {};
3
+ //# sourceMappingURL=canx.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"canx.d.ts","sourceRoot":"","sources":["../../bin/canx.ts"],"names":[],"mappings":""}
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env bun
2
+ import { cli } from '../src/cli';
3
+ cli.run(process.argv.slice(2));
@@ -19,6 +19,16 @@ export declare const rateLimit: (options?: {
19
19
  max?: number;
20
20
  }) => MiddlewareHandler;
21
21
  export declare const compress: () => MiddlewareHandler;
22
+ /**
23
+ * Serve static files from a directory
24
+ * @param root - The root directory to serve files from (relative to cwd or absolute)
25
+ * @param options - Configuration options
26
+ */
27
+ export declare const serveStatic: (root?: string, options?: {
28
+ index?: string;
29
+ maxAge?: number;
30
+ extensions?: string[];
31
+ }) => MiddlewareHandler;
22
32
  export declare function createMiddlewarePipeline(): MiddlewarePipeline;
23
33
  export default MiddlewarePipeline;
24
34
  //# sourceMappingURL=Middleware.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"Middleware.d.ts","sourceRoot":"","sources":["../../src/core/Middleware.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,iBAAiB,EAAgB,MAAM,UAAU,CAAC;AAG3F,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,WAAW,CAA2B;IAE9C,GAAG,CAAC,GAAG,QAAQ,EAAE,iBAAiB,EAAE,GAAG,IAAI;IAKrC,OAAO,CACX,GAAG,EAAE,WAAW,EAChB,GAAG,EAAE,YAAY,EACjB,gBAAgB,EAAE,iBAAiB,EAAE,EACrC,YAAY,EAAE,MAAM,OAAO,CAAC,QAAQ,CAAC,GAAG,QAAQ,GAC/C,OAAO,CAAC,QAAQ,CAAC;CAuBrB;AAGD,eAAO,MAAM,IAAI,GAAI,UAAS;IAAE,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IAAC,WAAW,CAAC,EAAE,OAAO,CAAA;CAAO,KAAG,iBAQ9G,CAAC;AAEF,eAAO,MAAM,MAAM,QAAO,iBAQzB,CAAC;AAEF,eAAO,MAAM,UAAU,QAAO,iBAO7B,CAAC;AAEF,eAAO,MAAM,SAAS,GAAI,UAAS;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAA;CAAO,KAAG,iBAkB7E,CAAC;AAEF,eAAO,MAAM,QAAQ,QAAO,iBAQ3B,CAAC;AAEF,wBAAgB,wBAAwB,IAAI,kBAAkB,CAE7D;AAED,eAAe,kBAAkB,CAAC"}
1
+ {"version":3,"file":"Middleware.d.ts","sourceRoot":"","sources":["../../src/core/Middleware.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,iBAAiB,EAAgB,MAAM,UAAU,CAAC;AAG3F,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,WAAW,CAA2B;IAE9C,GAAG,CAAC,GAAG,QAAQ,EAAE,iBAAiB,EAAE,GAAG,IAAI;IAKrC,OAAO,CACX,GAAG,EAAE,WAAW,EAChB,GAAG,EAAE,YAAY,EACjB,gBAAgB,EAAE,iBAAiB,EAAE,EACrC,YAAY,EAAE,MAAM,OAAO,CAAC,QAAQ,CAAC,GAAG,QAAQ,GAC/C,OAAO,CAAC,QAAQ,CAAC;CAuBrB;AAGD,eAAO,MAAM,IAAI,GAAI,UAAS;IAAE,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IAAC,WAAW,CAAC,EAAE,OAAO,CAAA;CAAO,KAAG,iBAQ9G,CAAC;AAEF,eAAO,MAAM,MAAM,QAAO,iBAQzB,CAAC;AAEF,eAAO,MAAM,UAAU,QAAO,iBAO7B,CAAC;AAEF,eAAO,MAAM,SAAS,GAAI,UAAS;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAA;CAAO,KAAG,iBAkB7E,CAAC;AAEF,eAAO,MAAM,QAAQ,QAAO,iBAQ3B,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,WAAW,GAAI,OAAM,MAAiB,EAAE,UAAS;IAC5D,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;CAClB,KAAG,iBA0ER,CAAC;AAEF,wBAAgB,wBAAwB,IAAI,kBAAkB,CAE7D;AAED,eAAe,kBAAkB,CAAC"}
@@ -86,6 +86,77 @@ export const compress = () => {
86
86
  return next();
87
87
  };
88
88
  };
89
+ /**
90
+ * Serve static files from a directory
91
+ * @param root - The root directory to serve files from (relative to cwd or absolute)
92
+ * @param options - Configuration options
93
+ */
94
+ export const serveStatic = (root = 'public', options = {}) => {
95
+ const { index = 'index.html', maxAge = 86400 } = options;
96
+ // Use path utilities inline to avoid import issues
97
+ const isAbsolute = (p) => p.startsWith('/') || /^[A-Za-z]:[\\/]/.test(p);
98
+ const join = (...parts) => parts.join('/').replace(/\/+/g, '/');
99
+ const extname = (p) => {
100
+ const lastDot = p.lastIndexOf('.');
101
+ const lastSlash = Math.max(p.lastIndexOf('/'), p.lastIndexOf('\\'));
102
+ return lastDot > lastSlash ? p.slice(lastDot) : '';
103
+ };
104
+ const rootPath = isAbsolute(root) ? root : join(process.cwd(), root);
105
+ const mimeTypes = {
106
+ '.html': 'text/html',
107
+ '.css': 'text/css',
108
+ '.js': 'application/javascript',
109
+ '.json': 'application/json',
110
+ '.png': 'image/png',
111
+ '.jpg': 'image/jpeg',
112
+ '.jpeg': 'image/jpeg',
113
+ '.gif': 'image/gif',
114
+ '.svg': 'image/svg+xml',
115
+ '.ico': 'image/x-icon',
116
+ '.woff': 'font/woff',
117
+ '.woff2': 'font/woff2',
118
+ '.ttf': 'font/ttf',
119
+ '.eot': 'application/vnd.ms-fontobject',
120
+ '.pdf': 'application/pdf',
121
+ '.webp': 'image/webp',
122
+ '.mp4': 'video/mp4',
123
+ '.webm': 'video/webm',
124
+ '.txt': 'text/plain',
125
+ '.xml': 'application/xml',
126
+ };
127
+ return async (req, res, next) => {
128
+ if (req.method !== 'GET' && req.method !== 'HEAD') {
129
+ return next();
130
+ }
131
+ // Clean the path to prevent directory traversal
132
+ const cleanPath = req.path.replace(/\.\./g, '').replace(/\/+/g, '/');
133
+ let filePath = join(rootPath, cleanPath);
134
+ try {
135
+ let file = Bun.file(filePath);
136
+ // Check if it's a directory by trying index file
137
+ if (!(await file.exists())) {
138
+ file = Bun.file(join(filePath, index));
139
+ if (!(await file.exists())) {
140
+ return next();
141
+ }
142
+ filePath = join(filePath, index);
143
+ }
144
+ const ext = extname(filePath).toLowerCase();
145
+ const contentType = mimeTypes[ext] || 'application/octet-stream';
146
+ return new Response(file, {
147
+ headers: {
148
+ 'Content-Type': contentType,
149
+ 'Cache-Control': `public, max-age=${maxAge}`,
150
+ 'Content-Length': String(file.size),
151
+ },
152
+ });
153
+ }
154
+ catch (e) {
155
+ // File not found, continue to next middleware
156
+ }
157
+ return next();
158
+ };
159
+ };
89
160
  export function createMiddlewarePipeline() {
90
161
  return new MiddlewarePipeline();
91
162
  }
@@ -31,6 +31,11 @@ export declare class Router implements RouterInstance {
31
31
  group(prefix: string, cb: (r: RouterInstance) => void): RouterInstance;
32
32
  middleware(...h: MiddlewareHandler[]): RouterInstance;
33
33
  use(...h: MiddlewareHandler[]): Router;
34
+ /**
35
+ * Register a resource controller with standard RESTful routes
36
+ * Creates: GET /, GET /:id, POST /, PUT /:id, DELETE /:id
37
+ */
38
+ resource(path: string, controller: any, ...middlewares: MiddlewareHandler[]): RouterInstance;
34
39
  getRoutes(): Route[];
35
40
  private collect;
36
41
  }
@@ -1 +1 @@
1
- {"version":3,"file":"Router.d.ts","sourceRoot":"","sources":["../../src/core/Router.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EACV,UAAU,EACV,KAAK,EACL,YAAY,EACZ,aAAa,EACb,iBAAiB,EACjB,WAAW,EACX,cAAc,EACf,MAAM,UAAU,CAAC;AAalB,UAAU,UAAU;IAClB,OAAO,EAAE,YAAY,CAAC;IACtB,WAAW,EAAE,iBAAiB,EAAE,CAAC;IACjC,MAAM,EAAE,WAAW,CAAC;CACrB;AAyCD,qBAAa,MAAO,YAAW,cAAc;IAC3C,OAAO,CAAC,KAAK,CAAyC;IACtD,OAAO,CAAC,aAAa,CAAgB;IACrC,OAAO,CAAC,iBAAiB,CAA2B;IACpD,OAAO,CAAC,kBAAkB,CAA2B;IACrD,OAAO,CAAC,MAAM,CAAc;IAC5B,OAAO,CAAC,UAAU,CAA6C;gBAEnD,OAAO,GAAE,aAAkB;IAMvC,OAAO,CAAC,aAAa;IAMrB,OAAO,CAAC,QAAQ;IAuBhB,KAAK,CAAC,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI;IAU1D,OAAO,CAAC,SAAS;IAmBjB,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,CAAC,iBAAiB,GAAG,YAAY,GAAG,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC,EAAE,GAAG,cAAc;IAC7F,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,CAAC,iBAAiB,GAAG,YAAY,GAAG,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC,EAAE,GAAG,cAAc;IAC9F,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,CAAC,iBAAiB,GAAG,YAAY,GAAG,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC,EAAE,GAAG,cAAc;IAC7F,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,CAAC,iBAAiB,GAAG,YAAY,GAAG,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC,EAAE,GAAG,cAAc;IAC/F,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,CAAC,iBAAiB,GAAG,YAAY,GAAG,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC,EAAE,GAAG,cAAc;IAChG,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,CAAC,iBAAiB,GAAG,YAAY,GAAG,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC,EAAE,GAAG,cAAc;IACjG,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,CAAC,iBAAiB,GAAG,YAAY,GAAG,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC,EAAE,GAAG,cAAc;IAC9F,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,CAAC,iBAAiB,GAAG,YAAY,GAAG,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC,EAAE,GAAG,cAAc;IAE7F,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,eAAe,EAAE,GAAG,GAAG,cAAc;IA6B9D,KAAK,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,cAAc,KAAK,IAAI,GAAG,cAAc;IAQtE,UAAU,CAAC,GAAG,CAAC,EAAE,iBAAiB,EAAE,GAAG,cAAc;IACrD,GAAG,CAAC,GAAG,CAAC,EAAE,iBAAiB,EAAE,GAAG,MAAM;IAEtC,SAAS,IAAI,KAAK,EAAE;IAMpB,OAAO,CAAC,OAAO;CAKhB;AAED,wBAAgB,YAAY,CAAC,OAAO,CAAC,EAAE,aAAa,GAAG,MAAM,CAAgC;AAC7F,eAAe,MAAM,CAAC"}
1
+ {"version":3,"file":"Router.d.ts","sourceRoot":"","sources":["../../src/core/Router.ts"],"names":[],"mappings":"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"}
@@ -55,20 +55,25 @@ export class Router {
55
55
  return p.startsWith('/') ? p : '/' + p;
56
56
  }
57
57
  addRoute(method, path, handler, mws = []) {
58
+ // Normalize path but preserve original for param name extraction
59
+ const originalPath = (this.prefix + path).startsWith('/') ? this.prefix + path : '/' + this.prefix + path;
58
60
  const normalized = this.normalizePath(this.prefix + path);
59
- const tree = this.trees.get(method);
60
61
  const segments = normalized.split('/').filter(Boolean);
61
- let node = tree;
62
- for (const seg of segments) {
62
+ const originalSegments = originalPath.split('/').filter(Boolean);
63
+ let node = this.trees.get(method);
64
+ for (let i = 0; i < segments.length; i++) {
65
+ const seg = segments[i];
66
+ const originalSeg = originalSegments[i] || seg;
63
67
  let key = seg, isParam = false, isWild = false, param = null;
64
- if (seg.startsWith(':')) {
68
+ // Extract param name from ORIGINAL segment to preserve casing
69
+ if (originalSeg.startsWith(':')) {
65
70
  isParam = true;
66
- param = seg.slice(1);
71
+ param = originalSeg.slice(1); // Use original casing
67
72
  key = ':';
68
73
  }
69
- else if (seg === '*' || seg.startsWith('*')) {
74
+ else if (originalSeg === '*' || originalSeg.startsWith('*')) {
70
75
  isWild = true;
71
- param = seg.length > 1 ? seg.slice(1) : 'wildcard';
76
+ param = originalSeg.length > 1 ? originalSeg.slice(1) : 'wildcard';
72
77
  key = '*';
73
78
  }
74
79
  if (!node.children.has(key)) {
@@ -99,12 +104,15 @@ export class Router {
99
104
  let node = tree;
100
105
  for (let i = 0; i < segments.length; i++) {
101
106
  const seg = segments[i];
107
+ // Try exact match first
102
108
  let child = node.children.get(this.routerOptions.caseSensitive ? seg : seg.toLowerCase());
109
+ // If no exact match, try parameter match
103
110
  if (!child) {
104
111
  child = node.children.get(':');
105
112
  if (child?.paramName)
106
113
  params[child.paramName] = seg;
107
114
  }
115
+ // If still no match, try wildcard
108
116
  if (!child) {
109
117
  child = node.children.get('*');
110
118
  if (child?.paramName) {
@@ -115,6 +123,10 @@ export class Router {
115
123
  }
116
124
  if (!child)
117
125
  return null;
126
+ // If this is a param node, capture the parameter value
127
+ if (child.isParam && child.paramName && !params[child.paramName]) {
128
+ params[child.paramName] = seg;
129
+ }
118
130
  node = child;
119
131
  }
120
132
  return node.handler ? { handler: node.handler, middlewares: node.middlewares, params } : null;
@@ -161,6 +173,48 @@ export class Router {
161
173
  }
162
174
  middleware(...h) { this.currentMiddlewares.push(...h); return this; }
163
175
  use(...h) { this.globalMiddlewares.push(...h); return this; }
176
+ /**
177
+ * Register a resource controller with standard RESTful routes
178
+ * Creates: GET /, GET /:id, POST /, PUT /:id, DELETE /:id
179
+ */
180
+ resource(path, controller, ...middlewares) {
181
+ const instance = typeof controller === 'function' ? new controller() : controller;
182
+ const basePath = path.startsWith('/') ? path : '/' + path;
183
+ // Helper to create handler
184
+ const createHandler = (method) => async (req, res) => {
185
+ if (typeof instance.setContext === 'function') {
186
+ instance.setContext(req, res);
187
+ }
188
+ if (typeof instance[method] === 'function') {
189
+ return instance[method](req, res);
190
+ }
191
+ return res.status(404).json({ error: `Method ${method} not found` });
192
+ };
193
+ // Standard RESTful routes
194
+ if (typeof instance.index === 'function') {
195
+ this.addRoute('GET', basePath, createHandler('index'), middlewares);
196
+ }
197
+ if (typeof instance.show === 'function') {
198
+ this.addRoute('GET', basePath + '/:id', createHandler('show'), middlewares);
199
+ }
200
+ if (typeof instance.store === 'function') {
201
+ this.addRoute('POST', basePath, createHandler('store'), middlewares);
202
+ }
203
+ if (typeof instance.update === 'function') {
204
+ this.addRoute('PUT', basePath + '/:id', createHandler('update'), middlewares);
205
+ }
206
+ if (typeof instance.destroy === 'function') {
207
+ this.addRoute('DELETE', basePath + '/:id', createHandler('destroy'), middlewares);
208
+ }
209
+ // Optional: create, edit for form-based apps
210
+ if (typeof instance.create === 'function') {
211
+ this.addRoute('GET', basePath + '/create', createHandler('create'), middlewares);
212
+ }
213
+ if (typeof instance.edit === 'function') {
214
+ this.addRoute('GET', basePath + '/:id/edit', createHandler('edit'), middlewares);
215
+ }
216
+ return this;
217
+ }
164
218
  getRoutes() {
165
219
  const routes = [];
166
220
  this.trees.forEach((tree, method) => this.collect(tree, '', method, routes));
@@ -1 +1 @@
1
- {"version":3,"file":"Server.d.ts","sourceRoot":"","sources":["../../src/core/Server.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EACV,YAAY,EACZ,WAAW,EACX,YAAY,EAEZ,WAAW,EAIZ,MAAM,UAAU,CAAC;AA+ClB;;GAEG;AACH,wBAAgB,iBAAiB,CAC/B,GAAG,EAAE,OAAO,EACZ,MAAM,GAAE,WAAgB,GACvB,WAAW,CAgFb;AAED;;GAEG;AACH,wBAAgB,kBAAkB,IAAI,YAAY,CAqMjD;AAkDD;;GAEG;AACH,qBAAa,MAAM;IACjB,OAAO,CAAC,MAAM,CAA6C;IAC3D,OAAO,CAAC,MAAM,CAAe;IAC7B,OAAO,CAAC,cAAc,CAAiD;gBAGrE,MAAM,EAAE,YAAY,EACpB,OAAO,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,OAAO,CAAC,QAAQ,CAAC,GAAG,QAAQ;IAczD;;OAEG;IACG,MAAM,CAAC,QAAQ,CAAC,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IA+GlD;;OAEG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAQ5B;;OAEG;IACH,IAAI,QAAQ,+BAEX;CACF;AAED,eAAe,MAAM,CAAC"}
1
+ {"version":3,"file":"Server.d.ts","sourceRoot":"","sources":["../../src/core/Server.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EACV,YAAY,EACZ,WAAW,EACX,YAAY,EAEZ,WAAW,EAIZ,MAAM,UAAU,CAAC;AA+ClB;;GAEG;AACH,wBAAgB,iBAAiB,CAC/B,GAAG,EAAE,OAAO,EACZ,MAAM,GAAE,WAAgB,GACvB,WAAW,CAgFb;AAED;;GAEG;AACH,wBAAgB,kBAAkB,IAAI,YAAY,CAqMjD;AAkDD;;GAEG;AACH,qBAAa,MAAM;IACjB,OAAO,CAAC,MAAM,CAA6C;IAC3D,OAAO,CAAC,MAAM,CAAe;IAC7B,OAAO,CAAC,cAAc,CAAiD;gBAGrE,MAAM,EAAE,YAAY,EACpB,OAAO,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,OAAO,CAAC,QAAQ,CAAC,GAAG,QAAQ;IAczD;;OAEG;IACG,MAAM,CAAC,QAAQ,CAAC,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IAgHlD;;OAEG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAQ5B;;OAEG;IACH,IAAI,QAAQ,+BAEX;CACF;AAED,eAAe,MAAM,CAAC"}
@@ -420,12 +420,13 @@ export class Server {
420
420
  if (callback) {
421
421
  callback();
422
422
  }
423
+ const displayHost = this.config.hostname === '0.0.0.0' ? 'localhost' : this.config.hostname;
423
424
  console.log(`
424
425
  ╔══════════════════════════════════════════════════════════╗
425
426
  ║ ║
426
427
  ║ 🚀 CanxJS Server running ║
427
428
  ║ ║
428
- ║ → Local: http://${this.config.hostname}:${this.config.port}
429
+ ║ → Local: http://${displayHost}:${this.config.port}
429
430
  ║ → Mode: ${this.config.development ? 'Development' : 'Production'} ║
430
431
  ║ ║
431
432
  ╚══════════════════════════════════════════════════════════╝
package/dist/index.d.ts CHANGED
@@ -5,16 +5,17 @@
5
5
  */
6
6
  export { Server, createCanxRequest, createCanxResponse } from './core/Server';
7
7
  export { Router, createRouter } from './core/Router';
8
- export { MiddlewarePipeline, cors, logger, bodyParser, rateLimit, compress, createMiddlewarePipeline } from './core/Middleware';
8
+ export { MiddlewarePipeline, cors, logger, bodyParser, rateLimit, compress, serveStatic, createMiddlewarePipeline } from './core/Middleware';
9
9
  export { security } from './middlewares/SecurityMiddleware';
10
10
  export { rateLimit as rateLimitMiddleware } from './middlewares/RateLimitMiddleware';
11
11
  export { validateSchema } from './middlewares/ValidationMiddleware';
12
+ export { csrf, csrfField, csrfMeta } from './middlewares/CsrfMiddleware';
12
13
  export { z, Schema as ZSchema } from './schema/Schema';
13
14
  export type { Infer } from './schema/Schema';
14
15
  export { ClientGenerator } from './generator/ClientGenerator';
15
16
  export { TestClient } from './testing/TestClient';
16
- export { BaseController, Controller, Get, Post, Put, Patch, Delete, Middleware, getControllerMeta } from './mvc/Controller';
17
- export { Model, initDatabase, closeDatabase, query, execute } from './mvc/Model';
17
+ export { BaseController, Controller, Get, Post, Put, Patch, Delete, Middleware, Validate, getControllerMeta } from './mvc/Controller';
18
+ export { Model, QueryBuilderImpl, initDatabase, closeDatabase, query, execute } from './mvc/Model';
18
19
  export { jsx, jsxs, Fragment, html, render, renderPage, createLayout, View } from './mvc/View';
19
20
  export { hotWire, createHotWire } from './features/HotWire';
20
21
  export { autoCache, autoCacheMiddleware, createAutoCache } from './features/AutoCache';
@@ -44,6 +45,7 @@ export type { ServiceProvider } from './container/Container';
44
45
  export { validate, validateAsync, is } from './utils/Validator';
45
46
  export { ResponseBuilder, response } from './utils/Response';
46
47
  export { RequestParser, parseRequest } from './utils/Request';
48
+ export { env, isProduction, isDevelopment, isTest, requireEnv } from './utils/Env';
47
49
  export { ErrorHandler } from './core/ErrorHandler';
48
50
  export { CanxException } from './core/exceptions/CanxException';
49
51
  export { HttpException } from './core/exceptions/HttpException';
@@ -58,7 +60,7 @@ export { initI18n, useI18n, t, plural, I18n, i18nMiddleware } from './utils/i18n
58
60
  export type { I18nConfig, TranslationObject } from './utils/i18n';
59
61
  export { ResponseAssertions, MockFactory, createTestClient, assertResponse, factory, randomString, randomEmail, randomNumber, randomUuid, sleep, } from './testing/TestCase';
60
62
  export type { TestResponse, TestRequest } from './testing/TestCase';
61
- export { Canx, createApp } from './Application';
63
+ export { Canx, createApp, defineConfig } from './Application';
62
64
  export type * from './types';
63
65
  export type { CanxRequest as Request, CanxResponse as Response } from './types';
64
66
  export { Canx as default } from './Application';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAKH,OAAO,EAAE,MAAM,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAC9E,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAIrD,OAAO,EAAE,kBAAkB,EAAE,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,QAAQ,EAAE,WAAW,EAAE,wBAAwB,EAAE,MAAM,mBAAmB,CAAC;AAC7I,OAAO,EAAE,QAAQ,EAAE,MAAM,kCAAkC,CAAC;AAC5D,OAAO,EAAE,SAAS,IAAI,mBAAmB,EAAE,MAAM,mCAAmC,CAAC;AACrF,OAAO,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AACpE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,8BAA8B,CAAC;AAKzE,OAAO,EAAE,CAAC,EAAE,MAAM,IAAI,OAAO,EAAE,MAAM,iBAAiB,CAAC;AACvD,YAAY,EAAE,KAAK,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAC9D,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAKlD,OAAO,EAAE,cAAc,EAAE,UAAU,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,QAAQ,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACtI,OAAO,EAAE,KAAK,EAAE,gBAAgB,EAAE,YAAY,EAAE,aAAa,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AACnG,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,YAAY,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAK/F,OAAO,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAC5D,OAAO,EAAE,SAAS,EAAE,mBAAmB,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACvF,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAC1E,OAAO,EAAE,WAAW,EAAE,iBAAiB,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AACrF,OAAO,EAAE,SAAS,EAAE,eAAe,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAK7E,OAAO,EACL,IAAI,EACJ,YAAY,EACZ,cAAc,EACd,OAAO,EACP,SAAS,EACT,OAAO,EACP,YAAY,EACZ,OAAO,EACP,KAAK,EACL,KAAK,EACL,WAAW,EACX,YAAY,EACZ,qBAAqB,GACtB,MAAM,aAAa,CAAC;AAKrB,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACzE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,IAAI,aAAa,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAKzF,OAAO,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AACnD,OAAO,EAAE,WAAW,EAAE,MAAM,6BAA6B,CAAC;AAC1D,OAAO,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAC5D,OAAO,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAK7D,OAAO,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAC5D,OAAO,EAAE,EAAE,EAAE,qBAAqB,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAKlF,OAAO,EAAE,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAC;AAC9F,OAAO,EAAE,WAAW,EAAE,MAAM,+BAA+B,CAAC;AAC5D,OAAO,EAAE,QAAQ,EAAE,MAAM,4BAA4B,CAAC;AACtD,YAAY,EAAE,aAAa,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAK1F,OAAO,EAAE,MAAM,EAAE,kBAAkB,EAAE,YAAY,EAAE,MAAM,EAAE,iBAAiB,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAKlI,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACrF,OAAO,EAAE,aAAa,EAAE,MAAM,EAAE,UAAU,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAC/G,YAAY,EAAE,WAAW,EAAE,UAAU,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACjG,YAAY,EAAE,UAAU,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AAKpF,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,eAAe,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AACjJ,YAAY,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAK7D,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,EAAE,EAAE,MAAM,mBAAmB,CAAC;AAEhE,OAAO,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC7D,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAG9D,OAAO,EAAE,GAAG,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAGnF,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,aAAa,EAAE,MAAM,iCAAiC,CAAC;AAChE,OAAO,EAAE,aAAa,EAAE,MAAM,iCAAiC,CAAC;AAChE,OAAO,EAAE,iBAAiB,EAAE,MAAM,qCAAqC,CAAC;AACxE,OAAO,EAAE,mBAAmB,EAAE,MAAM,uCAAuC,CAAC;AAC5E,OAAO,EACL,SAAS,EACT,eAAe,EACf,aAAa,EACb,mBAAmB,EACnB,kBAAkB,EAClB,aAAa,EACb,cAAc,EACd,eAAe,EACf,aAAa,EACb,uBAAuB,EACvB,YAAY,EACZ,YAAY,EACZ,WAAW,EACX,mBAAmB,EACnB,gBAAgB,EAChB,WAAW,EACX,MAAM,GACP,MAAM,sBAAsB,CAAC;AAG9B,OAAO,EAAE,GAAG,EAAE,YAAY,EAAE,MAAM,EAAE,aAAa,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAC/F,YAAY,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAG/C,OAAO,EACL,MAAM,EACN,OAAO,EACP,aAAa,EACb,WAAW,EACX,SAAS,EACT,SAAS,EACT,UAAU,EACV,WAAW,EACX,YAAY,EACZ,mBAAmB,GACpB,MAAM,gBAAgB,CAAC;AACxB,YAAY,EAAE,iBAAiB,EAAE,YAAY,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAGnG,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAClF,YAAY,EAAE,UAAU,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAKlE,OAAO,EACL,kBAAkB,EAClB,WAAW,EACX,gBAAgB,EAChB,cAAc,EACd,OAAO,EACP,YAAY,EACZ,WAAW,EACX,YAAY,EACZ,UAAU,EACV,KAAK,GACN,MAAM,oBAAoB,CAAC;AAC5B,YAAY,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAKpE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAK9D,mBAAmB,SAAS,CAAC;AAC7B,YAAY,EAAE,WAAW,IAAI,OAAO,EAAE,YAAY,IAAI,QAAQ,EAAE,MAAM,SAAS,CAAC;AAKhF,OAAO,EAAE,IAAI,IAAI,OAAO,EAAE,MAAM,eAAe,CAAC"}
package/dist/index.js CHANGED
@@ -11,10 +11,11 @@ export { Router, createRouter } from './core/Router';
11
11
  // ============================================
12
12
  // Middleware Exports
13
13
  // ============================================
14
- export { MiddlewarePipeline, cors, logger, bodyParser, rateLimit, compress, createMiddlewarePipeline } from './core/Middleware';
14
+ export { MiddlewarePipeline, cors, logger, bodyParser, rateLimit, compress, serveStatic, createMiddlewarePipeline } from './core/Middleware';
15
15
  export { security } from './middlewares/SecurityMiddleware';
16
16
  export { rateLimit as rateLimitMiddleware } from './middlewares/RateLimitMiddleware';
17
17
  export { validateSchema } from './middlewares/ValidationMiddleware';
18
+ export { csrf, csrfField, csrfMeta } from './middlewares/CsrfMiddleware';
18
19
  // ============================================
19
20
  // Schema / Validation Exports
20
21
  // ============================================
@@ -24,8 +25,8 @@ export { TestClient } from './testing/TestClient';
24
25
  // ============================================
25
26
  // MVC Exports
26
27
  // ============================================
27
- export { BaseController, Controller, Get, Post, Put, Patch, Delete, Middleware, getControllerMeta } from './mvc/Controller';
28
- export { Model, initDatabase, closeDatabase, query, execute } from './mvc/Model';
28
+ export { BaseController, Controller, Get, Post, Put, Patch, Delete, Middleware, Validate, getControllerMeta } from './mvc/Controller';
29
+ export { Model, QueryBuilderImpl, initDatabase, closeDatabase, query, execute } from './mvc/Model';
29
30
  export { jsx, jsxs, Fragment, html, render, renderPage, createLayout, View } from './mvc/View';
30
31
  // ============================================
31
32
  // Feature Exports
@@ -79,8 +80,11 @@ export { container, bind, singleton, resolve, Injectable, Inject, Container, Sco
79
80
  // Utils Exports
80
81
  // ============================================
81
82
  export { validate, validateAsync, is } from './utils/Validator';
83
+ // Utils - Request/Response
82
84
  export { ResponseBuilder, response } from './utils/Response';
83
85
  export { RequestParser, parseRequest } from './utils/Request';
86
+ // Environment Helper
87
+ export { env, isProduction, isDevelopment, isTest, requireEnv } from './utils/Env';
84
88
  // Error Handling
85
89
  export { ErrorHandler } from './core/ErrorHandler';
86
90
  export { CanxException } from './core/exceptions/CanxException';
@@ -101,7 +105,7 @@ export { ResponseAssertions, MockFactory, createTestClient, assertResponse, fact
101
105
  // ============================================
102
106
  // Application Exports
103
107
  // ============================================
104
- export { Canx, createApp } from './Application';
108
+ export { Canx, createApp, defineConfig } from './Application';
105
109
  // ============================================
106
110
  // Default Export
107
111
  // ============================================
@@ -0,0 +1,33 @@
1
+ /**
2
+ * CanxJS CSRF Protection Middleware
3
+ * Protects against Cross-Site Request Forgery attacks
4
+ */
5
+ import type { MiddlewareHandler } from '../types';
6
+ export interface CsrfConfig {
7
+ /** Cookie name for CSRF token */
8
+ cookieName?: string;
9
+ /** Header name for CSRF token */
10
+ headerName?: string;
11
+ /** Form field name for CSRF token */
12
+ fieldName?: string;
13
+ /** HTTP methods to protect */
14
+ methods?: string[];
15
+ /** Token expiry in seconds */
16
+ maxAge?: number;
17
+ /** Paths to exclude from CSRF protection */
18
+ ignorePaths?: string[];
19
+ }
20
+ /**
21
+ * CSRF Protection Middleware
22
+ */
23
+ export declare function csrf(config?: CsrfConfig): MiddlewareHandler;
24
+ /**
25
+ * Helper to generate CSRF hidden input for forms
26
+ */
27
+ export declare function csrfField(token: string): string;
28
+ /**
29
+ * Helper to get CSRF meta tag for AJAX
30
+ */
31
+ export declare function csrfMeta(token: string): string;
32
+ export default csrf;
33
+ //# sourceMappingURL=CsrfMiddleware.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CsrfMiddleware.d.ts","sourceRoot":"","sources":["../../src/middlewares/CsrfMiddleware.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAA6B,MAAM,UAAU,CAAC;AAE7E,MAAM,WAAW,UAAU;IACzB,iCAAiC;IACjC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,iCAAiC;IACjC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,qCAAqC;IACrC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,8BAA8B;IAC9B,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,8BAA8B;IAC9B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,4CAA4C;IAC5C,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;CACxB;AAoBD;;GAEG;AACH,wBAAgB,IAAI,CAAC,MAAM,GAAE,UAAe,GAAG,iBAAiB,CAqD/D;AAED;;GAEG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAE/C;AAED;;GAEG;AACH,wBAAgB,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAE9C;AAED,eAAe,IAAI,CAAC"}
@@ -0,0 +1,82 @@
1
+ /**
2
+ * CanxJS CSRF Protection Middleware
3
+ * Protects against Cross-Site Request Forgery attacks
4
+ */
5
+ const DEFAULT_CONFIG = {
6
+ cookieName: 'csrf_token',
7
+ headerName: 'x-csrf-token',
8
+ fieldName: '_csrf',
9
+ methods: ['POST', 'PUT', 'PATCH', 'DELETE'],
10
+ maxAge: 3600,
11
+ ignorePaths: [],
12
+ };
13
+ /**
14
+ * Generate a random CSRF token
15
+ */
16
+ function generateToken() {
17
+ const array = new Uint8Array(32);
18
+ crypto.getRandomValues(array);
19
+ return Array.from(array, b => b.toString(16).padStart(2, '0')).join('');
20
+ }
21
+ /**
22
+ * CSRF Protection Middleware
23
+ */
24
+ export function csrf(config = {}) {
25
+ const opts = { ...DEFAULT_CONFIG, ...config };
26
+ return async (req, res, next) => {
27
+ // Check if path should be ignored
28
+ if (opts.ignorePaths.some(p => req.path.startsWith(p))) {
29
+ return next();
30
+ }
31
+ // Get or create token
32
+ let token = req.cookie(opts.cookieName);
33
+ if (!token) {
34
+ token = generateToken();
35
+ res.cookie(opts.cookieName, token, {
36
+ httpOnly: true,
37
+ sameSite: 'Strict',
38
+ maxAge: opts.maxAge,
39
+ path: '/',
40
+ });
41
+ }
42
+ // Attach token to request for use in views
43
+ req.csrfToken = token;
44
+ req.getCsrfToken = () => token;
45
+ // Skip validation for safe methods
46
+ if (!opts.methods.includes(req.method)) {
47
+ return next();
48
+ }
49
+ // Get token from header or body
50
+ const headerToken = req.header(opts.headerName);
51
+ let bodyToken;
52
+ try {
53
+ const body = await req.body();
54
+ bodyToken = body?.[opts.fieldName];
55
+ }
56
+ catch {
57
+ // Body might not be parseable
58
+ }
59
+ const submittedToken = headerToken || bodyToken;
60
+ // Validate token
61
+ if (!submittedToken || submittedToken !== token) {
62
+ return res.status(403).json({
63
+ error: 'CSRF token mismatch',
64
+ message: 'Invalid or missing CSRF token',
65
+ });
66
+ }
67
+ return next();
68
+ };
69
+ }
70
+ /**
71
+ * Helper to generate CSRF hidden input for forms
72
+ */
73
+ export function csrfField(token) {
74
+ return `<input type="hidden" name="_csrf" value="${token}" />`;
75
+ }
76
+ /**
77
+ * Helper to get CSRF meta tag for AJAX
78
+ */
79
+ export function csrfMeta(token) {
80
+ return `<meta name="csrf-token" content="${token}" />`;
81
+ }
82
+ export default csrf;
@@ -10,6 +10,18 @@ export declare const Post: (path?: string) => MethodDecorator;
10
10
  export declare const Put: (path?: string) => MethodDecorator;
11
11
  export declare const Patch: (path?: string) => MethodDecorator;
12
12
  export declare const Delete: (path?: string) => MethodDecorator;
13
+ /**
14
+ * Validate decorator - validates request body against a schema
15
+ * @param schema - Zod-like schema with parse/safeParse method
16
+ */
17
+ export declare function Validate(schema: {
18
+ parse?: (data: any) => any;
19
+ safeParse?: (data: any) => {
20
+ success: boolean;
21
+ data?: any;
22
+ error?: any;
23
+ };
24
+ }): MethodDecorator;
13
25
  export declare abstract class BaseController {
14
26
  protected request: CanxRequest;
15
27
  protected response: CanxResponse;
@@ -23,6 +35,14 @@ export declare abstract class BaseController {
23
35
  protected header(name: string): string | null;
24
36
  protected cookie(name: string): string | undefined;
25
37
  protected setCookie(name: string, value: string, options?: any): void;
38
+ protected created<T>(data: T): Response;
39
+ protected noContent(): Response;
40
+ protected accepted<T>(data?: T): Response;
41
+ protected notFound(message?: string): Response;
42
+ protected badRequest(message?: string): Response;
43
+ protected unauthorized(message?: string): Response;
44
+ protected forbidden(message?: string): Response;
45
+ protected validated<T>(): Promise<T>;
26
46
  }
27
47
  export default BaseController;
28
48
  //# sourceMappingURL=Controller.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"Controller.d.ts","sourceRoot":"","sources":["../../src/mvc/Controller.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAc,iBAAiB,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAKzG,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,cAAc,CAKhE;AAGD,wBAAgB,UAAU,CAAC,MAAM,GAAE,MAAW,GAAG,cAAc,CAK9D;AAED,wBAAgB,UAAU,CAAC,GAAG,WAAW,EAAE,iBAAiB,EAAE,GAAG,eAAe,GAAG,cAAc,CAYhG;AAcD,eAAO,MAAM,GAAG,UAXA,MAAM,KAAQ,eAWiB,CAAC;AAChD,eAAO,MAAM,IAAI,UAZD,MAAM,KAAQ,eAYmB,CAAC;AAClD,eAAO,MAAM,GAAG,UAbA,MAAM,KAAQ,eAaiB,CAAC;AAChD,eAAO,MAAM,KAAK,UAdF,MAAM,KAAQ,eAcqB,CAAC;AACpD,eAAO,MAAM,MAAM,UAfH,MAAM,KAAQ,eAeuB,CAAC;AAGtD,8BAAsB,cAAc;IAClC,SAAS,CAAC,OAAO,EAAG,WAAW,CAAC;IAChC,SAAS,CAAC,QAAQ,EAAG,YAAY,CAAC;IAElC,UAAU,CAAC,GAAG,EAAE,WAAW,EAAE,GAAG,EAAE,YAAY,GAAG,IAAI;IAKrD,SAAS,CAAC,IAAI,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,MAAM,GAAE,MAAY,GAAG,QAAQ;IAI1D,SAAS,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,GAAE,MAAY,GAAG,QAAQ;IAI/D,SAAS,CAAC,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,GAAE,GAAG,GAAG,GAAS,GAAG,QAAQ;IAIlE,SAAS,CAAC,KAAK,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAIhD,SAAS,CAAC,KAAK,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS;cAI3C,IAAI,CAAC,CAAC,GAAG,OAAO,KAAK,OAAO,CAAC,CAAC,CAAC;IAI/C,SAAS,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAI7C,SAAS,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAIlD,SAAS,CAAC,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,GAAG,IAAI;CAGtE;AAED,eAAe,cAAc,CAAC"}
1
+ {"version":3,"file":"Controller.d.ts","sourceRoot":"","sources":["../../src/mvc/Controller.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAc,iBAAiB,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAKzG,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,cAAc,CAKhE;AAGD,wBAAgB,UAAU,CAAC,MAAM,GAAE,MAAW,GAAG,cAAc,CAK9D;AAED,wBAAgB,UAAU,CAAC,GAAG,WAAW,EAAE,iBAAiB,EAAE,GAAG,eAAe,GAAG,cAAc,CAYhG;AAcD,eAAO,MAAM,GAAG,UAXA,MAAM,KAAQ,eAWiB,CAAC;AAChD,eAAO,MAAM,IAAI,UAZD,MAAM,KAAQ,eAYmB,CAAC;AAClD,eAAO,MAAM,GAAG,UAbA,MAAM,KAAQ,eAaiB,CAAC;AAChD,eAAO,MAAM,KAAK,UAdF,MAAM,KAAQ,eAcqB,CAAC;AACpD,eAAO,MAAM,MAAM,UAfH,MAAM,KAAQ,eAeuB,CAAC;AAEtD;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,MAAM,EAAE;IAAE,KAAK,CAAC,EAAE,CAAC,IAAI,EAAE,GAAG,KAAK,GAAG,CAAC;IAAC,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,GAAG,KAAK;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,IAAI,CAAC,EAAE,GAAG,CAAC;QAAC,KAAK,CAAC,EAAE,GAAG,CAAA;KAAE,CAAA;CAAE,GAAG,eAAe,CAuC1J;AAGD,8BAAsB,cAAc;IAClC,SAAS,CAAC,OAAO,EAAG,WAAW,CAAC;IAChC,SAAS,CAAC,QAAQ,EAAG,YAAY,CAAC;IAElC,UAAU,CAAC,GAAG,EAAE,WAAW,EAAE,GAAG,EAAE,YAAY,GAAG,IAAI;IAKrD,SAAS,CAAC,IAAI,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,MAAM,GAAE,MAAY,GAAG,QAAQ;IAI1D,SAAS,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,GAAE,MAAY,GAAG,QAAQ;IAI/D,SAAS,CAAC,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,GAAE,GAAG,GAAG,GAAS,GAAG,QAAQ;IAIlE,SAAS,CAAC,KAAK,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAIhD,SAAS,CAAC,KAAK,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS;cAI3C,IAAI,CAAC,CAAC,GAAG,OAAO,KAAK,OAAO,CAAC,CAAC,CAAC;IAI/C,SAAS,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAI7C,SAAS,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAIlD,SAAS,CAAC,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,GAAG,IAAI;IAKrE,SAAS,CAAC,OAAO,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,GAAG,QAAQ;IAIvC,SAAS,CAAC,SAAS,IAAI,QAAQ;IAI/B,SAAS,CAAC,QAAQ,CAAC,CAAC,EAAE,IAAI,CAAC,EAAE,CAAC,GAAG,QAAQ;IAIzC,SAAS,CAAC,QAAQ,CAAC,OAAO,GAAE,MAAoB,GAAG,QAAQ;IAI3D,SAAS,CAAC,UAAU,CAAC,OAAO,GAAE,MAAsB,GAAG,QAAQ;IAI/D,SAAS,CAAC,YAAY,CAAC,OAAO,GAAE,MAAuB,GAAG,QAAQ;IAIlE,SAAS,CAAC,SAAS,CAAC,OAAO,GAAE,MAAoB,GAAG,QAAQ;cAI5C,SAAS,CAAC,CAAC,KAAK,OAAO,CAAC,CAAC,CAAC;CAG3C;AAED,eAAe,cAAc,CAAC"}