balda 0.0.13 → 0.0.15

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/lib/index.d.ts CHANGED
@@ -1,17 +1,17 @@
1
- import { schedule, TaskContext } from 'node-cron';
2
- import { ZodType, z } from 'zod';
3
- import { TSchema, Static } from '@sinclair/typebox';
4
- import { Ajv } from 'ajv';
1
+ import { IRouter, RequestHandler, Router as Router$1 } from 'express';
2
+ export { ErrorRequestHandler as ExpressErrorMiddleware, RequestHandler as ExpressMiddleware, NextFunction as ExpressNextFunction, Request as ExpressRequest, Response as ExpressResponse } from 'express';
3
+ import { GraphQLSchema } from 'graphql';
4
+ import { createSchema, createYoga } from 'graphql-yoga';
5
5
  import { ServerResponse, IncomingMessage, Server as Server$2 } from 'node:http';
6
6
  import { Http2Server } from 'node:http2';
7
7
  import { Server as Server$1, ServerOptions as ServerOptions$1 } from 'node:https';
8
8
  export { ServerOptions as HttpsServerOptions } from 'node:https';
9
- import { GraphQLSchema } from 'graphql';
10
- import { createSchema, createYoga } from 'graphql-yoga';
11
- import { RequestHandler, Router as Router$1, IRouter } from 'express';
12
- export { ErrorRequestHandler as ExpressErrorMiddleware, RequestHandler as ExpressMiddleware, NextFunction as ExpressNextFunction, Request as ExpressRequest, Response as ExpressResponse } from 'express';
9
+ import { Ajv } from 'ajv';
10
+ import { ZodType, z } from 'zod';
11
+ import { TSchema, Static } from '@sinclair/typebox';
13
12
  import * as pino from 'pino';
14
13
  import pino__default, { pino as pino$1 } from 'pino';
14
+ import { schedule, TaskContext } from 'node-cron';
15
15
  import { IClientSubscribeOptions, IClientOptions, IClientPublishOptions, MqttClient } from 'mqtt';
16
16
  import { SQSClientConfig, SendMessageCommandInput } from '@aws-sdk/client-sqs';
17
17
  import { Queue, JobsOptions, Job } from 'bullmq';
@@ -19,412 +19,227 @@ import { SendOptions } from 'pg-boss';
19
19
  import { AsyncLocalStorage } from 'node:async_hooks';
20
20
  import { S3Client } from '@aws-sdk/client-s3';
21
21
 
