@carno.js/core 1.1.1 → 1.2.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 (124) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +188 -188
  3. package/dist/Carno.js +45 -26
  4. package/dist/Carno.mjs +45 -26
  5. package/dist/bun/index.js +4 -4
  6. package/dist/bun/index.js.map +30 -29
  7. package/dist/compression/CompressionMiddleware.js +110 -0
  8. package/dist/compression/CompressionMiddleware.mjs +90 -0
  9. package/dist/index.js +3 -1
  10. package/dist/index.mjs +2 -0
  11. package/package.json +2 -2
  12. package/src/Carno.ts +728 -673
  13. package/src/DefaultRoutes.ts +34 -34
  14. package/src/cache/CacheDriver.ts +50 -50
  15. package/src/cache/CacheService.ts +139 -139
  16. package/src/cache/MemoryDriver.ts +104 -104
  17. package/src/cache/RedisDriver.ts +116 -116
  18. package/src/compiler/JITCompiler.ts +167 -167
  19. package/src/compression/CompressionMiddleware.ts +221 -0
  20. package/src/container/Container.ts +168 -168
  21. package/src/context/Context.ts +130 -130
  22. package/src/cors/CorsHandler.ts +145 -145
  23. package/src/decorators/Controller.ts +63 -63
  24. package/src/decorators/Inject.ts +16 -16
  25. package/src/decorators/Middleware.ts +22 -22
  26. package/src/decorators/Service.ts +18 -18
  27. package/src/decorators/methods.ts +58 -58
  28. package/src/decorators/params.ts +47 -47
  29. package/src/events/Lifecycle.ts +97 -97
  30. package/src/exceptions/HttpException.ts +99 -99
  31. package/src/index.ts +99 -95
  32. package/src/metadata.ts +46 -46
  33. package/src/middleware/CarnoMiddleware.ts +20 -14
  34. package/src/router/RadixRouter.ts +225 -225
  35. package/src/testing/TestHarness.ts +185 -185
  36. package/src/utils/Metadata.ts +43 -43
  37. package/src/utils/parseQuery.ts +161 -161
  38. package/src/validation/ValibotAdapter.ts +95 -95
  39. package/src/validation/ValidatorAdapter.ts +69 -69
  40. package/src/validation/ZodAdapter.ts +102 -102
  41. package/dist/Carno.d.js +0 -14
  42. package/dist/Carno.d.mjs +0 -1
  43. package/dist/DefaultRoutes.d.js +0 -13
  44. package/dist/DefaultRoutes.d.mjs +0 -0
  45. package/dist/cache/CacheDriver.d.js +0 -13
  46. package/dist/cache/CacheDriver.d.mjs +0 -0
  47. package/dist/cache/CacheService.d.js +0 -13
  48. package/dist/cache/CacheService.d.mjs +0 -0
  49. package/dist/cache/MemoryDriver.d.js +0 -13
  50. package/dist/cache/MemoryDriver.d.mjs +0 -0
  51. package/dist/cache/RedisDriver.d.js +0 -13
  52. package/dist/cache/RedisDriver.d.mjs +0 -0
  53. package/dist/compiler/JITCompiler.d.js +0 -13
  54. package/dist/compiler/JITCompiler.d.mjs +0 -0
  55. package/dist/container/Container.d.js +0 -13
  56. package/dist/container/Container.d.mjs +0 -0
  57. package/dist/context/Context.d.js +0 -13
  58. package/dist/context/Context.d.mjs +0 -0
  59. package/dist/cors/CorsHandler.d.js +0 -13
  60. package/dist/cors/CorsHandler.d.mjs +0 -0
  61. package/dist/decorators/Controller.d.js +0 -13
  62. package/dist/decorators/Controller.d.mjs +0 -0
  63. package/dist/decorators/Inject.d.js +0 -13
  64. package/dist/decorators/Inject.d.mjs +0 -0
  65. package/dist/decorators/Middleware.d.js +0 -13
  66. package/dist/decorators/Middleware.d.mjs +0 -0
  67. package/dist/decorators/Service.d.js +0 -13
  68. package/dist/decorators/Service.d.mjs +0 -0
  69. package/dist/decorators/methods.d.js +0 -13
  70. package/dist/decorators/methods.d.mjs +0 -0
  71. package/dist/decorators/params.d.js +0 -13
  72. package/dist/decorators/params.d.mjs +0 -0
  73. package/dist/events/Lifecycle.d.js +0 -13
  74. package/dist/events/Lifecycle.d.mjs +0 -0
  75. package/dist/exceptions/HttpException.d.js +0 -13
  76. package/dist/exceptions/HttpException.d.mjs +0 -0
  77. package/dist/index.d.js +0 -130
  78. package/dist/index.d.mjs +0 -78
  79. package/dist/metadata.d.js +0 -13
  80. package/dist/metadata.d.mjs +0 -0
  81. package/dist/middleware/CarnoMiddleware.d.js +0 -13
  82. package/dist/middleware/CarnoMiddleware.d.mjs +0 -0
  83. package/dist/router/RadixRouter.d.js +0 -13
  84. package/dist/router/RadixRouter.d.mjs +0 -0
  85. package/dist/testing/TestHarness.d.js +0 -13
  86. package/dist/testing/TestHarness.d.mjs +0 -0
  87. package/dist/utils/Metadata.d.js +0 -13
  88. package/dist/utils/Metadata.d.mjs +0 -0
  89. package/dist/utils/parseQuery.d.js +0 -13
  90. package/dist/utils/parseQuery.d.mjs +0 -0
  91. package/dist/validation/ValibotAdapter.d.js +0 -13
  92. package/dist/validation/ValibotAdapter.d.mjs +0 -0
  93. package/dist/validation/ValidatorAdapter.d.js +0 -13
  94. package/dist/validation/ValidatorAdapter.d.mjs +0 -0
  95. package/dist/validation/ZodAdapter.d.js +0 -13
  96. package/dist/validation/ZodAdapter.d.mjs +0 -0
  97. package/src/Carno.d.ts +0 -135
  98. package/src/DefaultRoutes.d.ts +0 -19
  99. package/src/cache/CacheDriver.d.ts +0 -43
  100. package/src/cache/CacheService.d.ts +0 -89
  101. package/src/cache/MemoryDriver.d.ts +0 -32
  102. package/src/cache/RedisDriver.d.ts +0 -34
  103. package/src/compiler/JITCompiler.d.ts +0 -36
  104. package/src/container/Container.d.ts +0 -38
  105. package/src/context/Context.d.ts +0 -36
  106. package/src/cors/CorsHandler.d.ts +0 -47
  107. package/src/decorators/Controller.d.ts +0 -13
  108. package/src/decorators/Inject.d.ts +0 -6
  109. package/src/decorators/Middleware.d.ts +0 -5
  110. package/src/decorators/Service.d.ts +0 -9
  111. package/src/decorators/methods.d.ts +0 -7
  112. package/src/decorators/params.d.ts +0 -13
  113. package/src/events/Lifecycle.d.ts +0 -54
  114. package/src/exceptions/HttpException.d.ts +0 -43
  115. package/src/index.d.ts +0 -42
  116. package/src/metadata.d.ts +0 -41
  117. package/src/middleware/CarnoMiddleware.d.ts +0 -12
  118. package/src/router/RadixRouter.d.ts +0 -19
  119. package/src/testing/TestHarness.d.ts +0 -71
  120. package/src/utils/Metadata.d.ts +0 -20
  121. package/src/utils/parseQuery.d.ts +0 -23
  122. package/src/validation/ValibotAdapter.d.ts +0 -30
  123. package/src/validation/ValidatorAdapter.d.ts +0 -54
  124. package/src/validation/ZodAdapter.d.ts +0 -35
@@ -1,116 +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
- }
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
+ }
@@ -1,167 +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
- }
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
+ }