Skip to content

Commit 3d0821f

Browse files
authored
Merge pull request #20 from Netail/feat/typescript-generics
feat: typescript generics
2 parents c6f1fcb + 5659027 commit 3d0821f

File tree

2 files changed

+91
-74
lines changed

2 files changed

+91
-74
lines changed

lib/http-proxy/index.ts

Lines changed: 88 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -99,128 +99,128 @@ export interface NormalizedServerOptions extends ServerOptions {
9999
forward?: NormalizeProxyTarget<ProxyTargetUrl>;
100100
}
101101

102-
export type ErrorCallback =
102+
export type ErrorCallback<TIncomingMessage extends typeof http.IncomingMessage = typeof http.IncomingMessage, TServerResponse extends typeof http.ServerResponse = typeof http.ServerResponse, TError = Error> =
103103
(
104-
err: Error,
105-
req: http.IncomingMessage,
106-
res: http.ServerResponse | net.Socket,
104+
err: TError,
105+
req: InstanceType<TIncomingMessage>,
106+
res: InstanceType<TServerResponse> | net.Socket,
107107
target?: ProxyTargetUrl,
108108
) => void;
109109

110-
type ProxyServerEventMap = {
111-
error: Parameters<ErrorCallback>;
110+
type ProxyServerEventMap<TIncomingMessage extends typeof http.IncomingMessage = typeof http.IncomingMessage, TServerResponse extends typeof http.ServerResponse = typeof http.ServerResponse, TError = Error> = {
111+
error: Parameters<ErrorCallback<TIncomingMessage, TServerResponse, TError>>;
112112
start: [
113-
req: http.IncomingMessage,
114-
res: http.ServerResponse,
113+
req: InstanceType<TIncomingMessage>,
114+
res: InstanceType<TServerResponse>,
115115
target: ProxyTargetUrl,
116116
];
117117
open: [socket: net.Socket];
118118
proxyReq: [
119119
proxyReq: http.ClientRequest,
120-
req: http.IncomingMessage,
121-
res: http.ServerResponse,
120+
req: InstanceType<TIncomingMessage>,
121+
res: InstanceType<TServerResponse>,
122122
options: ServerOptions,
123123
socket: net.Socket,
124124
];
125125
proxyRes: [
126-
proxyRes: http.IncomingMessage,
127-
req: http.IncomingMessage,
128-
res: http.ServerResponse,
126+
proxyRes: InstanceType<TIncomingMessage>,
127+
req: InstanceType<TIncomingMessage>,
128+
res: InstanceType<TServerResponse>,
129129
];
130130
proxyReqWs: [
131131
proxyReq: http.ClientRequest,
132-
req: http.IncomingMessage,
132+
req: InstanceType<TIncomingMessage>,
133133
socket: net.Socket,
134134
options: ServerOptions,
135135
head: any,
136136
];
137137
econnreset: [
138138
err: Error,
139-
req: http.IncomingMessage,
140-
res: http.ServerResponse,
139+
req: InstanceType<TIncomingMessage>,
140+
res: InstanceType<TServerResponse>,
141141
target: ProxyTargetUrl,
142142
];
143143
end: [
144-
req: http.IncomingMessage,
145-
res: http.ServerResponse,
146-
proxyRes: http.IncomingMessage,
144+
req: InstanceType<TIncomingMessage>,
145+
res: InstanceType<TServerResponse>,
146+
proxyRes: InstanceType<TIncomingMessage>,
147147
];
148148
close: [
149-
proxyRes: http.IncomingMessage,
149+
proxyRes: InstanceType<TIncomingMessage>,
150150
proxySocket: net.Socket,
151151
proxyHead: any,
152152
];
153153
}
154154

155-
type ProxyMethodArgs = {
155+
type ProxyMethodArgs<TIncomingMessage extends typeof http.IncomingMessage = typeof http.IncomingMessage, TServerResponse extends typeof http.ServerResponse = typeof http.ServerResponse, TError = Error> = {
156156
ws: [
157-
req: http.IncomingMessage,
157+
req: InstanceType<TIncomingMessage>,
158158
socket: any,
159159
head: any,
160160
...args:
161-
[
162-
options?: ServerOptions,
163-
callback?: ErrorCallback,
164-
]
161+
[
162+
options?: ServerOptions,
163+
callback?: ErrorCallback<TIncomingMessage, TServerResponse, TError>,
164+
]
165165
| [
166-
callback?: ErrorCallback,
167-
]
166+
callback?: ErrorCallback<TIncomingMessage, TServerResponse, TError>,
167+
]
168168
]
169169
web: [
170-
req: http.IncomingMessage,
171-
res: http.ServerResponse,
170+
req: InstanceType<TIncomingMessage>,
171+
res: InstanceType<TServerResponse>,
172172
...args:
173-
[
174-
options: ServerOptions,
175-
callback?: ErrorCallback,
176-
]
177-
| [
178-
callback?: ErrorCallback
179-
]
173+
[
174+
options: ServerOptions,
175+
callback?: ErrorCallback<TIncomingMessage, TServerResponse, TError>,
176+
]
177+
| [
178+
callback?: ErrorCallback<TIncomingMessage, TServerResponse, TError>
179+
]
180180
]
181181
}
182182

183-
type PassFunctions = {
183+
type PassFunctions<TIncomingMessage extends typeof http.IncomingMessage = typeof http.IncomingMessage, TServerResponse extends typeof http.ServerResponse = typeof http.ServerResponse, TError = Error> = {
184184
ws: (
185-
req: http.IncomingMessage,
185+
req: InstanceType<TIncomingMessage>,
186186
socket: net.Socket,
187187
options: NormalizedServerOptions,
188188
head: Buffer | undefined,
189-
server: ProxyServer,
190-
cb?: ErrorCallback
189+
server: ProxyServer<TIncomingMessage, TServerResponse, TError>,
190+
cb?: ErrorCallback<TIncomingMessage, TServerResponse, TError>
191191
) => unknown
192192
web: (
193-
req: http.IncomingMessage,
194-
res: http.ServerResponse,
193+
req: InstanceType<TIncomingMessage>,
194+
res: InstanceType<TServerResponse>,
195195
options: NormalizedServerOptions,
196196
head: Buffer | undefined,
197-
server: ProxyServer,
198-
cb?: ErrorCallback
197+
server: ProxyServer<TIncomingMessage, TServerResponse, TError>,
198+
cb?: ErrorCallback<TIncomingMessage, TServerResponse, TError>
199199
) => unknown
200200
}
201201

202-
export class ProxyServer extends EventEmitter<ProxyServerEventMap> {
202+
export class ProxyServer<TIncomingMessage extends typeof http.IncomingMessage = typeof http.IncomingMessage, TServerResponse extends typeof http.ServerResponse = typeof http.ServerResponse, TError = Error> extends EventEmitter<ProxyServerEventMap<TIncomingMessage, TServerResponse, TError>> {
203203
/**
204204
* Used for proxying WS(S) requests
205205
* @param req - Client request.
206206
* @param socket - Client socket.
207207
* @param head - Client head.
208208
* @param options - Additional options.
209209
*/
210-
public readonly ws: (...args: ProxyMethodArgs["ws"]) => void;
210+
public readonly ws: (...args: ProxyMethodArgs<TIncomingMessage, TServerResponse, TError>["ws"]) => void;
211211

212212
/**
213213
* Used for proxying regular HTTP(S) requests
214214
* @param req - Client request.
215215
* @param res - Client response.
216216
* @param options - Additional options.
217217
*/
218-
public readonly web: (...args: ProxyMethodArgs["web"]) => void;
218+
public readonly web: (...args: ProxyMethodArgs<TIncomingMessage, TServerResponse, TError>["web"]) => void;
219219

220220
private options: ServerOptions;
221-
private webPasses: Array<PassFunctions['web']>;
222-
private wsPasses: Array<PassFunctions['ws']>;
223-
private _server?: http.Server | https.Server | null;
221+
private webPasses: Array<PassFunctions<TIncomingMessage, TServerResponse, TError>['web']>;
222+
private wsPasses: Array<PassFunctions<TIncomingMessage, TServerResponse, TError>['ws']>;
223+
private _server?: http.Server<TIncomingMessage, TServerResponse> | https.Server<TIncomingMessage, TServerResponse> | null;
224224

225225
/**
226226
* Creates the proxy server with specified options.
@@ -233,8 +233,8 @@ export class ProxyServer extends EventEmitter<ProxyServerEventMap> {
233233
this.options = options;
234234
this.web = this.createRightProxy("web")(options);
235235
this.ws = this.createRightProxy("ws")(options);
236-
this.webPasses = Object.values(WEB_PASSES);
237-
this.wsPasses = Object.values(WS_PASSES);
236+
this.webPasses = Object.values(WEB_PASSES) as Array<PassFunctions<TIncomingMessage, TServerResponse, TError>['web']>;
237+
this.wsPasses = Object.values(WS_PASSES) as Array<PassFunctions<TIncomingMessage, TServerResponse, TError>['ws']>;
238238
this.on("error", this.onError);
239239
}
240240

@@ -243,36 +243,48 @@ export class ProxyServer extends EventEmitter<ProxyServerEventMap> {
243243
* @param options Config object passed to the proxy
244244
* @returns Proxy object with handlers for `ws` and `web` requests
245245
*/
246-
static createProxyServer(options?: ServerOptions): ProxyServer {
247-
return new ProxyServer(options);
246+
static createProxyServer<
247+
TIncomingMessage extends typeof http.IncomingMessage,
248+
TServerResponse extends typeof http.ServerResponse,
249+
TError = Error
250+
>(options?: ServerOptions): ProxyServer<TIncomingMessage, TServerResponse, TError> {
251+
return new ProxyServer<TIncomingMessage, TServerResponse, TError>(options);
248252
}
249253

250254
/**
251255
* Creates the proxy server with specified options.
252256
* @param options Config object passed to the proxy
253257
* @returns Proxy object with handlers for `ws` and `web` requests
254258
*/
255-
static createServer(options?: ServerOptions): ProxyServer {
256-
return new ProxyServer(options);
259+
static createServer<
260+
TIncomingMessage extends typeof http.IncomingMessage,
261+
TServerResponse extends typeof http.ServerResponse,
262+
TError = Error
263+
>(options?: ServerOptions): ProxyServer<TIncomingMessage, TServerResponse, TError> {
264+
return new ProxyServer<TIncomingMessage, TServerResponse, TError>(options);
257265
}
258266

259267
/**
260268
* Creates the proxy server with specified options.
261269
* @param options Config object passed to the proxy
262270
* @returns Proxy object with handlers for `ws` and `web` requests
263271
*/
264-
static createProxy(options?: ServerOptions): ProxyServer {
265-
return new ProxyServer(options);
272+
static createProxy<
273+
TIncomingMessage extends typeof http.IncomingMessage,
274+
TServerResponse extends typeof http.ServerResponse,
275+
TError = Error
276+
>(options?: ServerOptions): ProxyServer<TIncomingMessage, TServerResponse, TError> {
277+
return new ProxyServer<TIncomingMessage, TServerResponse, TError>(options);
266278
}
267279

268280
// createRightProxy - Returns a function that when called creates the loader for
269281
// either `ws` or `web`'s passes.
270282
createRightProxy = <PT extends ProxyType>(type: PT): Function => {
271283
log("createRightProxy", { type });
272284
return (options: ServerOptions) => {
273-
return (...args: ProxyMethodArgs[PT] /* req, res, [head], [opts] */) => {
285+
return (...args: ProxyMethodArgs<TIncomingMessage, TServerResponse, TError>[PT] /* req, res, [head], [opts] */) => {
274286
const req = args[0];
275-
log("proxy: ", { type, path: req.url });
287+
log("proxy: ", { type, path: (req as http.IncomingMessage).url });
276288
const res = args[1];
277289
const passes = type === "ws" ? this.wsPasses : this.webPasses;
278290
if (type == "ws") {
@@ -284,13 +296,13 @@ export class ProxyServer extends EventEmitter<ProxyServerEventMap> {
284296
// and there's no way for a user of http-proxy-3 to get ahold
285297
// of this res object and attach their own error handler until
286298
// after the passes. So we better attach one ASAP right here:
287-
(res as net.Socket).on("error", (err) => {
299+
(res as net.Socket).on("error", (err: TError) => {
288300
this.emit("error", err, req, res);
289301
});
290302
}
291303
let counter = args.length - 1;
292304
let head: Buffer | undefined;
293-
let cb: ErrorCallback | undefined;
305+
let cb: ErrorCallback<TIncomingMessage, TServerResponse, TError> | undefined;
294306

295307
// optional args parse begin
296308
if (typeof args[counter] === "function") {
@@ -318,7 +330,7 @@ export class ProxyServer extends EventEmitter<ProxyServerEventMap> {
318330
}
319331

320332
if (!requestOptions.target && !requestOptions.forward) {
321-
this.emit("error", new Error("Must set target or forward"), req, res);
333+
this.emit("error", new Error("Must set target or forward") as TError, req, res);
322334
return;
323335
}
324336

@@ -340,7 +352,7 @@ export class ProxyServer extends EventEmitter<ProxyServerEventMap> {
340352
};
341353
};
342354

343-
onError = (err: Error) => {
355+
onError = (err: TError) => {
344356
// Force people to handle their own errors
345357
if (this.listeners("error").length === 1) {
346358
throw err;
@@ -355,12 +367,16 @@ export class ProxyServer extends EventEmitter<ProxyServerEventMap> {
355367
listen = (port: number, hostname?: string) => {
356368
log("listen", { port, hostname });
357369

370+
const requestListener = (req: InstanceType<TIncomingMessage>, res: InstanceType<TServerResponse>) => {
371+
this.web(req, res);
372+
};
373+
358374
this._server = this.options.ssl
359-
? https.createServer(this.options.ssl, this.web)
360-
: http.createServer(this.web);
375+
? https.createServer<TIncomingMessage, TServerResponse>(this.options.ssl, requestListener)
376+
: http.createServer<TIncomingMessage, TServerResponse>(requestListener);
361377

362378
if (this.options.ws) {
363-
this._server.on("upgrade", (req, socket, head) => {
379+
this._server.on("upgrade", (req: InstanceType<TIncomingMessage>, socket, head) => {
364380
this.ws(req, socket, head);
365381
});
366382
}
@@ -390,11 +406,11 @@ export class ProxyServer extends EventEmitter<ProxyServerEventMap> {
390406
});
391407
};
392408

393-
before = <PT extends ProxyType>(type: PT, passName: string, cb: PassFunctions[PT]) => {
409+
before = <PT extends ProxyType>(type: PT, passName: string, cb: PassFunctions<TIncomingMessage, TServerResponse, TError>[PT]) => {
394410
if (type !== "ws" && type !== "web") {
395411
throw new Error("type must be `web` or `ws`");
396412
}
397-
const passes = (type === "ws" ? this.wsPasses : this.webPasses) as PassFunctions[PT][];
413+
const passes = (type === "ws" ? this.wsPasses : this.webPasses) as PassFunctions<TIncomingMessage, TServerResponse, TError>[PT][];
398414
let i: false | number = false;
399415

400416
passes.forEach((v, idx) => {
@@ -410,11 +426,11 @@ export class ProxyServer extends EventEmitter<ProxyServerEventMap> {
410426
passes.splice(i, 0, cb);
411427
};
412428

413-
after = <PT extends ProxyType>(type: PT, passName: string, cb: PassFunctions[PT]) => {
429+
after = <PT extends ProxyType>(type: PT, passName: string, cb: PassFunctions<TIncomingMessage, TServerResponse, TError>[PT]) => {
414430
if (type !== "ws" && type !== "web") {
415431
throw new Error("type must be `web` or `ws`");
416432
}
417-
const passes = (type === "ws" ? this.wsPasses : this.webPasses) as PassFunctions[PT][];
433+
const passes = (type === "ws" ? this.wsPasses : this.webPasses) as PassFunctions<TIncomingMessage, TServerResponse, TError>[PT][];
418434
let i: false | number = false;
419435

420436
passes.forEach((v, idx) => {

lib/index.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ export {
1313
type ErrorCallback,
1414
};
1515
export { numOpenSockets } from './http-proxy/passes/ws-incoming';
16+
import * as http from 'node:http';
1617

1718
/**
1819
* Creates the proxy server.
@@ -29,8 +30,8 @@ export { numOpenSockets } from './http-proxy/passes/ws-incoming';
2930
* @api public
3031
*/
3132

32-
function createProxyServer(options: ServerOptions = {}): ProxyServer {
33-
return new ProxyServer(options);
33+
function createProxyServer<TIncomingMessage extends typeof http.IncomingMessage = typeof http.IncomingMessage, TServerResponse extends typeof http.ServerResponse = typeof http.ServerResponse, TError = Error>(options: ServerOptions = {}): ProxyServer<TIncomingMessage, TServerResponse, TError> {
34+
return new ProxyServer<TIncomingMessage, TServerResponse, TError>(options);
3435
}
3536

3637
export {

0 commit comments

Comments
 (0)