@carno.js/core 0.2.9 → 0.2.10

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.
@@ -2,6 +2,46 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.CorsHeadersCache = void 0;
4
4
  const cors_config_1 = require("./cors-config");
5
+ const allowAnyOrigin = () => {
6
+ return true;
7
+ };
8
+ const denyAnyOrigin = () => {
9
+ return false;
10
+ };
11
+ function buildOriginAllowed(origins) {
12
+ if (origins === '*') {
13
+ return allowAnyOrigin;
14
+ }
15
+ if (typeof origins === 'string') {
16
+ return createExactOriginMatcher(origins);
17
+ }
18
+ if (Array.isArray(origins)) {
19
+ return createSetOriginMatcher(origins);
20
+ }
21
+ if (origins instanceof RegExp) {
22
+ return createRegexOriginMatcher(origins);
23
+ }
24
+ if (typeof origins === 'function') {
25
+ return origins;
26
+ }
27
+ return denyAnyOrigin;
28
+ }
29
+ function createExactOriginMatcher(origin) {
30
+ return (value) => {
31
+ return value === origin;
32
+ };
33
+ }
34
+ function createSetOriginMatcher(origins) {
35
+ const originSet = new Set(origins);
36
+ return (value) => {
37
+ return originSet.has(value);
38
+ };
39
+ }
40
+ function createRegexOriginMatcher(origins) {
41
+ return (value) => {
42
+ return origins.test(value);
43
+ };
44
+ }
5
45
  class CorsHeadersCache {
6
46
  constructor(config) {
7
47
  this.config = config;
@@ -18,6 +58,7 @@ class CorsHeadersCache {
18
58
  : null;
19
59
  this.hasCredentials = !!config.credentials;
20
60
  this.isWildcard = config.origins === '*';
61
+ this.originAllowed = buildOriginAllowed(config.origins);
21
62
  }
22
63
  get(origin) {
23
64
  const cacheKey = this.isWildcard ? '*' : origin;
@@ -53,5 +94,8 @@ class CorsHeadersCache {
53
94
  }
54
95
  return response;
55
96
  }
97
+ isOriginAllowed(origin) {
98
+ return this.originAllowed(origin);
99
+ }
56
100
  }
57
101
  exports.CorsHeadersCache = CorsHeadersCache;
@@ -1,4 +1,12 @@
1
1
  import type { Context } from '../domain/Context';
2
2
  import type { CompiledRoute } from './CompiledRoute';
3
- export declare function executeSimpleRoute(compiled: CompiledRoute, context: Context): Promise<any>;
4
- export declare function executeSimpleRouteSync(compiled: CompiledRoute, context: Context): any;
3
+ /**
4
+ * Fast path executor completo - executa handler e monta response inline.
5
+ * Máximo 2 type checks no fast path.
6
+ */
7
+ export declare function executeFastPath(compiled: CompiledRoute, context: Context): Promise<Response>;
8
+ /**
9
+ * Fast path executor síncrono - para handlers que não retornam Promise.
10
+ * Elimina overhead de async/await quando handler é síncrono.
11
+ */
12
+ export declare function executeFastPathSync(compiled: CompiledRoute, context: Context): Response;
@@ -1,19 +1,50 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.executeSimpleRoute = executeSimpleRoute;
4
- exports.executeSimpleRouteSync = executeSimpleRouteSync;
5
- async function executeSimpleRoute(compiled, context) {
6
- if (!compiled.boundHandler) {
7
- throw new Error('Simple route must have a bound handler');
3
+ exports.executeFastPath = executeFastPath;
4
+ exports.executeFastPathSync = executeFastPathSync;
5
+ /**
6
+ * Frozen header objects - V8 otimiza acesso a objetos frozen.
7
+ * Criados uma vez no startup, reutilizados em todas requests.
8
+ */
9
+ const JSON_HEADERS = Object.freeze({
10
+ 'Content-Type': 'application/json'
11
+ });
12
+ const TEXT_HEADERS = Object.freeze({
13
+ 'Content-Type': 'text/html'
14
+ });
15
+ /**
16
+ * Fast path executor completo - executa handler e monta response inline.
17
+ * Máximo 2 type checks no fast path.
18
+ */
19
+ async function executeFastPath(compiled, context) {
20
+ const result = await compiled.boundHandler(context);
21
+ const status = context.getResponseStatus() || 200;
22
+ if (typeof result === 'string') {
23
+ return new Response(result, { status, headers: TEXT_HEADERS });
8
24
  }
9
- if (compiled.isAsync) {
10
- return compiled.boundHandler(context);
25
+ if (result instanceof Response) {
26
+ return result;
11
27
  }
12
- return compiled.boundHandler(context);
28
+ if (result === null || result === undefined) {
29
+ return new Response('', { status, headers: TEXT_HEADERS });
30
+ }
31
+ return new Response(JSON.stringify(result), { status, headers: JSON_HEADERS });
13
32
  }
14
- function executeSimpleRouteSync(compiled, context) {
15
- if (!compiled.boundHandler) {
16
- throw new Error('Simple route must have a bound handler');
33
+ /**
34
+ * Fast path executor síncrono - para handlers que não retornam Promise.
35
+ * Elimina overhead de async/await quando handler é síncrono.
36
+ */
37
+ function executeFastPathSync(compiled, context) {
38
+ const result = compiled.boundHandler(context);
39
+ const status = context.getResponseStatus() || 200;
40
+ if (typeof result === 'string') {
41
+ return new Response(result, { status, headers: TEXT_HEADERS });
42
+ }
43
+ if (result instanceof Response) {
44
+ return result;
45
+ }
46
+ if (result === null || result === undefined) {
47
+ return new Response('', { status, headers: TEXT_HEADERS });
17
48
  }
18
- return compiled.boundHandler(context);
49
+ return new Response(JSON.stringify(result), { status, headers: JSON_HEADERS });
19
50
  }
@@ -1,4 +1,28 @@
1
1
  import type { ParamInfo } from './ParamResolverFactory';
2
2
  import type { CompiledHandler, AsyncCompiledHandler } from './CompiledRoute';
3
+ /**
4
+ * Compila route handler em função otimizada.
5
+ *
6
+ * Estratégias de otimização:
7
+ * - Inline de acesso a parâmetros
8
+ * - Bind do handler no compile time
9
+ * - Código gerado monomórfico
10
+ * - Sem overhead de resolvers array
11
+ */
12
+ /**
13
+ * Compila route handler em função otimizada que retorna Response inline.
14
+ *
15
+ * Estratégias de otimização:
16
+ * - Inline de acesso a parâmetros
17
+ * - Inline de response building (elimina executeFastPath)
18
+ * - Bind do handler no compile time
19
+ * - Código gerado monomórfico
20
+ * - Headers pré-frozen para otimização V8
21
+ */
3
22
  export declare function compileRouteHandler(instance: any, methodName: string, paramInfos: ParamInfo[]): CompiledHandler | AsyncCompiledHandler;
4
- export declare function compileValidatedHandler(instance: any, methodName: string, paramInfos: ParamInfo[], validators: ((value: any) => any)[]): CompiledHandler | AsyncCompiledHandler;
23
+ /**
24
+ * Compila handler com validação inline.
25
+ */
26
+ export declare function compileValidatedHandler(instance: any, methodName: string, paramInfos: ParamInfo[], validatorAdapter: {
27
+ validateAndTransform: (token: any, value: any) => any;
28
+ }): CompiledHandler | AsyncCompiledHandler;
@@ -2,137 +2,244 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.compileRouteHandler = compileRouteHandler;
4
4
  exports.compileValidatedHandler = compileValidatedHandler;
5
+ const TEXT_HEADERS = Object.freeze({
6
+ 'Content-Type': 'text/html'
7
+ });
8
+ const JSON_HEADERS = Object.freeze({
9
+ 'Content-Type': 'application/json'
10
+ });
11
+ function isBodyInitResult(result) {
12
+ if (!result) {
13
+ return false;
14
+ }
15
+ if (result instanceof ReadableStream) {
16
+ return true;
17
+ }
18
+ if (result instanceof Blob || result instanceof ArrayBuffer) {
19
+ return true;
20
+ }
21
+ if (ArrayBuffer.isView(result)) {
22
+ return true;
23
+ }
24
+ return result instanceof FormData || result instanceof URLSearchParams;
25
+ }
26
+ /**
27
+ * Cria handler inline com response building integrado.
28
+ * Usado quando não há parâmetros.
29
+ */
30
+ function createInlineResponseHandler(handler, isAsync) {
31
+ if (isAsync) {
32
+ return async (c) => {
33
+ const r = await handler();
34
+ const s = c.getResponseStatus() || 200;
35
+ if (typeof r === 'string')
36
+ return new Response(r, { status: s, headers: TEXT_HEADERS });
37
+ if (r instanceof Response)
38
+ return r;
39
+ if (r == null)
40
+ return new Response('', { status: s, headers: TEXT_HEADERS });
41
+ if (typeof r === 'number' || typeof r === 'boolean') {
42
+ return new Response(String(r), { status: s, headers: TEXT_HEADERS });
43
+ }
44
+ if (isBodyInitResult(r)) {
45
+ return new Response(r, { status: s });
46
+ }
47
+ return new Response(JSON.stringify(r), { status: s, headers: JSON_HEADERS });
48
+ };
49
+ }
50
+ return (c) => {
51
+ const r = handler();
52
+ const s = c.getResponseStatus() || 200;
53
+ if (typeof r === 'string')
54
+ return new Response(r, { status: s, headers: TEXT_HEADERS });
55
+ if (r instanceof Response)
56
+ return r;
57
+ if (r == null)
58
+ return new Response('', { status: s, headers: TEXT_HEADERS });
59
+ if (typeof r === 'number' || typeof r === 'boolean') {
60
+ return new Response(String(r), { status: s, headers: TEXT_HEADERS });
61
+ }
62
+ if (isBodyInitResult(r)) {
63
+ return new Response(r, { status: s });
64
+ }
65
+ return new Response(JSON.stringify(r), { status: s, headers: JSON_HEADERS });
66
+ };
67
+ }
5
68
  function escapeKey(key) {
6
- return key.replace(/['"\\]/g, '\\$&');
69
+ return key.replace(/['\"\\]/g, '\\$&');
7
70
  }
8
- function buildArgExpression(param, index) {
71
+ /**
72
+ * Gera expressão de acesso a parâmetro inline.
73
+ * Otimizado para evitar chamadas de função quando possível.
74
+ */
75
+ function buildArgExpression(param) {
9
76
  const key = param.key ? escapeKey(param.key) : undefined;
10
77
  switch (param.type) {
11
78
  case 'param':
12
- return key ? `ctx.param['${key}']` : 'ctx.param';
79
+ return key ? `c.param['${key}']` : 'c.param';
13
80
  case 'query':
14
- return key ? `ctx.query['${key}']` : 'ctx.query';
81
+ return key ? `c.query['${key}']` : 'c.query';
15
82
  case 'body':
16
- return key ? `ctx.body['${key}']` : 'ctx.body';
83
+ return key ? `c.body['${key}']` : 'c.body';
17
84
  case 'headers':
18
- return key
19
- ? `ctx.headers.get('${key}')`
20
- : 'ctx.headers';
85
+ return key ? `c.headers.get('${key}')` : 'c.headers';
21
86
  case 'req':
22
- return 'ctx.req';
87
+ return 'c.req';
23
88
  case 'locals':
24
- return 'ctx.locals';
25
- case 'di':
26
- return `resolvers[${index}](ctx)`;
89
+ return 'c.locals';
27
90
  default:
28
- return `resolvers[${index}](ctx)`;
91
+ return 'undefined';
29
92
  }
30
93
  }
94
+ /**
95
+ * Compila route handler em função otimizada.
96
+ *
97
+ * Estratégias de otimização:
98
+ * - Inline de acesso a parâmetros
99
+ * - Bind do handler no compile time
100
+ * - Código gerado monomórfico
101
+ * - Sem overhead de resolvers array
102
+ */
103
+ /**
104
+ * Compila route handler em função otimizada que retorna Response inline.
105
+ *
106
+ * Estratégias de otimização:
107
+ * - Inline de acesso a parâmetros
108
+ * - Inline de response building (elimina executeFastPath)
109
+ * - Bind do handler no compile time
110
+ * - Código gerado monomórfico
111
+ * - Headers pré-frozen para otimização V8
112
+ */
31
113
  function compileRouteHandler(instance, methodName, paramInfos) {
32
114
  const handler = instance[methodName].bind(instance);
33
115
  if (paramInfos.length === 0) {
34
- return () => handler();
116
+ return createInlineResponseHandler(handler, false);
35
117
  }
36
- const hasBodyParam = paramInfos.some((p) => p.type === 'body');
37
118
  const hasDIParam = paramInfos.some((p) => p.type === 'di');
38
119
  if (hasDIParam) {
39
120
  return createFallbackHandler(handler, paramInfos);
40
121
  }
122
+ const hasBodyParam = paramInfos.some((p) => p.type === 'body');
41
123
  const argExpressions = paramInfos.map(buildArgExpression);
124
+ const argsCode = argExpressions.join(',');
42
125
  if (hasBodyParam) {
43
- return createAsyncHandler(handler, argExpressions);
126
+ const code = `return async function(c){
127
+ await c.getBody();
128
+ const r=await h(${argsCode});
129
+ const s=c.getResponseStatus()||200;
130
+ if(typeof r==='string')return new Response(r,{status:s,headers:TH});
131
+ if(r instanceof Response)return r;
132
+ if(r==null)return new Response('',{status:s,headers:TH});
133
+ if(typeof r==='number'||typeof r==='boolean')return new Response(String(r),{status:s,headers:TH});
134
+ if(isBI(r))return new Response(r,{status:s});
135
+ return new Response(JSON.stringify(r),{status:s,headers:JH});
136
+ }`;
137
+ return new Function('h', 'TH', 'JH', 'isBI', code)(handler, TEXT_HEADERS, JSON_HEADERS, isBodyInitResult);
44
138
  }
45
- return createSyncHandler(handler, argExpressions);
46
- }
47
- function createSyncHandler(handler, argExpressions) {
48
- const code = `
49
- return function compiledHandler(ctx) {
50
- return handler(${argExpressions.join(', ')});
51
- }
52
- `;
53
- return new Function('handler', code)(handler);
54
- }
55
- function createAsyncHandler(handler, argExpressions) {
56
- const code = `
57
- return async function compiledHandler(ctx) {
58
- await ctx.getBody();
59
- return handler(${argExpressions.join(', ')});
60
- }
61
- `;
62
- return new Function('handler', code)(handler);
139
+ const code = `return function(c){
140
+ const r=h(${argsCode});
141
+ const s=c.getResponseStatus()||200;
142
+ if(typeof r==='string')return new Response(r,{status:s,headers:TH});
143
+ if(r instanceof Response)return r;
144
+ if(r==null)return new Response('',{status:s,headers:TH});
145
+ if(typeof r==='number'||typeof r==='boolean')return new Response(String(r),{status:s,headers:TH});
146
+ if(isBI(r))return new Response(r,{status:s});
147
+ return new Response(JSON.stringify(r),{status:s,headers:JH});
148
+ }`;
149
+ return new Function('h', 'TH', 'JH', 'isBI', code)(handler, TEXT_HEADERS, JSON_HEADERS, isBodyInitResult);
63
150
  }
151
+ /**
152
+ * Handler fallback para casos com DI.
153
+ */
64
154
  function createFallbackHandler(handler, paramInfos) {
65
155
  return (ctx) => {
66
- const args = [];
67
- for (const param of paramInfos) {
68
- switch (param.type) {
69
- case 'param':
70
- args.push(param.key ? ctx.param[param.key] : ctx.param);
71
- break;
72
- case 'query':
73
- args.push(param.key ? ctx.query[param.key] : ctx.query);
74
- break;
75
- case 'body':
76
- args.push(param.key ? ctx.body[param.key] : ctx.body);
77
- break;
78
- case 'headers':
79
- args.push(param.key ? ctx.headers.get(param.key) : ctx.headers);
80
- break;
81
- case 'req':
82
- args.push(ctx.req);
83
- break;
84
- case 'locals':
85
- args.push(ctx.locals);
86
- break;
87
- default:
88
- args.push(undefined);
89
- break;
90
- }
91
- }
156
+ const args = resolveArgs(paramInfos, ctx);
92
157
  return handler(...args);
93
158
  };
94
159
  }
95
- function compileValidatedHandler(instance, methodName, paramInfos, validators) {
160
+ /**
161
+ * Resolve argumentos para fallback handler.
162
+ */
163
+ function resolveArgs(paramInfos, ctx) {
164
+ const args = new Array(paramInfos.length);
165
+ let i = 0;
166
+ for (const param of paramInfos) {
167
+ args[i++] = resolveArg(param, ctx);
168
+ }
169
+ return args;
170
+ }
171
+ /**
172
+ * Resolve um argumento individual.
173
+ */
174
+ function resolveArg(param, ctx) {
175
+ switch (param.type) {
176
+ case 'param':
177
+ return param.key ? ctx.param[param.key] : ctx.param;
178
+ case 'query':
179
+ return param.key ? ctx.query[param.key] : ctx.query;
180
+ case 'body':
181
+ return param.key ? ctx.body[param.key] : ctx.body;
182
+ case 'headers':
183
+ return param.key ? ctx.headers.get(param.key) : ctx.headers;
184
+ case 'req':
185
+ return ctx.req;
186
+ case 'locals':
187
+ return ctx.locals;
188
+ default:
189
+ return undefined;
190
+ }
191
+ }
192
+ /**
193
+ * Compila handler com validação inline.
194
+ */
195
+ function compileValidatedHandler(instance, methodName, paramInfos, validatorAdapter) {
96
196
  const handler = instance[methodName].bind(instance);
97
197
  const hasBodyParam = paramInfos.some((p) => p.type === 'body');
98
- const resolveArg = (ctx, param, index) => {
99
- let value;
100
- switch (param.type) {
101
- case 'param':
102
- value = param.key ? ctx.param[param.key] : ctx.param;
103
- break;
104
- case 'query':
105
- value = param.key ? ctx.query[param.key] : ctx.query;
106
- break;
107
- case 'body':
108
- value = param.key ? ctx.body[param.key] : ctx.body;
109
- break;
110
- case 'headers':
111
- value = param.key ? ctx.headers.get(param.key) : ctx.headers;
112
- break;
113
- case 'req':
114
- value = ctx.req;
115
- break;
116
- case 'locals':
117
- value = ctx.locals;
118
- break;
119
- default:
120
- value = undefined;
121
- }
122
- if (param.needsValidation && validators[index]) {
123
- return validators[index](value);
124
- }
125
- return value;
126
- };
198
+ if (paramInfos.length === 0) {
199
+ return createInlineResponseHandler(handler, false);
200
+ }
201
+ const { argAssignments, argList, tokenParams, tokenValues, } = buildValidatedArgs(paramInfos);
127
202
  if (hasBodyParam) {
128
- return async (ctx) => {
129
- await ctx.getBody();
130
- const args = paramInfos.map((p, i) => resolveArg(ctx, p, i));
131
- return handler(...args);
132
- };
203
+ const code = `return async function(c){\nawait c.getBody();\n${argAssignments}\nconst r=await h(${argList});\nconst s=c.getResponseStatus()||200;\nif(typeof r==='string')return new Response(r,{status:s,headers:TH});\nif(r instanceof Response)return r;\nif(r==null)return new Response('',{status:s,headers:TH});\nif(typeof r==='number'||typeof r==='boolean')return new Response(String(r),{status:s,headers:TH});\nif(isBI(r))return new Response(r,{status:s});\nreturn new Response(JSON.stringify(r),{status:s,headers:JH});\n}`;
204
+ return new Function('h', 'va', ...tokenParams, 'TH', 'JH', 'isBI', code)(handler, validatorAdapter, ...tokenValues, TEXT_HEADERS, JSON_HEADERS, isBodyInitResult);
133
205
  }
134
- return (ctx) => {
135
- const args = paramInfos.map((p, i) => resolveArg(ctx, p, i));
136
- return handler(...args);
206
+ const code = `return function(c){\n${argAssignments}\nconst r=h(${argList});\nconst s=c.getResponseStatus()||200;\nif(typeof r==='string')return new Response(r,{status:s,headers:TH});\nif(r instanceof Response)return r;\nif(r==null)return new Response('',{status:s,headers:TH});\nif(typeof r==='number'||typeof r==='boolean')return new Response(String(r),{status:s,headers:TH});\nif(isBI(r))return new Response(r,{status:s});\nreturn new Response(JSON.stringify(r),{status:s,headers:JH});\n}`;
207
+ return new Function('h', 'va', ...tokenParams, 'TH', 'JH', 'isBI', code)(handler, validatorAdapter, ...tokenValues, TEXT_HEADERS, JSON_HEADERS, isBodyInitResult);
208
+ }
209
+ function buildValidatedArgs(paramInfos) {
210
+ const assignments = [];
211
+ const args = [];
212
+ const tokenParams = [];
213
+ const tokenValues = [];
214
+ let index = 0;
215
+ for (const param of paramInfos) {
216
+ const argName = `a${index}`;
217
+ const argExpr = buildArgExpression(param);
218
+ const tokenName = getTokenParamName(param, index, tokenParams, tokenValues);
219
+ const valueExpr = buildValidatedExpression(argExpr, tokenName);
220
+ assignments.push(`const ${argName}=${valueExpr};`);
221
+ args.push(argName);
222
+ index += 1;
223
+ }
224
+ return {
225
+ argAssignments: assignments.join('\n'),
226
+ argList: args.join(','),
227
+ tokenParams,
228
+ tokenValues,
137
229
  };
138
230
  }
231
+ function buildValidatedExpression(argExpr, tokenName) {
232
+ if (!tokenName) {
233
+ return argExpr;
234
+ }
235
+ return `va.validateAndTransform(${tokenName}, ${argExpr})`;
236
+ }
237
+ function getTokenParamName(param, index, tokenParams, tokenValues) {
238
+ if (!param.needsValidation || !param.token) {
239
+ return null;
240
+ }
241
+ const tokenName = `t${index}`;
242
+ tokenParams.push(tokenName);
243
+ tokenValues.push(param.token);
244
+ return tokenName;
245
+ }
@@ -25,5 +25,4 @@ export declare class RouteCompiler {
25
25
  private createStandardRoute;
26
26
  private createComplexRoute;
27
27
  private createFallbackRoute;
28
- private createValidatedHandler;
29
28
  }
@@ -67,7 +67,7 @@ class RouteCompiler {
67
67
  const hasBodyParam = paramInfos.some((p) => p.type === 'body');
68
68
  let boundHandler;
69
69
  if (hasValidation) {
70
- boundHandler = this.createValidatedHandler(instance, route.methodName, paramInfos, hasBodyParam);
70
+ boundHandler = (0, JITCompiler_1.compileValidatedHandler)(instance, route.methodName, paramInfos, this.validatorAdapter);
71
71
  }
72
72
  else {
73
73
  boundHandler = (0, JITCompiler_1.compileRouteHandler)(instance, route.methodName, paramInfos);
@@ -153,48 +153,5 @@ class RouteCompiler {
153
153
  original: route,
154
154
  };
155
155
  }
156
- createValidatedHandler(instance, methodName, paramInfos, hasBodyParam) {
157
- const handler = instance[methodName].bind(instance);
158
- const resolveArg = (ctx, param) => {
159
- let value;
160
- switch (param.type) {
161
- case 'param':
162
- value = param.key ? ctx.param[param.key] : ctx.param;
163
- break;
164
- case 'query':
165
- value = param.key ? ctx.query[param.key] : ctx.query;
166
- break;
167
- case 'body':
168
- value = param.key ? ctx.body[param.key] : ctx.body;
169
- break;
170
- case 'headers':
171
- value = param.key ? ctx.headers.get(param.key) : ctx.headers;
172
- break;
173
- case 'req':
174
- value = ctx.req;
175
- break;
176
- case 'locals':
177
- value = ctx.locals;
178
- break;
179
- default:
180
- value = undefined;
181
- }
182
- if (param.needsValidation && param.token) {
183
- return this.validatorAdapter.validateAndTransform(param.token, value);
184
- }
185
- return value;
186
- };
187
- if (hasBodyParam) {
188
- return async (ctx) => {
189
- await ctx.getBody();
190
- const args = paramInfos.map((p) => resolveArg(ctx, p));
191
- return handler(...args);
192
- };
193
- }
194
- return (ctx) => {
195
- const args = paramInfos.map((p) => resolveArg(ctx, p));
196
- return handler(...args);
197
- };
198
- }
199
156
  }
200
157
  exports.RouteCompiler = RouteCompiler;
@@ -24,7 +24,24 @@ class Router {
24
24
  if (injector.hasOnResponseHook()) {
25
25
  await injector.callHook(events_1.EventType.OnResponse, { context, result });
26
26
  }
27
- return this.mountResponse(result, context);
27
+ const status = context.getResponseStatus() || 200;
28
+ if (result instanceof Response) {
29
+ return result;
30
+ }
31
+ if (result === null || result === undefined) {
32
+ return new Response("", { status, headers: this.textHeaders });
33
+ }
34
+ const resultType = typeof result;
35
+ if (resultType === "string") {
36
+ return new Response(result, { status, headers: this.textHeaders });
37
+ }
38
+ if (resultType === "number" || resultType === "boolean") {
39
+ return new Response(String(result), { status, headers: this.textHeaders });
40
+ }
41
+ if (this.isBodyInit(result)) {
42
+ return new Response(result, { status });
43
+ }
44
+ return this.createJsonResponse(result, status);
28
45
  }
29
46
  mountResponse(result, context) {
30
47
  const status = context.getResponseStatus() || 200;
@@ -18,10 +18,13 @@ export interface Node<T> {
18
18
  export declare class Memoirist<T> {
19
19
  root: Record<string, Node<T>>;
20
20
  history: [string, string, T][];
21
+ private routeCache;
21
22
  private static regex;
22
23
  add(method: string, path: string, store: T): FindResult<T>['store'];
23
24
  find(method: string, url: string): FindResult<T> | null;
24
25
  updateStore(method: string, path: string, oldStore: T, newStore: T): boolean;
26
+ private buildCacheKey;
27
+ private invalidateCache;
25
28
  private updateHistoryStore;
26
29
  private normalizePath;
27
30
  private findNode;