@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.
Files changed (60) hide show
  1. package/dist/Carno.d.ts +10 -8
  2. package/dist/Carno.js +31 -33
  3. package/dist/commons/decorators/index.d.ts +1 -0
  4. package/dist/commons/decorators/index.js +1 -0
  5. package/dist/commons/decorators/validation.decorator.d.ts +32 -0
  6. package/dist/commons/decorators/validation.decorator.js +40 -0
  7. package/dist/constants.d.ts +1 -0
  8. package/dist/constants.js +2 -1
  9. package/dist/container/InjectorService.d.ts +3 -1
  10. package/dist/container/InjectorService.js +4 -3
  11. package/dist/container/MethodInvoker.d.ts +3 -2
  12. package/dist/container/MethodInvoker.js +4 -17
  13. package/dist/container/middleware.resolver.js +6 -6
  14. package/dist/domain/BaseContext.d.ts +15 -0
  15. package/dist/domain/Context.d.ts +45 -24
  16. package/dist/domain/Context.js +110 -89
  17. package/dist/domain/FastContext.d.ts +34 -0
  18. package/dist/domain/FastContext.js +59 -0
  19. package/dist/domain/cors-headers-cache.d.ts +2 -0
  20. package/dist/domain/cors-headers-cache.js +44 -0
  21. package/dist/index.d.ts +1 -0
  22. package/dist/index.js +1 -0
  23. package/dist/route/FastPathExecutor.d.ts +10 -2
  24. package/dist/route/FastPathExecutor.js +43 -12
  25. package/dist/route/JITCompiler.d.ts +25 -1
  26. package/dist/route/JITCompiler.js +205 -98
  27. package/dist/route/ParamResolverFactory.d.ts +0 -5
  28. package/dist/route/ParamResolverFactory.js +0 -40
  29. package/dist/route/RouteCompiler.d.ts +3 -4
  30. package/dist/route/RouteCompiler.js +2 -54
  31. package/dist/route/RouteExecutor.js +18 -1
  32. package/dist/route/memoirist.d.ts +3 -0
  33. package/dist/route/memoirist.js +33 -3
  34. package/dist/utils/ValidationCache.d.ts +2 -0
  35. package/dist/utils/ValidationCache.js +10 -2
  36. package/dist/utils/index.d.ts +0 -1
  37. package/dist/utils/index.js +0 -1
  38. package/dist/validation/ValidatorAdapter.d.ts +66 -0
  39. package/dist/validation/ValidatorAdapter.js +20 -0
  40. package/dist/validation/adapters/ClassValidatorAdapter.d.ts +23 -0
  41. package/dist/validation/adapters/ClassValidatorAdapter.js +47 -0
  42. package/dist/validation/adapters/ZodAdapter.d.ts +14 -0
  43. package/dist/validation/adapters/ZodAdapter.js +56 -0
  44. package/dist/validation/adapters/index.d.ts +4 -0
  45. package/dist/validation/adapters/index.js +7 -0
  46. package/dist/validation/index.d.ts +3 -0
  47. package/dist/validation/index.js +20 -0
  48. package/package.json +17 -6
  49. package/dist/Cheetah.d.ts +0 -65
  50. package/dist/Cheetah.js +0 -307
  51. package/dist/default-routes-cheetah.d.ts +0 -3
  52. package/dist/default-routes-cheetah.js +0 -29
  53. package/dist/domain/CheetahClosure.d.ts +0 -1
  54. package/dist/domain/CheetahMiddleware.d.ts +0 -5
  55. package/dist/domain/CheetahMiddleware.js +0 -2
  56. package/dist/services/request-logger.service.d.ts +0 -15
  57. package/dist/services/request-logger.service.js +0 -50
  58. package/dist/utils/isClassValidator.d.ts +0 -6
  59. package/dist/utils/isClassValidator.js +0 -13
  60. /package/dist/domain/{CheetahClosure.js → BaseContext.js} +0 -0
package/dist/Carno.d.ts CHANGED
@@ -1,27 +1,29 @@
1
1
  import { Server } from "bun";
2
- import { ValidatorOptions } from "class-validator";
3
2
  import * as pino from "pino";
3
+ import type { ValidationConfig, ValidatorAdapterConstructor } from "./validation/ValidatorAdapter";
4
4
  import { TokenRouteWithProvider } from "./container/ContainerConfiguration";
