@eggjs/koa 2.21.0 → 2.22.1

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/src/context.ts CHANGED
@@ -1,10 +1,12 @@
1
1
  import util from 'node:util';
2
2
  import type { IncomingMessage, ServerResponse } from 'node:http';
3
- import { ParsedUrlQuery } from 'node:querystring';
3
+ import type { ParsedUrlQuery } from 'node:querystring';
4
+
4
5
  import createError from 'http-errors';
5
6
  import statuses from 'statuses';
6
7
  import Cookies from 'cookies';
7
- import { type Accepts } from 'accepts';
8
+ import type { Accepts } from 'accepts';
9
+
8
10
  import type { Application } from './application.js';
9
11
  import type { Request } from './request.js';
10
12
  import type { Response } from './response.js';
@@ -19,6 +21,7 @@ export class Context {
19
21
  response: Response & AnyProto;
20
22
  originalUrl: string;
21
23
  respond?: boolean;
24
+ // oxlint-disable-next-line typescript/no-explicit-any
22
25
  #state: Record<string, any> = {};
23
26
 
24
27
  constructor(app: Application, req: IncomingMessage, res: ServerResponse) {
@@ -26,10 +29,10 @@ export class Context {
26
29
  this.req = req;
27
30
  this.res = res;
28
31
  this.request = new app.RequestClass(app, this, req, res);
29
- this.response = new app.ResponseClass(app, this as any, req, res);
32
+ this.response = new app.ResponseClass(app, this, req, res);
30
33
  this.request.response = this.response;
31
34
  this.response.request = this.request;
32
- this.originalUrl = req.url!;
35
+ this.originalUrl = req.url ?? '/';
33
36
  }
34
37
 
35
38
  /**
@@ -74,15 +77,24 @@ export class Context {
74
77
  * ```ts
75
78
  * this.assert(this.user, 401, 'Please login!');
76
79
  * ```
77
- *
78
- * @param {Mixed} value
79
- * @param {Number} status
80
- * @param {String} errorMessage
81
- * @param {Object} errorProps
82
80
  */
83
- assert(value: any, status?: number, errorProps?: Record<string, any>): void;
84
- assert(value: any, status?: number, errorMessage?: string, errorProps?: Record<string, any>): void;
85
- assert(value: any, status?: number, errorMessageOrProps?: string | Record<string, any>, errorProps?: Record<string, any>) {
81
+ assert(
82
+ value: unknown,
83
+ status?: number,
84
+ errorProps?: Record<string, unknown>
85
+ ): void;
86
+ assert(
87
+ value: unknown,
88
+ status?: number,
89
+ errorMessage?: string,
90
+ errorProps?: Record<string, unknown>
91
+ ): void;
92
+ assert(
93
+ value: unknown,
94
+ status?: number,
95
+ errorMessageOrProps?: string | Record<string, unknown>,
96
+ errorProps?: Record<string, unknown>
97
+ ) {
86
98
  if (value) {
87
99
  return;
88
100
  }
@@ -131,7 +143,12 @@ export class Context {
131
143
  throw(error: Error, errorProps: object): void;
132
144
  throw(error: Error, status: number): void;
133
145
  throw(error: Error, status: number, errorProps: object): void;
134
- throw(arg1: number | string | Error, arg2?: number | string | Error | object, errorProps?: object) {
146
+ throw(
147
+ arg1: number | string | Error,
148
+ arg2?: number | string | Error | object,
149
+ errorProps?: object
150
+ ) {
151
+ // oxlint-disable-next-line typescript/no-explicit-any
135
152
  const args: any[] = [];
136
153
  if (typeof arg2 === 'number') {
137
154
  // throw(error, status)
@@ -163,7 +180,8 @@ export class Context {
163
180
  // When dealing with cross-globals a normal `instanceof` check doesn't work properly.
164
181
  // See https://github.com/koajs/koa/issues/1466
165
182
  // We can probably remove it once jest fixes https://github.com/facebook/jest/issues/2549.
166
- const isNativeError = err instanceof Error ||
183
+ const isNativeError =
184
+ err instanceof Error ||
167
185
  Object.prototype.toString.call(err) === '[object Error]';
168
186
  if (!isNativeError) {
169
187
  err = new Error(util.format('non-error thrown: %j', err));
@@ -171,7 +189,8 @@ export class Context {
171
189
 
172
190
  let headerSent = false;
173
191
  if (this.response.headerSent || !this.response.writable) {
174
- headerSent = (err as any).headerSent = true;
192
+ headerSent = true;
193
+ err.headerSent = true;
175
194
  }
176
195
 
177
196
  // delegate
@@ -187,10 +206,14 @@ export class Context {
187
206
  const { res } = this;
188
207
 
189
208
  // first unset all headers
190
- res.getHeaderNames().forEach(name => res.removeHeader(name));
209
+ for (const name of res.getHeaderNames()) {
210
+ res.removeHeader(name);
211
+ }
191
212
 
192
213
  // then set those specified
193
- if (err.headers) this.response.set(err.headers);
214
+ if (err.headers) {
215
+ this.response.set(err.headers);
216
+ }
194
217
 
195
218
  // force text/plain
196
219
  this.response.type = 'text';
@@ -198,15 +221,20 @@ export class Context {
198
221
  let statusCode = err.status || err.statusCode;
199
222
 
200
223
  // ENOENT support
201
- if (err.code === 'ENOENT') statusCode = 404;
224
+ if (err.code === 'ENOENT') {
225
+ statusCode = 404;
226
+ }
202
227
 
203
228
  // default to 500
204
- if (typeof statusCode !== 'number' || !statuses.message[statusCode]) statusCode = 500;
229
+ if (typeof statusCode !== 'number' || !statuses.message[statusCode]) {
230
+ statusCode = 500;
231
+ }
205
232
 
206
233
  // respond
207
234
  const statusMessage = statuses.message[statusCode] as string;
208
235
  const msg = err.expose ? err.message : statusMessage;
209
- this.response.status = err.status = statusCode;
236
+ err.status = statusCode;
237
+ this.response.status = statusCode;
210
238
  this.response.length = Buffer.byteLength(msg);
211
239
  res.end(msg);
212
240
  }
@@ -238,29 +266,43 @@ export class Context {
238
266
  acceptsLanguages(): string[];
239
267
  acceptsLanguages(languages: string[]): string | false;
240
268
  acceptsLanguages(...languages: string[]): string | false;
241
- acceptsLanguages(languages?: string | string[], ...others: string[]): string | string[] | false {
242
- return this.request.acceptsLanguages(languages as any, ...others);
269
+ acceptsLanguages(
270
+ languages?: string | string[],
271
+ ...others: string[]
272
+ ): string | string[] | false {
273
+ return this.request.acceptsLanguages(languages as string, ...others);
243
274
  }
244
275
 
245
276
  acceptsEncodings(): string[];
246
277
  acceptsEncodings(encodings: string[]): string | false;
247
278
  acceptsEncodings(...encodings: string[]): string | false;
248
- acceptsEncodings(encodings?: string | string[], ...others: string[]): string[] | string | false {
249
- return this.request.acceptsEncodings(encodings as any, ...others);
279
+ acceptsEncodings(
280
+ encodings?: string | string[],
281
+ ...others: string[]
282
+ ): string[] | string | false {
283
+ return this.request.acceptsEncodings(encodings as string, ...others);
250
284
  }
251
285
 
252
286
  acceptsCharsets(): string[];
253
287
  acceptsCharsets(charsets: string[]): string | false;
254
288
  acceptsCharsets(...charsets: string[]): string | false;
255
- acceptsCharsets(charsets?: string | string[], ...others: string[]): string[] | string | false {
256
- return this.request.acceptsCharsets(charsets as any, ...others);
289
+ acceptsCharsets(
290
+ charsets?: string | string[],
291
+ ...others: string[]
292
+ ): string[] | string | false {
293
+ return this.request.acceptsCharsets(charsets as string, ...others);
257
294
  }
258
295
 
259
- accepts(...args: Parameters<Request['accepts']>): string | string[] | false {
260
- return this.request.accepts(...args);
296
+ accepts(args: string[]): string | string[] | false;
297
+ accepts(...args: string[]): string | string[] | false;
298
+ accepts(
299
+ args?: string | string[],
300
+ ...others: string[]
301
+ ): string | string[] | false {
302
+ return this.request.accepts(args as string, ...others);
261
303
  }
262
304
 
263
- get<T = string | string []>(field: string): T {
305
+ get<T = string | string[]>(field: string): T {
264
306
  return this.request.get(field);
265
307
  }
266
308
 
@@ -440,10 +482,12 @@ export class Context {
440
482
  this.response.message = msg;
441
483
  }
442
484
 
485
+ // oxlint-disable-next-line typescript/no-explicit-any
443
486
  get body(): any {
444
487
  return this.response.body;
445
488
  }
446
489
 
490
+ // oxlint-disable-next-line typescript/no-explicit-any
447
491
  set body(val: any) {
448
492
  this.response.body = val;
449
493
  }
package/src/index.ts CHANGED
@@ -6,4 +6,4 @@ export * from './application.js';
6
6
  export * from './context.js';
7
7
  export * from './request.js';
8
8
  export * from './response.js';
9
- export * from './types.js';
9
+ export type { CustomError, AnyProto } from './types.js';
package/src/request.ts CHANGED
@@ -3,11 +3,13 @@ import { format as stringify } from 'node:url';
3
3
  import qs, { type ParsedUrlQuery } from 'node:querystring';
4
4
  import util from 'node:util';
5
5
  import type { IncomingMessage, ServerResponse } from 'node:http';
6
+
6
7
  import accepts, { type Accepts } from 'accepts';
7
8
  import contentType from 'content-type';
8
9
  import parse from 'parseurl';
9
10
  import typeis from 'type-is';
10
11
  import fresh from 'fresh';
12
+
11
13
  import type { Application } from './application.js';
12
14
  import type { Context } from './context.js';
13
15
  import type { Response } from './response.js';
@@ -25,12 +27,17 @@ export class Request {
25
27
  response: Response;
26
28
  originalUrl: string;
27
29
 
28
- constructor(app: Application, ctx: Context, req: IncomingMessage, res: ServerResponse) {
30
+ constructor(
31
+ app: Application,
32
+ ctx: Context,
33
+ req: IncomingMessage,
34
+ res: ServerResponse
35
+ ) {
29
36
  this.app = app;
30
37
  this.req = req;
31
38
  this.res = res;
32
39
  this.ctx = ctx;
33
- this.originalUrl = req.url!;
40
+ this.originalUrl = req.url ?? '/';
34
41
  }
35
42
 
36
43
  /**
@@ -70,7 +77,7 @@ export class Request {
70
77
  */
71
78
 
72
79
  get url() {
73
- return this.req.url!;
80
+ return this.req.url ?? '/';
74
81
  }
75
82
 
76
83
  /**
@@ -95,7 +102,9 @@ export class Request {
95
102
 
96
103
  get href() {
97
104
  // support: `GET http://example.com/foo`
98
- if (/^https?:\/\//i.test(this.originalUrl)) return this.originalUrl;
105
+ if (/^https?:\/\//i.test(this.originalUrl)) {
106
+ return this.originalUrl;
107
+ }
99
108
  return this.origin + this.originalUrl;
100
109
  }
101
110
 
@@ -104,34 +113,32 @@ export class Request {
104
113
  */
105
114
 
106
115
  get method() {
107
- return this.req.method!;
116
+ return this.req.method ?? 'GET';
108
117
  }
109
118
 
110
119
  /**
111
120
  * Set request method.
112
121
  */
113
-
114
- set method(val) {
122
+ set method(val: string) {
115
123
  this.req.method = val;
116
124
  }
117
125
 
118
126
  /**
119
127
  * Get request pathname.
120
128
  */
121
-
122
129
  get path() {
123
- return parse(this.req)!.pathname as string;
130
+ return parse(this.req)?.pathname ?? '';
124
131
  }
125
132
 
126
133
  /**
127
134
  * Set pathname, retaining the query string when present.
128
135
  */
136
+ set path(pathname: string) {
137
+ const url = parse(this.req);
138
+ if (!url) return;
139
+ if (url.pathname === pathname) return;
129
140
 
130
- set path(path) {
131
- const url = parse(this.req)!;
132
- if (url.pathname === path) return;
133
-
134
- url.pathname = path;
141
+ url.pathname = pathname;
135
142
  url.path = null;
136
143
 
137
144
  this.url = stringify(url);
@@ -149,7 +156,8 @@ export class Request {
149
156
  }
150
157
  let parsedUrlQuery = this._parsedUrlQueryCache[str];
151
158
  if (!parsedUrlQuery) {
152
- parsedUrlQuery = this._parsedUrlQueryCache[str] = qs.parse(str);
159
+ parsedUrlQuery = qs.parse(str);
160
+ this._parsedUrlQueryCache[str] = parsedUrlQuery;
153
161
  }
154
162
  return parsedUrlQuery;
155
163
  }
@@ -157,7 +165,6 @@ export class Request {
157
165
  /**
158
166
  * Set query string as an object.
159
167
  */
160
-
161
168
  set query(obj: ParsedUrlQuery) {
162
169
  this.querystring = qs.stringify(obj);
163
170
  }
@@ -165,18 +172,17 @@ export class Request {
165
172
  /**
166
173
  * Get query string.
167
174
  */
168
-
169
175
  get querystring() {
170
176
  if (!this.req) return '';
171
- return parse(this.req)!.query as string || '';
177
+ return (parse(this.req)?.query as string) ?? '';
172
178
  }
173
179
 
174
180
  /**
175
181
  * Set query string.
176
182
  */
177
-
178
- set querystring(str) {
179
- const url = parse(this.req)!;
183
+ set querystring(str: string) {
184
+ const url = parse(this.req);
185
+ if (!url) return;
180
186
  if (url.search === `?${str}`) return;
181
187
 
182
188
  url.search = str;
@@ -188,18 +194,17 @@ export class Request {
188
194
  * Get the search string. Same as the query string
189
195
  * except it includes the leading ?.
190
196
  */
191
-
192
197
  get search() {
193
- if (!this.querystring) return '';
194
- return `?${this.querystring}`;
198
+ const querystring = this.querystring;
199
+ if (!querystring) return '';
200
+ return `?${querystring}`;
195
201
  }
196
202
 
197
203
  /**
198
204
  * Set the search string. Same as
199
205
  * request.querystring= but included for ubiquity.
200
206
  */
201
-
202
- set search(str) {
207
+ set search(str: string) {
203
208
  this.querystring = str;
204
209
  }
205
210
 
@@ -257,7 +262,7 @@ export class Request {
257
262
  this._memoizedURL = Object.create(null);
258
263
  }
259
264
  }
260
- return this._memoizedURL!;
265
+ return this._memoizedURL as URL;
261
266
  }
262
267
 
263
268
  /**
@@ -295,7 +300,7 @@ export class Request {
295
300
  * Check if the request is idempotent.
296
301
  */
297
302
  get idempotent() {
298
- const methods = [ 'GET', 'HEAD', 'PUT', 'DELETE', 'OPTIONS', 'TRACE' ];
303
+ const methods = ['GET', 'HEAD', 'PUT', 'DELETE', 'OPTIONS', 'TRACE'];
299
304
  return methods.includes(this.method);
300
305
  }
301
306
 
@@ -326,7 +331,7 @@ export class Request {
326
331
  if (len === '') {
327
332
  return;
328
333
  }
329
- return parseInt(len);
334
+ return Number.parseInt(len);
330
335
  }
331
336
 
332
337
  /**
@@ -371,9 +376,7 @@ export class Request {
371
376
  get ips() {
372
377
  const proxy = this.app.proxy;
373
378
  const val = this.get<string>(this.app.proxyIpHeader);
374
- let ips = proxy && val
375
- ? splitCommaSeparatedValues(val)
376
- : [];
379
+ let ips = proxy && val ? splitCommaSeparatedValues(val) : [];
377
380
  if (this.app.maxIpsCount > 0) {
378
381
  ips = ips.slice(-this.app.maxIpsCount);
379
382
  }
@@ -413,10 +416,7 @@ export class Request {
413
416
  const offset = this.app.subdomainOffset;
414
417
  const hostname = this.hostname;
415
418
  if (net.isIP(hostname)) return [];
416
- return hostname
417
- .split('.')
418
- .reverse()
419
- .slice(offset);
419
+ return hostname.split('.').reverse().slice(offset);
420
420
  }
421
421
 
422
422
  protected _accept: Accepts;
@@ -471,8 +471,13 @@ export class Request {
471
471
  * this.accepts('html', 'json');
472
472
  * // => "json"
473
473
  */
474
- accepts(...args: any[]): string | string[] | false {
475
- return this.accept.types(...args);
474
+ accepts(args: string[]): string | string[] | false;
475
+ accepts(...args: string[]): string | string[] | false;
476
+ accepts(
477
+ args?: string | string[],
478
+ ...others: string[]
479
+ ): string | string[] | false {
480
+ return this.accept.types(args as string, ...others);
476
481
  }
477
482
 
478
483
  /**
@@ -486,14 +491,17 @@ export class Request {
486
491
  acceptsEncodings(): string[];
487
492
  acceptsEncodings(encodings: string[]): string | false;
488
493
  acceptsEncodings(...encodings: string[]): string | false;
489
- acceptsEncodings(encodings?: string | string[], ...others: string[]): string[] | string | false {
494
+ acceptsEncodings(
495
+ encodings?: string | string[],
496
+ ...others: string[]
497
+ ): string[] | string | false {
490
498
  if (!encodings) {
491
499
  return this.accept.encodings();
492
500
  }
493
501
  if (Array.isArray(encodings)) {
494
- encodings = [ ...encodings, ...others ];
502
+ encodings = [...encodings, ...others];
495
503
  } else {
496
- encodings = [ encodings, ...others ];
504
+ encodings = [encodings, ...others];
497
505
  }
498
506
  return this.accept.encodings(...encodings);
499
507
  }
@@ -509,14 +517,17 @@ export class Request {
509
517
  acceptsCharsets(): string[];
510
518
  acceptsCharsets(charsets: string[]): string | false;
511
519
  acceptsCharsets(...charsets: string[]): string | false;
512
- acceptsCharsets(charsets?: string | string[], ...others: string[]): string[] | string | false {
520
+ acceptsCharsets(
521
+ charsets?: string | string[],
522
+ ...others: string[]
523
+ ): string[] | string | false {
513
524
  if (!charsets) {
514
525
  return this.accept.charsets();
515
526
  }
516
527
  if (Array.isArray(charsets)) {
517
- charsets = [ ...charsets, ...others ];
528
+ charsets = [...charsets, ...others];
518
529
  } else {
519
- charsets = [ charsets, ...others ];
530
+ charsets = [charsets, ...others];
520
531
  }
521
532
  return this.accept.charsets(...charsets);
522
533
  }
@@ -532,14 +543,17 @@ export class Request {
532
543
  acceptsLanguages(): string[];
533
544
  acceptsLanguages(languages: string[]): string | false;
534
545
  acceptsLanguages(...languages: string[]): string | false;
535
- acceptsLanguages(languages?: string | string[], ...others: string[]): string | string[] | false {
546
+ acceptsLanguages(
547
+ languages?: string | string[],
548
+ ...others: string[]
549
+ ): string | string[] | false {
536
550
  if (!languages) {
537
551
  return this.accept.languages();
538
552
  }
539
553
  if (Array.isArray(languages)) {
540
- languages = [ ...languages, ...others ];
554
+ languages = [...languages, ...others];
541
555
  } else {
542
- languages = [ languages, ...others ];
556
+ languages = [languages, ...others];
543
557
  }
544
558
  return this.accept.languages(...languages);
545
559
  }
@@ -566,9 +580,11 @@ export class Request {
566
580
  * this.is('html'); // => false
567
581
  */
568
582
  is(type?: string | string[], ...types: string[]): string | false | null {
569
- const testTypes: string[] = Array.isArray(type) ? type :
570
- (type ? [ type ] : []);
571
- return typeis(this.req, [ ...testTypes, ...types ]);
583
+ let testTypes: string[] = [];
584
+ if (type) {
585
+ testTypes = Array.isArray(type) ? type : [type];
586
+ }
587
+ return typeis(this.req, [...testTypes, ...types]);
572
588
  }
573
589
 
574
590
  /**
@@ -598,9 +614,9 @@ export class Request {
598
614
  * this.get('Something');
599
615
  * // => ''
600
616
  */
601
- get<T = string | string []>(field: string): T {
617
+ get<T = string | string[]>(field: string): T {
602
618
  const req = this.req;
603
- switch (field = field.toLowerCase()) {
619
+ switch ((field = field.toLowerCase())) {
604
620
  case 'referer':
605
621
  case 'referrer':
606
622
  return (req.headers.referrer || req.headers.referer || '') as T;
@@ -642,8 +658,11 @@ export class Request {
642
658
  *
643
659
  * @param {string} value - The comma-separated value string to split.
644
660
  * @param {number} [limit] - The maximum number of values to return.
645
- * @return {string[]} An array of values from the comma-separated string.
661
+ * @returns {string[]} An array of values from the comma-separated string.
646
662
  */
647
663
  function splitCommaSeparatedValues(value: string, limit?: number): string[] {
648
- return value.split(',', limit).map(v => v.trim()).filter(v => v);
664
+ return value
665
+ .split(',', limit)
666
+ .map(v => v.trim())
667
+ .filter(v => v.length > 0);
649
668
  }