@travetto/web 7.0.0-rc.1 → 7.0.0-rc.3

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.
@@ -28,12 +28,12 @@ export class ControllerVisitUtil {
28
28
 
29
29
  await visitor.onControllerStart?.(controller);
30
30
  for (const endpoint of controller.endpoints) {
31
- const endpointSchema = SchemaRegistryIndex.getMethodConfig(cls, endpoint.methodName);
31
+ const endpointSchema = SchemaRegistryIndex.get(cls).getMethod(endpoint.methodName);
32
32
  if (endpointSchema.private === true && options.skipPrivate) {
33
33
  continue;
34
34
  }
35
35
 
36
- const { parameters: params, returnType } = SchemaRegistryIndex.getMethodConfig(cls, endpoint.methodName);
36
+ const { parameters: params, returnType } = endpointSchema;
37
37
  await visitor.onEndpointStart?.(endpoint, controller, params);
38
38
  if (returnType) {
39
39
  await this.#onSchemaEvent(visitor, returnType.type);
@@ -20,18 +20,18 @@ export abstract class BaseWebRouter implements WebRouter {
20
20
  #cleanup = new Map<string, Function>();
21
21
  #interceptors: WebInterceptor[];
22
22
 
23
- async #register(c: Class): Promise<void> {
24
- const config = ControllerRegistryIndex.getConfig(c);
23
+ async #register(cls: Class): Promise<void> {
24
+ const config = ControllerRegistryIndex.getConfig(cls);
25
25
 
26
- let endpoints = await EndpointUtil.getBoundEndpoints(c);
26
+ let endpoints = await EndpointUtil.getBoundEndpoints(cls);
27
27
  endpoints = EndpointUtil.orderEndpoints(endpoints);
28
28
 
29
- for (const ep of endpoints) {
30
- ep.filter = EndpointUtil.createEndpointHandler(this.#interceptors, ep, config);
29
+ for (const endpoint of endpoints) {
30
+ endpoint.filter = EndpointUtil.createEndpointHandler(this.#interceptors, endpoint, config);
31
31
  }
32
32
 
33
33
  const fn = await this.register(endpoints, config);
34
- this.#cleanup.set(c.Ⲑid, fn);
34
+ this.#cleanup.set(cls.Ⲑid, fn);
35
35
  };
36
36
 
37
37
  /**
@@ -41,25 +41,25 @@ export abstract class BaseWebRouter implements WebRouter {
41
41
 
42
42
  this.#interceptors = await DependencyRegistryIndex.getInstances(toConcrete<WebInterceptor>());
43
43
  this.#interceptors = EndpointUtil.orderInterceptors(this.#interceptors);
44
- const names = this.#interceptors.map(x => x.constructor.name);
44
+ const names = this.#interceptors.map(interceptor => interceptor.constructor.name);
45
45
  console.debug('Sorting interceptors', { count: names.length, names });
46
46
 
47
47
  // Register all active
48
- for (const c of ControllerRegistryIndex.getClasses()) {
49
- await this.#register(c);
48
+ for (const cls of ControllerRegistryIndex.getClasses()) {
49
+ await this.#register(cls);
50
50
  }
51
51
 
52
52
  // Listen for updates
53
- Registry.onClassChange(async e => {
54
- const targetCls = 'curr' in e ? e.curr : e.prev;
55
- console.debug('Registry event', { type: e.type, target: targetCls.Ⲑid });
53
+ Registry.onClassChange(async event => {
54
+ const targetCls = 'current' in event ? event.current : event.previous;
55
+ console.debug('Registry event', { type: event.type, target: targetCls.Ⲑid });
56
56
 
57
- if ('prev' in e) {
58
- this.#cleanup.get(e.prev.Ⲑid)?.();
59
- this.#cleanup.delete(e.prev.Ⲑid);
57
+ if ('previous' in event) {
58
+ this.#cleanup.get(event.previous.Ⲑid)?.();
59
+ this.#cleanup.delete(event.previous.Ⲑid);
60
60
  }
61
- if ('curr' in e) {
62
- await this.#register(e.curr);
61
+ if ('current' in event) {
62
+ await this.#register(event.current);
63
63
  }
64
64
  }, ControllerRegistryIndex);
65
65
  }
@@ -27,16 +27,16 @@ export class StandardWebRouter extends BaseWebRouter {
27
27
  raw = router();
28
28
 
29
29
  async register(endpoints: EndpointConfig[]): Promise<() => void> {
30
- for (const ep of endpoints) {
31
- const fullPath = ep.fullPath.replace(/[*][^*]+/g, '*'); // Flatten wildcards
30
+ for (const endpoint of endpoints) {
31
+ const fullPath = endpoint.fullPath.replace(/[*][^*]+/g, '*'); // Flatten wildcards
32
32
  const handler = (): void => { };
33
- this.#cache.set(handler, ep);
34
- this.raw[HTTP_METHODS[ep.httpMethod ?? DEFAULT_HTTP_METHOD].lower](fullPath, handler);
33
+ this.#cache.set(handler, endpoint);
34
+ this.raw[HTTP_METHODS[endpoint.httpMethod ?? DEFAULT_HTTP_METHOD].lower](fullPath, handler);
35
35
  }
36
36
 
37
37
  return (): void => {
38
- for (const ep of endpoints ?? []) {
39
- this.raw.off(ep.httpMethod ?? DEFAULT_HTTP_METHOD, ep.fullPath);
38
+ for (const endpoint of endpoints ?? []) {
39
+ this.raw.off(endpoint.httpMethod ?? DEFAULT_HTTP_METHOD, endpoint.fullPath);
40
40
  }
41
41
  };
42
42
  }
package/src/types/core.ts CHANGED
@@ -3,8 +3,8 @@ function verb<
3
3
  M extends string,
4
4
  L extends string,
5
5
  C extends Partial<MethodConfig>
6
- >(method: M, lower: L, cfg: C): { method: M, lower: L } & C & MethodConfig {
7
- return { body: false, cacheable: false, emptyStatusCode: 204, ...cfg, method, lower, };
6
+ >(method: M, lower: L, config: C): { method: M, lower: L } & C & MethodConfig {
7
+ return { body: false, cacheable: false, emptyStatusCode: 204, ...config, method, lower, };
8
8
  }
9
9
 
10
10
  export const HTTP_METHODS = {
@@ -9,14 +9,14 @@ export type WebHeadersInit = Headers | Record<string, undefined | null | HeaderV
9
9
  */
10
10
  export class WebHeaders extends Headers {
11
11
 
12
- constructor(o?: WebHeadersInit) {
13
- const passed = (o instanceof Headers);
14
- super(passed ? o : undefined);
12
+ constructor(input?: WebHeadersInit) {
13
+ const passed = (input instanceof Headers);
14
+ super(passed ? input : undefined);
15
15
 
16
- if (o && !passed) {
17
- for (const [k, v] of (Array.isArray(o) ? o : Object.entries(o))) {
18
- if (v !== undefined && v !== null && !k.startsWith(':')) {
19
- this.append(k, castTo(v));
16
+ if (input && !passed) {
17
+ for (const [key, value] of (Array.isArray(input) ? input : Object.entries(input))) {
18
+ if (value !== undefined && value !== null && !key.startsWith(':')) {
19
+ this.append(key, castTo(value));
20
20
  }
21
21
  }
22
22
  }
@@ -33,21 +33,21 @@ export class WebHeaders extends Headers {
33
33
  * Get a header value as a list, breaking on commas except for cookies
34
34
  */
35
35
  getList(key: string): string[] | undefined {
36
- const v = this.get(key);
37
- if (!v) {
36
+ const value = this.get(key);
37
+ if (!value) {
38
38
  return;
39
- } else if (v.toLowerCase() === 'set-cookie') {
39
+ } else if (value.toLowerCase() === 'set-cookie') {
40
40
  return this.getSetCookie();
41
41
  }
42
- return v.split(key === 'cookie' ? /\s{0,3};\s{0,3}/ : /\s{0,3},\s{0,3}/);
42
+ return value.split(key === 'cookie' ? /\s{0,3};\s{0,3}/ : /\s{0,3},\s{0,3}/);
43
43
  }
44
44
 
45
45
  // @ts-expect-error
46
- forEach(set: (v: string | string[], k: string, headers: WebHeaders) => void): void;
47
- forEach(set: (v: Any, k: string, headers: WebHeaders) => void): void;
48
- forEach(set: (v: string | string[], k: string, headers: WebHeaders) => void): void {
49
- for (const [k, v] of this.entries()) {
50
- set(k === 'set-cookie' ? this.getSetCookie() : v, k, this);
46
+ forEach(set: (value: string | string[], key: string, headers: WebHeaders) => void): void;
47
+ forEach(set: (value: Any, key: string, headers: WebHeaders) => void): void;
48
+ forEach(set: (value: string | string[], key: string, headers: WebHeaders) => void): void {
49
+ for (const [key, value] of this.entries()) {
50
+ set(key === 'set-cookie' ? this.getSetCookie() : value, key, this);
51
51
  }
52
52
  }
53
53
 
@@ -25,9 +25,9 @@ export class BaseWebMessage<B = unknown, C = unknown> implements WebMessage<B, C
25
25
  readonly headers: WebHeaders;
26
26
  body?: B;
27
27
 
28
- constructor(o: WebMessageInit<B, C> = {}) {
29
- this.context = o.context ?? castTo<C>({});
30
- this.headers = new WebHeaders(o.headers);
31
- this.body = o.body;
28
+ constructor(input: WebMessageInit<B, C> = {}) {
29
+ this.context = input.context ?? castTo<C>({});
30
+ this.headers = new WebHeaders(input.headers);
31
+ this.body = input.body;
32
32
  }
33
33
  }
package/src/util/body.ts CHANGED
@@ -19,13 +19,13 @@ export class WebBodyUtil {
19
19
  */
20
20
  static async * buildMultiPartBody(form: FormData, boundary: string): AsyncIterable<string | Buffer> {
21
21
  const nl = '\r\n';
22
- for (const [k, v] of form.entries()) {
23
- const data = v.slice();
22
+ for (const [key, value] of form.entries()) {
23
+ const data = value.slice();
24
24
  const filename = data instanceof File ? data.name : undefined;
25
25
  const size = data instanceof Blob ? data.size : data.length;
26
26
  const type = data instanceof Blob ? data.type : undefined;
27
27
  yield `--${boundary}${nl}`;
28
- yield `Content-Disposition: form-data; name="${k}"; filename="${filename ?? k}"${nl}`;
28
+ yield `Content-Disposition: form-data; name="${key}"; filename="${filename ?? key}"${nl}`;
29
29
  yield `Content-Length: ${size}${nl}`;
30
30
  if (type) {
31
31
  yield `Content-Type: ${type}${nl}`;
@@ -66,7 +66,7 @@ export class WebBodyUtil {
66
66
  toAdd.push(['Content-disposition', `attachment; filename="${value.name}"`]);
67
67
  }
68
68
 
69
- return toAdd.filter((x): x is [string, string] => !!x[1]);
69
+ return toAdd.filter((pair): pair is [string, string] => !!pair[1]);
70
70
  }
71
71
 
72
72
  /**
@@ -97,8 +97,8 @@ export class WebBodyUtil {
97
97
 
98
98
  const out: Omit<WebMessage<WebBinaryBody>, 'context'> = { headers: new WebHeaders(message.headers), body: null! };
99
99
  if (body instanceof Blob) {
100
- for (const [k, v] of this.getBlobHeaders(body)) {
101
- out.headers.set(k, v);
100
+ for (const [key, value] of this.getBlobHeaders(body)) {
101
+ out.headers.set(key, value);
102
102
  }
103
103
  out.body = Readable.fromWeb(body.stream());
104
104
  } else if (body instanceof FormData) {
@@ -139,29 +139,29 @@ export class WebBodyUtil {
139
139
  /**
140
140
  * Set body and mark as unprocessed
141
141
  */
142
- static markRaw(val: WebBinaryBody | undefined): typeof val {
143
- if (val) {
144
- Object.defineProperty(val, WebRawStreamSymbol, { value: val });
142
+ static markRaw(body: WebBinaryBody | undefined): typeof body {
143
+ if (body) {
144
+ Object.defineProperty(body, WebRawStreamSymbol, { value: body });
145
145
  }
146
- return val;
146
+ return body;
147
147
  }
148
148
 
149
149
  /**
150
150
  * Is the input raw
151
151
  */
152
- static isRaw(val: unknown): val is WebBinaryBody {
152
+ static isRaw(body: unknown): body is WebBinaryBody {
153
153
  // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
154
- return !!val && ((Buffer.isBuffer(val) || BinaryUtil.isReadable(val)) && (val as Any)[WebRawStreamSymbol] === val);
154
+ return !!body && ((Buffer.isBuffer(body) || BinaryUtil.isReadable(body)) && (body as Any)[WebRawStreamSymbol] === body);
155
155
  }
156
156
 
157
157
  /**
158
158
  * Simple parse support
159
159
  */
160
- static parseBody(type: string, val: string): unknown {
160
+ static parseBody(type: string, body: string): unknown {
161
161
  switch (type) {
162
- case 'text': return val;
163
- case 'json': return JSON.parse(val);
164
- case 'form': return Object.fromEntries(new URLSearchParams(val));
162
+ case 'text': return body;
163
+ case 'json': return JSON.parse(body);
164
+ case 'form': return Object.fromEntries(new URLSearchParams(body));
165
165
  }
166
166
  }
167
167
 
@@ -199,11 +199,11 @@ export class WebBodyUtil {
199
199
  }
200
200
  all.push(decoder.decode(Buffer.alloc(0), { stream: false }));
201
201
  return { text: all.join(''), read: received };
202
- } catch (err) {
203
- if (err instanceof Error && err.name === 'AbortError') {
202
+ } catch (error) {
203
+ if (error instanceof Error && error.name === 'AbortError') {
204
204
  throw WebError.for('Request Aborted', 400, { received });
205
205
  } else {
206
- throw err;
206
+ throw error;
207
207
  }
208
208
  }
209
209
  }
@@ -38,18 +38,18 @@ export class WebCommonUtil {
38
38
  }
39
39
 
40
40
  static #buildEdgeMap<T, U extends OrderedState<T>>(items: List<U>): Map<T, Set<T>> {
41
- const edgeMap = new Map(items.map(x => [x.key, new Set(x.after ?? [])]));
41
+ const edgeMap = new Map(items.map(item => [item.key, new Set(item.after ?? [])]));
42
42
 
43
43
  // Build out edge map
44
44
  for (const input of items) {
45
- for (const bf of input.before ?? []) {
46
- if (edgeMap.has(bf)) {
47
- edgeMap.get(bf)!.add(input.key);
45
+ for (const item of input.before ?? []) {
46
+ if (edgeMap.has(item)) {
47
+ edgeMap.get(item)!.add(input.key);
48
48
  }
49
49
  }
50
50
  const afterSet = edgeMap.get(input.key)!;
51
- for (const el of input.after ?? []) {
52
- afterSet.add(el);
51
+ for (const item of input.after ?? []) {
52
+ afterSet.add(item);
53
53
  }
54
54
  }
55
55
  return edgeMap;
@@ -64,7 +64,7 @@ export class WebCommonUtil {
64
64
  rules,
65
65
  this.#convert.bind(this),
66
66
  (regex, mime) => regex.test(mime),
67
- k => k
67
+ key => key
68
68
  );
69
69
  }
70
70
 
@@ -94,8 +94,8 @@ export class WebCommonUtil {
94
94
  }
95
95
  }
96
96
 
97
- const inputMap = new Map(items.map(x => [x.key, x]));
98
- return keys.map(k => inputMap.get(k)!);
97
+ const inputMap = new Map(items.map(item => [item.key, item]));
98
+ return keys.map(key => inputMap.get(key)!);
99
99
  }
100
100
 
101
101
  /**
@@ -110,18 +110,18 @@ export class WebCommonUtil {
110
110
  /**
111
111
  * From catch value
112
112
  */
113
- static catchResponse(err: unknown): WebResponse<Error> {
114
- if (err instanceof WebResponse) {
115
- return err;
113
+ static catchResponse(error: unknown): WebResponse<Error> {
114
+ if (error instanceof WebResponse) {
115
+ return error;
116
116
  }
117
117
 
118
- const body = err instanceof Error ? err :
119
- (!!err && typeof err === 'object' && ('message' in err && typeof err.message === 'string')) ?
120
- new AppError(err.message, { details: err }) :
121
- new AppError(`${err}`);
118
+ const body = error instanceof Error ? error :
119
+ (!!error && typeof error === 'object' && ('message' in error && typeof error.message === 'string')) ?
120
+ new AppError(error.message, { details: error }) :
121
+ new AppError(`${error}`);
122
122
 
123
- const error: Error & Partial<WebError> = body;
124
- const statusCode = error.details?.statusCode ?? ERROR_CATEGORY_STATUS[error.category!] ?? 500;
123
+ const webError: Error & Partial<WebError> = body;
124
+ const statusCode = webError.details?.statusCode ?? ERROR_CATEGORY_STATUS[webError.category!] ?? 500;
125
125
 
126
126
  return new WebResponse({ body, context: { httpStatusCode: statusCode } });
127
127
  }
@@ -147,7 +147,7 @@ export class WebCommonUtil {
147
147
  if (typeof input === 'number') {
148
148
  return input;
149
149
  }
150
- const [, num, unit] = input.toLowerCase().split(/(\d+)/);
151
- return parseInt(num, 10) * (UNIT_MAPPING[unit] ?? 1);
150
+ const [, value, unit] = input.toLowerCase().split(/(\d+)/);
151
+ return parseInt(value, 10) * (UNIT_MAPPING[unit] ?? 1);
152
152
  }
153
153
  }
@@ -4,8 +4,8 @@ import { Cookie, CookieGetOptions, CookieSetOptions } from '../types/cookie.ts';
4
4
  import { KeyGrip } from './keygrip.ts';
5
5
  import { WebHeaderUtil } from './header.ts';
6
6
 
7
- const pairText = (c: Cookie): string => `${c.name}=${c.value}`;
8
- const pair = (k: string, v: unknown): string => `${k}=${v}`;
7
+ const pairText = (cookie: Cookie): string => `${cookie.name}=${cookie.value}`;
8
+ const pair = (key: string, value: unknown): string => `${key}=${value}`;
9
9
 
10
10
  type CookieJarOptions = { keys?: string[] } & CookieSetOptions;
11
11
 
@@ -66,13 +66,13 @@ export class CookieJar {
66
66
  return this;
67
67
  }
68
68
 
69
- has(name: string, opts: CookieGetOptions = {}): boolean {
70
- const needSigned = opts.signed ?? this.#setOptions.signed;
69
+ has(name: string, options: CookieGetOptions = {}): boolean {
70
+ const needSigned = options.signed ?? this.#setOptions.signed;
71
71
  return name in this.#cookies && this.#cookies[name].signed === needSigned;
72
72
  }
73
73
 
74
- get(name: string, opts: CookieGetOptions = {}): string | undefined {
75
- if (this.has(name, opts)) {
74
+ get(name: string, options: CookieGetOptions = {}): string | undefined {
75
+ if (this.has(name, options)) {
76
76
  return this.#cookies[name]?.value;
77
77
  }
78
78
  }
@@ -111,12 +111,12 @@ export class CookieJar {
111
111
  }
112
112
 
113
113
  exportCookieHeader(): string {
114
- return this.getAll().flatMap(c => this.#exportCookie(c)).join('; ');
114
+ return this.getAll().flatMap(cookie => this.#exportCookie(cookie)).join('; ');
115
115
  }
116
116
 
117
117
  exportSetCookieHeader(): string[] {
118
118
  return this.getAll()
119
- .filter(x => x.response)
120
- .flatMap(c => this.#exportCookie(c, true));
119
+ .filter(cookie => cookie.response)
120
+ .flatMap(cookie => this.#exportCookie(cookie, true));
121
121
  }
122
122
  }
@@ -65,12 +65,12 @@ export class EndpointUtil {
65
65
 
66
66
  const inputByClass = Map.groupBy(
67
67
  [...controller?.interceptorConfigs ?? [], ...endpoint.interceptorConfigs ?? []],
68
- x => x[0]
68
+ entry => entry[0]
69
69
  );
70
70
 
71
71
  const configs = new Map<Class, unknown>(interceptors.map(inst => {
72
72
  const cls = asConstructable<WebInterceptor>(inst).constructor;
73
- const inputs = (inputByClass.get(cls) ?? []).map(x => x[1]);
73
+ const inputs = (inputByClass.get(cls) ?? []).map(entry => entry[1]);
74
74
  const config = Object.assign({}, inst.config, ...inputs);
75
75
  return [cls, inst.finalizeConfig?.({ config, endpoint }, castTo(inputs)) ?? config];
76
76
  }));
@@ -96,8 +96,8 @@ export class EndpointUtil {
96
96
  case 'header': return isArray ? request.headers.getList(name) : request.headers.get(name);
97
97
  case 'query': {
98
98
  const withQuery: typeof request & { [WebQueryExpandedSymbol]?: Record<string, unknown> } = request;
99
- const q = withQuery[WebQueryExpandedSymbol] ??= BindUtil.expandPaths(request.context.httpQuery ?? {});
100
- return q[name];
99
+ const query = withQuery[WebQueryExpandedSymbol] ??= BindUtil.expandPaths(request.context.httpQuery ?? {});
100
+ return query[name];
101
101
  }
102
102
  }
103
103
  }
@@ -114,38 +114,32 @@ export class EndpointUtil {
114
114
  } else if (param.location === 'query') {
115
115
  // TODO: Revisit this logic?
116
116
  const withQuery: typeof request & { [WebQueryExpandedSymbol]?: Record<string, unknown> } = request;
117
- const q = withQuery[WebQueryExpandedSymbol] ??= BindUtil.expandPaths(request.context.httpQuery ?? {});
117
+ const query = withQuery[WebQueryExpandedSymbol] ??= BindUtil.expandPaths(request.context.httpQuery ?? {});
118
118
  if (param.prefix) { // Has a prefix provided
119
- return q[param.prefix];
119
+ return query[param.prefix];
120
120
  } else if (input.type.Ⲑid) { // Is a full type
121
- return q;
121
+ return query;
122
122
  }
123
123
  }
124
124
 
125
- let res = this.extractParameterValue(request, param, input.name!.toString(), input.array);
126
- if (!res && input.aliases) {
127
- for (const name of input.aliases) {
128
- res = this.extractParameterValue(request, param, name, input.array);
129
- if (res !== undefined) {
130
- break;
131
- }
132
- }
125
+ let result = this.extractParameterValue(request, param, input.name!, input.array) ?? undefined;
126
+ for (let i = 0; result === undefined && input.aliases && i < input.aliases.length; i += 1) {
127
+ result = this.extractParameterValue(request, param, input.aliases[i], input.array) ?? undefined;
133
128
  }
134
- return res;
129
+ return result;
135
130
  }
136
131
 
137
132
  /**
138
133
  * Extract all parameters for a given endpoint/request/response combo
139
134
  * @param endpoint The endpoint to extract for
140
- * @param req The request
141
- * @param res The response
135
+ * @param request The request
142
136
  */
143
137
  static async extractParameters(endpoint: EndpointConfig, request: WebRequest): Promise<unknown[]> {
144
138
  const cls = endpoint.class;
145
139
  const vals = WebCommonUtil.getRequestParams(request);
146
- const { parameters } = SchemaRegistryIndex.getMethodConfig(cls, endpoint.methodName);
147
- const combined = parameters.map((cfg) =>
148
- ({ schema: cfg, param: endpoint.parameters[cfg.index], value: vals?.[cfg.index] }));
140
+ const { parameters } = SchemaRegistryIndex.get(cls).getMethod(endpoint.methodName);
141
+ const combined = parameters.map((config) =>
142
+ ({ schema: config, param: endpoint.parameters[config.index], value: vals?.[config.index] }));
149
143
 
150
144
  try {
151
145
  const extracted = combined.map(({ param, schema, value }) =>
@@ -154,20 +148,20 @@ export class EndpointUtil {
154
148
  this.extractParameter(request, param, schema)
155
149
  );
156
150
  const params = BindUtil.coerceMethodParams(cls, endpoint.methodName, extracted);
157
- await SchemaValidator.validateMethod(cls, endpoint.methodName, params, endpoint.parameters.map(x => x.prefix));
151
+ await SchemaValidator.validateMethod(cls, endpoint.methodName, params, endpoint.parameters.map(paramConfig => paramConfig.prefix));
158
152
  return params;
159
- } catch (err) {
160
- if (err instanceof ValidationResultError) {
161
- for (const el of err.details?.errors ?? []) {
162
- if (el.kind === 'required') {
163
- const config = combined.find(x => x.schema.name === el.path);
153
+ } catch (error) {
154
+ if (error instanceof ValidationResultError) {
155
+ for (const validationError of error.details?.errors ?? []) {
156
+ if (validationError.kind === 'required') {
157
+ const config = combined.find(paramConfig => paramConfig.schema.name === validationError.path);
164
158
  if (config) {
165
- el.message = `Missing ${config.param.location} value: ${config.schema.name}`;
159
+ validationError.message = `Missing ${config.param.location} value: ${config.schema.name}`;
166
160
  }
167
161
  }
168
162
  }
169
163
  }
170
- throw err;
164
+ throw error;
171
165
  }
172
166
  }
173
167
 
@@ -181,7 +175,7 @@ export class EndpointUtil {
181
175
  const headers = endpoint.finalizedResponseHeaders;
182
176
  let response: WebResponse;
183
177
  if (body instanceof WebResponse) {
184
- for (const [k, v] of headers) { body.headers.setIfAbsent(k, v); }
178
+ for (const [key, value] of headers) { body.headers.setIfAbsent(key, value); }
185
179
  // Rewrite context
186
180
  Object.assign(body.context, { ...endpoint.responseContext, ...body.context });
187
181
  response = body;
@@ -189,8 +183,8 @@ export class EndpointUtil {
189
183
  response = new WebResponse({ body, headers, context: { ...endpoint.responseContext } });
190
184
  }
191
185
  return endpoint.responseFinalizer?.(response) ?? response;
192
- } catch (err) {
193
- throw WebCommonUtil.catchResponse(err);
186
+ } catch (error) {
187
+ throw WebCommonUtil.catchResponse(error);
194
188
  }
195
189
  }
196
190
 
@@ -208,7 +202,7 @@ export class EndpointUtil {
208
202
 
209
203
  // Filter interceptors if needed
210
204
  for (const filter of [controller?.interceptorExclude, endpoint.interceptorExclude]) {
211
- interceptors = filter ? interceptors.filter(x => !filter(x)) : interceptors;
205
+ interceptors = filter ? interceptors.filter(interceptor => !filter(interceptor)) : interceptors;
212
206
  }
213
207
 
214
208
  const interceptorFilters =
@@ -219,7 +213,7 @@ export class EndpointUtil {
219
213
  const endpointFilters = [
220
214
  ...(controller?.filters ?? []).map(fn => fn.bind(controller?.instance)),
221
215
  ...(endpoint.filters ?? []).map(fn => fn.bind(endpoint.instance)),
222
- ...(endpoint.parameters.filter(cfg => cfg.resolve).map(fn => fn.resolve!))
216
+ ...(endpoint.parameters.filter(config => config.resolve).map(fn => fn.resolve!))
223
217
  ]
224
218
  .map(fn => ({ filter: fn }));
225
219
 
@@ -236,8 +230,8 @@ export class EndpointUtil {
236
230
  /**
237
231
  * Get bound endpoints, honoring the conditional status
238
232
  */
239
- static async getBoundEndpoints(c: Class): Promise<EndpointConfig[]> {
240
- const config = ControllerRegistryIndex.getConfig(c);
233
+ static async getBoundEndpoints(cls: Class): Promise<EndpointConfig[]> {
234
+ const config = ControllerRegistryIndex.getConfig(cls);
241
235
 
242
236
  // Skip registering conditional controllers
243
237
  if (config.conditional && !await config.conditional()) {
@@ -252,15 +246,15 @@ export class EndpointUtil {
252
246
 
253
247
  // Filter out conditional endpoints
254
248
  const endpoints = (await Promise.all(
255
- config.endpoints.map(ep => Promise.resolve(ep.conditional?.() ?? true).then(v => v ? ep : undefined))
256
- )).filter(x => !!x);
249
+ config.endpoints.map(endpoint => Promise.resolve(endpoint.conditional?.() ?? true).then(value => value ? endpoint : undefined))
250
+ )).filter(endpoint => !!endpoint);
257
251
 
258
252
  if (!endpoints.length) {
259
253
  return [];
260
254
  }
261
255
 
262
- for (const ep of endpoints) {
263
- ep.instance = config.instance;
256
+ for (const endpoint of endpoints) {
257
+ endpoint.instance = config.instance;
264
258
  }
265
259
 
266
260
  return endpoints;
@@ -271,12 +265,12 @@ export class EndpointUtil {
271
265
  */
272
266
  static orderEndpoints(endpoints: EndpointConfig[]): EndpointConfig[] {
273
267
  return endpoints
274
- .map(ep => {
275
- const parts = ep.path.replace(/^[/]|[/]$/g, '').split('/');
276
- return [ep, parts.map(x => /[*]/.test(x) ? 1 : /:/.test(x) ? 2 : 3)] as const;
268
+ .map(endpoint => {
269
+ const parts = endpoint.path.replace(/^[/]|[/]$/g, '').split('/');
270
+ return [endpoint, parts.map(part => /[*]/.test(part) ? 1 : /:/.test(part) ? 2 : 3)] as const;
277
271
  })
278
272
  .toSorted((a, b) => this.#compareEndpoints(a[1], b[1]) || a[0].path.localeCompare(b[0].path))
279
- .map(([ep,]) => ep);
273
+ .map(([endpoint,]) => endpoint);
280
274
  }
281
275
 
282
276
 
@@ -284,25 +278,25 @@ export class EndpointUtil {
284
278
  * Order interceptors
285
279
  */
286
280
  static orderInterceptors(instances: WebInterceptor[]): WebInterceptor[] {
287
- const cats = WEB_INTERCEPTOR_CATEGORIES.map(x => ({
288
- key: x,
289
- start: castTo<Class<WebInterceptor>>({ name: `${x}Start` }),
290
- end: castTo<Class<WebInterceptor>>({ name: `${x}End` }),
281
+ const categoryList = WEB_INTERCEPTOR_CATEGORIES.map(category => ({
282
+ key: category,
283
+ start: castTo<Class<WebInterceptor>>({ name: `${category}Start` }),
284
+ end: castTo<Class<WebInterceptor>>({ name: `${category}End` }),
291
285
  }));
292
286
 
293
- const categoryMapping = TypedObject.fromEntries(cats.map(x => [x.key, x]));
287
+ const categoryMapping = TypedObject.fromEntries(categoryList.map(category => [category.key, category]));
294
288
 
295
- const ordered = instances.map(x => {
296
- const group = categoryMapping[x.category];
297
- const after = [...x.dependsOn ?? [], group.start];
298
- const before = [...x.runsBefore ?? [], group.end];
299
- return ({ key: x.constructor, before, after, target: x, placeholder: false });
289
+ const ordered = instances.map(category => {
290
+ const group = categoryMapping[category.category];
291
+ const after = [...category.dependsOn ?? [], group.start];
292
+ const before = [...category.runsBefore ?? [], group.end];
293
+ return ({ key: category.constructor, before, after, target: category, placeholder: false });
300
294
  });
301
295
 
302
296
  // Add category sets into the ordering
303
297
  let i = 0;
304
- for (const cat of cats) {
305
- const prevEnd = cats[i - 1]?.end ? [cats[i - 1].end] : [];
298
+ for (const cat of categoryList) {
299
+ const prevEnd = categoryList[i - 1]?.end ? [categoryList[i - 1].end] : [];
306
300
  ordered.push(
307
301
  { key: cat.start, before: [cat.end], after: prevEnd, placeholder: true, target: undefined! },
308
302
  { key: cat.end, before: [], after: [cat.start], placeholder: true, target: undefined! }
@@ -311,7 +305,7 @@ export class EndpointUtil {
311
305
  }
312
306
 
313
307
  return WebCommonUtil.ordered(ordered)
314
- .filter(x => !x.placeholder) // Drop out the placeholders
315
- .map(x => x.target);
308
+ .filter(category => !category.placeholder) // Drop out the placeholders
309
+ .map(category => category.target);
316
310
  }
317
311
  }