diff --git a/.env.app.example b/.env.app.example index a2a7122..4a41a78 100644 --- a/.env.app.example +++ b/.env.app.example @@ -13,3 +13,5 @@ DISALLOWED_INTERNAL_IPS=your_internal_ip_e_g_192.168 DISALLOWED_EXT_IPS=your_external_ip DISCORD_WEBHOOK_URL=https://discord.com/api/webhooks/your_webhook_url UPDATE_INTERVAL_SECONDS=300 +TRACKER_TOKEN=test +TRACKER_PORT=12345 diff --git a/package-lock.json b/package-lock.json index ec8454b..25530b5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5,6 +5,7 @@ "packages": { "": { "dependencies": { + "bittorrent-tracker": "^11.0.2", "docker-compose": "^0.24.8", "dotenv": "^16.4.5", "transmission": "^0.4.10" @@ -14,6 +15,31 @@ "typescript": "^5.4.5" } }, + "node_modules/@thaunknown/simple-peer": { + "version": "9.12.1", + "resolved": "https://registry.npmjs.org/@thaunknown/simple-peer/-/simple-peer-9.12.1.tgz", + "integrity": "sha512-IS5BXvXx7cvBAzaxqotJf4s4rJCPk5JABLK6Gbnn7oAmWVcH4hYABabBBrvvJtv/xyUqR4v/H3LalnGRJJfEog==", + "dependencies": { + "debug": "^4.3.2", + "err-code": "^3.0.1", + "get-browser-rtc": "^1.1.0", + "queue-microtask": "^1.2.3", + "streamx": "^2.13.2", + "uint8-util": "^2.1.9" + } + }, + "node_modules/@thaunknown/simple-websocket": { + "version": "9.1.1", + "resolved": "https://registry.npmjs.org/@thaunknown/simple-websocket/-/simple-websocket-9.1.1.tgz", + "integrity": "sha512-vzQloFWRodRZqZhpxMpBljFtISesY8TihA8T5uKwCYdj2I1ImMhE/gAeTCPsCGOtxJfGKu3hw/is6MXauWLjOg==", + "dependencies": { + "debug": "^4.3.4", + "queue-microtask": "^1.2.3", + "streamx": "^2.13.2", + "uint8-util": "^2.1.9", + "ws": "^8.12.0" + } + }, "node_modules/@types/node": { "version": "20.12.7", "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.7.tgz", @@ -23,6 +49,25 @@ "undici-types": "~5.26.4" } }, + "node_modules/abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "dependencies": { + "event-target-shim": "^5.0.0" + }, + "engines": { + "node": ">=6.5" + } + }, + "node_modules/addr-to-ip-port": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/addr-to-ip-port/-/addr-to-ip-port-2.0.0.tgz", + "integrity": "sha512-9bYbtjamtdLHZSqVIUXhilOryNPiL+x+Q5J/Unpg4VY3ZIkK3fT52UoErj1NdUeVm3J1t2iBEAur4Ywbl/bahw==", + "engines": { + "node": ">=12.20.0" + } + }, "node_modules/async": { "version": "2.6.4", "resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz", @@ -31,6 +76,188 @@ "lodash": "^4.17.14" } }, + "node_modules/bare-events": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.2.2.tgz", + "integrity": "sha512-h7z00dWdG0PYOQEvChhOSWvOfkIKsdZGkWr083FgN/HyoQuebSew/cgirYqh9SCuy/hRvxc5Vy6Fw8xAmYHLkQ==", + "optional": true + }, + "node_modules/base64-arraybuffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz", + "integrity": "sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ==", + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/bencode": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/bencode/-/bencode-4.0.0.tgz", + "integrity": "sha512-AERXw18df0pF3ziGOCyUjqKZBVNH8HV3lBxnx5w0qtgMIk4a1wb9BkcCQbkp9Zstfrn/dzRwl7MmUHHocX3sRQ==", + "dependencies": { + "uint8-util": "^2.2.2" + }, + "engines": { + "node": ">=12.20.0" + } + }, + "node_modules/bittorrent-peerid": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/bittorrent-peerid/-/bittorrent-peerid-1.3.6.tgz", + "integrity": "sha512-VyLcUjVMEOdSpHaCG/7odvCdLbAB1y3l9A2V6WIje24uV7FkJPrQrH/RrlFmKxP89pFVDEnE+YlHaFujlFIZsg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/bittorrent-tracker": { + "version": "11.0.2", + "resolved": "https://registry.npmjs.org/bittorrent-tracker/-/bittorrent-tracker-11.0.2.tgz", + "integrity": "sha512-MUv1zqWd1OZKPkgncj9JkpumhtF2Q+xeHptz8rJz+APK5/ZIAOIiHyLqDmoDL06JMa1iHPmeOlJG8I5Hi1UIbw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "@thaunknown/simple-peer": "^9.12.1", + "@thaunknown/simple-websocket": "^9.1.0", + "bencode": "^4.0.0", + "bittorrent-peerid": "^1.3.3", + "chrome-dgram": "^3.0.6", + "clone": "^2.0.0", + "compact2string": "^1.4.1", + "cross-fetch-ponyfill": "^1.0.1", + "debug": "^4.1.1", + "ip": "^1.1.5", + "lru": "^3.1.0", + "minimist": "^1.2.5", + "once": "^1.4.0", + "queue-microtask": "^1.2.3", + "random-iterate": "^1.0.1", + "run-parallel": "^1.2.0", + "run-series": "^1.1.9", + "socks": "^2.0.0", + "string2compact": "^2.0.0", + "uint8-util": "^2.1.9", + "unordered-array-remove": "^1.0.2", + "ws": "^8.0.0" + }, + "bin": { + "bittorrent-tracker": "bin/cmd.js" + }, + "engines": { + "node": ">=12.20.0" + }, + "optionalDependencies": { + "bufferutil": "^4.0.3", + "utf-8-validate": "^5.0.5" + } + }, + "node_modules/bufferutil": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-4.0.8.tgz", + "integrity": "sha512-4T53u4PdgsXqKaIctwF8ifXlRTTmEPJ8iEPWFdGZvcf7sbwYo6FKFEX9eNNAnzFZ7EzJAQ3CJeOtCRA4rDp7Pw==", + "hasInstallScript": true, + "optional": true, + "dependencies": { + "node-gyp-build": "^4.3.0" + }, + "engines": { + "node": ">=6.14.2" + } + }, + "node_modules/chrome-dgram": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/chrome-dgram/-/chrome-dgram-3.0.6.tgz", + "integrity": "sha512-bqBsUuaOiXiqxXt/zA/jukNJJ4oaOtc7ciwqJpZVEaaXwwxqgI2/ZdG02vXYWUhHGziDlvGMQWk0qObgJwVYKA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "inherits": "^2.0.4", + "run-series": "^1.1.9" + } + }, + "node_modules/clone": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", + "integrity": "sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/compact2string": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/compact2string/-/compact2string-1.4.1.tgz", + "integrity": "sha512-3D+EY5nsRhqnOwDxveBv5T8wGo4DEvYxjDtPGmdOX+gfr5gE92c2RC0w2wa+xEefm07QuVqqcF3nZJUZ92l/og==", + "dependencies": { + "ipaddr.js": ">= 0.1.5" + } + }, + "node_modules/cross-fetch-ponyfill": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/cross-fetch-ponyfill/-/cross-fetch-ponyfill-1.0.3.tgz", + "integrity": "sha512-uOBkDhUAGAbx/FEzNKkOfx3w57H8xReBBXoZvUnOKTI0FW0Xvrj3GrYv2iZXUqlffC1LMGfQzhmBM/ke+6eTDA==", + "dependencies": { + "abort-controller": "^3.0.0", + "node-fetch": "^3.3.0" + } + }, + "node_modules/data-uri-to-buffer": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", + "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==", + "engines": { + "node": ">= 12" + } + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, "node_modules/docker-compose": { "version": "0.24.8", "resolved": "https://registry.npmjs.org/docker-compose/-/docker-compose-0.24.8.tgz", @@ -53,11 +280,301 @@ "url": "https://dotenvx.com" } }, + "node_modules/err-code": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/err-code/-/err-code-3.0.1.tgz", + "integrity": "sha512-GiaH0KJUewYok+eeY05IIgjtAe4Yltygk9Wqp1V5yVWLdhf0hYZchRjNIT9bb0mSwRcIusT3cx7PJUf3zEIfUA==" + }, + "node_modules/event-target-shim": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", + "engines": { + "node": ">=6" + } + }, + "node_modules/fast-fifo": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.3.2.tgz", + "integrity": "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==" + }, + "node_modules/fetch-blob": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", + "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "paypal", + "url": "https://paypal.me/jimmywarting" + } + ], + "dependencies": { + "node-domexception": "^1.0.0", + "web-streams-polyfill": "^3.0.3" + }, + "engines": { + "node": "^12.20 || >= 14.13" + } + }, + "node_modules/formdata-polyfill": { + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", + "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", + "dependencies": { + "fetch-blob": "^3.1.2" + }, + "engines": { + "node": ">=12.20.0" + } + }, + "node_modules/get-browser-rtc": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/get-browser-rtc/-/get-browser-rtc-1.1.0.tgz", + "integrity": "sha512-MghbMJ61EJrRsDe7w1Bvqt3ZsBuqhce5nrn/XAwgwOXhcsz53/ltdxOse1h/8eKXj5slzxdsz56g5rzOFSGwfQ==" + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "node_modules/ip": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.9.tgz", + "integrity": "sha512-cyRxvOEpNHNtchU3Ln9KC/auJgup87llfQpQ+t5ghoC/UhL16SWzbueiCsdTnWmqAWl7LadfuwhlqmtOaqMHdQ==" + }, + "node_modules/ip-address": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-9.0.5.tgz", + "integrity": "sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==", + "dependencies": { + "jsbn": "1.1.0", + "sprintf-js": "^1.1.3" + }, + "engines": { + "node": ">= 12" + } + }, + "node_modules/ipaddr.js": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.2.0.tgz", + "integrity": "sha512-Ag3wB2o37wslZS19hZqorUnrnzSkpOVy+IiiDEiTqNubEYpYuHWIf6K4psgN2ZWKExS4xhVCrRVfb/wfW8fWJA==", + "engines": { + "node": ">= 10" + } + }, + "node_modules/jsbn": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz", + "integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==" + }, "node_modules/lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, + "node_modules/lru": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/lru/-/lru-3.1.0.tgz", + "integrity": "sha512-5OUtoiVIGU4VXBOshidmtOsvBIvcQR6FD/RzWSvaeHyxCGB+PCUCu+52lqMfdc0h/2CLvHhZS4TwUmMQrrMbBQ==", + "dependencies": { + "inherits": "^2.0.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/node-domexception": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", + "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "github", + "url": "https://paypal.me/jimmywarting" + } + ], + "engines": { + "node": ">=10.5.0" + } + }, + "node_modules/node-fetch": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz", + "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==", + "dependencies": { + "data-uri-to-buffer": "^4.0.0", + "fetch-blob": "^3.1.4", + "formdata-polyfill": "^4.0.10" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/node-fetch" + } + }, + "node_modules/node-gyp-build": { + "version": "4.8.1", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.1.tgz", + "integrity": "sha512-OSs33Z9yWr148JZcbZd5WiAXhh/n9z8TxQcdMhIOlpN9AhWpLfvVFO73+m77bBABQMaY9XSvIa+qk0jlI7Gcaw==", + "optional": true, + "bin": { + "node-gyp-build": "bin.js", + "node-gyp-build-optional": "optional.js", + "node-gyp-build-test": "build-test.js" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/queue-tick": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/queue-tick/-/queue-tick-1.0.1.tgz", + "integrity": "sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag==" + }, + "node_modules/random-iterate": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/random-iterate/-/random-iterate-1.0.1.tgz", + "integrity": "sha512-Jdsdnezu913Ot8qgKgSgs63XkAjEsnMcS1z+cC6D6TNXsUXsMxy0RpclF2pzGZTEiTXL9BiArdGTEexcv4nqcA==" + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/run-series": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/run-series/-/run-series-1.1.9.tgz", + "integrity": "sha512-Arc4hUN896vjkqCYrUXquBFtRZdv1PfLbTYP71efP6butxyQ0kWpiNJyAgsxscmQg1cqvHY32/UCBzXedTpU2g==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/smart-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", + "engines": { + "node": ">= 6.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks": { + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.3.tgz", + "integrity": "sha512-l5x7VUUWbjVFbafGLxPWkYsHIhEvmF85tbIeFZWc8ZPtoMyybuEhL7Jye/ooC4/d48FgOjSJXgsF/AJPYCW8Zw==", + "dependencies": { + "ip-address": "^9.0.5", + "smart-buffer": "^4.2.0" + }, + "engines": { + "node": ">= 10.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/sprintf-js": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz", + "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==" + }, + "node_modules/streamx": { + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.16.1.tgz", + "integrity": "sha512-m9QYj6WygWyWa3H1YY69amr4nVgy61xfjys7xO7kviL5rfIEc2naf+ewFiOA+aEJD7y0JO3h2GoiUv4TDwEGzQ==", + "dependencies": { + "fast-fifo": "^1.1.0", + "queue-tick": "^1.0.1" + }, + "optionalDependencies": { + "bare-events": "^2.2.0" + } + }, + "node_modules/string2compact": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/string2compact/-/string2compact-2.0.1.tgz", + "integrity": "sha512-Bm/T8lHMTRXw+u83LE+OW7fXmC/wM+Mbccfdo533ajSBNxddDHlRrvxE49NdciGHgXkUQM5WYskJ7uTkbBUI0A==", + "dependencies": { + "addr-to-ip-port": "^2.0.0", + "ipaddr.js": "^2.0.0" + }, + "engines": { + "node": ">=12.20.0" + } + }, "node_modules/transmission": { "version": "0.4.10", "resolved": "https://registry.npmjs.org/transmission/-/transmission-0.4.10.tgz", @@ -83,12 +600,71 @@ "node": ">=14.17" } }, + "node_modules/uint8-util": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/uint8-util/-/uint8-util-2.2.4.tgz", + "integrity": "sha512-uEI5lLozmKQPYEevfEhP9LY3Je5ZmrQhaWXrzTVqrLNQl36xsRh8NiAxYwB9J+2BAt99TRbmCkROQB2ZKhx4UA==", + "dependencies": { + "base64-arraybuffer": "^1.0.2" + } + }, "node_modules/undici-types": { "version": "5.26.5", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", "dev": true }, + "node_modules/unordered-array-remove": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/unordered-array-remove/-/unordered-array-remove-1.0.2.tgz", + "integrity": "sha512-45YsfD6svkgaCBNyvD+dFHm4qFX9g3wRSIVgWVPtm2OCnphvPxzJoe20ATsiNpNJrmzHifnxm+BN5F7gFT/4gw==" + }, + "node_modules/utf-8-validate": { + "version": "5.0.10", + "resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.10.tgz", + "integrity": "sha512-Z6czzLq4u8fPOyx7TU6X3dvUZVvoJmxSQ+IcrlmagKhilxlhZgxPK6C5Jqbkw1IDUmFTM+cz9QDnnLTwDz/2gQ==", + "hasInstallScript": true, + "optional": true, + "dependencies": { + "node-gyp-build": "^4.3.0" + }, + "engines": { + "node": ">=6.14.2" + } + }, + "node_modules/web-streams-polyfill": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz", + "integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==", + "engines": { + "node": ">= 8" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" + }, + "node_modules/ws": { + "version": "8.17.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.0.tgz", + "integrity": "sha512-uJq6108EgZMAl20KagGkzCKfMEjxmKvZHG7Tlq0Z6nOky7YF7aq4mOx6xK8TJ/i1LeK4Qus7INktacctDgY8Ow==", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, "node_modules/yaml": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.4.1.tgz", @@ -107,6 +683,31 @@ } }, "dependencies": { + "@thaunknown/simple-peer": { + "version": "9.12.1", + "resolved": "https://registry.npmjs.org/@thaunknown/simple-peer/-/simple-peer-9.12.1.tgz", + "integrity": "sha512-IS5BXvXx7cvBAzaxqotJf4s4rJCPk5JABLK6Gbnn7oAmWVcH4hYABabBBrvvJtv/xyUqR4v/H3LalnGRJJfEog==", + "requires": { + "debug": "^4.3.2", + "err-code": "^3.0.1", + "get-browser-rtc": "^1.1.0", + "queue-microtask": "^1.2.3", + "streamx": "^2.13.2", + "uint8-util": "^2.1.9" + } + }, + "@thaunknown/simple-websocket": { + "version": "9.1.1", + "resolved": "https://registry.npmjs.org/@thaunknown/simple-websocket/-/simple-websocket-9.1.1.tgz", + "integrity": "sha512-vzQloFWRodRZqZhpxMpBljFtISesY8TihA8T5uKwCYdj2I1ImMhE/gAeTCPsCGOtxJfGKu3hw/is6MXauWLjOg==", + "requires": { + "debug": "^4.3.4", + "queue-microtask": "^1.2.3", + "streamx": "^2.13.2", + "uint8-util": "^2.1.9", + "ws": "^8.12.0" + } + }, "@types/node": { "version": "20.12.7", "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.7.tgz", @@ -116,6 +717,19 @@ "undici-types": "~5.26.4" } }, + "abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "requires": { + "event-target-shim": "^5.0.0" + } + }, + "addr-to-ip-port": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/addr-to-ip-port/-/addr-to-ip-port-2.0.0.tgz", + "integrity": "sha512-9bYbtjamtdLHZSqVIUXhilOryNPiL+x+Q5J/Unpg4VY3ZIkK3fT52UoErj1NdUeVm3J1t2iBEAur4Ywbl/bahw==" + }, "async": { "version": "2.6.4", "resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz", @@ -124,6 +738,114 @@ "lodash": "^4.17.14" } }, + "bare-events": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.2.2.tgz", + "integrity": "sha512-h7z00dWdG0PYOQEvChhOSWvOfkIKsdZGkWr083FgN/HyoQuebSew/cgirYqh9SCuy/hRvxc5Vy6Fw8xAmYHLkQ==", + "optional": true + }, + "base64-arraybuffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz", + "integrity": "sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ==" + }, + "bencode": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/bencode/-/bencode-4.0.0.tgz", + "integrity": "sha512-AERXw18df0pF3ziGOCyUjqKZBVNH8HV3lBxnx5w0qtgMIk4a1wb9BkcCQbkp9Zstfrn/dzRwl7MmUHHocX3sRQ==", + "requires": { + "uint8-util": "^2.2.2" + } + }, + "bittorrent-peerid": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/bittorrent-peerid/-/bittorrent-peerid-1.3.6.tgz", + "integrity": "sha512-VyLcUjVMEOdSpHaCG/7odvCdLbAB1y3l9A2V6WIje24uV7FkJPrQrH/RrlFmKxP89pFVDEnE+YlHaFujlFIZsg==" + }, + "bittorrent-tracker": { + "version": "11.0.2", + "resolved": "https://registry.npmjs.org/bittorrent-tracker/-/bittorrent-tracker-11.0.2.tgz", + "integrity": "sha512-MUv1zqWd1OZKPkgncj9JkpumhtF2Q+xeHptz8rJz+APK5/ZIAOIiHyLqDmoDL06JMa1iHPmeOlJG8I5Hi1UIbw==", + "requires": { + "@thaunknown/simple-peer": "^9.12.1", + "@thaunknown/simple-websocket": "^9.1.0", + "bencode": "^4.0.0", + "bittorrent-peerid": "^1.3.3", + "bufferutil": "^4.0.3", + "chrome-dgram": "^3.0.6", + "clone": "^2.0.0", + "compact2string": "^1.4.1", + "cross-fetch-ponyfill": "^1.0.1", + "debug": "^4.1.1", + "ip": "^1.1.5", + "lru": "^3.1.0", + "minimist": "^1.2.5", + "once": "^1.4.0", + "queue-microtask": "^1.2.3", + "random-iterate": "^1.0.1", + "run-parallel": "^1.2.0", + "run-series": "^1.1.9", + "socks": "^2.0.0", + "string2compact": "^2.0.0", + "uint8-util": "^2.1.9", + "unordered-array-remove": "^1.0.2", + "utf-8-validate": "^5.0.5", + "ws": "^8.0.0" + } + }, + "bufferutil": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-4.0.8.tgz", + "integrity": "sha512-4T53u4PdgsXqKaIctwF8ifXlRTTmEPJ8iEPWFdGZvcf7sbwYo6FKFEX9eNNAnzFZ7EzJAQ3CJeOtCRA4rDp7Pw==", + "optional": true, + "requires": { + "node-gyp-build": "^4.3.0" + } + }, + "chrome-dgram": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/chrome-dgram/-/chrome-dgram-3.0.6.tgz", + "integrity": "sha512-bqBsUuaOiXiqxXt/zA/jukNJJ4oaOtc7ciwqJpZVEaaXwwxqgI2/ZdG02vXYWUhHGziDlvGMQWk0qObgJwVYKA==", + "requires": { + "inherits": "^2.0.4", + "run-series": "^1.1.9" + } + }, + "clone": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", + "integrity": "sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==" + }, + "compact2string": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/compact2string/-/compact2string-1.4.1.tgz", + "integrity": "sha512-3D+EY5nsRhqnOwDxveBv5T8wGo4DEvYxjDtPGmdOX+gfr5gE92c2RC0w2wa+xEefm07QuVqqcF3nZJUZ92l/og==", + "requires": { + "ipaddr.js": ">= 0.1.5" + } + }, + "cross-fetch-ponyfill": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/cross-fetch-ponyfill/-/cross-fetch-ponyfill-1.0.3.tgz", + "integrity": "sha512-uOBkDhUAGAbx/FEzNKkOfx3w57H8xReBBXoZvUnOKTI0FW0Xvrj3GrYv2iZXUqlffC1LMGfQzhmBM/ke+6eTDA==", + "requires": { + "abort-controller": "^3.0.0", + "node-fetch": "^3.3.0" + } + }, + "data-uri-to-buffer": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", + "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==" + }, + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "requires": { + "ms": "2.1.2" + } + }, "docker-compose": { "version": "0.24.8", "resolved": "https://registry.npmjs.org/docker-compose/-/docker-compose-0.24.8.tgz", @@ -137,11 +859,190 @@ "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.5.tgz", "integrity": "sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==" }, + "err-code": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/err-code/-/err-code-3.0.1.tgz", + "integrity": "sha512-GiaH0KJUewYok+eeY05IIgjtAe4Yltygk9Wqp1V5yVWLdhf0hYZchRjNIT9bb0mSwRcIusT3cx7PJUf3zEIfUA==" + }, + "event-target-shim": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==" + }, + "fast-fifo": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.3.2.tgz", + "integrity": "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==" + }, + "fetch-blob": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", + "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==", + "requires": { + "node-domexception": "^1.0.0", + "web-streams-polyfill": "^3.0.3" + } + }, + "formdata-polyfill": { + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", + "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", + "requires": { + "fetch-blob": "^3.1.2" + } + }, + "get-browser-rtc": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/get-browser-rtc/-/get-browser-rtc-1.1.0.tgz", + "integrity": "sha512-MghbMJ61EJrRsDe7w1Bvqt3ZsBuqhce5nrn/XAwgwOXhcsz53/ltdxOse1h/8eKXj5slzxdsz56g5rzOFSGwfQ==" + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "ip": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.9.tgz", + "integrity": "sha512-cyRxvOEpNHNtchU3Ln9KC/auJgup87llfQpQ+t5ghoC/UhL16SWzbueiCsdTnWmqAWl7LadfuwhlqmtOaqMHdQ==" + }, + "ip-address": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-9.0.5.tgz", + "integrity": "sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==", + "requires": { + "jsbn": "1.1.0", + "sprintf-js": "^1.1.3" + } + }, + "ipaddr.js": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.2.0.tgz", + "integrity": "sha512-Ag3wB2o37wslZS19hZqorUnrnzSkpOVy+IiiDEiTqNubEYpYuHWIf6K4psgN2ZWKExS4xhVCrRVfb/wfW8fWJA==" + }, + "jsbn": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz", + "integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==" + }, "lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, + "lru": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/lru/-/lru-3.1.0.tgz", + "integrity": "sha512-5OUtoiVIGU4VXBOshidmtOsvBIvcQR6FD/RzWSvaeHyxCGB+PCUCu+52lqMfdc0h/2CLvHhZS4TwUmMQrrMbBQ==", + "requires": { + "inherits": "^2.0.1" + } + }, + "minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==" + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node-domexception": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", + "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==" + }, + "node-fetch": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz", + "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==", + "requires": { + "data-uri-to-buffer": "^4.0.0", + "fetch-blob": "^3.1.4", + "formdata-polyfill": "^4.0.10" + } + }, + "node-gyp-build": { + "version": "4.8.1", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.1.tgz", + "integrity": "sha512-OSs33Z9yWr148JZcbZd5WiAXhh/n9z8TxQcdMhIOlpN9AhWpLfvVFO73+m77bBABQMaY9XSvIa+qk0jlI7Gcaw==", + "optional": true + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "requires": { + "wrappy": "1" + } + }, + "queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==" + }, + "queue-tick": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/queue-tick/-/queue-tick-1.0.1.tgz", + "integrity": "sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag==" + }, + "random-iterate": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/random-iterate/-/random-iterate-1.0.1.tgz", + "integrity": "sha512-Jdsdnezu913Ot8qgKgSgs63XkAjEsnMcS1z+cC6D6TNXsUXsMxy0RpclF2pzGZTEiTXL9BiArdGTEexcv4nqcA==" + }, + "run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "requires": { + "queue-microtask": "^1.2.2" + } + }, + "run-series": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/run-series/-/run-series-1.1.9.tgz", + "integrity": "sha512-Arc4hUN896vjkqCYrUXquBFtRZdv1PfLbTYP71efP6butxyQ0kWpiNJyAgsxscmQg1cqvHY32/UCBzXedTpU2g==" + }, + "smart-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==" + }, + "socks": { + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.3.tgz", + "integrity": "sha512-l5x7VUUWbjVFbafGLxPWkYsHIhEvmF85tbIeFZWc8ZPtoMyybuEhL7Jye/ooC4/d48FgOjSJXgsF/AJPYCW8Zw==", + "requires": { + "ip-address": "^9.0.5", + "smart-buffer": "^4.2.0" + } + }, + "sprintf-js": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz", + "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==" + }, + "streamx": { + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.16.1.tgz", + "integrity": "sha512-m9QYj6WygWyWa3H1YY69amr4nVgy61xfjys7xO7kviL5rfIEc2naf+ewFiOA+aEJD7y0JO3h2GoiUv4TDwEGzQ==", + "requires": { + "bare-events": "^2.2.0", + "fast-fifo": "^1.1.0", + "queue-tick": "^1.0.1" + } + }, + "string2compact": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/string2compact/-/string2compact-2.0.1.tgz", + "integrity": "sha512-Bm/T8lHMTRXw+u83LE+OW7fXmC/wM+Mbccfdo533ajSBNxddDHlRrvxE49NdciGHgXkUQM5WYskJ7uTkbBUI0A==", + "requires": { + "addr-to-ip-port": "^2.0.0", + "ipaddr.js": "^2.0.0" + } + }, "transmission": { "version": "0.4.10", "resolved": "https://registry.npmjs.org/transmission/-/transmission-0.4.10.tgz", @@ -157,12 +1058,50 @@ "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==", "dev": true }, + "uint8-util": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/uint8-util/-/uint8-util-2.2.4.tgz", + "integrity": "sha512-uEI5lLozmKQPYEevfEhP9LY3Je5ZmrQhaWXrzTVqrLNQl36xsRh8NiAxYwB9J+2BAt99TRbmCkROQB2ZKhx4UA==", + "requires": { + "base64-arraybuffer": "^1.0.2" + } + }, "undici-types": { "version": "5.26.5", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", "dev": true }, + "unordered-array-remove": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/unordered-array-remove/-/unordered-array-remove-1.0.2.tgz", + "integrity": "sha512-45YsfD6svkgaCBNyvD+dFHm4qFX9g3wRSIVgWVPtm2OCnphvPxzJoe20ATsiNpNJrmzHifnxm+BN5F7gFT/4gw==" + }, + "utf-8-validate": { + "version": "5.0.10", + "resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.10.tgz", + "integrity": "sha512-Z6czzLq4u8fPOyx7TU6X3dvUZVvoJmxSQ+IcrlmagKhilxlhZgxPK6C5Jqbkw1IDUmFTM+cz9QDnnLTwDz/2gQ==", + "optional": true, + "requires": { + "node-gyp-build": "^4.3.0" + } + }, + "web-streams-polyfill": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz", + "integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==" + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" + }, + "ws": { + "version": "8.17.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.0.tgz", + "integrity": "sha512-uJq6108EgZMAl20KagGkzCKfMEjxmKvZHG7Tlq0Z6nOky7YF7aq4mOx6xK8TJ/i1LeK4Qus7INktacctDgY8Ow==", + "requires": {} + }, "yaml": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.4.1.tgz", diff --git a/package.json b/package.json index 2f1b44d..336fe65 100644 --- a/package.json +++ b/package.json @@ -1,12 +1,14 @@ { "scripts": { - "start": "npx ts-node src/index.ts" + "start": "npx tsx src/index.ts" }, "devDependencies": { "@types/node": "^20.12.7", "typescript": "^5.4.5" }, + "type": "module", "dependencies": { + "bittorrent-tracker": "^11.0.2", "docker-compose": "^0.24.8", "dotenv": "^16.4.5", "transmission": "^0.4.10" diff --git a/src/index.ts b/src/index.ts index 1fe200e..608da40 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,12 +1,24 @@ import { setPortFlow } from './set-port-flow'; import { settings } from './settings'; +import { trackerServer } from './tracker/tracker'; +import { kvDataStorage } from './services/kv-data-storage'; +import { onTrackerAnnounce } from './tracker-announce-flow'; const isWorker = process.argv[2] === 'worker'; if (isWorker) { - //initial timeout is in case of a crash to not flood everything - console.log(`Starting worker, first check in ${settings.updateIntervalMs/1000}s`); - setTimeout(worker, settings.updateIntervalMs); + trackerServer.on('announce', onTrackerAnnounce); + + const lastRun = kvDataStorage.get('lastRun') || 0; + const sinceLastRun = Date.now() - lastRun; + if (sinceLastRun > settings.updateIntervalMs) { + console.log(`Starting worker, check now`); + worker(); + } else { + console.log(`Starting worker, first check in ${(settings.updateIntervalMs - sinceLastRun)/1000}s`); + setTimeout(worker, settings.updateIntervalMs - sinceLastRun); + } + } else { setPortFlow() .then(() => console.log('All done')) diff --git a/src/check-in.ts b/src/services/daily-check-in.ts similarity index 100% rename from src/check-in.ts rename to src/services/daily-check-in.ts diff --git a/src/docker.ts b/src/services/docker.ts similarity index 80% rename from src/docker.ts rename to src/services/docker.ts index bb72150..8fb0479 100644 --- a/src/docker.ts +++ b/src/services/docker.ts @@ -1,5 +1,5 @@ import { v2 as compose } from 'docker-compose'; -import { settings } from './settings'; +import { settings } from '../settings'; type IPInfo = { ip: string, @@ -60,11 +60,4 @@ export class DockerContainer { ip: dataRaw[6], } } - - async setOpenFirewallPort(port: number) { - const {exitCode: exit0} = await this.exec(`iptables -A INPUT -i tun0 -p tcp --dport ${port} -j ACCEPT`); - const {exitCode: exit1} = await this.exec(`iptables -A INPUT -i tun0 -p udp --dport ${port} -j ACCEPT`); - - return exit0 === 0 && exit1 === 0; - } } diff --git a/src/services/gluetun-container.ts b/src/services/gluetun-container.ts new file mode 100644 index 0000000..071287c --- /dev/null +++ b/src/services/gluetun-container.ts @@ -0,0 +1,21 @@ +import { DockerContainer } from './docker'; +import { settings } from '../settings'; + +export class GluetunContainer extends DockerContainer { + constructor() { + super( + settings.dockerGluetun.service, + settings.dockerGluetun.cwd, + settings.dockerGluetun.serviceName + ); + } + + async setOpenFirewallPort(port: number) { + const {exitCode: exit0} = await this.exec(`iptables -A INPUT -i tun0 -p tcp --dport ${port} -j ACCEPT`); + const {exitCode: exit1} = await this.exec(`iptables -A INPUT -i tun0 -p udp --dport ${port} -j ACCEPT`); + + return exit0 === 0 && exit1 === 0; + } +} + +export const gluetunContainer = new GluetunContainer(); diff --git a/src/kv-data-storage.ts b/src/services/kv-data-storage.ts similarity index 94% rename from src/kv-data-storage.ts rename to src/services/kv-data-storage.ts index b1dca4a..608dbdc 100644 --- a/src/kv-data-storage.ts +++ b/src/services/kv-data-storage.ts @@ -2,6 +2,9 @@ import { writeFile } from 'fs/promises'; import { join } from 'path'; import { existsSync, readFileSync } from 'fs'; +import path from 'path'; +const __dirname = path.resolve(); + class KeyValueDataStorage { private readonly data: Record = {}; private readonly filePath: string; diff --git a/src/notification.ts b/src/services/notification.ts similarity index 94% rename from src/notification.ts rename to src/services/notification.ts index c56be28..103592c 100644 --- a/src/notification.ts +++ b/src/services/notification.ts @@ -1,4 +1,4 @@ -import { settings } from './settings'; +import { settings } from '../settings'; class NotificationService { async sendNotification(message: string, important = false) { diff --git a/src/transmission.ts b/src/services/transmission-client.ts similarity index 90% rename from src/transmission.ts rename to src/services/transmission-client.ts index abe5948..2b543ea 100644 --- a/src/transmission.ts +++ b/src/services/transmission-client.ts @@ -1,5 +1,6 @@ // @ts-ignore import TransmissionClient from 'transmission'; +import { settings } from '../settings'; type TransmissionOptions = { url?: string; @@ -48,3 +49,5 @@ export class Transmission { }); } } + +export const transmissionClient = new Transmission(settings.transmission); diff --git a/src/services/transmission-container.ts b/src/services/transmission-container.ts new file mode 100644 index 0000000..37a4cbe --- /dev/null +++ b/src/services/transmission-container.ts @@ -0,0 +1,25 @@ +import { DockerContainer } from './docker'; +import { settings } from '../settings'; +import { kvDataStorage } from './kv-data-storage'; +import { notificationService } from './notification'; + +export class TransmissionContainer extends DockerContainer { + constructor() { + super( + settings.dockerTransmission.service, + settings.dockerTransmission.cwd, + settings.dockerTransmission.serviceName + ); + } + + async downTransmission(reason: string) { + console.log(reason); + + await kvDataStorage.set({ isServiceRunning: false }); + await notificationService.sendNotification(reason, true); + + return await this.down(); + } +} + +export const transmissionContainer = new TransmissionContainer(); diff --git a/src/set-port-flow.ts b/src/set-port-flow.ts index 8f28660..3557156 100644 --- a/src/set-port-flow.ts +++ b/src/set-port-flow.ts @@ -1,41 +1,22 @@ -import { Transmission } from './transmission'; -import { DockerContainer } from './docker'; +import { transmissionClient } from './services/transmission-client'; import { settings } from './settings'; -import { notificationService } from './notification'; -import { kvDataStorage } from './kv-data-storage'; -import { dailyCheckIn } from './check-in'; - -async function downTransmission(transmissionContainer: DockerContainer, reason: string) { - console.log(reason); - - await kvDataStorage.set({ isServiceRunning: false }); - await notificationService.sendNotification(reason, true); - return await transmissionContainer.down(); -} +import { notificationService } from './services/notification'; +import { kvDataStorage } from './services/kv-data-storage'; +import { dailyCheckIn } from './services/daily-check-in'; +import { transmissionContainer } from './services/transmission-container'; +import { gluetunContainer } from './services/gluetun-container'; export async function setPortFlow() { - const transmissionClient = new Transmission(settings.transmission); - const transmissionContainer = new DockerContainer( - settings.dockerTransmission.service, - settings.dockerTransmission.cwd, - settings.dockerTransmission.serviceName - ); - const gluetunContainer = new DockerContainer( - settings.dockerGluetun.service, - settings.dockerGluetun.cwd, - settings.dockerGluetun.serviceName - ); - try { - await doSetPortFlow(transmissionClient, transmissionContainer, gluetunContainer); + await doSetPortFlow(); } catch (e) { console.error('Error in set port flow', e); - await downTransmission(transmissionContainer, `Shutting down: error in set port flow.`); + await transmissionContainer.downTransmission(`Shutting down: error in set port flow.`) } await dailyCheckIn(); } -async function doSetPortFlow(transmissionClient: Transmission, transmissionContainer: DockerContainer, gluetunContainer: DockerContainer) { +async function doSetPortFlow() { console.log('Starting set port flow'); const containerState = await transmissionContainer.getState(); @@ -58,12 +39,25 @@ async function doSetPortFlow(transmissionClient: Transmission, transmissionConta console.log(`External ip: ${ipInfo?.ip} Country: ${ipInfo?.country}`); if (!defaultInterface || !ipInfo) { - return await downTransmission( - transmissionContainer, + await kvDataStorage.set({ + country: null, + internalIp: null, + externalIp: null, + interface: null, + }) + + return await transmissionContainer.downTransmission( `Shutting down: defaultInterface: ${!!defaultInterface} ipInfo: ${!!ipInfo}`, ); } + await kvDataStorage.set({ + country: ipInfo.country, + internalIp: defaultInterface.ip, + externalIp: ipInfo.ip, + interface: defaultInterface.interface, + }) + const countryOK = !settings.disallowedCountries.some((country) => ipInfo.country.includes(country)); const internalIpOK = !settings.disallowedIntIps.some((ip) => defaultInterface.ip.includes(ip)); const externalIpOK = !settings.disallowedExtIps.some((ip) => ipInfo.ip.includes(ip)); @@ -72,8 +66,7 @@ async function doSetPortFlow(transmissionClient: Transmission, transmissionConta console.log(`Country OK: ${countryOK} Internal IP OK: ${internalIpOK} External IP OK: ${externalIpOK} Interface OK: ${interfaceOK}`); if (!countryOK || !internalIpOK || !externalIpOK || !interfaceOK) { - return await downTransmission( - transmissionContainer, + return await transmissionContainer.downTransmission( `Shutting down: Country OK: ${countryOK}, Internal IP OK: ${internalIpOK}, External IP OK: ${externalIpOK}, Interface OK: ${interfaceOK}.`, ); } @@ -92,8 +85,7 @@ async function doSetPortFlow(transmissionClient: Transmission, transmissionConta console.log(`Data received: ${JSON.stringify(data)}`); if (!data.status || !data.supported) { - return await downTransmission( - transmissionContainer, + return await transmissionContainer.downTransmission( `Shutting down: could not fetch new port, data: ${JSON.stringify(data)}`, ); } @@ -101,8 +93,7 @@ async function doSetPortFlow(transmissionClient: Transmission, transmissionConta const newPort= Number(data.status.split(" ")[1]); if (!newPort) { - return await downTransmission( - transmissionContainer, + return await transmissionContainer.downTransmission( `Shutting down: could not parse new port, data: ${JSON.stringify(data)}`, ); } @@ -110,8 +101,7 @@ async function doSetPortFlow(transmissionClient: Transmission, transmissionConta console.log(`Setting port to ${newPort}`); const resultOK = await gluetunContainer.setOpenFirewallPort(newPort); if (!resultOK) { - return await downTransmission( - transmissionContainer, + return await transmissionContainer.downTransmission( `Shutting down: could not open new port in gluetun firewall`, ); } @@ -126,8 +116,7 @@ async function doSetPortFlow(transmissionClient: Transmission, transmissionConta console.log(`Port ${newPort} is open: ${newPortOpen}`); if (!newPortOpen) { - return await downTransmission( - transmissionContainer, + return await transmissionContainer.downTransmission( `Shutting down: new port is still not open, data: ${JSON.stringify(data)}`, ); } diff --git a/src/settings.ts b/src/settings.ts index 200469e..4767821 100644 --- a/src/settings.ts +++ b/src/settings.ts @@ -24,4 +24,6 @@ export const settings = { disallowedExtIps: process.env.DISALLOWED_EXT_IPS?.split(',') ?? [], discordWebhookUrl: process.env.DISCORD_WEBHOOK_URL, updateIntervalMs: (Number(process.env.UPDATE_INTERVAL_SECONDS) ?? 60 * 5) * 1000, + trackerToken: process.env.TRACKER_TOKEN, + trackerPort: Number(process.env.TRACKER_PORT), } as const; diff --git a/src/tracker-announce-flow.ts b/src/tracker-announce-flow.ts new file mode 100644 index 0000000..1a46922 --- /dev/null +++ b/src/tracker-announce-flow.ts @@ -0,0 +1,38 @@ +import { TrackerAnnounceData } from './tracker/types'; +import { settings } from './settings'; +import { transmissionContainer } from './services/transmission-container'; +import { kvDataStorage } from './services/kv-data-storage'; +import { notificationService } from './services/notification'; + +export const onTrackerAnnounce = async (data: TrackerAnnounceData) => { + //check if ip is allowed + if (settings.disallowedIntIps.some((ip) => data.ip.includes(ip)) || settings.disallowedExtIps.some((ip) => data.ip.includes(ip))) { + console.log(`Announce from disallowed ip ${data.ip}`); + const transmissionContainerStatus = await transmissionContainer.getState() || { state: 'unknown' }; + if (transmissionContainerStatus.state !== 'running') { + const lastNotRunningButAnnouncedNotification = kvDataStorage.get('lastNotRunningButAnnouncedNotification') || 0; + if (Date.now() - lastNotRunningButAnnouncedNotification < 60 * 60 * 1000) { + return; + } + await notificationService.sendNotification(`Announce from disallowed ip ${data.ip}, but transmission is not running`, true); + await kvDataStorage.set({ lastNotRunningButAnnouncedNotification: Date.now() }); + return; + } + await transmissionContainer.downTransmission(`Shutting down: announce from disallowed ip ${data.ip}`); + return; + } + + //check if ip matches external ip + const externalIp = kvDataStorage.get('externalIp') || '0.0.0.0'; + if (data.ip !== externalIp) { + const ipMismatchCount = kvDataStorage.get('ipMismatchCount') || 0; + if (ipMismatchCount > 2) { + console.log(`Announce from ip ${data.ip} but external ip is ${externalIp}`); + await transmissionContainer.downTransmission(`Shutting down: announce from ip ${data.ip} but external ip is ${externalIp}`); + } + await kvDataStorage.set({ ipMismatchCount: ipMismatchCount + 1 }); + + return; + } + await kvDataStorage.set({ ipMismatchCount: 0 }); +}; diff --git a/src/tracker/tracker.ts b/src/tracker/tracker.ts new file mode 100644 index 0000000..f643f00 --- /dev/null +++ b/src/tracker/tracker.ts @@ -0,0 +1,95 @@ +// @ts-ignore +import { Server } from 'bittorrent-tracker'; +import { TrackerAnnounceData, TrackerParams } from './types'; +import { settings } from '../settings'; + +export const trackerServer = new Server({ + udp: true, // enable udp server? [default=true] + http: true, // enable http server? [default=true] + ws: true, // enable websocket server? [default=true] + stats: false, // enable web-based statistics? [default=true] + trustProxy: false, // enable trusting x-forwarded-for header for remote IP [default=false] + interval: 3 * 60 * 1000, + filter: function (infoHash: string, params: TrackerParams, cb: (arg0: Error | null) => void) { + console.log(`tracker announced from ${params.addr} with correct token ${params.token === process.env.TRACKER_TOKEN}`); + if (settings.trackerToken && params.token === settings.trackerToken) { + const announceData: TrackerAnnounceData = { + infoHash, + ip: params.ip, + port: params.port, + addr: params.addr, + token: params.token, + } + this.emit('announce', announceData); + cb(null) + } else { + cb(new Error('unauthorised')) + } + } +}) + +trackerServer.on('error', function (err: { message: any; }) { + console.log('tracker server error', err.message) +}) + +trackerServer.on('warning', function (err: { message: any; }) { + console.log('tracker server warning',err.message) +}) + +// trackerServer.on('listening', function () { +// // fired when all requested servers are listening +// +// // HTTP +// const httpAddr = trackerServer.http.address() +// const httpHost = httpAddr.address !== '::' ? httpAddr.address : 'localhost' +// const httpPort = httpAddr.port +// console.log(`HTTP tracker: http://${httpHost}:${httpPort}/announce`) +// +// // UDP +// const udpAddr = trackerServer.udp.address() +// const udpHost = udpAddr.address +// const udpPort = udpAddr.port +// console.log(`UDP tracker: udp://${udpHost}:${udpPort}`) +// +// // WS +// const wsAddr = trackerServer.ws.address() +// const wsHost = wsAddr.address !== '::' ? wsAddr.address : 'localhost' +// const wsPort = wsAddr.port +// console.log(`WebSocket tracker: ws://${wsHost}:${wsPort}`) +// +// }) + + +// start tracker server listening! Use 0 to listen on a random free port. +const port = settings.trackerPort; +trackerServer.listen(port, () => { + console.log(`tracker listening on port ${port}`) +}) + +// trackerServer.on('start', function (addr: string) { +// console.log('got start message from ' + addr) +// }) +// trackerServer.on('complete', function (addr: string) { +// console.log('got complete message from ' + addr) +// }) +// trackerServer.on('update', function (addr: string) { +// console.log('got update message from ' + addr) +// }) +// trackerServer.on('stop', function (addr: string) { +// console.log('got stop message from ' + addr) +// }) +// trackerServer.on('announce', function (data: TrackerAnnounceData) { +// console.log('got announce message', data) +// }) + +// // get info hashes for all torrents in the tracker server +// Object.keys(trackerServer.torrents) + +// // get the number of seeders for a particular torrent +// trackerServer.torrents[infoHash].complete + +// // get the number of leechers for a particular torrent +// trackerServer.torrents[infoHash].incomplete + +// // get the peers who are in a particular torrent swarm +// trackerServer.torrents[infoHash].peers diff --git a/src/tracker/types.ts b/src/tracker/types.ts new file mode 100644 index 0000000..85f437a --- /dev/null +++ b/src/tracker/types.ts @@ -0,0 +1,36 @@ +export type TrackerParams = { + token: string, + info_hash: string, + peer_id: string, + port: number, + uploaded: string, // string number bytes + downloaded: string, // string number bytes + left: number, + corrupt?: string, // string number bytes + numwant: number, + key: string, + event?: string, // started, completed, stopped + compact: number, + no_peer_id?: string, // "1" or "0" + supportcrypto: string, // "1" or "0" + redundant?: string, // "1" or "0" + type: string, // http, udp, ws + action: number, // 1? + ip: string, + addr: string, // ip:port + headers: { + host: string, + "user-agent": string, + accept?: string, + "accept-encoding": string, + connection?: string, + } +} + +export type TrackerAnnounceData = { + infoHash: string, + ip: string, + port: number, + addr: string, + token: string, +} diff --git a/tsconfig.json b/tsconfig.json index e075f97..3a97d2b 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,5 +1,12 @@ { "compilerOptions": { + "target": "esnext", + "module": "esnext", + "moduleResolution": "node", + "allowJs": true, + "esModuleInterop": true, + "allowSyntheticDefaultImports": true, + "sourceMap": true, /* Visit https://aka.ms/tsconfig to read more about this file */ /* Projects */ @@ -11,7 +18,7 @@ // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ /* Language and Environment */ - "target": "es2016", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ +// "target": "es2016", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ // "jsx": "preserve", /* Specify what JSX code is generated. */ // "experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */ @@ -25,7 +32,7 @@ // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */ /* Modules */ - "module": "commonjs", /* Specify what module code is generated. */ +// "module": "commonjs", /* Specify what module code is generated. */ // "rootDir": "./", /* Specify the root folder within your source files. */ // "moduleResolution": "node10", /* Specify how TypeScript looks up a file from a given module specifier. */ // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ @@ -44,7 +51,7 @@ // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */ /* JavaScript Support */ - // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */ +// "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */ // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */ @@ -77,7 +84,7 @@ // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ // "verbatimModuleSyntax": true, /* Do not transform or elide any imports or exports not marked as type-only, ensuring they are written in the output file's format based on the 'module' setting. */ // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ - "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */ +// "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */ // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */