@carno.js/core 0.2.8 → 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.
- package/dist/Carno.d.ts +10 -8
- package/dist/Carno.js +31 -33
- package/dist/commons/decorators/index.d.ts +1 -0
- package/dist/commons/decorators/index.js +1 -0
- package/dist/commons/decorators/validation.decorator.d.ts +32 -0
- package/dist/commons/decorators/validation.decorator.js +40 -0
- package/dist/constants.d.ts +1 -0
- package/dist/constants.js +2 -1
- package/dist/container/InjectorService.d.ts +3 -1
- package/dist/container/InjectorService.js +4 -3
- package/dist/container/MethodInvoker.d.ts +3 -2
- package/dist/container/MethodInvoker.js +4 -17
- package/dist/container/middleware.resolver.js +6 -6
- package/dist/domain/BaseContext.d.ts +15 -0
- package/dist/domain/Context.d.ts +45 -24
- package/dist/domain/Context.js +110 -89
- package/dist/domain/FastContext.d.ts +34 -0
- package/dist/domain/FastContext.js +59 -0
- package/dist/domain/cors-headers-cache.d.ts +2 -0
- package/dist/domain/cors-headers-cache.js +44 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/route/FastPathExecutor.d.ts +10 -2
- package/dist/route/FastPathExecutor.js +43 -12
- package/dist/route/JITCompiler.d.ts +25 -1
- package/dist/route/JITCompiler.js +205 -98
- package/dist/route/ParamResolverFactory.d.ts +0 -5
- package/dist/route/ParamResolverFactory.js +0 -40
- package/dist/route/RouteCompiler.d.ts +3 -4
- package/dist/route/RouteCompiler.js +2 -54
- package/dist/route/RouteExecutor.js +18 -1
- package/dist/route/memoirist.d.ts +3 -0
- package/dist/route/memoirist.js +33 -3
- package/dist/utils/ValidationCache.d.ts +2 -0
- package/dist/utils/ValidationCache.js +10 -2
- package/dist/utils/index.d.ts +0 -1
- package/dist/utils/index.js +0 -1
- package/dist/validation/ValidatorAdapter.d.ts +66 -0
- package/dist/validation/ValidatorAdapter.js +20 -0
- package/dist/validation/adapters/ClassValidatorAdapter.d.ts +23 -0
- package/dist/validation/adapters/ClassValidatorAdapter.js +47 -0
- package/dist/validation/adapters/ZodAdapter.d.ts +14 -0
- package/dist/validation/adapters/ZodAdapter.js +56 -0
- package/dist/validation/adapters/index.d.ts +4 -0
- package/dist/validation/adapters/index.js +7 -0
- package/dist/validation/index.d.ts +3 -0
- package/dist/validation/index.js +20 -0
- package/package.json +17 -6
- package/dist/Cheetah.d.ts +0 -65
- package/dist/Cheetah.js +0 -307
- package/dist/default-routes-cheetah.d.ts +0 -3
- package/dist/default-routes-cheetah.js +0 -29
- package/dist/domain/CheetahClosure.d.ts +0 -1
- package/dist/domain/CheetahMiddleware.d.ts +0 -5
- package/dist/domain/CheetahMiddleware.js +0 -2
- package/dist/services/request-logger.service.d.ts +0 -15
- package/dist/services/request-logger.service.js +0 -50
- package/dist/utils/isClassValidator.d.ts +0 -6
- package/dist/utils/isClassValidator.js +0 -13
- /package/dist/domain/{CheetahClosure.js → BaseContext.js} +0 -0
package/dist/domain/Context.js
CHANGED
|
@@ -15,144 +15,165 @@ const http_code_enum_1 = require("../commons/http-code.enum");
|
|
|
15
15
|
const Injectable_decorator_1 = require("../commons/decorators/Injectable.decorator");
|
|
16
16
|
const HttpException_1 = require("../exceptions/HttpException");
|
|
17
17
|
const provider_scope_1 = require("./provider-scope");
|
|
18
|
+
/**
|
|
19
|
+
* Context otimizado com shape mínimo e lazy loading.
|
|
20
|
+
*
|
|
21
|
+
* Shape fixo mínimo (sempre alocado):
|
|
22
|
+
* - req: Request
|
|
23
|
+
* - param: Record<string, string>
|
|
24
|
+
* - status: number
|
|
25
|
+
*
|
|
26
|
+
* Lazy loading (só aloca quando usado):
|
|
27
|
+
* - query: Record<string, string> (getter lazy)
|
|
28
|
+
* - headers: Headers (getter que retorna req.headers)
|
|
29
|
+
* - body: Record<string, any> (getter lazy)
|
|
30
|
+
* - locals: Record<string, any> (getter lazy)
|
|
31
|
+
* - rawBody: ArrayBuffer (lazy)
|
|
32
|
+
*
|
|
33
|
+
* V8/JSC otimiza shape consistente. Propriedades lazy não quebram
|
|
34
|
+
* monomorfismo porque são getters, não props dinâmicas.
|
|
35
|
+
*/
|
|
18
36
|
let Context = Context_1 = class Context {
|
|
19
37
|
constructor() {
|
|
20
|
-
this.
|
|
21
|
-
this.
|
|
22
|
-
this.
|
|
23
|
-
this.
|
|
24
|
-
this.locals = {};
|
|
25
|
-
this._pendingRequest = null;
|
|
38
|
+
this._query = null;
|
|
39
|
+
this._locals = null;
|
|
40
|
+
this._body = null;
|
|
41
|
+
this._rawBody = null;
|
|
26
42
|
this._bodyParsed = false;
|
|
43
|
+
this.req = undefined;
|
|
44
|
+
this.param = {};
|
|
45
|
+
this.status = 200;
|
|
46
|
+
}
|
|
47
|
+
get headers() {
|
|
48
|
+
return this.req.headers;
|
|
49
|
+
}
|
|
50
|
+
get query() {
|
|
51
|
+
if (this._query === null) {
|
|
52
|
+
this._query = this.parseQueryString();
|
|
53
|
+
}
|
|
54
|
+
return this._query;
|
|
55
|
+
}
|
|
56
|
+
set query(value) {
|
|
57
|
+
this._query = value;
|
|
58
|
+
}
|
|
59
|
+
get locals() {
|
|
60
|
+
if (this._locals === null) {
|
|
61
|
+
this._locals = {};
|
|
62
|
+
}
|
|
63
|
+
return this._locals;
|
|
64
|
+
}
|
|
65
|
+
set locals(value) {
|
|
66
|
+
this._locals = value;
|
|
27
67
|
}
|
|
28
68
|
get body() {
|
|
69
|
+
if (this._body === null) {
|
|
70
|
+
return {};
|
|
71
|
+
}
|
|
29
72
|
return this._body;
|
|
30
73
|
}
|
|
31
74
|
set body(value) {
|
|
32
75
|
this._body = value;
|
|
33
76
|
this._bodyParsed = true;
|
|
34
77
|
}
|
|
78
|
+
get rawBody() {
|
|
79
|
+
return this._rawBody ?? undefined;
|
|
80
|
+
}
|
|
81
|
+
set rawBody(value) {
|
|
82
|
+
this._rawBody = value ?? null;
|
|
83
|
+
}
|
|
35
84
|
async getBody() {
|
|
36
|
-
if (!this._bodyParsed
|
|
37
|
-
await this.
|
|
38
|
-
this._pendingRequest = null;
|
|
39
|
-
this._bodyParsed = true;
|
|
85
|
+
if (!this._bodyParsed) {
|
|
86
|
+
await this.parseBody();
|
|
40
87
|
}
|
|
41
|
-
return this._body;
|
|
88
|
+
return this._body ?? {};
|
|
42
89
|
}
|
|
43
90
|
isBodyParsed() {
|
|
44
91
|
return this._bodyParsed;
|
|
45
92
|
}
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
93
|
+
setResponseStatus(status) {
|
|
94
|
+
this.status = status;
|
|
95
|
+
}
|
|
96
|
+
getResponseStatus() {
|
|
97
|
+
return this.status;
|
|
98
|
+
}
|
|
99
|
+
setParam(param) {
|
|
100
|
+
this.param = param;
|
|
52
101
|
}
|
|
53
102
|
static createFromRequestSync(url, request, server) {
|
|
54
|
-
const
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
if (
|
|
60
|
-
|
|
103
|
+
const ctx = new Context_1();
|
|
104
|
+
ctx.req = request;
|
|
105
|
+
ctx.param = {};
|
|
106
|
+
ctx._queryString = url.query;
|
|
107
|
+
const method = request.method;
|
|
108
|
+
if (method !== 'GET' && method !== 'HEAD') {
|
|
109
|
+
ctx._bodyParsed = false;
|
|
61
110
|
}
|
|
62
111
|
else {
|
|
63
|
-
|
|
112
|
+
ctx._bodyParsed = true;
|
|
64
113
|
}
|
|
65
|
-
return
|
|
114
|
+
return ctx;
|
|
66
115
|
}
|
|
67
|
-
static async
|
|
68
|
-
const
|
|
69
|
-
if (
|
|
70
|
-
await
|
|
116
|
+
static async createFromRequest(url, request, server) {
|
|
117
|
+
const ctx = Context_1.createFromRequestSync(url, request, server);
|
|
118
|
+
if (!ctx._bodyParsed) {
|
|
119
|
+
await ctx.getBody();
|
|
71
120
|
}
|
|
72
|
-
return
|
|
121
|
+
return ctx;
|
|
73
122
|
}
|
|
74
123
|
static createFromJob(job) {
|
|
75
|
-
|
|
76
|
-
return context;
|
|
77
|
-
}
|
|
78
|
-
// @ts-ignore
|
|
79
|
-
setQuery({ query }) {
|
|
80
|
-
this.query = this.buildQueryObject(query);
|
|
124
|
+
return new Context_1();
|
|
81
125
|
}
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
126
|
+
parseQueryString() {
|
|
127
|
+
if (!this._queryString) {
|
|
128
|
+
return {};
|
|
85
129
|
}
|
|
130
|
+
return Object.fromEntries(new URLSearchParams(this._queryString));
|
|
86
131
|
}
|
|
87
|
-
|
|
88
|
-
this.
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
}
|
|
93
|
-
setParam(param) {
|
|
94
|
-
this.param = param;
|
|
95
|
-
}
|
|
96
|
-
setResponseStatus(status) {
|
|
97
|
-
this.resultStatus = status;
|
|
98
|
-
}
|
|
99
|
-
getResponseStatus() {
|
|
100
|
-
return this.resultStatus;
|
|
101
|
-
}
|
|
102
|
-
buildQueryObject(query) {
|
|
103
|
-
return query ? Object.fromEntries(new URLSearchParams(query)) : {};
|
|
104
|
-
}
|
|
105
|
-
async resolveBody(request) {
|
|
106
|
-
const contentType = request.headers.get('content-type') || '';
|
|
107
|
-
// Clone request once - preserve original request untouched
|
|
108
|
-
const clonedRequest = request.clone();
|
|
109
|
-
// FormData multipart requires consuming as formData
|
|
110
|
-
if (contentType.includes('multipart/form-data')) {
|
|
111
|
-
// Need separate clone for rawBody since formData() consumes the body
|
|
112
|
-
this.rawBody = await request.clone().arrayBuffer();
|
|
113
|
-
this.setBody(await clonedRequest.formData());
|
|
132
|
+
async parseBody() {
|
|
133
|
+
this._bodyParsed = true;
|
|
134
|
+
const contentType = this.req.headers.get('content-type') ?? '';
|
|
135
|
+
if (contentType.includes('application/json')) {
|
|
136
|
+
this._body = await this.parseJsonBody();
|
|
114
137
|
return;
|
|
115
138
|
}
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
if (contentType.includes('application/json')) {
|
|
119
|
-
this._body = this.parseJsonFromBuffer(this.rawBody);
|
|
139
|
+
if (contentType.includes('multipart/form-data')) {
|
|
140
|
+
this._body = await this.parseFormDataBody();
|
|
120
141
|
return;
|
|
121
142
|
}
|
|
122
143
|
if (contentType.includes('application/x-www-form-urlencoded')) {
|
|
123
|
-
this._body = this.
|
|
144
|
+
this._body = await this.parseUrlEncodedBody();
|
|
124
145
|
return;
|
|
125
146
|
}
|
|
126
|
-
|
|
127
|
-
this._body = { body: this.decodeBuffer(this.rawBody) };
|
|
147
|
+
this._body = {};
|
|
128
148
|
}
|
|
129
|
-
|
|
130
|
-
|
|
149
|
+
async parseJsonBody() {
|
|
150
|
+
const contentLength = this.req.headers.get('content-length');
|
|
151
|
+
if (contentLength === '0') {
|
|
131
152
|
return {};
|
|
132
153
|
}
|
|
133
|
-
return this.parseJsonText(this.decodeBuffer(buffer));
|
|
134
|
-
}
|
|
135
|
-
parseJsonText(text) {
|
|
136
154
|
try {
|
|
137
|
-
|
|
155
|
+
const payload = await this.req.json();
|
|
156
|
+
return payload;
|
|
138
157
|
}
|
|
139
158
|
catch {
|
|
140
|
-
throw new HttpException_1.HttpException(
|
|
159
|
+
throw new HttpException_1.HttpException('Invalid JSON body', http_code_enum_1.HttpCode.BAD_REQUEST);
|
|
141
160
|
}
|
|
142
161
|
}
|
|
143
|
-
|
|
144
|
-
|
|
162
|
+
async parseFormDataBody() {
|
|
163
|
+
const formData = await this.req.formData();
|
|
164
|
+
const result = {};
|
|
165
|
+
for (const [key, value] of formData.entries()) {
|
|
166
|
+
result[key] = value;
|
|
167
|
+
}
|
|
168
|
+
return result;
|
|
145
169
|
}
|
|
146
|
-
|
|
147
|
-
|
|
170
|
+
async parseUrlEncodedBody() {
|
|
171
|
+
const text = await this.req.text();
|
|
172
|
+
if (!text) {
|
|
148
173
|
return {};
|
|
149
174
|
}
|
|
150
|
-
const text = this.decodeBuffer(buffer);
|
|
151
175
|
return Object.fromEntries(new URLSearchParams(text));
|
|
152
176
|
}
|
|
153
|
-
decodeBuffer(buffer) {
|
|
154
|
-
return new TextDecoder().decode(buffer);
|
|
155
|
-
}
|
|
156
177
|
};
|
|
157
178
|
exports.Context = Context;
|
|
158
179
|
exports.Context = Context = Context_1 = __decorate([
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { BaseContext } from './BaseContext';
|
|
2
|
+
/**
|
|
3
|
+
* FastContext - Contexto mínimo monomórfico para fast path.
|
|
4
|
+
*
|
|
5
|
+
* Shape fixo otimizado para V8/JSC JIT:
|
|
6
|
+
* - Apenas 3 propriedades diretas: req, param, status
|
|
7
|
+
* - Lazy getters para headers e query (zero alocação se não usados)
|
|
8
|
+
* - Sem locals, sem body, sem flags extras
|
|
9
|
+
* - Monomórfico: sempre mesmo shape, JIT otimiza agressivamente
|
|
10
|
+
*
|
|
11
|
+
* Usado quando:
|
|
12
|
+
* - Rota SIMPLE (RouteType.SIMPLE)
|
|
13
|
+
* - Sem middlewares
|
|
14
|
+
* - Sem DI
|
|
15
|
+
* - Sem body parsing
|
|
16
|
+
*/
|
|
17
|
+
export declare class FastContext implements BaseContext {
|
|
18
|
+
readonly req: Request;
|
|
19
|
+
param: Record<string, string>;
|
|
20
|
+
status: number;
|
|
21
|
+
private _query;
|
|
22
|
+
private _queryString;
|
|
23
|
+
constructor(req: Request, param: Record<string, string>, queryString: string | undefined);
|
|
24
|
+
get headers(): Headers;
|
|
25
|
+
get query(): Record<string, string>;
|
|
26
|
+
setResponseStatus(status: number): void;
|
|
27
|
+
getResponseStatus(): number;
|
|
28
|
+
private parseQueryString;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Factory otimizado para criar FastContext.
|
|
32
|
+
* Extrai queryString inline sem overhead de parseUrl.
|
|
33
|
+
*/
|
|
34
|
+
export declare function createFastContext(req: Request, param: Record<string, string>, url: string): FastContext;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.FastContext = void 0;
|
|
4
|
+
exports.createFastContext = createFastContext;
|
|
5
|
+
/**
|
|
6
|
+
* FastContext - Contexto mínimo monomórfico para fast path.
|
|
7
|
+
*
|
|
8
|
+
* Shape fixo otimizado para V8/JSC JIT:
|
|
9
|
+
* - Apenas 3 propriedades diretas: req, param, status
|
|
10
|
+
* - Lazy getters para headers e query (zero alocação se não usados)
|
|
11
|
+
* - Sem locals, sem body, sem flags extras
|
|
12
|
+
* - Monomórfico: sempre mesmo shape, JIT otimiza agressivamente
|
|
13
|
+
*
|
|
14
|
+
* Usado quando:
|
|
15
|
+
* - Rota SIMPLE (RouteType.SIMPLE)
|
|
16
|
+
* - Sem middlewares
|
|
17
|
+
* - Sem DI
|
|
18
|
+
* - Sem body parsing
|
|
19
|
+
*/
|
|
20
|
+
class FastContext {
|
|
21
|
+
constructor(req, param, queryString) {
|
|
22
|
+
this.req = req;
|
|
23
|
+
this.param = param;
|
|
24
|
+
this.status = 200;
|
|
25
|
+
this._query = null;
|
|
26
|
+
this._queryString = queryString;
|
|
27
|
+
}
|
|
28
|
+
get headers() {
|
|
29
|
+
return this.req.headers;
|
|
30
|
+
}
|
|
31
|
+
get query() {
|
|
32
|
+
if (this._query === null) {
|
|
33
|
+
this._query = this.parseQueryString();
|
|
34
|
+
}
|
|
35
|
+
return this._query;
|
|
36
|
+
}
|
|
37
|
+
setResponseStatus(status) {
|
|
38
|
+
this.status = status;
|
|
39
|
+
}
|
|
40
|
+
getResponseStatus() {
|
|
41
|
+
return this.status;
|
|
42
|
+
}
|
|
43
|
+
parseQueryString() {
|
|
44
|
+
if (!this._queryString) {
|
|
45
|
+
return {};
|
|
46
|
+
}
|
|
47
|
+
return Object.fromEntries(new URLSearchParams(this._queryString));
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
exports.FastContext = FastContext;
|
|
51
|
+
/**
|
|
52
|
+
* Factory otimizado para criar FastContext.
|
|
53
|
+
* Extrai queryString inline sem overhead de parseUrl.
|
|
54
|
+
*/
|
|
55
|
+
function createFastContext(req, param, url) {
|
|
56
|
+
const queryIdx = url.indexOf('?');
|
|
57
|
+
const queryString = queryIdx !== -1 ? url.slice(queryIdx + 1) : undefined;
|
|
58
|
+
return new FastContext(req, param, queryString);
|
|
59
|
+
}
|
|
@@ -8,8 +8,10 @@ export declare class CorsHeadersCache {
|
|
|
8
8
|
private readonly maxAgeString;
|
|
9
9
|
private readonly hasCredentials;
|
|
10
10
|
private readonly isWildcard;
|
|
11
|
+
private readonly originAllowed;
|
|
11
12
|
constructor(config: CorsConfig);
|
|
12
13
|
get(origin: string): Record<string, string>;
|
|
13
14
|
private buildHeaders;
|
|
14
15
|
applyToResponse(response: Response, origin: string): Response;
|
|
16
|
+
isOriginAllowed(origin: string): boolean;
|
|
15
17
|
}
|
|
@@ -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;
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -29,3 +29,4 @@ __exportStar(require("./services/logger.service"), exports);
|
|
|
29
29
|
__exportStar(require("./cache/cache.service"), exports);
|
|
30
30
|
__exportStar(require("./cache/bento-cache.driver"), exports);
|
|
31
31
|
__exportStar(require("./testing"), exports);
|
|
32
|
+
__exportStar(require("./validation"), exports);
|
|
@@ -1,4 +1,12 @@
|
|
|
1
1
|
import type { Context } from '../domain/Context';
|
|
2
2
|
import type { CompiledRoute } from './CompiledRoute';
|
|
3
|
-
|
|
4
|
-
|
|
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.
|
|
4
|
-
exports.
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
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 (
|
|
10
|
-
return
|
|
25
|
+
if (result instanceof Response) {
|
|
26
|
+
return result;
|
|
11
27
|
}
|
|
12
|
-
|
|
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
|
-
|
|
15
|
-
|
|
16
|
-
|
|
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
|
|
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
|
-
|
|
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;
|