@carno.js/core 0.2.11 → 1.0.2

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 (314) hide show
  1. package/LICENSE +673 -673
  2. package/README.md +188 -0
  3. package/dist/Carno.js +272 -333
  4. package/dist/Carno.mjs +268 -0
  5. package/dist/DefaultRoutes.js +51 -0
  6. package/dist/DefaultRoutes.mjs +34 -0
  7. package/dist/bun/index.js +183 -0
  8. package/dist/bun/index.js.map +86 -0
  9. package/dist/cache/CacheDriver.js +13 -0
  10. package/dist/cache/CacheDriver.mjs +0 -0
  11. package/dist/cache/CacheService.js +113 -0
  12. package/dist/cache/CacheService.mjs +93 -0
  13. package/dist/cache/MemoryDriver.js +66 -0
  14. package/dist/cache/MemoryDriver.mjs +46 -0
  15. package/dist/cache/RedisDriver.js +81 -0
  16. package/dist/cache/RedisDriver.mjs +61 -0
  17. package/dist/compiler/JITCompiler.js +111 -0
  18. package/dist/compiler/JITCompiler.mjs +89 -0
  19. package/dist/container/Container.js +99 -0
  20. package/dist/container/Container.mjs +78 -0
  21. package/dist/context/Context.js +97 -0
  22. package/dist/context/Context.mjs +77 -0
  23. package/dist/cors/CorsHandler.js +90 -0
  24. package/dist/cors/CorsHandler.mjs +68 -0
  25. package/dist/decorators/Controller.js +42 -0
  26. package/dist/decorators/Controller.mjs +22 -0
  27. package/dist/decorators/Inject.js +30 -0
  28. package/dist/decorators/Inject.mjs +10 -0
  29. package/dist/decorators/Middleware.js +35 -0
  30. package/dist/decorators/Middleware.mjs +15 -0
  31. package/dist/decorators/Service.js +31 -0
  32. package/dist/decorators/Service.mjs +12 -0
  33. package/dist/decorators/methods.js +60 -0
  34. package/dist/decorators/methods.mjs +34 -0
  35. package/dist/decorators/params.js +63 -0
  36. package/dist/decorators/params.mjs +37 -0
  37. package/dist/events/Lifecycle.js +69 -0
  38. package/dist/events/Lifecycle.mjs +41 -0
  39. package/dist/exceptions/HttpException.js +112 -26
  40. package/dist/exceptions/HttpException.mjs +82 -0
  41. package/dist/index.js +129 -31
  42. package/dist/index.mjs +94 -0
  43. package/dist/metadata.js +34 -0
  44. package/dist/metadata.mjs +9 -0
  45. package/dist/middleware/CarnoMiddleware.js +13 -0
  46. package/dist/middleware/CarnoMiddleware.mjs +0 -0
  47. package/dist/router/RadixRouter.js +121 -0
  48. package/dist/router/RadixRouter.mjs +101 -0
  49. package/dist/testing/TestHarness.js +81 -0
  50. package/dist/testing/TestHarness.mjs +60 -0
  51. package/dist/utils/Metadata.js +53 -0
  52. package/dist/utils/Metadata.mjs +31 -0
  53. package/dist/validation/ValibotAdapter.js +67 -0
  54. package/dist/validation/ValibotAdapter.mjs +48 -0
  55. package/dist/validation/ValidatorAdapter.js +35 -19
  56. package/dist/validation/ValidatorAdapter.mjs +14 -0
  57. package/dist/validation/ZodAdapter.js +80 -0
  58. package/dist/validation/ZodAdapter.mjs +59 -0
  59. package/package.json +21 -63
  60. package/src/Carno.ts +605 -0
  61. package/src/DefaultRoutes.ts +34 -0
  62. package/src/cache/CacheDriver.ts +50 -0
  63. package/src/cache/CacheService.ts +139 -0
  64. package/src/cache/MemoryDriver.ts +104 -0
  65. package/src/cache/RedisDriver.ts +116 -0
  66. package/src/compiler/JITCompiler.ts +167 -0
  67. package/src/container/Container.ts +168 -0
  68. package/src/context/Context.ts +128 -0
  69. package/src/cors/CorsHandler.ts +145 -0
  70. package/src/decorators/Controller.ts +63 -0
  71. package/src/decorators/Inject.ts +16 -0
  72. package/src/decorators/Middleware.ts +22 -0
  73. package/src/decorators/Service.ts +18 -0
  74. package/src/decorators/methods.ts +58 -0
  75. package/src/decorators/params.ts +47 -0
  76. package/src/events/Lifecycle.ts +97 -0
  77. package/src/exceptions/HttpException.ts +99 -0
  78. package/src/index.ts +92 -0
  79. package/src/metadata.ts +46 -0
  80. package/src/middleware/CarnoMiddleware.ts +14 -0
  81. package/src/router/RadixRouter.ts +225 -0
  82. package/src/testing/TestHarness.ts +177 -0
  83. package/src/utils/Metadata.ts +43 -0
  84. package/src/validation/ValibotAdapter.ts +95 -0
  85. package/src/validation/ValidatorAdapter.ts +69 -0
  86. package/src/validation/ZodAdapter.ts +102 -0
  87. package/dist/Carno.d.ts +0 -75
  88. package/dist/cache/bento-cache.driver.d.ts +0 -13
  89. package/dist/cache/bento-cache.driver.js +0 -55
  90. package/dist/cache/cache.service.d.ts +0 -8
  91. package/dist/cache/cache.service.js +0 -6
  92. package/dist/commons/decorators/Injectable.decorator.d.ts +0 -20
  93. package/dist/commons/decorators/Injectable.decorator.js +0 -33
  94. package/dist/commons/decorators/controller.decorator.d.ts +0 -8
  95. package/dist/commons/decorators/controller.decorator.js +0 -22
  96. package/dist/commons/decorators/http.decorators.d.ts +0 -13
  97. package/dist/commons/decorators/http.decorators.js +0 -63
  98. package/dist/commons/decorators/index.d.ts +0 -6
  99. package/dist/commons/decorators/index.js +0 -22
  100. package/dist/commons/decorators/inject.decorator.d.ts +0 -1
  101. package/dist/commons/decorators/inject.decorator.js +0 -5
  102. package/dist/commons/decorators/middleware.decorator.d.ts +0 -2
  103. package/dist/commons/decorators/middleware.decorator.js +0 -30
  104. package/dist/commons/decorators/service.decorator.d.ts +0 -2
  105. package/dist/commons/decorators/service.decorator.js +0 -7
  106. package/dist/commons/decorators/validation.decorator.d.ts +0 -32
  107. package/dist/commons/decorators/validation.decorator.js +0 -40
  108. package/dist/commons/http-code.enum.d.ts +0 -50
  109. package/dist/commons/http-code.enum.js +0 -54
  110. package/dist/commons/index.d.ts +0 -3
  111. package/dist/commons/index.js +0 -19
  112. package/dist/commons/registries/ProviderControl.d.ts +0 -77
  113. package/dist/commons/registries/ProviderControl.js +0 -112
  114. package/dist/commons/registries/ProviderRegistry.d.ts +0 -7
  115. package/dist/commons/registries/ProviderRegistry.js +0 -20
  116. package/dist/constants.d.ts +0 -8
  117. package/dist/constants.js +0 -11
  118. package/dist/container/ContainerConfiguration.d.ts +0 -45
  119. package/dist/container/ContainerConfiguration.js +0 -121
  120. package/dist/container/DependencyResolver.d.ts +0 -20
  121. package/dist/container/DependencyResolver.js +0 -85
  122. package/dist/container/InjectorService.d.ts +0 -58
  123. package/dist/container/InjectorService.js +0 -286
  124. package/dist/container/MethodInvoker.d.ts +0 -21
  125. package/dist/container/MethodInvoker.js +0 -83
  126. package/dist/container/RouteResolver.d.ts +0 -27
  127. package/dist/container/RouteResolver.js +0 -173
  128. package/dist/container/container.d.ts +0 -41
  129. package/dist/container/container.js +0 -71
  130. package/dist/container/createContainer.d.ts +0 -3
  131. package/dist/container/createContainer.js +0 -12
  132. package/dist/container/createInjector.d.ts +0 -2
  133. package/dist/container/createInjector.js +0 -7
  134. package/dist/container/index.d.ts +0 -6
  135. package/dist/container/index.js +0 -22
  136. package/dist/container/middleware.resolver.d.ts +0 -9
  137. package/dist/container/middleware.resolver.js +0 -35
  138. package/dist/default-routes-carno.d.ts +0 -3
  139. package/dist/default-routes-carno.js +0 -29
  140. package/dist/domain/BaseContext.d.ts +0 -15
  141. package/dist/domain/BaseContext.js +0 -2
  142. package/dist/domain/CarnoClosure.d.ts +0 -1
  143. package/dist/domain/CarnoClosure.js +0 -2
  144. package/dist/domain/CarnoMiddleware.d.ts +0 -5
  145. package/dist/domain/CarnoMiddleware.js +0 -2
  146. package/dist/domain/Context.d.ts +0 -58
  147. package/dist/domain/Context.js +0 -188
  148. package/dist/domain/FastContext.d.ts +0 -34
  149. package/dist/domain/FastContext.js +0 -59
  150. package/dist/domain/LocalsContainer.d.ts +0 -4
  151. package/dist/domain/LocalsContainer.js +0 -10
  152. package/dist/domain/Metadata.d.ts +0 -449
  153. package/dist/domain/Metadata.js +0 -511
  154. package/dist/domain/cors-config.d.ts +0 -12
  155. package/dist/domain/cors-config.js +0 -18
  156. package/dist/domain/cors-headers-cache.d.ts +0 -17
  157. package/dist/domain/cors-headers-cache.js +0 -101
  158. package/dist/domain/http-method.d.ts +0 -7
  159. package/dist/domain/http-method.js +0 -11
  160. package/dist/domain/index.d.ts +0 -10
  161. package/dist/domain/index.js +0 -26
  162. package/dist/domain/provider-scope.d.ts +0 -5
  163. package/dist/domain/provider-scope.js +0 -9
  164. package/dist/domain/provider-type.d.ts +0 -6
  165. package/dist/domain/provider-type.js +0 -10
  166. package/dist/domain/provider.d.ts +0 -37
  167. package/dist/domain/provider.js +0 -70
  168. package/dist/events/hooks.decorator.d.ts +0 -3
  169. package/dist/events/hooks.decorator.js +0 -29
  170. package/dist/events/index.d.ts +0 -2
  171. package/dist/events/index.js +0 -18
  172. package/dist/events/on-event.d.ts +0 -13
  173. package/dist/events/on-event.js +0 -11
  174. package/dist/exceptions/HttpException.d.ts +0 -9
  175. package/dist/exceptions/index.d.ts +0 -1
  176. package/dist/exceptions/index.js +0 -17
  177. package/dist/index.d.ts +0 -16
  178. package/dist/route/CompiledRoute.d.ts +0 -23
  179. package/dist/route/CompiledRoute.js +0 -9
  180. package/dist/route/FastPathExecutor.d.ts +0 -12
  181. package/dist/route/FastPathExecutor.js +0 -50
  182. package/dist/route/JITCompiler.d.ts +0 -28
  183. package/dist/route/JITCompiler.js +0 -245
  184. package/dist/route/Matcher.d.ts +0 -11
  185. package/dist/route/Matcher.js +0 -48
  186. package/dist/route/ParamResolverFactory.d.ts +0 -14
  187. package/dist/route/ParamResolverFactory.js +0 -49
  188. package/dist/route/RouteCompiler.d.ts +0 -28
  189. package/dist/route/RouteCompiler.js +0 -157
  190. package/dist/route/RouteExecutor.d.ts +0 -12
  191. package/dist/route/RouteExecutor.js +0 -84
  192. package/dist/route/memoirist.d.ts +0 -31
  193. package/dist/route/memoirist.js +0 -373
  194. package/dist/services/logger.service.d.ts +0 -23
  195. package/dist/services/logger.service.js +0 -47
  196. package/dist/testing/core-testing.d.ts +0 -24
  197. package/dist/testing/core-testing.js +0 -102
  198. package/dist/testing/index.d.ts +0 -1
  199. package/dist/testing/index.js +0 -17
  200. package/dist/utils/ValidationCache.d.ts +0 -5
  201. package/dist/utils/ValidationCache.js +0 -35
  202. package/dist/utils/ancestorOf.d.ts +0 -2
  203. package/dist/utils/ancestorOf.js +0 -10
  204. package/dist/utils/ancestorsOf.d.ts +0 -6
  205. package/dist/utils/ancestorsOf.js +0 -20
  206. package/dist/utils/classOf.d.ts +0 -13
  207. package/dist/utils/classOf.js +0 -21
  208. package/dist/utils/cleanObject.d.ts +0 -6
  209. package/dist/utils/cleanObject.js +0 -22
  210. package/dist/utils/constructorOf.d.ts +0 -11
  211. package/dist/utils/constructorOf.js +0 -18
  212. package/dist/utils/createInstance.d.ts +0 -1
  213. package/dist/utils/createInstance.js +0 -7
  214. package/dist/utils/decoratorTypeOf.d.ts +0 -11
  215. package/dist/utils/decoratorTypeOf.js +0 -32
  216. package/dist/utils/deepClone.d.ts +0 -6
  217. package/dist/utils/deepClone.js +0 -63
  218. package/dist/utils/deepMerge.d.ts +0 -9
  219. package/dist/utils/deepMerge.js +0 -62
  220. package/dist/utils/descriptorOf.d.ts +0 -8
  221. package/dist/utils/descriptorOf.js +0 -16
  222. package/dist/utils/formatValidationErrors.d.ts +0 -5
  223. package/dist/utils/formatValidationErrors.js +0 -80
  224. package/dist/utils/getClassOrSymbol.d.ts +0 -1
  225. package/dist/utils/getClassOrSymbol.js +0 -8
  226. package/dist/utils/getConstructorArgNames.d.ts +0 -1
  227. package/dist/utils/getConstructorArgNames.js +0 -12
  228. package/dist/utils/getMethodArgTypes.d.ts +0 -1
  229. package/dist/utils/getMethodArgTypes.js +0 -9
  230. package/dist/utils/getValue.d.ts +0 -32
  231. package/dist/utils/getValue.js +0 -47
  232. package/dist/utils/hasJsonMethod.d.ts +0 -1
  233. package/dist/utils/hasJsonMethod.js +0 -6
  234. package/dist/utils/index.d.ts +0 -15
  235. package/dist/utils/index.js +0 -31
  236. package/dist/utils/isArray.d.ts +0 -13
  237. package/dist/utils/isArray.js +0 -21
  238. package/dist/utils/isArrowFn.d.ts +0 -1
  239. package/dist/utils/isArrowFn.js +0 -7
  240. package/dist/utils/isBoolean.d.ts +0 -7
  241. package/dist/utils/isBoolean.js +0 -15
  242. package/dist/utils/isBuffer.d.ts +0 -7
  243. package/dist/utils/isBuffer.js +0 -19
  244. package/dist/utils/isClass.d.ts +0 -1
  245. package/dist/utils/isClass.js +0 -26
  246. package/dist/utils/isCollection.d.ts +0 -6
  247. package/dist/utils/isCollection.js +0 -20
  248. package/dist/utils/isDate.d.ts +0 -6
  249. package/dist/utils/isDate.js +0 -11
  250. package/dist/utils/isEmpty.d.ts +0 -6
  251. package/dist/utils/isEmpty.js +0 -12
  252. package/dist/utils/isFunction.d.ts +0 -1
  253. package/dist/utils/isFunction.js +0 -6
  254. package/dist/utils/isInheritedFrom.d.ts +0 -1
  255. package/dist/utils/isInheritedFrom.js +0 -24
  256. package/dist/utils/isMomentObject.d.ts +0 -1
  257. package/dist/utils/isMomentObject.js +0 -6
  258. package/dist/utils/isMongooseObject.d.ts +0 -2
  259. package/dist/utils/isMongooseObject.js +0 -11
  260. package/dist/utils/isNil.d.ts +0 -1
  261. package/dist/utils/isNil.js +0 -6
  262. package/dist/utils/isNumber.d.ts +0 -7
  263. package/dist/utils/isNumber.js +0 -15
  264. package/dist/utils/isObject.d.ts +0 -1
  265. package/dist/utils/isObject.js +0 -6
  266. package/dist/utils/isObservable.d.ts +0 -1
  267. package/dist/utils/isObservable.js +0 -6
  268. package/dist/utils/isPlainObject.d.ts +0 -7
  269. package/dist/utils/isPlainObject.js +0 -16
  270. package/dist/utils/isPrimitive.d.ts +0 -14
  271. package/dist/utils/isPrimitive.js +0 -28
  272. package/dist/utils/isPrimitiveType.d.ts +0 -1
  273. package/dist/utils/isPrimitiveType.js +0 -11
  274. package/dist/utils/isPromise.d.ts +0 -7
  275. package/dist/utils/isPromise.js +0 -14
  276. package/dist/utils/isProtectedKey.d.ts +0 -5
  277. package/dist/utils/isProtectedKey.js +0 -10
  278. package/dist/utils/isRegExp.d.ts +0 -1
  279. package/dist/utils/isRegExp.js +0 -6
  280. package/dist/utils/isRequestScope.d.ts +0 -11
  281. package/dist/utils/isRequestScope.js +0 -23
  282. package/dist/utils/isSerializable.d.ts +0 -1
  283. package/dist/utils/isSerializable.js +0 -11
  284. package/dist/utils/isStream.d.ts +0 -1
  285. package/dist/utils/isStream.js +0 -6
  286. package/dist/utils/isString.d.ts +0 -6
  287. package/dist/utils/isString.js +0 -14
  288. package/dist/utils/isSymbol.d.ts +0 -6
  289. package/dist/utils/isSymbol.js +0 -14
  290. package/dist/utils/methodsOf.d.ts +0 -9
  291. package/dist/utils/methodsOf.js +0 -24
  292. package/dist/utils/nameOf.d.ts +0 -14
  293. package/dist/utils/nameOf.js +0 -31
  294. package/dist/utils/objectKeys.d.ts +0 -1
  295. package/dist/utils/objectKeys.js +0 -7
  296. package/dist/utils/primitiveOf.d.ts +0 -1
  297. package/dist/utils/primitiveOf.js +0 -18
  298. package/dist/utils/prototypeOf.d.ts +0 -6
  299. package/dist/utils/prototypeOf.js +0 -12
  300. package/dist/utils/setValue.d.ts +0 -1
  301. package/dist/utils/setValue.js +0 -32
  302. package/dist/utils/toMap.d.ts +0 -3
  303. package/dist/utils/toMap.js +0 -34
  304. package/dist/utils/toStringConstructor.d.ts +0 -1
  305. package/dist/utils/toStringConstructor.js +0 -10
  306. package/dist/validation/ValidatorAdapter.d.ts +0 -66
  307. package/dist/validation/adapters/ClassValidatorAdapter.d.ts +0 -23
  308. package/dist/validation/adapters/ClassValidatorAdapter.js +0 -47
  309. package/dist/validation/adapters/ZodAdapter.d.ts +0 -14
  310. package/dist/validation/adapters/ZodAdapter.js +0 -56
  311. package/dist/validation/adapters/index.d.ts +0 -4
  312. package/dist/validation/adapters/index.js +0 -7
  313. package/dist/validation/index.d.ts +0 -3
  314. package/dist/validation/index.js +0 -20
