@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/response.ts CHANGED
@@ -3,7 +3,10 @@ import { extname } from 'node:path';
3
3
  import util from 'node:util';
4
4
  import Stream from 'node:stream';
5
5
  import type { IncomingMessage, ServerResponse } from 'node:http';
6
- import contentDisposition from 'content-disposition';
6
+
7
+ import contentDisposition, {
8
+ type Options as ContentDispositionOptions,
9
+ } from 'content-disposition';
7
10
  import { getType } from 'cache-content-type';
8
11
  import onFinish from 'on-finished';
9
12
  import escape from 'escape-html';
@@ -12,6 +15,7 @@ import statuses from 'statuses';
12
15
  import destroy from 'destroy';
13
16
  import vary from 'vary';
14
17
  import encodeUrl from 'encodeurl';
18
+
15
19
  import type { Application } from './application.js';
16
20
  import type { Context } from './context.js';
17
21
  import type { Request } from './request.js';
@@ -24,7 +28,12 @@ export class Response {
24
28
  ctx: Context;
25
29
  request: Request;
26
30
 
27
- constructor(app: Application, ctx: Context, req: IncomingMessage, res: ServerResponse) {
31
+ constructor(
32
+ app: Application,
33
+ ctx: Context,
34
+ req: IncomingMessage,
35
+ res: ServerResponse
36
+ ) {
28
37
  this.app = app;
29
38
  this.req = req;
30
39
  this.res = res;
@@ -70,17 +79,19 @@ export class Response {
70
79
  assert(code >= 100 && code <= 999, `invalid status code: ${code}`);
71
80
  this._explicitStatus = true;
72
81
  this.res.statusCode = code;
73
- if (this.req.httpVersionMajor < 2) {
74
- this.res.statusMessage = statuses.message[code]!;
82
+ if (this.req.httpVersionMajor < 2 && statuses.message[code]) {
83
+ this.res.statusMessage = statuses.message[code];
84
+ }
85
+ if (this.body && statuses.empty[code]) {
86
+ this.body = null;
75
87
  }
76
- if (this.body && statuses.empty[code]) this.body = null;
77
88
  }
78
89
 
79
90
  /**
80
91
  * Get response status message
81
92
  */
82
93
  get message(): string {
83
- return this.res.statusMessage || statuses.message[this.status]!;
94
+ return this.res.statusMessage ?? statuses.message[this.status];
84
95
  }
85
96
 
86
97
  /**
@@ -90,6 +101,7 @@ export class Response {
90
101
  this.res.statusMessage = msg;
91
102
  }
92
103
 
104
+ // oxlint-disable-next-line typescript/no-explicit-any
93
105
  _body: any;
94
106
  _explicitNullBody: boolean;
95
107
 
@@ -103,14 +115,20 @@ export class Response {
103
115
  /**
104
116
  * Set response body.
105
117
  */
106
- set body(val: string | Buffer | object | Stream | null | undefined | boolean) {
118
+ set body(
119
+ val: string | Buffer | object | Stream | null | undefined | boolean
120
+ ) {
107
121
  const original = this._body;
108
122
  this._body = val;
109
123
 
110
124
  // no content
111
- if (val == null) {
112
- if (!statuses.empty[this.status]) this.status = 204;
113
- if (val === null) this._explicitNullBody = true;
125
+ if (val === null || val === undefined) {
126
+ if (!statuses.empty[this.status]) {
127
+ this.status = 204;
128
+ }
129
+ if (val === null) {
130
+ this._explicitNullBody = true;
131
+ }
114
132
  this.remove('Content-Type');
115
133
  this.remove('Content-Length');
116
134
  this.remove('Transfer-Encoding');
@@ -140,14 +158,18 @@ export class Response {
140
158
  // stream
141
159
  if (val instanceof Stream) {
142
160
  onFinish(this.res, destroy.bind(null, val));
143
- // eslint-disable-next-line eqeqeq
161
+ // oxlint-disable-next-line eqeqeq
144
162
  if (original != val) {
145
163
  val.once('error', err => this.ctx.onerror(err));
146
164
  // overwriting
147
- if (original != null) this.remove('Content-Length');
165
+ if (original !== null && original !== undefined) {
166
+ this.remove('Content-Length');
167
+ }
148
168
  }
149
169
 
150
- if (setType) this.type = 'bin';
170
+ if (setType) {
171
+ this.type = 'bin';
172
+ }
151
173
  return;
152
174
  }
153
175
 
@@ -173,7 +195,7 @@ export class Response {
173
195
  */
174
196
  get length(): number | undefined {
175
197
  if (this.has('Content-Length')) {
176
- return parseInt(this.get('Content-Length'), 10) || 0;
198
+ return Number.parseInt(this.get('Content-Length')) || 0;
177
199
  }
178
200
 
179
201
  const { body } = this;
@@ -234,7 +256,7 @@ export class Response {
234
256
  if (this.ctx.accepts('html')) {
235
257
  url = escape(url);
236
258
  this.type = 'text/html; charset=utf-8';
237
- this.body = `Redirecting to <a href="${url}">${url}</a>.`;
259
+ this.body = `Redirecting to ${url}.`;
238
260
  return;
239
261
  }
240
262
 
@@ -246,7 +268,7 @@ export class Response {
246
268
  /**
247
269
  * Set Content-Disposition header to "attachment" with optional `filename`.
248
270
  */
249
- attachment(filename?: string, options?: any) {
271
+ attachment(filename?: string, options?: ContentDispositionOptions) {
250
272
  if (filename) this.type = extname(filename);
251
273
  this.set('Content-Disposition', contentDisposition(filename, options));
252
274
  }
@@ -292,9 +314,11 @@ export class Response {
292
314
  * this.response.is('html', 'json')
293
315
  */
294
316
  is(type?: string | string[], ...types: string[]): string | false {
295
- const testTypes: string[] = Array.isArray(type) ? type :
296
- (type ? [ type ] : []);
297
- return typeis(this.type as string, [ ...testTypes, ...types ]);
317
+ let testTypes: string[] = [];
318
+ if (type) {
319
+ testTypes = Array.isArray(type) ? type : [type];
320
+ }
321
+ return typeis(this.type, [...testTypes, ...types]);
298
322
  }
299
323
 
300
324
  /**
@@ -379,17 +403,21 @@ export class Response {
379
403
  * this.set('Accept', 'application/json');
380
404
  * this.set({ Accept: 'text/plain', 'X-API-Key': 'tobi' });
381
405
  */
382
- set(field: string | Record<string, string>, val?: string | number | any[]) {
406
+ set(
407
+ field: string | Record<string, string>,
408
+ val?: string | number | unknown[]
409
+ ) {
383
410
  if (this.headerSent) return;
384
411
  if (typeof field === 'string') {
412
+ let value = val as string | string[];
385
413
  if (Array.isArray(val)) {
386
- val = val.map(v => {
414
+ value = val.map(v => {
387
415
  return typeof v === 'string' ? v : String(v);
388
416
  });
389
417
  } else if (typeof val !== 'string') {
390
- val = String(val);
418
+ value = String(val);
391
419
  }
392
- this.res.setHeader(field, val);
420
+ this.res.setHeader(field, value);
393
421
  } else {
394
422
  for (const key in field) {
395
423
  this.set(key, field[key]);
@@ -408,13 +436,11 @@ export class Response {
408
436
  * this.append('Warning', '199 Miscellaneous warning');
409
437
  */
410
438
  append(field: string, val: string | string[]) {
411
- const prev = this.get(field);
439
+ const prev = this.get<string | string[]>(field);
412
440
 
413
- let value: any | any[] = val;
441
+ let value = val;
414
442
  if (prev) {
415
- value = Array.isArray(prev)
416
- ? prev.concat(value)
417
- : [ prev ].concat(val);
443
+ value = Array.isArray(prev) ? prev.concat(value) : [prev].concat(val);
418
444
  }
419
445
 
420
446
  return this.set(field, value);
package/src/types.ts CHANGED
@@ -4,8 +4,10 @@ export type CustomError = Error & {
4
4
  statusCode?: number;
5
5
  code?: string;
6
6
  expose?: boolean;
7
+ headerSent?: boolean;
7
8
  };
8
9
 
9
- export type AnyProto = {
10
+ export interface AnyProto {
11
+ // oxlint-disable-next-line typescript/no-explicit-any
10
12
  [key: string | symbol]: any;
11
- };
13
+ }