snap-on-openapi 1.0.12 → 1.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/dist/OpenApi.d.ts +4 -7
- package/dist/OpenApi.js +79 -53
- package/dist/services/ConfigBuilder/types/DefaultConfig.d.ts +8 -1
- package/dist/services/ConfigBuilder/types/DefaultConfig.js +20 -6
- package/dist/services/RoutingFactory/RoutingFactory.d.ts +3 -1
- package/dist/services/RoutingFactory/RoutingFactory.js +26 -1
- package/dist/services/RoutingFactory/types/StandardRoute.d.ts +26 -0
- package/dist/services/RoutingFactory/types/StandardRoute.js +1 -0
- package/dist/services/TestUtils/TestUtils.d.ts +2 -0
- package/dist/services/TestUtils/TestUtils.js +4 -0
- package/dist/services/TestUtils/utils/TestLogger.d.ts +15 -0
- package/dist/services/TestUtils/utils/TestLogger.js +13 -0
- package/dist/types/Route.d.ts +2 -8
- package/dist/types/RouteResponse.d.ts +5 -0
- package/dist/types/RouteResponse.js +1 -0
- package/dist/types/config/Config.d.ts +10 -10
- package/dist/types/config/ContextParams.d.ts +2 -0
- package/dist/types/config/RouteConfig.d.ts +2 -0
- package/dist/types/config/RouteHandlerWrapper.d.ts +4 -0
- package/dist/types/config/RouteHandlerWrapper.js +1 -0
- package/dist/types/events/OnErrorEvent.d.ts +7 -0
- package/dist/types/events/OnErrorEvent.js +1 -0
- package/dist/types/events/OnHandlerEvent.d.ts +8 -0
- package/dist/types/events/OnHandlerEvent.js +1 -0
- package/dist/types/events/OnRequestEvent.d.ts +5 -0
- package/dist/types/events/OnRequestEvent.js +1 -0
- package/dist/types/events/OnResponseEvent.d.ts +5 -0
- package/dist/types/events/OnResponseEvent.js +1 -0
- package/dist/types/events/OnRouteEvent.d.ts +10 -0
- package/dist/types/events/OnRouteEvent.js +1 -0
- package/package.json +1 -1
package/dist/OpenApi.d.ts
CHANGED
|
@@ -22,6 +22,7 @@ import { InitialBuilder } from './types/InitialBuilder.js';
|
|
|
22
22
|
import { DefaultRouteContextMap } from './services/ConfigBuilder/types/DefaultRouteContextMap.js';
|
|
23
23
|
import { DefaultRouteParamsMap } from './services/ConfigBuilder/types/DefaultRouteParamsMap.js';
|
|
24
24
|
import z from 'zod';
|
|
25
|
+
import { RouteResponse } from './types/RouteResponse.js';
|
|
25
26
|
export declare class OpenApi<TRouteTypes extends string, TErrorCodes extends string, TConfig extends AnyConfig<TRouteTypes, TErrorCodes>> {
|
|
26
27
|
static readonly builder: InitialBuilder;
|
|
27
28
|
readonly validators: ValidationUtils;
|
|
@@ -46,15 +47,11 @@ export declare class OpenApi<TRouteTypes extends string, TErrorCodes extends str
|
|
|
46
47
|
mergePaths(...paths: RoutePath[]): RoutePath;
|
|
47
48
|
addServer(url: string, description: string): void;
|
|
48
49
|
protected getRouteForPath(path: string, method: string): AnyRoute<TRouteTypes> | null;
|
|
49
|
-
processRootRoute(originalReq: Request): Promise<
|
|
50
|
-
|
|
51
|
-
body: unknown;
|
|
52
|
-
headers: Record<string, string>;
|
|
53
|
-
}>;
|
|
54
|
-
protected handleError(e: unknown, req: Request): {
|
|
50
|
+
processRootRoute(originalReq: Request): Promise<RouteResponse>;
|
|
51
|
+
protected handleError(e: unknown, req: Request): Promise<{
|
|
55
52
|
status: number;
|
|
56
53
|
body: z.TypeOf<import("./index.js").OpenApiErrorConfigMap<TErrorCodes>[TErrorCodes]["responseValidator"]>;
|
|
57
54
|
headers: {};
|
|
58
|
-
}
|
|
55
|
+
}>;
|
|
59
56
|
protected static getBuilder(): ConfigBuilder<SampleRouteType, ErrorCode, DefaultErrorMap, DefaultRouteParamsMap, DefaultRouteContextMap, DefaultRouteMap, DefaultConfig>;
|
|
60
57
|
}
|
package/dist/OpenApi.js
CHANGED
|
@@ -129,6 +129,9 @@ export class OpenApi {
|
|
|
129
129
|
}
|
|
130
130
|
async processRootRoute(originalReq) {
|
|
131
131
|
try {
|
|
132
|
+
if (this.config.onRequest) {
|
|
133
|
+
await this.config.onRequest({ request: originalReq, logger: this.logger });
|
|
134
|
+
}
|
|
132
135
|
const url = new URL(originalReq.url);
|
|
133
136
|
const basePath = this.getBasePath() === '/' ? '' : this.getBasePath();
|
|
134
137
|
const urlPath = url.pathname.replace(basePath, '');
|
|
@@ -176,12 +179,19 @@ export class OpenApi {
|
|
|
176
179
|
query: reqQuery,
|
|
177
180
|
body: body,
|
|
178
181
|
};
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
182
|
+
const onRoute = {
|
|
183
|
+
request: originalReq,
|
|
184
|
+
logger: this.logger,
|
|
185
|
+
path: urlPath,
|
|
186
|
+
method: originalReq.method,
|
|
187
|
+
params: pathParams,
|
|
188
|
+
query: reqQuery,
|
|
189
|
+
body: body,
|
|
190
|
+
route: route,
|
|
191
|
+
};
|
|
192
|
+
if (this.config.onRoute) {
|
|
193
|
+
await this.config.onRoute(onRoute);
|
|
194
|
+
}
|
|
185
195
|
const queryValidator = route.validators.query?.strict() ?? z.object({});
|
|
186
196
|
const query = queryValidator.safeParse(req.query);
|
|
187
197
|
if (!query.success) {
|
|
@@ -192,80 +202,96 @@ export class OpenApi {
|
|
|
192
202
|
if (!path.success) {
|
|
193
203
|
throw new ValidationError(path.error, ValidationLocation.Path, req.params);
|
|
194
204
|
}
|
|
195
|
-
let response;
|
|
196
205
|
const containsBody = route.method !== Method.GET;
|
|
206
|
+
let bodyData = {};
|
|
197
207
|
if (containsBody && route.validators.body) {
|
|
198
|
-
const
|
|
199
|
-
if (!
|
|
200
|
-
throw new ValidationError(
|
|
208
|
+
const bodyResult = route.validators.body.safeParse(req.body);
|
|
209
|
+
if (!bodyResult.success) {
|
|
210
|
+
throw new ValidationError(bodyResult.error, ValidationLocation.Body, req.body);
|
|
201
211
|
}
|
|
202
|
-
|
|
203
|
-
route: route,
|
|
204
|
-
request: originalReq,
|
|
205
|
-
params: {
|
|
206
|
-
query: query.data,
|
|
207
|
-
path: path.data,
|
|
208
|
-
body: body.data,
|
|
209
|
-
},
|
|
210
|
-
});
|
|
211
|
-
response = await route.handler({
|
|
212
|
-
...context,
|
|
213
|
-
params: {
|
|
214
|
-
query: query.data,
|
|
215
|
-
path: path.data,
|
|
216
|
-
body: body.data,
|
|
217
|
-
},
|
|
218
|
-
});
|
|
212
|
+
bodyData = bodyResult.data;
|
|
219
213
|
}
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
214
|
+
const context = await this.config.routes[route.type].contextFactory({
|
|
215
|
+
route: route,
|
|
216
|
+
request: originalReq,
|
|
217
|
+
logger: this.logger,
|
|
218
|
+
params: {
|
|
219
|
+
query: query.data,
|
|
220
|
+
path: path.data,
|
|
221
|
+
body: bodyData,
|
|
222
|
+
},
|
|
223
|
+
});
|
|
224
|
+
const onHandler = {
|
|
225
|
+
...onRoute,
|
|
226
|
+
validated: {
|
|
227
|
+
query: query.data,
|
|
228
|
+
path: path.data,
|
|
229
|
+
body: bodyData,
|
|
230
|
+
},
|
|
231
|
+
};
|
|
232
|
+
const wrapper = this.config.routes[route.type].handlerWrapper ?? (async (handler) => handler());
|
|
233
|
+
const handler = async () => {
|
|
234
|
+
const response = await route.handler({
|
|
231
235
|
...context,
|
|
232
236
|
params: {
|
|
233
237
|
query: query.data,
|
|
234
238
|
path: path.data,
|
|
235
|
-
body:
|
|
236
|
-
}
|
|
239
|
+
body: bodyData,
|
|
240
|
+
},
|
|
237
241
|
});
|
|
238
|
-
|
|
239
|
-
|
|
242
|
+
return response;
|
|
243
|
+
};
|
|
244
|
+
const response = await wrapper(handler, {
|
|
245
|
+
route: route,
|
|
246
|
+
request: originalReq,
|
|
247
|
+
logger: this.logger,
|
|
248
|
+
params: {
|
|
249
|
+
query: query.data,
|
|
250
|
+
path: path.data,
|
|
251
|
+
body: bodyData,
|
|
252
|
+
},
|
|
253
|
+
}, context);
|
|
240
254
|
const finalResponseValidator = z.object({
|
|
241
255
|
body: route.validators.response ?? z.undefined(),
|
|
242
256
|
headers: route.validators.responseHeaders?.strict() ?? z.object({}),
|
|
257
|
+
status: z.literal(200),
|
|
243
258
|
});
|
|
259
|
+
const onResponse = {
|
|
260
|
+
...onHandler,
|
|
261
|
+
response,
|
|
262
|
+
};
|
|
244
263
|
if (this.config.disableResponseValidation) {
|
|
245
|
-
this.
|
|
246
|
-
|
|
264
|
+
if (this.config.onResponse) {
|
|
265
|
+
await this.config.onResponse(onResponse);
|
|
266
|
+
}
|
|
267
|
+
return response;
|
|
247
268
|
}
|
|
248
|
-
const validated = finalResponseValidator.safeParse(
|
|
269
|
+
const validated = finalResponseValidator.safeParse(response);
|
|
249
270
|
if (!validated.success) {
|
|
250
|
-
throw new ValidationError(validated.error, ValidationLocation.Response,
|
|
271
|
+
throw new ValidationError(validated.error, ValidationLocation.Response, response);
|
|
251
272
|
}
|
|
252
|
-
this.
|
|
253
|
-
|
|
273
|
+
if (this.config.onResponse) {
|
|
274
|
+
await this.config.onResponse(onResponse);
|
|
275
|
+
}
|
|
276
|
+
return response;
|
|
254
277
|
}
|
|
255
278
|
catch (e) {
|
|
256
|
-
return this.handleError(e, originalReq);
|
|
279
|
+
return await this.handleError(e, originalReq);
|
|
257
280
|
}
|
|
258
281
|
}
|
|
259
|
-
handleError(e, req) {
|
|
260
|
-
this.logger.error('Error during request openAPI route handling', e);
|
|
282
|
+
async handleError(e, req) {
|
|
261
283
|
try {
|
|
262
|
-
const
|
|
284
|
+
const event = {
|
|
285
|
+
request: req,
|
|
286
|
+
logger: this.logger,
|
|
287
|
+
error: e,
|
|
288
|
+
};
|
|
289
|
+
const response = this.config.onError ? await this.config.onError(event) : this.config.defaultError;
|
|
263
290
|
const status = this.config.errors[response.code].status;
|
|
264
291
|
const valid = this.config.errors[response.code].responseValidator.safeParse(response.body);
|
|
265
292
|
if (!valid.success) {
|
|
266
293
|
throw new Error("Error response haven't passed validation");
|
|
267
294
|
}
|
|
268
|
-
this.logger.info(`Response: '${status}'`, response.body);
|
|
269
295
|
return { status: Number(status), body: response.body, headers: {} };
|
|
270
296
|
}
|
|
271
297
|
catch (e) {
|
|
@@ -2,6 +2,9 @@ import { ErrorCode } from '../../../enums/ErrorCode.js';
|
|
|
2
2
|
import { SampleRouteType } from '../../../enums/SampleRouteType.js';
|
|
3
3
|
import { Config } from '../../../types/config/Config.js';
|
|
4
4
|
import { ErrorResponse } from '../../../types/config/ErrorResponse.js';
|
|
5
|
+
import { OnErrorEvent } from '../../../types/events/OnErrorEvent.js';
|
|
6
|
+
import { OnResponseEvent } from '../../../types/events/OnResponseEvent.js';
|
|
7
|
+
import { OnRouteEvent } from '../../../types/events/OnRouteEvent.js';
|
|
5
8
|
import { RoutePath } from '../../../types/RoutePath.js';
|
|
6
9
|
import { DefaultErrorMap } from './DefaultErrorMap.js';
|
|
7
10
|
import { DefaultRouteContextMap } from './DefaultRouteContextMap.js';
|
|
@@ -17,6 +20,10 @@ export declare class DefaultConfig implements Config<SampleRouteType, ErrorCode,
|
|
|
17
20
|
readonly error: ErrorCode.UnknownError;
|
|
18
21
|
};
|
|
19
22
|
};
|
|
20
|
-
|
|
23
|
+
onRequest?: () => Promise<void>;
|
|
24
|
+
onRoute?: (e: OnRouteEvent) => Promise<void>;
|
|
25
|
+
onHandler?: () => Promise<void>;
|
|
26
|
+
onResponse?: (e: OnResponseEvent) => Promise<void>;
|
|
27
|
+
onError?: (e: OnErrorEvent) => Promise<ErrorResponse<ErrorCode, DefaultErrorMap>>;
|
|
21
28
|
skipDescriptionsCheck?: boolean;
|
|
22
29
|
}
|
|
@@ -14,9 +14,23 @@ export class DefaultConfig {
|
|
|
14
14
|
error: ErrorCode.UnknownError,
|
|
15
15
|
},
|
|
16
16
|
};
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
17
|
+
onRequest = () => Promise.resolve();
|
|
18
|
+
onRoute = async (e) => {
|
|
19
|
+
e.logger.info(`Calling route ${e.route.path}`);
|
|
20
|
+
e.logger.info(`${e.method}: ${e.request.url}`, {
|
|
21
|
+
path: e.path,
|
|
22
|
+
query: e.query,
|
|
23
|
+
body: e.body,
|
|
24
|
+
});
|
|
25
|
+
};
|
|
26
|
+
onHandler = () => Promise.resolve();
|
|
27
|
+
onResponse = async (e) => {
|
|
28
|
+
e.logger.info(`Response: ${e.response.status}`, { body: e.response.body, headers: e.response.headers });
|
|
29
|
+
};
|
|
30
|
+
onError = async (e) => {
|
|
31
|
+
e.logger.error('Error during request openAPI route handling', { url: e.request.url, error: e.error });
|
|
32
|
+
if (e.error instanceof ValidationError) {
|
|
33
|
+
const zodError = e.error.getZodError();
|
|
20
34
|
const map = [];
|
|
21
35
|
for (const issue of zodError.issues) {
|
|
22
36
|
map.push({
|
|
@@ -24,18 +38,18 @@ export class DefaultConfig {
|
|
|
24
38
|
message: issue.message,
|
|
25
39
|
});
|
|
26
40
|
}
|
|
27
|
-
if (e.getLocation() !== ValidationLocation.Response) {
|
|
41
|
+
if (e.error.getLocation() !== ValidationLocation.Response) {
|
|
28
42
|
const response = {
|
|
29
43
|
error: {
|
|
30
44
|
code: ErrorCode.ValidationFailed,
|
|
31
|
-
location: e.getLocation(),
|
|
45
|
+
location: e.error.getLocation(),
|
|
32
46
|
fieldErrors: map,
|
|
33
47
|
},
|
|
34
48
|
};
|
|
35
49
|
return { code: ErrorCode.ValidationFailed, body: response };
|
|
36
50
|
}
|
|
37
51
|
}
|
|
38
|
-
if (e instanceof BuiltInError && e.getCode() === ErrorCode.NotFound) {
|
|
52
|
+
if (e.error instanceof BuiltInError && e.error.getCode() === ErrorCode.NotFound) {
|
|
39
53
|
return { code: ErrorCode.NotFound, body: { error: ErrorCode.NotFound } };
|
|
40
54
|
}
|
|
41
55
|
const unknownError = {
|
|
@@ -3,8 +3,10 @@ import { Method } from '../../enums/Methods.js';
|
|
|
3
3
|
import { Route } from '../../types/Route.js';
|
|
4
4
|
import { AnyConfig } from '../../types/config/AnyConfig.js';
|
|
5
5
|
import { RouteExtraProps } from '../../types/config/RouteExtraProps.js';
|
|
6
|
+
import { StandardRoute } from './types/StandardRoute.js';
|
|
6
7
|
export declare class RoutingFactory<TRouteTypes extends string, TErrorCodes extends string, TConfig extends AnyConfig<TRouteTypes, TErrorCodes>> {
|
|
7
8
|
protected map: TConfig;
|
|
8
9
|
constructor(map: TConfig);
|
|
9
|
-
|
|
10
|
+
createCustomRoute<TType extends TRouteTypes, TMethod extends Method, TResponseValidator extends ZodFirstPartySchemaTypes | undefined = undefined, TQueryValidator extends ZodObject<ZodRawShape> | undefined = undefined, TPathValidator extends ZodObject<ZodRawShape> | undefined = undefined, TBodyValidator extends ZodFirstPartySchemaTypes | undefined = undefined, TResponseHeadersValidator extends ZodObject<ZodRawShape> | undefined = undefined>(params: Route<TType, Awaited<ReturnType<TConfig['routes'][TType]['contextFactory']>>, TResponseValidator, TPathValidator, TQueryValidator, TBodyValidator, TResponseHeadersValidator, TMethod> & (RouteExtraProps<TConfig['routes'][TType]['extraProps']>)): Route<TType, Awaited<ReturnType<TConfig['routes'][TType]['contextFactory']>>, TResponseValidator, TPathValidator, TQueryValidator, TBodyValidator, TResponseHeadersValidator>;
|
|
11
|
+
createRoute<TType extends TRouteTypes, TMethod extends Method, TResponseValidator extends ZodFirstPartySchemaTypes | undefined = undefined, TQueryValidator extends ZodObject<ZodRawShape> | undefined = undefined, TPathValidator extends ZodObject<ZodRawShape> | undefined = undefined, TBodyValidator extends ZodFirstPartySchemaTypes | undefined = undefined, TResponseHeadersValidator extends ZodObject<ZodRawShape> | undefined = undefined>(params: StandardRoute<TType, Awaited<ReturnType<TConfig['routes'][TType]['contextFactory']>>, TResponseValidator, TPathValidator, TQueryValidator, TBodyValidator, TMethod> & (RouteExtraProps<TConfig['routes'][TType]['extraProps']>)): Route<TType, Awaited<ReturnType<TConfig['routes'][TType]['contextFactory']>>, TResponseValidator, TPathValidator, TQueryValidator, TBodyValidator, TResponseHeadersValidator>;
|
|
10
12
|
}
|
|
@@ -3,7 +3,7 @@ export class RoutingFactory {
|
|
|
3
3
|
constructor(map) {
|
|
4
4
|
this.map = map;
|
|
5
5
|
}
|
|
6
|
-
|
|
6
|
+
createCustomRoute(params) {
|
|
7
7
|
const result = {
|
|
8
8
|
...params,
|
|
9
9
|
method: params.method,
|
|
@@ -21,4 +21,29 @@ export class RoutingFactory {
|
|
|
21
21
|
};
|
|
22
22
|
return result;
|
|
23
23
|
}
|
|
24
|
+
createRoute(params) {
|
|
25
|
+
const newHandler = async (ctx) => {
|
|
26
|
+
const body = await params.handler(ctx);
|
|
27
|
+
return {
|
|
28
|
+
body: body,
|
|
29
|
+
status: 200,
|
|
30
|
+
headers: {},
|
|
31
|
+
};
|
|
32
|
+
};
|
|
33
|
+
const result = {
|
|
34
|
+
...params,
|
|
35
|
+
method: params.method,
|
|
36
|
+
type: params.type,
|
|
37
|
+
path: params.path,
|
|
38
|
+
description: params.description,
|
|
39
|
+
validators: {
|
|
40
|
+
query: params.validators.query,
|
|
41
|
+
path: params.validators.path,
|
|
42
|
+
response: params.validators.response,
|
|
43
|
+
body: params.validators.body,
|
|
44
|
+
},
|
|
45
|
+
handler: newHandler,
|
|
46
|
+
};
|
|
47
|
+
return result;
|
|
48
|
+
}
|
|
24
49
|
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { z, ZodFirstPartySchemaTypes, ZodObject, ZodRawShape } from 'zod';
|
|
2
|
+
import { Method } from '../../../enums/Methods.js';
|
|
3
|
+
import { RoutePath } from '../../../types/RoutePath.js';
|
|
4
|
+
type BodyHandlerResponse<T extends ZodFirstPartySchemaTypes | undefined = undefined> = Promise<T extends undefined ? void : z.infer<Exclude<T, undefined>>>;
|
|
5
|
+
export interface StandardRoute<TType extends string, TContext extends object, TResponseValidator extends ZodFirstPartySchemaTypes | undefined, TPathValidator extends ZodObject<ZodRawShape> | undefined, TQueryValidator extends ZodObject<ZodRawShape> | undefined, TBodyValidator extends ZodFirstPartySchemaTypes | undefined, TMethod extends Method = Method> {
|
|
6
|
+
tags?: string[];
|
|
7
|
+
operationId?: string;
|
|
8
|
+
type: TType;
|
|
9
|
+
method: TMethod;
|
|
10
|
+
path: RoutePath;
|
|
11
|
+
description: string;
|
|
12
|
+
validators: {
|
|
13
|
+
query?: TQueryValidator;
|
|
14
|
+
path?: TPathValidator;
|
|
15
|
+
body?: TMethod extends 'GET' ? never : TBodyValidator;
|
|
16
|
+
response?: TResponseValidator;
|
|
17
|
+
};
|
|
18
|
+
handler: (context: {
|
|
19
|
+
params: {
|
|
20
|
+
body: TBodyValidator extends ZodFirstPartySchemaTypes ? z.infer<TBodyValidator> : object;
|
|
21
|
+
query: TQueryValidator extends ZodObject<ZodRawShape> ? z.infer<TQueryValidator> : object;
|
|
22
|
+
path: TPathValidator extends ZodObject<ZodRawShape> ? z.infer<TPathValidator> : object;
|
|
23
|
+
};
|
|
24
|
+
} & TContext) => BodyHandlerResponse<TResponseValidator>;
|
|
25
|
+
}
|
|
26
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -2,6 +2,7 @@ import { OpenApi } from '../../OpenApi.js';
|
|
|
2
2
|
import { Method } from '../../enums/Methods.js';
|
|
3
3
|
import { SampleRouteType } from '../../enums/SampleRouteType.js';
|
|
4
4
|
import { RoutePath } from '../../types/RoutePath.js';
|
|
5
|
+
import { TestLogger } from './utils/TestLogger.js';
|
|
5
6
|
export declare class TestUtils {
|
|
6
7
|
static createRequest(route: RoutePath, method?: Method, body?: object): Request;
|
|
7
8
|
static sendRequest(api: OpenApi<any, any, any>, route: RoutePath, method?: Method, body?: object): Promise<{
|
|
@@ -10,4 +11,5 @@ export declare class TestUtils {
|
|
|
10
11
|
}>;
|
|
11
12
|
static createOpenApi(): OpenApi<SampleRouteType, import("../../index.js").OpenApiErrorCode, import("../../index.js").OpenApiDefaultConfig>;
|
|
12
13
|
static awaitGeneric<T>(timeoutMs: number, intervalMs: number, callback: () => Promise<T | null>): Promise<T | null>;
|
|
14
|
+
static getTestLogger(): TestLogger;
|
|
13
15
|
}
|
|
@@ -2,6 +2,7 @@ import z from 'zod';
|
|
|
2
2
|
import { OpenApi } from '../../OpenApi.js';
|
|
3
3
|
import { Method } from '../../enums/Methods.js';
|
|
4
4
|
import { SampleRouteType } from '../../enums/SampleRouteType.js';
|
|
5
|
+
import { TestLogger } from './utils/TestLogger.js';
|
|
5
6
|
export class TestUtils {
|
|
6
7
|
static createRequest(route, method = Method.GET, body) {
|
|
7
8
|
const request = new Request(`http://localhost${route}`, {
|
|
@@ -45,4 +46,7 @@ export class TestUtils {
|
|
|
45
46
|
} while (now < deadline);
|
|
46
47
|
return null;
|
|
47
48
|
}
|
|
49
|
+
static getTestLogger() {
|
|
50
|
+
return new TestLogger('TestUtils');
|
|
51
|
+
}
|
|
48
52
|
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Logger } from '../../Logger/Logger.js';
|
|
2
|
+
export declare class TestLogger extends Logger {
|
|
3
|
+
private messages;
|
|
4
|
+
popMessage(): {
|
|
5
|
+
message: string;
|
|
6
|
+
level: string;
|
|
7
|
+
data?: object;
|
|
8
|
+
} | undefined;
|
|
9
|
+
shiftMessage(): {
|
|
10
|
+
message: string;
|
|
11
|
+
level: string;
|
|
12
|
+
data?: object;
|
|
13
|
+
} | undefined;
|
|
14
|
+
protected log(message: string, level: string, data?: object): void;
|
|
15
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Logger } from '../../Logger/Logger.js';
|
|
2
|
+
export class TestLogger extends Logger {
|
|
3
|
+
messages = [];
|
|
4
|
+
popMessage() {
|
|
5
|
+
return this.messages.pop();
|
|
6
|
+
}
|
|
7
|
+
shiftMessage() {
|
|
8
|
+
return this.messages.shift();
|
|
9
|
+
}
|
|
10
|
+
log(message, level, data) {
|
|
11
|
+
this.messages.push({ message, level, data });
|
|
12
|
+
}
|
|
13
|
+
}
|
package/dist/types/Route.d.ts
CHANGED
|
@@ -1,12 +1,7 @@
|
|
|
1
1
|
import { z, ZodFirstPartySchemaTypes, ZodObject, ZodRawShape } from 'zod';
|
|
2
2
|
import { Method } from '../enums/Methods.js';
|
|
3
3
|
import { RoutePath } from './RoutePath.js';
|
|
4
|
-
|
|
5
|
-
type FullHandlerRespnse<T extends ZodFirstPartySchemaTypes | undefined, THeaders extends ZodObject<ZodRawShape> | undefined> = Promise<{
|
|
6
|
-
body: Awaited<BodyHandlerResponse<T>>;
|
|
7
|
-
headers: z.infer<Exclude<THeaders, undefined>>;
|
|
8
|
-
}>;
|
|
9
|
-
type HandlerResponse<T extends ZodFirstPartySchemaTypes | undefined, TH extends ZodObject<ZodRawShape> | undefined> = TH extends undefined ? BodyHandlerResponse<T> : FullHandlerRespnse<T, Exclude<TH, undefined>>;
|
|
4
|
+
import { RouteResponse } from './RouteResponse.js';
|
|
10
5
|
export interface Route<TType extends string, TContext extends object, TResponseValidator extends ZodFirstPartySchemaTypes | undefined, TPathValidator extends ZodObject<ZodRawShape> | undefined, TQueryValidator extends ZodObject<ZodRawShape> | undefined, TBodyValidator extends ZodFirstPartySchemaTypes | undefined, TResponseHeadersValidator extends ZodObject<ZodRawShape> | undefined, TMethod extends Method = Method> {
|
|
11
6
|
tags?: string[];
|
|
12
7
|
operationId?: string;
|
|
@@ -27,6 +22,5 @@ export interface Route<TType extends string, TContext extends object, TResponseV
|
|
|
27
22
|
query: TQueryValidator extends ZodObject<ZodRawShape> ? z.infer<TQueryValidator> : object;
|
|
28
23
|
path: TPathValidator extends ZodObject<ZodRawShape> ? z.infer<TPathValidator> : object;
|
|
29
24
|
};
|
|
30
|
-
} & TContext) =>
|
|
25
|
+
} & TContext) => Promise<RouteResponse>;
|
|
31
26
|
}
|
|
32
|
-
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { ZodOpenApiVersion } from 'zod-openapi';
|
|
2
2
|
import { Logger } from '../../services/Logger/Logger.js';
|
|
3
3
|
import { LogLevel } from '../../services/Logger/types/LogLevel.js';
|
|
4
|
-
import { AnyRoute } from '../AnyRoute.js';
|
|
5
4
|
import { RoutePath } from '../RoutePath.js';
|
|
6
5
|
import { ErrorConfigMap } from './ErrorConfigMap.js';
|
|
7
6
|
import { ErrorResponse } from './ErrorResponse.js';
|
|
@@ -9,6 +8,11 @@ import { RouteConfigMap } from './RouteConfigMap.js';
|
|
|
9
8
|
import { RouteContextMap } from './RouteContextMap.js';
|
|
10
9
|
import { RouteExtraPropsMap } from './RouteExtraPropsMap.js';
|
|
11
10
|
import { Server } from './Server.js';
|
|
11
|
+
import { OnErrorEvent } from '../events/OnErrorEvent.js';
|
|
12
|
+
import { OnHandlerEvent } from '../events/OnHandlerEvent.js';
|
|
13
|
+
import { OnRequestEvent } from '../events/OnRequestEvent.js';
|
|
14
|
+
import { OnResponseEvent } from '../events/OnResponseEvent.js';
|
|
15
|
+
import { OnRouteEvent } from '../events/OnRouteEvent.js';
|
|
12
16
|
export type Config<TRouteTypes extends string, TErrorCodes extends string, TErrorConfigMap extends ErrorConfigMap<TErrorCodes>, TRouteParamMap extends RouteExtraPropsMap<TRouteTypes>, TRouteContextMap extends RouteContextMap<TRouteTypes, TRouteParamMap>, TRouteConfigMap extends RouteConfigMap<TRouteTypes, TErrorCodes, TRouteParamMap, TRouteContextMap>> = {
|
|
13
17
|
disableResponseValidation?: boolean;
|
|
14
18
|
logger?: Logger;
|
|
@@ -28,13 +32,9 @@ export type Config<TRouteTypes extends string, TErrorCodes extends string, TErro
|
|
|
28
32
|
apiVersion?: string;
|
|
29
33
|
servers?: Server[];
|
|
30
34
|
logLevel?: LogLevel;
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
body?: unknown;
|
|
37
|
-
status?: number;
|
|
38
|
-
headers?: Record<string, string>;
|
|
39
|
-
}>;
|
|
35
|
+
onRequest?: (e: OnRequestEvent) => Promise<void>;
|
|
36
|
+
onRoute?: (e: OnRouteEvent) => Promise<void>;
|
|
37
|
+
onHandler?: (e: OnHandlerEvent) => Promise<void>;
|
|
38
|
+
onResponse?: (e: OnResponseEvent) => Promise<void>;
|
|
39
|
+
onError?: (e: OnErrorEvent) => Promise<ErrorResponse<TErrorCodes, TErrorConfigMap>>;
|
|
40
40
|
};
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { ZodObject, ZodRawShape } from 'zod';
|
|
2
2
|
import { AnyRoute } from '../AnyRoute.js';
|
|
3
3
|
import { RouteExtraProps } from './RouteExtraProps.js';
|
|
4
|
+
import { Logger } from '../../services/Logger/Logger.js';
|
|
4
5
|
export type ContextParams<TRouteType extends string, TExtraProps extends ZodObject<ZodRawShape> | undefined> = {
|
|
5
6
|
route: AnyRoute<TRouteType> & RouteExtraProps<TExtraProps>;
|
|
6
7
|
request: Request;
|
|
8
|
+
logger: Logger;
|
|
7
9
|
params: {
|
|
8
10
|
body: unknown;
|
|
9
11
|
query: unknown;
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { ZodObject, ZodRawShape } from 'zod';
|
|
2
2
|
import { ContextParams } from './ContextParams.js';
|
|
3
|
+
import { RouteHandlerWrapper } from './RouteHandlerWrapper.js';
|
|
3
4
|
export type RouteConfig<TRouteType extends string, TErrorCodes extends string, TExtraProps extends ZodObject<ZodRawShape> | undefined = ZodObject<ZodRawShape> | undefined, TContext extends object | undefined = object | undefined> = {
|
|
4
5
|
authorization: boolean;
|
|
5
6
|
extraProps: TExtraProps;
|
|
6
7
|
contextFactory: (params: ContextParams<TRouteType, TExtraProps>) => Promise<TContext>;
|
|
8
|
+
handlerWrapper?: RouteHandlerWrapper<TRouteType, TExtraProps, TContext>;
|
|
7
9
|
errors?: {
|
|
8
10
|
[key in TErrorCodes]?: true;
|
|
9
11
|
};
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { ZodObject, ZodRawShape } from 'zod';
|
|
2
|
+
import { ContextParams } from './ContextParams.js';
|
|
3
|
+
import { RouteResponse } from '../RouteResponse.js';
|
|
4
|
+
export type RouteHandlerWrapper<TRouteType extends string, TExtraProps extends ZodObject<ZodRawShape> | undefined, TContext extends object | undefined> = (handler: () => Promise<RouteResponse>, params: ContextParams<TRouteType, TExtraProps>, context: TContext) => Promise<RouteResponse>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { AnyRoute } from '../AnyRoute.js';
|
|
2
|
+
import { OnRequestEvent } from './OnRequestEvent.js';
|
|
3
|
+
export interface OnRouteEvent extends OnRequestEvent {
|
|
4
|
+
path: string;
|
|
5
|
+
method: string;
|
|
6
|
+
params: Record<string, string>;
|
|
7
|
+
query: Record<string, string | string[]>;
|
|
8
|
+
body: unknown;
|
|
9
|
+
route: AnyRoute<string>;
|
|
10
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/package.json
CHANGED