@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
@@ -0,0 +1,139 @@
1
+ import type { CacheDriver, CacheConfig } from './CacheDriver';
2
+ import { MemoryDriver } from './MemoryDriver';
3
+
4
+ /**
5
+ * CacheService - High-performance caching with driver pattern.
6
+ *
7
+ * Features:
8
+ * - In-memory (default) or Redis backend
9
+ * - getOrSet for cache-aside pattern
10
+ * - Key prefixing for namespacing
11
+ * - Configurable default TTL
12
+ *
13
+ * Usage:
14
+ * ```typescript
15
+ * const cache = new CacheService();
16
+ *
17
+ * // Basic operations
18
+ * await cache.set('user:123', { name: 'John' }, 3600);
19
+ * const user = await cache.get<User>('user:123');
20
+ *
21
+ * // Cache-aside pattern
22
+ * const user = await cache.getOrSet('user:123',
23
+ * async () => db.findUser(123),
24
+ * 3600
25
+ * );
26
+ * ```
27
+ */
28
+ export class CacheService {
29
+ private driver: CacheDriver;
30
+ private prefix: string;
31
+ private defaultTtl: number | undefined;
32
+
33
+ constructor(config: CacheConfig = {}) {
34
+ this.driver = config.driver || new MemoryDriver();
35
+ this.prefix = config.prefix || '';
36
+ this.defaultTtl = config.defaultTtl;
37
+ }
38
+
39
+ /**
40
+ * Get the full key with prefix.
41
+ */
42
+ private key(key: string): string {
43
+ return this.prefix ? `${this.prefix}:${key}` : key;
44
+ }
45
+
46
+ /**
47
+ * Get a value from cache.
48
+ */
49
+ async get<T>(key: string): Promise<T | null> {
50
+ return this.driver.get<T>(this.key(key));
51
+ }
52
+
53
+ /**
54
+ * Set a value in cache.
55
+ * @param ttl Time to live in seconds
56
+ */
57
+ async set<T>(key: string, value: T, ttl?: number): Promise<boolean> {
58
+ return this.driver.set(this.key(key), value, ttl ?? this.defaultTtl);
59
+ }
60
+
61
+ /**
62
+ * Delete a value from cache.
63
+ */
64
+ async del(key: string): Promise<boolean> {
65
+ return this.driver.del(this.key(key));
66
+ }
67
+
68
+ /**
69
+ * Check if key exists.
70
+ */
71
+ async has(key: string): Promise<boolean> {
72
+ return this.driver.has(this.key(key));
73
+ }
74
+
75
+ /**
76
+ * Clear all cached values.
77
+ */
78
+ async clear(): Promise<void> {
79
+ return this.driver.clear();
80
+ }
81
+
82
+ /**
83
+ * Get value from cache or compute and store it.
84
+ * This is the cache-aside pattern - most commonly used method.
85
+ *
86
+ * @param key Cache key
87
+ * @param cb Callback to compute value if not cached
88
+ * @param ttl Time to live in seconds
89
+ */
90
+ async getOrSet<T>(key: string, cb: () => Promise<T>, ttl?: number): Promise<T> {
91
+ const cached = await this.get<T>(key);
92
+
93
+ if (cached !== null) {
94
+ return cached;
95
+ }
96
+
97
+ const value = await cb();
98
+ await this.set(key, value, ttl);
99
+
100
+ return value;
101
+ }
102
+
103
+ /**
104
+ * Get multiple values at once.
105
+ */
106
+ async getMany<T>(keys: string[]): Promise<(T | null)[]> {
107
+ return Promise.all(keys.map(key => this.get<T>(key)));
108
+ }
109
+
110
+ /**
111
+ * Set multiple values at once.
112
+ */
113
+ async setMany<T>(entries: Array<{ key: string; value: T; ttl?: number }>): Promise<boolean[]> {
114
+ return Promise.all(
115
+ entries.map(entry => this.set(entry.key, entry.value, entry.ttl))
116
+ );
117
+ }
118
+
119
+ /**
120
+ * Delete multiple values at once.
121
+ */
122
+ async delMany(keys: string[]): Promise<boolean[]> {
123
+ return Promise.all(keys.map(key => this.del(key)));
124
+ }
125
+
126
+ /**
127
+ * Close the cache driver connection.
128
+ */
129
+ async close(): Promise<void> {
130
+ await this.driver.close?.();
131
+ }
132
+
133
+ /**
134
+ * Get the underlying driver (for advanced use).
135
+ */
136
+ getDriver(): CacheDriver {
137
+ return this.driver;
138
+ }
139
+ }
@@ -0,0 +1,104 @@
1
+ import type { CacheDriver } from './CacheDriver';
2
+
3
+ interface CacheEntry<T> {
4
+ value: T;
5
+ expiresAt: number | null;
6
+ }
7
+
8
+ /**
9
+ * In-Memory Cache Driver.
10
+ * Ultra-fast, perfect for single-instance applications.
11
+ *
12
+ * Features:
13
+ * - O(1) get/set/del operations
14
+ * - Lazy expiration (checked on access)
15
+ * - Periodic cleanup of expired entries
16
+ */
17
+ export class MemoryDriver implements CacheDriver {
18
+ readonly name = 'MemoryDriver';
19
+
20
+ private cache = new Map<string, CacheEntry<any>>();
21
+ private cleanupInterval: Timer | null = null;
22
+
23
+ constructor(cleanupIntervalMs: number = 0) {
24
+ // Periodic cleanup of expired entries (disabled by default for performance)
25
+ if (cleanupIntervalMs > 0) {
26
+ this.cleanupInterval = setInterval(() => this.cleanup(), cleanupIntervalMs);
27
+ }
28
+ }
29
+
30
+ async get<T>(key: string): Promise<T | null> {
31
+ const entry = this.cache.get(key);
32
+
33
+ if (!entry) {
34
+ return null;
35
+ }
36
+
37
+ // Check expiration
38
+ if (entry.expiresAt !== null && Date.now() > entry.expiresAt) {
39
+ this.cache.delete(key);
40
+ return null;
41
+ }
42
+
43
+ return entry.value;
44
+ }
45
+
46
+ async set<T>(key: string, value: T, ttl?: number): Promise<boolean> {
47
+ const expiresAt = ttl ? Date.now() + ttl : null;
48
+
49
+ this.cache.set(key, { value, expiresAt });
50
+
51
+ return true;
52
+ }
53
+
54
+ async del(key: string): Promise<boolean> {
55
+ return this.cache.delete(key);
56
+ }
57
+
58
+ async has(key: string): Promise<boolean> {
59
+ const entry = this.cache.get(key);
60
+
61
+ if (!entry) {
62
+ return false;
63
+ }
64
+
65
+ if (entry.expiresAt !== null && Date.now() > entry.expiresAt) {
66
+ this.cache.delete(key);
67
+ return false;
68
+ }
69
+
70
+ return true;
71
+ }
72
+
73
+ async clear(): Promise<void> {
74
+ this.cache.clear();
75
+ }
76
+
77
+ async close(): Promise<void> {
78
+ if (this.cleanupInterval) {
79
+ clearInterval(this.cleanupInterval);
80
+ this.cleanupInterval = null;
81
+ }
82
+ this.cache.clear();
83
+ }
84
+
85
+ /**
86
+ * Remove expired entries.
87
+ */
88
+ private cleanup(): void {
89
+ const now = Date.now();
90
+
91
+ for (const [key, entry] of this.cache) {
92
+ if (entry.expiresAt !== null && now > entry.expiresAt) {
93
+ this.cache.delete(key);
94
+ }
95
+ }
96
+ }
97
+
98
+ /**
99
+ * Get cache stats (for debugging).
100
+ */
101
+ stats(): { size: number } {
102
+ return { size: this.cache.size };
103
+ }
104
+ }
@@ -0,0 +1,116 @@
1
+ import type { CacheDriver } from './CacheDriver';
2
+
3
+ /**
4
+ * Redis Cache Driver Configuration.
5
+ */
6
+ export interface RedisConfig {
7
+ host?: string;
8
+ port?: number;
9
+ password?: string;
10
+ db?: number;
11
+ url?: string;
12
+ }
13
+
14
+ /**
15
+ * Redis Cache Driver.
16
+ * For distributed caching in multi-instance deployments.
17
+ *
18
+ * Uses Bun's native Redis client for maximum performance.
19
+ */
20
+ export class RedisDriver implements CacheDriver {
21
+ readonly name = 'RedisDriver';
22
+
23
+ private client: any = null;
24
+ private connected = false;
25
+
26
+ constructor(private config: RedisConfig = {}) { }
27
+
28
+ /**
29
+ * Connect to Redis (lazy - connects on first use).
30
+ */
31
+ private async ensureConnected(): Promise<void> {
32
+ if (this.connected) return;
33
+
34
+ const url = this.config.url ||
35
+ `redis://${this.config.host || 'localhost'}:${this.config.port || 6379}`;
36
+
37
+ // Use Bun's native Redis client if available
38
+ if (typeof Bun !== 'undefined' && (Bun as any).redis) {
39
+ this.client = new (Bun as any).redis(url);
40
+ } else {
41
+ // Fallback to ioredis
42
+ try {
43
+ const Redis = require('ioredis');
44
+ this.client = new Redis({
45
+ host: this.config.host || 'localhost',
46
+ port: this.config.port || 6379,
47
+ password: this.config.password,
48
+ db: this.config.db || 0
49
+ });
50
+ } catch {
51
+ throw new Error('Redis client not available. Install ioredis or use Bun with Redis support.');
52
+ }
53
+ }
54
+
55
+ this.connected = true;
56
+ }
57
+
58
+ async get<T>(key: string): Promise<T | null> {
59
+ await this.ensureConnected();
60
+
61
+ const value = await this.client.get(key);
62
+
63
+ if (value === null) {
64
+ return null;
65
+ }
66
+
67
+ try {
68
+ return JSON.parse(value);
69
+ } catch {
70
+ return value as T;
71
+ }
72
+ }
73
+
74
+ async set<T>(key: string, value: T, ttl?: number): Promise<boolean> {
75
+ await this.ensureConnected();
76
+
77
+ const serialized = typeof value === 'string' ? value : JSON.stringify(value);
78
+
79
+ if (ttl) {
80
+ await this.client.setex(key, ttl, serialized);
81
+ } else {
82
+ await this.client.set(key, serialized);
83
+ }
84
+
85
+ return true;
86
+ }
87
+
88
+ async del(key: string): Promise<boolean> {
89
+ await this.ensureConnected();
90
+
91
+ const result = await this.client.del(key);
92
+
93
+ return result > 0;
94
+ }
95
+
96
+ async has(key: string): Promise<boolean> {
97
+ await this.ensureConnected();
98
+
99
+ const result = await this.client.exists(key);
100
+
101
+ return result > 0;
102
+ }
103
+
104
+ async clear(): Promise<void> {
105
+ await this.ensureConnected();
106
+
107
+ await this.client.flushdb();
108
+ }
109
+
110
+ async close(): Promise<void> {
111
+ if (this.client && this.connected) {
112
+ await this.client.quit?.();
113
+ this.connected = false;
114
+ }
115
+ }
116
+ }
@@ -0,0 +1,167 @@
1
+ /**
2
+ * JIT Compiler for Turbo.
3
+ *
4
+ * Aggressive AOT optimizations:
5
+ * - Detects async at compile time (not runtime)
6
+ * - Generates specialized handlers via new Function()
7
+ * - Inlines parameter access
8
+ * - Zero overhead for simple handlers
9
+ */
10
+
11
+ import type { ParamType } from '../decorators/params';
12
+
13
+ export interface ParamInfo {
14
+ type: ParamType;
15
+ key?: string;
16
+ index: number;
17
+ }
18
+
19
+ export interface CompiledHandler {
20
+ fn: Function;
21
+ isAsync: boolean;
22
+ isStatic: boolean;
23
+ staticValue?: any;
24
+ }
25
+
26
+ const ASYNC_REGEX = /^async\s|^\([^)]*\)\s*=>\s*\{[\s\S]*await\s|^function\s*\*|\.then\s*\(/;
27
+
28
+ /**
29
+ * Detects if function is async at compile time.
30
+ * Checks: async keyword, await usage, generators, .then()
31
+ */
32
+ export function isAsyncFunction(fn: Function): boolean {
33
+ if (fn.constructor.name === 'AsyncFunction') {
34
+ return true;
35
+ }
36
+
37
+ const source = fn.toString();
38
+
39
+ return ASYNC_REGEX.test(source);
40
+ }
41
+
42
+ /**
43
+ * Detects if handler returns a static value.
44
+ * Static handlers can be pre-computed at startup.
45
+ */
46
+ export function isStaticHandler(fn: Function): boolean {
47
+ const source = fn.toString();
48
+
49
+ if (source.includes('this.') || source.includes('await')) {
50
+ return false;
51
+ }
52
+
53
+ const returnMatch = source.match(/=>\s*["'`]|return\s+["'`]|=>\s*\{|=>\s*\d/);
54
+
55
+ return !!returnMatch;
56
+ }
57
+
58
+ /**
59
+ * Compiles handler with inlined parameter access.
60
+ * Uses new Function() for maximum V8 optimization.
61
+ */
62
+ export function compileHandler(
63
+ instance: any,
64
+ methodName: string,
65
+ params: ParamInfo[]
66
+ ): CompiledHandler {
67
+ const method = instance[methodName];
68
+ const bound = method.bind(instance);
69
+ const async = isAsyncFunction(method);
70
+
71
+ if (params.length === 0) {
72
+ const isStatic = isStaticHandler(method);
73
+
74
+ if (isStatic && !async) {
75
+ const staticValue = bound();
76
+
77
+ return {
78
+ fn: bound,
79
+ isAsync: false,
80
+ isStatic: true,
81
+ staticValue
82
+ };
83
+ }
84
+
85
+ return {
86
+ fn: bound,
87
+ isAsync: async,
88
+ isStatic: false
89
+ };
90
+ }
91
+
92
+ const argExprs = params
93
+ .sort((a, b) => a.index - b.index)
94
+ .map(p => buildArgExpression(p));
95
+
96
+ const argsCode = argExprs.join(',');
97
+ const hasBody = params.some(p => p.type === 'body');
98
+
99
+ if (hasBody) {
100
+ const code = `return async function(c){
101
+ await c.parseBody();
102
+ return h(${argsCode});
103
+ }`;
104
+
105
+ return {
106
+ fn: new Function('h', code)(bound),
107
+ isAsync: true,
108
+ isStatic: false
109
+ };
110
+ }
111
+
112
+ if (async) {
113
+ const code = `return async function(c){
114
+ return await h(${argsCode});
115
+ }`;
116
+
117
+ return {
118
+ fn: new Function('h', code)(bound),
119
+ isAsync: true,
120
+ isStatic: false
121
+ };
122
+ }
123
+
124
+ const code = `return function(c){
125
+ return h(${argsCode});
126
+ }`;
127
+
128
+ return {
129
+ fn: new Function('h', code)(bound),
130
+ isAsync: false,
131
+ isStatic: false
132
+ };
133
+ }
134
+
135
+ function escapeKey(key: string): string {
136
+ return key.replace(/['\"\\]/g, '\\$&');
137
+ }
138
+
139
+ function buildArgExpression(param: ParamInfo): string {
140
+ const key = param.key ? escapeKey(param.key) : undefined;
141
+
142
+ switch (param.type) {
143
+ case 'param':
144
+ return key ? `c.params['${key}']` : 'c.params';
145
+
146
+ case 'query':
147
+ return key ? `c.query['${key}']` : 'c.query';
148
+
149
+ case 'body':
150
+ return key ? `c.body['${key}']` : 'c.body';
151
+
152
+ case 'header':
153
+ return key ? `c.req.headers.get('${key}')` : 'c.req.headers';
154
+
155
+ case 'req':
156
+ return 'c.req';
157
+
158
+ case 'ctx':
159
+ return 'c';
160
+
161
+ case 'locals':
162
+ return key ? `c.locals['${key}']` : 'c.locals';
163
+
164
+ default:
165
+ return 'undefined';
166
+ }
167
+ }
@@ -0,0 +1,168 @@
1
+ /**
2
+ * Lightweight DI Container for Turbo.
3
+ *
4
+ * Features:
5
+ * - Constructor injection via reflect-metadata
6
+ * - Singleton scope by default
7
+ * - Request scope support
8
+ * - Lazy instantiation
9
+ */
10
+
11
+ export type Token<T = any> = new (...args: any[]) => T;
12
+
13
+ export enum Scope {
14
+ SINGLETON = 'singleton', // Always the same instance
15
+ REQUEST = 'request', // New instance per request
16
+ INSTANCE = 'instance' // New instance per dependency injection
17
+ }
18
+
19
+ export interface ProviderConfig<T = any> {
20
+ token: Token<T>;
21
+ useClass?: Token<T>;
22
+ useValue?: T;
23
+ scope?: Scope;
24
+ }
25
+
26
+ interface ProviderEntry {
27
+ config: ProviderConfig;
28
+ instance: any | null;
29
+ }
30
+
31
+ export class Container {
32
+ private configs = new Map<Token, ProviderConfig>();
33
+ private instances = new Map<Token, any>();
34
+ private resolving = new Set<Token>();
35
+
36
+ register<T>(config: ProviderConfig<T> | Token<T>): this {
37
+ const normalized = this.normalizeConfig(config);
38
+
39
+ this.configs.set(normalized.token, normalized);
40
+
41
+ if (normalized.useValue !== undefined) {
42
+ this.instances.set(normalized.token, normalized.useValue);
43
+ }
44
+
45
+ return this;
46
+ }
47
+
48
+ get<T>(token: Token<T>): T {
49
+ const cached = this.instances.get(token);
50
+
51
+ if (cached !== undefined) {
52
+ return cached;
53
+ }
54
+
55
+ const res = this.resolveInternal(token);
56
+ return res.instance;
57
+ }
58
+
59
+ has(token: Token): boolean {
60
+ return this.configs.has(token);
61
+ }
62
+
63
+ /**
64
+ * Resolves a token to return instance and its effective scope.
65
+ */
66
+ private resolveInternal<T>(token: Token<T>, requestLocals?: Map<Token, any>): { instance: T, scope: Scope } {
67
+ // 1. Check Request Cache
68
+ if (requestLocals?.has(token)) {
69
+ return { instance: requestLocals.get(token), scope: Scope.REQUEST };
70
+ }
71
+
72
+ // 2. Check Singleton Cache
73
+ const cached = this.instances.get(token);
74
+ if (cached !== undefined) {
75
+ return { instance: cached, scope: Scope.SINGLETON };
76
+ }
77
+
78
+ const config = this.configs.get(token);
79
+
80
+ if (!config) {
81
+ throw new Error(`Provider not found: ${token.name}`);
82
+ }
83
+
84
+ // 3. Create Instance with Scope Bubbling
85
+ const creation = this.createInstance(config, requestLocals);
86
+
87
+ // 4. Cache based on Effective Scope
88
+ if (creation.scope === Scope.SINGLETON) {
89
+ this.instances.set(token, creation.instance);
90
+ } else if (creation.scope === Scope.REQUEST && requestLocals) {
91
+ requestLocals.set(token, creation.instance);
92
+ }
93
+ // INSTANCE scope is never cached
94
+
95
+ return creation;
96
+ }
97
+
98
+ private createInstance(config: ProviderConfig, requestLocals?: Map<Token, any>): { instance: any, scope: Scope } {
99
+ const target = config.useClass ?? config.token;
100
+
101
+ if (this.resolving.has(target)) {
102
+ throw new Error(`Circular dependency detected: ${target.name}`);
103
+ }
104
+
105
+ this.resolving.add(target);
106
+
107
+ try {
108
+ const depsToken = this.getDependencies(target);
109
+
110
+ if (depsToken.length === 0) {
111
+ // No deps: Scope is as configured
112
+ return { instance: new target(), scope: config.scope || Scope.SINGLETON };
113
+ }
114
+
115
+ const args: any[] = [];
116
+ let effectiveScope = config.scope || Scope.SINGLETON;
117
+
118
+ for (const depToken of depsToken) {
119
+ const depResult = this.resolveInternal(depToken, requestLocals);
120
+ args.push(depResult.instance);
121
+
122
+ // Scope Bubbling Logic:
123
+ // If a dependency is REQUEST scoped, the parent MUST become REQUEST scoped (if it was Singleton)
124
+ // to avoid holding a stale reference to a request-bound instance.
125
+ if (depResult.scope === Scope.REQUEST && effectiveScope === Scope.SINGLETON) {
126
+ effectiveScope = Scope.REQUEST;
127
+ }
128
+
129
+ // Note: INSTANCE scope dependencies do not force bubbling because they are transient and safe to hold (usually),
130
+ // unless semantic logic dictates otherwise. For now, strictly bubbling REQUEST scope.
131
+ }
132
+
133
+ return { instance: new target(...args), scope: effectiveScope };
134
+ } finally {
135
+ this.resolving.delete(target);
136
+ }
137
+ }
138
+
139
+ private getDependencies(target: Token): Token[] {
140
+ const types = Reflect.getMetadata('design:paramtypes', target) || [];
141
+ return types.filter((t: any) => t && typeof t === 'function' && !this.isPrimitive(t));
142
+ }
143
+
144
+ private isPrimitive(type: any): boolean {
145
+ return type === String || type === Number || type === Boolean || type === Object || type === Array || type === Symbol;
146
+ }
147
+
148
+ private normalizeConfig<T>(config: ProviderConfig<T> | Token<T>): ProviderConfig<T> {
149
+ if (typeof config === 'function') {
150
+ return {
151
+ token: config,
152
+ useClass: config,
153
+ scope: Scope.SINGLETON
154
+ };
155
+ }
156
+
157
+ return {
158
+ ...config,
159
+ useClass: config.useClass ?? config.token,
160
+ scope: config.scope ?? Scope.SINGLETON
161
+ };
162
+ }
163
+
164
+ clear(): void {
165
+ this.configs.clear();
166
+ this.instances.clear();
167
+ }
168
+ }