@corpus-core/colibri-tor 1.1.22
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +90 -0
- package/dist/browser.d.ts +48 -0
- package/dist/browser.js +96 -0
- package/dist/index.d.ts +25 -0
- package/dist/index.js +24 -0
- package/dist/node.d.ts +34 -0
- package/dist/node.js +275 -0
- package/dist/types.d.ts +39 -0
- package/dist/types.js +23 -0
- package/node_modules/tor-js/README.md +166 -0
- package/node_modules/tor-js/dist/Log.d.ts +24 -0
- package/node_modules/tor-js/dist/Log.d.ts.map +1 -0
- package/node_modules/tor-js/dist/TorClient.d.ts +37 -0
- package/node_modules/tor-js/dist/TorClient.d.ts.map +1 -0
- package/node_modules/tor-js/dist/commonExports.d.ts +6 -0
- package/node_modules/tor-js/dist/commonExports.d.ts.map +1 -0
- package/node_modules/tor-js/dist/entryPoints/wasm-base64/index.d.ts +3 -0
- package/node_modules/tor-js/dist/entryPoints/wasm-base64/index.d.ts.map +1 -0
- package/node_modules/tor-js/dist/entryPoints/wasm-base64/index.js +2139 -0
- package/node_modules/tor-js/dist/entryPoints/wasm-base64/index.js.map +1 -0
- package/node_modules/tor-js/dist/entryPoints/wasm-base64/singleton.d.ts +4 -0
- package/node_modules/tor-js/dist/entryPoints/wasm-base64/singleton.d.ts.map +1 -0
- package/node_modules/tor-js/dist/entryPoints/wasm-base64/singleton.js +2187 -0
- package/node_modules/tor-js/dist/entryPoints/wasm-base64/singleton.js.map +1 -0
- package/node_modules/tor-js/dist/entryPoints/wasm-cdn/index.d.ts +3 -0
- package/node_modules/tor-js/dist/entryPoints/wasm-cdn/index.d.ts.map +1 -0
- package/node_modules/tor-js/dist/entryPoints/wasm-cdn/index.js +2242 -0
- package/node_modules/tor-js/dist/entryPoints/wasm-cdn/index.js.map +1 -0
- package/node_modules/tor-js/dist/entryPoints/wasm-cdn/singleton.d.ts +4 -0
- package/node_modules/tor-js/dist/entryPoints/wasm-cdn/singleton.d.ts.map +1 -0
- package/node_modules/tor-js/dist/entryPoints/wasm-cdn/singleton.js +2290 -0
- package/node_modules/tor-js/dist/entryPoints/wasm-cdn/singleton.js.map +1 -0
- package/node_modules/tor-js/dist/entryPoints/wasm-file/index.d.ts +3 -0
- package/node_modules/tor-js/dist/entryPoints/wasm-file/index.d.ts.map +1 -0
- package/node_modules/tor-js/dist/entryPoints/wasm-file/index.js +2139 -0
- package/node_modules/tor-js/dist/entryPoints/wasm-file/index.js.map +1 -0
- package/node_modules/tor-js/dist/entryPoints/wasm-file/singleton.d.ts +4 -0
- package/node_modules/tor-js/dist/entryPoints/wasm-file/singleton.d.ts.map +1 -0
- package/node_modules/tor-js/dist/entryPoints/wasm-file/singleton.js +2187 -0
- package/node_modules/tor-js/dist/entryPoints/wasm-file/singleton.js.map +1 -0
- package/node_modules/tor-js/dist/helpers.d.ts +7 -0
- package/node_modules/tor-js/dist/helpers.d.ts.map +1 -0
- package/node_modules/tor-js/dist/polyfills.d.ts +1 -0
- package/node_modules/tor-js/dist/polyfills.d.ts.map +1 -0
- package/node_modules/tor-js/dist/singleton.d.ts +24 -0
- package/node_modules/tor-js/dist/singleton.d.ts.map +1 -0
- package/node_modules/tor-js/dist/socketProvider.d.ts +76 -0
- package/node_modules/tor-js/dist/socketProvider.d.ts.map +1 -0
- package/node_modules/tor-js/dist/storage/filesystem.d.ts +18 -0
- package/node_modules/tor-js/dist/storage/filesystem.d.ts.map +1 -0
- package/node_modules/tor-js/dist/storage/index.d.ts +7 -0
- package/node_modules/tor-js/dist/storage/index.d.ts.map +1 -0
- package/node_modules/tor-js/dist/storage/indexeddb.d.ts +14 -0
- package/node_modules/tor-js/dist/storage/indexeddb.d.ts.map +1 -0
- package/node_modules/tor-js/dist/storage/locking.d.ts +15 -0
- package/node_modules/tor-js/dist/storage/locking.d.ts.map +1 -0
- package/node_modules/tor-js/dist/storage/memory.d.ts +13 -0
- package/node_modules/tor-js/dist/storage/memory.d.ts.map +1 -0
- package/node_modules/tor-js/dist/storage/node-deps.d.ts +8 -0
- package/node_modules/tor-js/dist/storage/node-deps.d.ts.map +1 -0
- package/node_modules/tor-js/dist/tor_js_bg.wasm +0 -0
- package/node_modules/tor-js/dist/types.d.ts +41 -0
- package/node_modules/tor-js/dist/types.d.ts.map +1 -0
- package/node_modules/tor-js/dist/wasm-B6es-efC.d.ts +302 -0
- package/node_modules/tor-js/dist/wasm-pkg/tor_js.d.ts +311 -0
- package/node_modules/tor-js/dist/wasm-pkg/tor_js.js +1159 -0
- package/node_modules/tor-js/dist/wasm.d.ts +31 -0
- package/node_modules/tor-js/dist/wasm.d.ts.map +1 -0
- package/node_modules/tor-js/package.json +61 -0
- package/node_modules/tor-js/src/Log.ts +100 -0
- package/node_modules/tor-js/src/TorClient.ts +134 -0
- package/node_modules/tor-js/src/commonExports.ts +7 -0
- package/node_modules/tor-js/src/entryPoints/wasm-base64/index.ts +17 -0
- package/node_modules/tor-js/src/entryPoints/wasm-base64/singleton.ts +7 -0
- package/node_modules/tor-js/src/entryPoints/wasm-cdn/index.ts +155 -0
- package/node_modules/tor-js/src/entryPoints/wasm-cdn/singleton.ts +7 -0
- package/node_modules/tor-js/src/entryPoints/wasm-file/index.ts +19 -0
- package/node_modules/tor-js/src/entryPoints/wasm-file/singleton.ts +7 -0
- package/node_modules/tor-js/src/globals.d.ts +2 -0
- package/node_modules/tor-js/src/helpers.ts +20 -0
- package/node_modules/tor-js/src/polyfills.ts +4 -0
- package/node_modules/tor-js/src/singleton.ts +54 -0
- package/node_modules/tor-js/src/socketProvider.ts +405 -0
- package/node_modules/tor-js/src/storage/filesystem.ts +171 -0
- package/node_modules/tor-js/src/storage/index.ts +21 -0
- package/node_modules/tor-js/src/storage/indexeddb.ts +99 -0
- package/node_modules/tor-js/src/storage/locking.ts +195 -0
- package/node_modules/tor-js/src/storage/memory.ts +42 -0
- package/node_modules/tor-js/src/storage/node-deps.ts +23 -0
- package/node_modules/tor-js/src/types.ts +48 -0
- package/node_modules/tor-js/src/wasm-base64-data.d.ts +3 -0
- package/node_modules/tor-js/src/wasm.ts +135 -0
- package/package.json +67 -0
package/README.md
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
<img src="c4_logo.png" alt="C4 Logo" width="300"/>
|
|
2
|
+
|
|
3
|
+
# @corpus-core/colibri-tor
|
|
4
|
+
|
|
5
|
+
Tor network transport for [Colibri Stateless](https://github.com/corpus-core/colibri-stateless). Routes all RPC requests through [Tor](https://www.torproject.org/) for enhanced network-level privacy.
|
|
6
|
+
|
|
7
|
+
- **Browser**: Uses [Arti](https://gitlab.torproject.org/tpo/core/arti) compiled to WebAssembly via [tor-js](https://github.com/voltrevo/arti) -- no browser extension or external software needed.
|
|
8
|
+
- **Node.js**: Connects to a locally running Tor SOCKS5 proxy -- zero dependencies, pure `node:net`/`node:tls` implementation.
|
|
9
|
+
|
|
10
|
+
## Installation
|
|
11
|
+
|
|
12
|
+
```sh
|
|
13
|
+
npm install @corpus-core/colibri-tor @corpus-core/colibri-stateless
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Usage
|
|
17
|
+
|
|
18
|
+
### Browser (Arti WASM)
|
|
19
|
+
|
|
20
|
+
```typescript
|
|
21
|
+
import Colibri from '@corpus-core/colibri-stateless';
|
|
22
|
+
import { createBrowserFetch } from '@corpus-core/colibri-tor/browser';
|
|
23
|
+
|
|
24
|
+
// Bootstrap starts immediately in the background (no await needed).
|
|
25
|
+
// The first actual request will wait for bootstrap to complete.
|
|
26
|
+
const client = new Colibri({
|
|
27
|
+
fetch: createBrowserFetch(),
|
|
28
|
+
prover: ['https://mainnet.colibri-proof.tech']
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
// This request will await Tor bootstrap if still in progress
|
|
32
|
+
const balance = await client.request({
|
|
33
|
+
method: 'eth_getBalance',
|
|
34
|
+
params: ['0x...', 'latest']
|
|
35
|
+
});
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### Node.js (SOCKS5 Proxy)
|
|
39
|
+
|
|
40
|
+
Start a Tor daemon first (e.g. `tor --SocksPort 9050` or via your system's package manager), then:
|
|
41
|
+
|
|
42
|
+
```typescript
|
|
43
|
+
import Colibri from '@corpus-core/colibri-stateless';
|
|
44
|
+
import { createSocksFetch } from '@corpus-core/colibri-tor/node';
|
|
45
|
+
|
|
46
|
+
const torFetch = await createSocksFetch({ socksPort: 9050 });
|
|
47
|
+
|
|
48
|
+
const client = new Colibri({
|
|
49
|
+
fetch: torFetch,
|
|
50
|
+
prover: ['https://mainnet.colibri-proof.tech']
|
|
51
|
+
});
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## API
|
|
55
|
+
|
|
56
|
+
### `createBrowserFetch(options?): typeof fetch`
|
|
57
|
+
|
|
58
|
+
Creates a `fetch`-compatible function that routes requests through Tor via Arti WASM. Browser only. Returns synchronously -- Tor bootstrap starts immediately in the background and the first actual request awaits completion if needed.
|
|
59
|
+
|
|
60
|
+
| Option | Type | Default | Description |
|
|
61
|
+
|--------|------|---------|-------------|
|
|
62
|
+
| `gateway` | `string` | `'https://tor-js-gateway.voltrevo.com'` | WebSocket/WebRTC gateway URL for Tor relay connections |
|
|
63
|
+
| `onBootstrap` | `(ms: number) => void` | `undefined` | Callback when Tor bootstrap completes |
|
|
64
|
+
| `logLevel` | `LogLevel` | `'warn'` | Arti log level (`'trace'` \| `'debug'` \| `'info'` \| `'warn'` \| `'error'`) |
|
|
65
|
+
|
|
66
|
+
### `createSocksFetch(options?): Promise<typeof fetch>`
|
|
67
|
+
|
|
68
|
+
Creates a `fetch`-compatible function that routes requests through a local Tor SOCKS5 proxy. Node.js only.
|
|
69
|
+
|
|
70
|
+
| Option | Type | Default | Description |
|
|
71
|
+
|--------|------|---------|-------------|
|
|
72
|
+
| `socksHost` | `string` | `'127.0.0.1'` | SOCKS5 proxy hostname |
|
|
73
|
+
| `socksPort` | `number` | `9050` | SOCKS5 proxy port |
|
|
74
|
+
|
|
75
|
+
## Building tor-js from source
|
|
76
|
+
|
|
77
|
+
Until `tor-js` is published on npm, the CI automatically builds the Arti WASM package from source and bundles it with `@corpus-core/colibri-tor` via `bundleDependencies`. Users installing the published package get `tor-js` included -- no extra steps needed.
|
|
78
|
+
|
|
79
|
+
For local development, you can trigger the same build manually:
|
|
80
|
+
|
|
81
|
+
```sh
|
|
82
|
+
# Requires: Rust toolchain, wasm-pack, Node.js
|
|
83
|
+
npm run build:arti
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
This clones [voltrevo/arti](https://github.com/voltrevo/arti), builds the WASM package, and installs the resulting `tor-js` ts-wrapper into `node_modules/`.
|
|
87
|
+
|
|
88
|
+
## License
|
|
89
|
+
|
|
90
|
+
MIT
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2025 corpus.core
|
|
3
|
+
*
|
|
4
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
|
5
|
+
* this software and associated documentation files (the "Software"), to deal in
|
|
6
|
+
* the Software without restriction, including without limitation the rights to
|
|
7
|
+
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
|
8
|
+
* the Software, and to permit persons to whom the Software is furnished to do so,
|
|
9
|
+
* subject to the following conditions:
|
|
10
|
+
*
|
|
11
|
+
* The above copyright notice and this permission notice shall be included in all
|
|
12
|
+
* copies or substantial portions of the Software.
|
|
13
|
+
*
|
|
14
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
15
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
|
16
|
+
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
|
17
|
+
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
|
18
|
+
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
19
|
+
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
20
|
+
*
|
|
21
|
+
* SPDX-License-Identifier: MIT
|
|
22
|
+
*/
|
|
23
|
+
import type { ThorBrowserOptions } from './types.js';
|
|
24
|
+
import { DEFAULT_GATEWAY } from './types.js';
|
|
25
|
+
export type { ThorBrowserOptions };
|
|
26
|
+
export { DEFAULT_GATEWAY };
|
|
27
|
+
/**
|
|
28
|
+
* Create a `fetch`-compatible function that routes HTTP requests through the
|
|
29
|
+
* Tor network using Arti compiled to WebAssembly. Browser only.
|
|
30
|
+
*
|
|
31
|
+
* Tor bootstrap starts immediately but does **not** block the returned
|
|
32
|
+
* function. The first actual `fetch` call will await the bootstrap if it
|
|
33
|
+
* has not completed yet. This allows the application to continue
|
|
34
|
+
* initializing while Tor connects in the background.
|
|
35
|
+
*
|
|
36
|
+
* ```typescript
|
|
37
|
+
* // Bootstrap starts immediately, returns without blocking
|
|
38
|
+
* const torFetch = createBrowserFetch();
|
|
39
|
+
* const client = new Colibri({ fetch: torFetch });
|
|
40
|
+
* // ... app continues initializing ...
|
|
41
|
+
* // First request will await bootstrap completion if still in progress
|
|
42
|
+
* await client.request({ method: 'eth_blockNumber' });
|
|
43
|
+
* ```
|
|
44
|
+
*
|
|
45
|
+
* @param options - Browser transport options (gateway URL, log level, etc.)
|
|
46
|
+
* @return A `fetch`-compatible function that routes through Tor
|
|
47
|
+
*/
|
|
48
|
+
export declare function createBrowserFetch(options?: ThorBrowserOptions): typeof globalThis.fetch;
|
package/dist/browser.js
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2025 corpus.core
|
|
3
|
+
*
|
|
4
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
|
5
|
+
* this software and associated documentation files (the "Software"), to deal in
|
|
6
|
+
* the Software without restriction, including without limitation the rights to
|
|
7
|
+
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
|
8
|
+
* the Software, and to permit persons to whom the Software is furnished to do so,
|
|
9
|
+
* subject to the following conditions:
|
|
10
|
+
*
|
|
11
|
+
* The above copyright notice and this permission notice shall be included in all
|
|
12
|
+
* copies or substantial portions of the Software.
|
|
13
|
+
*
|
|
14
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
15
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
|
16
|
+
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
|
17
|
+
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
|
18
|
+
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
19
|
+
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
20
|
+
*
|
|
21
|
+
* SPDX-License-Identifier: MIT
|
|
22
|
+
*/
|
|
23
|
+
import { DEFAULT_GATEWAY } from './types.js';
|
|
24
|
+
export { DEFAULT_GATEWAY };
|
|
25
|
+
// tor-js is loaded dynamically so the import path can switch between vendored
|
|
26
|
+
// artifacts (built from source via scripts/build-arti.sh) and the future npm
|
|
27
|
+
// package without changing this file.
|
|
28
|
+
let torJsImport = null;
|
|
29
|
+
function getTorJs() {
|
|
30
|
+
if (!torJsImport) {
|
|
31
|
+
// Dynamic import -- resolved at runtime. When tor-js is published on
|
|
32
|
+
// npm this will become `import('tor-js')`. Until then, the vendored
|
|
33
|
+
// build (src/vendor/tor-js.js) is used via the package.json "imports"
|
|
34
|
+
// map or a direct relative path.
|
|
35
|
+
torJsImport = import('tor-js').catch(() => {
|
|
36
|
+
throw new Error('tor-js is not installed. Install it via npm (once published) ' +
|
|
37
|
+
'or run `npm run build:arti` to build from source.');
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
return torJsImport;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Create a `fetch`-compatible function that routes HTTP requests through the
|
|
44
|
+
* Tor network using Arti compiled to WebAssembly. Browser only.
|
|
45
|
+
*
|
|
46
|
+
* Tor bootstrap starts immediately but does **not** block the returned
|
|
47
|
+
* function. The first actual `fetch` call will await the bootstrap if it
|
|
48
|
+
* has not completed yet. This allows the application to continue
|
|
49
|
+
* initializing while Tor connects in the background.
|
|
50
|
+
*
|
|
51
|
+
* ```typescript
|
|
52
|
+
* // Bootstrap starts immediately, returns without blocking
|
|
53
|
+
* const torFetch = createBrowserFetch();
|
|
54
|
+
* const client = new Colibri({ fetch: torFetch });
|
|
55
|
+
* // ... app continues initializing ...
|
|
56
|
+
* // First request will await bootstrap completion if still in progress
|
|
57
|
+
* await client.request({ method: 'eth_blockNumber' });
|
|
58
|
+
* ```
|
|
59
|
+
*
|
|
60
|
+
* @param options - Browser transport options (gateway URL, log level, etc.)
|
|
61
|
+
* @return A `fetch`-compatible function that routes through Tor
|
|
62
|
+
*/
|
|
63
|
+
export function createBrowserFetch(options = {}) {
|
|
64
|
+
const gateway = options.gateway ?? DEFAULT_GATEWAY;
|
|
65
|
+
// Kick off bootstrap eagerly -- the promise is shared across all requests.
|
|
66
|
+
const startTime = Date.now();
|
|
67
|
+
const clientReady = getTorJs().then(async ({ TorClient }) => {
|
|
68
|
+
const client = new TorClient({
|
|
69
|
+
gateway,
|
|
70
|
+
logLevel: options.logLevel ?? 'warn',
|
|
71
|
+
});
|
|
72
|
+
await client.ready();
|
|
73
|
+
options.onBootstrap?.(Date.now() - startTime);
|
|
74
|
+
return client;
|
|
75
|
+
});
|
|
76
|
+
const torFetch = async (input, init) => {
|
|
77
|
+
const client = await clientReady;
|
|
78
|
+
const url = typeof input === 'string'
|
|
79
|
+
? input
|
|
80
|
+
: input instanceof URL
|
|
81
|
+
? input.href
|
|
82
|
+
: input.url;
|
|
83
|
+
// tor-js TorClient.fetch() returns a Response-compatible object.
|
|
84
|
+
// We validate the essential properties to catch API mismatches early.
|
|
85
|
+
const response = await client.fetch(url, {
|
|
86
|
+
method: init?.method,
|
|
87
|
+
headers: init?.headers,
|
|
88
|
+
body: init?.body,
|
|
89
|
+
});
|
|
90
|
+
if (typeof response?.status !== 'number') {
|
|
91
|
+
throw new Error('tor-js returned an invalid response object (missing status)');
|
|
92
|
+
}
|
|
93
|
+
return response;
|
|
94
|
+
};
|
|
95
|
+
return torFetch;
|
|
96
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2025 corpus.core
|
|
3
|
+
*
|
|
4
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
|
5
|
+
* this software and associated documentation files (the "Software"), to deal in
|
|
6
|
+
* the Software without restriction, including without limitation the rights to
|
|
7
|
+
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
|
8
|
+
* the Software, and to permit persons to whom the Software is furnished to do so,
|
|
9
|
+
* subject to the following conditions:
|
|
10
|
+
*
|
|
11
|
+
* The above copyright notice and this permission notice shall be included in all
|
|
12
|
+
* copies or substantial portions of the Software.
|
|
13
|
+
*
|
|
14
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
15
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
|
16
|
+
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
|
17
|
+
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
|
18
|
+
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
19
|
+
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
20
|
+
*
|
|
21
|
+
* SPDX-License-Identifier: MIT
|
|
22
|
+
*/
|
|
23
|
+
export { createBrowserFetch, DEFAULT_GATEWAY } from './browser.js';
|
|
24
|
+
export { createSocksFetch } from './node.js';
|
|
25
|
+
export type { ThorBrowserOptions, ThorNodeOptions, LogLevel } from './types.js';
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2025 corpus.core
|
|
3
|
+
*
|
|
4
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
|
5
|
+
* this software and associated documentation files (the "Software"), to deal in
|
|
6
|
+
* the Software without restriction, including without limitation the rights to
|
|
7
|
+
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
|
8
|
+
* the Software, and to permit persons to whom the Software is furnished to do so,
|
|
9
|
+
* subject to the following conditions:
|
|
10
|
+
*
|
|
11
|
+
* The above copyright notice and this permission notice shall be included in all
|
|
12
|
+
* copies or substantial portions of the Software.
|
|
13
|
+
*
|
|
14
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
15
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
|
16
|
+
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
|
17
|
+
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
|
18
|
+
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
19
|
+
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
20
|
+
*
|
|
21
|
+
* SPDX-License-Identifier: MIT
|
|
22
|
+
*/
|
|
23
|
+
export { createBrowserFetch, DEFAULT_GATEWAY } from './browser.js';
|
|
24
|
+
export { createSocksFetch } from './node.js';
|
package/dist/node.d.ts
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2025 corpus.core
|
|
3
|
+
*
|
|
4
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
|
5
|
+
* this software and associated documentation files (the "Software"), to deal in
|
|
6
|
+
* the Software without restriction, including without limitation the rights to
|
|
7
|
+
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
|
8
|
+
* the Software, and to permit persons to whom the Software is furnished to do so,
|
|
9
|
+
* subject to the following conditions:
|
|
10
|
+
*
|
|
11
|
+
* The above copyright notice and this permission notice shall be included in all
|
|
12
|
+
* copies or substantial portions of the Software.
|
|
13
|
+
*
|
|
14
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
15
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
|
16
|
+
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
|
17
|
+
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
|
18
|
+
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
19
|
+
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
20
|
+
*
|
|
21
|
+
* SPDX-License-Identifier: MIT
|
|
22
|
+
*/
|
|
23
|
+
import type { ThorNodeOptions } from './types.js';
|
|
24
|
+
export type { ThorNodeOptions };
|
|
25
|
+
/**
|
|
26
|
+
* Create a `fetch`-compatible function that routes HTTP requests through a
|
|
27
|
+
* locally running Tor SOCKS5 proxy. Node.js only.
|
|
28
|
+
*
|
|
29
|
+
* The user must start the Tor daemon themselves (e.g. `tor --SocksPort 9050`).
|
|
30
|
+
*
|
|
31
|
+
* @param options - Node.js transport options (SOCKS host/port)
|
|
32
|
+
* @return A `fetch`-compatible function routing through the Tor SOCKS5 proxy
|
|
33
|
+
*/
|
|
34
|
+
export declare function createSocksFetch(options?: ThorNodeOptions): Promise<typeof globalThis.fetch>;
|
package/dist/node.js
ADDED
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2025 corpus.core
|
|
3
|
+
*
|
|
4
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
|
5
|
+
* this software and associated documentation files (the "Software"), to deal in
|
|
6
|
+
* the Software without restriction, including without limitation the rights to
|
|
7
|
+
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
|
8
|
+
* the Software, and to permit persons to whom the Software is furnished to do so,
|
|
9
|
+
* subject to the following conditions:
|
|
10
|
+
*
|
|
11
|
+
* The above copyright notice and this permission notice shall be included in all
|
|
12
|
+
* copies or substantial portions of the Software.
|
|
13
|
+
*
|
|
14
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
15
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
|
16
|
+
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
|
17
|
+
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
|
18
|
+
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
19
|
+
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
20
|
+
*
|
|
21
|
+
* SPDX-License-Identifier: MIT
|
|
22
|
+
*/
|
|
23
|
+
const SOCKS5_HANDSHAKE_TIMEOUT_MS = 30000;
|
|
24
|
+
const HTTP_RESPONSE_TIMEOUT_MS = 60000;
|
|
25
|
+
const MAX_RESPONSE_SIZE = 64 * 1024 * 1024; // 64 MiB
|
|
26
|
+
/**
|
|
27
|
+
* Perform a SOCKS5 CONNECT handshake over an existing TCP socket.
|
|
28
|
+
*
|
|
29
|
+
* Implements RFC 1928 (no-auth) + CONNECT to a domain:port target.
|
|
30
|
+
* Uses buffered reads to handle TCP stream fragmentation correctly.
|
|
31
|
+
* The socket is left connected to the remote host on success.
|
|
32
|
+
*/
|
|
33
|
+
async function socks5Connect(socksHost, socksPort, targetHost, targetPort) {
|
|
34
|
+
const net = await import('node:net');
|
|
35
|
+
const hostBuf = Buffer.from(targetHost, 'utf-8');
|
|
36
|
+
if (hostBuf.length > 255) {
|
|
37
|
+
throw new Error(`SOCKS5: hostname too long (${hostBuf.length} bytes, max 255)`);
|
|
38
|
+
}
|
|
39
|
+
return new Promise((resolve, reject) => {
|
|
40
|
+
const socket = net.createConnection(socksPort, socksHost, () => {
|
|
41
|
+
socket.write(Buffer.from([0x05, 0x01, 0x00]));
|
|
42
|
+
});
|
|
43
|
+
socket.setTimeout(SOCKS5_HANDSHAKE_TIMEOUT_MS);
|
|
44
|
+
socket.once('timeout', () => {
|
|
45
|
+
socket.destroy();
|
|
46
|
+
reject(new Error('SOCKS5 handshake timeout'));
|
|
47
|
+
});
|
|
48
|
+
let phase = 'greeting';
|
|
49
|
+
let buffer = Buffer.alloc(0);
|
|
50
|
+
socket.once('error', (err) => {
|
|
51
|
+
socket.destroy();
|
|
52
|
+
reject(err);
|
|
53
|
+
});
|
|
54
|
+
socket.on('data', (chunk) => {
|
|
55
|
+
buffer = Buffer.concat([buffer, chunk]);
|
|
56
|
+
if (phase === 'greeting') {
|
|
57
|
+
if (buffer.length < 2)
|
|
58
|
+
return;
|
|
59
|
+
if (buffer[0] !== 0x05 || buffer[1] !== 0x00) {
|
|
60
|
+
socket.destroy();
|
|
61
|
+
reject(new Error(`SOCKS5 handshake failed: server chose method ${buffer[1]}`));
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
buffer = buffer.subarray(2);
|
|
65
|
+
phase = 'connect';
|
|
66
|
+
const req = Buffer.alloc(4 + 1 + hostBuf.length + 2);
|
|
67
|
+
req[0] = 0x05; // VER
|
|
68
|
+
req[1] = 0x01; // CMD: CONNECT
|
|
69
|
+
req[2] = 0x00; // RSV
|
|
70
|
+
req[3] = 0x03; // ATYP: DOMAINNAME
|
|
71
|
+
req[4] = hostBuf.length;
|
|
72
|
+
hostBuf.copy(req, 5);
|
|
73
|
+
req.writeUInt16BE(targetPort, 5 + hostBuf.length);
|
|
74
|
+
socket.write(req);
|
|
75
|
+
}
|
|
76
|
+
if (phase === 'connect') {
|
|
77
|
+
// Minimum CONNECT response: VER(1) + REP(1) + RSV(1) + ATYP(1) + addr + port(2)
|
|
78
|
+
// For ATYP=1 (IPv4): 4+4+2 = 10 bytes total
|
|
79
|
+
if (buffer.length < 4)
|
|
80
|
+
return;
|
|
81
|
+
let expectedLen;
|
|
82
|
+
switch (buffer[3]) {
|
|
83
|
+
case 0x01:
|
|
84
|
+
expectedLen = 10;
|
|
85
|
+
break; // IPv4: 4 header + 4 addr + 2 port
|
|
86
|
+
case 0x04:
|
|
87
|
+
expectedLen = 22;
|
|
88
|
+
break; // IPv6: 4 header + 16 addr + 2 port
|
|
89
|
+
case 0x03: { // Domain: 4 header + 1 len + N + 2 port
|
|
90
|
+
if (buffer.length < 5)
|
|
91
|
+
return;
|
|
92
|
+
expectedLen = 5 + buffer[4] + 2;
|
|
93
|
+
break;
|
|
94
|
+
}
|
|
95
|
+
default:
|
|
96
|
+
expectedLen = 10;
|
|
97
|
+
break;
|
|
98
|
+
}
|
|
99
|
+
if (buffer.length < expectedLen)
|
|
100
|
+
return;
|
|
101
|
+
if (buffer[0] !== 0x05) {
|
|
102
|
+
socket.destroy();
|
|
103
|
+
reject(new Error('SOCKS5 connect: unexpected version'));
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
if (buffer[1] !== 0x00) {
|
|
107
|
+
socket.destroy();
|
|
108
|
+
const codes = {
|
|
109
|
+
0x01: 'general failure',
|
|
110
|
+
0x02: 'connection not allowed',
|
|
111
|
+
0x03: 'network unreachable',
|
|
112
|
+
0x04: 'host unreachable',
|
|
113
|
+
0x05: 'connection refused',
|
|
114
|
+
0x06: 'TTL expired',
|
|
115
|
+
0x07: 'command not supported',
|
|
116
|
+
0x08: 'address type not supported',
|
|
117
|
+
};
|
|
118
|
+
reject(new Error(`SOCKS5 connect failed: ${codes[buffer[1]] || `code ${buffer[1]}`}`));
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
socket.setTimeout(0);
|
|
122
|
+
socket.removeAllListeners('data');
|
|
123
|
+
socket.removeAllListeners('error');
|
|
124
|
+
socket.removeAllListeners('timeout');
|
|
125
|
+
resolve(socket);
|
|
126
|
+
}
|
|
127
|
+
});
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Perform an HTTP request through an established SOCKS5 tunnel.
|
|
132
|
+
*
|
|
133
|
+
* For HTTPS targets, wraps the raw socket in TLS using `node:tls`.
|
|
134
|
+
* Uses HTTP/1.0 to avoid chunked transfer-encoding complexity.
|
|
135
|
+
* Returns a standard Web API `Response` (Node 18+).
|
|
136
|
+
*/
|
|
137
|
+
async function httpOverSocks(socksHost, socksPort, url, init) {
|
|
138
|
+
const parsed = new URL(url);
|
|
139
|
+
const isHttps = parsed.protocol === 'https:';
|
|
140
|
+
const targetPort = parsed.port ? parseInt(parsed.port) : (isHttps ? 443 : 80);
|
|
141
|
+
let socket = await socks5Connect(socksHost, socksPort, parsed.hostname, targetPort);
|
|
142
|
+
if (isHttps) {
|
|
143
|
+
const tls = await import('node:tls');
|
|
144
|
+
const tlsSocket = tls.connect({
|
|
145
|
+
socket: socket,
|
|
146
|
+
servername: parsed.hostname,
|
|
147
|
+
});
|
|
148
|
+
await new Promise((resolve, reject) => {
|
|
149
|
+
tlsSocket.once('secureConnect', resolve);
|
|
150
|
+
tlsSocket.once('error', reject);
|
|
151
|
+
});
|
|
152
|
+
socket = tlsSocket;
|
|
153
|
+
}
|
|
154
|
+
const method = init?.method ?? 'GET';
|
|
155
|
+
if (!/^[A-Z]+$/.test(method)) {
|
|
156
|
+
socket.destroy();
|
|
157
|
+
throw new Error(`Invalid HTTP method: ${method}`);
|
|
158
|
+
}
|
|
159
|
+
const bodyStr = init?.body != null
|
|
160
|
+
? (typeof init.body === 'string' ? init.body : new TextDecoder().decode(init.body))
|
|
161
|
+
: undefined;
|
|
162
|
+
const bodyBuf = bodyStr ? Buffer.from(bodyStr, 'utf-8') : undefined;
|
|
163
|
+
const headers = {
|
|
164
|
+
'Host': parsed.host,
|
|
165
|
+
'Connection': 'close',
|
|
166
|
+
};
|
|
167
|
+
if (init?.headers) {
|
|
168
|
+
const h = init.headers;
|
|
169
|
+
if (h instanceof Headers) {
|
|
170
|
+
h.forEach((v, k) => { headers[k] = v; });
|
|
171
|
+
}
|
|
172
|
+
else if (Array.isArray(h)) {
|
|
173
|
+
for (const [k, v] of h)
|
|
174
|
+
headers[k] = v;
|
|
175
|
+
}
|
|
176
|
+
else {
|
|
177
|
+
Object.assign(headers, h);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
if (bodyBuf) {
|
|
181
|
+
headers['Content-Length'] = bodyBuf.length.toString();
|
|
182
|
+
}
|
|
183
|
+
// Validate headers against CRLF injection (CWE-113)
|
|
184
|
+
for (const [k, v] of Object.entries(headers)) {
|
|
185
|
+
if (/[\r\n]/.test(k) || /[\r\n]/.test(v)) {
|
|
186
|
+
socket.destroy();
|
|
187
|
+
throw new Error('Invalid header: CR/LF characters not allowed in header name or value');
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
// HTTP/1.0 avoids chunked transfer-encoding; Connection: close ensures
|
|
191
|
+
// the server closes the socket after the response.
|
|
192
|
+
const path = parsed.pathname + parsed.search;
|
|
193
|
+
let reqStr = `${method} ${path} HTTP/1.0\r\n`;
|
|
194
|
+
for (const [k, v] of Object.entries(headers)) {
|
|
195
|
+
reqStr += `${k}: ${v}\r\n`;
|
|
196
|
+
}
|
|
197
|
+
reqStr += '\r\n';
|
|
198
|
+
return new Promise((resolve, reject) => {
|
|
199
|
+
socket.setTimeout(HTTP_RESPONSE_TIMEOUT_MS);
|
|
200
|
+
socket.once('timeout', () => {
|
|
201
|
+
socket.destroy();
|
|
202
|
+
reject(new Error('HTTP response timeout'));
|
|
203
|
+
});
|
|
204
|
+
socket.once('error', (err) => {
|
|
205
|
+
socket.destroy();
|
|
206
|
+
reject(err);
|
|
207
|
+
});
|
|
208
|
+
let totalSize = 0;
|
|
209
|
+
const chunks = [];
|
|
210
|
+
socket.on('data', (chunk) => {
|
|
211
|
+
totalSize += chunk.length;
|
|
212
|
+
if (totalSize > MAX_RESPONSE_SIZE) {
|
|
213
|
+
socket.destroy();
|
|
214
|
+
reject(new Error(`Response too large (>${MAX_RESPONSE_SIZE} bytes)`));
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
217
|
+
chunks.push(chunk);
|
|
218
|
+
});
|
|
219
|
+
socket.on('end', () => {
|
|
220
|
+
socket.destroy();
|
|
221
|
+
try {
|
|
222
|
+
const raw = Buffer.concat(chunks);
|
|
223
|
+
const headerEnd = raw.indexOf('\r\n\r\n');
|
|
224
|
+
if (headerEnd === -1) {
|
|
225
|
+
reject(new Error('Malformed HTTP response: no header/body separator'));
|
|
226
|
+
return;
|
|
227
|
+
}
|
|
228
|
+
const headerStr = raw.subarray(0, headerEnd).toString('utf-8');
|
|
229
|
+
const body = raw.subarray(headerEnd + 4);
|
|
230
|
+
const [statusLine, ...headerLines] = headerStr.split('\r\n');
|
|
231
|
+
const statusMatch = statusLine.match(/^HTTP\/[\d.]+ (\d+)/);
|
|
232
|
+
const status = statusMatch ? parseInt(statusMatch[1]) : 0;
|
|
233
|
+
const respHeaders = new Headers();
|
|
234
|
+
for (const line of headerLines) {
|
|
235
|
+
const idx = line.indexOf(':');
|
|
236
|
+
if (idx > 0) {
|
|
237
|
+
respHeaders.append(line.substring(0, idx).trim(), line.substring(idx + 1).trim());
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
resolve(new Response(body, { status, headers: respHeaders }));
|
|
241
|
+
}
|
|
242
|
+
catch (e) {
|
|
243
|
+
reject(e);
|
|
244
|
+
}
|
|
245
|
+
});
|
|
246
|
+
socket.write(reqStr);
|
|
247
|
+
if (bodyBuf)
|
|
248
|
+
socket.write(bodyBuf);
|
|
249
|
+
});
|
|
250
|
+
}
|
|
251
|
+
/**
|
|
252
|
+
* Create a `fetch`-compatible function that routes HTTP requests through a
|
|
253
|
+
* locally running Tor SOCKS5 proxy. Node.js only.
|
|
254
|
+
*
|
|
255
|
+
* The user must start the Tor daemon themselves (e.g. `tor --SocksPort 9050`).
|
|
256
|
+
*
|
|
257
|
+
* @param options - Node.js transport options (SOCKS host/port)
|
|
258
|
+
* @return A `fetch`-compatible function routing through the Tor SOCKS5 proxy
|
|
259
|
+
*/
|
|
260
|
+
export async function createSocksFetch(options = {}) {
|
|
261
|
+
const host = options.socksHost ?? '127.0.0.1';
|
|
262
|
+
const port = options.socksPort ?? 9050;
|
|
263
|
+
if (port < 1 || port > 65535 || !Number.isInteger(port)) {
|
|
264
|
+
throw new Error(`Invalid SOCKS port: ${port} (must be 1-65535)`);
|
|
265
|
+
}
|
|
266
|
+
const socksFetch = async (input, init) => {
|
|
267
|
+
const url = typeof input === 'string'
|
|
268
|
+
? input
|
|
269
|
+
: input instanceof URL
|
|
270
|
+
? input.href
|
|
271
|
+
: input.url;
|
|
272
|
+
return httpOverSocks(host, port, url, init);
|
|
273
|
+
};
|
|
274
|
+
return socksFetch;
|
|
275
|
+
}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2025 corpus.core
|
|
3
|
+
*
|
|
4
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
|
5
|
+
* this software and associated documentation files (the "Software"), to deal in
|
|
6
|
+
* the Software without restriction, including without limitation the rights to
|
|
7
|
+
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
|
8
|
+
* the Software, and to permit persons to whom the Software is furnished to do so,
|
|
9
|
+
* subject to the following conditions:
|
|
10
|
+
*
|
|
11
|
+
* The above copyright notice and this permission notice shall be included in all
|
|
12
|
+
* copies or substantial portions of the Software.
|
|
13
|
+
*
|
|
14
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
15
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
|
16
|
+
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
|
17
|
+
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
|
18
|
+
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
19
|
+
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
20
|
+
*
|
|
21
|
+
* SPDX-License-Identifier: MIT
|
|
22
|
+
*/
|
|
23
|
+
export type LogLevel = 'trace' | 'debug' | 'info' | 'warn' | 'error';
|
|
24
|
+
export declare const DEFAULT_GATEWAY = "https://tor-js-gateway.voltrevo.com";
|
|
25
|
+
export interface ThorBrowserOptions {
|
|
26
|
+
/** WebSocket/WebRTC gateway URL for Tor relay connections.
|
|
27
|
+
* Default: `'https://tor-js-gateway.voltrevo.com'`. */
|
|
28
|
+
gateway?: string;
|
|
29
|
+
/** Callback invoked when Tor bootstrap completes, with elapsed time in ms. */
|
|
30
|
+
onBootstrap?: (elapsedMs: number) => void;
|
|
31
|
+
/** Arti log level. Default: `'warn'`. */
|
|
32
|
+
logLevel?: LogLevel;
|
|
33
|
+
}
|
|
34
|
+
export interface ThorNodeOptions {
|
|
35
|
+
/** SOCKS5 proxy hostname. Default: `'127.0.0.1'`. */
|
|
36
|
+
socksHost?: string;
|
|
37
|
+
/** SOCKS5 proxy port. Default: `9050`. */
|
|
38
|
+
socksPort?: number;
|
|
39
|
+
}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2025 corpus.core
|
|
3
|
+
*
|
|
4
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
|
5
|
+
* this software and associated documentation files (the "Software"), to deal in
|
|
6
|
+
* the Software without restriction, including without limitation the rights to
|
|
7
|
+
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
|
8
|
+
* the Software, and to permit persons to whom the Software is furnished to do so,
|
|
9
|
+
* subject to the following conditions:
|
|
10
|
+
*
|
|
11
|
+
* The above copyright notice and this permission notice shall be included in all
|
|
12
|
+
* copies or substantial portions of the Software.
|
|
13
|
+
*
|
|
14
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
15
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
|
16
|
+
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
|
17
|
+
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
|
18
|
+
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
19
|
+
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
20
|
+
*
|
|
21
|
+
* SPDX-License-Identifier: MIT
|
|
22
|
+
*/
|
|
23
|
+
export const DEFAULT_GATEWAY = 'https://tor-js-gateway.voltrevo.com';
|