package/src/Carno.ts ADDED
@@ -0,0 +1,605 @@
1
+ import 'reflect-metadata';
2
+
3
+ import { CONTROLLER_META, ROUTES_META, PARAMS_META, MIDDLEWARE_META } from './metadata';
4
+ import type { RouteInfo, MiddlewareInfo, ControllerMeta } from './metadata';
5
+ import type { ParamMetadata } from './decorators/params';
6
+ // RadixRouter removed - using Bun's native SIMD-accelerated router
7
+ import { compileHandler } from './compiler/JITCompiler';
8
+ import { Context } from './context/Context';
9
+ import { Container, Scope } from './container/Container';
10
+ import type { Token, ProviderConfig } from './container/Container';
11
+ import { CorsHandler, type CorsConfig } from './cors/CorsHandler';
12
+ import type { ValidatorAdapter } from './validation/ValidatorAdapter';
13
+ import { HttpException } from './exceptions/HttpException';
14
+ import { ValidationException } from './validation/ZodAdapter';
15
+ import { EventType, hasEventHandlers, getEventHandlers } from './events/Lifecycle';
16
+ import { CacheService } from './cache/CacheService';
17
+ import type { CacheConfig } from './cache/CacheDriver';
18
+ import { DEFAULT_STATIC_ROUTES } from './DefaultRoutes';
19
+ import { ZodAdapter } from './validation/ZodAdapter';
20
+ import type { CarnoMiddleware } from './middleware/CarnoMiddleware';
21
+
22
+ export type MiddlewareHandler = (ctx: Context) => Response | void | Promise<Response | void>;
23
+
24
+ /**
25
+ * Carno plugin configuration.
26
+ */
27
+ export interface CarnoConfig {
28
+ exports?: (Token | ProviderConfig)[];
29
+ globalMiddlewares?: MiddlewareHandler[];
30
+ disableStartupLog?: boolean;
31
+ cors?: CorsConfig;
32
+ validation?: ValidatorAdapter | boolean | (new (...args: any[]) => ValidatorAdapter);
33
+ cache?: CacheConfig | boolean;
34
+ }
35
+
36
+ // CompiledRoute removed - handlers are registered directly in Bun's routes
37
+
38
+ const NOT_FOUND_RESPONSE = new Response('Not Found', { status: 404 });
39
+
40
+ /**
41
+ * Pre-computed response - frozen and reused.
42
+ */
43
+ const TEXT_OPTS = Object.freeze({
44
+ status: 200,
45
+ headers: { 'Content-Type': 'text/plain' }
46
+ });
47
+
48
+ const JSON_OPTS = Object.freeze({
49
+ status: 200,
50
+ headers: { 'Content-Type': 'application/json' }
51
+ });
52
+
53
+ const INTERNAL_ERROR_RESPONSE = new Response(
54
+ '{"statusCode":500,"message":"Internal Server Error"}',
55
+ { status: 500, headers: { 'Content-Type': 'application/json' } }
56
+ );
57
+
58
+ // METHOD_MAP removed - Bun handles method routing natively
59
+
60
+ /**
61
+ * Carno Application - Ultra-aggressive performance.
62
+ *
63
+ * ZERO runtime work in hot path:
64
+ * - All responses pre-created at startup
65
+ * - Direct Bun native routes - no fetch fallback needed
66
+ * - No function calls in hot path
67
+ */
68
+ export class Carno {
69
+ private _controllers: (new (...args: any[]) => any)[] = [];
70
+ private _services: (Token | ProviderConfig)[] = [];
71
+ private _middlewares: MiddlewareHandler[] = [];
72
+ private routes: Record<string, Record<string, Response | Function> | Response | Function> = {};
73
+ private container = new Container();
74
+ private corsHandler: CorsHandler | null = null;
75
+ private hasCors = false;
76
+ private validator: ValidatorAdapter | null = null;
77
+ private server: any;
78
+
79
+ // Cached lifecycle event flags - checked once at startup
80
+ private hasInitHooks = false;
81
+ private hasBootHooks = false;
82
+ private hasShutdownHooks = false;
83
+
84
+ constructor(public config: CarnoConfig = {}) {
85
+ this.config.exports = this.config.exports || [];
86
+ this.config.globalMiddlewares = this.config.globalMiddlewares || [];
87
+
88
+ // Initialize CORS handler if configured
89
+ if (this.config.cors) {
90
+ this.corsHandler = new CorsHandler(this.config.cors);
91
+ this.hasCors = true;
92
+ }
93
+
94
+ // Initialize validator
95
+ // Default: ZodAdapter if undefined or true
96
+ if (this.config.validation === undefined || this.config.validation === true) {
97
+ this.validator = new ZodAdapter();
98
+ }
99
+ // Constructor class passed directly
100
+ else if (typeof this.config.validation === 'function') {
101
+ const AdapterClass = this.config.validation as (new (...args: any[]) => ValidatorAdapter);
102
+ this.validator = new AdapterClass();
103
+ }
104
+ // Instance passed directly
105
+ else if (this.config.validation) {
106
+ this.validator = this.config.validation as ValidatorAdapter;
107
+ }
108
+ }
109
+
110
+ /**
111
+ * Use a Carno plugin.
112
+ * Imports controllers, services and global middlewares from another Carno instance.
113
+ */
114
+ use(plugin: Carno): this {
115
+ // Import controllers from plugin
116
+ if (plugin._controllers.length > 0) {
117
+ this._controllers.push(...plugin._controllers);
118
+ }
119
+
120
+ // Import services from plugin exports
121
+ for (const exported of plugin.config.exports || []) {
122
+ const existingService = this.findServiceInPlugin(plugin, exported);
123
+ const serviceToAdd = this.shouldCloneService(existingService)
124
+ ? { ...existingService }
125
+ : exported;
126
+
127
+ this._services.push(serviceToAdd);
128
+ }
129
+
130
+ // Import services registered via .services() on the plugin
131
+ if (plugin._services.length > 0) {
132
+ this._services.push(...plugin._services);
133
+ }
134
+
135
+ // Import global middlewares
136
+ if (plugin.config.globalMiddlewares) {
137
+ this._middlewares.push(...plugin.config.globalMiddlewares);
138
+ }
139
+
140
+ // Import middlewares registered via .middlewares() on the plugin
141
+ if (plugin._middlewares.length > 0) {
142
+ this._middlewares.push(...plugin._middlewares);
143
+ }
144
+
145
+ return this;
146
+ }
147
+
148
+ private findServiceInPlugin(plugin: Carno, exported: any): any | undefined {
149
+ return plugin._services.find(
150
+ s => this.getServiceToken(s) === this.getServiceToken(exported)
151
+ );
152
+ }
153
+
154
+ private getServiceToken(service: any): any {
155
+ return service?.token || service;
156
+ }
157
+
158
+ private shouldCloneService(service: any): boolean {
159
+ return !!(service?.useValue !== undefined || service?.useClass);
160
+ }
161
+
162
+ /**
163
+ * Register one or more services/providers.
164
+ */
165
+ services(serviceClass: Token | ProviderConfig | (Token | ProviderConfig)[]): this {
166
+ const items = Array.isArray(serviceClass) ? serviceClass : [serviceClass];
167
+ this._services.push(...items);
168
+ return this;
169
+ }
170
+
171
+ /**
172
+ * Register one or more global middlewares.
173
+ */
174
+ middlewares(handler: MiddlewareHandler | MiddlewareHandler[]): this {
175
+ const items = Array.isArray(handler) ? handler : [handler];
176
+ this._middlewares.push(...items);
177
+ return this;
178
+ }
179
+
180
+ /**
181
+ * Register one or more controllers.
182
+ */
183
+ controllers(controllerClass: (new (...args: any[]) => any) | (new (...args: any[]) => any)[]): this {
184
+ const items = Array.isArray(controllerClass) ? controllerClass : [controllerClass];
185
+ this._controllers.push(...items);
186
+ return this;
187
+ }
188
+
189
+ /**
190
+ * Get a service instance from the container.
191
+ */
192
+ get<T>(token: Token<T>): T {
193
+ return this.container.get(token);
194
+ }
195
+
196
+ listen(port: number = 3000): void {
197
+ this.bootstrap();
198
+ this.compileRoutes();
199
+
200
+ // All routes go through Bun's native SIMD-accelerated router
201
+ const config: any = {
202
+ port,
203
+ fetch: this.handleNotFound.bind(this),
204
+ error: this.handleError.bind(this),
205
+ routes: {
206
+ ...DEFAULT_STATIC_ROUTES,
207
+ ...this.routes
208
+ }
209
+ };
210
+
211
+ this.server = Bun.serve(config);
212
+
213
+ // Execute BOOT hooks after server is ready
214
+ if (this.hasBootHooks) {
215
+ this.executeLifecycleHooks(EventType.BOOT);
216
+ }
217
+
218
+ // Register shutdown handlers
219
+ if (this.hasShutdownHooks) {
220
+ this.registerShutdownHandlers();
221
+ }
222
+
223
+ if (!this.config.disableStartupLog) {
224
+ console.log(`Carno running on port ${port}`);
225
+ }
226
+ }
227
+
228
+ private bootstrap(): void {
229
+ // Cache lifecycle event flags
230
+ this.hasInitHooks = hasEventHandlers(EventType.INIT);
231
+ this.hasBootHooks = hasEventHandlers(EventType.BOOT);
232
+ this.hasShutdownHooks = hasEventHandlers(EventType.SHUTDOWN);
233
+
234
+ // Register Container itself so it can be injected
235
+ this.container.register({
236
+ token: Container,
237
+ useValue: this.container
238
+ });
239
+
240
+ // Always register CacheService (Memory by default)
241
+ const cacheConfig = typeof this.config.cache === 'object' ? this.config.cache : {};
242
+ this.container.register({
243
+ token: CacheService,
244
+ useValue: new CacheService(cacheConfig)
245
+ });
246
+
247
+ for (const service of this._services) {
248
+ this.container.register(service);
249
+ }
250
+
251
+ for (const ControllerClass of this._controllers) {
252
+ this.container.register(ControllerClass);
253
+ }
254
+
255
+ if (this.hasInitHooks) {
256
+ this.executeLifecycleHooks(EventType.INIT);
257
+ }
258
+
259
+ for (const service of this._services) {
260
+ const token = typeof service === 'function' ? service : service.token;
261
+ const serviceConfig = typeof service === 'function' ? null : service;
262
+
263
+ if (!serviceConfig || serviceConfig.scope !== Scope.REQUEST) {
264
+ this.container.get(token);
265
+ }
266
+ }
267
+ }
268
+
269
+ private compileRoutes(): void {
270
+ for (const ControllerClass of this._controllers) {
271
+ this.compileController(ControllerClass);
272
+ }
273
+ }
274
+
275
+ private compileController(
276
+ ControllerClass: new (...args: any[]) => any,
277
+ parentPath: string = '',
278
+ inheritedMiddlewares: MiddlewareHandler[] = []
279
+ ): void {
280
+ const meta: ControllerMeta = Reflect.getMetadata(CONTROLLER_META, ControllerClass) || { path: '' };
281
+ const basePath = parentPath + (meta.path || '');
282
+ const routes: RouteInfo[] = Reflect.getMetadata(ROUTES_META, ControllerClass) || [];
283
+ const middlewares: MiddlewareInfo[] = Reflect.getMetadata(MIDDLEWARE_META, ControllerClass) || [];
284
+ const instance = this.container.get(ControllerClass);
285
+
286
+ // Extract controller-level middlewares (applied to all routes of this controller)
287
+ const controllerMiddlewares = middlewares
288
+ .filter(m => !m.target)
289
+ .map(m => m.handler as MiddlewareHandler);
290
+
291
+ // Combine inherited middlewares with this controller's middlewares
292
+ // This combined list is passed down to children and applied to current routes
293
+ const scopedMiddlewares = [...inheritedMiddlewares, ...controllerMiddlewares];
294
+
295
+ for (const route of routes) {
296
+ const fullPath = this.normalizePath(basePath + route.path);
297
+ const params: ParamMetadata[] = Reflect.getMetadata(PARAMS_META, ControllerClass, route.handlerName) || [];
298
+
299
+ // Middlewares specific to this route handler
300
+ const routeMiddlewares = middlewares
301
+ .filter(m => m.target === route.handlerName)
302
+ .map(m => m.handler as MiddlewareHandler);
303
+
304
+ // Get parameter types for validation
305
+ const paramTypes: any[] = Reflect.getMetadata('design:paramtypes', ControllerClass.prototype, route.handlerName) || [];
306
+
307
+ // Find Body param with DTO that has @Schema for validation
308
+ let bodyDtoType: any = null;
309
+ for (const param of params) {
310
+ if (param.type === 'body' && !param.key) {
311
+ const dtoType = paramTypes[param.index];
312
+ if (dtoType && this.validator?.hasValidation(dtoType)) {
313
+ bodyDtoType = dtoType;
314
+ }
315
+ }
316
+ }
317
+
318
+ const compiled = compileHandler(instance, route.handlerName, params);
319
+
320
+ const allMiddlewares = [
321
+ ...(this.config.globalMiddlewares || []),
322
+ ...this._middlewares,
323
+ ...scopedMiddlewares,
324
+ ...routeMiddlewares
325
+ ];
326
+
327
+ // Pre-resolve class-based middlewares at compile time for maximum performance
328
+ const resolvedMiddlewares = allMiddlewares.map(m => this.resolveMiddleware(m));
329
+
330
+ const hasMiddlewares = resolvedMiddlewares.length > 0;
331
+
332
+ const method = route.method.toUpperCase();
333
+
334
+ // Static response - no function needed
335
+ if (compiled.isStatic && !hasMiddlewares) {
336
+ this.registerRoute(fullPath, method, this.createStaticResponse(compiled.staticValue));
337
+ } else {
338
+ // Dynamic handler - compile to Bun-compatible function
339
+ this.registerRoute(fullPath, method, this.createHandler(compiled, params, resolvedMiddlewares, bodyDtoType));
340
+ }
341
+ }
342
+
343
+ // Compile child controllers with parent path and inherited middlewares
344
+ if (meta.children) {
345
+ for (const ChildController of meta.children) {
346
+ if (!this.container.has(ChildController)) {
347
+ this.container.register(ChildController);
348
+ }
349
+
350
+ this.compileController(ChildController, basePath, scopedMiddlewares);
351
+ }
352
+ }
353
+ }
354
+
355
+ /**
356
+ * Register a route with Bun's native router format.
357
+ * Path: "/users/:id", Method: "GET", Handler: Function or Response
358
+ */
359
+ private registerRoute(path: string, method: string, handler: Response | Function): void {
360
+ if (!this.routes[path]) {
361
+ this.routes[path] = {};
362
+ }
363
+
364
+ (this.routes[path] as Record<string, Response | Function>)[method] = handler;
365
+ }
366
+
367
+ private createStaticResponse(value: any): Response {
368
+ const isString = typeof value === 'string';
369
+ const body = isString ? value : JSON.stringify(value);
370
+ const opts = isString ? TEXT_OPTS : JSON_OPTS;
371
+
372
+ return new Response(body, opts);
373
+ }
374
+
375
+ private createHandler(
376
+ compiled: { fn: Function; isAsync: boolean },
377
+ params: ParamMetadata[],
378
+ middlewares: MiddlewareHandler[],
379
+ bodyDtoType?: any
380
+ ): Function {
381
+ const handler = compiled.fn;
382
+ const hasMiddlewares = middlewares.length > 0;
383
+ const hasParams = params.length > 0;
384
+ const applyCors = this.hasCors ? this.applyCors.bind(this) : null;
385
+ const validator = bodyDtoType ? this.validator : null;
386
+ const needsValidation = !!validator;
387
+
388
+ // Force middleware path when validation is needed
389
+ const hasMiddlewaresOrValidation = hasMiddlewares || needsValidation;
390
+
391
+ // No middlewares, no params - fastest path
392
+ if (!hasMiddlewaresOrValidation && !hasParams) {
393
+ if (compiled.isAsync) {
394
+ return async (req: Request) => {
395
+ const ctx = new Context(req);
396
+ const result = await handler(ctx);
397
+ const response = this.buildResponse(result);
398
+
399
+ return applyCors ? applyCors(response, req) : response;
400
+ };
401
+ }
402
+
403
+ return (req: Request) => {
404
+ const ctx = new Context(req);
405
+ const result = handler(ctx);
406
+ const response = this.buildResponse(result);
407
+
408
+ return applyCors ? applyCors(response, req) : response;
409
+ };
410
+ }
411
+
412
+ // With params - use Bun's native req.params
413
+ if (!hasMiddlewaresOrValidation && hasParams) {
414
+ if (compiled.isAsync) {
415
+ return async (req: Request) => {
416
+ const ctx = new Context(req, (req as any).params);
417
+ const result = await handler(ctx);
418
+ const response = this.buildResponse(result);
419
+
420
+ return applyCors ? applyCors(response, req) : response;
421
+ };
422
+ }
423
+
424
+ return (req: Request) => {
425
+ const ctx = new Context(req, (req as any).params);
426
+ const result = handler(ctx);
427
+ const response = this.buildResponse(result);
428
+
429
+ return applyCors ? applyCors(response, req) : response;
430
+ };
431
+ }
432
+
433
+ // With middlewares - full pipeline
434
+ return async (req: Request) => {
435
+ const ctx = new Context(req, (req as any).params || {});
436
+
437
+ for (const middleware of middlewares) {
438
+ const result = await middleware(ctx);
439
+
440
+ if (result instanceof Response) {
441
+ return applyCors ? applyCors(result, req) : result;
442
+ }
443
+ }
444
+
445
+ // Validate body if validator is configured
446
+ if (validator && bodyDtoType) {
447
+ await ctx.parseBody();
448
+ validator.validateOrThrow(bodyDtoType, ctx.body);
449
+ }
450
+
451
+ const result = compiled.isAsync
452
+ ? await handler(ctx)
453
+ : handler(ctx);
454
+
455
+ const response = this.buildResponse(result);
456
+
457
+ return applyCors ? applyCors(response, req) : response;
458
+ };
459
+ }
460
+
461
+ private resolveMiddleware(middleware: any): MiddlewareHandler {
462
+ // Check if it's a class with a handle method
463
+ if (typeof middleware === 'function' && middleware.prototype?.handle) {
464
+ // Instantiate via Container and bind the handle method
465
+ const instance = this.container.get(middleware) as CarnoMiddleware;
466
+ return (ctx: Context) => instance.handle(ctx, () => { });
467
+ }
468
+
469
+ // Already a function
470
+ return middleware;
471
+ }
472
+
473
+ /**
474
+ * Apply CORS headers to a response.
475
+ */
476
+ private applyCors(response: Response, req: Request): Response {
477
+ const origin = req.headers.get('origin');
478
+
479
+ if (origin && this.corsHandler) {
480
+ return this.corsHandler.apply(response, origin);
481
+ }
482
+
483
+ return response;
484
+ }
485
+
486
+ /**
487
+ * Fallback handler - only called for unmatched routes.
488
+ * All matched routes go through Bun's native router.
489
+ */
490
+ private handleNotFound(req: Request): Response {
491
+ // CORS preflight for unmatched routes
492
+ if (this.hasCors && req.method === 'OPTIONS') {
493
+ const origin = req.headers.get('origin');
494
+
495
+ if (origin) {
496
+ return this.corsHandler!.preflight(origin);
497
+ }
498
+ }
499
+
500
+ return NOT_FOUND_RESPONSE;
501
+ }
502
+
503
+ private buildResponse(result: any): Response {
504
+ if (result instanceof Response) {
505
+ return result;
506
+ }
507
+
508
+ if (typeof result === 'string') {
509
+ return new Response(result, TEXT_OPTS);
510
+ }
511
+
512
+ // Handle undefined/void return values - return empty 204 No Content
513
+ if (result === undefined) {
514
+ return new Response(null, { status: 204 });
515
+ }
516
+
517
+ return Response.json(result);
518
+ }
519
+
520
+ private normalizePath(path: string): string {
521
+ if (!path.startsWith('/')) path = '/' + path;
522
+ if (path !== '/' && path.endsWith('/')) path = path.slice(0, -1);
523
+
524
+ return path.replace(/\/+/g, '/');
525
+ }
526
+
527
+ private hasParams(path: string): boolean {
528
+ return path.includes(':') || path.includes('*');
529
+ }
530
+
531
+ stop(): void {
532
+ this.server?.stop?.();
533
+ }
534
+
535
+ /**
536
+ * Error handler for Bun.serve.
537
+ * Converts exceptions to proper HTTP responses.
538
+ */
539
+ private handleError(error: Error): Response {
540
+ let response: Response;
541
+
542
+ // HttpException - return custom response
543
+ if (error instanceof HttpException) {
544
+ response = error.toResponse();
545
+ }
546
+ // ValidationException - return 400 with errors
547
+ else if (error instanceof ValidationException) {
548
+ response = error.toResponse();
549
+ }
550
+ // Unknown error - return 500
551
+ else {
552
+ console.error('Unhandled error:', error);
553
+ response = INTERNAL_ERROR_RESPONSE;
554
+ }
555
+
556
+ // Apply CORS headers if configured
557
+ if (this.hasCors && this.corsHandler) {
558
+ return this.corsHandler.apply(response, '*');
559
+ }
560
+
561
+ return response;
562
+ }
563
+
564
+ /**
565
+ * Execute lifecycle hooks for a specific event type.
566
+ */
567
+ private executeLifecycleHooks(type: EventType): void {
568
+ const handlers = getEventHandlers(type);
569
+
570
+ for (const handler of handlers) {
571
+ try {
572
+ const instance = this.container.has(handler.target)
573
+ ? this.container.get(handler.target)
574
+ : null;
575
+
576
+ if (instance && typeof (instance as any)[handler.methodName] === 'function') {
577
+ const result = (instance as any)[handler.methodName]();
578
+
579
+ // Handle async hooks
580
+ if (result instanceof Promise) {
581
+ result.catch((err: Error) =>
582
+ console.error(`Error in ${type} hook ${handler.methodName}:`, err)
583
+ );
584
+ }
585
+ }
586
+ } catch (err) {
587
+ console.error(`Error in ${type} hook ${handler.methodName}:`, err);
588
+ }
589
+ }
590
+ }
591
+
592
+ /**
593
+ * Register SIGTERM/SIGINT handlers for graceful shutdown.
594
+ */
595
+ private registerShutdownHandlers(): void {
596
+ const shutdown = () => {
597
+ this.executeLifecycleHooks(EventType.SHUTDOWN);
598
+ this.stop();
599
+ process.exit(0);
600
+ };
601
+
602
+ process.on('SIGTERM', shutdown);
603
+ process.on('SIGINT', shutdown);
604
+ }
605
+ }
@@ -0,0 +1,34 @@
1
+ import { Controller } from './decorators/Controller';
2
+ import { Get } from './decorators/methods';
3
+
4
+ /**
5
+ * Default routes controller.
6
+ * Auto-registered by Turbo for common endpoints.
7
+ */
8
+ @Controller()
9
+ export class DefaultRoutes {
10
+
11
+ /**
12
+ * Favicon - returns empty response to prevent 404.
13
+ */
14
+ @Get('/favicon.ico')
15
+ favicon() {
16
+ return new Response(null, { status: 204 });
17
+ }
18
+ }
19
+
20
+ /**
21
+ * Pre-compiled static responses for maximum performance.
22
+ * Use these directly in Bun.serve static routes.
23
+ */
24
+ export const DEFAULT_STATIC_ROUTES = {
25
+ '/health': new Response('{"status":"ok"}', {
26
+ status: 200,
27
+ headers: { 'Content-Type': 'application/json' }
28
+ }),
29
+ '/ready': new Response('{"ready":true}', {
30
+ status: 200,
31
+ headers: { 'Content-Type': 'application/json' }
32
+ }),
33
+ '/favicon.ico': new Response(null, { status: 204 })
34
+ };
@@ -0,0 +1,50 @@
1
+ /**
2
+ * Cache Driver Interface.
3
+ * Implement this to add new cache backends (Redis, Memcached, etc.)
4
+ */
5
+ export interface CacheDriver {
6
+ /**
7
+ * Driver name for debugging.
8
+ */
9
+ readonly name: string;
10
+
11
+ /**
12
+ * Get a value from cache.
13
+ */
14
+ get<T>(key: string): Promise<T | null>;
15
+
16
+ /**
17
+ * Set a value in cache.
18
+ * @param ttl Time to live in seconds (optional)
19
+ */
20
+ set<T>(key: string, value: T, ttl?: number): Promise<boolean>;
21
+
22
+ /**
23
+ * Delete a value from cache.
24
+ */
25
+ del(key: string): Promise<boolean>;
26
+
27
+ /**
28
+ * Check if key exists.
29
+ */
30
+ has(key: string): Promise<boolean>;
31
+
32
+ /**
33
+ * Clear all cached values.
34
+ */
35
+ clear(): Promise<void>;
36
+
37
+ /**
38
+ * Close connection (for Redis, etc.)
39
+ */
40
+ close?(): Promise<void>;
41
+ }
42
+
43
+ /**
44
+ * Cache configuration.
45
+ */
46
+ export interface CacheConfig {
47
+ driver?: CacheDriver;
48
+ prefix?: string;
49
+ defaultTtl?: number;
50
+ }