├── .husky └── commit-msg ├── lib ├── exceptions.ts ├── index.ts ├── constants.ts ├── agent.ts ├── types.ts ├── utils.ts ├── tor.ts ├── http.ts └── socks.ts ├── tests ├── README.md ├── options.spec.ts ├── socks.spec.ts ├── download.spec.ts ├── example.js ├── requests.spec.ts └── dumb.js ├── tsconfig.module.json ├── tsconfig.json ├── LICENSE ├── package.json ├── .gitignore ├── README.md └── pnpm-lock.yaml /.husky/commit-msg: -------------------------------------------------------------------------------- 1 | pnpm exec commitlint --edit $1 2 | -------------------------------------------------------------------------------- /lib/exceptions.ts: -------------------------------------------------------------------------------- 1 | export class TorHttpException extends Error { 2 | constructor(message: string) { 3 | super(`[HTTP]: ${message}`); 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /lib/index.ts: -------------------------------------------------------------------------------- 1 | export { TorClient } from './tor'; 2 | export { Socks, SocksOptions } from './socks'; 3 | export { HttpResponse, TorDownloadOptions, TorRequestOptions, TorClientOptions } from './types'; 4 | -------------------------------------------------------------------------------- /tests/README.md: -------------------------------------------------------------------------------- 1 | ## Important 2 | 1. Node 20+ is required to run tests. 3 | 2. Tests can take long time (because Tor network is slow). 4 | 3. Create ./downloads directory in root of project (where package.json is located). 5 | -------------------------------------------------------------------------------- /tsconfig.module.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig", 3 | "compilerOptions": { 4 | "target": "esnext", 5 | "outDir": "dist/esm", 6 | "module": "ES6", 7 | "moduleResolution": "NodeNext", 8 | "esModuleInterop": true, 9 | }, 10 | "exclude": ["tests", "downloads", "node_modules/**"] 11 | } 12 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES6", 4 | "module": "commonjs", 5 | "declaration": true, 6 | "declarationMap": true, 7 | "outDir": "dist/cjs", 8 | "esModuleInterop": true, 9 | "forceConsistentCasingInFileNames": true, 10 | "strict": true, 11 | "skipLibCheck": true 12 | }, 13 | "exclude": ["tests", "downloads", "node_modules/**"] 14 | } 15 | -------------------------------------------------------------------------------- /tests/options.spec.ts: -------------------------------------------------------------------------------- 1 | import { describe, test } from 'node:test'; 2 | import { rejects } from 'node:assert/strict'; 3 | import { TorClient } from '../lib'; 4 | 5 | describe('TOR client options test', () => { 6 | const client = new TorClient(); 7 | 8 | test('should throw timeout error', () => { 9 | rejects(() => client.get('https://www.google.com', { timeout: 20 })); 10 | }); 11 | }); 12 | -------------------------------------------------------------------------------- /lib/constants.ts: -------------------------------------------------------------------------------- 1 | export enum HttpMethod { 2 | POST = 'POST', 3 | GET = 'GET', 4 | DELETE = 'DELETE', 5 | PUT = 'PUT', 6 | PATCH = 'PATCH', 7 | } 8 | 9 | export const ALLOWED_PROTOCOLS = ['http:', 'https:']; 10 | 11 | export enum MimeTypes { 12 | JSON = 'application/json', 13 | HTML = 'text/html', 14 | FORM = 'application/x-www-form-urlencoded', 15 | } 16 | 17 | export const headers = { 18 | 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; rv:109.0) Gecko/20100101 Firefox/115.0', 19 | } 20 | -------------------------------------------------------------------------------- /tests/socks.spec.ts: -------------------------------------------------------------------------------- 1 | import { describe, test } from 'node:test'; 2 | import { notStrictEqual } from 'node:assert/strict'; 3 | import { Socks } from '../lib'; 4 | 5 | describe('Test socks5 client', () => { 6 | test('should connect to Tor socks5 server', async () => { 7 | const socks = await Socks.connect({ 8 | socksHost: '127.0.0.1', 9 | socksPort: 9050, 10 | }); 11 | 12 | const socket = await socks.proxy('www.google.com', 443); 13 | notStrictEqual(socket, undefined); 14 | socket.end(); 15 | socket.destroy(); 16 | }) 17 | }) 18 | -------------------------------------------------------------------------------- /tests/download.spec.ts: -------------------------------------------------------------------------------- 1 | import { describe, test } from 'node:test'; 2 | import { equal } from 'node:assert/strict'; 3 | import { TorClient } from '../lib'; 4 | 5 | describe('Test Tor download', () => { 6 | const client = new TorClient(); 7 | 8 | test('should download image to ./downloads folder', async () => { 9 | const logoUrl = 'http://2gzyxa5ihm7nsggfxnu52rck2vv4rvmdlkiu3zzui5du4xyclen53wid.onion/static/images/tor-logo@2x.png?h=16ad42bc'; 10 | const res = await client.download(logoUrl, { 11 | dir: './downloads' 12 | }); 13 | 14 | equal(typeof res, 'string'); 15 | }); 16 | }) 17 | -------------------------------------------------------------------------------- /tests/example.js: -------------------------------------------------------------------------------- 1 | const { TorClient, Socks } = require('../dist/cjs'); 2 | 3 | const URL = 'https://duckduckgogg42xjoc72x3sjasowoarfbgcmvfimaftt6twagswzczad.onion/?q=tor'; 4 | //const URL = 'https://duckduckgo.com'; 5 | //const URL = 'http://localhost:80'; 6 | 7 | async function test() { 8 | try { 9 | const client = new TorClient(); 10 | const result = await client.get(URL, { timeout: 10 * 1000 }); 11 | 12 | /* Testing with netcat: 13 | const socksClient = await Socks.connect({ socksHost: 'localhost', socksPort: 9050 }); 14 | //socksClient.socket.destroy(); 15 | const result = await socksClient.request('localhost', 80); 16 | */ 17 | 18 | console.log(`Result:`, result); 19 | } catch (err) { 20 | console.log("We got error!"); 21 | console.log(err.message); 22 | } 23 | } 24 | 25 | test(); 26 | -------------------------------------------------------------------------------- /lib/agent.ts: -------------------------------------------------------------------------------- 1 | import { Agent, AgentOptions } from 'http'; 2 | import { Agent as AgentS, AgentOptions as AgentOptionsS } from 'https'; 3 | import { Socket } from 'net'; 4 | 5 | interface SocksOptions extends AgentOptions, AgentOptionsS { 6 | socksSocket: Socket; 7 | } 8 | 9 | export class HttpAgent extends Agent { 10 | private socksSocket: Socket; 11 | 12 | constructor(options: SocksOptions) { 13 | super(options); 14 | this.socksSocket = options.socksSocket; 15 | } 16 | 17 | createConnection() { 18 | return this.socksSocket; 19 | } 20 | } 21 | 22 | export class HttpsAgent extends AgentS { 23 | private socksSocket: Socket; 24 | 25 | constructor(options: SocksOptions) { 26 | super(options); 27 | this.socksSocket = options.socksSocket; 28 | } 29 | 30 | createConnection() { 31 | return this.socksSocket; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /lib/types.ts: -------------------------------------------------------------------------------- 1 | import { IncomingHttpHeaders } from "http"; 2 | import { HttpAgent, HttpsAgent } from "./agent"; 3 | 4 | export interface TorRequestOptions { 5 | headers?: object; 6 | timeout?: number; 7 | } 8 | 9 | export interface TorDownloadOptions extends TorRequestOptions { 10 | filename?: string; 11 | dir?: string; 12 | } 13 | 14 | export interface TorClientOptions { 15 | socksHost?: string; 16 | socksPort?: number; 17 | } 18 | 19 | export interface HttpResponse { 20 | status: number; 21 | headers: IncomingHttpHeaders; 22 | data: TResponseData; 23 | } 24 | 25 | export interface HttpOptions { 26 | headers?: object; 27 | method?: string; 28 | data?: string; 29 | agent?: SocksAgent; 30 | timeout?: number; 31 | } 32 | 33 | export interface DownloadOptions extends HttpOptions { 34 | path: string; 35 | } 36 | 37 | export type SocksAgent = HttpAgent | HttpsAgent; 38 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Michał Dziuba 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /lib/utils.ts: -------------------------------------------------------------------------------- 1 | import { IncomingMessage } from "http"; 2 | import { HttpResponse, TorDownloadOptions } from "./types"; 3 | import { randomBytes } from 'crypto'; 4 | import { join, isAbsolute } from 'path'; 5 | 6 | export function buildResponse(res: IncomingMessage, data: string): HttpResponse { 7 | const status = res.statusCode || 200; 8 | const headers = res.headers; 9 | 10 | return { status, headers, data } 11 | } 12 | 13 | function generateFilename(pathname: string) { 14 | const filename = pathname.split('/').pop(); 15 | if (!filename || filename === '') { 16 | return `${Date.now()}${randomBytes(6).toString('hex')}`; 17 | } 18 | 19 | return `${filename}`; 20 | } 21 | 22 | export function getPath(options: TorDownloadOptions, pathname: string) { 23 | const filename = options.filename || generateFilename(pathname); 24 | const dir = options.dir || './'; 25 | 26 | if (isAbsolute(dir)) { 27 | return join(dir, filename); 28 | } 29 | 30 | return join( 31 | process.cwd(), 32 | dir, 33 | filename 34 | ); 35 | } 36 | 37 | export function preventDNSLookup( 38 | hostname: string, 39 | _options: any, 40 | _cb: any, 41 | ) { 42 | throw new Error(`Blocked DNS lookup for: ${hostname}`); 43 | } 44 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@md03/tor", 3 | "version": "1.0.0", 4 | "description": "Node.js Tor client without dependencies", 5 | "main": "dist/cjs/index.js", 6 | "typings": "dist/cjs/index.d.ts", 7 | "module": "dist/esm/index.js", 8 | "files": [ 9 | "dist" 10 | ], 11 | "scripts": { 12 | "prepare": "husky", 13 | "test": "node --import tsx --test tests/*.spec.ts", 14 | "build": "rimraf dist && tsc && tsc -p tsconfig.module.json", 15 | "sample": "node ./tests/example.js" 16 | }, 17 | "repository": { 18 | "type": "git", 19 | "url": "git+https://github.com/michaldziuba03/tor-client.git" 20 | }, 21 | "keywords": [ 22 | "tor", 23 | "tor-client", 24 | "proxy", 25 | "http", 26 | "socks", 27 | "socks5", 28 | "socket", 29 | "networking" 30 | ], 31 | "author": "michaldziuba03", 32 | "license": "MIT", 33 | "bugs": { 34 | "url": "https://github.com/michaldziuba03/tor-client/issues" 35 | }, 36 | "homepage": "https://github.com/michaldziuba03/tor-client#readme", 37 | "devDependencies": { 38 | "@commitlint/cli": "^19.5.0", 39 | "@commitlint/config-conventional": "^19.5.0", 40 | "@types/node": "^16.18.118", 41 | "husky": "^9.1.6", 42 | "rimraf": "^6.0.1", 43 | "tsx": "^4.19.2", 44 | "typescript": "^4.9.5" 45 | }, 46 | "commitlint": { 47 | "extends": [ 48 | "@commitlint/config-conventional" 49 | ] 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /tests/requests.spec.ts: -------------------------------------------------------------------------------- 1 | import { describe, test } from 'node:test'; 2 | import { equal, ok } from 'node:assert/strict'; 3 | import { TorClient } from '../lib'; 4 | 5 | const onionUrls = { 6 | duckduckgo: 'https://duckduckgogg42xjoc72x3sjasowoarfbgcmvfimaftt6twagswzczad.onion/', 7 | ahmia: 'http://juhanurmihxlp77nkq76byazcldy2hlmovfu2epvl5ankdibsot4csyd.onion/', 8 | } 9 | 10 | describe('Test HTTP requests', () => { 11 | const client = new TorClient(); 12 | 13 | test('should be configured to TOR', async () => { 14 | const res = await client.torcheck(); 15 | ok(res); 16 | }); 17 | 18 | test('should make GET request to duckduckgo hidden services', async () => { 19 | const url = onionUrls.duckduckgo + '?q=linux'; 20 | const res = await client.get(url); 21 | 22 | equal(res.status, 200); 23 | ok(res.data.includes('linux at DuckDuckGo')); 24 | }); 25 | 26 | test('should make POST request to duckduckgo hidden services', async () => { 27 | const url = onionUrls.duckduckgo; 28 | const res = await client.post(url, { q: 'linux' }); 29 | 30 | equal(res.status, 200); 31 | ok(res.data.includes('linux at DuckDuckGo')); 32 | }); 33 | 34 | test('should make GET request to regular website', async () => { 35 | const url = 'https://en.wikipedia.org/wiki/Tor'; 36 | const res = await client.get(url); 37 | 38 | equal(res.status, 200); 39 | }); 40 | 41 | test('should make GET request to ahmia hidden services', async () => { 42 | const url = onionUrls.ahmia; 43 | const res = await client.get(url); 44 | 45 | equal(res.status, 200); 46 | }) 47 | }); -------------------------------------------------------------------------------- /tests/dumb.js: -------------------------------------------------------------------------------- 1 | const net = require('net'); 2 | 3 | /** 4 | * Handle initial SOCKS5 handshake. 5 | * 6 | * @param {net.Socket} socket 7 | * @param {Buffer} chunk 8 | */ 9 | function handleInitialize(socket, chunk) { 10 | console.log(''); 11 | if (chunk.length < 2) 12 | return; 13 | 14 | console.log('Received:', chunk); 15 | const response = Buffer.from([0x5, 0x0]); 16 | socket.write(response); 17 | 18 | socket.removeAllListeners('data'); 19 | socket.on('data', (data) => handleConnectionRequest(socket, data)); 20 | } 21 | 22 | /** 23 | * Handle connnection request 24 | * 25 | * @param {net.Socket} socket 26 | * @param {Buffer} chunk 27 | */ 28 | function handleConnectionRequest(socket, chunk) { 29 | console.log(''); 30 | console.log('Received:', chunk); 31 | 32 | const response = Buffer.from([0x5, 0x0, 0x0, 0x01, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0]); 33 | const httpResponse = 'HTTP/1.1 200 OK\r\nContent-Length: 13\r\n\r\nHello, World!'; 34 | socket.write(Buffer.concat([response, Buffer.from(httpResponse)])); 35 | //socket.write(response); 36 | 37 | socket.removeAllListeners('data'); 38 | socket.on('data', (data) => dumbTunnel(socket, data)); 39 | console.log(''); 40 | } 41 | 42 | /** 43 | * Echo request as response 44 | * 45 | * @param {net.Socket} socket 46 | * @param {Buffer} chunk 47 | */ 48 | function dumbTunnel(socket, chunk) { 49 | console.log('Received:', chunk); 50 | socket.write(chunk); 51 | } 52 | 53 | const server = net.createServer((socket) => { 54 | // assume that all data comes at once 55 | console.log(''); 56 | socket.on('data', chunk => handleInitialize(socket, chunk)); 57 | socket.on('close', () => { 58 | socket.destroy(); 59 | }) 60 | socket.on('error', (err) => { 61 | console.log(''); 62 | console.error(err.message); 63 | }) 64 | }); 65 | 66 | server.listen(9050, () => { 67 | console.log("Dummy SOCKS5 server started."); 68 | }); 69 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | lerna-debug.log* 8 | downloads 9 | # Diagnostic reports (https://nodejs.org/api/report.html) 10 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 11 | 12 | # Runtime data 13 | pids 14 | *.pid 15 | *.seed 16 | *.pid.lock 17 | 18 | # Directory for instrumented libs generated by jscoverage/JSCover 19 | lib-cov 20 | 21 | # Coverage directory used by tools like istanbul 22 | coverage 23 | *.lcov 24 | 25 | # nyc test coverage 26 | .nyc_output 27 | 28 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 29 | .grunt 30 | 31 | # Bower dependency directory (https://bower.io/) 32 | bower_components 33 | 34 | # node-waf configuration 35 | .lock-wscript 36 | 37 | # Compiled binary addons (https://nodejs.org/api/addons.html) 38 | build/Release 39 | 40 | # Dependency directories 41 | node_modules/ 42 | jspm_packages/ 43 | 44 | # TypeScript v1 declaration files 45 | typings/ 46 | 47 | # TypeScript cache 48 | *.tsbuildinfo 49 | 50 | # Optional npm cache directory 51 | .npm 52 | 53 | # Optional eslint cache 54 | .eslintcache 55 | 56 | # Microbundle cache 57 | .rpt2_cache/ 58 | .rts2_cache_cjs/ 59 | .rts2_cache_es/ 60 | .rts2_cache_umd/ 61 | 62 | # Optional REPL history 63 | .node_repl_history 64 | 65 | # Output of 'npm pack' 66 | *.tgz 67 | 68 | # Yarn Integrity file 69 | .yarn-integrity 70 | 71 | # dotenv environment variables file 72 | .env 73 | .env.test 74 | 75 | # parcel-bundler cache (https://parceljs.org/) 76 | .cache 77 | 78 | # Next.js build output 79 | .next 80 | 81 | # Nuxt.js build / generate output 82 | .nuxt 83 | dist/ 84 | pp/ 85 | 86 | # Gatsby files 87 | .cache/ 88 | # Comment in the public line in if your project uses Gatsby and *not* Next.js 89 | # https://nextjs.org/blog/next-9-1#public-directory-support 90 | # public 91 | 92 | # vuepress build output 93 | .vuepress/dist 94 | 95 | # Serverless directories 96 | .serverless/ 97 | 98 | # FuseBox cache 99 | .fusebox/ 100 | 101 | # DynamoDB Local files 102 | .dynamodb/ 103 | 104 | # TernJS port file 105 | .tern-port 106 | -------------------------------------------------------------------------------- /lib/tor.ts: -------------------------------------------------------------------------------- 1 | import { Socket } from "net"; 2 | import { TLSSocket } from 'tls'; 3 | import { HttpAgent, HttpsAgent } from "./agent"; 4 | import { HttpClient } from "./http"; 5 | import { Socks } from "./socks"; 6 | import { TorClientOptions, TorDownloadOptions, TorRequestOptions } from "./types"; 7 | import { getPath } from "./utils"; 8 | 9 | 10 | export class TorClient { 11 | private readonly http = new HttpClient(); 12 | private readonly options: TorClientOptions; 13 | 14 | constructor(options: TorClientOptions = {}) { 15 | this.options = options; 16 | } 17 | 18 | private createAgent(protocol: string, socket: Socket) { 19 | if (protocol === 'http:') { 20 | return new HttpAgent({ socksSocket: socket }); 21 | } 22 | 23 | const tlsSocket = new TLSSocket(socket); 24 | return new HttpsAgent({ socksSocket: tlsSocket }); 25 | } 26 | 27 | private getDestination(url: string) { 28 | const urlObj = new URL(url); 29 | let port = urlObj.protocol === 'http:' ? 80 : 443; 30 | if (urlObj.port || urlObj.port !== '') { 31 | port = parseInt(urlObj.port); 32 | } 33 | 34 | return { port, host: urlObj.host, protocol: urlObj.protocol, pathname: urlObj.pathname } 35 | } 36 | 37 | private async connectSocks(host: string, port: number, timeout?: number) { 38 | const socksOptions = { 39 | socksHost: this.options.socksHost || '127.0.0.1', 40 | socksPort: this.options.socksPort || 9050, 41 | timeout, 42 | } 43 | const socks = await Socks.connect(socksOptions); 44 | 45 | return socks.proxy(host, port); 46 | } 47 | 48 | async download(url: string, options: TorDownloadOptions = {}) { 49 | const { protocol, host, port, pathname } = this.getDestination(url); 50 | 51 | const path = getPath(options, pathname); 52 | const socket = await this.connectSocks(host, port); 53 | const agent = this.createAgent(protocol, socket); 54 | 55 | return this.http.download(url, { 56 | path, 57 | agent, 58 | headers: options.headers, 59 | timeout: options.timeout, 60 | }); 61 | } 62 | 63 | async get(url: string, options: TorRequestOptions = {}) { 64 | const { protocol, host, port } = this.getDestination(url); 65 | 66 | const socket = await this.connectSocks(host, port, options.timeout); 67 | const agent = this.createAgent(protocol, socket); 68 | 69 | return this.http.get(url, { 70 | agent, 71 | headers: options.headers, 72 | timeout: options.timeout, 73 | }); 74 | } 75 | 76 | async post(url: string, data: object, options: TorRequestOptions = {}) { 77 | const { protocol, host, port } = this.getDestination(url); 78 | 79 | const socket = await this.connectSocks(host, port); 80 | const agent = this.createAgent(protocol, socket); 81 | 82 | return this.http.post(url, data, { 83 | agent, 84 | headers: options.headers, 85 | timeout: options.timeout, 86 | }); 87 | } 88 | 89 | async torcheck(options?: TorRequestOptions) { 90 | const result = await this.get('https://check.torproject.org/', options); 91 | if (!result.status || result.status !== 200) { 92 | throw new Error(`Network error with check.torproject.org, status code: ${result.status}`); 93 | } 94 | 95 | return result.data.includes('Congratulations. This browser is configured to use Tor'); 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 | logo 3 |
4 | 5 |

6 | Node.js Tor client 7 |

8 | 9 |

10 | A simple library for making HTTP requests over the Tor network programmatically in JavaScript. 11 |

12 | 13 | > I do **NOT** recommend using this library with other runtimes such Deno or Bun. 14 | > It relies on HTTP Agent and for example Bun is not using HTTP Agent in every context so you can end up with making HTTP request without Tor... 15 | 16 | ## 🧅 Features 17 | 18 | - [x] Simple codebase 19 | - [x] Own implementation of SOCKS5 protocol 20 | - [x] Built-in HTTP wrapper (but still possible to use with `axios`) 21 | - [x] Same `User-Agent` as in Tor Browser by default 22 | - [x] Written in TypeScript 23 | - [x] No external dependencies 24 | 25 | ### Install Tor 26 | 27 | This library expects Tor proxy server to be available locally on port `9050` (by default). 28 | 29 | #### Arch/Manjaro/Garuda (Linux) 30 | ```bash 31 | $ sudo pacman -S tor 32 | $ sudo systemctl enable tor.service 33 | $ sudo systemctl start tor.service 34 | ``` 35 | ##### Debian/Ubuntu/Mint (Linux) 36 | ```bash 37 | $ sudo apt install tor 38 | ``` 39 | 40 | ### Code example 41 | ```ts 42 | const client = new TorClient(); 43 | const result = await client.get('https://check.torproject.org/'); 44 | // status (number): 45 | console.log(result.status); 46 | // data (string by default): 47 | console.log(result.data); 48 | // headers (object): 49 | console.log(result.headers); 50 | ``` 51 | 52 | ### Documentation 53 | #### Configuration for `SOCKS5` proxy 54 | ```ts 55 | const client = new TorClient({ 56 | socksHost: 'localhost' 57 | socksPort: 2137, 58 | }); 59 | ``` 60 | By default client connects with `localhost:9050`. 61 | 62 | #### Request options 63 | By default request does **not** have any timeout. 64 | ```ts 65 | { 66 | headers: object, 67 | timeout: number, 68 | } 69 | ``` 70 | 71 | #### `.torcheck(options?)` 72 | Ping `https://check.torproject.org/` to check Tor connection status. 73 | ```ts 74 | const client = new TorClient(); 75 | const isUsed = await client.torcheck(); 76 | console.log(isUsed); // true or false 77 | ``` 78 | 79 | #### `.get(url, options?)` 80 | Make http GET request (works with regular and `.onion` sites). 81 | ```ts 82 | const client = new TorClient(); 83 | const url = 'https://duckduckgogg42xjoc72x3sjasowoarfbgcmvfimaftt6twagswzczad.onion/?q=tor'; 84 | const result = await client.get(url); 85 | console.log(result.data); // HTML -> string 86 | ``` 87 | 88 | #### `.post(url, data, options?)` 89 | Make http POST request (works with regular and `.onion` sites). 90 | ```ts 91 | const client = new TorClient(); 92 | const url = 'https://duckduckgogg42xjoc72x3sjasowoarfbgcmvfimaftt6twagswzczad.onion/'; 93 | const result = await client.post(url, { q: 'tor' }); 94 | console.log(result.data); // HTML -> string 95 | ``` 96 | 97 | #### `.download(url, options?)` 98 | Download response body to file (implementation based on Node.js Streams and works with binaries and text files) 99 | ```ts 100 | const client = new TorClient(); 101 | const resultPath = await client.download('', { 102 | filename: 'myfile.png', 103 | dir: './downloads' // folder must exists! 104 | }); 105 | 106 | console.log(resultPath); // string 107 | ``` 108 | 109 | #### Passing options for requests 110 | You can pass your custom headers and request timeout. 111 | ```ts 112 | const client = new TorClient(); 113 | const result = await client.get('https://www.deviceinfo.me/', { 114 | headers: { 115 | 'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.69 Safari/537.36', 116 | }, 117 | timeout: 20000, 118 | }); 119 | 120 | console.log(result.data); 121 | ``` 122 | 123 | By default TorClient uses User-Agent: `Mozilla/5.0 (Windows NT 10.0; rv:109.0) Gecko/20100101 Firefox/115.0` (from Tor Browser - most popular Tor client). 124 | 125 | ## License 126 | 127 | Distributed under the MIT License. See `LICENSE` for more information. 128 | -------------------------------------------------------------------------------- /lib/http.ts: -------------------------------------------------------------------------------- 1 | import { createWriteStream } from 'fs'; 2 | import http from 'http'; 3 | import https, { RequestOptions } from 'https'; 4 | import qs from 'querystring'; 5 | 6 | import { ALLOWED_PROTOCOLS } from './constants'; 7 | import { DownloadOptions, HttpOptions, HttpResponse } from './types'; 8 | import { headers, HttpMethod, MimeTypes } from './constants'; 9 | import { buildResponse, preventDNSLookup } from './utils'; 10 | import { TorHttpException } from './exceptions'; 11 | 12 | /** 13 | * Wrapper around `http` module for making HTTP requests over Tor. 14 | */ 15 | export class HttpClient { 16 | private getClient(protocol: string) { 17 | if (protocol === 'http:') return http; 18 | 19 | return https; 20 | } 21 | 22 | private createRequestOptions(url: string, options: HttpOptions) { 23 | const { protocol } = new URL(url); 24 | if (!ALLOWED_PROTOCOLS.includes(protocol)) { 25 | throw new TorHttpException('Invalid HTTP protocol in URL'); 26 | } 27 | 28 | if (!options.agent) { 29 | throw new TorHttpException('HttpAgent is required for TOR requests'); 30 | } 31 | 32 | const client = this.getClient(protocol); 33 | const requestOptions: RequestOptions = { 34 | headers: { ...headers, ...options.headers }, 35 | method: options.method, 36 | agent: options.agent, 37 | lookup: preventDNSLookup, 38 | } 39 | 40 | return { client, requestOptions } 41 | } 42 | 43 | request(url: string, options: HttpOptions = {}) { 44 | const { client, requestOptions } = this.createRequestOptions(url, options); 45 | 46 | return new Promise((resolve, reject) => { 47 | const req = client.request(url, requestOptions, res => { 48 | let data = ''; 49 | 50 | res.on('data', chunk => data += chunk); 51 | res.on('error', reject); 52 | res.on('close', () => { 53 | const response = buildResponse(res, data); 54 | resolve(response); 55 | 56 | }); 57 | }); 58 | 59 | if (options.timeout) req.setTimeout(options.timeout); 60 | 61 | req.on('error', reject); 62 | req.on('timeout', () => reject(new TorHttpException('Http request timeout'))); 63 | 64 | if (options.data) { 65 | req.write(options.data); 66 | } 67 | 68 | req.end(); 69 | }); 70 | } 71 | 72 | download(url: string, options: DownloadOptions) { 73 | const { client, requestOptions } = this.createRequestOptions(url, options); 74 | 75 | return new Promise((resolve, reject) => { 76 | const req = client.request(url, requestOptions, res => { 77 | const fileStream = createWriteStream(options.path); 78 | res.pipe(fileStream); 79 | 80 | res.on('error', (err) => { 81 | fileStream.end(); 82 | reject(err); 83 | }); 84 | 85 | res.on('close', () => { 86 | fileStream.end(); 87 | resolve(options.path); 88 | }); 89 | }); 90 | 91 | if (options.timeout) req.setTimeout(options.timeout); 92 | req.on('error', reject); 93 | req.on('timeout', () => reject(new TorHttpException('Download timeout'))); 94 | req.end(); 95 | }); 96 | } 97 | 98 | delete(url: string, options: HttpOptions = {}) { 99 | return this.request(url, { 100 | ...options, 101 | method: HttpMethod.DELETE, 102 | }); 103 | } 104 | 105 | get(url: string, options: HttpOptions = {}) { 106 | return this.request(url, { 107 | ...options, 108 | method: HttpMethod.GET, 109 | }); 110 | } 111 | 112 | post(url: string, data: object, options: HttpOptions = {}) { 113 | const dataString = qs.stringify(data as Record); 114 | return this.request(url, { 115 | agent: options.agent, 116 | timeout: options.timeout, 117 | method: HttpMethod.POST, 118 | data: dataString, 119 | headers: { 120 | 'Content-Type': MimeTypes.FORM, 121 | 'Content-Length': dataString.length, 122 | ...options.headers, 123 | }, 124 | }); 125 | } 126 | 127 | put(url: string, data: object, options: HttpOptions = {}) { 128 | const dataString = qs.stringify(data as Record); 129 | return this.request(url, { 130 | agent: options.agent, 131 | timeout: options.timeout, 132 | method: HttpMethod.PUT, 133 | data: dataString, 134 | headers: { 135 | 'Content-Type': MimeTypes.FORM, 136 | 'Content-Length': dataString.length, 137 | ...options.headers, 138 | }, 139 | }); 140 | } 141 | 142 | patch(url: string, data: object, options: HttpOptions = {}) { 143 | const dataString = qs.stringify(data as Record); 144 | return this.request(url, { 145 | agent: options.agent, 146 | timeout: options.timeout, 147 | method: HttpMethod.PATCH, 148 | data: dataString, 149 | headers: { 150 | 'Content-Type': MimeTypes.FORM, 151 | 'Content-Length': dataString.length, 152 | ...options.headers, 153 | }, 154 | }); 155 | } 156 | } 157 | -------------------------------------------------------------------------------- /lib/socks.ts: -------------------------------------------------------------------------------- 1 | /* Copyright (c) Michał Dziuba 2 | * 3 | * Permission is hereby granted, free of charge, to any person obtaining a copy 4 | * of this software and associated documentation files (the "Software"), to deal 5 | * in the Software without restriction, including without limitation the rights 6 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | * copies of the Software, and to permit persons to whom the Software is 8 | * furnished to do so, subject to the following conditions: 9 | * 10 | * The above copyright notice and this permission notice shall be included in all 11 | * copies or substantial portions of the Software. 12 | * 13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | * SOFTWARE. 20 | */ 21 | 22 | import net, { Socket, isIP } from 'node:net'; 23 | 24 | const IPv4 = 4; 25 | const IPv6 = 6; 26 | 27 | const socksVersion = 0x05; // SOCKS v5 28 | const authMethods = 0x01; // NUMBER OF SUPPORTED AUTH METHODS 29 | const noPassMethod = 0x00; // PREFERED AUTH METHOD BY DEFAULT (no password) 30 | 31 | export interface SocksOptions { 32 | socksHost: string; 33 | socksPort: number; 34 | keepAlive?: boolean | undefined; 35 | noDelay?: boolean | undefined; 36 | timeout?: number | undefined; 37 | } 38 | 39 | /** 40 | * Handles SOCKS5 protocol 41 | */ 42 | export class Socks { 43 | private recv: Buffer; 44 | 45 | constructor( 46 | public readonly socket: Socket, 47 | private readonly options: SocksOptions 48 | ) { 49 | this.recv = Buffer.alloc(0); 50 | this.socket.on('timeout', this.onTimeout); 51 | } 52 | 53 | private onTimeout = () => { 54 | const err = new Error('SOCKS5 connection attempt timed out'); 55 | this.socket.destroy(err); 56 | } 57 | 58 | /** 59 | * Connect to the SOCKS5 proxy server. 60 | * @throws {Error} on connection failure 61 | */ 62 | static connect(options: SocksOptions): Promise { 63 | const socket = net.connect({ 64 | host: options.socksHost, 65 | port: options.socksPort, 66 | keepAlive: options.keepAlive, 67 | noDelay: options.noDelay, 68 | timeout: options.timeout, 69 | }); 70 | 71 | return new Promise((resolve, reject) => { 72 | const onError = (err: Error) => { 73 | socket.destroy(); // safe to call many times 74 | reject(err); 75 | } 76 | 77 | const onTimeout = () => { 78 | const err = new Error('SOCKS5 connection attempt timed out'); 79 | socket.destroy(err); // will notify error listener to reject 80 | } 81 | 82 | socket.once('error', onError); 83 | socket.once('timeout', onTimeout); 84 | socket.once('connect', () => { 85 | socket.removeListener('error', onError); 86 | socket.removeListener('timeout', onTimeout); 87 | resolve(new Socks(socket, options)); 88 | }); 89 | }); 90 | } 91 | 92 | /** 93 | * All content will be proxied after success of this function. 94 | * 95 | * @param {string} host - destination hostname (domain or IP address) 96 | * @param {number} port - destination port 97 | * @throws {Error} on connection failure 98 | */ 99 | async proxy(host: string, port: number) { 100 | await this.initialize(); 101 | return this.request(host, port); 102 | } 103 | 104 | /** 105 | * Perform `initial greeting` to the SOCKS5 proxy server. 106 | * 107 | * @throws {Error} on connection failure 108 | */ 109 | initialize() { 110 | if (this.socket.destroyed) { 111 | throw new Error('SOCKS5 connection is already destroyed'); 112 | } 113 | 114 | const request = [socksVersion, authMethods, noPassMethod]; 115 | const buffer = Buffer.from(request); 116 | 117 | return new Promise((resolve, reject) => { 118 | // without close handler, Node.js app crashes silently. 119 | const onClose = () => { 120 | reject(new Error('SOCKS5 dropped connection')); 121 | } 122 | 123 | const onError = (err: Error) => { 124 | this.socket.removeListener('close', onClose); 125 | this.socket.destroy(); 126 | reject(err); 127 | } 128 | 129 | const onData = (chunk: Buffer) => { 130 | let err; 131 | this.recv = Buffer.concat([this.recv, chunk]); 132 | 133 | if (this.recv.length < 2) { 134 | return; // wait for more data 135 | } 136 | 137 | if (this.recv[0] !== socksVersion) { 138 | err = new Error('Invalid SOCKS version in response'); 139 | } 140 | // TODO: add support for more auth methods 141 | else if (this.recv[1] !== noPassMethod) { 142 | err = new Error('Unexpected SOCKS authentication method'); 143 | } 144 | 145 | if (err) { 146 | this.socket.destroy(err); 147 | return; 148 | } 149 | 150 | this.recv = this.recv.subarray(2); 151 | this.socket.removeListener('data', onData); 152 | this.socket.removeListener('error', onError); 153 | this.socket.removeListener('close', onClose); 154 | return resolve(true); 155 | } 156 | 157 | this.socket.once('close', onClose); 158 | this.socket.once('error', onError); 159 | this.socket.on('data', onData); 160 | 161 | this.socket.write(buffer); 162 | }); 163 | } 164 | 165 | /** 166 | * Performs `connection request` to the SOCKS5 proxy server. 167 | * 168 | * @param {string} host - destination hostname (domain or IP address) 169 | * @param {number} port - destination port 170 | * @throws {Error} on connection failure 171 | */ 172 | request(host: string, port: number) { 173 | if (this.socket.destroyed) { 174 | throw new Error('SOCKS5 connection is already destroyed'); 175 | } 176 | 177 | const cmd = 0x01; // TCP/IP stream connection; 178 | const reserved = 0x00; // reserved byte; 179 | const parsedHost = this.parseHost(host); // parsed host type, host length and host value 180 | const request = [socksVersion, cmd, reserved, ...parsedHost]; 181 | 182 | request.length += 2; 183 | const buffer = Buffer.from(request); 184 | buffer.writeUInt16BE(port, buffer.length - 2); 185 | 186 | return new Promise((resolve, reject) => { 187 | let expectedLength = 10; 188 | 189 | const onClose = () => { 190 | reject(new Error('SOCKS5 dropped connection')); 191 | } 192 | 193 | const onError = (err: Error) => { 194 | this.socket.removeListener('close', onClose); 195 | this.socket.destroy(); 196 | reject(err); 197 | } 198 | 199 | const onData = (chunk: Buffer) => { 200 | let err; 201 | this.recv = Buffer.concat([this.recv, chunk]); 202 | 203 | // initial min size == 10 204 | if (this.recv.length < expectedLength) { 205 | return; // wait for more data 206 | } 207 | 208 | if (this.recv[0] !== socksVersion) { 209 | err = new Error('Invalid SOCKS version in response'); 210 | } 211 | else if (this.recv[1] !== 0x00) { 212 | const msg = this.mapError(chunk[1]); 213 | err = new Error(msg); 214 | } 215 | else if (this.recv[2] !== reserved) { 216 | err = new Error('Invalid SOCKS response shape'); 217 | } 218 | 219 | const addressType = this.recv[3]; 220 | expectedLength = 6; 221 | 222 | if (addressType == 0x01) { 223 | expectedLength += 4; 224 | } else if (addressType == 0x03) { 225 | expectedLength += this.recv[4] + 1; 226 | } else if (addressType == 0x04) { 227 | expectedLength += 16; 228 | } else { 229 | err = new Error('Unexpected address type'); 230 | } 231 | 232 | if (err) { 233 | this.socket.destroy(err); 234 | return; 235 | } 236 | 237 | if (this.recv.length < expectedLength) { 238 | return; 239 | } 240 | 241 | this.socket.removeListener('data', onData); 242 | this.socket.removeListener('error', onError); 243 | this.socket.removeListener('close', onClose); 244 | this.socket.removeListener('timeout', this.onTimeout); 245 | this.recv = this.recv.subarray(expectedLength); 246 | 247 | // if we have leftover, emit it to the user, it is not our problem anymore 248 | if (this.recv.length > 0) { 249 | /* setTimeout should be safer than setImmediate, because it runs almost 250 | * as soon as possible in the next event loop iteration (before network callbacks) 251 | */ 252 | setTimeout(() => { 253 | this.socket.emit('data', this.recv); 254 | }); 255 | } 256 | 257 | return resolve(this.socket); 258 | } 259 | 260 | this.socket.once('error', onError); 261 | this.socket.once('close', onClose); 262 | this.socket.on('data', onData); 263 | 264 | this.socket.write(buffer); 265 | }); 266 | } 267 | 268 | private parseHost(host: string): number[] { 269 | const type = isIP(host); 270 | 271 | if (type === IPv4) { 272 | const hostType = 0x01; // 0x01 means IPv4 273 | const buffer = Buffer.from(host.split('.').map(octet => parseInt(octet, 10))); 274 | return [hostType, ...buffer]; 275 | } else if (type === IPv6) { 276 | const hostType = 0x04; // 0x04 means IPv6 277 | const buffer = Buffer.from(host.split(':').map(hex => parseInt(hex, 16))); 278 | return [hostType, ...buffer]; 279 | } else { 280 | const buffer = Buffer.from(host); 281 | const hostType = 0x03; // 0x03 means domain name 282 | const len = buffer.length; 283 | return [hostType, len, ...buffer]; 284 | } 285 | } 286 | 287 | private mapError(status: number) { 288 | switch(status) { 289 | case 0x01: 290 | return 'General failure'; 291 | case 0x02: 292 | return 'Connection not allowed by ruleset'; 293 | case 0x03: 294 | return 'Network unreachable'; 295 | case 0x04: 296 | return 'Host unreachable'; 297 | case 0x05: 298 | return 'Connection refused by destination host'; 299 | case 0x06: 300 | return 'TTL expired'; 301 | case 0x07: 302 | return 'Command not supported / protocol error'; 303 | case 0x08: 304 | return 'Address type not supported'; 305 | default: 306 | return 'Unknown SOCKS response status'; 307 | } 308 | } 309 | } 310 | -------------------------------------------------------------------------------- /pnpm-lock.yaml: -------------------------------------------------------------------------------- 1 | lockfileVersion: '9.0' 2 | 3 | settings: 4 | autoInstallPeers: true 5 | excludeLinksFromLockfile: false 6 | 7 | importers: 8 | 9 | .: 10 | devDependencies: 11 | '@commitlint/cli': 12 | specifier: ^19.5.0 13 | version: 19.5.0(@types/node@16.18.118)(typescript@4.9.5) 14 | '@commitlint/config-conventional': 15 | specifier: ^19.5.0 16 | version: 19.5.0 17 | '@types/node': 18 | specifier: ^16.18.118 19 | version: 16.18.118 20 | husky: 21 | specifier: ^9.1.6 22 | version: 9.1.6 23 | rimraf: 24 | specifier: ^6.0.1 25 | version: 6.0.1 26 | tsx: 27 | specifier: ^4.19.2 28 | version: 4.19.2 29 | typescript: 30 | specifier: ^4.9.5 31 | version: 4.9.5 32 | 33 | packages: 34 | 35 | '@babel/code-frame@7.26.2': 36 | resolution: {integrity: sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==} 37 | engines: {node: '>=6.9.0'} 38 | 39 | '@babel/helper-validator-identifier@7.25.9': 40 | resolution: {integrity: sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==} 41 | engines: {node: '>=6.9.0'} 42 | 43 | '@commitlint/cli@19.5.0': 44 | resolution: {integrity: sha512-gaGqSliGwB86MDmAAKAtV9SV1SHdmN8pnGq4EJU4+hLisQ7IFfx4jvU4s+pk6tl0+9bv6yT+CaZkufOinkSJIQ==} 45 | engines: {node: '>=v18'} 46 | hasBin: true 47 | 48 | '@commitlint/config-conventional@19.5.0': 49 | resolution: {integrity: sha512-OBhdtJyHNPryZKg0fFpZNOBM1ZDbntMvqMuSmpfyP86XSfwzGw4CaoYRG4RutUPg0BTK07VMRIkNJT6wi2zthg==} 50 | engines: {node: '>=v18'} 51 | 52 | '@commitlint/config-validator@19.5.0': 53 | resolution: {integrity: sha512-CHtj92H5rdhKt17RmgALhfQt95VayrUo2tSqY9g2w+laAXyk7K/Ef6uPm9tn5qSIwSmrLjKaXK9eiNuxmQrDBw==} 54 | engines: {node: '>=v18'} 55 | 56 | '@commitlint/ensure@19.5.0': 57 | resolution: {integrity: sha512-Kv0pYZeMrdg48bHFEU5KKcccRfKmISSm9MvgIgkpI6m+ohFTB55qZlBW6eYqh/XDfRuIO0x4zSmvBjmOwWTwkg==} 58 | engines: {node: '>=v18'} 59 | 60 | '@commitlint/execute-rule@19.5.0': 61 | resolution: {integrity: sha512-aqyGgytXhl2ejlk+/rfgtwpPexYyri4t8/n4ku6rRJoRhGZpLFMqrZ+YaubeGysCP6oz4mMA34YSTaSOKEeNrg==} 62 | engines: {node: '>=v18'} 63 | 64 | '@commitlint/format@19.5.0': 65 | resolution: {integrity: sha512-yNy088miE52stCI3dhG/vvxFo9e4jFkU1Mj3xECfzp/bIS/JUay4491huAlVcffOoMK1cd296q0W92NlER6r3A==} 66 | engines: {node: '>=v18'} 67 | 68 | '@commitlint/is-ignored@19.5.0': 69 | resolution: {integrity: sha512-0XQ7Llsf9iL/ANtwyZ6G0NGp5Y3EQ8eDQSxv/SRcfJ0awlBY4tHFAvwWbw66FVUaWICH7iE5en+FD9TQsokZ5w==} 70 | engines: {node: '>=v18'} 71 | 72 | '@commitlint/lint@19.5.0': 73 | resolution: {integrity: sha512-cAAQwJcRtiBxQWO0eprrAbOurtJz8U6MgYqLz+p9kLElirzSCc0vGMcyCaA1O7AqBuxo11l1XsY3FhOFowLAAg==} 74 | engines: {node: '>=v18'} 75 | 76 | '@commitlint/load@19.5.0': 77 | resolution: {integrity: sha512-INOUhkL/qaKqwcTUvCE8iIUf5XHsEPCLY9looJ/ipzi7jtGhgmtH7OOFiNvwYgH7mA8osUWOUDV8t4E2HAi4xA==} 78 | engines: {node: '>=v18'} 79 | 80 | '@commitlint/message@19.5.0': 81 | resolution: {integrity: sha512-R7AM4YnbxN1Joj1tMfCyBryOC5aNJBdxadTZkuqtWi3Xj0kMdutq16XQwuoGbIzL2Pk62TALV1fZDCv36+JhTQ==} 82 | engines: {node: '>=v18'} 83 | 84 | '@commitlint/parse@19.5.0': 85 | resolution: {integrity: sha512-cZ/IxfAlfWYhAQV0TwcbdR1Oc0/r0Ik1GEessDJ3Lbuma/MRO8FRQX76eurcXtmhJC//rj52ZSZuXUg0oIX0Fw==} 86 | engines: {node: '>=v18'} 87 | 88 | '@commitlint/read@19.5.0': 89 | resolution: {integrity: sha512-TjS3HLPsLsxFPQj6jou8/CZFAmOP2y+6V4PGYt3ihbQKTY1Jnv0QG28WRKl/d1ha6zLODPZqsxLEov52dhR9BQ==} 90 | engines: {node: '>=v18'} 91 | 92 | '@commitlint/resolve-extends@19.5.0': 93 | resolution: {integrity: sha512-CU/GscZhCUsJwcKTJS9Ndh3AKGZTNFIOoQB2n8CmFnizE0VnEuJoum+COW+C1lNABEeqk6ssfc1Kkalm4bDklA==} 94 | engines: {node: '>=v18'} 95 | 96 | '@commitlint/rules@19.5.0': 97 | resolution: {integrity: sha512-hDW5TPyf/h1/EufSHEKSp6Hs+YVsDMHazfJ2azIk9tHPXS6UqSz1dIRs1gpqS3eMXgtkT7JH6TW4IShdqOwhAw==} 98 | engines: {node: '>=v18'} 99 | 100 | '@commitlint/to-lines@19.5.0': 101 | resolution: {integrity: sha512-R772oj3NHPkodOSRZ9bBVNq224DOxQtNef5Pl8l2M8ZnkkzQfeSTr4uxawV2Sd3ui05dUVzvLNnzenDBO1KBeQ==} 102 | engines: {node: '>=v18'} 103 | 104 | '@commitlint/top-level@19.5.0': 105 | resolution: {integrity: sha512-IP1YLmGAk0yWrImPRRc578I3dDUI5A2UBJx9FbSOjxe9sTlzFiwVJ+zeMLgAtHMtGZsC8LUnzmW1qRemkFU4ng==} 106 | engines: {node: '>=v18'} 107 | 108 | '@commitlint/types@19.5.0': 109 | resolution: {integrity: sha512-DSHae2obMSMkAtTBSOulg5X7/z+rGLxcXQIkg3OmWvY6wifojge5uVMydfhUvs7yQj+V7jNmRZ2Xzl8GJyqRgg==} 110 | engines: {node: '>=v18'} 111 | 112 | '@esbuild/aix-ppc64@0.23.1': 113 | resolution: {integrity: sha512-6VhYk1diRqrhBAqpJEdjASR/+WVRtfjpqKuNw11cLiaWpAT/Uu+nokB+UJnevzy/P9C/ty6AOe0dwueMrGh/iQ==} 114 | engines: {node: '>=18'} 115 | cpu: [ppc64] 116 | os: [aix] 117 | 118 | '@esbuild/android-arm64@0.23.1': 119 | resolution: {integrity: sha512-xw50ipykXcLstLeWH7WRdQuysJqejuAGPd30vd1i5zSyKK3WE+ijzHmLKxdiCMtH1pHz78rOg0BKSYOSB/2Khw==} 120 | engines: {node: '>=18'} 121 | cpu: [arm64] 122 | os: [android] 123 | 124 | '@esbuild/android-arm@0.23.1': 125 | resolution: {integrity: sha512-uz6/tEy2IFm9RYOyvKl88zdzZfwEfKZmnX9Cj1BHjeSGNuGLuMD1kR8y5bteYmwqKm1tj8m4cb/aKEorr6fHWQ==} 126 | engines: {node: '>=18'} 127 | cpu: [arm] 128 | os: [android] 129 | 130 | '@esbuild/android-x64@0.23.1': 131 | resolution: {integrity: sha512-nlN9B69St9BwUoB+jkyU090bru8L0NA3yFvAd7k8dNsVH8bi9a8cUAUSEcEEgTp2z3dbEDGJGfP6VUnkQnlReg==} 132 | engines: {node: '>=18'} 133 | cpu: [x64] 134 | os: [android] 135 | 136 | '@esbuild/darwin-arm64@0.23.1': 137 | resolution: {integrity: sha512-YsS2e3Wtgnw7Wq53XXBLcV6JhRsEq8hkfg91ESVadIrzr9wO6jJDMZnCQbHm1Guc5t/CdDiFSSfWP58FNuvT3Q==} 138 | engines: {node: '>=18'} 139 | cpu: [arm64] 140 | os: [darwin] 141 | 142 | '@esbuild/darwin-x64@0.23.1': 143 | resolution: {integrity: sha512-aClqdgTDVPSEGgoCS8QDG37Gu8yc9lTHNAQlsztQ6ENetKEO//b8y31MMu2ZaPbn4kVsIABzVLXYLhCGekGDqw==} 144 | engines: {node: '>=18'} 145 | cpu: [x64] 146 | os: [darwin] 147 | 148 | '@esbuild/freebsd-arm64@0.23.1': 149 | resolution: {integrity: sha512-h1k6yS8/pN/NHlMl5+v4XPfikhJulk4G+tKGFIOwURBSFzE8bixw1ebjluLOjfwtLqY0kewfjLSrO6tN2MgIhA==} 150 | engines: {node: '>=18'} 151 | cpu: [arm64] 152 | os: [freebsd] 153 | 154 | '@esbuild/freebsd-x64@0.23.1': 155 | resolution: {integrity: sha512-lK1eJeyk1ZX8UklqFd/3A60UuZ/6UVfGT2LuGo3Wp4/z7eRTRYY+0xOu2kpClP+vMTi9wKOfXi2vjUpO1Ro76g==} 156 | engines: {node: '>=18'} 157 | cpu: [x64] 158 | os: [freebsd] 159 | 160 | '@esbuild/linux-arm64@0.23.1': 161 | resolution: {integrity: sha512-/93bf2yxencYDnItMYV/v116zff6UyTjo4EtEQjUBeGiVpMmffDNUyD9UN2zV+V3LRV3/on4xdZ26NKzn6754g==} 162 | engines: {node: '>=18'} 163 | cpu: [arm64] 164 | os: [linux] 165 | 166 | '@esbuild/linux-arm@0.23.1': 167 | resolution: {integrity: sha512-CXXkzgn+dXAPs3WBwE+Kvnrf4WECwBdfjfeYHpMeVxWE0EceB6vhWGShs6wi0IYEqMSIzdOF1XjQ/Mkm5d7ZdQ==} 168 | engines: {node: '>=18'} 169 | cpu: [arm] 170 | os: [linux] 171 | 172 | '@esbuild/linux-ia32@0.23.1': 173 | resolution: {integrity: sha512-VTN4EuOHwXEkXzX5nTvVY4s7E/Krz7COC8xkftbbKRYAl96vPiUssGkeMELQMOnLOJ8k3BY1+ZY52tttZnHcXQ==} 174 | engines: {node: '>=18'} 175 | cpu: [ia32] 176 | os: [linux] 177 | 178 | '@esbuild/linux-loong64@0.23.1': 179 | resolution: {integrity: sha512-Vx09LzEoBa5zDnieH8LSMRToj7ir/Jeq0Gu6qJ/1GcBq9GkfoEAoXvLiW1U9J1qE/Y/Oyaq33w5p2ZWrNNHNEw==} 180 | engines: {node: '>=18'} 181 | cpu: [loong64] 182 | os: [linux] 183 | 184 | '@esbuild/linux-mips64el@0.23.1': 185 | resolution: {integrity: sha512-nrFzzMQ7W4WRLNUOU5dlWAqa6yVeI0P78WKGUo7lg2HShq/yx+UYkeNSE0SSfSure0SqgnsxPvmAUu/vu0E+3Q==} 186 | engines: {node: '>=18'} 187 | cpu: [mips64el] 188 | os: [linux] 189 | 190 | '@esbuild/linux-ppc64@0.23.1': 191 | resolution: {integrity: sha512-dKN8fgVqd0vUIjxuJI6P/9SSSe/mB9rvA98CSH2sJnlZ/OCZWO1DJvxj8jvKTfYUdGfcq2dDxoKaC6bHuTlgcw==} 192 | engines: {node: '>=18'} 193 | cpu: [ppc64] 194 | os: [linux] 195 | 196 | '@esbuild/linux-riscv64@0.23.1': 197 | resolution: {integrity: sha512-5AV4Pzp80fhHL83JM6LoA6pTQVWgB1HovMBsLQ9OZWLDqVY8MVobBXNSmAJi//Csh6tcY7e7Lny2Hg1tElMjIA==} 198 | engines: {node: '>=18'} 199 | cpu: [riscv64] 200 | os: [linux] 201 | 202 | '@esbuild/linux-s390x@0.23.1': 203 | resolution: {integrity: sha512-9ygs73tuFCe6f6m/Tb+9LtYxWR4c9yg7zjt2cYkjDbDpV/xVn+68cQxMXCjUpYwEkze2RcU/rMnfIXNRFmSoDw==} 204 | engines: {node: '>=18'} 205 | cpu: [s390x] 206 | os: [linux] 207 | 208 | '@esbuild/linux-x64@0.23.1': 209 | resolution: {integrity: sha512-EV6+ovTsEXCPAp58g2dD68LxoP/wK5pRvgy0J/HxPGB009omFPv3Yet0HiaqvrIrgPTBuC6wCH1LTOY91EO5hQ==} 210 | engines: {node: '>=18'} 211 | cpu: [x64] 212 | os: [linux] 213 | 214 | '@esbuild/netbsd-x64@0.23.1': 215 | resolution: {integrity: sha512-aevEkCNu7KlPRpYLjwmdcuNz6bDFiE7Z8XC4CPqExjTvrHugh28QzUXVOZtiYghciKUacNktqxdpymplil1beA==} 216 | engines: {node: '>=18'} 217 | cpu: [x64] 218 | os: [netbsd] 219 | 220 | '@esbuild/openbsd-arm64@0.23.1': 221 | resolution: {integrity: sha512-3x37szhLexNA4bXhLrCC/LImN/YtWis6WXr1VESlfVtVeoFJBRINPJ3f0a/6LV8zpikqoUg4hyXw0sFBt5Cr+Q==} 222 | engines: {node: '>=18'} 223 | cpu: [arm64] 224 | os: [openbsd] 225 | 226 | '@esbuild/openbsd-x64@0.23.1': 227 | resolution: {integrity: sha512-aY2gMmKmPhxfU+0EdnN+XNtGbjfQgwZj43k8G3fyrDM/UdZww6xrWxmDkuz2eCZchqVeABjV5BpildOrUbBTqA==} 228 | engines: {node: '>=18'} 229 | cpu: [x64] 230 | os: [openbsd] 231 | 232 | '@esbuild/sunos-x64@0.23.1': 233 | resolution: {integrity: sha512-RBRT2gqEl0IKQABT4XTj78tpk9v7ehp+mazn2HbUeZl1YMdaGAQqhapjGTCe7uw7y0frDi4gS0uHzhvpFuI1sA==} 234 | engines: {node: '>=18'} 235 | cpu: [x64] 236 | os: [sunos] 237 | 238 | '@esbuild/win32-arm64@0.23.1': 239 | resolution: {integrity: sha512-4O+gPR5rEBe2FpKOVyiJ7wNDPA8nGzDuJ6gN4okSA1gEOYZ67N8JPk58tkWtdtPeLz7lBnY6I5L3jdsr3S+A6A==} 240 | engines: {node: '>=18'} 241 | cpu: [arm64] 242 | os: [win32] 243 | 244 | '@esbuild/win32-ia32@0.23.1': 245 | resolution: {integrity: sha512-BcaL0Vn6QwCwre3Y717nVHZbAa4UBEigzFm6VdsVdT/MbZ38xoj1X9HPkZhbmaBGUD1W8vxAfffbDe8bA6AKnQ==} 246 | engines: {node: '>=18'} 247 | cpu: [ia32] 248 | os: [win32] 249 | 250 | '@esbuild/win32-x64@0.23.1': 251 | resolution: {integrity: sha512-BHpFFeslkWrXWyUPnbKm+xYYVYruCinGcftSBaa8zoF9hZO4BcSCFUvHVTtzpIY6YzUnYtuEhZ+C9iEXjxnasg==} 252 | engines: {node: '>=18'} 253 | cpu: [x64] 254 | os: [win32] 255 | 256 | '@isaacs/cliui@8.0.2': 257 | resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} 258 | engines: {node: '>=12'} 259 | 260 | '@types/conventional-commits-parser@5.0.0': 261 | resolution: {integrity: sha512-loB369iXNmAZglwWATL+WRe+CRMmmBPtpolYzIebFaX4YA3x+BEfLqhUAV9WanycKI3TG1IMr5bMJDajDKLlUQ==} 262 | 263 | '@types/node@16.18.118': 264 | resolution: {integrity: sha512-YgPbVGrf+mL4Qp8KTcd18OXfIsm1QYwHkldmWTNIR8aZH2EYSPNyLFFZHEXZIGYvYrwnW++xGoWyt4w279QDrQ==} 265 | 266 | JSONStream@1.3.5: 267 | resolution: {integrity: sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==} 268 | hasBin: true 269 | 270 | ajv@8.17.1: 271 | resolution: {integrity: sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==} 272 | 273 | ansi-regex@5.0.1: 274 | resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} 275 | engines: {node: '>=8'} 276 | 277 | ansi-regex@6.1.0: 278 | resolution: {integrity: sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==} 279 | engines: {node: '>=12'} 280 | 281 | ansi-styles@4.3.0: 282 | resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} 283 | engines: {node: '>=8'} 284 | 285 | ansi-styles@6.2.1: 286 | resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==} 287 | engines: {node: '>=12'} 288 | 289 | argparse@2.0.1: 290 | resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} 291 | 292 | array-ify@1.0.0: 293 | resolution: {integrity: sha512-c5AMf34bKdvPhQ7tBGhqkgKNUzMr4WUs+WDtC2ZUGOUncbxKMTvqxYctiseW3+L4bA8ec+GcZ6/A/FW4m8ukng==} 294 | 295 | balanced-match@1.0.2: 296 | resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} 297 | 298 | brace-expansion@2.0.1: 299 | resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} 300 | 301 | callsites@3.1.0: 302 | resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} 303 | engines: {node: '>=6'} 304 | 305 | chalk@5.3.0: 306 | resolution: {integrity: sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==} 307 | engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} 308 | 309 | cliui@8.0.1: 310 | resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} 311 | engines: {node: '>=12'} 312 | 313 | color-convert@2.0.1: 314 | resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} 315 | engines: {node: '>=7.0.0'} 316 | 317 | color-name@1.1.4: 318 | resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} 319 | 320 | compare-func@2.0.0: 321 | resolution: {integrity: sha512-zHig5N+tPWARooBnb0Zx1MFcdfpyJrfTJ3Y5L+IFvUm8rM74hHz66z0gw0x4tijh5CorKkKUCnW82R2vmpeCRA==} 322 | 323 | conventional-changelog-angular@7.0.0: 324 | resolution: {integrity: sha512-ROjNchA9LgfNMTTFSIWPzebCwOGFdgkEq45EnvvrmSLvCtAw0HSmrCs7/ty+wAeYUZyNay0YMUNYFTRL72PkBQ==} 325 | engines: {node: '>=16'} 326 | 327 | conventional-changelog-conventionalcommits@7.0.2: 328 | resolution: {integrity: sha512-NKXYmMR/Hr1DevQegFB4MwfM5Vv0m4UIxKZTTYuD98lpTknaZlSRrDOG4X7wIXpGkfsYxZTghUN+Qq+T0YQI7w==} 329 | engines: {node: '>=16'} 330 | 331 | conventional-commits-parser@5.0.0: 332 | resolution: {integrity: sha512-ZPMl0ZJbw74iS9LuX9YIAiW8pfM5p3yh2o/NbXHbkFuZzY5jvdi5jFycEOkmBW5H5I7nA+D6f3UcsCLP2vvSEA==} 333 | engines: {node: '>=16'} 334 | hasBin: true 335 | 336 | cosmiconfig-typescript-loader@5.1.0: 337 | resolution: {integrity: sha512-7PtBB+6FdsOvZyJtlF3hEPpACq7RQX6BVGsgC7/lfVXnKMvNCu/XY3ykreqG5w/rBNdu2z8LCIKoF3kpHHdHlA==} 338 | engines: {node: '>=v16'} 339 | peerDependencies: 340 | '@types/node': '*' 341 | cosmiconfig: '>=8.2' 342 | typescript: '>=4' 343 | 344 | cosmiconfig@9.0.0: 345 | resolution: {integrity: sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==} 346 | engines: {node: '>=14'} 347 | peerDependencies: 348 | typescript: '>=4.9.5' 349 | peerDependenciesMeta: 350 | typescript: 351 | optional: true 352 | 353 | cross-spawn@7.0.3: 354 | resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} 355 | engines: {node: '>= 8'} 356 | 357 | dargs@8.1.0: 358 | resolution: {integrity: sha512-wAV9QHOsNbwnWdNW2FYvE1P56wtgSbM+3SZcdGiWQILwVjACCXDCI3Ai8QlCjMDB8YK5zySiXZYBiwGmNY3lnw==} 359 | engines: {node: '>=12'} 360 | 361 | dot-prop@5.3.0: 362 | resolution: {integrity: sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==} 363 | engines: {node: '>=8'} 364 | 365 | eastasianwidth@0.2.0: 366 | resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} 367 | 368 | emoji-regex@8.0.0: 369 | resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} 370 | 371 | emoji-regex@9.2.2: 372 | resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} 373 | 374 | env-paths@2.2.1: 375 | resolution: {integrity: sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==} 376 | engines: {node: '>=6'} 377 | 378 | error-ex@1.3.2: 379 | resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==} 380 | 381 | esbuild@0.23.1: 382 | resolution: {integrity: sha512-VVNz/9Sa0bs5SELtn3f7qhJCDPCF5oMEl5cO9/SSinpE9hbPVvxbd572HH5AKiP7WD8INO53GgfDDhRjkylHEg==} 383 | engines: {node: '>=18'} 384 | hasBin: true 385 | 386 | escalade@3.2.0: 387 | resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} 388 | engines: {node: '>=6'} 389 | 390 | fast-deep-equal@3.1.3: 391 | resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} 392 | 393 | fast-uri@3.0.3: 394 | resolution: {integrity: sha512-aLrHthzCjH5He4Z2H9YZ+v6Ujb9ocRuW6ZzkJQOrTxleEijANq4v1TsaPaVG1PZcuurEzrLcWRyYBYXD5cEiaw==} 395 | 396 | find-up@7.0.0: 397 | resolution: {integrity: sha512-YyZM99iHrqLKjmt4LJDj58KI+fYyufRLBSYcqycxf//KpBk9FoewoGX0450m9nB44qrZnovzC2oeP5hUibxc/g==} 398 | engines: {node: '>=18'} 399 | 400 | foreground-child@3.3.0: 401 | resolution: {integrity: sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==} 402 | engines: {node: '>=14'} 403 | 404 | fsevents@2.3.3: 405 | resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} 406 | engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} 407 | os: [darwin] 408 | 409 | get-caller-file@2.0.5: 410 | resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} 411 | engines: {node: 6.* || 8.* || >= 10.*} 412 | 413 | get-tsconfig@4.8.1: 414 | resolution: {integrity: sha512-k9PN+cFBmaLWtVz29SkUoqU5O0slLuHJXt/2P+tMVFT+phsSGXGkp9t3rQIqdz0e+06EHNGs3oM6ZX1s2zHxRg==} 415 | 416 | git-raw-commits@4.0.0: 417 | resolution: {integrity: sha512-ICsMM1Wk8xSGMowkOmPrzo2Fgmfo4bMHLNX6ytHjajRJUqvHOw/TFapQ+QG75c3X/tTDDhOSRPGC52dDbNM8FQ==} 418 | engines: {node: '>=16'} 419 | hasBin: true 420 | 421 | glob@11.0.0: 422 | resolution: {integrity: sha512-9UiX/Bl6J2yaBbxKoEBRm4Cipxgok8kQYcOPEhScPwebu2I0HoQOuYdIO6S3hLuWoZgpDpwQZMzTFxgpkyT76g==} 423 | engines: {node: 20 || >=22} 424 | hasBin: true 425 | 426 | global-directory@4.0.1: 427 | resolution: {integrity: sha512-wHTUcDUoZ1H5/0iVqEudYW4/kAlN5cZ3j/bXn0Dpbizl9iaUVeWSHqiOjsgk6OW2bkLclbBjzewBz6weQ1zA2Q==} 428 | engines: {node: '>=18'} 429 | 430 | husky@9.1.6: 431 | resolution: {integrity: sha512-sqbjZKK7kf44hfdE94EoX8MZNk0n7HeW37O4YrVGCF4wzgQjp+akPAkfUK5LZ6KuR/6sqeAVuXHji+RzQgOn5A==} 432 | engines: {node: '>=18'} 433 | hasBin: true 434 | 435 | import-fresh@3.3.0: 436 | resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==} 437 | engines: {node: '>=6'} 438 | 439 | import-meta-resolve@4.1.0: 440 | resolution: {integrity: sha512-I6fiaX09Xivtk+THaMfAwnA3MVA5Big1WHF1Dfx9hFuvNIWpXnorlkzhcQf6ehrqQiiZECRt1poOAkPmer3ruw==} 441 | 442 | ini@4.1.1: 443 | resolution: {integrity: sha512-QQnnxNyfvmHFIsj7gkPcYymR8Jdw/o7mp5ZFihxn6h8Ci6fh3Dx4E1gPjpQEpIuPo9XVNY/ZUwh4BPMjGyL01g==} 444 | engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} 445 | 446 | is-arrayish@0.2.1: 447 | resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} 448 | 449 | is-fullwidth-code-point@3.0.0: 450 | resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} 451 | engines: {node: '>=8'} 452 | 453 | is-obj@2.0.0: 454 | resolution: {integrity: sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==} 455 | engines: {node: '>=8'} 456 | 457 | is-text-path@2.0.0: 458 | resolution: {integrity: sha512-+oDTluR6WEjdXEJMnC2z6A4FRwFoYuvShVVEGsS7ewc0UTi2QtAKMDJuL4BDEVt+5T7MjFo12RP8ghOM75oKJw==} 459 | engines: {node: '>=8'} 460 | 461 | isexe@2.0.0: 462 | resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} 463 | 464 | jackspeak@4.0.2: 465 | resolution: {integrity: sha512-bZsjR/iRjl1Nk1UkjGpAzLNfQtzuijhn2g+pbZb98HQ1Gk8vM9hfbxeMBP+M2/UUdwj0RqGG3mlvk2MsAqwvEw==} 466 | engines: {node: 20 || >=22} 467 | 468 | jiti@1.21.6: 469 | resolution: {integrity: sha512-2yTgeWTWzMWkHu6Jp9NKgePDaYHbntiwvYuuJLbbN9vl7DC9DvXKOB2BC3ZZ92D3cvV/aflH0osDfwpHepQ53w==} 470 | hasBin: true 471 | 472 | js-tokens@4.0.0: 473 | resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} 474 | 475 | js-yaml@4.1.0: 476 | resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} 477 | hasBin: true 478 | 479 | json-parse-even-better-errors@2.3.1: 480 | resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} 481 | 482 | json-schema-traverse@1.0.0: 483 | resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} 484 | 485 | jsonparse@1.3.1: 486 | resolution: {integrity: sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==} 487 | engines: {'0': node >= 0.2.0} 488 | 489 | lines-and-columns@1.2.4: 490 | resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} 491 | 492 | locate-path@7.2.0: 493 | resolution: {integrity: sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA==} 494 | engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} 495 | 496 | lodash.camelcase@4.3.0: 497 | resolution: {integrity: sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==} 498 | 499 | lodash.isplainobject@4.0.6: 500 | resolution: {integrity: sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==} 501 | 502 | lodash.kebabcase@4.1.1: 503 | resolution: {integrity: sha512-N8XRTIMMqqDgSy4VLKPnJ/+hpGZN+PHQiJnSenYqPaVV/NCqEogTnAdZLQiGKhxX+JCs8waWq2t1XHWKOmlY8g==} 504 | 505 | lodash.merge@4.6.2: 506 | resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} 507 | 508 | lodash.mergewith@4.6.2: 509 | resolution: {integrity: sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ==} 510 | 511 | lodash.snakecase@4.1.1: 512 | resolution: {integrity: sha512-QZ1d4xoBHYUeuouhEq3lk3Uq7ldgyFXGBhg04+oRLnIz8o9T65Eh+8YdroUwn846zchkA9yDsDl5CVVaV2nqYw==} 513 | 514 | lodash.startcase@4.4.0: 515 | resolution: {integrity: sha512-+WKqsK294HMSc2jEbNgpHpd0JfIBhp7rEV4aqXWqFr6AlXov+SlcgB1Fv01y2kGe3Gc8nMW7VA0SrGuSkRfIEg==} 516 | 517 | lodash.uniq@4.5.0: 518 | resolution: {integrity: sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==} 519 | 520 | lodash.upperfirst@4.3.1: 521 | resolution: {integrity: sha512-sReKOYJIJf74dhJONhU4e0/shzi1trVbSWDOhKYE5XV2O+H7Sb2Dihwuc7xWxVl+DgFPyTqIN3zMfT9cq5iWDg==} 522 | 523 | lru-cache@11.0.2: 524 | resolution: {integrity: sha512-123qHRfJBmo2jXDbo/a5YOQrJoHF/GNQTLzQ5+IdK5pWpceK17yRc6ozlWd25FxvGKQbIUs91fDFkXmDHTKcyA==} 525 | engines: {node: 20 || >=22} 526 | 527 | meow@12.1.1: 528 | resolution: {integrity: sha512-BhXM0Au22RwUneMPwSCnyhTOizdWoIEPU9sp0Aqa1PnDMR5Wv2FGXYDjuzJEIX+Eo2Rb8xuYe5jrnm5QowQFkw==} 529 | engines: {node: '>=16.10'} 530 | 531 | minimatch@10.0.1: 532 | resolution: {integrity: sha512-ethXTt3SGGR+95gudmqJ1eNhRO7eGEGIgYA9vnPatK4/etz2MEVDno5GMCibdMTuBMyElzIlgxMna3K94XDIDQ==} 533 | engines: {node: 20 || >=22} 534 | 535 | minimist@1.2.8: 536 | resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} 537 | 538 | minipass@7.1.2: 539 | resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} 540 | engines: {node: '>=16 || 14 >=14.17'} 541 | 542 | p-limit@4.0.0: 543 | resolution: {integrity: sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==} 544 | engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} 545 | 546 | p-locate@6.0.0: 547 | resolution: {integrity: sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==} 548 | engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} 549 | 550 | package-json-from-dist@1.0.1: 551 | resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} 552 | 553 | parent-module@1.0.1: 554 | resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} 555 | engines: {node: '>=6'} 556 | 557 | parse-json@5.2.0: 558 | resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} 559 | engines: {node: '>=8'} 560 | 561 | path-exists@5.0.0: 562 | resolution: {integrity: sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==} 563 | engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} 564 | 565 | path-key@3.1.1: 566 | resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} 567 | engines: {node: '>=8'} 568 | 569 | path-scurry@2.0.0: 570 | resolution: {integrity: sha512-ypGJsmGtdXUOeM5u93TyeIEfEhM6s+ljAhrk5vAvSx8uyY/02OvrZnA0YNGUrPXfpJMgI1ODd3nwz8Npx4O4cg==} 571 | engines: {node: 20 || >=22} 572 | 573 | picocolors@1.1.1: 574 | resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} 575 | 576 | require-directory@2.1.1: 577 | resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} 578 | engines: {node: '>=0.10.0'} 579 | 580 | require-from-string@2.0.2: 581 | resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} 582 | engines: {node: '>=0.10.0'} 583 | 584 | resolve-from@4.0.0: 585 | resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} 586 | engines: {node: '>=4'} 587 | 588 | resolve-from@5.0.0: 589 | resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} 590 | engines: {node: '>=8'} 591 | 592 | resolve-pkg-maps@1.0.0: 593 | resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} 594 | 595 | rimraf@6.0.1: 596 | resolution: {integrity: sha512-9dkvaxAsk/xNXSJzMgFqqMCuFgt2+KsOFek3TMLfo8NCPfWpBmqwyNn5Y+NX56QUYfCtsyhF3ayiboEoUmJk/A==} 597 | engines: {node: 20 || >=22} 598 | hasBin: true 599 | 600 | semver@7.6.3: 601 | resolution: {integrity: sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==} 602 | engines: {node: '>=10'} 603 | hasBin: true 604 | 605 | shebang-command@2.0.0: 606 | resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} 607 | engines: {node: '>=8'} 608 | 609 | shebang-regex@3.0.0: 610 | resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} 611 | engines: {node: '>=8'} 612 | 613 | signal-exit@4.1.0: 614 | resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} 615 | engines: {node: '>=14'} 616 | 617 | split2@4.2.0: 618 | resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==} 619 | engines: {node: '>= 10.x'} 620 | 621 | string-width@4.2.3: 622 | resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} 623 | engines: {node: '>=8'} 624 | 625 | string-width@5.1.2: 626 | resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} 627 | engines: {node: '>=12'} 628 | 629 | strip-ansi@6.0.1: 630 | resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} 631 | engines: {node: '>=8'} 632 | 633 | strip-ansi@7.1.0: 634 | resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==} 635 | engines: {node: '>=12'} 636 | 637 | text-extensions@2.4.0: 638 | resolution: {integrity: sha512-te/NtwBwfiNRLf9Ijqx3T0nlqZiQ2XrrtBvu+cLL8ZRrGkO0NHTug8MYFKyoSrv/sHTaSKfilUkizV6XhxMJ3g==} 639 | engines: {node: '>=8'} 640 | 641 | through@2.3.8: 642 | resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==} 643 | 644 | tinyexec@0.3.1: 645 | resolution: {integrity: sha512-WiCJLEECkO18gwqIp6+hJg0//p23HXp4S+gGtAKu3mI2F2/sXC4FvHvXvB0zJVVaTPhx1/tOwdbRsa1sOBIKqQ==} 646 | 647 | tsx@4.19.2: 648 | resolution: {integrity: sha512-pOUl6Vo2LUq/bSa8S5q7b91cgNSjctn9ugq/+Mvow99qW6x/UZYwzxy/3NmqoT66eHYfCVvFvACC58UBPFf28g==} 649 | engines: {node: '>=18.0.0'} 650 | hasBin: true 651 | 652 | typescript@4.9.5: 653 | resolution: {integrity: sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==} 654 | engines: {node: '>=4.2.0'} 655 | hasBin: true 656 | 657 | unicorn-magic@0.1.0: 658 | resolution: {integrity: sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ==} 659 | engines: {node: '>=18'} 660 | 661 | which@2.0.2: 662 | resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} 663 | engines: {node: '>= 8'} 664 | hasBin: true 665 | 666 | wrap-ansi@7.0.0: 667 | resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} 668 | engines: {node: '>=10'} 669 | 670 | wrap-ansi@8.1.0: 671 | resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} 672 | engines: {node: '>=12'} 673 | 674 | y18n@5.0.8: 675 | resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} 676 | engines: {node: '>=10'} 677 | 678 | yargs-parser@21.1.1: 679 | resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} 680 | engines: {node: '>=12'} 681 | 682 | yargs@17.7.2: 683 | resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} 684 | engines: {node: '>=12'} 685 | 686 | yocto-queue@1.1.1: 687 | resolution: {integrity: sha512-b4JR1PFR10y1mKjhHY9LaGo6tmrgjit7hxVIeAmyMw3jegXR4dhYqLaQF5zMXZxY7tLpMyJeLjr1C4rLmkVe8g==} 688 | engines: {node: '>=12.20'} 689 | 690 | snapshots: 691 | 692 | '@babel/code-frame@7.26.2': 693 | dependencies: 694 | '@babel/helper-validator-identifier': 7.25.9 695 | js-tokens: 4.0.0 696 | picocolors: 1.1.1 697 | 698 | '@babel/helper-validator-identifier@7.25.9': {} 699 | 700 | '@commitlint/cli@19.5.0(@types/node@16.18.118)(typescript@4.9.5)': 701 | dependencies: 702 | '@commitlint/format': 19.5.0 703 | '@commitlint/lint': 19.5.0 704 | '@commitlint/load': 19.5.0(@types/node@16.18.118)(typescript@4.9.5) 705 | '@commitlint/read': 19.5.0 706 | '@commitlint/types': 19.5.0 707 | tinyexec: 0.3.1 708 | yargs: 17.7.2 709 | transitivePeerDependencies: 710 | - '@types/node' 711 | - typescript 712 | 713 | '@commitlint/config-conventional@19.5.0': 714 | dependencies: 715 | '@commitlint/types': 19.5.0 716 | conventional-changelog-conventionalcommits: 7.0.2 717 | 718 | '@commitlint/config-validator@19.5.0': 719 | dependencies: 720 | '@commitlint/types': 19.5.0 721 | ajv: 8.17.1 722 | 723 | '@commitlint/ensure@19.5.0': 724 | dependencies: 725 | '@commitlint/types': 19.5.0 726 | lodash.camelcase: 4.3.0 727 | lodash.kebabcase: 4.1.1 728 | lodash.snakecase: 4.1.1 729 | lodash.startcase: 4.4.0 730 | lodash.upperfirst: 4.3.1 731 | 732 | '@commitlint/execute-rule@19.5.0': {} 733 | 734 | '@commitlint/format@19.5.0': 735 | dependencies: 736 | '@commitlint/types': 19.5.0 737 | chalk: 5.3.0 738 | 739 | '@commitlint/is-ignored@19.5.0': 740 | dependencies: 741 | '@commitlint/types': 19.5.0 742 | semver: 7.6.3 743 | 744 | '@commitlint/lint@19.5.0': 745 | dependencies: 746 | '@commitlint/is-ignored': 19.5.0 747 | '@commitlint/parse': 19.5.0 748 | '@commitlint/rules': 19.5.0 749 | '@commitlint/types': 19.5.0 750 | 751 | '@commitlint/load@19.5.0(@types/node@16.18.118)(typescript@4.9.5)': 752 | dependencies: 753 | '@commitlint/config-validator': 19.5.0 754 | '@commitlint/execute-rule': 19.5.0 755 | '@commitlint/resolve-extends': 19.5.0 756 | '@commitlint/types': 19.5.0 757 | chalk: 5.3.0 758 | cosmiconfig: 9.0.0(typescript@4.9.5) 759 | cosmiconfig-typescript-loader: 5.1.0(@types/node@16.18.118)(cosmiconfig@9.0.0(typescript@4.9.5))(typescript@4.9.5) 760 | lodash.isplainobject: 4.0.6 761 | lodash.merge: 4.6.2 762 | lodash.uniq: 4.5.0 763 | transitivePeerDependencies: 764 | - '@types/node' 765 | - typescript 766 | 767 | '@commitlint/message@19.5.0': {} 768 | 769 | '@commitlint/parse@19.5.0': 770 | dependencies: 771 | '@commitlint/types': 19.5.0 772 | conventional-changelog-angular: 7.0.0 773 | conventional-commits-parser: 5.0.0 774 | 775 | '@commitlint/read@19.5.0': 776 | dependencies: 777 | '@commitlint/top-level': 19.5.0 778 | '@commitlint/types': 19.5.0 779 | git-raw-commits: 4.0.0 780 | minimist: 1.2.8 781 | tinyexec: 0.3.1 782 | 783 | '@commitlint/resolve-extends@19.5.0': 784 | dependencies: 785 | '@commitlint/config-validator': 19.5.0 786 | '@commitlint/types': 19.5.0 787 | global-directory: 4.0.1 788 | import-meta-resolve: 4.1.0 789 | lodash.mergewith: 4.6.2 790 | resolve-from: 5.0.0 791 | 792 | '@commitlint/rules@19.5.0': 793 | dependencies: 794 | '@commitlint/ensure': 19.5.0 795 | '@commitlint/message': 19.5.0 796 | '@commitlint/to-lines': 19.5.0 797 | '@commitlint/types': 19.5.0 798 | 799 | '@commitlint/to-lines@19.5.0': {} 800 | 801 | '@commitlint/top-level@19.5.0': 802 | dependencies: 803 | find-up: 7.0.0 804 | 805 | '@commitlint/types@19.5.0': 806 | dependencies: 807 | '@types/conventional-commits-parser': 5.0.0 808 | chalk: 5.3.0 809 | 810 | '@esbuild/aix-ppc64@0.23.1': 811 | optional: true 812 | 813 | '@esbuild/android-arm64@0.23.1': 814 | optional: true 815 | 816 | '@esbuild/android-arm@0.23.1': 817 | optional: true 818 | 819 | '@esbuild/android-x64@0.23.1': 820 | optional: true 821 | 822 | '@esbuild/darwin-arm64@0.23.1': 823 | optional: true 824 | 825 | '@esbuild/darwin-x64@0.23.1': 826 | optional: true 827 | 828 | '@esbuild/freebsd-arm64@0.23.1': 829 | optional: true 830 | 831 | '@esbuild/freebsd-x64@0.23.1': 832 | optional: true 833 | 834 | '@esbuild/linux-arm64@0.23.1': 835 | optional: true 836 | 837 | '@esbuild/linux-arm@0.23.1': 838 | optional: true 839 | 840 | '@esbuild/linux-ia32@0.23.1': 841 | optional: true 842 | 843 | '@esbuild/linux-loong64@0.23.1': 844 | optional: true 845 | 846 | '@esbuild/linux-mips64el@0.23.1': 847 | optional: true 848 | 849 | '@esbuild/linux-ppc64@0.23.1': 850 | optional: true 851 | 852 | '@esbuild/linux-riscv64@0.23.1': 853 | optional: true 854 | 855 | '@esbuild/linux-s390x@0.23.1': 856 | optional: true 857 | 858 | '@esbuild/linux-x64@0.23.1': 859 | optional: true 860 | 861 | '@esbuild/netbsd-x64@0.23.1': 862 | optional: true 863 | 864 | '@esbuild/openbsd-arm64@0.23.1': 865 | optional: true 866 | 867 | '@esbuild/openbsd-x64@0.23.1': 868 | optional: true 869 | 870 | '@esbuild/sunos-x64@0.23.1': 871 | optional: true 872 | 873 | '@esbuild/win32-arm64@0.23.1': 874 | optional: true 875 | 876 | '@esbuild/win32-ia32@0.23.1': 877 | optional: true 878 | 879 | '@esbuild/win32-x64@0.23.1': 880 | optional: true 881 | 882 | '@isaacs/cliui@8.0.2': 883 | dependencies: 884 | string-width: 5.1.2 885 | string-width-cjs: string-width@4.2.3 886 | strip-ansi: 7.1.0 887 | strip-ansi-cjs: strip-ansi@6.0.1 888 | wrap-ansi: 8.1.0 889 | wrap-ansi-cjs: wrap-ansi@7.0.0 890 | 891 | '@types/conventional-commits-parser@5.0.0': 892 | dependencies: 893 | '@types/node': 16.18.118 894 | 895 | '@types/node@16.18.118': {} 896 | 897 | JSONStream@1.3.5: 898 | dependencies: 899 | jsonparse: 1.3.1 900 | through: 2.3.8 901 | 902 | ajv@8.17.1: 903 | dependencies: 904 | fast-deep-equal: 3.1.3 905 | fast-uri: 3.0.3 906 | json-schema-traverse: 1.0.0 907 | require-from-string: 2.0.2 908 | 909 | ansi-regex@5.0.1: {} 910 | 911 | ansi-regex@6.1.0: {} 912 | 913 | ansi-styles@4.3.0: 914 | dependencies: 915 | color-convert: 2.0.1 916 | 917 | ansi-styles@6.2.1: {} 918 | 919 | argparse@2.0.1: {} 920 | 921 | array-ify@1.0.0: {} 922 | 923 | balanced-match@1.0.2: {} 924 | 925 | brace-expansion@2.0.1: 926 | dependencies: 927 | balanced-match: 1.0.2 928 | 929 | callsites@3.1.0: {} 930 | 931 | chalk@5.3.0: {} 932 | 933 | cliui@8.0.1: 934 | dependencies: 935 | string-width: 4.2.3 936 | strip-ansi: 6.0.1 937 | wrap-ansi: 7.0.0 938 | 939 | color-convert@2.0.1: 940 | dependencies: 941 | color-name: 1.1.4 942 | 943 | color-name@1.1.4: {} 944 | 945 | compare-func@2.0.0: 946 | dependencies: 947 | array-ify: 1.0.0 948 | dot-prop: 5.3.0 949 | 950 | conventional-changelog-angular@7.0.0: 951 | dependencies: 952 | compare-func: 2.0.0 953 | 954 | conventional-changelog-conventionalcommits@7.0.2: 955 | dependencies: 956 | compare-func: 2.0.0 957 | 958 | conventional-commits-parser@5.0.0: 959 | dependencies: 960 | JSONStream: 1.3.5 961 | is-text-path: 2.0.0 962 | meow: 12.1.1 963 | split2: 4.2.0 964 | 965 | cosmiconfig-typescript-loader@5.1.0(@types/node@16.18.118)(cosmiconfig@9.0.0(typescript@4.9.5))(typescript@4.9.5): 966 | dependencies: 967 | '@types/node': 16.18.118 968 | cosmiconfig: 9.0.0(typescript@4.9.5) 969 | jiti: 1.21.6 970 | typescript: 4.9.5 971 | 972 | cosmiconfig@9.0.0(typescript@4.9.5): 973 | dependencies: 974 | env-paths: 2.2.1 975 | import-fresh: 3.3.0 976 | js-yaml: 4.1.0 977 | parse-json: 5.2.0 978 | optionalDependencies: 979 | typescript: 4.9.5 980 | 981 | cross-spawn@7.0.3: 982 | dependencies: 983 | path-key: 3.1.1 984 | shebang-command: 2.0.0 985 | which: 2.0.2 986 | 987 | dargs@8.1.0: {} 988 | 989 | dot-prop@5.3.0: 990 | dependencies: 991 | is-obj: 2.0.0 992 | 993 | eastasianwidth@0.2.0: {} 994 | 995 | emoji-regex@8.0.0: {} 996 | 997 | emoji-regex@9.2.2: {} 998 | 999 | env-paths@2.2.1: {} 1000 | 1001 | error-ex@1.3.2: 1002 | dependencies: 1003 | is-arrayish: 0.2.1 1004 | 1005 | esbuild@0.23.1: 1006 | optionalDependencies: 1007 | '@esbuild/aix-ppc64': 0.23.1 1008 | '@esbuild/android-arm': 0.23.1 1009 | '@esbuild/android-arm64': 0.23.1 1010 | '@esbuild/android-x64': 0.23.1 1011 | '@esbuild/darwin-arm64': 0.23.1 1012 | '@esbuild/darwin-x64': 0.23.1 1013 | '@esbuild/freebsd-arm64': 0.23.1 1014 | '@esbuild/freebsd-x64': 0.23.1 1015 | '@esbuild/linux-arm': 0.23.1 1016 | '@esbuild/linux-arm64': 0.23.1 1017 | '@esbuild/linux-ia32': 0.23.1 1018 | '@esbuild/linux-loong64': 0.23.1 1019 | '@esbuild/linux-mips64el': 0.23.1 1020 | '@esbuild/linux-ppc64': 0.23.1 1021 | '@esbuild/linux-riscv64': 0.23.1 1022 | '@esbuild/linux-s390x': 0.23.1 1023 | '@esbuild/linux-x64': 0.23.1 1024 | '@esbuild/netbsd-x64': 0.23.1 1025 | '@esbuild/openbsd-arm64': 0.23.1 1026 | '@esbuild/openbsd-x64': 0.23.1 1027 | '@esbuild/sunos-x64': 0.23.1 1028 | '@esbuild/win32-arm64': 0.23.1 1029 | '@esbuild/win32-ia32': 0.23.1 1030 | '@esbuild/win32-x64': 0.23.1 1031 | 1032 | escalade@3.2.0: {} 1033 | 1034 | fast-deep-equal@3.1.3: {} 1035 | 1036 | fast-uri@3.0.3: {} 1037 | 1038 | find-up@7.0.0: 1039 | dependencies: 1040 | locate-path: 7.2.0 1041 | path-exists: 5.0.0 1042 | unicorn-magic: 0.1.0 1043 | 1044 | foreground-child@3.3.0: 1045 | dependencies: 1046 | cross-spawn: 7.0.3 1047 | signal-exit: 4.1.0 1048 | 1049 | fsevents@2.3.3: 1050 | optional: true 1051 | 1052 | get-caller-file@2.0.5: {} 1053 | 1054 | get-tsconfig@4.8.1: 1055 | dependencies: 1056 | resolve-pkg-maps: 1.0.0 1057 | 1058 | git-raw-commits@4.0.0: 1059 | dependencies: 1060 | dargs: 8.1.0 1061 | meow: 12.1.1 1062 | split2: 4.2.0 1063 | 1064 | glob@11.0.0: 1065 | dependencies: 1066 | foreground-child: 3.3.0 1067 | jackspeak: 4.0.2 1068 | minimatch: 10.0.1 1069 | minipass: 7.1.2 1070 | package-json-from-dist: 1.0.1 1071 | path-scurry: 2.0.0 1072 | 1073 | global-directory@4.0.1: 1074 | dependencies: 1075 | ini: 4.1.1 1076 | 1077 | husky@9.1.6: {} 1078 | 1079 | import-fresh@3.3.0: 1080 | dependencies: 1081 | parent-module: 1.0.1 1082 | resolve-from: 4.0.0 1083 | 1084 | import-meta-resolve@4.1.0: {} 1085 | 1086 | ini@4.1.1: {} 1087 | 1088 | is-arrayish@0.2.1: {} 1089 | 1090 | is-fullwidth-code-point@3.0.0: {} 1091 | 1092 | is-obj@2.0.0: {} 1093 | 1094 | is-text-path@2.0.0: 1095 | dependencies: 1096 | text-extensions: 2.4.0 1097 | 1098 | isexe@2.0.0: {} 1099 | 1100 | jackspeak@4.0.2: 1101 | dependencies: 1102 | '@isaacs/cliui': 8.0.2 1103 | 1104 | jiti@1.21.6: {} 1105 | 1106 | js-tokens@4.0.0: {} 1107 | 1108 | js-yaml@4.1.0: 1109 | dependencies: 1110 | argparse: 2.0.1 1111 | 1112 | json-parse-even-better-errors@2.3.1: {} 1113 | 1114 | json-schema-traverse@1.0.0: {} 1115 | 1116 | jsonparse@1.3.1: {} 1117 | 1118 | lines-and-columns@1.2.4: {} 1119 | 1120 | locate-path@7.2.0: 1121 | dependencies: 1122 | p-locate: 6.0.0 1123 | 1124 | lodash.camelcase@4.3.0: {} 1125 | 1126 | lodash.isplainobject@4.0.6: {} 1127 | 1128 | lodash.kebabcase@4.1.1: {} 1129 | 1130 | lodash.merge@4.6.2: {} 1131 | 1132 | lodash.mergewith@4.6.2: {} 1133 | 1134 | lodash.snakecase@4.1.1: {} 1135 | 1136 | lodash.startcase@4.4.0: {} 1137 | 1138 | lodash.uniq@4.5.0: {} 1139 | 1140 | lodash.upperfirst@4.3.1: {} 1141 | 1142 | lru-cache@11.0.2: {} 1143 | 1144 | meow@12.1.1: {} 1145 | 1146 | minimatch@10.0.1: 1147 | dependencies: 1148 | brace-expansion: 2.0.1 1149 | 1150 | minimist@1.2.8: {} 1151 | 1152 | minipass@7.1.2: {} 1153 | 1154 | p-limit@4.0.0: 1155 | dependencies: 1156 | yocto-queue: 1.1.1 1157 | 1158 | p-locate@6.0.0: 1159 | dependencies: 1160 | p-limit: 4.0.0 1161 | 1162 | package-json-from-dist@1.0.1: {} 1163 | 1164 | parent-module@1.0.1: 1165 | dependencies: 1166 | callsites: 3.1.0 1167 | 1168 | parse-json@5.2.0: 1169 | dependencies: 1170 | '@babel/code-frame': 7.26.2 1171 | error-ex: 1.3.2 1172 | json-parse-even-better-errors: 2.3.1 1173 | lines-and-columns: 1.2.4 1174 | 1175 | path-exists@5.0.0: {} 1176 | 1177 | path-key@3.1.1: {} 1178 | 1179 | path-scurry@2.0.0: 1180 | dependencies: 1181 | lru-cache: 11.0.2 1182 | minipass: 7.1.2 1183 | 1184 | picocolors@1.1.1: {} 1185 | 1186 | require-directory@2.1.1: {} 1187 | 1188 | require-from-string@2.0.2: {} 1189 | 1190 | resolve-from@4.0.0: {} 1191 | 1192 | resolve-from@5.0.0: {} 1193 | 1194 | resolve-pkg-maps@1.0.0: {} 1195 | 1196 | rimraf@6.0.1: 1197 | dependencies: 1198 | glob: 11.0.0 1199 | package-json-from-dist: 1.0.1 1200 | 1201 | semver@7.6.3: {} 1202 | 1203 | shebang-command@2.0.0: 1204 | dependencies: 1205 | shebang-regex: 3.0.0 1206 | 1207 | shebang-regex@3.0.0: {} 1208 | 1209 | signal-exit@4.1.0: {} 1210 | 1211 | split2@4.2.0: {} 1212 | 1213 | string-width@4.2.3: 1214 | dependencies: 1215 | emoji-regex: 8.0.0 1216 | is-fullwidth-code-point: 3.0.0 1217 | strip-ansi: 6.0.1 1218 | 1219 | string-width@5.1.2: 1220 | dependencies: 1221 | eastasianwidth: 0.2.0 1222 | emoji-regex: 9.2.2 1223 | strip-ansi: 7.1.0 1224 | 1225 | strip-ansi@6.0.1: 1226 | dependencies: 1227 | ansi-regex: 5.0.1 1228 | 1229 | strip-ansi@7.1.0: 1230 | dependencies: 1231 | ansi-regex: 6.1.0 1232 | 1233 | text-extensions@2.4.0: {} 1234 | 1235 | through@2.3.8: {} 1236 | 1237 | tinyexec@0.3.1: {} 1238 | 1239 | tsx@4.19.2: 1240 | dependencies: 1241 | esbuild: 0.23.1 1242 | get-tsconfig: 4.8.1 1243 | optionalDependencies: 1244 | fsevents: 2.3.3 1245 | 1246 | typescript@4.9.5: {} 1247 | 1248 | unicorn-magic@0.1.0: {} 1249 | 1250 | which@2.0.2: 1251 | dependencies: 1252 | isexe: 2.0.0 1253 | 1254 | wrap-ansi@7.0.0: 1255 | dependencies: 1256 | ansi-styles: 4.3.0 1257 | string-width: 4.2.3 1258 | strip-ansi: 6.0.1 1259 | 1260 | wrap-ansi@8.1.0: 1261 | dependencies: 1262 | ansi-styles: 6.2.1 1263 | string-width: 5.1.2 1264 | strip-ansi: 7.1.0 1265 | 1266 | y18n@5.0.8: {} 1267 | 1268 | yargs-parser@21.1.1: {} 1269 | 1270 | yargs@17.7.2: 1271 | dependencies: 1272 | cliui: 8.0.1 1273 | escalade: 3.2.0 1274 | get-caller-file: 2.0.5 1275 | require-directory: 2.1.1 1276 | string-width: 4.2.3 1277 | y18n: 5.0.8 1278 | yargs-parser: 21.1.1 1279 | 1280 | yocto-queue@1.1.1: {} 1281 | --------------------------------------------------------------------------------