lieko-express 0.0.11 → 0.0.13
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/lieko-express.d.ts +135 -267
- package/lieko-express.js +69 -0
- package/package.json +1 -1
package/lieko-express.d.ts
CHANGED
|
@@ -1,293 +1,161 @@
|
|
|
1
|
-
declare
|
|
2
|
-
|
|
1
|
+
declare module "lieko-express" {
|
|
2
|
+
import { IncomingMessage, ServerResponse } from "http";
|
|
3
3
|
|
|
4
|
-
//
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
:
|
|
9
|
-
? { [k in Param]: string }
|
|
10
|
-
: Record<string, never>;
|
|
4
|
+
// -------------------------------
|
|
5
|
+
// Request Extensions
|
|
6
|
+
// -------------------------------
|
|
7
|
+
interface LiekoRequest extends IncomingMessage {
|
|
8
|
+
app: any;
|
|
11
9
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
10
|
+
// Passport fields
|
|
11
|
+
user?: any;
|
|
12
|
+
session?: any;
|
|
13
|
+
|
|
14
|
+
// Auth helpers
|
|
15
|
+
logout(callback?: (err: any) => void): Promise<void> | void;
|
|
16
|
+
|
|
17
|
+
// URL helpers
|
|
18
|
+
originalUrl: string;
|
|
19
|
+
params: Record<string, string>;
|
|
19
20
|
query: Record<string, any>;
|
|
20
|
-
params: Record<string, any>;
|
|
21
21
|
body: any;
|
|
22
22
|
files: Record<string, any>;
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
send(data: any): void;
|
|
34
|
-
text(data: string): void;
|
|
35
|
-
|
|
36
|
-
// headers helpers
|
|
37
|
-
setHeader(name: string, value: string | number): void;
|
|
38
|
-
set(name: string | Record<string, string | number>, value?: string | number): void;
|
|
39
|
-
header(name: string, value: string | number): void;
|
|
40
|
-
getHeader(name: string): string | number | string[] | undefined;
|
|
41
|
-
removeHeader(name: string): void;
|
|
42
|
-
headersSent?: boolean;
|
|
43
|
-
|
|
44
|
-
// redirect helpers
|
|
45
|
-
redirect(url: string): void;
|
|
46
|
-
redirect(status: number, url: string): void;
|
|
47
|
-
|
|
48
|
-
// streaming (optional)
|
|
49
|
-
write?(chunk: any): void;
|
|
50
|
-
end?(chunk?: any): void;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
// Extended Lieko Request and Response with framework helpers
|
|
54
|
-
interface Request<
|
|
55
|
-
Params extends Record<string, any> = Record<string, any>,
|
|
56
|
-
Query extends Record<string, any> = Record<string, any>,
|
|
57
|
-
Body = any
|
|
58
|
-
> extends RequestBase {
|
|
59
|
-
params: Params;
|
|
60
|
-
query: Query;
|
|
61
|
-
body: Body;
|
|
62
|
-
files: Record<string, {
|
|
63
|
-
filename: string;
|
|
64
|
-
tempFilePath?: string;
|
|
65
|
-
data?: Buffer;
|
|
66
|
-
contentType?: string;
|
|
67
|
-
size?: number;
|
|
68
|
-
}>;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
interface Response extends ResponseBase {
|
|
72
|
-
// Rich helpers provided by Lieko
|
|
73
|
-
ok(data?: any, message?: string): void;
|
|
74
|
-
success: (data?: any, message?: string) => void;
|
|
75
|
-
created(data?: any, message?: string): void;
|
|
76
|
-
noContent(): void;
|
|
77
|
-
accepted(data?: any, message?: string): void;
|
|
78
|
-
|
|
79
|
-
badRequest(message?: string, details?: any): void;
|
|
80
|
-
unauthorized(message?: string, details?: any): void;
|
|
81
|
-
forbidden(message?: string, details?: any): void;
|
|
82
|
-
notFound(message?: string, details?: any): void;
|
|
83
|
-
error(message?: string, status?: number, details?: any): void;
|
|
84
|
-
fail: (message?: string, status?: number, details?: any) => void;
|
|
85
|
-
serverError(message?: string, details?: any): void;
|
|
86
|
-
|
|
87
|
-
// convenience helpers sometimes provided
|
|
88
|
-
paginated?(items: any[], total: number, message?: string): void;
|
|
89
|
-
html?(html: string, status?: number): void;
|
|
90
|
-
|
|
91
|
-
// short alias
|
|
92
|
-
statusCode?: number;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
// -------------- Handler / Middleware --------------
|
|
96
|
-
type Handler<
|
|
97
|
-
Params extends Record<string, any> = Record<string, any>,
|
|
98
|
-
Query extends Record<string, any> = Record<string, any>,
|
|
99
|
-
Body = any
|
|
100
|
-
> = (req: Request<Params, Query, Body>, res: Response, next?: (err?: any) => void) => any | Promise<any>;
|
|
101
|
-
|
|
102
|
-
// -------------- CORS / BodyParser options --------------
|
|
103
|
-
interface CorsOptions {
|
|
104
|
-
enabled?: boolean;
|
|
105
|
-
origin?: "*" | string | string[]; // supports wildcard like https://*.example.com
|
|
106
|
-
methods?: string[]; // allowed methods
|
|
107
|
-
headers?: string[]; // allowed headers
|
|
108
|
-
exposedHeaders?: string[];
|
|
109
|
-
credentials?: boolean;
|
|
110
|
-
maxAge?: number;
|
|
111
|
-
debug?: boolean;
|
|
112
|
-
strictOrigin?: boolean; // 403 if origin not allowed
|
|
113
|
-
allowPrivateNetwork?: boolean; // Access-Control-Allow-Private-Network
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
interface JsonBodyOptions {
|
|
117
|
-
limit?: string; // e.g. "10mb"
|
|
118
|
-
strict?: boolean;
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
interface UrlencodedOptions {
|
|
122
|
-
limit?: string;
|
|
123
|
-
extended?: boolean;
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
interface MultipartOptions {
|
|
127
|
-
limit?: string;
|
|
128
|
-
tempDir?: string;
|
|
129
|
-
}
|
|
23
|
+
xhr: boolean;
|
|
24
|
+
|
|
25
|
+
// IP helpers
|
|
26
|
+
ip: {
|
|
27
|
+
raw: string | null;
|
|
28
|
+
ipv4: string | null;
|
|
29
|
+
ipv6: string | null;
|
|
30
|
+
display: string;
|
|
31
|
+
};
|
|
32
|
+
ips: string[];
|
|
130
33
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
}
|
|
34
|
+
protocol: string;
|
|
35
|
+
secure: boolean;
|
|
36
|
+
hostname: string;
|
|
37
|
+
subdomains: string[];
|
|
136
38
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
type ValidatorFn = (value: any, field: string, data: any) => { field: string; message: string; type: string } | null;
|
|
39
|
+
get(name: string): string | undefined;
|
|
40
|
+
header(name: string): string | undefined;
|
|
140
41
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
string(message?: string): ValidatorFn;
|
|
146
|
-
number(message?: string): ValidatorFn;
|
|
147
|
-
boolean(message?: string): ValidatorFn;
|
|
148
|
-
integer(message?: string): ValidatorFn;
|
|
149
|
-
positive(message?: string): ValidatorFn;
|
|
150
|
-
negative(message?: string): ValidatorFn;
|
|
151
|
-
email(message?: string): ValidatorFn;
|
|
152
|
-
min(minValue: number, message?: string): ValidatorFn;
|
|
153
|
-
max(maxValue: number, message?: string): ValidatorFn;
|
|
154
|
-
length(n: number, message?: string): ValidatorFn;
|
|
155
|
-
minLength(minLength: number, message?: string): ValidatorFn;
|
|
156
|
-
maxLength(maxLength: number, message?: string): ValidatorFn;
|
|
157
|
-
pattern(regex: RegExp, message?: string): ValidatorFn;
|
|
158
|
-
oneOf(allowedValues: any[], message?: string): ValidatorFn;
|
|
159
|
-
notOneOf(values: any[], message?: string): ValidatorFn;
|
|
160
|
-
custom(validatorFn: (value: any, data: any) => boolean, message?: string): ValidatorFn;
|
|
161
|
-
equal(expectedValue: any, message?: string): ValidatorFn;
|
|
162
|
-
mustBeTrue(message?: string): ValidatorFn;
|
|
163
|
-
mustBeFalse(message?: string): ValidatorFn;
|
|
164
|
-
date(message?: string): ValidatorFn;
|
|
165
|
-
before(limit: string | Date, message?: string): ValidatorFn;
|
|
166
|
-
after(limit: string | Date, message?: string): ValidatorFn;
|
|
167
|
-
startsWith(prefix: string, message?: string): ValidatorFn;
|
|
168
|
-
endsWith(suffix: string, message?: string): ValidatorFn;
|
|
169
|
-
}
|
|
42
|
+
accepts(types: string | string[]): string | false;
|
|
43
|
+
acceptsLanguages(langs: string | string[]): string | false;
|
|
44
|
+
acceptsCharsets(charsets: string | string[]): string | false;
|
|
45
|
+
acceptsEncodings(enc: string | string[]): string | false;
|
|
170
46
|
|
|
171
|
-
|
|
172
|
-
constructor(rules: Record<string, ValidatorFn[]>);
|
|
173
|
-
rules: Record<string, ValidatorFn[]>;
|
|
174
|
-
fields: Record<string, ValidatorFn[]>;
|
|
175
|
-
validate(data: Record<string, any>): true | never;
|
|
47
|
+
is(type: string): boolean;
|
|
176
48
|
}
|
|
177
49
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
50
|
+
// -------------------------------
|
|
51
|
+
// Response Extensions
|
|
52
|
+
// -------------------------------
|
|
53
|
+
interface LiekoResponse extends ServerResponse {
|
|
54
|
+
app: any;
|
|
55
|
+
locals: Record<string, any>;
|
|
181
56
|
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
): this;
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
57
|
+
status(code: number): this;
|
|
58
|
+
set(name: string, value: string): this;
|
|
59
|
+
header(name: string, value: string): this;
|
|
60
|
+
type(mime: string): this;
|
|
61
|
+
|
|
62
|
+
json(data: any): this;
|
|
63
|
+
send(data: any): this;
|
|
64
|
+
html(html: string, status?: number): this;
|
|
65
|
+
|
|
66
|
+
redirect(url: string, status?: number): this;
|
|
67
|
+
|
|
68
|
+
ok(data: any, message?: string): this;
|
|
69
|
+
success(data: any, message?: string): this;
|
|
70
|
+
created(data: any, message?: string): this;
|
|
71
|
+
noContent(): this;
|
|
72
|
+
accepted(data?: any, message?: string): this;
|
|
73
|
+
paginated(items: any[], total: number, message?: string): this;
|
|
74
|
+
|
|
75
|
+
// Cookie helpers
|
|
76
|
+
cookie(
|
|
77
|
+
name: string,
|
|
78
|
+
value: string,
|
|
79
|
+
options?: {
|
|
80
|
+
path?: string;
|
|
81
|
+
httpOnly?: boolean;
|
|
82
|
+
secure?: boolean;
|
|
83
|
+
sameSite?: "lax" | "strict" | "none";
|
|
84
|
+
maxAge?: number;
|
|
85
|
+
expires?: Date;
|
|
86
|
+
domain?: string;
|
|
87
|
+
}
|
|
208
88
|
): this;
|
|
209
89
|
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
90
|
+
clearCookie(
|
|
91
|
+
name: string,
|
|
92
|
+
options?: {
|
|
93
|
+
path?: string;
|
|
94
|
+
httpOnly?: boolean;
|
|
95
|
+
secure?: boolean;
|
|
96
|
+
sameSite?: "lax" | "strict" | "none";
|
|
97
|
+
}
|
|
213
98
|
): this;
|
|
214
99
|
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
): this;
|
|
100
|
+
error(obj: any): this;
|
|
101
|
+
fail(obj: any): this;
|
|
102
|
+
badRequest(msg?: string): this;
|
|
103
|
+
unauthorized(msg?: string): this;
|
|
104
|
+
forbidden(msg?: string): this;
|
|
105
|
+
notFound(msg?: string): this;
|
|
106
|
+
serverError(msg?: string): this;
|
|
107
|
+
}
|
|
219
108
|
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
109
|
+
// -------------------------------
|
|
110
|
+
// Handler Types
|
|
111
|
+
// -------------------------------
|
|
112
|
+
type LiekoHandler = (
|
|
113
|
+
req: LiekoRequest,
|
|
114
|
+
res: LiekoResponse,
|
|
115
|
+
next: (err?: any) => void
|
|
116
|
+
) => any;
|
|
117
|
+
|
|
118
|
+
type LiekoErrorHandler = (
|
|
119
|
+
err: any,
|
|
120
|
+
req: LiekoRequest,
|
|
121
|
+
res: LiekoResponse,
|
|
122
|
+
next: (err?: any) => void
|
|
123
|
+
) => any;
|
|
124
|
+
|
|
125
|
+
// -------------------------------
|
|
126
|
+
// Router / App Class
|
|
127
|
+
// -------------------------------
|
|
128
|
+
class LiekoExpress {
|
|
129
|
+
constructor();
|
|
130
|
+
|
|
131
|
+
get(path: string, ...handlers: LiekoHandler[]): this;
|
|
132
|
+
post(path: string, ...handlers: LiekoHandler[]): this;
|
|
133
|
+
put(path: string, ...handlers: LiekoHandler[]): this;
|
|
134
|
+
patch(path: string, ...handlers: LiekoHandler[]): this;
|
|
135
|
+
delete(path: string, ...handlers: LiekoHandler[]): this;
|
|
136
|
+
all(path: string, ...handlers: LiekoHandler[]): this;
|
|
137
|
+
|
|
138
|
+
use(mw: LiekoHandler): this;
|
|
139
|
+
use(path: string, mw: LiekoHandler): this;
|
|
140
|
+
use(path: string, router: LiekoExpress): this;
|
|
141
|
+
use(path: string, mw: LiekoHandler, router: LiekoExpress): this;
|
|
142
|
+
|
|
143
|
+
group(
|
|
144
|
+
basePath: string,
|
|
145
|
+
...middlewares: LiekoHandler[]
|
|
223
146
|
): this;
|
|
224
147
|
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
use(path: string, handler: Handler | App): this;
|
|
148
|
+
errorHandler(handler: LiekoErrorHandler): this;
|
|
149
|
+
notFound(handler: LiekoHandler): this;
|
|
228
150
|
|
|
229
|
-
|
|
230
|
-
|
|
151
|
+
set(name: string, value: any): this;
|
|
152
|
+
get(setting: string): any;
|
|
231
153
|
|
|
232
|
-
// CORS
|
|
233
|
-
cors(options?: Partial<CorsOptions>): Handler;
|
|
234
|
-
|
|
235
|
-
// body parser
|
|
236
|
-
bodyParser: {
|
|
237
|
-
json(options?: JsonBodyOptions): Handler;
|
|
238
|
-
urlencoded(options?: UrlencodedOptions): Handler;
|
|
239
|
-
multipart(options?: MultipartOptions): Handler;
|
|
240
|
-
};
|
|
241
|
-
|
|
242
|
-
// static files
|
|
243
|
-
static(root: string, options?: { maxAge?: number; index?: string }): Handler;
|
|
244
|
-
|
|
245
|
-
// error handler
|
|
246
|
-
error(res: Response, obj: any): void;
|
|
247
|
-
|
|
248
|
-
// settings
|
|
249
|
-
set(key: string, value: any): this;
|
|
250
|
-
get(key: string): any;
|
|
251
|
-
|
|
252
|
-
// debug
|
|
253
|
-
debug(value?: boolean | string): this;
|
|
254
|
-
|
|
255
|
-
// utilities
|
|
256
|
-
listRoutes(): { method: string; path: string | string[]; middlewares: number }[];
|
|
257
|
-
printRoutes(): void;
|
|
258
|
-
|
|
259
|
-
// server control
|
|
260
154
|
listen(port: number, host?: string, callback?: () => void): any;
|
|
261
|
-
listen(...args: any[]): any;
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
// -------------- Factory / Constructor --------------
|
|
265
|
-
interface ConstructorOptions {
|
|
266
|
-
// initial options
|
|
267
|
-
cors?: Partial<CorsOptions>;
|
|
268
|
-
bodyParser?: Partial<BodyParserOptions>;
|
|
269
|
-
trustProxy?: boolean | string | string[];
|
|
270
|
-
debug?: boolean;
|
|
271
|
-
allowTrailingSlash?: boolean;
|
|
272
|
-
strictTrailingSlash?: boolean;
|
|
273
|
-
// other global options
|
|
274
|
-
[key: string]: any;
|
|
275
155
|
}
|
|
276
156
|
|
|
277
|
-
|
|
278
|
-
|
|
157
|
+
function Lieko(): LiekoExpress;
|
|
158
|
+
function Router(): LiekoExpress;
|
|
279
159
|
|
|
280
|
-
|
|
281
|
-
Router: () => App;
|
|
282
|
-
Schema: typeof Schema;
|
|
283
|
-
schema: (...args: any[]) => Schema;
|
|
284
|
-
validators: Validators;
|
|
285
|
-
validate: typeof validate;
|
|
286
|
-
validatePartial: (schema: Schema) => Handler;
|
|
287
|
-
ValidationError: typeof ValidationError;
|
|
288
|
-
static: (root: string, options?: { maxAge?: number; index?: string }) => Handler;
|
|
289
|
-
}
|
|
160
|
+
export = Lieko;
|
|
290
161
|
}
|
|
291
|
-
|
|
292
|
-
declare const Lieko: Lieko.LiekoStatic;
|
|
293
|
-
export = Lieko;
|
package/lieko-express.js
CHANGED
|
@@ -1105,6 +1105,7 @@ ${cyan} (req, res, next) => {
|
|
|
1105
1105
|
}
|
|
1106
1106
|
|
|
1107
1107
|
req.originalUrl = req.url;
|
|
1108
|
+
req.path = req.url.split('?')[0];
|
|
1108
1109
|
req.xhr = (req.headers['x-requested-with'] || '').toLowerCase() === 'xmlhttprequest';
|
|
1109
1110
|
|
|
1110
1111
|
req.get = (name) => {
|
|
@@ -1200,6 +1201,26 @@ ${cyan} (req, res, next) => {
|
|
|
1200
1201
|
if (t === 'multipart') return ct.includes('multipart');
|
|
1201
1202
|
return false;
|
|
1202
1203
|
};
|
|
1204
|
+
|
|
1205
|
+
/**
|
|
1206
|
+
* Passport-compatible logout (Passport 0.6+ / 0.7)
|
|
1207
|
+
* This ensures logout(cb) always calls cb(null) and never overwrites Express res
|
|
1208
|
+
*/
|
|
1209
|
+
req.logout = function logout(callback) {
|
|
1210
|
+
req.user = null;
|
|
1211
|
+
|
|
1212
|
+
// Remove passport session field if it exists
|
|
1213
|
+
if (req.session && req.session.passport) {
|
|
1214
|
+
delete req.session.passport;
|
|
1215
|
+
}
|
|
1216
|
+
|
|
1217
|
+
// Passport v0.6+ expects async logout
|
|
1218
|
+
if (typeof callback === "function") {
|
|
1219
|
+
return callback(null);
|
|
1220
|
+
}
|
|
1221
|
+
|
|
1222
|
+
return Promise.resolve();
|
|
1223
|
+
};
|
|
1203
1224
|
}
|
|
1204
1225
|
|
|
1205
1226
|
_enhanceResponse(req, res) {
|
|
@@ -1478,6 +1499,54 @@ ${cyan} (req, res, next) => {
|
|
|
1478
1499
|
return res.status(500).error(msg);
|
|
1479
1500
|
};
|
|
1480
1501
|
|
|
1502
|
+
res.cookie = (name, value, options = {}) => {
|
|
1503
|
+
const opts = {
|
|
1504
|
+
path: '/',
|
|
1505
|
+
httpOnly: true,
|
|
1506
|
+
secure: req.secure || false,
|
|
1507
|
+
sameSite: 'lax',
|
|
1508
|
+
maxAge: null,
|
|
1509
|
+
expires: null,
|
|
1510
|
+
...options
|
|
1511
|
+
};
|
|
1512
|
+
|
|
1513
|
+
let cookie = `${name}=${encodeURIComponent(value)}`;
|
|
1514
|
+
|
|
1515
|
+
if (opts.maxAge) cookie += `; Max-Age=${Math.floor(opts.maxAge / 1000)}`;
|
|
1516
|
+
if (opts.expires) cookie += `; Expires=${opts.expires.toUTCString()}`;
|
|
1517
|
+
cookie += `; Path=${opts.path}`;
|
|
1518
|
+
if (opts.domain) cookie += `; Domain=${opts.domain}`;
|
|
1519
|
+
if (opts.httpOnly) cookie += '; HttpOnly';
|
|
1520
|
+
if (opts.secure) cookie += '; Secure';
|
|
1521
|
+
if (opts.sameSite) cookie += `; SameSite=${opts.sameSite}`;
|
|
1522
|
+
|
|
1523
|
+
res.setHeader('Set-Cookie', cookie);
|
|
1524
|
+
return res;
|
|
1525
|
+
};
|
|
1526
|
+
|
|
1527
|
+
res.clearCookie = (name, options = {}) => {
|
|
1528
|
+
if (responseSent) return res;
|
|
1529
|
+
|
|
1530
|
+
const opts = {
|
|
1531
|
+
path: '/',
|
|
1532
|
+
httpOnly: true,
|
|
1533
|
+
secure: req.secure || false,
|
|
1534
|
+
sameSite: 'lax',
|
|
1535
|
+
...options
|
|
1536
|
+
};
|
|
1537
|
+
|
|
1538
|
+
const cookieValue = `${name}=; Max-Age=0; Expires=${new Date(0).toUTCString()}; Path=${opts.path}`;
|
|
1539
|
+
|
|
1540
|
+
let header = cookieValue;
|
|
1541
|
+
|
|
1542
|
+
if (opts.httpOnly) header += '; HttpOnly';
|
|
1543
|
+
if (opts.secure) header += '; Secure';
|
|
1544
|
+
if (opts.sameSite && opts.sameSite !== 'none') header += `; SameSite=${opts.sameSite}`;
|
|
1545
|
+
|
|
1546
|
+
res.setHeader('Set-Cookie', header);
|
|
1547
|
+
return res;
|
|
1548
|
+
};
|
|
1549
|
+
|
|
1481
1550
|
const originalEnd = res.end.bind(res);
|
|
1482
1551
|
|
|
1483
1552
|
res.end = (...args) => {
|