22
- type CronSchedule = {
23
- name: string;
24
- args: Parameters<typeof schedule>;
22
+ type GraphQLSchemaInput = Parameters<typeof createSchema>[0];
23
+ type GraphQLTypeDef = GraphQLSchemaInput["typeDefs"];
24
+ type GraphQLResolvers = GraphQLSchemaInput["resolvers"];
25
+ interface GraphQLContext {
26
+ }
27
+ type GraphQLResolverFunction<TContext = GraphQLContext> = (parent: unknown, args: Record<string, unknown>, context: TContext, info: unknown) => unknown | Promise<unknown>;
28
+ type GraphQLResolverMap<TContext = GraphQLContext> = Record<string, GraphQLResolverFunction<TContext> | Record<string, unknown>>;
29
+ type GraphQLOptions = {
30
+ schema?: GraphQLSchemaInput;
31
+ yogaOptions?: Parameters<typeof createYoga>[0];
25
32
  };
26
- type CronScheduleParams = Parameters<typeof schedule>;
33
+ type GraphQLResolverType = "Query" | "Mutation" | "Subscription";
27
34
 
28
- /**
29
- * Decorator to schedule a cron job. Must be applied to a class method. By default, the cron job will not overlap with other cron jobs of the same type.
30
- * ```ts
31
- * @cron('* * * * *', { timezone: 'Europe/Istanbul' })
32
- * async test() {
33
- * console.log('test');
34
- * }
35
- * ```
36
- */
37
- declare const cron: (schedule: CronScheduleParams[0], options?: CronScheduleParams[2]) => (target: any, propertyKey: string, descriptor: PropertyDescriptor) => PropertyDescriptor;
35
+ declare class GraphQL {
36
+ private schemaOptions;
37
+ private yogaOptions;
38
+ isEnabled: boolean;
39
+ constructor(options?: GraphQLOptions);
40
+ getSchema(createSchemaFn: typeof createSchema): GraphQLSchema;
41
+ getYogaOptions(): Parameters<typeof createYoga>[0];
42
+ /**
43
+ * Add a type definition to the schema
44
+ */
45
+ addTypeDef(typeDef: GraphQLTypeDef): void;
46
+ /**
47
+ * Add a resolver to the schema
48
+ * @param type - The resolver type (Query, Mutation, Subscription, or a custom type name)
49
+ * @param resolvers - An object mapping field names to resolver functions, or a full resolver object
50
+ */
51
+ addResolver(type: GraphQLResolverType, resolvers: GraphQLResolverMap): void;
52
+ addResolver(resolver: GraphQLResolvers): void;
53
+ addResolver(type: string, resolvers: GraphQLResolverMap): void;
54
+ private initializeConfiguration;
55
+ private createDisabledConfiguration;
56
+ private createEnabledConfiguration;
57
+ private resolveSchemaOptions;
58
+ private resolveYogaOptions;
59
+ private addResolverByType;
60
+ private ensureResolversInitialized;
61
+ private mergeResolverIntoObject;
62
+ private addFullResolver;
63
+ private addResolverArray;
64
+ private addResolverObject;
65
+ private addTypeDefArray;
66
+ private ensureTypeDefsArray;
67
+ }
38
68
 
39
- type FlagType = "boolean" | "string" | "number" | "list";
40
- type InferFlagType<T extends FlagType> = T extends "boolean" ? boolean : T extends "string" ? string : T extends "number" ? number : T extends "list" ? string[] : never;
41
- type ArgOptions = {
69
+ type SyncOrAsync<T = void> = T | Promise<T>;
70
+
71
+ type AjvInstance = InstanceType<typeof Ajv>;
72
+ type AjvCompileParams = Parameters<AjvInstance["compile"]>;
73
+
74
+ type RequestSchema = ZodType | TSchema | AjvCompileParams[0];
75
+ type ValidatedData<T extends RequestSchema> = T extends ZodType ? z.infer<T> : T extends TSchema ? Static<T> : T extends AjvCompileParams[0] ? any : any;
76
+ interface CustomValidationError {
77
+ status?: number;
78
+ message?: string;
79
+ }
80
+ interface ValidationOptions {
42
81
  /**
43
- * The description of the argument.
82
+ * The schema to validate the request body against (Zod, TypeBox, or plain JSON schema)
44
83
  */
45
- description?: string;
84
+ body?: RequestSchema;
46
85
  /**
47
- * Whether the argument is required.
86
+ * The schema to validate the query parameters against (Zod, TypeBox, or plain JSON schema)
87
+ */
88
+ query?: RequestSchema;
89
+ /**
90
+ * The schema to validate both body and query against (Zod, TypeBox, or plain JSON schema)
91
+ */
92
+ all?: RequestSchema;
93
+ /**
94
+ * Whether to use safe validation (returns original data if validation fails instead of throwing)
48
95
  * @default false
49
96
  */
50
- required?: boolean;
97
+ safe?: boolean;
98
+ }
99
+
100
+ type StaticPluginOptions = {
51
101
  /**
52
- * The default value of the argument.
102
+ * The file system directory path where the assets are located
103
+ * @example "./tmp/assets" or "public"
53
104
  */
54
- defaultValue?: string;
105
+ source: string;
55
106
  /**
56
- * A function to parse the argument value.
57
- * @default The value is returned as is.
107
+ * The URL path where the assets will be served
108
+ * @example "/assets" or "/public"
58
109
  */
59
- parse?: (value: string) => string;
110
+ path: string;
60
111
  };
61
- type FlagOptions<T extends FlagType> = {
112
+ type FileAllowedMimeType = "text/html" | "text/css" | "application/javascript" | "application/typescript" | "text/jsx" | "text/tsx" | "application/json" | "application/xml" | "application/yaml" | "text/csv" | "text/plain" | "text/markdown" | "image/png" | "image/jpeg" | "image/gif" | "image/svg+xml" | "image/x-icon" | "image/webp" | "image/avif" | "image/bmp" | "image/tiff" | "image/heic" | "image/heif" | "video/mp4" | "video/webm" | "video/x-msvideo" | "video/quicktime" | "video/x-matroska" | "video/x-ms-wmv" | "video/x-flv" | "video/x-m4v" | "video/mpeg" | "video/3gpp" | "audio/mpeg" | "audio/wav" | "audio/ogg" | "audio/flac" | "audio/aac" | "audio/mp4" | "audio/x-ms-wma" | "audio/opus" | "audio/midi" | "font/woff" | "font/woff2" | "font/ttf" | "font/otf" | "application/vnd.ms-fontobject" | "application/pdf" | "application/msword" | "application/vnd.openxmlformats-officedocument.wordprocessingml.document" | "application/vnd.ms-excel" | "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" | "application/vnd.ms-powerpoint" | "application/vnd.openxmlformats-officedocument.presentationml.presentation" | "application/vnd.oasis.opendocument.text" | "application/vnd.oasis.opendocument.spreadsheet" | "application/vnd.oasis.opendocument.presentation" | "application/rtf" | "application/epub+zip" | "application/zip" | "application/x-tar" | "application/gzip" | "application/x-bzip2" | "application/x-xz" | "application/vnd.rar" | "application/x-7z-compressed" | "application/wasm" | "application/manifest+json" | "text/calendar" | "text/vcard" | "application/sql" | "application/x-sh" | "application/x-msdos-program" | "application/x-msdownload" | "application/octet-stream" | "application/x-iso9660-image" | "application/x-apple-diskimage" | "application/vnd.android.package-archive" | "application/java-archive" | "application/x-shockwave-flash";
113
+
114
+ type FormFile = {
62
115
  /**
63
- * The description of the flag.
116
+ * The name of the form field.
64
117
  */
65
- description?: string;
118
+ formName: string;
66
119
  /**
67
- * The type of the flag.
120
+ * The mime type of the file. (e.g. "image/png")
68
121
  */
69
- type: T;
122
+ mimeType: string;
70
123
  /**
71
- * The name of the flag.
72
- * @default The name of the field.
124
+ * The size of the file in bytes.
73
125
  */
74
- name?: string;
126
+ size: number;
75
127
  /**
76
- * The aliases of the flag.
128
+ * The temporary path of the file. Will be deleted after the request is processed automatically even in error cases.
77
129
  */
78
- aliases?: string[] | string;
130
+ tmpPath: string;
79
131
  /**
80
- * The default value of the flag.
132
+ * The original filename (including extension) as sent by the client
133
+ * (e.g. "avatar.png", "document.txt").
81
134
  */
82
- defaultValue?: InferFlagType<T>;
135
+ originalName: string;
136
+ };
137
+ type FilePluginOptions = {
83
138
  /**
84
- * Whether the flag is required.
85
- * @default false
139
+ * The maximum size of each file.
140
+ * Supports formats like "5mb", "100kb".
141
+ * Example: "10mb", "500kb"
142
+ * Default: 1mb
86
143
  */
87
- required?: boolean;
144
+ maxFileSize?: `${number}mb` | `${number}kb`;
88
145
  /**
89
- * A function to parse the flag value.
90
- * @default The value is returned as is.
146
+ * The maximum number of files allowed in a single request.
91
147
  */
92
- parse?: (value: any) => InferFlagType<T>;
93
- };
94
-
95
- declare const VALIDATION_ERROR_SYMBOL = "VALIDATION_ERROR";
96
- declare const ARG_SYMBOL = "ARG";
97
- /**
98
- * Decorator to mark a field of a command class as an argument.
99
- * @param options - The options for the argument.
100
- * @warning Arguments are evaluated in the order they are defined in the Command class.
101
- */
102
- declare const arg: (options: ArgOptions) => (target: any, propertyKey: string) => void;
103
-
104
- declare const flag: {
105
- <T extends FlagType>(options: FlagOptions<T>): (target: any, propertyKey: string) => void;
106
- boolean(options: Omit<FlagOptions<"boolean">, "type">): (target: any, propertyKey: string) => void;
107
- string(options: Omit<FlagOptions<"string">, "type">): (target: any, propertyKey: string) => void;
108
- number(options: Omit<FlagOptions<"number">, "type">): (target: any, propertyKey: string) => void;
109
- list(options: Omit<FlagOptions<"list">, "type">): (target: any, propertyKey: string) => void;
148
+ maxFiles?: number;
149
+ /**
150
+ * Allowed MIME types for uploaded files.
151
+ * If specified, only files with these MIME types will be accepted.
152
+ * Example: ['image/jpeg', 'image/png', 'application/pdf']
153
+ */
154
+ allowedMimeTypes?: (FileAllowedMimeType | (string & {}))[];
110
155
  };
111
156
 
112
157
  /**
113
- * Type of Swagger UI to use
114
- */
115
- type SwaggerUIType = "standard" | "rapidoc" | "scalar" | "elements" | "custom";
116
- type HTMLString = string;
117
- /**
118
- * Custom UI generator function that takes the spec URL and global options and returns HTML
119
- */
120
- type CustomUIGenerator = (specUrl: string, globalOptions: SwaggerGlobalOptions) => HTMLString;
121
- /**
122
- * Type of request body for a route
123
- */
124
- type SwaggerBodyType = "json" | "form-data" | "urlencoded";
125
- /**
126
- * JSONSchema type for OpenAPI/AJV-compatible schemas
127
- */
128
- type JSONSchema = {
129
- $id?: string;
130
- $schema?: string;
131
- type?: string | string[];
132
- properties?: Record<string, JSONSchema>;
133
- items?: JSONSchema | JSONSchema[];
134
- required?: string[];
135
- enum?: any[];
136
- allOf?: JSONSchema[];
137
- oneOf?: JSONSchema[];
138
- anyOf?: JSONSchema[];
139
- not?: JSONSchema;
140
- additionalProperties?: boolean | JSONSchema;
141
- description?: string;
142
- format?: string;
143
- default?: any;
144
- title?: string;
145
- definitions?: Record<string, JSONSchema>;
146
- [key: string]: any;
147
- };
148
- /**
149
- * Base options shared across all Swagger UI types
158
+ * The request object.
159
+ * This is the main object that is passed to the handler function.
160
+ * It contains the request body, query parameters, files, cookies, etc.
161
+ * It also contains the validation methods.
150
162
  */
151
- type SwaggerGlobalOptionsBase = {
152
- /** The path to the swagger documentation, defaults to /docs for the UI and /docs/json for the raw json */
153
- path?: string;
154
- /** API title */
155
- title?: string;
156
- /** API description */
157
- description?: string;
158
- /** API version */
159
- version?: string;
160
- /** Server URLs */
161
- servers?: string[];
162
- /** Components (schemas, responses, parameters, etc.) */
163
- components?: Record<string, any>;
164
- /** Security schemes (OpenAPI 3.0 style) */
165
- securitySchemes?: Record<string, Security>;
166
- /** OpenID Connect configuration (discovery document) */
167
- openIdConnect?: OpenIDConnectConfig;
168
- /** API tags */
169
- tags?: Record<string, any>;
170
- /** Global security requirements */
171
- security?: Security[];
172
- /** External documentation */
173
- externalDocs?: {
174
- description?: string;
175
- url: string;
176
- };
177
- /** Info object (detailed metadata) */
178
- info?: {
179
- title: string;
180
- description?: string;
181
- version: string;
182
- termsOfService?: string;
183
- contact?: {
184
- name?: string;
185
- url?: string;
186
- email?: string;
187
- };
188
- license?: {
189
- name: string;
190
- url?: string;
191
- };
192
- };
193
- /**
194
- * OpenAPI models to be shown in the documentation. Must be valid OpenAPI/AJV JSONSchema objects.
195
- */
196
- models?: Record<string, JSONSchema> | JSONSchema[];
197
- };
198
- /**
199
- * Global documentation options for the API (OpenAPI/Swagger style)
200
- */
201
- type SwaggerGlobalOptions = (SwaggerGlobalOptionsBase & {
202
- /** Type of Swagger UI to use, one of 'standard', 'redoc', 'rapidoc', 'scalar', or 'elements'. Defaults to 'standard'. */
203
- type?: Exclude<SwaggerUIType, "custom">;
204
- }) | (SwaggerGlobalOptionsBase & {
205
- /** Type of Swagger UI to use. When set to 'custom', customUIGenerator is required. */
206
- type: "custom";
207
- /** Custom UI generator function. Required when type is 'custom'. Must return a string of HTML that uses the given specUrl. */
208
- customUIGenerator: CustomUIGenerator;
209
- });
210
- /**
211
- * Route-specific documentation options (for individual endpoints)
212
- */
213
- type SwaggerRouteOptions = {
214
- /** Service category where the route belongs to */
215
- service?: string;
216
- /** Name of the route */
217
- name?: string;
218
- /** Query parameters schema */
219
- query?: ZodType;
220
- /** Request body schema */
221
- requestBody?: ZodType;
222
- /** Responses for this route */
223
- responses?: Record<number, ZodType>;
224
- /** Errors for this route */
225
- errors?: Record<number, ZodType>;
226
- /** Security requirements for this route */
227
- security?: Security[] | Security;
228
- /** Description of the route */
229
- description?: string;
230
- /** Deprecated flag */
231
- deprecated?: boolean;
232
- /** Exclude from swagger */
233
- excludeFromSwagger?: boolean;
234
- /**
235
- * The request body type for this route. Allowed values: 'json', 'form-data', 'urlencoded'. Defaults to 'json'.
236
- */
237
- bodyType?: SwaggerBodyType;
238
- };
239
- type OAuth2Flows = {
240
- implicit?: OAuth2Flow;
241
- authorizationCode?: OAuth2Flow;
242
- clientCredentials?: OAuth2Flow;
243
- password?: OAuth2Flow;
244
- };
245
- type OAuth2Flow = {
246
- authorizationUrl?: string;
247
- tokenUrl?: string;
248
- refreshUrl?: string;
249
- scopes: Record<string, string>;
250
- };
251
- type OpenIDConnectConfig = {
252
- issuer: string;
253
- authorizationEndpoint: string;
254
- tokenEndpoint: string;
255
- userinfoEndpoint?: string;
256
- jwksUri: string;
257
- endSessionEndpoint?: string;
258
- introspectionEndpoint?: string;
259
- revocationEndpoint?: string;
260
- scopesSupported?: string[];
261
- responseTypesSupported?: string[];
262
- grantTypesSupported?: string[];
263
- tokenEndpointAuthMethodsSupported?: string[];
264
- subjectTypesSupported?: string[];
265
- idTokenSigningAlgValuesSupported?: string[];
266
- claimsSupported?: string[];
267
- codeChallengeMethodsSupported?: string[];
268
- };
269
- type Security = BearerOptions | ApiKeyOptions | OAuth2Options | OpenIdConnectOptions;
270
- type BearerOptions = {
271
- type: "bearer";
272
- bearerFormat?: string;
273
- description?: string;
274
- };
275
- type ApiKeyOptions = {
276
- type: "apiKey";
277
- name: string;
278
- in: "header" | "query" | "cookie";
279
- description?: string;
280
- };
281
- type OAuth2Options = {
282
- type: "oauth2";
283
- flows: OAuth2Flows;
284
- description?: string;
285
- name?: string;
286
- };
287
- type OpenIdConnectOptions = {
288
- type: "openIdConnect";
289
- openIdConnectUrl: string;
290
- description?: string;
291
- name?: string;
292
- };
293
-
294
- /**
295
- * Decorator to mark a class as a controller, routes defined in the controller will be registered at import time when calling the `listen` method.
296
- * You can customize the path pattern for controller imports in the server options `controllerPatterns`
297
- * @param path - The path pattern for the controller.
298
- * @param swaggerOptions - The swagger options for the controller that will be applied to all routes defined in the controller. Controller options will override route options.
299
- * @swagger If swagger is enabled, the default service name for all routes defined in the controller will be the controller name.
300
- * @swagger For naming commodity, the default service name will remove the "Controller" suffix if it exists. e.g. "UserController" -> "User"
301
- */
302
- declare const controller: (path?: string, swaggerOptions?: SwaggerRouteOptions) => (target: any) => void;
303
-
304
- type AjvInstance = InstanceType<typeof Ajv>;
305
- type AjvCompileParams = Parameters<AjvInstance["compile"]>;
306
-
307
- type RequestSchema = ZodType | TSchema | AjvCompileParams[0];
308
- type ValidatedData<T extends RequestSchema> = T extends ZodType ? z.infer<T> : T extends TSchema ? Static<T> : T extends AjvCompileParams[0] ? any : any;
309
- interface CustomValidationError {
310
- status?: number;
311
- message?: string;
312
- }
313
- interface ValidationOptions {
314
- /**
315
- * The schema to validate the request body against (Zod, TypeBox, or plain JSON schema)
316
- */
317
- body?: RequestSchema;
163
+ declare class Request<Params extends Record<string, string> = any> {
164
+ #private;
318
165
  /**
319
- * The schema to validate the query parameters against (Zod, TypeBox, or plain JSON schema)
166
+ * Creates a new request object from a Web API Request object.
167
+ * Optimized to inline body check and avoid unnecessary property spreading.
168
+ * @param request - The Web API Request object to create a new request object from.
169
+ * @returns The new request object.
320
170
  */
321
- query?: RequestSchema;
171
+ static fromRequest(request: globalThis.Request): Request;
322
172
  /**
323
- * The schema to validate both body and query against (Zod, TypeBox, or plain JSON schema)
173
+ * Convert this request back to a Web API Request object.
174
+ * Useful for passing to external libraries that expect standard Request objects.
175
+ * @returns A Web API Request object
324
176
  */
325
- all?: RequestSchema;
177
+ toWebApi(): globalThis.Request;
326
178
  /**
327
- * Whether to use safe validation (returns original data if validation fails instead of throwing)
328
- * @default false
179
+ * Compiles and validates the request data against the input schema.
180
+ * @param inputSchema - The schema to validate the request data against (Zod, TypeBox, or plain JSON schema).
181
+ * @param data - The request data to validate.
182
+ * @param safe - If true, the function will return the original data if the validation fails instead of throwing an error.
183
+ * @returns The validated data.
329
184
  */
330
- safe?: boolean;
331
- }
332
-
333
- type SyncOrAsync<T = void> = T | Promise<T>;
334
-
335
- interface AsyncLocalStorageContext {
336
- }
337
- type AsyncLocalStorageContextSetters<K extends keyof AsyncLocalStorageContext = keyof AsyncLocalStorageContext> = Record<K, (req: Request) => SyncOrAsync<AsyncLocalStorageContext[K]>>;
338
-
339
- type StaticPluginOptions = {
185
+ private static compileAndValidate;
340
186
  /**
341
- * The file system directory path where the assets are located
342
- * @example "./tmp/assets" or "public"
187
+ * The URL of the request
343
188
  */
344
- source: string;
189
+ url: string;
345
190
  /**
346
- * The URL path where the assets will be served
347
- * @example "/assets" or "/public"
191
+ * The HTTP method of the request
348
192
  */
349
- path: string;
350
- };
351
- type FileAllowedMimeType = "text/html" | "text/css" | "application/javascript" | "application/typescript" | "text/jsx" | "text/tsx" | "application/json" | "application/xml" | "application/yaml" | "text/csv" | "text/plain" | "text/markdown" | "image/png" | "image/jpeg" | "image/gif" | "image/svg+xml" | "image/x-icon" | "image/webp" | "image/avif" | "image/bmp" | "image/tiff" | "image/heic" | "image/heif" | "video/mp4" | "video/webm" | "video/x-msvideo" | "video/quicktime" | "video/x-matroska" | "video/x-ms-wmv" | "video/x-flv" | "video/x-m4v" | "video/mpeg" | "video/3gpp" | "audio/mpeg" | "audio/wav" | "audio/ogg" | "audio/flac" | "audio/aac" | "audio/mp4" | "audio/x-ms-wma" | "audio/opus" | "audio/midi" | "font/woff" | "font/woff2" | "font/ttf" | "font/otf" | "application/vnd.ms-fontobject" | "application/pdf" | "application/msword" | "application/vnd.openxmlformats-officedocument.wordprocessingml.document" | "application/vnd.ms-excel" | "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" | "application/vnd.ms-powerpoint" | "application/vnd.openxmlformats-officedocument.presentationml.presentation" | "application/vnd.oasis.opendocument.text" | "application/vnd.oasis.opendocument.spreadsheet" | "application/vnd.oasis.opendocument.presentation" | "application/rtf" | "application/epub+zip" | "application/zip" | "application/x-tar" | "application/gzip" | "application/x-bzip2" | "application/x-xz" | "application/vnd.rar" | "application/x-7z-compressed" | "application/wasm" | "application/manifest+json" | "text/calendar" | "text/vcard" | "application/sql" | "application/x-sh" | "application/x-msdos-program" | "application/x-msdownload" | "application/octet-stream" | "application/x-iso9660-image" | "application/x-apple-diskimage" | "application/vnd.android.package-archive" | "application/java-archive" | "application/x-shockwave-flash";
352
-
353
- type FormFile = {
193
+ method: string;
354
194
  /**
355
- * The name of the form field.
195
+ * The headers of the request
356
196
  */
357
- formName: string;
197
+ headers: globalThis.Headers;
358
198
  /**
359
- * The mime type of the file. (e.g. "image/png")
199
+ * The signal for aborting the request
360
200
  */
361
- mimeType: string;
201
+ signal?: AbortSignal;
362
202
  /**
363
- * The size of the file in bytes.
203
+ * The referrer of the request
364
204
  */
365
- size: number;
205
+ referrer?: string;
366
206
  /**
367
- * The temporary path of the file. Will be deleted after the request is processed automatically even in error cases.
207
+ * The referrer policy of the request
368
208
  */
369
- tmpPath: string;
209
+ referrerPolicy?: ReferrerPolicy;
370
210
  /**
371
- * The original filename (including extension) as sent by the client
372
- * (e.g. "avatar.png", "document.txt").
211
+ * The mode of the request
373
212
  */
374
- originalName: string;
375
- };
376
- type FilePluginOptions = {
213
+ mode?: RequestMode;
377
214
  /**
378
- * The maximum size of each file.
379
- * Supports formats like "5mb", "100kb".
380
- * Example: "10mb", "500kb"
381
- * Default: 1mb
215
+ * The credentials mode of the request
382
216
  */
383
- maxFileSize?: `${number}mb` | `${number}kb`;
217
+ credentials?: RequestCredentials;
384
218
  /**
385
- * The maximum number of files allowed in a single request.
219
+ * The cache mode of the request
386
220
  */
387
- maxFiles?: number;
221
+ cache?: RequestCache;
388
222
  /**
389
- * Allowed MIME types for uploaded files.
390
- * If specified, only files with these MIME types will be accepted.
391
- * Example: ['image/jpeg', 'image/png', 'application/pdf']
223
+ * The redirect mode of the request
392
224
  */
393
- allowedMimeTypes?: (FileAllowedMimeType | (string & {}))[];
394
- };
395
-
396
- /**
397
- * The request object.
398
- * This is the main object that is passed to the handler function.
399
- * It contains the request body, query parameters, files, cookies, etc.
400
- * It also contains the validation methods.
401
- */
402
- declare class Request<Params extends Record<string, string> = any> extends globalThis.Request {
403
- #private;
225
+ redirect?: RequestRedirect;
404
226
  /**
405
- * Creates a new request object from a Web API Request object.
406
- * @param request - The Web API Request object to create a new request object from.
407
- * @returns The new request object.
227
+ * The integrity of the request
408
228
  */
409
- static fromRequest(request: globalThis.Request): Request;
229
+ integrity?: string;
410
230
  /**
411
- * Compiles and validates the request data against the input schema.
412
- * @param inputSchema - The schema to validate the request data against (Zod, TypeBox, or plain JSON schema).
413
- * @param data - The request data to validate.
414
- * @param safe - If true, the function will return the original data if the validation fails instead of throwing an error.
415
- * @returns The validated data.
231
+ * The keepalive flag of the request
416
232
  */
417
- private static compileAndValidate;
233
+ keepalive?: boolean;
418
234
  /**
419
- * The raw Web API Request body.
420
- * @warning if using body parser middleware, this property will be read and the parsed body will be set to the `parsedBody` property.
421
- * @warning this body can be read once so be careful not to use it after the body parser middleware has been applied.
235
+ * The parsed body of the request from the body parser middleware.
236
+ * If body parser middleware is not used, this will be undefined.
422
237
  */
423
- readonly body: globalThis.Request["body"];
238
+ body: any;
424
239
  /**
425
- * The parsed body of the request from the body parser middleware.
240
+ * Flag indicating if the body has been read/parsed
426
241
  */
427
- parsedBody: any;
242
+ bodyUsed: boolean;
428
243
  /**
429
244
  * The context of the request. Can be augmented extending AsyncLocalStorageContext interface
430
245
  * @asyncLocalStorage middleware is required
@@ -528,24 +343,103 @@ declare class Request<Params extends Record<string, string> = any> extends globa
528
343
  validateAll<T extends RequestSchema>(inputSchema: T, safe?: boolean): ValidatedData<T>;
529
344
  }
530
345
 
531
- /**
532
- * Cookie options for setting cookies
533
- */
534
- type CookieOptions = {
346
+ interface AsyncLocalStorageContext {
347
+ }
348
+ type AsyncLocalStorageContextSetters<K extends keyof AsyncLocalStorageContext = keyof AsyncLocalStorageContext> = Record<K, (req: Request) => SyncOrAsync<AsyncLocalStorageContext[K]>>;
349
+
350
+ interface JsonOptions {
535
351
  /**
536
- * Domain for the cookie
352
+ * The maximum size of the JSON body in bytes.
353
+ * If the body is larger than this limit, the request will be rejected.
354
+ * Default: 100kb
537
355
  */
538
- domain?: string;
356
+ sizeLimit?: `${number}mb` | `${number}kb`;
539
357
  /**
540
- * Path for the cookie
358
+ * If true, the JSON body will be parsed as an empty object if it is empty.
359
+ * Default: false (body will be undefined)
541
360
  */
542
- path?: string;
361
+ parseEmptyBodyAsObject?: boolean;
543
362
  /**
544
- * Expiration date for the cookie
363
+ * The custom error message to return when the JSON body is too large.
364
+ * Default: response with status 413 and body { message: "ERR_REQUEST_BODY_TOO_LARGE" }
545
365
  */
546
- expires?: Date;
366
+ customErrorMessage?: {
367
+ status?: number;
368
+ message?: string;
369
+ };
370
+ }
371
+
372
+ /**
373
+ * Options for URL-encoded middleware
374
+ */
375
+ type UrlEncodedOptions = {
547
376
  /**
548
- * Max age in seconds for the cookie
377
+ * The maximum size of the URL-encoded body.
378
+ * Supports formats like "5mb", "100kb".
379
+ * Defaults to "1mb".
380
+ */
381
+ limit?: `${number}mb` | `${number}kb`;
382
+ /**
383
+ * Whether to parse extended syntax (objects and arrays). Defaults to false.
384
+ */
385
+ extended?: boolean;
386
+ /**
387
+ * The character encoding to use when parsing. Defaults to 'utf8'.
388
+ */
389
+ charset?: string;
390
+ /**
391
+ * Whether to allow empty values. Defaults to true.
392
+ */
393
+ allowEmpty?: boolean;
394
+ /**
395
+ * Maximum number of parameters to parse. Defaults to 1000.
396
+ */
397
+ parameterLimit?: number;
398
+ };
399
+
400
+ type BodyParserOptions = {
401
+ json?: JsonOptions;
402
+ urlencoded?: UrlEncodedOptions;
403
+ fileParser?: FilePluginOptions;
404
+ };
405
+
406
+ type CompressionOptions = {
407
+ /**
408
+ * Minimum response size in bytes to trigger compression
409
+ * Default: 1024 (1KB)
410
+ */
411
+ threshold?: number;
412
+ /**
413
+ * Compression level (0-9)
414
+ * 0 = no compression, 9 = maximum compression
415
+ * Default: 6
416
+ */
417
+ level?: number;
418
+ /**
419
+ * Content types to compress (regex patterns)
420
+ * Default: common compressible types (text, json, xml, javascript, etc.)
421
+ */
422
+ filter?: RegExp[];
423
+ };
424
+
425
+ /**
426
+ * Cookie options for setting cookies
427
+ */
428
+ type CookieOptions = {
429
+ /**
430
+ * Domain for the cookie
431
+ */
432
+ domain?: string;
433
+ /**
434
+ * Path for the cookie
435
+ */
436
+ path?: string;
437
+ /**
438
+ * Expiration date for the cookie
439
+ */
440
+ expires?: Date;
441
+ /**
442
+ * Max age in seconds for the cookie
549
443
  */
550
444
  maxAge?: number;
551
445
  /**
@@ -603,1003 +497,772 @@ type CookieMiddlewareOptions = {
603
497
  sign?: boolean;
604
498
  };
605
499
 
500
+ type CorsMethods = "GET" | "POST" | "PUT" | "DELETE" | "OPTIONS" | "PATCH" | "HEAD";
606
501
  /**
607
- * The response object.
608
- * This is the main object that is passed to the handler function.
609
- * It contains the response body, status, headers, etc.
610
- * It also contains the methods to send the response.
502
+ * Options for CORS middleware, similar to Express.js
611
503
  */
612
- declare class Response$1 {
613
- static toWebResponse(response: Response$1): globalThis.Response;
504
+ type CorsOptions = {
614
505
  /**
615
- * The node http response object available only on the node runtime, useful for direct response manipulation
616
- * @warning undefined on other runtimes since they already use Web API Response object
506
+ * Configures the Access-Control-Allow-Origin CORS header.
507
+ *
508
+ * ⚠️ WARNING: The default value '*' allows ALL origins, which is insecure for production.
509
+ *
510
+ * For production, explicitly set allowed origins:
511
+ * - Single origin: 'https://example.com'
512
+ * - Multiple origins: ['https://example.com', 'https://app.example.com']
513
+ * - Pattern matching: /^https:\/\/.*\.example\.com$/
514
+ *
515
+ * Defaults to '*' (allows all origins) - only suitable for development/public APIs.
617
516
  */
618
- nodeResponse: ServerResponse;
517
+ origin?: string | RegExp | (string | RegExp)[];
619
518
  /**
620
- * The status of the response
519
+ * Configures the Access-Control-Allow-Methods CORS header. Defaults to 'GET,HEAD,PUT,PATCH,POST,DELETE'.
621
520
  */
622
- responseStatus: number;
521
+ methods?: CorsMethods[] | string;
623
522
  /**
624
- * The headers of the response
523
+ * Configures the Access-Control-Allow-Headers CORS header. Defaults to allowing all requested headers.
625
524
  */
626
- headers: Record<string, string>;
525
+ allowedHeaders?: string[] | string;
627
526
  /**
628
- * The body of the response
527
+ * Configures the Access-Control-Expose-Headers CORS header. Defaults to none.
629
528
  */
630
- private body;
631
- constructor(status?: number);
529
+ exposedHeaders?: string[] | string;
632
530
  /**
633
- * Set a header for the response
531
+ * Configures the Access-Control-Allow-Credentials CORS header. Defaults to false.
634
532
  */
635
- setHeader(key: string, value: string): this;
533
+ credentials?: boolean;
636
534
  /**
637
- * Set the status of the response, status defaults to 200
535
+ * Configures the Access-Control-Max-Age CORS header. Defaults to undefined (not sent).
638
536
  */
639
- status(status: number): this;
537
+ maxAge?: number;
640
538
  /**
641
- * Send a response with the given body, tries to determine the content type based on the body type, status defaults to 200
642
- * @warning If cannot determine the content type, it will be sent as is
539
+ * Pass the CORS preflight response to the next handler. Defaults to false (ends response).
643
540
  */
644
- send(body: any): void;
541
+ preflightContinue?: boolean;
645
542
  /**
646
- * Send a response with the given body without any content type or encoding (as is), status defaults to 200
543
+ * Provides a status code to use for successful OPTIONS requests, if preflightContinue is false. Defaults to 204.
647
544
  */
648
- raw(body: any): void;
545
+ optionsSuccessStatus?: number;
546
+ };
547
+
548
+ type ExpressHandler = RequestHandler;
549
+ type ExpressRouter = IRouter;
550
+ interface ExpressAdapterOptions {
551
+ basePath?: string;
552
+ }
553
+
554
+ /**
555
+ * Options for helmet middleware
556
+ */
557
+ interface HelmetOptions {
558
+ dnsPrefetchControl?: boolean;
559
+ frameguard?: boolean | {
560
+ action: "DENY" | "SAMEORIGIN" | string;
561
+ };
562
+ hsts?: boolean | {
563
+ maxAge?: number;
564
+ includeSubDomains?: boolean;
565
+ preload?: boolean;
566
+ };
567
+ contentTypeOptions?: boolean;
568
+ ieNoOpen?: boolean;
569
+ xssFilter?: boolean;
570
+ referrerPolicy?: false | string;
571
+ crossOriginResourcePolicy?: false | string;
572
+ crossOriginOpenerPolicy?: false | string;
573
+ crossOriginEmbedderPolicy?: false | string;
574
+ contentSecurityPolicy?: false | string;
575
+ }
576
+
577
+ type LoggerOptions = Parameters<typeof pino$1>[0];
578
+
579
+ interface LogOptions {
649
580
  /**
650
- * Send a response with the given text, status defaults to 200
581
+ * Whether to log the request.
582
+ * @default true
651
583
  */
652
- text(body: string): void;
584
+ logRequest?: boolean;
653
585
  /**
654
- * Send a response with the given JSON, status defaults to 200
586
+ * What to log for the request.
587
+ * @default true for all properties
655
588
  */
656
- json<T extends Record<string, unknown> | Array<unknown>>(body: T): void;
589
+ requestPayload?: {
590
+ method?: boolean;
591
+ url?: boolean;
592
+ ip?: boolean;
593
+ headers?: boolean;
594
+ /** Only json objects and strings are logged */
595
+ body?: boolean;
596
+ };
657
597
  /**
658
- * Send a response with the given HTML, status defaults to 200
598
+ * Whether to log the response.
599
+ * @default true
659
600
  */
660
- html(htmlString: string): void;
601
+ logResponse?: boolean;
661
602
  /**
662
- * Send a response with the given XML, status defaults to 200
603
+ * Whether to log the response body.
604
+ * @default false
663
605
  */
664
- xml(body: string): void;
606
+ responsePayload?: {
607
+ status?: boolean;
608
+ headers?: boolean;
609
+ body?: boolean;
610
+ };
665
611
  /**
666
- * Send a response with the given binary with Content-Type of application/octet-stream header, status defaults to 200
612
+ * What to log for the response.
613
+ * @default true for all properties
667
614
  */
668
- download(body: Uint8Array | Buffer): void;
615
+ pinoOptions?: LoggerOptions;
616
+ }
617
+
618
+ type MethodOverrideOptions = {
669
619
  /**
670
- * Send a response with the given file content, status defaults to 200
671
- * @param options only affects node and bun environment
620
+ * HTTP methods that can be overridden
621
+ * Default: ['POST']
672
622
  */
673
- file(pathToFile: string, options?: {
674
- encoding?: string;
675
- flag?: string;
676
- }): void;
623
+ methods?: string[];
677
624
  /**
678
- * 2XX Success
625
+ * Header name to read the override method from
626
+ * Default: 'X-HTTP-Method-Override'
679
627
  */
628
+ header?: string;
629
+ };
630
+
631
+ type StorageStrategy = "memory" | "custom";
632
+ type BaseRateLimiterOptions = {
680
633
  /**
681
- * 200 OK
634
+ * The number of requests per window
635
+ * @default 100
682
636
  */
683
- ok(body?: any): void;
637
+ limit?: number;
684
638
  /**
685
- * 201 Created
639
+ * The message to return when the rate limit is exceeded
640
+ * @default "ERR_RATE_LIMIT_EXCEEDED"
686
641
  */
687
- created(body?: any): void;
642
+ message?: string;
688
643
  /**
689
- * 202 Accepted
644
+ * The status code to return when the rate limit is exceeded
645
+ * @default 429
690
646
  */
691
- accepted(body?: any): void;
647
+ statusCode?: number;
692
648
  /**
693
- * 204 No Content
649
+ * The storage strategy to use
650
+ * @default "memory"
694
651
  */
695
- noContent(): void;
652
+ storageStrategy?: StorageStrategy;
653
+ };
654
+ /**
655
+ * Key Strategy
656
+ */
657
+ type IpRateLimiterOptions = {
696
658
  /**
697
- * 206 Partial Content
659
+ * The type of rate limiter
698
660
  */
699
- partialContent(body?: any): void;
661
+ type: "ip";
662
+ } & BaseRateLimiterOptions;
663
+ type CustomRateLimiterOptions = {
700
664
  /**
701
- * 3XX Redirection
665
+ * The type of rate limiter
702
666
  */
667
+ type: "custom";
703
668
  /**
704
- * 300 Multiple Choices
669
+ * Generate a key for the rate limiter from the request (e.g. user id, email, etc.)
705
670
  */
706
- multipleChoices(url: string): void;
707
- redirect(url: string): void;
671
+ key: (req: Request) => string;
708
672
  /**
709
- * 301 Moved Permanently
673
+ * The storage strategy to use
674
+ * @default "memory"
710
675
  */
711
- movedPermanently(url: string): void;
676
+ storageStrategy?: StorageStrategy;
677
+ } & BaseRateLimiterOptions;
678
+ /**
679
+ * Memory Storage Strategy
680
+ */
681
+ type MemoryStorageStrategy = {
712
682
  /**
713
- * 302 Found (Temporary Redirect)
714
- */
715
- found(url: string): void;
716
- /**
717
- * 303 See Other
718
- */
719
- seeOther(url: string): void;
720
- /**
721
- * 304 Not Modified
722
- */
723
- notModified(): void;
724
- /**
725
- * 307 Temporary Redirect
726
- */
727
- temporaryRedirect(url: string): void;
728
- /**
729
- * 308 Permanent Redirect
730
- */
731
- permanentRedirect(url: string): void;
732
- /**
733
- * 4XX Client Errors
734
- */
735
- /**
736
- * 400 Bad Request
737
- */
738
- badRequest(body?: any): void;
739
- /**
740
- * 401 Unauthorized
741
- */
742
- unauthorized(body?: any): void;
743
- /**
744
- * 403 Forbidden
745
- */
746
- forbidden(body?: any): void;
747
- /**
748
- * 404 Not Found
749
- */
750
- notFound(body?: any): void;
751
- /**
752
- * 405 Method Not Allowed
753
- */
754
- methodNotAllowed(body?: any): void;
755
- /**
756
- * 406 Not Acceptable
757
- */
758
- notAcceptable(body?: any): void;
759
- /**
760
- * 409 Conflict
761
- */
762
- conflict(body?: any): void;
763
- /**
764
- * 410 Gone
765
- */
766
- gone(body?: any): void;
767
- /**
768
- * 413 Payload Too Large
769
- */
770
- payloadTooLarge(body?: any): void;
771
- /**
772
- * 415 Unsupported Media Type
773
- */
774
- unsupportedMediaType(body?: any): void;
775
- /**
776
- * 422 Unprocessable Entity
777
- */
778
- unprocessableEntity(body?: any): void;
779
- /**
780
- * 429 Too Many Requests
781
- */
782
- tooManyRequests(body?: any): void;
783
- /**
784
- * 5XX Server Errors
785
- */
786
- internalServerError(body?: any): void;
787
- /**
788
- * 501 Not Implemented
789
- */
790
- notImplemented(body?: any): void;
791
- /**
792
- * 502 Bad Gateway
793
- */
794
- badGateway(body?: any): void;
795
- /**
796
- * 503 Service Unavailable
797
- */
798
- serviceUnavailable(body?: any): void;
799
- /**
800
- * 504 Gateway Timeout
801
- */
802
- gatewayTimeout(body?: any): void;
803
- /**
804
- * 505 HTTP Version Not Supported
683
+ * The type of storage strategy
805
684
  */
806
- httpVersionNotSupported(body?: any): void;
685
+ type: "memory";
807
686
  /**
808
- * Set a cookie for the response, cookie middleware must be registered in order to use this function
687
+ * The window in milliseconds
688
+ * @default 60000
809
689
  */
810
- cookie?(_name: string, _value: string, _options?: CookieOptions): void;
690
+ windowMs?: number;
691
+ };
692
+ /**
693
+ * Custom Storage Strategy
694
+ */
695
+ type CustomStorageStrategy = {
811
696
  /**
812
- * Clear a cookie for the response, cookie middleware must be registered in order to use this function
697
+ * The type of storage strategy
813
698
  */
814
- clearCookie?(_name: string, _options?: CookieOptions): void;
699
+ type: "custom";
815
700
  /**
816
- * Stream a response using an async generator or ReadableStream
817
- * Sets appropriate headers for Server-Sent Events by default
701
+ * Set a value in the storage
818
702
  */
819
- stream(source: AsyncGenerator<any> | Generator<any> | ReadableStream, options?: {
820
- customHeaders?: Record<string, string>;
821
- }): void;
703
+ set: (key: string, value: any) => Promise<void>;
822
704
  /**
823
- * Get the body of the response
705
+ * Get a value from the storage
824
706
  */
825
- getBody(): any;
826
- }
827
-
828
- type DelHandler = (req: Request, res: Response$1, ...args: any[]) => any;
707
+ get: (key: string) => Promise<any>;
708
+ };
709
+ type StorageOptions$1 = MemoryStorageStrategy | CustomStorageStrategy;
829
710
  /**
830
- * Decorator to mark an handler for a DELETE request
831
- * @param path - The path of the route
832
- * @param options - The options for the route
833
- * @warning Must receive the request and response as the first two arguments or it might not work as expected.
834
- * @example
835
- * ```ts
836
- * import { del, controller, Request, Response } from "balda";
837
- *
838
- * @controller("/api")
839
- * class MyController {
840
- * @del("/")
841
- * async handler(req: Request, res: Response) {
842
- * // ...
843
- * }
844
- * }
845
- * ```
711
+ * Rate limiter options
846
712
  */
847
- declare const del: (path: string, options?: SwaggerRouteOptions) => <T extends DelHandler>(target: any, propertyKey: string, descriptor: PropertyDescriptor) => TypedPropertyDescriptor<T>;
713
+ type RateLimiterKeyOptions = IpRateLimiterOptions | CustomRateLimiterOptions;
714
+
715
+ type SessionStore = {
716
+ get: (sid: string) => Promise<Record<string, any> | undefined>;
717
+ set: (sid: string, value: Record<string, any>, ttlSeconds?: number) => Promise<void>;
718
+ destroy: (sid: string) => Promise<void>;
719
+ };
720
+ type SessionOptions = {
721
+ /** Cookie name used for session id */
722
+ name?: string;
723
+ /** Secret used to sign session id (optional, for future) */
724
+ secret?: string;
725
+ /** TTL seconds for session */
726
+ ttl?: number;
727
+ /** Custom store, default is in-memory */
728
+ store?: SessionStore;
729
+ /** Whether to set HttpOnly secure flags */
730
+ cookie?: {
731
+ path?: string;
732
+ httpOnly?: boolean;
733
+ secure?: boolean;
734
+ sameSite?: "Strict" | "Lax" | "None";
735
+ domain?: string;
736
+ };
737
+ };
848
738
 
849
- type GetHandler = (req: Request, res: Response$1, ...args: any[]) => any;
850
739
  /**
851
- * Decorator to mark an handler for a GET request
852
- * @param path - The path of the route
853
- * @param options - The options for the route
854
- * @warning Must receive the request and response as the first two arguments or it might not work as expected.
855
- * @example
856
- * ```ts
857
- * import { get, controller, Request, Response } from "balda";
858
- *
859
- * @controller("/api")
860
- * class MyController {
861
- * @get("/")
862
- * async handler(req: Request, res: Response) {
863
- * // ...
864
- * }
865
- * }
866
- * ```
740
+ * Type of Swagger UI to use
867
741
  */
868
- declare const get: (path: string, options?: SwaggerRouteOptions) => <T extends GetHandler>(target: any, propertyKey: string, descriptor: PropertyDescriptor) => TypedPropertyDescriptor<T>;
869
-
870
- type PatchHandler = (req: Request, res: Response$1, ...args: any[]) => any;
742
+ type SwaggerUIType = "standard" | "rapidoc" | "scalar" | "elements" | "custom";
743
+ type HTMLString = string;
871
744
  /**
872
- * Decorator to mark an handler for a PATCH request
873
- * @param path - The path of the route
874
- * @param options - The options for the route
875
- * @warning Must receive the request and response as the first two arguments or it might not work as expected.
876
- * @example
877
- * ```ts
878
- * import { patch, controller, Request, Response } from "balda";
879
- *
880
- * @controller("/api")
881
- * class MyController {
882
- * @patch("/")
883
- * async handler(req: Request, res: Response) {
884
- * // ...
885
- * }
886
- * }
887
- * ```
745
+ * Custom UI generator function that takes the spec URL and global options and returns HTML
888
746
  */
889
- declare const patch: (path: string, options?: SwaggerRouteOptions) => <T extends PatchHandler>(target: any, propertyKey: string, descriptor: PropertyDescriptor) => TypedPropertyDescriptor<T>;
890
-
891
- type PostHandler = (req: Request, res: Response$1, ...args: any[]) => any;
747
+ type CustomUIGenerator = (specUrl: string, globalOptions: SwaggerGlobalOptions) => HTMLString;
892
748
  /**
893
- * Decorator to mark an handler for a POST request
894
- * @param path - The path of the route
895
- * @param options - The options for the route
896
- * @warning Must receive the request and response as the first two arguments or it might not work as expected.
897
- * @example
898
- * ```ts
899
- * import { post, controller, Request, Response } from "balda";
900
- *
901
- * @controller("/api")
902
- * class MyController {
903
- * @post("/")
904
- * async handler(req: Request, res: Response) {
905
- * // ...
906
- * }
907
- * }
908
- * ```
749
+ * Type of request body for a route
909
750
  */
910
- declare const post: (path: string, options?: SwaggerRouteOptions) => <T extends PostHandler>(target: any, propertyKey: string, descriptor: PropertyDescriptor) => TypedPropertyDescriptor<T>;
911
-
912
- type PutHandler = (req: Request, res: Response$1, ...args: any[]) => any;
751
+ type SwaggerBodyType = "json" | "form-data" | "urlencoded";
913
752
  /**
914
- * Decorator to mark an handler for a PUT request
915
- * @param path - The path of the route
916
- * @param options - The options for the route
917
- * @warning Must receive the request and response as the first two arguments or it might not work as expected.
918
- * @example
919
- * ```ts
920
- * import { put, controller, Request, Response } from "balda";
921
- *
922
- * @controller("/api")
923
- * class MyController {
924
- * @put("/")
925
- * async handler(req: Request, res: Response) {
926
- * // ...
927
- * }
753
+ * JSONSchema type for OpenAPI/AJV-compatible schemas
928
754
  */
929
- declare const put: (path: string, options?: SwaggerRouteOptions) => <T extends PutHandler>(target: any, propertyKey: string, descriptor: PropertyDescriptor) => TypedPropertyDescriptor<T>;
930
-
931
- type GraphQLSchemaInput = Parameters<typeof createSchema>[0];
932
- type GraphQLTypeDef = GraphQLSchemaInput["typeDefs"];
933
- type GraphQLResolvers = GraphQLSchemaInput["resolvers"];
934
- interface GraphQLContext {
935
- }
936
- type GraphQLResolverFunction<TContext = GraphQLContext> = (parent: unknown, args: Record<string, unknown>, context: TContext, info: unknown) => unknown | Promise<unknown>;
937
- type GraphQLResolverMap<TContext = GraphQLContext> = Record<string, GraphQLResolverFunction<TContext> | Record<string, unknown>>;
938
- type GraphQLOptions = {
939
- schema?: GraphQLSchemaInput;
940
- yogaOptions?: Parameters<typeof createYoga>[0];
755
+ type JSONSchema = {
756
+ $id?: string;
757
+ $schema?: string;
758
+ type?: string | string[];
759
+ properties?: Record<string, JSONSchema>;
760
+ items?: JSONSchema | JSONSchema[];
761
+ required?: string[];
762
+ enum?: any[];
763
+ allOf?: JSONSchema[];
764
+ oneOf?: JSONSchema[];
765
+ anyOf?: JSONSchema[];
766
+ not?: JSONSchema;
767
+ additionalProperties?: boolean | JSONSchema;
768
+ description?: string;
769
+ format?: string;
770
+ default?: any;
771
+ title?: string;
772
+ definitions?: Record<string, JSONSchema>;
773
+ [key: string]: any;
941
774
  };
942
- type GraphQLResolverType = "Query" | "Mutation" | "Subscription";
943
-
944
- declare class GraphQL {
945
- private schemaOptions;
946
- private yogaOptions;
947
- isEnabled: boolean;
948
- constructor(options?: GraphQLOptions);
949
- getSchema(createSchemaFn: typeof createSchema): GraphQLSchema;
950
- getYogaOptions(): Parameters<typeof createYoga>[0];
775
+ /**
776
+ * Base options shared across all Swagger UI types
777
+ */
778
+ type SwaggerGlobalOptionsBase = {
779
+ /** The path to the swagger documentation, defaults to /docs for the UI and /docs/json for the raw json */
780
+ path?: string;
781
+ /** API title */
782
+ title?: string;
783
+ /** API description */
784
+ description?: string;
785
+ /** API version */
786
+ version?: string;
787
+ /** Server URLs */
788
+ servers?: string[];
789
+ /** Components (schemas, responses, parameters, etc.) */
790
+ components?: Record<string, any>;
791
+ /** Security schemes (OpenAPI 3.0 style) */
792
+ securitySchemes?: Record<string, Security>;
793
+ /** OpenID Connect configuration (discovery document) */
794
+ openIdConnect?: OpenIDConnectConfig;
795
+ /** API tags */
796
+ tags?: Record<string, any>;
797
+ /** Global security requirements */
798
+ security?: Security[];
799
+ /** External documentation */
800
+ externalDocs?: {
801
+ description?: string;
802
+ url: string;
803
+ };
804
+ /** Info object (detailed metadata) */
805
+ info?: {
806
+ title: string;
807
+ description?: string;
808
+ version: string;
809
+ termsOfService?: string;
810
+ contact?: {
811
+ name?: string;
812
+ url?: string;
813
+ email?: string;
814
+ };
815
+ license?: {
816
+ name: string;
817
+ url?: string;
818
+ };
819
+ };
951
820
  /**
952
- * Add a type definition to the schema
821
+ * OpenAPI models to be shown in the documentation. Must be valid OpenAPI/AJV JSONSchema objects.
953
822
  */
954
- addTypeDef(typeDef: GraphQLTypeDef): void;
823
+ models?: Record<string, JSONSchema> | JSONSchema[];
824
+ };
825
+ /**
826
+ * Global documentation options for the API (OpenAPI/Swagger style)
827
+ */
828
+ type SwaggerGlobalOptions = (SwaggerGlobalOptionsBase & {
829
+ /** Type of Swagger UI to use, one of 'standard', 'redoc', 'rapidoc', 'scalar', or 'elements'. Defaults to 'standard'. */
830
+ type?: Exclude<SwaggerUIType, "custom">;
831
+ }) | (SwaggerGlobalOptionsBase & {
832
+ /** Type of Swagger UI to use. When set to 'custom', customUIGenerator is required. */
833
+ type: "custom";
834
+ /** Custom UI generator function. Required when type is 'custom'. Must return a string of HTML that uses the given specUrl. */
835
+ customUIGenerator: CustomUIGenerator;
836
+ });
837
+ /**
838
+ * Route-specific documentation options (for individual endpoints)
839
+ */
840
+ type SwaggerRouteOptions = {
841
+ /** Service category where the route belongs to */
842
+ service?: string;
843
+ /** Name of the route */
844
+ name?: string;
845
+ /** Query parameters schema */
846
+ query?: ZodType;
847
+ /** Request body schema */
848
+ requestBody?: ZodType;
849
+ /** Responses for this route */
850
+ responses?: Record<number, ZodType>;
851
+ /** Errors for this route */
852
+ errors?: Record<number, ZodType>;
853
+ /** Security requirements for this route */
854
+ security?: Security[] | Security;
855
+ /** Description of the route */
856
+ description?: string;
857
+ /** Deprecated flag */
858
+ deprecated?: boolean;
859
+ /** Exclude from swagger */
860
+ excludeFromSwagger?: boolean;
955
861
  /**
956
- * Add a resolver to the schema
957
- * @param type - The resolver type (Query, Mutation, Subscription, or a custom type name)
958
- * @param resolvers - An object mapping field names to resolver functions, or a full resolver object
862
+ * The request body type for this route. Allowed values: 'json', 'form-data', 'urlencoded'. Defaults to 'json'.
959
863
  */
960
- addResolver(type: GraphQLResolverType, resolvers: GraphQLResolverMap): void;
961
- addResolver(resolver: GraphQLResolvers): void;
962
- addResolver(type: string, resolvers: GraphQLResolverMap): void;
963
- private initializeConfiguration;
964
- private createDisabledConfiguration;
965
- private createEnabledConfiguration;
966
- private resolveSchemaOptions;
967
- private resolveYogaOptions;
968
- private addResolverByType;
969
- private ensureResolversInitialized;
970
- private mergeResolverIntoObject;
971
- private addFullResolver;
972
- private addResolverArray;
973
- private addResolverObject;
974
- private addTypeDefArray;
975
- private ensureTypeDefsArray;
976
- }
864
+ bodyType?: SwaggerBodyType;
865
+ };
866
+ type OAuth2Flows = {
867
+ implicit?: OAuth2Flow;
868
+ authorizationCode?: OAuth2Flow;
869
+ clientCredentials?: OAuth2Flow;
870
+ password?: OAuth2Flow;
871
+ };
872
+ type OAuth2Flow = {
873
+ authorizationUrl?: string;
874
+ tokenUrl?: string;
875
+ refreshUrl?: string;
876
+ scopes: Record<string, string>;
877
+ };
878
+ type OpenIDConnectConfig = {
879
+ issuer: string;
880
+ authorizationEndpoint: string;
881
+ tokenEndpoint: string;
882
+ userinfoEndpoint?: string;
883
+ jwksUri: string;
884
+ endSessionEndpoint?: string;
885
+ introspectionEndpoint?: string;
886
+ revocationEndpoint?: string;
887
+ scopesSupported?: string[];
888
+ responseTypesSupported?: string[];
889
+ grantTypesSupported?: string[];
890
+ tokenEndpointAuthMethodsSupported?: string[];
891
+ subjectTypesSupported?: string[];
892
+ idTokenSigningAlgValuesSupported?: string[];
893
+ claimsSupported?: string[];
894
+ codeChallengeMethodsSupported?: string[];
895
+ };
896
+ type Security = BearerOptions | ApiKeyOptions | OAuth2Options | OpenIdConnectOptions;
897
+ type BearerOptions = {
898
+ type: "bearer";
899
+ bearerFormat?: string;
900
+ description?: string;
901
+ };
902
+ type ApiKeyOptions = {
903
+ type: "apiKey";
904
+ name: string;
905
+ in: "header" | "query" | "cookie";
906
+ description?: string;
907
+ };
908
+ type OAuth2Options = {
909
+ type: "oauth2";
910
+ flows: OAuth2Flows;
911
+ description?: string;
912
+ name?: string;
913
+ };
914
+ type OpenIdConnectOptions = {
915
+ type: "openIdConnect";
916
+ openIdConnectUrl: string;
917
+ description?: string;
918
+ name?: string;
919
+ };
977
920
 
978
921
  /**
979
- * Singleton that handles the routing of requests to the appropriate handler(s).
922
+ * Swagger plugin that serves the swagger UI and JSON specification, by default the UI will be available at /docs and the JSON specification at /docs/json
923
+ * @warning The json specification is always available at /${globalOptions.path}/json
924
+ * @internal
980
925
  */
981
- declare class Router {
982
- private trees;
983
- private routes;
984
- private middlewares;
985
- private basePath;
986
- private staticRouteCache;
987
- /**
988
- * Create a new router with an optional base path and default middlewares.
989
- * Base path is normalized so it never produces duplicate slashes and never ends with a trailing slash (except root).
990
- */
991
- constructor(basePath?: string, middlewares?: ServerRouteMiddleware[]);
992
- /** Returns a shallow copy of all registered routes. */
993
- getRoutes(): Route[];
994
- /**
995
- * Add or update a route
996
- * @internal
997
- */
998
- addOrUpdate(method: HttpMethod, path: string, middleware: ServerRouteMiddleware[], handler: ServerRouteHandler, swaggerOptions?: SwaggerRouteOptions): void;
999
- /**
1000
- * Find the matching route for the given HTTP method and path.
1001
- * Returns the resolved middleware chain, handler, and extracted params; or null if not found.
1002
- * Uses O(1) cache lookup for static routes, falls back to O(k) tree traversal for dynamic routes.
1003
- */
1004
- find(method: string, rawPath: string): {
1005
- middleware: ServerRouteMiddleware[];
1006
- handler: ServerRouteHandler;
1007
- params: Params;
1008
- } | null;
1009
- /**
1010
- * Register a GET route under this router's base path.
1011
- */
1012
- get(path: string, handler: ServerRouteHandler, swaggerOptions?: SwaggerRouteOptions): void;
1013
- get(path: string, middleware: ServerRouteMiddleware | ServerRouteMiddleware[], handler: ServerRouteHandler, swaggerOptions?: SwaggerRouteOptions): void;
1014
- /**
1015
- * Register a POST route under this router's base path.
1016
- */
1017
- post(path: string, handler: ServerRouteHandler, swaggerOptions?: SwaggerRouteOptions): void;
1018
- post(path: string, middleware: ServerRouteMiddleware | ServerRouteMiddleware[], handler: ServerRouteHandler, swaggerOptions?: SwaggerRouteOptions): void;
1019
- /**
1020
- * Register a PATCH route under this router's base path.
1021
- */
1022
- patch(path: string, handler: ServerRouteHandler, swaggerOptions?: SwaggerRouteOptions): void;
1023
- patch(path: string, middleware: ServerRouteMiddleware | ServerRouteMiddleware[], handler: ServerRouteHandler, swaggerOptions?: SwaggerRouteOptions): void;
1024
- /**
1025
- * Register a PUT route under this router's base path.
1026
- */
1027
- put(path: string, handler: ServerRouteHandler, swaggerOptions?: SwaggerRouteOptions): void;
1028
- put(path: string, middleware: ServerRouteMiddleware | ServerRouteMiddleware[], handler: ServerRouteHandler, swaggerOptions?: SwaggerRouteOptions): void;
926
+ declare const swagger: (globalOptions?: SwaggerGlobalOptions | boolean) => void;
927
+
928
+ type TimeoutOptions = {
929
+ /** Timeout in milliseconds */
930
+ ms: number;
931
+ };
932
+
933
+ type TrustProxyOptions = {
934
+ /** Enable using X-Forwarded-* headers to determine client IP */
935
+ trust?: boolean;
936
+ /** Header name to read the client IP chain from */
937
+ header?: string;
938
+ /** Select which IP from the chain to use: 'first' (client) or 'last' (closest proxy) */
939
+ hop?: "first" | "last";
940
+ };
941
+
942
+ /**
943
+ * The next function.
944
+ * This is the function that is passed to the handler function.
945
+ * It has a pointer to the next middleware or handler function of the middleware chain.
946
+ */
947
+ type NextFunction = () => SyncOrAsync;
948
+
949
+ /**
950
+ * The response object.
951
+ * This is the main object that is passed to the handler function.
952
+ * It contains the response body, status, headers, etc.
953
+ * It also contains the methods to send the response.
954
+ */
955
+ declare class Response$1 {
956
+ static toWebResponse(response: Response$1): globalThis.Response;
1029
957
  /**
1030
- * Register a DELETE route under this router's base path.
958
+ * The node http response object available only on the node runtime, useful for direct response manipulation
959
+ * @warning undefined on other runtimes since they already use Web API Response object
1031
960
  */
1032
- delete(path: string, handler: ServerRouteHandler, swaggerOptions?: SwaggerRouteOptions): void;
1033
- delete(path: string, middleware: ServerRouteMiddleware | ServerRouteMiddleware[], handler: ServerRouteHandler, swaggerOptions?: SwaggerRouteOptions): void;
961
+ nodeResponse: ServerResponse;
1034
962
  /**
1035
- * Register an OPTIONS route under this router's base path.
963
+ * The status of the response
1036
964
  */
1037
- options(path: string, handler: ServerRouteHandler, swaggerOptions?: SwaggerRouteOptions): void;
1038
- options(path: string, middleware: ServerRouteMiddleware | ServerRouteMiddleware[], handler: ServerRouteHandler, swaggerOptions?: SwaggerRouteOptions): void;
965
+ responseStatus: number;
1039
966
  /**
1040
- * Register an HEAD route under this router's base path.
967
+ * The headers of the response
1041
968
  */
1042
- head(path: string, handler: ServerRouteHandler, swaggerOptions?: SwaggerRouteOptions): void;
1043
- head(path: string, middleware: ServerRouteMiddleware | ServerRouteMiddleware[], handler: ServerRouteHandler, swaggerOptions?: SwaggerRouteOptions): void;
969
+ headers: Record<string, string>;
1044
970
  /**
1045
- * Create a grouped router that shares a base path and middlewares.
1046
- * The callback receives a child router where routes are defined; routes
1047
- * are then merged back into the parent with the composed base path and middlewares.
971
+ * The body of the response
1048
972
  */
1049
- group(path: string, middleware: ServerRouteMiddleware[] | ServerRouteMiddleware, cb: (router: Router) => void): void;
1050
- group(path: string, cb: (router: Router) => void): void;
973
+ private body;
974
+ constructor(status?: number);
1051
975
  /**
1052
- * Apply global middlewares to all routes
1053
- * @param middlewares - The middlewares to apply
1054
- * @internal
976
+ * Set a header for the response
1055
977
  */
1056
- applyGlobalMiddlewaresToAllRoutes(middlewares: ServerRouteMiddleware[]): void;
1057
- private normalizeBasePath;
1058
- private joinPath;
1059
- }
1060
-
1061
- type Params = Record<string, string>;
1062
- interface Route {
1063
- method: string;
1064
- path: string;
1065
- middleware: ServerRouteMiddleware[];
1066
- handler: ServerRouteHandler;
1067
- swaggerOptions?: SwaggerRouteOptions;
1068
- }
1069
- /**
1070
- * The client router is a subset of the router that is used to define routes on library level by the end user.
1071
- */
1072
- type ClientRouter = Omit<Router, "applyGlobalMiddlewaresToAllRoutes" | "addOrUpdate">;
1073
-
1074
- /**
1075
- * The server class that is used to create and manage the server
1076
- */
1077
- declare class Server<H extends NodeHttpClient = NodeHttpClient> implements ServerInterface {
1078
- readonly _brand: "BaldaServer";
1079
- isListening: boolean;
1080
- isProduction: boolean;
1081
- graphql: GraphQL;
1082
- readonly serverOptions: ResolvedServerOptions;
1083
- readonly router: ClientRouter;
1084
- private wasInitialized;
1085
- private serverConnector;
1086
- private globalMiddlewares;
1087
- private controllerImportBlacklistedPaths;
1088
- private notFoundHandler?;
1089
- private readonly nativeEnv;
1090
- private httpsOptions?;
978
+ setHeader(key: string, value: string): this;
1091
979
  /**
1092
- * The constructor for the server
1093
- * @warning Routes will only be defined after calling the `listen` method so you're free to define middlewares before calling it
1094
- * @param options - The options for the server
1095
- * @param options.port - The port to listen on, if not provided, it will use the PORT environment variable, if not provided, it will default to 80
1096
- * @param options.host - The hostname to listen on, if not provided, it will use the HOST environment variable, if not provided, it will default to 0.0.0.0
1097
- * @param options.controllerPatterns - The patterns to match for controllers, defaults to an empty array
1098
- * @param options.plugins - The plugins to apply to the server, by default no plugins are applied, plugins are applied in the order they are defined in the options
1099
- * @param options.logger - The logger to use for the server, by default a default logger is used
1100
- * @param options.tapOptions - Options fetch to the runtime server before the server is up and running
980
+ * Set the status of the response, status defaults to 200
1101
981
  */
1102
- constructor(options?: ServerOptions<H>);
1103
- get url(): string;
1104
- get port(): number;
1105
- get host(): string;
1106
- get routes(): Route[];
1107
- hash(data: string): Promise<string>;
1108
- compareHash(hash: string, data: string): Promise<boolean>;
1109
- getEnvironment(): Record<string, string>;
1110
- tmpDir(...append: string[]): string;
1111
- mkdir(path: string, options?: {
1112
- recursive?: boolean;
1113
- mode?: number | string;
1114
- }): Promise<void>;
1115
- get(path: string, handler: ServerRouteHandler): void;
1116
- get(path: string, options: StandardMethodOptions, handler: ServerRouteHandler): void;
1117
- post(path: string, handler: ServerRouteHandler): void;
1118
- post(path: string, options: StandardMethodOptions, handler: ServerRouteHandler): void;
1119
- patch(path: string, handler: ServerRouteHandler): void;
1120
- patch(path: string, options: StandardMethodOptions, handler: ServerRouteHandler): void;
1121
- put(path: string, handler: ServerRouteHandler): void;
1122
- put(path: string, options: StandardMethodOptions, handler: ServerRouteHandler): void;
1123
- delete(path: string, handler: ServerRouteHandler): void;
1124
- delete(path: string, options: StandardMethodOptions, handler: ServerRouteHandler): void;
1125
- options(path: string, handler: ServerRouteHandler): void;
1126
- options(path: string, options: StandardMethodOptions, handler: ServerRouteHandler): void;
1127
- head(path: string, handler: ServerRouteHandler): void;
1128
- head(path: string, options: StandardMethodOptions, handler: ServerRouteHandler): void;
1129
- group(path: string, middleware: ServerRouteMiddleware[] | ServerRouteMiddleware, cb: (router: ClientRouter) => void): void;
1130
- group(path: string, cb: (router: ClientRouter) => void): void;
1131
- getNodeServer(): RuntimeServerMap<"node", H>;
1132
- getBunServer(): RuntimeServerMap<"bun">;
1133
- getDenoServer(): RuntimeServerMap<"deno">;
1134
- embed(key: string, value: any): void;
1135
- exit(code?: number): void;
1136
- on(event: SignalEvent, cb: () => SyncOrAsync): void;
1137
- on(event: string, cb: () => SyncOrAsync): void;
1138
- once(event: SignalEvent, cb: () => SyncOrAsync): void;
1139
- once(event: string, cb: () => SyncOrAsync): void;
1140
- use(...middlewares: ServerRouteMiddleware[]): void;
1141
- useExpress(pathOrMiddleware: string | RequestHandler | Router$1, maybeMiddleware?: RequestHandler | Router$1): void;
1142
- expressMiddleware(middleware: RequestHandler): ServerRouteMiddleware;
1143
- mountExpressRouter(basePath: string, expressRouter: Router$1): void;
1144
- setErrorHandler(errorHandler?: ServerErrorHandler): void;
1145
- setNotFoundHandler(notFoundHandler?: ServerRouteHandler): void;
1146
- listen(cb?: ServerListenCallback): void;
1147
- waitUntilListening(): Promise<void>;
1148
- close(): Promise<void>;
1149
- disconnect(): Promise<void>;
1150
- configureHash(options: {
1151
- iterations?: number;
1152
- saltLength?: number;
1153
- keyLength?: number;
1154
- }): void;
1155
- getMockServer(options?: Pick<ServerOptions, "controllerPatterns">): Promise<MockServer>;
1156
- private importControllers;
1157
- private extractOptionsAndHandlerFromRouteRegistration;
1158
- private applyPlugins;
982
+ status(status: number): this;
1159
983
  /**
1160
- * Initializes the server by importing the controllers and applying the plugins, it's idempotent, it will not re-import the controllers or apply the plugins if the server was already initialized (e.g. mockServer init)
1161
- * @internal
984
+ * Send a response with the given body, tries to determine the content type based on the body type, status defaults to 200
985
+ * @warning If cannot determine the content type, it will be sent as is
1162
986
  */
1163
- private bootstrap;
987
+ send(body: any): void;
1164
988
  /**
1165
- * Handles not found routes by delegating to custom handler or default error response
1166
- * Checks if the path exists for other methods and returns 405 if so
1167
- * @internal
989
+ * Send a response with the given body without any content type or encoding (as is), status defaults to 200
1168
990
  */
1169
- private handleNotFound;
991
+ raw(body: any): void;
1170
992
  /**
1171
- * Registers a not found route for all routes that are not defined
1172
- * @internal
993
+ * Send a response with the given text, status defaults to 200
1173
994
  */
1174
- private registerNotFoundRoutes;
1175
- }
1176
-
1177
- declare class MockResponse<T = any> {
1178
- private readonly response;
1179
- constructor(response: Response$1);
1180
- body(): T;
1181
- statusCode(): number;
1182
- headers(): Record<string, string>;
1183
- assertStatus(status: number): this;
1184
- assertHeader(header: string, value: string): this;
1185
- assertHeaderExists(header: string): this;
1186
- assertHeaderNotExists(header: string): this;
1187
- assertBodySubset(subset: Partial<T>): this;
1188
- assertBodyDeepEqual(expected: T): this;
1189
- assertBodyNotSubset(subset: Partial<T>): this;
1190
- assertBodyNotDeepEqual(expected: T): this;
1191
- assertCustom(assertion: (response: Response$1) => void): this;
1192
- private assertSubset;
1193
- private assertDeepEqual;
1194
- private assertNotSubset;
1195
- private assertNotDeepEqual;
1196
- private assertArraySubset;
1197
- private assertArrayDeepEqual;
1198
- private isObject;
1199
- }
1200
-
1201
- /**
1202
- * The options for the mock server, only one of body, formData, urlencoded can be provided
1203
- */
1204
- interface MockServerOptions {
995
+ text(body: string): void;
1205
996
  /**
1206
- * The body of the request, if formData is provided, it will be ignored
997
+ * Send a response with the given JSON, status defaults to 200
1207
998
  */
1208
- body?: any;
999
+ json<T extends Record<string, unknown> | Array<unknown>>(body: T): void;
1209
1000
  /**
1210
- * The form data of the request
1001
+ * Send a response with the given HTML, status defaults to 200
1211
1002
  */
1212
- formData?: FormData;
1003
+ html(htmlString: string): void;
1213
1004
  /**
1214
- * The urlencoded body of the request
1005
+ * Send a response with the given XML, status defaults to 200
1215
1006
  */
1216
- urlencoded?: Record<string, string>;
1007
+ xml(body: string): void;
1217
1008
  /**
1218
- * The headers of the request
1009
+ * Send a response with the given binary with Content-Type of application/octet-stream header, status defaults to 200
1219
1010
  */
1220
- headers?: Record<string, string>;
1011
+ download(body: Uint8Array | Buffer): void;
1221
1012
  /**
1222
- * The query parameters of the request, if provided, they will be merged with the query parameters from the path (precedence is given to the query parameters provided here)
1013
+ * Send a response with the given file content, status defaults to 200
1014
+ * @param options only affects node and bun environment
1223
1015
  */
1224
- query?: Record<string, string>;
1016
+ file(pathToFile: string, options?: {
1017
+ encoding?: string;
1018
+ flag?: string;
1019
+ }): void;
1225
1020
  /**
1226
- * The cookies of the request
1021
+ * 2XX Success
1227
1022
  */
1228
- cookies?: Record<string, string>;
1229
1023
  /**
1230
- * The ip of the request
1024
+ * 200 OK
1231
1025
  */
1232
- ip?: string;
1233
- }
1234
-
1235
- /**
1236
- * Allows to mock server requests without needing to start the server, useful for testing purposes
1237
- */
1238
- declare class MockServer {
1239
- readonly server: Server<NodeHttpClient>;
1240
- constructor(server: Server<NodeHttpClient>);
1026
+ ok(body?: any): void;
1241
1027
  /**
1242
- * Simulates an HTTP request without making an actual network call, useful for testing purposes
1243
- * Executes the middleware chain and handler of the route
1244
- * @param method - The HTTP method (GET, POST, PUT, DELETE, PATCH)
1245
- * @param path - The request path
1246
- * @param options - Request options including body, headers, query params, etc.
1247
- * @throws {Error} - If more than one of body, formData, urlencoded is provided
1028
+ * 201 Created
1248
1029
  */
1249
- request<T = any>(method: HttpMethod, path: string, options?: MockServerOptions): Promise<MockResponse<T>>;
1250
- get<T = any>(path: string, options?: Omit<MockServerOptions, "body" | "formData" | "urlencoded">): Promise<MockResponse<T>>;
1251
- post<T = any>(path: string, options?: MockServerOptions): Promise<MockResponse<T>>;
1252
- put<T = any>(path: string, options?: MockServerOptions): Promise<MockResponse<T>>;
1253
- patch<T = any>(path: string, options?: MockServerOptions): Promise<MockResponse<T>>;
1254
- delete<T = any>(path: string, options?: Omit<MockServerOptions, "body" | "formData">): Promise<MockResponse<T>>;
1030
+ created(body?: any): void;
1255
1031
  /**
1256
- * Converts FormData to a proper multipart/form-data body with boundaries
1032
+ * 202 Accepted
1257
1033
  */
1258
- private formDataToMultipart;
1259
- private validateOptions;
1260
- }
1261
-
1262
- type CompressionOptions = {
1034
+ accepted(body?: any): void;
1263
1035
  /**
1264
- * Minimum response size in bytes to trigger compression
1265
- * Default: 1024 (1KB)
1036
+ * 204 No Content
1266
1037
  */
1267
- threshold?: number;
1038
+ noContent(): void;
1268
1039
  /**
1269
- * Compression level (0-9)
1270
- * 0 = no compression, 9 = maximum compression
1271
- * Default: 6
1040
+ * 206 Partial Content
1272
1041
  */
1273
- level?: number;
1042
+ partialContent(body?: any): void;
1274
1043
  /**
1275
- * Content types to compress (regex patterns)
1276
- * Default: common compressible types (text, json, xml, javascript, etc.)
1044
+ * 3XX Redirection
1277
1045
  */
1278
- filter?: RegExp[];
1279
- };
1280
-
1281
- type CorsMethods = "GET" | "POST" | "PUT" | "DELETE" | "OPTIONS" | "PATCH" | "HEAD";
1282
- /**
1283
- * Options for CORS middleware, similar to Express.js
1284
- */
1285
- type CorsOptions = {
1286
1046
  /**
1287
- * Configures the Access-Control-Allow-Origin CORS header.
1288
- *
1289
- * ⚠️ WARNING: The default value '*' allows ALL origins, which is insecure for production.
1290
- *
1291
- * For production, explicitly set allowed origins:
1292
- * - Single origin: 'https://example.com'
1293
- * - Multiple origins: ['https://example.com', 'https://app.example.com']
1294
- * - Pattern matching: /^https:\/\/.*\.example\.com$/
1295
- *
1296
- * Defaults to '*' (allows all origins) - only suitable for development/public APIs.
1047
+ * 300 Multiple Choices
1297
1048
  */
1298
- origin?: string | RegExp | (string | RegExp)[];
1049
+ multipleChoices(url: string): void;
1050
+ redirect(url: string): void;
1299
1051
  /**
1300
- * Configures the Access-Control-Allow-Methods CORS header. Defaults to 'GET,HEAD,PUT,PATCH,POST,DELETE'.
1052
+ * 301 Moved Permanently
1301
1053
  */
1302
- methods?: CorsMethods[] | string;
1054
+ movedPermanently(url: string): void;
1303
1055
  /**
1304
- * Configures the Access-Control-Allow-Headers CORS header. Defaults to allowing all requested headers.
1056
+ * 302 Found (Temporary Redirect)
1305
1057
  */
1306
- allowedHeaders?: string[] | string;
1058
+ found(url: string): void;
1307
1059
  /**
1308
- * Configures the Access-Control-Expose-Headers CORS header. Defaults to none.
1060
+ * 303 See Other
1309
1061
  */
1310
- exposedHeaders?: string[] | string;
1062
+ seeOther(url: string): void;
1311
1063
  /**
1312
- * Configures the Access-Control-Allow-Credentials CORS header. Defaults to false.
1064
+ * 304 Not Modified
1313
1065
  */
1314
- credentials?: boolean;
1066
+ notModified(): void;
1315
1067
  /**
1316
- * Configures the Access-Control-Max-Age CORS header. Defaults to undefined (not sent).
1068
+ * 307 Temporary Redirect
1317
1069
  */
1318
- maxAge?: number;
1070
+ temporaryRedirect(url: string): void;
1319
1071
  /**
1320
- * Pass the CORS preflight response to the next handler. Defaults to false (ends response).
1072
+ * 308 Permanent Redirect
1321
1073
  */
1322
- preflightContinue?: boolean;
1074
+ permanentRedirect(url: string): void;
1323
1075
  /**
1324
- * Provides a status code to use for successful OPTIONS requests, if preflightContinue is false. Defaults to 204.
1076
+ * 4XX Client Errors
1325
1077
  */
1326
- optionsSuccessStatus?: number;
1327
- };
1328
-
1329
- type ExpressHandler = RequestHandler;
1330
- type ExpressRouter = IRouter;
1331
- interface ExpressAdapterOptions {
1332
- basePath?: string;
1333
- }
1334
-
1335
- /**
1336
- * Options for helmet middleware
1337
- */
1338
- interface HelmetOptions {
1339
- dnsPrefetchControl?: boolean;
1340
- frameguard?: boolean | {
1341
- action: "DENY" | "SAMEORIGIN" | string;
1342
- };
1343
- hsts?: boolean | {
1344
- maxAge?: number;
1345
- includeSubDomains?: boolean;
1346
- preload?: boolean;
1347
- };
1348
- contentTypeOptions?: boolean;
1349
- ieNoOpen?: boolean;
1350
- xssFilter?: boolean;
1351
- referrerPolicy?: false | string;
1352
- crossOriginResourcePolicy?: false | string;
1353
- crossOriginOpenerPolicy?: false | string;
1354
- crossOriginEmbedderPolicy?: false | string;
1355
- contentSecurityPolicy?: false | string;
1356
- }
1357
-
1358
- type LoggerOptions = Parameters<typeof pino$1>[0];
1359
-
1360
- interface LogOptions {
1361
1078
  /**
1362
- * Whether to log the request.
1363
- * @default true
1079
+ * 400 Bad Request
1364
1080
  */
1365
- logRequest?: boolean;
1081
+ badRequest(body?: any): void;
1366
1082
  /**
1367
- * What to log for the request.
1368
- * @default true for all properties
1083
+ * 401 Unauthorized
1369
1084
  */
1370
- requestPayload?: {
1371
- method?: boolean;
1372
- url?: boolean;
1373
- ip?: boolean;
1374
- headers?: boolean;
1375
- /** Only json objects and strings are logged */
1376
- body?: boolean;
1377
- };
1085
+ unauthorized(body?: any): void;
1378
1086
  /**
1379
- * Whether to log the response.
1380
- * @default true
1087
+ * 403 Forbidden
1381
1088
  */
1382
- logResponse?: boolean;
1089
+ forbidden(body?: any): void;
1383
1090
  /**
1384
- * Whether to log the response body.
1385
- * @default false
1091
+ * 404 Not Found
1386
1092
  */
1387
- responsePayload?: {
1388
- status?: boolean;
1389
- headers?: boolean;
1390
- body?: boolean;
1391
- };
1093
+ notFound(body?: any): void;
1094
+ /**
1095
+ * 405 Method Not Allowed
1096
+ */
1097
+ methodNotAllowed(body?: any): void;
1098
+ /**
1099
+ * 406 Not Acceptable
1100
+ */
1101
+ notAcceptable(body?: any): void;
1102
+ /**
1103
+ * 409 Conflict
1104
+ */
1105
+ conflict(body?: any): void;
1106
+ /**
1107
+ * 410 Gone
1108
+ */
1109
+ gone(body?: any): void;
1110
+ /**
1111
+ * 413 Payload Too Large
1112
+ */
1113
+ payloadTooLarge(body?: any): void;
1392
1114
  /**
1393
- * What to log for the response.
1394
- * @default true for all properties
1115
+ * 415 Unsupported Media Type
1395
1116
  */
1396
- pinoOptions?: LoggerOptions;
1397
- }
1398
-
1399
- type MethodOverrideOptions = {
1117
+ unsupportedMediaType(body?: any): void;
1400
1118
  /**
1401
- * HTTP methods that can be overridden
1402
- * Default: ['POST']
1119
+ * 422 Unprocessable Entity
1403
1120
  */
1404
- methods?: string[];
1121
+ unprocessableEntity(body?: any): void;
1405
1122
  /**
1406
- * Header name to read the override method from
1407
- * Default: 'X-HTTP-Method-Override'
1123
+ * 429 Too Many Requests
1408
1124
  */
1409
- header?: string;
1410
- };
1411
-
1412
- type StorageStrategy = "memory" | "custom";
1413
- type BaseRateLimiterOptions = {
1125
+ tooManyRequests(body?: any): void;
1414
1126
  /**
1415
- * The number of requests per window
1416
- * @default 100
1127
+ * 5XX Server Errors
1417
1128
  */
1418
- limit?: number;
1129
+ internalServerError(body?: any): void;
1419
1130
  /**
1420
- * The message to return when the rate limit is exceeded
1421
- * @default "ERR_RATE_LIMIT_EXCEEDED"
1131
+ * 501 Not Implemented
1422
1132
  */
1423
- message?: string;
1133
+ notImplemented(body?: any): void;
1424
1134
  /**
1425
- * The status code to return when the rate limit is exceeded
1426
- * @default 429
1135
+ * 502 Bad Gateway
1427
1136
  */
1428
- statusCode?: number;
1137
+ badGateway(body?: any): void;
1429
1138
  /**
1430
- * The storage strategy to use
1431
- * @default "memory"
1139
+ * 503 Service Unavailable
1432
1140
  */
1433
- storageStrategy?: StorageStrategy;
1434
- };
1435
- /**
1436
- * Key Strategy
1437
- */
1438
- type IpRateLimiterOptions = {
1141
+ serviceUnavailable(body?: any): void;
1439
1142
  /**
1440
- * The type of rate limiter
1143
+ * 504 Gateway Timeout
1441
1144
  */
1442
- type: "ip";
1443
- } & BaseRateLimiterOptions;
1444
- type CustomRateLimiterOptions = {
1145
+ gatewayTimeout(body?: any): void;
1445
1146
  /**
1446
- * The type of rate limiter
1147
+ * 505 HTTP Version Not Supported
1447
1148
  */
1448
- type: "custom";
1149
+ httpVersionNotSupported(body?: any): void;
1449
1150
  /**
1450
- * Generate a key for the rate limiter from the request (e.g. user id, email, etc.)
1151
+ * Set a cookie for the response, cookie middleware must be registered in order to use this function
1451
1152
  */
1452
- key: (req: Request) => string;
1153
+ cookie?(_name: string, _value: string, _options?: CookieOptions): void;
1453
1154
  /**
1454
- * The storage strategy to use
1455
- * @default "memory"
1155
+ * Clear a cookie for the response, cookie middleware must be registered in order to use this function
1456
1156
  */
1457
- storageStrategy?: StorageStrategy;
1458
- } & BaseRateLimiterOptions;
1459
- /**
1460
- * Memory Storage Strategy
1461
- */
1462
- type MemoryStorageStrategy = {
1157
+ clearCookie?(_name: string, _options?: CookieOptions): void;
1463
1158
  /**
1464
- * The type of storage strategy
1159
+ * Stream a response using an async generator or ReadableStream
1160
+ * Sets appropriate headers for Server-Sent Events by default
1465
1161
  */
1466
- type: "memory";
1162
+ stream(source: AsyncGenerator<any> | Generator<any> | ReadableStream, options?: {
1163
+ customHeaders?: Record<string, string>;
1164
+ }): void;
1467
1165
  /**
1468
- * The window in milliseconds
1469
- * @default 60000
1166
+ * Get the body of the response
1470
1167
  */
1471
- windowMs?: number;
1472
- };
1168
+ getBody(): any;
1169
+ }
1170
+
1473
1171
  /**
1474
- * Custom Storage Strategy
1172
+ * Singleton that handles the routing of requests to the appropriate handler(s).
1475
1173
  */
1476
- type CustomStorageStrategy = {
1174
+ declare class Router {
1175
+ private trees;
1176
+ private routes;
1177
+ private middlewares;
1178
+ private basePath;
1179
+ private staticRouteCache;
1477
1180
  /**
1478
- * The type of storage strategy
1181
+ * Create a new router with an optional base path and default middlewares.
1182
+ * Base path is normalized so it never produces duplicate slashes and never ends with a trailing slash (except root).
1479
1183
  */
1480
- type: "custom";
1184
+ constructor(basePath?: string, middlewares?: ServerRouteMiddleware[]);
1185
+ /** Returns a shallow copy of all registered routes. */
1186
+ getRoutes(): Route[];
1481
1187
  /**
1482
- * Set a value in the storage
1188
+ * Add or update a route
1189
+ * @internal
1483
1190
  */
1484
- set: (key: string, value: any) => Promise<void>;
1191
+ addOrUpdate(method: HttpMethod, path: string, middleware: ServerRouteMiddleware[], handler: ServerRouteHandler, swaggerOptions?: SwaggerRouteOptions): void;
1485
1192
  /**
1486
- * Get a value from the storage
1193
+ * Find the matching route for the given HTTP method and path.
1194
+ * Returns the resolved middleware chain, handler, and extracted params; or null if not found.
1195
+ * Uses O(1) cache lookup for static routes, falls back to O(k) tree traversal for dynamic routes.
1487
1196
  */
1488
- get: (key: string) => Promise<any>;
1489
- };
1490
- type StorageOptions$1 = MemoryStorageStrategy | CustomStorageStrategy;
1491
- /**
1492
- * Rate limiter options
1493
- */
1494
- type RateLimiterKeyOptions = IpRateLimiterOptions | CustomRateLimiterOptions;
1495
-
1496
- type SessionStore = {
1497
- get: (sid: string) => Promise<Record<string, any> | undefined>;
1498
- set: (sid: string, value: Record<string, any>, ttlSeconds?: number) => Promise<void>;
1499
- destroy: (sid: string) => Promise<void>;
1500
- };
1501
- type SessionOptions = {
1502
- /** Cookie name used for session id */
1503
- name?: string;
1504
- /** Secret used to sign session id (optional, for future) */
1505
- secret?: string;
1506
- /** TTL seconds for session */
1507
- ttl?: number;
1508
- /** Custom store, default is in-memory */
1509
- store?: SessionStore;
1510
- /** Whether to set HttpOnly secure flags */
1511
- cookie?: {
1512
- path?: string;
1513
- httpOnly?: boolean;
1514
- secure?: boolean;
1515
- sameSite?: "Strict" | "Lax" | "None";
1516
- domain?: string;
1517
- };
1518
- };
1519
-
1520
- /**
1521
- * Swagger plugin that serves the swagger UI and JSON specification, by default the UI will be available at /docs and the JSON specification at /docs/json
1522
- * @warning The json specification is always available at /${globalOptions.path}/json
1523
- * @internal
1524
- */
1525
- declare const swagger: (globalOptions?: SwaggerGlobalOptions | boolean) => void;
1526
-
1527
- type TimeoutOptions = {
1528
- /** Timeout in milliseconds */
1529
- ms: number;
1530
- };
1531
-
1532
- type TrustProxyOptions = {
1533
- /** Enable using X-Forwarded-* headers to determine client IP */
1534
- trust?: boolean;
1535
- /** Header name to read the client IP chain from */
1536
- header?: string;
1537
- /** Select which IP from the chain to use: 'first' (client) or 'last' (closest proxy) */
1538
- hop?: "first" | "last";
1539
- };
1540
-
1541
- /**
1542
- * The next function.
1543
- * This is the function that is passed to the handler function.
1544
- * It has a pointer to the next middleware or handler function of the middleware chain.
1545
- */
1546
- type NextFunction = () => SyncOrAsync;
1547
-
1548
- interface JsonOptions {
1197
+ find(method: string, rawPath: string): {
1198
+ middleware: ServerRouteMiddleware[];
1199
+ handler: ServerRouteHandler;
1200
+ params: Params;
1201
+ } | null;
1549
1202
  /**
1550
- * The maximum size of the JSON body in bytes.
1551
- * If the body is larger than this limit, the request will be rejected.
1552
- * Default: 100kb
1203
+ * Register a GET route under this router's base path.
1553
1204
  */
1554
- sizeLimit?: `${number}mb` | `${number}kb`;
1205
+ get(path: string, handler: ServerRouteHandler, swaggerOptions?: SwaggerRouteOptions): void;
1206
+ get(path: string, middleware: ServerRouteMiddleware | ServerRouteMiddleware[], handler: ServerRouteHandler, swaggerOptions?: SwaggerRouteOptions): void;
1555
1207
  /**
1556
- * If true, the JSON body will be parsed as an empty object if it is empty.
1557
- * Default: false (body will be undefined)
1208
+ * Register a POST route under this router's base path.
1558
1209
  */
1559
- parseEmptyBodyAsObject?: boolean;
1210
+ post(path: string, handler: ServerRouteHandler, swaggerOptions?: SwaggerRouteOptions): void;
1211
+ post(path: string, middleware: ServerRouteMiddleware | ServerRouteMiddleware[], handler: ServerRouteHandler, swaggerOptions?: SwaggerRouteOptions): void;
1560
1212
  /**
1561
- * The custom error message to return when the JSON body is too large.
1562
- * Default: response with status 413 and body { message: "ERR_REQUEST_BODY_TOO_LARGE" }
1213
+ * Register a PATCH route under this router's base path.
1563
1214
  */
1564
- customErrorMessage?: {
1565
- status?: number;
1566
- message?: string;
1567
- };
1568
- }
1569
-
1570
- /**
1571
- * Options for URL-encoded middleware
1572
- */
1573
- type UrlEncodedOptions = {
1215
+ patch(path: string, handler: ServerRouteHandler, swaggerOptions?: SwaggerRouteOptions): void;
1216
+ patch(path: string, middleware: ServerRouteMiddleware | ServerRouteMiddleware[], handler: ServerRouteHandler, swaggerOptions?: SwaggerRouteOptions): void;
1574
1217
  /**
1575
- * The maximum size of the URL-encoded body.
1576
- * Supports formats like "5mb", "100kb".
1577
- * Defaults to "1mb".
1218
+ * Register a PUT route under this router's base path.
1578
1219
  */
1579
- limit?: `${number}mb` | `${number}kb`;
1220
+ put(path: string, handler: ServerRouteHandler, swaggerOptions?: SwaggerRouteOptions): void;
1221
+ put(path: string, middleware: ServerRouteMiddleware | ServerRouteMiddleware[], handler: ServerRouteHandler, swaggerOptions?: SwaggerRouteOptions): void;
1580
1222
  /**
1581
- * Whether to parse extended syntax (objects and arrays). Defaults to false.
1223
+ * Register a DELETE route under this router's base path.
1582
1224
  */
1583
- extended?: boolean;
1225
+ delete(path: string, handler: ServerRouteHandler, swaggerOptions?: SwaggerRouteOptions): void;
1226
+ delete(path: string, middleware: ServerRouteMiddleware | ServerRouteMiddleware[], handler: ServerRouteHandler, swaggerOptions?: SwaggerRouteOptions): void;
1584
1227
  /**
1585
- * The character encoding to use when parsing. Defaults to 'utf8'.
1228
+ * Register an OPTIONS route under this router's base path.
1586
1229
  */
1587
- charset?: string;
1230
+ options(path: string, handler: ServerRouteHandler, swaggerOptions?: SwaggerRouteOptions): void;
1231
+ options(path: string, middleware: ServerRouteMiddleware | ServerRouteMiddleware[], handler: ServerRouteHandler, swaggerOptions?: SwaggerRouteOptions): void;
1588
1232
  /**
1589
- * Whether to allow empty values. Defaults to true.
1233
+ * Register an HEAD route under this router's base path.
1590
1234
  */
1591
- allowEmpty?: boolean;
1235
+ head(path: string, handler: ServerRouteHandler, swaggerOptions?: SwaggerRouteOptions): void;
1236
+ head(path: string, middleware: ServerRouteMiddleware | ServerRouteMiddleware[], handler: ServerRouteHandler, swaggerOptions?: SwaggerRouteOptions): void;
1592
1237
  /**
1593
- * Maximum number of parameters to parse. Defaults to 1000.
1238
+ * Create a grouped router that shares a base path and middlewares.
1239
+ * The callback receives a child router where routes are defined; routes
1240
+ * are then merged back into the parent with the composed base path and middlewares.
1594
1241
  */
1595
- parameterLimit?: number;
1596
- };
1242
+ group(path: string, middleware: ServerRouteMiddleware[] | ServerRouteMiddleware, cb: (router: Router) => void): void;
1243
+ group(path: string, cb: (router: Router) => void): void;
1244
+ /**
1245
+ * Apply global middlewares to all routes
1246
+ * @param middlewares - The middlewares to apply
1247
+ * @internal
1248
+ */
1249
+ applyGlobalMiddlewaresToAllRoutes(middlewares: ServerRouteMiddleware[]): void;
1250
+ private normalizeBasePath;
1251
+ private joinPath;
1252
+ }
1597
1253
 
1598
- type BodyParserOptions = {
1599
- json?: JsonOptions;
1600
- urlencoded?: UrlEncodedOptions;
1601
- fileParser?: FilePluginOptions;
1602
- };
1254
+ type Params = Record<string, string>;
1255
+ interface Route {
1256
+ method: string;
1257
+ path: string;
1258
+ middleware: ServerRouteMiddleware[];
1259
+ handler: ServerRouteHandler;
1260
+ swaggerOptions?: SwaggerRouteOptions;
1261
+ }
1262
+ /**
1263
+ * The client router is a subset of the router that is used to define routes on library level by the end user.
1264
+ */
1265
+ type ClientRouter = Omit<Router, "applyGlobalMiddlewaresToAllRoutes" | "addOrUpdate">;
1603
1266
 
1604
1267
  type ServerPlugin = {
1605
1268
  bodyParser?: BodyParserOptions;
@@ -1662,7 +1325,7 @@ type ServerOptions<H extends NodeHttpClient = NodeHttpClient> = {
1662
1325
  */
1663
1326
  graphql?: GraphQLOptions;
1664
1327
  /**
1665
- * The ajv instance to use for the server for validation, by default a global instance is used, you can pass a custom instance to use for the server
1328
+ * Custom AJV instance to use for the server for validation, by default a global instance is used, you can pass a custom instance to use for the server validation
1666
1329
  * @example
1667
1330
  * ```ts
1668
1331
  * const server = new Server({
@@ -1671,6 +1334,22 @@ type ServerOptions<H extends NodeHttpClient = NodeHttpClient> = {
1671
1334
  * ```
1672
1335
  */
1673
1336
  ajvInstance?: Ajv;
1337
+ /**
1338
+ * An AbortSignal to gracefully shutdown the server when aborted
1339
+ * @example
1340
+ * ```ts
1341
+ * const controller = new AbortController();
1342
+ * const server = new Server({
1343
+ * abortSignal: controller.signal,
1344
+ * });
1345
+ *
1346
+ * await server.waitUntilListening();
1347
+ *
1348
+ * // Later: abort the server
1349
+ * controller.abort();
1350
+ * ```
1351
+ */
1352
+ abortSignal?: AbortSignal;
1674
1353
  } & (H extends "https" | "http2-secure" ? HttpsOptions<H> : {});
1675
1354
  /** Internal resolved server options with all required properties */
1676
1355
  type ResolvedServerOptions = {
@@ -1682,6 +1361,7 @@ type ResolvedServerOptions = {
1682
1361
  tapOptions: ServerTapOptions;
1683
1362
  swagger: Parameters<typeof swagger>[0] | boolean;
1684
1363
  graphql?: GraphQLOptions;
1364
+ abortSignal?: AbortSignal;
1685
1365
  };
1686
1366
  type ServerErrorHandler = (req: Request, res: Response$1, next: NextFunction, error: Error) => SyncOrAsync;
1687
1367
  interface ServerInterface {
@@ -1766,246 +1446,652 @@ interface ServerInterface {
1766
1446
  */
1767
1447
  useExpress: (pathOrMiddleware: string | RequestHandler | ExpressRouter, maybeMiddleware?: RequestHandler | ExpressRouter) => void;
1768
1448
  /**
1769
- * Convert an Express middleware to a Balda-compatible middleware
1770
- * @param middleware - The Express middleware to convert
1771
- * @returns A Balda-compatible middleware
1449
+ * Convert an Express middleware to a Balda-compatible middleware
1450
+ * @param middleware - The Express middleware to convert
1451
+ * @returns A Balda-compatible middleware
1452
+ */
1453
+ expressMiddleware: (middleware: RequestHandler) => ServerRouteMiddleware;
1454
+ /**
1455
+ * Mount an Express router at a specific base path
1456
+ * @param basePath - The base path to mount the router at
1457
+ * @param expressRouter - The Express router to mount
1458
+ */
1459
+ mountExpressRouter: (basePath: string, expressRouter: ExpressRouter) => void;
1460
+ /**
1461
+ * Shorthand for the server.router.get method
1462
+ */
1463
+ get: (...args: any[]) => void;
1464
+ /**
1465
+ * Shorthand for the server.router.post method
1466
+ */
1467
+ post: (...args: any[]) => void;
1468
+ /**
1469
+ * Shorthand for the server.router.put method
1470
+ */
1471
+ put: (...args: any[]) => void;
1472
+ /**
1473
+ * Shorthand for the server.router.patch method
1474
+ */
1475
+ patch: (...args: any[]) => void;
1476
+ /**
1477
+ * Shorthand for the server.router.delete method
1478
+ */
1479
+ delete: (...args: any[]) => void;
1480
+ /**
1481
+ * Shorthand for the server.router.options method
1482
+ */
1483
+ options: (...args: any[]) => void;
1484
+ /**
1485
+ * Shorthand for the server.router.head method
1486
+ */
1487
+ head: (...args: any[]) => void;
1488
+ /**
1489
+ * Shorthand for the server.router.group method
1490
+ */
1491
+ group: (...args: any[]) => void;
1492
+ /**
1493
+ * Get the node server instance, you must be using node runtime to use this method based on the nodeHttpClient option passed to the server constructor (defaults to http)
1494
+ * @throws if the runtime is not node
1495
+ */
1496
+ getNodeServer: () => RuntimeServerMap<"node", NodeHttpClient>;
1497
+ /**
1498
+ * Get the bun server instance, you must be using bun runtime to use this method
1499
+ * @throws if the runtime is not bun
1500
+ */
1501
+ getBunServer: () => RuntimeServerMap<"bun">;
1502
+ /**
1503
+ * Get the deno server instance, you must be using deno runtime to use this method
1504
+ * @throws if the runtime is not deno
1505
+ */
1506
+ getDenoServer: () => RuntimeServerMap<"deno">;
1507
+ /**
1508
+ * Embed the given key into the server instance, this is useful for embedding the server with custom context inside the server instance, you can extend the server with your own properties to type it
1509
+ * @param key - The key to embed
1510
+ * @param value - The value to embed
1511
+ * @warning There are some keys that are protected and cannot be embedded, you can find the list of protected keys in the PROTECTED_KEYS constant
1512
+ * @throws An error if the key is already defined in the server instance or if the key is protected
1513
+ * @example
1514
+ * ```typescript
1515
+ * // For better type safety, you can declare a module for the server interface
1516
+ * declare module "balda" {
1517
+ * interface Server {
1518
+ * myCustomProperty: string;
1519
+ * }
1520
+ * }
1521
+ *
1522
+ * server.embed("myCustomProperty", "myCustomValue");
1523
+ * console.log(server.myCustomProperty); // Type safe if ServerInterface is extended
1524
+ * ```
1525
+ */
1526
+ embed: (key: string, value: any) => void;
1527
+ /**
1528
+ * Register a signal event listener to the server, this is useful for handling signals like SIGINT, SIGTERM, etc.
1529
+ * @param event - The signal event to listen for
1530
+ * @param cb - The callback to be called when the signal event is received
1531
+ */
1532
+ on: (event: SignalEvent, cb: () => SyncOrAsync) => void;
1533
+ /**
1534
+ * Register a signal event listener to the server, this is useful for handling signals like SIGINT, SIGTERM, etc.
1535
+ * @param event - The signal event to listen for
1536
+ * @param cb - The callback to be called when the signal event is received
1537
+ */
1538
+ once: (event: SignalEvent, cb: () => SyncOrAsync) => void;
1539
+ /**
1540
+ * Register a global middleware to be applied to all routes after the listener is bound, the middleware is applied in the order it is registered
1541
+ */
1542
+ use: (middleware: ServerRouteMiddleware) => void;
1543
+ /**
1544
+ * Set the error handler for the server
1545
+ * @param errorHandler - The error handler to be applied to all routes
1546
+ */
1547
+ setErrorHandler: (errorHandler?: ServerErrorHandler) => void;
1548
+ /**
1549
+ * Sets a custom handler for 404 Not Found responses.
1550
+ * If not set, the default RouteNotFoundError will be used.
1551
+ *
1552
+ * @param notFoundHandler - Optional handler to customize 404 responses
1553
+ * @example
1554
+ * server.setNotFoundHandler((req, res) => {
1555
+ * res.status(404).json({ error: "Custom not found message" });
1556
+ * });
1557
+ */
1558
+ setNotFoundHandler: (notFoundHandler?: ServerRouteHandler) => void;
1559
+ /**
1560
+ * Binds the server to the port and hostname defined in the serverOptions, meant to be called only once
1561
+ * It initializes the server without blocking the event loop, you can pass a callback to be called when the server is listening
1562
+ * Use `waitUntilListening` instead if you want to wait for the server to be listening for requests before returning
1563
+ * @warning All routes defined with decorators are defined on this method just before the server starts listening for requests
1564
+ */
1565
+ listen: (cb?: ServerListenCallback) => void;
1566
+ /**
1567
+ * Binds the server to the port and hostname defined in the serverOptions, meant to be called only once
1568
+ * It initializes the server blocking the event loop, it will wait for the server to be listening for requests before returning
1569
+ * Use `listen` instead if you want to initialize the server without blocking the event loop
1570
+ * @warning All routes defined with decorators are defined on this method just before the server starts listening for requests
1571
+ */
1572
+ waitUntilListening: () => Promise<void>;
1573
+ /**
1574
+ * Closes the server and frees the port
1575
+ * This method is idempotent and can be called multiple times safely
1576
+ * @alias disconnect
1577
+ */
1578
+ close: () => Promise<void>;
1579
+ /**
1580
+ * Disconnects the server and frees the port
1581
+ * This method is idempotent and can be called multiple times safely
1582
+ * Subsequent calls after the first will have no effect
1583
+ */
1584
+ disconnect: () => Promise<void>;
1585
+ /**
1586
+ * Configure hash settings for password hashing
1587
+ * @param options - Hash configuration options
1588
+ * @param options.iterations - Number of PBKDF2 iterations (default: 600,000)
1589
+ * @param options.saltLength - Salt length in bytes (default: 16)
1590
+ * @param options.keyLength - Key length in bits (default: 256)
1591
+ */
1592
+ configureHash: (options: {
1593
+ iterations?: number;
1594
+ saltLength?: number;
1595
+ keyLength?: number;
1596
+ }) => void;
1597
+ /**
1598
+ * Returns a mock server instance that can be used to test the server without starting it
1599
+ * It will import the controllers and apply the plugins to the mock server
1600
+ * @param options - The options for the mock server
1601
+ * @param options.controllerPatterns - Custom controller patterns to import if the mock server must not be initialized with the same controller patterns as the server
1602
+ */
1603
+ getMockServer: () => Promise<MockServer>;
1604
+ /**
1605
+ * Exit current runtime process with the given code based on the current runtime
1606
+ * @param code - The code to exit with, defaults to 0
1607
+ * @example
1608
+ * ```typescript
1609
+ * server.exit(1); // If node process.exit(1) is called
1610
+ * server.exit(); // If deno Deno.exit(0) is called
1611
+ * ```
1612
+ */
1613
+ exit: (code?: number) => void;
1614
+ }
1615
+ type StandardMethodOptions = {
1616
+ middlewares?: ServerRouteMiddleware[] | ServerRouteMiddleware;
1617
+ swagger?: SwaggerRouteOptions;
1618
+ };
1619
+ type SignalEvent = Deno.Signal | NodeJS.Signals;
1620
+
1621
+ type RunTimeType = "bun" | "node" | "deno";
1622
+
1623
+ type HttpMethod = "GET" | "POST" | "PUT" | "DELETE" | "PATCH" | "OPTIONS" | "HEAD";
1624
+ type NodeServer = Server$2 | Server$1 | Http2Server;
1625
+ type RuntimeServer = NodeServer | ReturnType<typeof Bun.serve> | ReturnType<typeof Deno.serve>;
1626
+ type RuntimeServerMap<T extends RunTimeType, H extends NodeHttpClient = "http"> = T extends "node" ? H extends "https" ? Server$1 : H extends "http2" | "http2-secure" ? Http2Server : Server$2 : T extends "bun" ? ReturnType<typeof Bun.serve> : T extends "deno" ? ReturnType<typeof Deno.serve> : never;
1627
+ type HttpsOptions<T extends NodeHttpClient> = T extends "https" | "http2-secure" ? {
1628
+ /** HTTPS/TLS options, required when nodeHttpClient is 'https' or 'http2-secure' */
1629
+ httpsOptions: ServerOptions$1;
1630
+ } : never;
1631
+ type ServerConnectInput<H extends NodeHttpClient = NodeHttpClient> = {
1632
+ /** The port to listen on, defaults to 80 */
1633
+ port: number;
1634
+ /** The hostname to listen on, defaults to 0.0.0.0 */
1635
+ host: string;
1636
+ /** The server routes with their corresponding handler */
1637
+ routes: ServerRoute[];
1638
+ /** The options for the server tap function */
1639
+ tapOptions?: ServerTapOptions;
1640
+ /** The runtime to use for the server */
1641
+ runtime: RunTimeType;
1642
+ /** Specific node client to use */
1643
+ nodeHttpClient: H;
1644
+ /** The graphql options to apply to the server */
1645
+ graphql?: GraphQL;
1646
+ } & (H extends "https" ? HttpsOptions<H> : {});
1647
+ type ServerRouteMiddleware = (req: Request, res: Response$1, next: NextFunction) => SyncOrAsync;
1648
+ type ServerRouteHandler = (req: Request, res: Response$1) => SyncOrAsync;
1649
+ interface ServerRoute {
1650
+ /** The path for the route */
1651
+ path: string;
1652
+ /** The HTTP method for the route */
1653
+ method: HttpMethod;
1654
+ /** The handler to call when the route is requested */
1655
+ handler: ServerRouteHandler;
1656
+ /** The middleware chain to call before the handler */
1657
+ middlewares?: ServerRouteMiddleware[];
1658
+ }
1659
+ type ServerListenCallback = ({ port, host, url, }: {
1660
+ port: number;
1661
+ host: string;
1662
+ url: string;
1663
+ }) => SyncOrAsync;
1664
+ /**
1665
+ * Custom bun fetch call to be used as an hook inside Bun.serve method
1666
+ */
1667
+ type CustomBunFetch = (req: Request, server: Bun.Server<any>) => SyncOrAsync;
1668
+ /**
1669
+ * Custom deno fetch call to be used as an hook inside Deno.serve method
1670
+ */
1671
+ type CustomDenoFetch = (...options: Parameters<Parameters<typeof Deno.serve>[0]["handler"]>) => SyncOrAsync<Response | void>;
1672
+ /**
1673
+ * The options for the server tap function, allows you to interact with the server behavior before it is used to listen for incoming requests
1674
+ */
1675
+ type ServerTapOptionsBuilder<T extends RunTimeType> = T extends "node" ? (req: Omit<IncomingMessage, "url">) => Promise<void> : T extends "bun" ? Partial<Parameters<typeof Bun.serve>[0]> & {
1676
+ fetch?: CustomBunFetch;
1677
+ } : T extends "deno" ? Partial<Omit<Parameters<typeof Deno.serve>[0], "handler">> & {
1678
+ handler?: CustomDenoFetch;
1679
+ websocket?: {
1680
+ open?: (ws: WebSocket) => void;
1681
+ message?: (ws: WebSocket, message: string) => void;
1682
+ close?: (ws: WebSocket) => void;
1683
+ };
1684
+ } : never;
1685
+ type BunTapOptions = ServerTapOptionsBuilder<"bun">;
1686
+ type NodeTapOptions = ServerTapOptionsBuilder<"node">;
1687
+ type DenoTapOptions = ServerTapOptionsBuilder<"deno">;
1688
+ type ServerTapOptions = {
1689
+ bun?: BunTapOptions;
1690
+ node?: NodeTapOptions;
1691
+ deno?: DenoTapOptions;
1692
+ };
1693
+
1694
+ declare class MockResponse<T = any> {
1695
+ private readonly response;
1696
+ constructor(response: Response$1);
1697
+ body(): T;
1698
+ statusCode(): number;
1699
+ headers(): Record<string, string>;
1700
+ assertStatus(status: number): this;
1701
+ assertHeader(header: string, value: string): this;
1702
+ assertHeaderExists(header: string): this;
1703
+ assertHeaderNotExists(header: string): this;
1704
+ assertBodySubset(subset: Partial<T>): this;
1705
+ assertBodyDeepEqual(expected: T): this;
1706
+ assertBodyNotSubset(subset: Partial<T>): this;
1707
+ assertBodyNotDeepEqual(expected: T): this;
1708
+ assertCustom(assertion: (response: Response$1) => void): this;
1709
+ private assertSubset;
1710
+ private assertDeepEqual;
1711
+ private assertNotSubset;
1712
+ private assertNotDeepEqual;
1713
+ private assertArraySubset;
1714
+ private assertArrayDeepEqual;
1715
+ private isObject;
1716
+ }
1717
+
1718
+ /**
1719
+ * The options for the mock server, only one of body, formData, urlencoded can be provided
1720
+ */
1721
+ interface MockServerOptions {
1722
+ /**
1723
+ * The body of the request, if formData is provided, it will be ignored
1772
1724
  */
1773
- expressMiddleware: (middleware: RequestHandler) => ServerRouteMiddleware;
1725
+ body?: any;
1774
1726
  /**
1775
- * Mount an Express router at a specific base path
1776
- * @param basePath - The base path to mount the router at
1777
- * @param expressRouter - The Express router to mount
1727
+ * The form data of the request
1778
1728
  */
1779
- mountExpressRouter: (basePath: string, expressRouter: ExpressRouter) => void;
1729
+ formData?: FormData;
1780
1730
  /**
1781
- * Shorthand for the server.router.get method
1731
+ * The urlencoded body of the request
1782
1732
  */
1783
- get: (...args: any[]) => void;
1733
+ urlencoded?: Record<string, string>;
1784
1734
  /**
1785
- * Shorthand for the server.router.post method
1735
+ * The headers of the request
1786
1736
  */
1787
- post: (...args: any[]) => void;
1737
+ headers?: Record<string, string>;
1788
1738
  /**
1789
- * Shorthand for the server.router.put method
1739
+ * The query parameters of the request, if provided, they will be merged with the query parameters from the path (precedence is given to the query parameters provided here)
1790
1740
  */
1791
- put: (...args: any[]) => void;
1741
+ query?: Record<string, string>;
1792
1742
  /**
1793
- * Shorthand for the server.router.patch method
1743
+ * The cookies of the request
1794
1744
  */
1795
- patch: (...args: any[]) => void;
1745
+ cookies?: Record<string, string>;
1796
1746
  /**
1797
- * Shorthand for the server.router.delete method
1747
+ * The ip of the request
1798
1748
  */
1799
- delete: (...args: any[]) => void;
1749
+ ip?: string;
1750
+ }
1751
+
1752
+ /**
1753
+ * Allows to mock server requests without needing to start the server, useful for testing purposes
1754
+ */
1755
+ declare class MockServer {
1756
+ readonly server: Server<NodeHttpClient>;
1757
+ constructor(server: Server<NodeHttpClient>);
1800
1758
  /**
1801
- * Shorthand for the server.router.options method
1759
+ * Simulates an HTTP request without making an actual network call, useful for testing purposes
1760
+ * Executes the middleware chain and handler of the route
1761
+ * @param method - The HTTP method (GET, POST, PUT, DELETE, PATCH)
1762
+ * @param path - The request path
1763
+ * @param options - Request options including body, headers, query params, etc.
1764
+ * @throws {Error} - If more than one of body, formData, urlencoded is provided
1802
1765
  */
1803
- options: (...args: any[]) => void;
1766
+ request<T = any>(method: HttpMethod, path: string, options?: MockServerOptions): Promise<MockResponse<T>>;
1767
+ get<T = any>(path: string, options?: Omit<MockServerOptions, "body" | "formData" | "urlencoded">): Promise<MockResponse<T>>;
1768
+ post<T = any>(path: string, options?: MockServerOptions): Promise<MockResponse<T>>;
1769
+ put<T = any>(path: string, options?: MockServerOptions): Promise<MockResponse<T>>;
1770
+ patch<T = any>(path: string, options?: MockServerOptions): Promise<MockResponse<T>>;
1771
+ delete<T = any>(path: string, options?: Omit<MockServerOptions, "body" | "formData">): Promise<MockResponse<T>>;
1804
1772
  /**
1805
- * Shorthand for the server.router.head method
1773
+ * Converts FormData to a proper multipart/form-data body with boundaries
1806
1774
  */
1807
- head: (...args: any[]) => void;
1775
+ private formDataToMultipart;
1776
+ private validateOptions;
1777
+ }
1778
+
1779
+ /**
1780
+ * The server class that is used to create and manage the server
1781
+ */
1782
+ declare class Server<H extends NodeHttpClient = NodeHttpClient> implements ServerInterface {
1783
+ #private;
1784
+ readonly _brand: "BaldaServer";
1785
+ readonly serverOptions: ResolvedServerOptions;
1786
+ readonly router: ClientRouter;
1787
+ isListening: boolean;
1788
+ isProduction: boolean;
1789
+ graphql: GraphQL;
1808
1790
  /**
1809
- * Shorthand for the server.router.group method
1791
+ * The constructor for the server
1792
+ * @warning Routes will only be defined after calling the `listen` method so you're free to define middlewares before calling it
1793
+ * @param options - The options for the server
1794
+ * @param options.port - The port to listen on, if not provided, it will use the PORT environment variable, if not provided, it will default to 80
1795
+ * @param options.host - The hostname to listen on, if not provided, it will use the HOST environment variable, if not provided, it will default to 0.0.0.0
1796
+ * @param options.controllerPatterns - The patterns to match for controllers, defaults to an empty array
1797
+ * @param options.plugins - The plugins to apply to the server, by default no plugins are applied, plugins are applied in the order they are defined in the options
1798
+ * @param options.logger - The logger to use for the server, by default a default logger is used
1799
+ * @param options.tapOptions - Options fetch to the runtime server before the server is up and running
1800
+ * @param options.abortSignal - An optional AbortSignal to gracefully shutdown the server when aborted
1810
1801
  */
1811
- group: (...args: any[]) => void;
1802
+ constructor(options?: ServerOptions<H>);
1803
+ get url(): string;
1804
+ get port(): number;
1805
+ get host(): string;
1806
+ get routes(): Route[];
1807
+ hash(data: string): Promise<string>;
1808
+ compareHash(hash: string, data: string): Promise<boolean>;
1809
+ getEnvironment(): Record<string, string>;
1810
+ tmpDir(...append: string[]): string;
1811
+ mkdir(path: string, options?: {
1812
+ recursive?: boolean;
1813
+ mode?: number | string;
1814
+ }): Promise<void>;
1815
+ get(path: string, handler: ServerRouteHandler): void;
1816
+ get(path: string, options: StandardMethodOptions, handler: ServerRouteHandler): void;
1817
+ post(path: string, handler: ServerRouteHandler): void;
1818
+ post(path: string, options: StandardMethodOptions, handler: ServerRouteHandler): void;
1819
+ patch(path: string, handler: ServerRouteHandler): void;
1820
+ patch(path: string, options: StandardMethodOptions, handler: ServerRouteHandler): void;
1821
+ put(path: string, handler: ServerRouteHandler): void;
1822
+ put(path: string, options: StandardMethodOptions, handler: ServerRouteHandler): void;
1823
+ delete(path: string, handler: ServerRouteHandler): void;
1824
+ delete(path: string, options: StandardMethodOptions, handler: ServerRouteHandler): void;
1825
+ options(path: string, handler: ServerRouteHandler): void;
1826
+ options(path: string, options: StandardMethodOptions, handler: ServerRouteHandler): void;
1827
+ head(path: string, handler: ServerRouteHandler): void;
1828
+ head(path: string, options: StandardMethodOptions, handler: ServerRouteHandler): void;
1829
+ group(path: string, middleware: ServerRouteMiddleware[] | ServerRouteMiddleware, cb: (router: ClientRouter) => void): void;
1830
+ group(path: string, cb: (router: ClientRouter) => void): void;
1831
+ getNodeServer(): RuntimeServerMap<"node", H>;
1832
+ getBunServer(): RuntimeServerMap<"bun">;
1833
+ getDenoServer(): RuntimeServerMap<"deno">;
1834
+ embed(key: string, value: any): void;
1835
+ exit(code?: number): void;
1836
+ on(event: SignalEvent, cb: () => SyncOrAsync): void;
1837
+ on(event: string, cb: () => SyncOrAsync): void;
1838
+ once(event: SignalEvent, cb: () => SyncOrAsync): void;
1839
+ once(event: string, cb: () => SyncOrAsync): void;
1840
+ use(...middlewares: ServerRouteMiddleware[]): void;
1841
+ useExpress(pathOrMiddleware: string | RequestHandler | Router$1, maybeMiddleware?: RequestHandler | Router$1): void;
1842
+ expressMiddleware(middleware: RequestHandler): ServerRouteMiddleware;
1843
+ mountExpressRouter(basePath: string, expressRouter: Router$1): void;
1844
+ setErrorHandler(errorHandler?: ServerErrorHandler): void;
1845
+ setNotFoundHandler(notFoundHandler?: ServerRouteHandler): void;
1846
+ listen(cb?: ServerListenCallback): void;
1847
+ waitUntilListening(): Promise<void>;
1812
1848
  /**
1813
- * Get the node server instance, you must be using node runtime to use this method based on the nodeHttpClient option passed to the server constructor (defaults to http)
1814
- * @throws if the runtime is not node
1849
+ * Closes the server and frees the port
1850
+ * This method is idempotent and can be called multiple times safely
1851
+ * @returns A promise that resolves when the server is closed
1815
1852
  */
1816
- getNodeServer: () => RuntimeServerMap<"node", NodeHttpClient>;
1853
+ close(): Promise<void>;
1817
1854
  /**
1818
- * Get the bun server instance, you must be using bun runtime to use this method
1819
- * @throws if the runtime is not bun
1855
+ * Disconnects the server and frees the port
1856
+ * This method is idempotent and can be called multiple times safely
1857
+ * Subsequent calls after the first will have no effect
1858
+ * @returns A promise that resolves when the server is disconnected
1820
1859
  */
1821
- getBunServer: () => RuntimeServerMap<"bun">;
1860
+ disconnect(): Promise<void>;
1861
+ configureHash(options: {
1862
+ iterations?: number;
1863
+ saltLength?: number;
1864
+ keyLength?: number;
1865
+ }): void;
1866
+ getMockServer(options?: Pick<ServerOptions, "controllerPatterns">): Promise<MockServer>;
1867
+ private importControllers;
1868
+ private extractOptionsAndHandlerFromRouteRegistration;
1869
+ private applyPlugins;
1822
1870
  /**
1823
- * Get the deno server instance, you must be using deno runtime to use this method
1824
- * @throws if the runtime is not deno
1871
+ * Initializes the server by importing the controllers and applying the plugins, it's idempotent, it will not re-import the controllers or apply the plugins if the server was already initialized (e.g. mockServer init)
1872
+ * @internal
1825
1873
  */
1826
- getDenoServer: () => RuntimeServerMap<"deno">;
1874
+ private bootstrap;
1827
1875
  /**
1828
- * Embed the given key into the server instance, this is useful for embedding the server with custom context inside the server instance, you can extend the server with your own properties to type it
1829
- * @param key - The key to embed
1830
- * @param value - The value to embed
1831
- * @warning There are some keys that are protected and cannot be embedded, you can find the list of protected keys in the PROTECTED_KEYS constant
1832
- * @throws An error if the key is already defined in the server instance or if the key is protected
1833
- * @example
1834
- * ```typescript
1835
- * // For better type safety, you can declare a module for the server interface
1836
- * declare module "balda" {
1837
- * interface Server {
1838
- * myCustomProperty: string;
1839
- * }
1840
- * }
1841
- *
1842
- * server.embed("myCustomProperty", "myCustomValue");
1843
- * console.log(server.myCustomProperty); // Type safe if ServerInterface is extended
1844
- * ```
1876
+ * Handles not found routes by delegating to custom handler or default error response
1877
+ * Checks if the path exists for other methods and returns 405 if so
1878
+ * @internal
1845
1879
  */
1846
- embed: (key: string, value: any) => void;
1880
+ private handleNotFound;
1847
1881
  /**
1848
- * Register a signal event listener to the server, this is useful for handling signals like SIGINT, SIGTERM, etc.
1849
- * @param event - The signal event to listen for
1850
- * @param cb - The callback to be called when the signal event is received
1882
+ * Registers a not found route for all routes that are not defined
1883
+ * @internal
1851
1884
  */
1852
- on: (event: SignalEvent, cb: () => SyncOrAsync) => void;
1885
+ private registerNotFoundRoutes;
1853
1886
  /**
1854
- * Register a signal event listener to the server, this is useful for handling signals like SIGINT, SIGTERM, etc.
1855
- * @param event - The signal event to listen for
1856
- * @param cb - The callback to be called when the signal event is received
1887
+ * Sets up the abort signal handler to gracefully shutdown the server when aborted
1888
+ * @internal
1857
1889
  */
1858
- once: (event: SignalEvent, cb: () => SyncOrAsync) => void;
1890
+ private setupAbortSignalHandler;
1891
+ }
1892
+
1893
+ type CronSchedule = {
1894
+ name: string;
1895
+ args: Parameters<typeof schedule>;
1896
+ };
1897
+ type CronScheduleParams = Parameters<typeof schedule>;
1898
+
1899
+ /**
1900
+ * Decorator to schedule a cron job. Must be applied to a class method. By default, the cron job will not overlap with other cron jobs of the same type.
1901
+ * ```ts
1902
+ * @cron('* * * * *', { timezone: 'Europe/Istanbul' })
1903
+ * async test() {
1904
+ * console.log('test');
1905
+ * }
1906
+ * ```
1907
+ */
1908
+ declare const cron: (schedule: CronScheduleParams[0], options?: CronScheduleParams[2]) => (target: any, propertyKey: string, descriptor: PropertyDescriptor) => PropertyDescriptor;
1909
+
1910
+ type FlagType = "boolean" | "string" | "number" | "list";
1911
+ type InferFlagType<T extends FlagType> = T extends "boolean" ? boolean : T extends "string" ? string : T extends "number" ? number : T extends "list" ? string[] : never;
1912
+ type ArgOptions = {
1859
1913
  /**
1860
- * Register a global middleware to be applied to all routes after the listener is bound, the middleware is applied in the order it is registered
1914
+ * The description of the argument.
1861
1915
  */
1862
- use: (middleware: ServerRouteMiddleware) => void;
1916
+ description?: string;
1863
1917
  /**
1864
- * Set the error handler for the server
1865
- * @param errorHandler - The error handler to be applied to all routes
1918
+ * Whether the argument is required.
1919
+ * @default false
1866
1920
  */
1867
- setErrorHandler: (errorHandler?: ServerErrorHandler) => void;
1921
+ required?: boolean;
1868
1922
  /**
1869
- * Sets a custom handler for 404 Not Found responses.
1870
- * If not set, the default RouteNotFoundError will be used.
1871
- *
1872
- * @param notFoundHandler - Optional handler to customize 404 responses
1873
- * @example
1874
- * server.setNotFoundHandler((req, res) => {
1875
- * res.status(404).json({ error: "Custom not found message" });
1876
- * });
1923
+ * The default value of the argument.
1877
1924
  */
1878
- setNotFoundHandler: (notFoundHandler?: ServerRouteHandler) => void;
1925
+ defaultValue?: string;
1879
1926
  /**
1880
- * Binds the server to the port and hostname defined in the serverOptions, meant to be called only once
1881
- * It initializes the server without blocking the event loop, you can pass a callback to be called when the server is listening
1882
- * Use `waitUntilListening` instead if you want to wait for the server to be listening for requests before returning
1883
- * @warning All routes defined with decorators are defined on this method just before the server starts listening for requests
1927
+ * A function to parse the argument value.
1928
+ * @default The value is returned as is.
1884
1929
  */
1885
- listen: (cb?: ServerListenCallback) => void;
1930
+ parse?: (value: string) => string;
1931
+ };
1932
+ type FlagOptions<T extends FlagType> = {
1886
1933
  /**
1887
- * Binds the server to the port and hostname defined in the serverOptions, meant to be called only once
1888
- * It initializes the server blocking the event loop, it will wait for the server to be listening for requests before returning
1889
- * Use `listen` instead if you want to initialize the server without blocking the event loop
1890
- * @warning All routes defined with decorators are defined on this method just before the server starts listening for requests
1934
+ * The description of the flag.
1891
1935
  */
1892
- waitUntilListening: () => Promise<void>;
1936
+ description?: string;
1893
1937
  /**
1894
- * @alias disconnect
1938
+ * The type of the flag.
1895
1939
  */
1896
- close: () => Promise<void>;
1940
+ type: T;
1897
1941
  /**
1898
- * Closes the server and frees the port
1942
+ * The name of the flag.
1943
+ * @default The name of the field.
1899
1944
  */
1900
- disconnect: () => Promise<void>;
1945
+ name?: string;
1901
1946
  /**
1902
- * Configure hash settings for password hashing
1903
- * @param options - Hash configuration options
1904
- * @param options.iterations - Number of PBKDF2 iterations (default: 600,000)
1905
- * @param options.saltLength - Salt length in bytes (default: 16)
1906
- * @param options.keyLength - Key length in bits (default: 256)
1947
+ * The aliases of the flag.
1907
1948
  */
1908
- configureHash: (options: {
1909
- iterations?: number;
1910
- saltLength?: number;
1911
- keyLength?: number;
1912
- }) => void;
1949
+ aliases?: string[] | string;
1913
1950
  /**
1914
- * Returns a mock server instance that can be used to test the server without starting it
1915
- * It will import the controllers and apply the plugins to the mock server
1916
- * @param options - The options for the mock server
1917
- * @param options.controllerPatterns - Custom controller patterns to import if the mock server must not be initialized with the same controller patterns as the server
1951
+ * The default value of the flag.
1918
1952
  */
1919
- getMockServer: () => Promise<MockServer>;
1953
+ defaultValue?: InferFlagType<T>;
1920
1954
  /**
1921
- * Exit current runtime process with the given code based on the current runtime
1922
- * @param code - The code to exit with, defaults to 0
1923
- * @example
1924
- * ```typescript
1925
- * server.exit(1); // If node process.exit(1) is called
1926
- * server.exit(); // If deno Deno.exit(0) is called
1927
- * ```
1955
+ * Whether the flag is required.
1956
+ * @default false
1928
1957
  */
1929
- exit: (code?: number) => void;
1930
- }
1931
- type StandardMethodOptions = {
1932
- middlewares?: ServerRouteMiddleware[] | ServerRouteMiddleware;
1933
- swagger?: SwaggerRouteOptions;
1958
+ required?: boolean;
1959
+ /**
1960
+ * A function to parse the flag value.
1961
+ * @default The value is returned as is.
1962
+ */
1963
+ parse?: (value: any) => InferFlagType<T>;
1934
1964
  };
1935
- type SignalEvent = Deno.Signal | NodeJS.Signals;
1936
1965
 
1937
- type RunTimeType = "bun" | "node" | "deno";
1966
+ declare const VALIDATION_ERROR_SYMBOL = "VALIDATION_ERROR";
1967
+ declare const ARG_SYMBOL = "ARG";
1968
+ /**
1969
+ * Decorator to mark a field of a command class as an argument.
1970
+ * @param options - The options for the argument.
1971
+ * @warning Arguments are evaluated in the order they are defined in the Command class.
1972
+ */
1973
+ declare const arg: (options: ArgOptions) => (target: any, propertyKey: string) => void;
1974
+
1975
+ declare const flag: {
1976
+ <T extends FlagType>(options: FlagOptions<T>): (target: any, propertyKey: string) => void;
1977
+ boolean(options: Omit<FlagOptions<"boolean">, "type">): (target: any, propertyKey: string) => void;
1978
+ string(options: Omit<FlagOptions<"string">, "type">): (target: any, propertyKey: string) => void;
1979
+ number(options: Omit<FlagOptions<"number">, "type">): (target: any, propertyKey: string) => void;
1980
+ list(options: Omit<FlagOptions<"list">, "type">): (target: any, propertyKey: string) => void;
1981
+ };
1938
1982
 
1939
- type HttpMethod = "GET" | "POST" | "PUT" | "DELETE" | "PATCH" | "OPTIONS" | "HEAD";
1940
- type NodeServer = Server$2 | Server$1 | Http2Server;
1941
- type RuntimeServer = NodeServer | ReturnType<typeof Bun.serve> | ReturnType<typeof Deno.serve>;
1942
- type RuntimeServerMap<T extends RunTimeType, H extends NodeHttpClient = "http"> = T extends "node" ? H extends "https" ? Server$1 : H extends "http2" | "http2-secure" ? Http2Server : Server$2 : T extends "bun" ? ReturnType<typeof Bun.serve> : T extends "deno" ? ReturnType<typeof Deno.serve> : never;
1943
- type HttpsOptions<T extends NodeHttpClient> = T extends "https" | "http2-secure" ? {
1944
- /** HTTPS/TLS options, required when nodeHttpClient is 'https' or 'http2-secure' */
1945
- httpsOptions: ServerOptions$1;
1946
- } : never;
1947
- type ServerConnectInput<H extends NodeHttpClient = NodeHttpClient> = {
1948
- /** The port to listen on, defaults to 80 */
1949
- port: number;
1950
- /** The hostname to listen on, defaults to 0.0.0.0 */
1951
- host: string;
1952
- /** The server routes with their corresponding handler */
1953
- routes: ServerRoute[];
1954
- /** The options for the server tap function */
1955
- tapOptions?: ServerTapOptions;
1956
- /** The runtime to use for the server */
1957
- runtime: RunTimeType;
1958
- /** Specific node client to use */
1959
- nodeHttpClient: H;
1960
- /** The graphql options to apply to the server */
1961
- graphql?: GraphQL;
1962
- } & (H extends "https" ? HttpsOptions<H> : {});
1963
- type ServerRouteMiddleware = (req: Request, res: Response$1, next: NextFunction) => SyncOrAsync;
1964
- type ServerRouteHandler = (req: Request, res: Response$1) => SyncOrAsync;
1965
- interface ServerRoute {
1966
- /** The path for the route */
1967
- path: string;
1968
- /** The HTTP method for the route */
1969
- method: HttpMethod;
1970
- /** The handler to call when the route is requested */
1971
- handler: ServerRouteHandler;
1972
- /** The middleware chain to call before the handler */
1973
- middlewares?: ServerRouteMiddleware[];
1974
- }
1975
- type ServerListenCallback = ({ port, host, url, }: {
1976
- port: number;
1977
- host: string;
1978
- url: string;
1979
- }) => SyncOrAsync;
1980
1983
  /**
1981
- * Custom bun fetch call to be used as an hook inside Bun.serve method
1984
+ * Decorator to mark a class as a controller, routes defined in the controller will be registered at import time when calling the `listen` method.
1985
+ * You can customize the path pattern for controller imports in the server options `controllerPatterns`
1986
+ * @param path - The path pattern for the controller.
1987
+ * @param swaggerOptions - The swagger options for the controller that will be applied to all routes defined in the controller. Controller options will override route options.
1988
+ * @swagger If swagger is enabled, the default service name for all routes defined in the controller will be the controller name.
1989
+ * @swagger For naming commodity, the default service name will remove the "Controller" suffix if it exists. e.g. "UserController" -> "User"
1982
1990
  */
1983
- type CustomBunFetch = (req: Request, server: Bun.Server<any>) => SyncOrAsync;
1991
+ declare const controller: (path?: string, swaggerOptions?: SwaggerRouteOptions) => (target: any) => void;
1992
+
1993
+ type DelHandler = (req: Request, res: Response$1, ...args: any[]) => any;
1984
1994
  /**
1985
- * Custom deno fetch call to be used as an hook inside Deno.serve method
1995
+ * Decorator to mark an handler for a DELETE request
1996
+ * @param path - The path of the route
1997
+ * @param options - The options for the route
1998
+ * @warning Must receive the request and response as the first two arguments or it might not work as expected.
1999
+ * @example
2000
+ * ```ts
2001
+ * import { del, controller, Request, Response } from "balda";
2002
+ *
2003
+ * @controller("/api")
2004
+ * class MyController {
2005
+ * @del("/")
2006
+ * async handler(req: Request, res: Response) {
2007
+ * // ...
2008
+ * }
2009
+ * }
2010
+ * ```
1986
2011
  */
1987
- type CustomDenoFetch = (...options: Parameters<Parameters<typeof Deno.serve>[0]["handler"]>) => SyncOrAsync<Response | void>;
2012
+ declare const del: (path: string, options?: SwaggerRouteOptions) => <T extends DelHandler>(target: any, propertyKey: string, descriptor: PropertyDescriptor) => TypedPropertyDescriptor<T>;
2013
+
2014
+ type GetHandler = (req: Request, res: Response$1, ...args: any[]) => any;
1988
2015
  /**
1989
- * The options for the server tap function, allows you to interact with the server behavior before it is used to listen for incoming requests
2016
+ * Decorator to mark an handler for a GET request
2017
+ * @param path - The path of the route
2018
+ * @param options - The options for the route
2019
+ * @warning Must receive the request and response as the first two arguments or it might not work as expected.
2020
+ * @example
2021
+ * ```ts
2022
+ * import { get, controller, Request, Response } from "balda";
2023
+ *
2024
+ * @controller("/api")
2025
+ * class MyController {
2026
+ * @get("/")
2027
+ * async handler(req: Request, res: Response) {
2028
+ * // ...
2029
+ * }
2030
+ * }
2031
+ * ```
1990
2032
  */
1991
- type ServerTapOptionsBuilder<T extends RunTimeType> = T extends "node" ? (req: Omit<IncomingMessage, "url">) => Promise<void> : T extends "bun" ? Partial<Parameters<typeof Bun.serve>[0]> & {
1992
- fetch?: CustomBunFetch;
1993
- } : T extends "deno" ? Partial<Omit<Parameters<typeof Deno.serve>[0], "handler">> & {
1994
- handler?: CustomDenoFetch;
1995
- websocket?: {
1996
- open?: (ws: WebSocket) => void;
1997
- message?: (ws: WebSocket, message: string) => void;
1998
- close?: (ws: WebSocket) => void;
1999
- };
2000
- } : never;
2001
- type BunTapOptions = ServerTapOptionsBuilder<"bun">;
2002
- type NodeTapOptions = ServerTapOptionsBuilder<"node">;
2003
- type DenoTapOptions = ServerTapOptionsBuilder<"deno">;
2004
- type ServerTapOptions = {
2005
- bun?: BunTapOptions;
2006
- node?: NodeTapOptions;
2007
- deno?: DenoTapOptions;
2008
- };
2033
+ declare const get: (path: string, options?: SwaggerRouteOptions) => <T extends GetHandler>(target: any, propertyKey: string, descriptor: PropertyDescriptor) => TypedPropertyDescriptor<T>;
2034
+
2035
+ type PatchHandler = (req: Request, res: Response$1, ...args: any[]) => any;
2036
+ /**
2037
+ * Decorator to mark an handler for a PATCH request
2038
+ * @param path - The path of the route
2039
+ * @param options - The options for the route
2040
+ * @warning Must receive the request and response as the first two arguments or it might not work as expected.
2041
+ * @example
2042
+ * ```ts
2043
+ * import { patch, controller, Request, Response } from "balda";
2044
+ *
2045
+ * @controller("/api")
2046
+ * class MyController {
2047
+ * @patch("/")
2048
+ * async handler(req: Request, res: Response) {
2049
+ * // ...
2050
+ * }
2051
+ * }
2052
+ * ```
2053
+ */
2054
+ declare const patch: (path: string, options?: SwaggerRouteOptions) => <T extends PatchHandler>(target: any, propertyKey: string, descriptor: PropertyDescriptor) => TypedPropertyDescriptor<T>;
2055
+
2056
+ type PostHandler = (req: Request, res: Response$1, ...args: any[]) => any;
2057
+ /**
2058
+ * Decorator to mark an handler for a POST request
2059
+ * @param path - The path of the route
2060
+ * @param options - The options for the route
2061
+ * @warning Must receive the request and response as the first two arguments or it might not work as expected.
2062
+ * @example
2063
+ * ```ts
2064
+ * import { post, controller, Request, Response } from "balda";
2065
+ *
2066
+ * @controller("/api")
2067
+ * class MyController {
2068
+ * @post("/")
2069
+ * async handler(req: Request, res: Response) {
2070
+ * // ...
2071
+ * }
2072
+ * }
2073
+ * ```
2074
+ */
2075
+ declare const post: (path: string, options?: SwaggerRouteOptions) => <T extends PostHandler>(target: any, propertyKey: string, descriptor: PropertyDescriptor) => TypedPropertyDescriptor<T>;
2076
+
2077
+ type PutHandler = (req: Request, res: Response$1, ...args: any[]) => any;
2078
+ /**
2079
+ * Decorator to mark an handler for a PUT request
2080
+ * @param path - The path of the route
2081
+ * @param options - The options for the route
2082
+ * @warning Must receive the request and response as the first two arguments or it might not work as expected.
2083
+ * @example
2084
+ * ```ts
2085
+ * import { put, controller, Request, Response } from "balda";
2086
+ *
2087
+ * @controller("/api")
2088
+ * class MyController {
2089
+ * @put("/")
2090
+ * async handler(req: Request, res: Response) {
2091
+ * // ...
2092
+ * }
2093
+ */
2094
+ declare const put: (path: string, options?: SwaggerRouteOptions) => <T extends PutHandler>(target: any, propertyKey: string, descriptor: PropertyDescriptor) => TypedPropertyDescriptor<T>;
2009
2095
 
2010
2096
  /**
2011
2097
  * Decorator to mark a middleware for a route or a controller class
@@ -3278,4 +3364,4 @@ declare const createPolicyDecorator: <T extends Record<string, PolicyProvider>>(
3278
3364
  */
3279
3365
  declare const router: ClientRouter;
3280
3366
 
3281
- export { ARG_SYMBOL, AzureBlobStorageProvider, BaseCron, BaseMqtt, BasePlugin, BaseQueue, type BaseStorageProviderOptions, type BlobStorageProviderOptions, BullMQConfiguration, type BullMQConfigurationOptions, BullMQPubSub, type BunTapOptions, Command, type CommandOptions, CommandRegistry, type CronSchedule, type CronScheduleParams, CronService, type CustomQueueConfiguration, type CustomStorageProviderOptions, CustomTypedQueue, type CustomValidationError, type DenoTapOptions, type ExpressAdapterOptions, type ExpressHandler, type ExpressRouter, type FileAllowedMimeType, GraphQL, type GraphQLContext, type GraphQLOptions, type GraphQLResolverFunction, type GraphQLResolverMap, type GraphQLResolverType, type GraphQLResolvers, type GraphQLSchemaInput, type GraphQLTypeDef, type HttpMethod, type HttpsOptions, LocalStorageProvider, type LocalStorageProviderOptions, type LoggerOptions, MockServer, type MockServerOptions, type MqttConnectionOptions, type MqttHandler, type MqttPublishOptions, MqttService, type MqttSubscribeOptions, type MqttSubscription, type MqttTopics, type NextFunction, type NodeHttpClient, type NodeServer, type NodeTapOptions, PGBossConfiguration, type PGBossConfigurationOptions, PGBossPubSub, type PolicyDecorator, PolicyManager, type PolicyMetadata, type PolicyProvider, QueueManager, QueueService, Request, type RequestSchema, type ResolvedServerOptions, Response$1 as Response, type ReturnType$1 as ReturnType, type ReturnTypeMap, type RuntimeServer, type RuntimeServerMap, S3StorageProvider, type S3StorageProviderOptions, SQSConfiguration, type SQSConfigurationOptions, SQSPubSub, type SerializeOptions, Server, type ServerConnectInput, type ServerErrorHandler, type ServerInterface, type ServerListenCallback, type ServerOptions, type ServerPlugin, type ServerRoute, type ServerRouteHandler, type ServerRouteMiddleware, type ServerTapOptions, type ServerTapOptionsBuilder, type SignalEvent, type StandardMethodOptions, type StaticPluginOptions, Storage, type StorageInterface, type StorageOptions, type StorageProviderOptions, TypedQueue, VALIDATION_ERROR_SYMBOL, type ValidatedData, type ValidationOptions, arg, asyncLocalStorage, asyncStorage, baseCommands, bullmqQueue, commandRegistry, compression, controller, cookie, cors, createExpressAdapter, createPolicyDecorator, createQueue, cron, defineLoggerConfig, defineQueueConfiguration, del, expressHandler, expressMiddleware, flag, get, getContentType, hash, helmet, log, logger, methodOverride, middleware, mountExpressRouter, mqtt, patch, pgbossQueue, post, put, rateLimiter, router, serialize, serveStatic, session, setCronGlobalErrorHandler, setMqttGlobalErrorHandler, sqsQueue, timeout, trustProxy, validate };
3367
+ export { ARG_SYMBOL, AzureBlobStorageProvider, BaseCron, BaseMqtt, BasePlugin, BaseQueue, type BaseStorageProviderOptions, type BlobStorageProviderOptions, BullMQConfiguration, type BullMQConfigurationOptions, BullMQPubSub, type BunTapOptions, Command, type CommandOptions, CommandRegistry, type CronSchedule, type CronScheduleParams, CronService, type CustomQueueConfiguration, type CustomStorageProviderOptions, CustomTypedQueue, type CustomValidationError, type DenoTapOptions, type ExpressAdapterOptions, type ExpressHandler, type ExpressRouter, type FileAllowedMimeType, GraphQL, type GraphQLContext, type GraphQLOptions, type GraphQLResolverFunction, type GraphQLResolverMap, type GraphQLResolverType, type GraphQLResolvers, type GraphQLSchemaInput, type GraphQLTypeDef, type HttpMethod, type HttpsOptions, LocalStorageProvider, type LocalStorageProviderOptions, type LoggerOptions, MockServer, type MockServerOptions, type MqttConnectionOptions, type MqttHandler, type MqttPublishOptions, MqttService, type MqttSubscribeOptions, type MqttSubscription, type MqttTopics, type NextFunction, type NodeHttpClient, type NodeServer, type NodeTapOptions, PGBossConfiguration, type PGBossConfigurationOptions, PGBossPubSub, type PolicyDecorator, PolicyManager, type PolicyMetadata, type PolicyProvider, QueueManager, QueueService, Request, type RequestSchema, type ResolvedServerOptions, Response$1 as Response, type ReturnType$1 as ReturnType, type ReturnTypeMap, type RuntimeServer, type RuntimeServerMap, S3StorageProvider, type S3StorageProviderOptions, SQSConfiguration, type SQSConfigurationOptions, SQSPubSub, type SerializeOptions, Server, type ServerConnectInput, type ServerErrorHandler, type ServerInterface, type ServerListenCallback, type ServerOptions, type ServerPlugin, type ServerRoute, type ServerRouteHandler, type ServerRouteMiddleware, type ServerTapOptions, type ServerTapOptionsBuilder, type SignalEvent, type StandardMethodOptions, type StaticPluginOptions, Storage, type StorageInterface, type StorageOptions, type StorageProviderOptions, TypedQueue, VALIDATION_ERROR_SYMBOL, type ValidatedData, type ValidationOptions, arg, asyncLocalStorage, asyncStorage, baseCommands, bullmqQueue, commandRegistry, compression, controller, cookie, cors, createExpressAdapter, createPolicyDecorator, createQueue, cron, Server as default, defineLoggerConfig, defineQueueConfiguration, del, expressHandler, expressMiddleware, flag, get, getContentType, hash, helmet, log, logger, methodOverride, middleware, mountExpressRouter, mqtt, patch, pgbossQueue, post, put, rateLimiter, router, serialize, serveStatic, session, setCronGlobalErrorHandler, setMqttGlobalErrorHandler, sqsQueue, timeout, trustProxy, validate };