Skip to content

Commit

Permalink
feat(typescript): types support
Browse files Browse the repository at this point in the history
  • Loading branch information
chimurai committed Oct 8, 2019
1 parent 3b97308 commit 375d2bb
Show file tree
Hide file tree
Showing 18 changed files with 260 additions and 43 deletions.
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
{
"name": "http-proxy-middleware",
"version": "0.20.0",
"version": "0.21.0-beta.0",
"description": "The one-liner node.js proxy middleware for connect, express and browser-sync",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"files": [
"dist"
],
Expand Down Expand Up @@ -51,7 +52,6 @@
"@commitlint/cli": "^8.0.0",
"@commitlint/config-conventional": "^8.0.0",
"@types/express": "^4.17.0",
"@types/http-proxy": "^1.17.0",
"@types/is-glob": "^4.0.0",
"@types/jest": "^24.0.15",
"@types/lodash": "^4.14.136",
Expand All @@ -72,6 +72,7 @@
"ws": "^7.1.0"
},
"dependencies": {
"@types/http-proxy": "^1.17.0",
"http-proxy": "^1.17.0",
"is-glob": "^4.0.1",
"lodash": "^4.17.14",
Expand Down
13 changes: 7 additions & 6 deletions src/config-factory.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
import * as _ from 'lodash';
import * as url from 'url';
import _ from 'lodash';
import url from 'url';
import { ERRORS } from './errors';
import { getInstance } from './logger';
import { Filter, Options } from './types';

const logger = getInstance();

export function createConfig(context, opts?) {
// structure of config object to be returned
const config = {
context: undefined,
options: {} as any
options: {} as Options
};

// app.use('/api', proxy({target:'http://localhost:9000'}));
Expand Down Expand Up @@ -55,7 +56,7 @@ export function createConfig(context, opts?) {
* @param {String} context [description]
* @return {Boolean} [description]
*/
function isStringShortHand(context) {
function isStringShortHand(context: Filter) {
if (_.isString(context)) {
return !!url.parse(context).host;
}
Expand All @@ -72,11 +73,11 @@ function isStringShortHand(context) {
* @param {*} opts [description]
* @return {Boolean} [description]
*/
function isContextless(context, opts) {
function isContextless(context: Filter, opts: Options) {
return _.isPlainObject(context) && _.isEmpty(opts);
}

function configureLogger(options) {
function configureLogger(options: Options) {
if (options.logLevel) {
logger.setLevel(options.logLevel);
}
Expand Down
8 changes: 4 additions & 4 deletions src/context-matcher.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import * as isGlob from 'is-glob';
import * as _ from 'lodash';
import * as micromatch from 'micromatch';
import * as url from 'url';
import isGlob from 'is-glob';
import _ from 'lodash';
import micromatch from 'micromatch';
import url from 'url';
import { ERRORS } from './errors';

export function match(context, uri, req) {
Expand Down
2 changes: 1 addition & 1 deletion src/handlers.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import * as _ from 'lodash';
import _ from 'lodash';
import { getInstance } from './logger';
const logger = getInstance();

Expand Down
37 changes: 22 additions & 15 deletions src/http-proxy-middleware.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,23 @@
import * as httpProxy from 'http-proxy';
import * as _ from 'lodash';
import express from 'express';
import httpProxy from 'http-proxy';
import _ from 'lodash';
import { createConfig } from './config-factory';
import * as contextMatcher from './context-matcher';
import * as handlers from './handlers';
import { getArrow, getInstance } from './logger';
import * as PathRewriter from './path-rewriter';
import * as Router from './router';
import { Filter, IRequest, IRequestHandler, IResponse, Options } from './types';

export class HttpProxyMiddleware {
private logger = getInstance();
private config;
private wsInternalSubscribed = false;
private proxyOptions;
private proxy;
private proxyOptions: Options;
private proxy: httpProxy;
private pathRewriter;

constructor(context, opts) {
constructor(context: Filter | Options, opts?: Options) {
this.config = createConfig(context, opts);
this.proxyOptions = this.config.options;

Expand All @@ -37,15 +39,19 @@ export class HttpProxyMiddleware {

// https://github.com/chimurai/http-proxy-middleware/issues/19
// expose function to upgrade externally
(this.middleware as any).upgrade = (req, socket, head) => {
this.middleware.upgrade = (req, socket, head) => {
if (!this.wsInternalSubscribed) {
this.handleUpgrade(req, socket, head);
}
};
}

// https://github.com/Microsoft/TypeScript/wiki/'this'-in-TypeScript#red-flags-for-this
public middleware = async (req, res, next) => {
public middleware: IRequestHandler = async (
req: IRequest,
res: IResponse,
next: express.NextFunction
) => {
if (this.shouldProxy(this.config.context, req)) {
const activeProxyOptions = this.prepareProxyRequest(req);
this.proxy.web(req, res, activeProxyOptions);
Expand All @@ -55,7 +61,7 @@ export class HttpProxyMiddleware {

if (this.proxyOptions.ws === true) {
// use initial request to access the server object to subscribe to http upgrade event
this.catchUpgradeRequest(req.connection.server);
this.catchUpgradeRequest((req.connection as any).server);
}
};

Expand All @@ -68,7 +74,7 @@ export class HttpProxyMiddleware {
}
};

private handleUpgrade = (req, socket, head) => {
private handleUpgrade = (req: IRequest, socket, head) => {
if (this.shouldProxy(this.config.context, req)) {
const activeProxyOptions = this.prepareProxyRequest(req);
this.proxy.ws(req, socket, head, activeProxyOptions);
Expand All @@ -84,7 +90,7 @@ export class HttpProxyMiddleware {
* @param {Object} req [description]
* @return {Boolean}
*/
private shouldProxy = (context, req) => {
private shouldProxy = (context, req: IRequest) => {
const path = req.originalUrl || req.url;
return contextMatcher.match(context, path, req);
};
Expand All @@ -97,7 +103,7 @@ export class HttpProxyMiddleware {
* @param {Object} req
* @return {Object} proxy options
*/
private prepareProxyRequest = req => {
private prepareProxyRequest = (req: IRequest) => {
// https://github.com/chimurai/http-proxy-middleware/issues/17
// https://github.com/chimurai/http-proxy-middleware/issues/94
req.url = req.originalUrl || req.url;
Expand Down Expand Up @@ -133,7 +139,7 @@ export class HttpProxyMiddleware {
};

// Modify option.target when router present.
private applyRouter = (req, options) => {
private applyRouter = (req: IRequest, options) => {
let newTarget;

if (options.router) {
Expand All @@ -151,7 +157,7 @@ export class HttpProxyMiddleware {
};

// rewrite path
private applyPathRewrite = (req, pathRewriter) => {
private applyPathRewrite = (req: IRequest, pathRewriter) => {
if (pathRewriter) {
const path = pathRewriter(req.url, req);

Expand All @@ -166,10 +172,11 @@ export class HttpProxyMiddleware {
}
};

private logError = (err, req, res) => {
private logError = (err, req: IRequest, res: IResponse) => {
const hostname =
(req.headers && req.headers.host) || (req.hostname || req.host); // (websocket) || (node0.10 || node 4/5)
const target = this.proxyOptions.target.host || this.proxyOptions.target;
const target =
(this.proxyOptions.target as any).host || this.proxyOptions.target;
const errorMessage =
'[HPM] Error occurred while trying to proxy request %s from %s to %s (%s) (%s)';
const errReference =
Expand Down
7 changes: 4 additions & 3 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { HttpProxyMiddleware } from './http-proxy-middleware';
import { Filter, Options } from './types';

function proxy(context, opts) {
const { middleware } = new HttpProxyMiddleware(context, opts);
function middleware(context: Filter | Options, options?: Options) {
const { middleware } = new HttpProxyMiddleware(context, options);
return middleware;
}

export = proxy;
export = middleware;
4 changes: 2 additions & 2 deletions src/logger.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as _ from 'lodash';
import * as util from 'util';
import _ from 'lodash';
import util from 'util';

let loggerInstance;

Expand Down
2 changes: 1 addition & 1 deletion src/path-rewriter.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import * as _ from 'lodash';
import _ from 'lodash';
import { ERRORS } from './errors';
import { getInstance } from './logger';
const logger = getInstance();
Expand Down
2 changes: 1 addition & 1 deletion src/router.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import * as _ from 'lodash';
import _ from 'lodash';
import { getInstance } from './logger';
const logger = getInstance();

Expand Down
56 changes: 56 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import express from 'express';
import http from 'http';
import httpProxy from 'http-proxy';
import net from 'net';

export interface IRequest extends express.Request {}
export interface IResponse extends express.Response {}

export interface IRequestHandler extends express.RequestHandler {
upgrade?: (req: IRequest, socket: net.Socket, head: any) => void;
}

export type Filter = FilterPath | FilterWildcards | FilterFn;
export type FilterFn = (pathname: string, req: IRequest) => boolean;
export type FilterPath = string;
export type FilterWildcards = string[];

export interface Options extends httpProxy.ServerOptions {
pathRewrite?:
| { [regexp: string]: string }
| ((path: string, req: IRequest) => string);
router?: { [hostOrPath: string]: string } | ((req: IRequest) => string);
logLevel?: 'debug' | 'info' | 'warn' | 'error' | 'silent';
logProvider?(provider: LogProvider): LogProvider;

onError?(err: Error, req: IRequest, res: IResponse): void;
onProxyRes?(
proxyRes: http.ServerResponse,
req: IRequest,
res: IResponse
): void;
onProxyReq?(
proxyReq: http.ClientRequest,
req: IRequest,
res: IResponse
): void;
onProxyReqWs?(
proxyReq: http.ClientRequest,
req: IRequest,
socket: net.Socket,
options: httpProxy.ServerOptions,
head: any
): void;
onOpen?(proxySocket: net.Socket): void;
onClose?(res: IResponse, socket: net.Socket, head: any): void;
}

interface LogProvider {
log: Logger;
debug?: Logger;
info?: Logger;
warn?: Logger;
error?: Logger;
}

type Logger = (...args: any[]) => void;
2 changes: 1 addition & 1 deletion test/e2e/_utils.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import * as express from 'express';
import express from 'express';

// tslint:disable-next-line: no-var-requires
export const proxyMiddleware = require('../../dist/index');
Expand Down
4 changes: 2 additions & 2 deletions test/e2e/express-router.spec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as express from 'express';
import * as http from 'http';
import express from 'express';
import http from 'http';
import { proxyMiddleware as proxy } from './_utils';

describe('Usage in Express', () => {
Expand Down
2 changes: 1 addition & 1 deletion test/e2e/http-proxy-middleware.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import * as http from 'http';
import http from 'http';
import { createServer, proxyMiddleware } from './_utils';

describe('E2E http-proxy-middleware', () => {
Expand Down
2 changes: 1 addition & 1 deletion test/e2e/path-rewriter.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import * as http from 'http';
import http from 'http';
import { createServer, proxyMiddleware } from './_utils';

describe('E2E pathRewrite', () => {
Expand Down
2 changes: 1 addition & 1 deletion test/e2e/router.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import * as http from 'http';
import http from 'http';
import { createServer, proxyMiddleware } from './_utils';

describe('E2E router', () => {
Expand Down
4 changes: 2 additions & 2 deletions test/e2e/websocket.spec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as http from 'http';
import * as WebSocket from 'ws';
import http from 'http';
import WebSocket from 'ws';
// tslint:disable-next-line: no-duplicate-imports
import { Server as WebSocketServer } from 'ws';
import { createServer, proxyMiddleware } from './_utils';
Expand Down
Loading

0 comments on commit 375d2bb

Please sign in to comment.