From 9cbb7e68fe6a958ff7084c6f633baf2768e0fa54 Mon Sep 17 00:00:00 2001 From: wanghx Date: Thu, 7 Sep 2017 20:50:07 +0800 Subject: [PATCH 01/19] docs: change badge --- README.md | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index a56196f..b6f9335 100644 --- a/README.md +++ b/README.md @@ -3,24 +3,18 @@ a simple tcp proxy [![NPM version][npm-image]][npm-url] -[![build status][travis-image]][travis-url] -[![Test coverage][codecov-image]][codecov-url] -[![David deps][david-image]][david-url] -[![Known Vulnerabilities][snyk-image]][snyk-url] -[![NPM download][download-image]][download-url] +[![Build Status][travis-image]][travis-url] +[![Appveyor status][appveyor-image]][appveyor-url] +[![Coverage Status][coveralls-image]][coveralls-url] [npm-image]: https://img.shields.io/npm/v/tcp-proxy.js.svg?style=flat-square [npm-url]: https://npmjs.org/package/tcp-proxy.js [travis-image]: https://img.shields.io/travis/{{org}}/tcp-proxy.js.svg?style=flat-square [travis-url]: https://travis-ci.org/{{org}}/tcp-proxy.js -[codecov-image]: https://codecov.io/gh/{{org}}/tcp-proxy.js/branch/master/graph/badge.svg -[codecov-url]: https://codecov.io/gh/{{org}}/tcp-proxy.js -[david-image]: https://img.shields.io/david/{{org}}/tcp-proxy.js.svg?style=flat-square -[david-url]: https://david-dm.org/{{org}}/tcp-proxy.js -[snyk-image]: https://snyk.io/test/npm/tcp-proxy.js/badge.svg?style=flat-square -[snyk-url]: https://snyk.io/test/npm/tcp-proxy.js -[download-image]: https://img.shields.io/npm/dm/tcp-proxy.js.svg?style=flat-square -[download-url]: https://npmjs.org/package/tcp-proxy.js +[appveyor-url]: https://ci.appveyor.com/project/whxaxes/tcp-proxy.js/branch/master +[appveyor-image]: https://ci.appveyor.com/api/projects/status/github/whxaxes/tcp-proxy.js?branch=master&svg=true +[coveralls-url]: https://coveralls.io/r/whxaxes/tcp-proxy.js +[coveralls-image]: https://img.shields.io/coveralls/whxaxes/tcp-proxy.js.svg ## Usage From 60333463b41e910d3a94a880093f04eae26e1d33 Mon Sep 17 00:00:00 2001 From: wanghx Date: Thu, 7 Sep 2017 20:52:53 +0800 Subject: [PATCH 02/19] feat: change travis.yml --- .travis.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 47cc542..4732996 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,5 +7,4 @@ install: - npm i npminstall && npminstall script: - npm run ci -after_script: - - npminstall codecov && codecov +after_script: "npm install coveralls && cat ./coverage/lcov.info | coveralls" From a258146c7ab2a8ec90cae3c898c64a99978720fe Mon Sep 17 00:00:00 2001 From: wanghx Date: Thu, 7 Sep 2017 20:55:30 +0800 Subject: [PATCH 03/19] chore: change badge url --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index b6f9335..cdadc31 100644 --- a/README.md +++ b/README.md @@ -9,8 +9,8 @@ a simple tcp proxy [npm-image]: https://img.shields.io/npm/v/tcp-proxy.js.svg?style=flat-square [npm-url]: https://npmjs.org/package/tcp-proxy.js -[travis-image]: https://img.shields.io/travis/{{org}}/tcp-proxy.js.svg?style=flat-square -[travis-url]: https://travis-ci.org/{{org}}/tcp-proxy.js +[travis-url]: https://travis-ci.org/whxaxes/tcp-proxy.js +[travis-image]: http://img.shields.io/travis/whxaxes/tcp-proxy.js.svg [appveyor-url]: https://ci.appveyor.com/project/whxaxes/tcp-proxy.js/branch/master [appveyor-image]: https://ci.appveyor.com/api/projects/status/github/whxaxes/tcp-proxy.js?branch=master&svg=true [coveralls-url]: https://coveralls.io/r/whxaxes/tcp-proxy.js From 20b8ba70317621b0877f1cc4c40ff07054f4cf09 Mon Sep 17 00:00:00 2001 From: wanghx Date: Thu, 7 Sep 2017 22:57:30 +0800 Subject: [PATCH 04/19] fix: socket write after end --- index.js | 61 ++++++++++++++++++++++------------------------ test/index.test.js | 11 ++++++--- 2 files changed, 36 insertions(+), 36 deletions(-) diff --git a/index.js b/index.js index 75e7fb1..1a56100 100644 --- a/index.js +++ b/index.js @@ -47,42 +47,40 @@ module.exports = class TCPProxy extends EventEmitter { }); } - const onClose = () => { - this.proxyClient && this.proxyClient.destroy(); - this.proxyServer && this.proxyServer.destroy(); - this.proxyClient = null; - this.proxyServer = null; - }; - return new Promise((resolve, reject) => { this.server = net .createServer(client => { - const server = net.connect( - { - port: forwardPort, - host: forwardHost, - }, - () => { - let _client = client; - let _server = server; - - // client interceptor - if (interceptor.client) { - _client = _client.pipe(genThrough(interceptor.client)); - } - - // server interceptor - if (interceptor.server) { - _server = _server.pipe(genThrough(interceptor.server)); - } - - _client.pipe(server); - _server.pipe(client); + let interceptorClient; + let interceptorServer; + const server = net.connect({ + port: forwardPort, + host: forwardHost, + }, () => { + let _client = client; + let _server = server; + + // client interceptor + if (interceptor.client) { + interceptorClient = genThrough(interceptor.client); + _client = _client.pipe(interceptorClient); } - ); - this.proxyClient = client; - this.proxyServer = server; + // server interceptor + if (interceptor.server) { + interceptorServer = genThrough(interceptor.server); + _server = _server.pipe(interceptorServer); + } + + _client.pipe(server); + _server.pipe(client); + }); + + const onClose = () => { + client.destroy(); + server.destroy(); + interceptorClient && interceptorClient.end(); + interceptorServer && interceptorServer.end(); + }; server.once('close', onClose); server.once('error', onClose); @@ -94,7 +92,6 @@ module.exports = class TCPProxy extends EventEmitter { this.server.once('close', () => { this.server = null; - onClose(); }); this.server.once('error', reject); diff --git a/test/index.test.js b/test/index.test.js index 16306b4..4b885e4 100644 --- a/test/index.test.js +++ b/test/index.test.js @@ -72,11 +72,14 @@ describe('test/index.test.js', () => { }, }, }); - const response = yield urllib.request(`http://localhost:${proxyPort}/`); - assert(response.data.toString() === `bello tom ${data.port}`); - const response2 = yield urllib.request(`http://localhost:${proxyPort}/123`); - assert(response2.data.toString() === `hello world ${data.port}`); + const response = yield { + result: urllib.request(`http://localhost:${proxyPort}/`), + result2: urllib.request(`http://localhost:${proxyPort}/123`), + }; + + assert(response.result.data.toString() === `bello tom ${data.port}`); + assert(response.result2.data.toString() === `hello world ${data.port}`); }); it('should support async interceptor', function* () { From 9e8d5201ebd779967f91aad21f02c0349c2dec96 Mon Sep 17 00:00:00 2001 From: wanghx Date: Thu, 7 Sep 2017 23:00:50 +0800 Subject: [PATCH 05/19] Release 1.0.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index c3fd47e..8efa8ef 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "tcp-proxy.js", - "version": "1.0.0", + "version": "1.0.1", "description": "simple tcp proxy", "dependencies": { "through2": "^2.0.3" From 67eae6b72e500a96e23f8d24287b2303b029c3ec Mon Sep 17 00:00:00 2001 From: wanghx Date: Fri, 8 Sep 2017 09:50:08 +0800 Subject: [PATCH 06/19] feat: add connection event --- index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.js b/index.js index 1a56100..385c1c5 100644 --- a/index.js +++ b/index.js @@ -73,6 +73,7 @@ module.exports = class TCPProxy extends EventEmitter { _client.pipe(server); _server.pipe(client); + this.emit('connection', _client, _server); }); const onClose = () => { @@ -86,7 +87,6 @@ module.exports = class TCPProxy extends EventEmitter { server.once('error', onClose); client.once('close', onClose); client.once('error', onClose); - this.emit('connection'); }) .listen(proxyPort); From dc5a8def9f3f45662856aa3c74a6fcc161bec2fb Mon Sep 17 00:00:00 2001 From: wanghx Date: Fri, 8 Sep 2017 09:56:15 +0800 Subject: [PATCH 07/19] fix: fix error of executing end() multiple times --- index.js | 4 ++++ test/index.test.js | 8 ++++++++ 2 files changed, 12 insertions(+) diff --git a/index.js b/index.js index 385c1c5..71f139f 100644 --- a/index.js +++ b/index.js @@ -103,6 +103,10 @@ module.exports = class TCPProxy extends EventEmitter { } end() { + if (!this.server) { + return Promise.resolve(); + } + return new Promise(resolve => { this.server.close(resolve); }); diff --git a/test/index.test.js b/test/index.test.js index 4b885e4..94fa525 100644 --- a/test/index.test.js +++ b/test/index.test.js @@ -34,6 +34,14 @@ describe('test/index.test.js', () => { assert(response.data.toString() === `hello world ${data.port}`); }); + it('proxy should not throw error with executing end function multiple times', function* () { + data = yield createServer(); + yield proxy.createProxy({ forwardPort: data.port }); + yield proxy.end(); + yield proxy.end(); + yield proxy.end(); + }); + it('proxy should start only one server', done => { co(function* () { data = yield createServer(); From 5bd2b5bda13235fff652024a85323640bb7d40e8 Mon Sep 17 00:00:00 2001 From: wanghx Date: Fri, 8 Sep 2017 09:58:28 +0800 Subject: [PATCH 08/19] Release 1.0.2 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 8efa8ef..c39ca61 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "tcp-proxy.js", - "version": "1.0.1", + "version": "1.0.2", "description": "simple tcp proxy", "dependencies": { "through2": "^2.0.3" From 147bfff3f99b0599d884d4069e7ad6ff4f4abb84 Mon Sep 17 00:00:00 2001 From: wanghx Date: Fri, 8 Sep 2017 10:49:43 +0800 Subject: [PATCH 09/19] fix: fix error of creating proxy without options --- index.js | 2 +- test/index.test.js | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/index.js b/index.js index 71f139f..3bf8ff9 100644 --- a/index.js +++ b/index.js @@ -31,7 +31,7 @@ function genThrough(interceptor) { } module.exports = class TCPProxy extends EventEmitter { - constructor(options) { + constructor(options = {}) { super(); this.port = options.port; } diff --git a/test/index.test.js b/test/index.test.js index 94fa525..81cffaf 100644 --- a/test/index.test.js +++ b/test/index.test.js @@ -34,6 +34,15 @@ describe('test/index.test.js', () => { assert(response.data.toString() === `hello world ${data.port}`); }); + it('proxy should work correctly without options', function* () { + const newProxy = new TCPProxy(); + data = yield createServer(); + yield newProxy.createProxy({ port: 9800, forwardPort: data.port }); + const response = yield urllib.request('http://localhost:9800/'); + assert(response.data.toString() === `hello world ${data.port}`); + yield newProxy.end(); + }); + it('proxy should not throw error with executing end function multiple times', function* () { data = yield createServer(); yield proxy.createProxy({ forwardPort: data.port }); From 7ef2ae9ae92df2f7b1a86fcd078072332da32698 Mon Sep 17 00:00:00 2001 From: wanghx Date: Fri, 8 Sep 2017 10:49:57 +0800 Subject: [PATCH 10/19] Release 1.0.3 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index c39ca61..2844835 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "tcp-proxy.js", - "version": "1.0.2", + "version": "1.0.3", "description": "simple tcp proxy", "dependencies": { "through2": "^2.0.3" From 5af99f66dbf0b983827cf0ceac0c2b4fcaea8331 Mon Sep 17 00:00:00 2001 From: wanghx Date: Fri, 8 Sep 2017 22:49:03 +0800 Subject: [PATCH 11/19] feat: make sure server has closed --- index.js | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/index.js b/index.js index 3bf8ff9..1d0a881 100644 --- a/index.js +++ b/index.js @@ -34,6 +34,7 @@ module.exports = class TCPProxy extends EventEmitter { constructor(options = {}) { super(); this.port = options.port; + this.clients = []; } createProxy({ port, forwardPort, forwardHost, interceptor }) { @@ -81,19 +82,17 @@ module.exports = class TCPProxy extends EventEmitter { server.destroy(); interceptorClient && interceptorClient.end(); interceptorServer && interceptorServer.end(); + this.server && this.server.removeListener('close', onClose); }; server.once('close', onClose); server.once('error', onClose); client.once('close', onClose); client.once('error', onClose); + this.server.once('close', onClose); }) .listen(proxyPort); - this.server.once('close', () => { - this.server = null; - }); - this.server.once('error', reject); this.server.once('listening', () => { this.server.removeListener('error', reject); @@ -108,7 +107,10 @@ module.exports = class TCPProxy extends EventEmitter { } return new Promise(resolve => { - this.server.close(resolve); + this.server.close(() => { + this.server = null; + resolve(); + }); }); } }; From c28ef22d527206273c661237443ffd7b5399eecb Mon Sep 17 00:00:00 2001 From: wanghx Date: Fri, 8 Sep 2017 22:49:18 +0800 Subject: [PATCH 12/19] Release 1.0.4 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 2844835..5fae674 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "tcp-proxy.js", - "version": "1.0.3", + "version": "1.0.4", "description": "simple tcp proxy", "dependencies": { "through2": "^2.0.3" From 4224839be35ee1f4cdfb4d0f1f388c84cff8cc6c Mon Sep 17 00:00:00 2001 From: wanghx Date: Fri, 8 Sep 2017 22:51:56 +0800 Subject: [PATCH 13/19] Release 1.0.5 --- index.js | 5 +++-- package.json | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/index.js b/index.js index 1d0a881..fbad86d 100644 --- a/index.js +++ b/index.js @@ -82,14 +82,14 @@ module.exports = class TCPProxy extends EventEmitter { server.destroy(); interceptorClient && interceptorClient.end(); interceptorServer && interceptorServer.end(); - this.server && this.server.removeListener('close', onClose); + this.removeListener('close', onClose); }; server.once('close', onClose); server.once('error', onClose); client.once('close', onClose); client.once('error', onClose); - this.server.once('close', onClose); + this.once('close', onClose); }) .listen(proxyPort); @@ -107,6 +107,7 @@ module.exports = class TCPProxy extends EventEmitter { } return new Promise(resolve => { + this.emit('close'); this.server.close(() => { this.server = null; resolve(); diff --git a/package.json b/package.json index 5fae674..b8a5ced 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "tcp-proxy.js", - "version": "1.0.4", + "version": "1.0.5", "description": "simple tcp proxy", "dependencies": { "through2": "^2.0.3" From 33d22083e169e74eccf0b5c2640a5bde36ba9f54 Mon Sep 17 00:00:00 2001 From: wanghx Date: Thu, 21 Sep 2017 12:00:59 +0800 Subject: [PATCH 14/19] feat: add debug module --- index.js | 14 ++++++++++++-- package.json | 1 + 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/index.js b/index.js index fbad86d..f5a0987 100644 --- a/index.js +++ b/index.js @@ -2,6 +2,7 @@ const net = require('net'); const through = require('through2'); +const debug = require('debug')('tcp-proxy'); const EventEmitter = require('events').EventEmitter; function genThrough(interceptor) { @@ -53,6 +54,7 @@ module.exports = class TCPProxy extends EventEmitter { .createServer(client => { let interceptorClient; let interceptorServer; + debug('new connection from %o', client.address()); const server = net.connect({ port: forwardPort, host: forwardHost, @@ -74,14 +76,16 @@ module.exports = class TCPProxy extends EventEmitter { _client.pipe(server); _server.pipe(client); + debug(`proxy 127.0.0.1:${port} connect to ${forwardHost}:${forwardPort}`); this.emit('connection', _client, _server); }); - const onClose = () => { + const onClose = err => { client.destroy(); server.destroy(); interceptorClient && interceptorClient.end(); interceptorServer && interceptorServer.end(); + debug(`${forwardHost}:${forwardPort} disconnect [${err ? `error: ${err.message}` : 'close'}]`); this.removeListener('close', onClose); }; @@ -93,8 +97,13 @@ module.exports = class TCPProxy extends EventEmitter { }) .listen(proxyPort); - this.server.once('error', reject); + this.server.once('error', e => { + debug(`proxy server error: ${e.message}`); + reject(e); + }); + this.server.once('listening', () => { + debug(`proxy server listening on ${proxyPort}`); this.server.removeListener('error', reject); resolve(this.server); }); @@ -109,6 +118,7 @@ module.exports = class TCPProxy extends EventEmitter { return new Promise(resolve => { this.emit('close'); this.server.close(() => { + debug('proxy server closed'); this.server = null; resolve(); }); diff --git a/package.json b/package.json index b8a5ced..5047fde 100644 --- a/package.json +++ b/package.json @@ -3,6 +3,7 @@ "version": "1.0.5", "description": "simple tcp proxy", "dependencies": { + "debug": "^3.0.1", "through2": "^2.0.3" }, "devDependencies": { From 146a97a22f89202d9f1b2520ab02196f7d21e34a Mon Sep 17 00:00:00 2001 From: wanghx Date: Thu, 21 Sep 2017 12:50:04 +0800 Subject: [PATCH 15/19] test: add unittest --- test/index.test.js | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/test/index.test.js b/test/index.test.js index 81cffaf..3f1098c 100644 --- a/test/index.test.js +++ b/test/index.test.js @@ -99,6 +99,25 @@ describe('test/index.test.js', () => { assert(response.result2.data.toString() === `hello world ${data.port}`); }); + it('should reject while proxy server error occurs', done => { + const httpServer = require('http') + .createServer() + .listen(proxyPort, () => { + proxy.createProxy({ forwardPort: 1234 }) + .then(() => { + end(new Error('no error occurs')); + }) + .catch(() => { + end(); + }); + }); + + function end(err) { + httpServer.close(); + done(err); + } + }); + it('should support async interceptor', function* () { data = yield createServer(); yield proxy.createProxy({ From e222327c5aa9bf2acbdc697b7b7e3e3bed3bb73b Mon Sep 17 00:00:00 2001 From: wanghx Date: Thu, 21 Sep 2017 12:53:12 +0800 Subject: [PATCH 16/19] Release 1.1.0 --- History.md | 6 ++++++ package.json | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) create mode 100644 History.md diff --git a/History.md b/History.md new file mode 100644 index 0000000..5b4163d --- /dev/null +++ b/History.md @@ -0,0 +1,6 @@ + +1.1.0 / 2017-09-21 +================== + + * test: add unittest + * feat: add debug module diff --git a/package.json b/package.json index 5047fde..ae5859d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "tcp-proxy.js", - "version": "1.0.5", + "version": "1.1.0", "description": "simple tcp proxy", "dependencies": { "debug": "^3.0.1", From 1348d15409a30c7982c6a50c8728c615b385cc85 Mon Sep 17 00:00:00 2001 From: wanghx Date: Thu, 21 Sep 2017 14:14:39 +0800 Subject: [PATCH 17/19] fix: fix debug output error --- index.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/index.js b/index.js index f5a0987..2d07c6b 100644 --- a/index.js +++ b/index.js @@ -40,6 +40,7 @@ module.exports = class TCPProxy extends EventEmitter { createProxy({ port, forwardPort, forwardHost, interceptor }) { const proxyPort = port || this.port; + forwardHost = forwardHost || '127.0.0.1'; interceptor = interceptor || {}; if (this.server) { @@ -76,7 +77,7 @@ module.exports = class TCPProxy extends EventEmitter { _client.pipe(server); _server.pipe(client); - debug(`proxy 127.0.0.1:${port} connect to ${forwardHost}:${forwardPort}`); + debug(`proxy 127.0.0.1:${proxyPort} connect to ${forwardHost}:${forwardPort}`); this.emit('connection', _client, _server); }); From bdfb0387f9643f0af7802b34eae665019ac87d71 Mon Sep 17 00:00:00 2001 From: wanghx Date: Thu, 21 Sep 2017 14:14:56 +0800 Subject: [PATCH 18/19] Release 1.1.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index ae5859d..b861433 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "tcp-proxy.js", - "version": "1.1.0", + "version": "1.1.1", "description": "simple tcp proxy", "dependencies": { "debug": "^3.0.1", From fb4b1734e51a9c7968cc6ac18d3f0bcee4e4f8d3 Mon Sep 17 00:00:00 2001 From: wanghx Date: Thu, 21 Sep 2017 15:05:48 +0800 Subject: [PATCH 19/19] docs: update license --- LICENSE | 21 +++++++++++++++++++++ README.md | 4 ++++ 2 files changed, 25 insertions(+) create mode 100644 LICENSE diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..2f27fe3 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2017 Axes + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/README.md b/README.md index cdadc31..60fc08c 100644 --- a/README.md +++ b/README.md @@ -80,3 +80,7 @@ proxy.createProxy({ }, }); ``` + +## License + +MIT \ No newline at end of file