5
5
  import { CorsConfig } from "./domain/cors-config";
6
6
  import Memoirist from "./route/memoirist";
7
7
  import { type CompiledRoute } from "./route/CompiledRoute";
8
- export interface ApplicationConfig {
9
- validation?: ValidatorOptions;
8
+ export interface ApplicationConfig<TAdapter extends ValidatorAdapterConstructor = ValidatorAdapterConstructor> {
9
+ validation?: ValidationConfig<TAdapter>;
10
10
  logger?: pino.LoggerOptions;
11
11
  exports?: any[];
12
12
  providers?: any[];
13
13
  cors?: CorsConfig;
14
14
  globalMiddlewares?: any[];
15
15
  }
16
- export declare class Carno {
17
- config: ApplicationConfig;
16
+ export declare class Carno<TAdapter extends ValidatorAdapterConstructor = ValidatorAdapterConstructor> {
17
+ config: ApplicationConfig<TAdapter>;
18
18
  router: Memoirist<CompiledRoute | TokenRouteWithProvider>;
19
19
  private injector;
20
20
  private corsCache?;
21
21
  private readonly emptyLocals;
22
+ private validatorAdapter;
22
23
  private fetch;
23
24
  private server;
24
- constructor(config?: ApplicationConfig);
25
+ constructor(config?: ApplicationConfig<TAdapter>);
26
+ private resolveValidatorAdapter;
25
27
  /**
26
28
  * Use the Carno plugin.
27
29
  *
@@ -49,7 +51,7 @@ export declare class Carno {
49
51
  listen(port?: number): Promise<void>;
50
52
  private registerShutdownHandlers;
51
53
  getHttpServer(): Server<any>;
52
- getInjector(): import(".").InjectorService;
54
+ getInjector(): import("./container").InjectorService;
53
55
  private createHttpServer;
54
56
  private fetcher;
55
57
  private catcher;
@@ -58,8 +60,8 @@ export declare class Carno {
58
60
  private closeHttpServer;
59
61
  private exitProcess;
60
62
  private reportHookFailure;
63
+ private resolveLogger;
61
64
  private isCorsEnabled;
62
- private isOriginAllowed;
63
65
  private handlePreflightRequest;
64
66
  private applyCorsHeaders;
65
67
  close(closeActiveConnections?: boolean): void;
package/dist/Carno.js CHANGED
@@ -5,6 +5,8 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.Carno = void 0;
7
7
  const node_process_1 = __importDefault(require("node:process"));
8
+ const ZodAdapter_1 = require("./validation/adapters/ZodAdapter");
9
+ const ValidationCache_1 = require("./utils/ValidationCache");
8
10
  const index_1 = require("./commons/index");
9
11
  const constants_1 = require("./constants");
10
12
  const createContainer_1 = require("./container/createContainer");
@@ -18,10 +20,8 @@ const HttpException_1 = require("./exceptions/HttpException");
18
20
  const RouteExecutor_1 = require("./route/RouteExecutor");
19
21
  const memoirist_1 = __importDefault(require("./route/memoirist"));
20
22
  const CompiledRoute_1 = require("./route/CompiledRoute");
21
- const FastPathExecutor_1 = require("./route/FastPathExecutor");
22
23
  const logger_service_1 = require("./services/logger.service");
23
24
  const parseUrl = require("parseurl-fast");
24
- // todo: change console.log for LoggerService.
25
25
  class Carno {
26
26
  constructor(config = {}) {
27
27
  this.config = config;
@@ -43,7 +43,7 @@ class Carno {
43
43
  });
44
44
  if (this.isCorsEnabled()) {
45
45
  const origin = request.headers.get("origin");
46
- if (origin && this.isOriginAllowed(origin)) {
46
+ if (origin && this.corsCache.isOriginAllowed(origin)) {
47
47
  response = this.applyCorsHeaders(response, origin);
48
48
  }
49
49
  }
@@ -53,14 +53,24 @@ class Carno {
53
53
  }
54
54
  };
55
55
  this.catcher = (error) => {
56
- console.error("Unhandled error:", error);
56
+ this.resolveLogger().error("Unhandled error", error);
57
57
  return new Response("Internal Server Error", { status: 500 });
58
58
  };
59
+ this.validatorAdapter = this.resolveValidatorAdapter();
59
60
  if (config.cors) {
60
61
  this.corsCache = new cors_headers_cache_1.CorsHeadersCache(config.cors);
61
62
  }
62
63
  void this.bootstrapApplication();
63
64
  }
65
+ resolveValidatorAdapter() {
66
+ const config = this.config.validation;
67
+ if (!config?.adapter) {
68
+ return new ZodAdapter_1.ZodAdapter();
69
+ }
70
+ const AdapterClass = config.adapter;
71
+ const options = config.options || {};
72
+ return new AdapterClass(options);
73
+ }
64
74
  /**
65
75
  * Use the Carno plugin.
66
76
  *
@@ -148,8 +158,9 @@ class Carno {
148
158
  };
149
159
  }
150
160
  async init() {
161
+ (0, ValidationCache_1.setValidatorAdapter)(this.validatorAdapter);
151
162
  this.loadProvidersAndControllers();
152
- await this.injector.loadModule((0, createContainer_1.createContainer)(), this.config, this.router);
163
+ await this.injector.loadModule((0, createContainer_1.createContainer)(), this.config, this.router, this.validatorAdapter);
153
164
  }
154
165
  async listen(port = 3000) {
155
166
  this.registerShutdownHandlers();
@@ -158,7 +169,7 @@ class Carno {
158
169
  }
159
170
  registerShutdownHandlers() {
160
171
  const shutdown = async (signal) => {
161
- console.log(`\nReceived ${signal}, starting graceful shutdown...`);
172
+ this.resolveLogger().info(`Received ${signal}, starting graceful shutdown...`);
162
173
  await this.handleShutdownHook();
163
174
  };
164
175
  node_process_1.default.on("SIGTERM", () => shutdown("SIGTERM"));
@@ -172,7 +183,7 @@ class Carno {
172
183
  }
173
184
  createHttpServer(port) {
174
185
  this.server = Bun.serve({ port, fetch: this.fetch, error: this.catcher });
175
- console.log(`Server running on port ${port}`);
186
+ this.resolveLogger().info(`Server running on port ${port}`);
176
187
  }
177
188
  async fetcher(request, server) {
178
189
  if (this.isCorsEnabled()) {
@@ -193,8 +204,9 @@ class Carno {
193
204
  let response;
194
205
  const isCompiledRoute = compiled.routeType !== undefined;
195
206
  if (isCompiledRoute && compiled.routeType === CompiledRoute_1.RouteType.SIMPLE) {
196
- const result = await (0, FastPathExecutor_1.executeSimpleRoute)(compiled, context);
197
- response = RouteExecutor_1.RouteExecutor.mountResponse(result, context);
207
+ response = compiled.isAsync
208
+ ? await compiled.boundHandler(context)
209
+ : compiled.boundHandler(context);
198
210
  }
199
211
  else {
200
212
  const needsLocalsContainer = isCompiledRoute
@@ -208,7 +220,7 @@ class Carno {
208
220
  }
209
221
  if (this.isCorsEnabled()) {
210
222
  const origin = request.headers.get("origin");
211
- if (origin && this.isOriginAllowed(origin)) {
223
+ if (origin && this.corsCache.isOriginAllowed(origin)) {
212
224
  response = this.applyCorsHeaders(response, origin);
213
225
  }
214
226
  }
@@ -235,42 +247,28 @@ class Carno {
235
247
  }
236
248
  closeHttpServer() {
237
249
  if (this.server) {
238
- console.log("Closing HTTP server...");
250
+ this.resolveLogger().info("Closing HTTP server...");
239
251
  this.server.stop(true);
240
252
  }
241
253
  }
242
254
  exitProcess(code = 0) {
243
- console.log("Shutdown complete.");
255
+ this.resolveLogger().info("Shutdown complete.");
244
256
  node_process_1.default.exit(code);
245
257
  }
246
258
  reportHookFailure(event, error) {
247
- console.error(`Lifecycle hook ${event} failed`, error);
259
+ this.resolveLogger().error(`Lifecycle hook ${event} failed`, error);
260
+ }
261
+ resolveLogger() {
262
+ const provider = this.injector.get(logger_service_1.LoggerService);
263
+ const instance = provider?.instance;
264
+ return instance ?? new logger_service_1.LoggerService(this.injector);
248
265
  }
249
266
  isCorsEnabled() {
250
267
  return !!this.config.cors;
251
268
  }
252
- isOriginAllowed(origin) {
253
- if (!origin || !this.config.cors) {
254
- return false;
255
- }
256
- const { origins } = this.config.cors;
257
- if (typeof origins === "string") {
258
- return origins === "*" || origins === origin;
259
- }
260
- if (Array.isArray(origins)) {
261
- return origins.includes(origin);
262
- }
263
- if (origins instanceof RegExp) {
264
- return origins.test(origin);
265
- }
266
- if (typeof origins === "function") {
267
- return origins(origin);
268
- }
269
- return false;
270
- }
271
269
  handlePreflightRequest(request) {
272
270
  const origin = request.headers.get("origin");
273
- if (!this.isOriginAllowed(origin)) {
271
+ if (!origin || !this.corsCache.isOriginAllowed(origin)) {
274
272
  return new Response(null, { status: 403 });
275
273
  }
276
274
  const corsHeaders = this.corsCache.get(origin);
@@ -3,3 +3,4 @@ export * from './http.decorators';
3
3
  export * from './service.decorator';
4
4
  export * from './middleware.decorator';
5
5
  export * from './Injectable.decorator';
6
+ export * from './validation.decorator';
@@ -19,3 +19,4 @@ __exportStar(require("./http.decorators"), exports);
19
19
  __exportStar(require("./service.decorator"), exports);
20
20
  __exportStar(require("./middleware.decorator"), exports);
21
21
  __exportStar(require("./Injectable.decorator"), exports);
22
+ __exportStar(require("./validation.decorator"), exports);
@@ -0,0 +1,32 @@
1
+ import { z } from "zod";
2
+ /**
3
+ * Decorator to attach a Zod schema to a DTO class
4
+ * The schema will be used for validation when the DTO is used in route handlers
5
+ *
6
+ * @example
7
+ * ```typescript
8
+ * const CreateUserSchema = z.object({
9
+ * name: z.string().min(3),
10
+ * email: z.string().email()
11
+ * });
12
+ *
13
+ * @ZodSchema(CreateUserSchema)
14
+ * class CreateUserDto {
15
+ * name: string;
16
+ * email: string;
17
+ * }
18
+ *
19
+ * @Controller('/users')
20
+ * class UserController {
21
+ * @Post()
22
+ * create(@Body() dto: CreateUserDto) {
23
+ * // dto is validated and typed
24
+ * return dto;
25
+ * }
26
+ * }
27
+ * ```
28
+ *
29
+ * @param schema - The Zod schema to use for validation
30
+ * @returns Class decorator
31
+ */
32
+ export declare function ZodSchema<T extends z.ZodType>(schema: T): ClassDecorator;
@@ -0,0 +1,40 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ZodSchema = ZodSchema;
4
+ const Metadata_1 = require("../../domain/Metadata");
5
+ const constants_1 = require("../../constants");
6
+ /**
7
+ * Decorator to attach a Zod schema to a DTO class
8
+ * The schema will be used for validation when the DTO is used in route handlers
9
+ *
10
+ * @example
11
+ * ```typescript
12
+ * const CreateUserSchema = z.object({
13
+ * name: z.string().min(3),
14
+ * email: z.string().email()
15
+ * });
16
+ *
17
+ * @ZodSchema(CreateUserSchema)
18
+ * class CreateUserDto {
19
+ * name: string;
20
+ * email: string;
21
+ * }
22
+ *
23
+ * @Controller('/users')
24
+ * class UserController {
25
+ * @Post()
26
+ * create(@Body() dto: CreateUserDto) {
27
+ * // dto is validated and typed
28
+ * return dto;
29
+ * }
30
+ * }
31
+ * ```
32
+ *
33
+ * @param schema - The Zod schema to use for validation
34
+ * @returns Class decorator
35
+ */
36
+ function ZodSchema(schema) {
37
+ return (target) => {
38
+ Metadata_1.Metadata.set(constants_1.VALIDATION_ZOD_SCHEMA, schema, target);
39
+ };
40
+ }
@@ -5,3 +5,4 @@ export declare const CONTROLLER_EVENTS = "carno:controller:events";
5
5
  export declare const ROUTE_PARAM = "carno:route:param";
6
6
  export declare const ROUTE_MIDDLEWARES = "carno:route:middlewares";
7
7
  export declare const PROVIDER = "carno:provider";
8
+ export declare const VALIDATION_ZOD_SCHEMA = "carno:validation:zod";
package/dist/constants.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.PROVIDER = exports.ROUTE_MIDDLEWARES = exports.ROUTE_PARAM = exports.CONTROLLER_EVENTS = exports.CONTROLLER_MIDDLEWARES = exports.CONTROLLER_ROUTES = exports.CONTROLLER = void 0;
3
+ exports.VALIDATION_ZOD_SCHEMA = exports.PROVIDER = exports.ROUTE_MIDDLEWARES = exports.ROUTE_PARAM = exports.CONTROLLER_EVENTS = exports.CONTROLLER_MIDDLEWARES = exports.CONTROLLER_ROUTES = exports.CONTROLLER = void 0;
4
4
  exports.CONTROLLER = "carno:controller";
5
5
  exports.CONTROLLER_ROUTES = "carno:controller:routes";
6
6
  exports.CONTROLLER_MIDDLEWARES = "carno:controller:middlewares";
@@ -8,3 +8,4 @@ exports.CONTROLLER_EVENTS = "carno:controller:events";
8
8
  exports.ROUTE_PARAM = "carno:route:param";
9
9
  exports.ROUTE_MIDDLEWARES = "carno:route:middlewares";
10
10
  exports.PROVIDER = "carno:provider";
11
+ exports.VALIDATION_ZOD_SCHEMA = "carno:validation:zod";
@@ -1,5 +1,6 @@
1
1
  import type { ApplicationConfig } from "../Carno";
2
2
  import { TokenProvider } from "../commons/registries/ProviderControl";
3
+ import type { ValidatorAdapter } from "../validation/ValidatorAdapter";
3
4
  import { Context } from "../domain/Context";
4
5
  import { LocalsContainer } from "../domain/LocalsContainer";
5
6
  import { Provider } from "../domain/provider";
@@ -20,7 +21,8 @@ export declare class InjectorService {
20
21
  private routeResolver;
21
22
  private dependencyResolver;
22
23
  private methodInvoker;
23
- loadModule(container: Container, applicationConfig: ApplicationConfig, router: Memoirist<any>): Promise<void>;
24
+ private validatorAdapter;
25
+ loadModule(container: Container, applicationConfig: ApplicationConfig, router: Memoirist<any>, validatorAdapter: ValidatorAdapter): Promise<void>;
24
26
  private initializeResolvers;
25
27
  private ensureProvider;
26
28
  get(token: TokenProvider): Provider | undefined;
@@ -40,10 +40,11 @@ let InjectorService = InjectorService_1 = class InjectorService {
40
40
  this._hasOnResponseHook = false;
41
41
  this.controllerScopes = new Map();
42
42
  }
43
- async loadModule(container, applicationConfig, router) {
43
+ async loadModule(container, applicationConfig, router, validatorAdapter) {
44
44
  this.container = container;
45
45
  this.router = router;
46
46
  this.applicationConfig = applicationConfig;
47
+ this.validatorAdapter = validatorAdapter;
47
48
  this.initializeResolvers();
48
49
  this.removeUnknownProviders();
49
50
  this.saveInjector();
@@ -57,7 +58,7 @@ let InjectorService = InjectorService_1 = class InjectorService {
57
58
  initializeResolvers() {
58
59
  this.routeResolver = new RouteResolver_1.RouteResolver(this.router, this.applicationConfig.globalMiddlewares);
59
60
  this.dependencyResolver = new DependencyResolver_1.DependencyResolver(this.container);
60
- this.methodInvoker = new MethodInvoker_1.MethodInvoker(this.applicationConfig);
61
+ this.methodInvoker = new MethodInvoker_1.MethodInvoker(this.applicationConfig, this.validatorAdapter);
61
62
  }
62
63
  ensureProvider(token) {
63
64
  if (!this.container.has(token) && ProviderControl_1.GlobalProvider.has(token)) {
@@ -175,7 +176,7 @@ let InjectorService = InjectorService_1 = class InjectorService {
175
176
  const compiler = new RouteCompiler_1.RouteCompiler({
176
177
  container: this.container,
177
178
  controllerScopes: this.controllerScopes,
178
- validationConfig: this.applicationConfig.validation,
179
+ validatorAdapter: this.validatorAdapter,
179
180
  hasOnRequestHook: this._hasOnRequestHook,
180
181
  hasOnResponseHook: this._hasOnResponseHook,
181
182
  });
@@ -2,10 +2,12 @@ import { ApplicationConfig } from "../Carno";
2
2
  import { TokenProvider } from "../commons/registries/ProviderControl";
3
3
  import { Context } from "../domain/Context";
4
4
  import { LocalsContainer } from "../domain/LocalsContainer";
5
+ import type { ValidatorAdapter } from "../validation/ValidatorAdapter";
5
6
  export declare class MethodInvoker {
6
7
  private applicationConfig;
8
+ private validatorAdapter;
7
9
  private historyMethods;
8
- constructor(applicationConfig: ApplicationConfig);
10
+ constructor(applicationConfig: ApplicationConfig, validatorAdapter: ValidatorAdapter);
9
11
  invoke(instance: any, methodName: string, locals: LocalsContainer, context: Context, invokeCallback: (token: TokenProvider, locals: LocalsContainer) => any): Promise<any>;
10
12
  private getMethodInfo;
11
13
  private getCachedMethod;
@@ -16,5 +18,4 @@ export declare class MethodInvoker {
16
18
  private hasBodyParam;
17
19
  private isBodyParam;
18
20
  private resolveService;
19
- private validateAndTransform;
20
21
  }
@@ -1,16 +1,13 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.MethodInvoker = void 0;
4
- const class_transformer_1 = require("class-transformer");
5
- const class_validator_1 = require("class-validator");
6
4
  const Metadata_1 = require("../domain/Metadata");
7
- const HttpException_1 = require("../exceptions/HttpException");
8
5
  const getClassOrSymbol_1 = require("../utils/getClassOrSymbol");
9
6
  const getMethodArgTypes_1 = require("../utils/getMethodArgTypes");
10
- const isClassValidator_1 = require("../utils/isClassValidator");
11
7
  class MethodInvoker {
12
- constructor(applicationConfig) {
8
+ constructor(applicationConfig, validatorAdapter) {
13
9
  this.applicationConfig = applicationConfig;
10
+ this.validatorAdapter = validatorAdapter;
14
11
  this.historyMethods = new WeakMap();
15
12
  }
16
13
  async invoke(instance, methodName, locals, context, invokeCallback) {
@@ -78,19 +75,9 @@ class MethodInvoker {
78
75
  return invokeCallback((0, getClassOrSymbol_1.getClassOrSymbol)(token), locals);
79
76
  }
80
77
  const value = param.fun(context, param.param);
81
- return (0, isClassValidator_1.isClassValidator)(token)
82
- ? this.validateAndTransform(token, value)
78
+ return this.validatorAdapter.hasValidation(token)
79
+ ? this.validatorAdapter.validateAndTransform(token, value)
83
80
  : value;
84
81
  }
85
- validateAndTransform(token, value) {
86
- const obj = (0, class_transformer_1.plainToInstance)(token, value);
87
- const errors = (0, class_validator_1.validateSync)(obj, this.applicationConfig.validation);
88
- // todo: deve retornar apenas os erros e no o objeto class-validator intei
89
- // ro.
90
- if (errors.length > 0) {
91
- throw new HttpException_1.HttpException(errors, 400);
92
- }
93
- return obj;
94
- }
95
82
  }
96
83
  exports.MethodInvoker = MethodInvoker;
@@ -14,21 +14,21 @@ class MiddlewareResolver {
14
14
  let currentIndex = 0;
15
15
  const next = async () => {
16
16
  if (currentIndex >= middlewares.length) {
17
- // Se processamos todos os middlewares, não faz nada.
18
- // Isso evita o erro "Middleware stack exhausted" se um middleware chamar `next()`
19
- // quando não mais middlewares.
17
+ // If all middlewares are already processed, do nothing.
18
+ // This avoids "Middleware stack exhausted" if a middleware calls `next()`
19
+ // when there are no more middlewares.
20
20
  return;
21
21
  }
22
22
  const middleware = middlewares[currentIndex++];
23
23
  // @ts-ignore
24
24
  const instance = injector.invoke(middleware, local);
25
- // Await a execução do middleware.
26
- // Se o middleware lançar uma exceção, ela será propagada.
25
+ // Await the middleware execution.
26
+ // If the middleware throws, the exception will propagate.
27
27
  await instance.handle(context, next);
28
28
  };
29
29
  if (middlewares.length === 0)
30
30
  return;
31
- // Inicia a execução dos middlewares
31
+ // Start the middleware execution
32
32
  await next();
33
33
  }
34
34
  }
@@ -0,0 +1,15 @@
1
+ /**
2
+ * BaseContext - Interface mínima que todo contexto deve implementar.
3
+ *
4
+ * Define o contrato básico para FastContext e Context,
5
+ * permitindo que handlers compilados trabalhem com ambos.
6
+ */
7
+ export interface BaseContext {
8
+ readonly req: Request;
9
+ param: Record<string, string>;
10
+ readonly headers: Headers;
11
+ readonly query: Record<string, string>;
12
+ status: number;
13
+ setResponseStatus(status: number): void;
14
+ getResponseStatus(): number;
15
+ }
@@ -1,36 +1,57 @@
1
1
  import { Server } from 'bun';
2
+ /**
3
+ * Context otimizado com shape mínimo e lazy loading.
4
+ *
5
+ * Shape fixo mínimo (sempre alocado):
6
+ * - req: Request
7
+ * - param: Record<string, string>
8
+ * - status: number
9
+ *
10
+ * Lazy loading (só aloca quando usado):
11
+ * - query: Record<string, string> (getter lazy)
12
+ * - headers: Headers (getter que retorna req.headers)
13
+ * - body: Record<string, any> (getter lazy)
14
+ * - locals: Record<string, any> (getter lazy)
15
+ * - rawBody: ArrayBuffer (lazy)
16
+ *
17
+ * V8/JSC otimiza shape consistente. Propriedades lazy não quebram
18
+ * monomorfismo porque são getters, não props dinâmicas.
19
+ */
2
20
  export declare class Context {
3
- query: Record<string, any>;
4
- private _body;
5
- rawBody?: ArrayBuffer;
6
- param: Record<string, any>;
7
21
  req: Request;
8
- headers: Request["headers"];
9
- locals: Record<string, any>;
10
- private resultStatus;
11
- private _pendingRequest;
22
+ param: Record<string, string>;
23
+ status: number;
24
+ private _queryString;
25
+ private _query;
26
+ private _locals;
27
+ private _body;
28
+ private _rawBody;
12
29
  private _bodyParsed;
13
30
  private constructor();
31
+ get headers(): Headers;
32
+ get query(): Record<string, string>;
33
+ set query(value: Record<string, string>);
34
+ get locals(): Record<string, any>;
35
+ set locals(value: Record<string, any>);
14
36
  get body(): Record<string, any>;
15
37
  set body(value: Record<string, any>);
38
+ get rawBody(): ArrayBuffer | undefined;
39
+ set rawBody(value: ArrayBuffer | undefined);
16
40
  getBody(): Promise<Record<string, any>>;
17
41
  isBodyParsed(): boolean;
18
- static createFromRequest(url: any, request: Request, server: Server<any>): Promise<Context>;
19
- static createFromRequestSync(url: any, request: Request, server: Server<any>): Context;
20
- static createFromRequestWithBody(url: any, request: Request, server: Server<any>): Promise<Context>;
21
- static createFromJob(job: any): Context;
22
- private setQuery;
23
- private setBody;
24
- private setReq;
25
- private setHeaders;
26
- setParam(param: Record<string, any>): void;
27
42
  setResponseStatus(status: number): void;
28
43
  getResponseStatus(): number;
29
- private buildQueryObject;
30
- private resolveBody;
31
- private parseJsonFromBuffer;
32
- private parseJsonText;
33
- private isEmptyBuffer;
34
- private parseUrlEncodedFromBuffer;
35
- private decodeBuffer;
44
+ setParam(param: Record<string, string>): void;
45
+ static createFromRequestSync(url: {
46
+ query?: string;
47
+ }, request: Request, server: Server<any>): Context;
48
+ static createFromRequest(url: {
49
+ query?: string;
50
+ }, request: Request, server: Server<any>): Promise<Context>;
51
+ static createFromJob(job: any): Context;
52
+ private parseQueryString;
53
+ private parseBody;
54
+ private parseJsonBody;
55
+ private parseFormDataBody;
56
+ private parseUrlEncodedBody;
36
57
  }