@eggjs/koa 2.21.0 → 2.22.0
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/Readme.md +8 -8
- package/dist/commonjs/application.d.ts +12 -12
- package/dist/commonjs/application.js +60 -22
- package/dist/commonjs/context.d.ts +6 -10
- package/dist/commonjs/context.js +21 -10
- package/dist/commonjs/index.d.ts +1 -1
- package/dist/commonjs/index.js +1 -2
- package/dist/commonjs/request.d.ts +3 -2
- package/dist/commonjs/request.js +35 -64
- package/dist/commonjs/response.d.ts +3 -2
- package/dist/commonjs/response.js +26 -19
- package/dist/commonjs/types.d.ts +3 -2
- package/dist/esm/application.d.ts +12 -12
- package/dist/esm/application.js +25 -20
- package/dist/esm/context.d.ts +6 -10
- package/dist/esm/context.js +21 -10
- package/dist/esm/index.d.ts +1 -1
- package/dist/esm/index.js +1 -2
- package/dist/esm/request.d.ts +3 -2
- package/dist/esm/request.js +35 -64
- package/dist/esm/response.d.ts +3 -2
- package/dist/esm/response.js +26 -19
- package/dist/esm/types.d.ts +3 -2
- package/dist/package.json +1 -1
- package/package.json +18 -8
- package/src/application.ts +48 -30
- package/src/context.ts +73 -29
- package/src/index.ts +1 -1
- package/src/request.ts +73 -54
- package/src/response.ts +53 -27
- package/src/types.ts +4 -2
package/src/index.ts
CHANGED
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(
|
|
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))
|
|
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)
|
|
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
|
-
|
|
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 =
|
|
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)
|
|
177
|
+
return (parse(this.req)?.query as string) ?? '';
|
|
172
178
|
}
|
|
173
179
|
|
|
174
180
|
/**
|
|
175
181
|
* Set query string.
|
|
176
182
|
*/
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
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
|
-
|
|
194
|
-
return
|
|
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 = [
|
|
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(
|
|
475
|
-
|
|
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(
|
|
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 = [
|
|
502
|
+
encodings = [...encodings, ...others];
|
|
495
503
|
} else {
|
|
496
|
-
encodings = [
|
|
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(
|
|
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 = [
|
|
528
|
+
charsets = [...charsets, ...others];
|
|
518
529
|
} else {
|
|
519
|
-
charsets = [
|
|
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(
|
|
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 = [
|
|
554
|
+
languages = [...languages, ...others];
|
|
541
555
|
} else {
|
|
542
|
-
languages = [
|
|
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
|
-
|
|
570
|
-
|
|
571
|
-
|
|
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
|
|
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
|
-
* @
|
|
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
|
|
664
|
+
return value
|
|
665
|
+
.split(',', limit)
|
|
666
|
+
.map(v => v.trim())
|
|
667
|
+
.filter(v => v.length > 0);
|
|
649
668
|
}
|
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
|
-
|
|
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(
|
|
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
|
|
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(
|
|
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
|
|
112
|
-
if (!statuses.empty[this.status])
|
|
113
|
-
|
|
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
|
-
//
|
|
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
|
|
165
|
+
if (original !== null && original !== undefined) {
|
|
166
|
+
this.remove('Content-Length');
|
|
167
|
+
}
|
|
148
168
|
}
|
|
149
169
|
|
|
150
|
-
if (setType)
|
|
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')
|
|
198
|
+
return Number.parseInt(this.get('Content-Length')) || 0;
|
|
177
199
|
}
|
|
178
200
|
|
|
179
201
|
const { body } = this;
|
|
@@ -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?:
|
|
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
|
-
|
|
296
|
-
|
|
297
|
-
|
|
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(
|
|
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
|
-
|
|
414
|
+
value = val.map(v => {
|
|
387
415
|
return typeof v === 'string' ? v : String(v);
|
|
388
416
|
});
|
|
389
417
|
} else if (typeof val !== 'string') {
|
|
390
|
-
|
|
418
|
+
value = String(val);
|
|
391
419
|
}
|
|
392
|
-
this.res.setHeader(field,
|
|
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
|
|
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
|
|
10
|
+
export interface AnyProto {
|
|
11
|
+
// oxlint-disable-next-line typescript/no-explicit-any
|
|
10
12
|
[key: string | symbol]: any;
|
|
11
|
-
}
|
|
13
|
+
}
|