specters 2.0.0

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.
Files changed (4) hide show
  1. package/README.md +159 -0
  2. package/index.d.ts +164 -0
  3. package/index.js +130 -0
  4. package/package.json +56 -0
package/README.md ADDED
@@ -0,0 +1,159 @@
1
+ # Specter Node.js Bindings
2
+
3
+ Node.js bindings for Specter, a high-performance HTTP client with full TLS, HTTP/2, and HTTP/3 fingerprint control.
4
+
5
+ ## Features
6
+
7
+ - **Native async/await**: Promise-based API with native performance
8
+ - **Browser fingerprinting**: Impersonate Chrome, Firefox, or use custom TLS/HTTP2 settings
9
+ - **HTTP/3 support**: Automatic upgrade via Alt-Svc headers
10
+ - **Connection pooling**: HTTP/2 multiplexing and HTTP/1.1 keep-alive
11
+ - **Timeout control**: Granular timeouts for connect, TTFB, read/write idle, and total request time
12
+ - **Automatic decompression**: gzip, deflate, brotli, zstd
13
+
14
+ ## Installation
15
+
16
+ ```bash
17
+ npm install @specter/client
18
+ ```
19
+
20
+ ## Quick Start
21
+
22
+ ```javascript
23
+ const { Client } = require('@specter/client');
24
+
25
+ async function main() {
26
+ // Create a client with default settings
27
+ const client = Client.builder().build();
28
+
29
+ // Make a GET request
30
+ const response = await client.get('https://httpbin.org/get').send();
31
+ console.log(`Status: ${response.status}`);
32
+ console.log(await response.text());
33
+ }
34
+
35
+ main();
36
+ ```
37
+
38
+ ## Browser Impersonation
39
+
40
+ ```javascript
41
+ const { Client, FingerprintProfile } = require('@specter/client');
42
+
43
+ // Impersonate Chrome 142
44
+ const client = Client.builder()
45
+ .fingerprint(FingerprintProfile.Chrome142)
46
+ .build();
47
+
48
+ // Or Firefox 133
49
+ const client = Client.builder()
50
+ .fingerprint(FingerprintProfile.Firefox133)
51
+ .build();
52
+ ```
53
+
54
+ ## Timeout Configuration
55
+
56
+ ```javascript
57
+ const { Client, timeoutsApiDefaults, timeoutsStreamingDefaults } = require('@specter/client');
58
+
59
+ // Use preset timeout configurations
60
+ const client1 = Client.builder().apiTimeouts().build();
61
+ const client2 = Client.builder().streamingTimeouts().build();
62
+
63
+ // Or configure manually
64
+ const timeouts = {
65
+ connect: 10.0, // TCP + TLS handshake
66
+ ttfb: 30.0, // Time to first byte
67
+ readIdle: 60.0, // Max time between chunks
68
+ total: 120.0 // Total request deadline
69
+ };
70
+
71
+ const client = Client.builder().timeouts(timeouts).build();
72
+ ```
73
+
74
+ ## HTTP Methods
75
+
76
+ ```javascript
77
+ const { Client } = require('@specter/client');
78
+
79
+ const client = Client.builder().build();
80
+
81
+ // GET
82
+ const response = await client.get('https://api.example.com/items').send();
83
+
84
+ // POST
85
+ const response = await client.post('https://api.example.com/items').send();
86
+
87
+ // PUT
88
+ const response = await client.put('https://api.example.com/items/1').send();
89
+
90
+ // DELETE
91
+ const response = await client.delete('https://api.example.com/items/1').send();
92
+
93
+ // PATCH
94
+ const response = await client.patch('https://api.example.com/items/1').send();
95
+
96
+ // HEAD
97
+ const response = await client.head('https://api.example.com/items/1').send();
98
+
99
+ // OPTIONS
100
+ const response = await client.options('https://api.example.com/items').send();
101
+
102
+ // Arbitrary method
103
+ const response = await client.request('PURGE', 'https://api.example.com/cache').send();
104
+ ```
105
+
106
+ ## Response Handling
107
+
108
+ ```javascript
109
+ const response = await client.get('https://api.example.com/data').send();
110
+
111
+ // Status code
112
+ console.log(response.status);
113
+
114
+ // Headers
115
+ console.log(response.headers); // Record<string, string>
116
+ console.log(response.getHeader('content-type'));
117
+
118
+ // Body
119
+ console.log(response.text()); // Decompressed text
120
+ console.log(response.json()); // JSON string (use JSON.parse)
121
+ const data = response.bytes(); // Buffer
122
+
123
+ // Response metadata
124
+ console.log(response.httpVersion); // "HTTP/2", "HTTP/1.1", etc.
125
+ console.log(response.isSuccess); // true for 2xx status
126
+
127
+ ## Request Builder
128
+
129
+ ```javascript
130
+ const { Client } = require('@specter/client');
131
+
132
+ const client = Client.builder().build();
133
+
134
+ const response = await client
135
+ .post('https://api.example.com/items')
136
+ .header('Authorization', 'Bearer token')
137
+ .json(JSON.stringify({ name: 'example' }))
138
+ .send();
139
+
140
+ console.log(response.status);
141
+ ```
142
+ ```
143
+
144
+ ## Development
145
+
146
+ ```bash
147
+ # Install dependencies
148
+ npm install
149
+
150
+ # Build the native module
151
+ npm run build
152
+
153
+ # Run tests
154
+ npm test
155
+ ```
156
+
157
+ ## License
158
+
159
+ MIT
package/index.d.ts ADDED
@@ -0,0 +1,164 @@
1
+ /**
2
+ * Specter - Node.js bindings for the Specter HTTP client.
3
+ *
4
+ * A high-performance async HTTP client with full TLS, HTTP/2, and HTTP/3
5
+ * fingerprint control for browser impersonation.
6
+ */
7
+
8
+ /** Browser fingerprint profiles for impersonation. */
9
+ export enum FingerprintProfile {
10
+ /** Chrome 142 on macOS */
11
+ Chrome142 = 0,
12
+ /** Firefox 133 on macOS */
13
+ Firefox133 = 1,
14
+ /** No fingerprinting - use default TLS settings */
15
+ None = 2,
16
+ }
17
+
18
+ /** HTTP version preference. */
19
+ export enum HttpVersion {
20
+ /** Force HTTP/1.1 */
21
+ Http1_1 = 0,
22
+ /** Attempt HTTP/2, fallback to HTTP/1.1 */
23
+ Http2 = 1,
24
+ /** Attempt HTTP/3, fallback to HTTP/2, fallback to HTTP/1.1 */
25
+ Http3 = 2,
26
+ /** HTTP/3 only, no fallback */
27
+ Http3Only = 3,
28
+ /** Let the client decide based on server support */
29
+ Auto = 4,
30
+ }
31
+
32
+ /** Timeout configuration for HTTP requests. */
33
+ export interface Timeouts {
34
+ /** TCP + TLS/QUIC handshake timeout in seconds */
35
+ connect?: number;
36
+ /** Time-to-first-byte timeout in seconds */
37
+ ttfb?: number;
38
+ /** Maximum time between received bytes in seconds (resets on each chunk) */
39
+ readIdle?: number;
40
+ /** Maximum time between sent bytes in seconds */
41
+ writeIdle?: number;
42
+ /** Absolute deadline for entire request in seconds */
43
+ total?: number;
44
+ /** Time to wait for a pooled connection in seconds */
45
+ poolAcquire?: number;
46
+ }
47
+
48
+ /** HTTP request builder for setting headers and body. */
49
+ export class RequestBuilder {
50
+ /** Add a header to the request. Returns this for chaining. */
51
+ header(key: string, value: string): this;
52
+ /** Set all headers (replaces existing headers). Returns this for chaining. */
53
+ headers(headers: string[][]): this;
54
+ /** Set the request body as bytes. Returns this for chaining. */
55
+ body(body: Buffer): this;
56
+ /** Set the request body as JSON string and add Content-Type header. Returns this for chaining. */
57
+ json(jsonStr: string): this;
58
+ /** Set the request body as form data and add Content-Type header. Returns this for chaining. */
59
+ form(formStr: string): this;
60
+ /** Send the request and return the response. */
61
+ send(): Promise<Response>;
62
+ }
63
+
64
+ /** HTTP response with decompression support. */
65
+ export class Response {
66
+ /** HTTP status code */
67
+ get status(): number;
68
+ /** Response headers as an object */
69
+ get headers(): Record<string, string>;
70
+ /** Get all headers as an array of [key, value] pairs */
71
+ headersList(): string[][];
72
+ /** Get a specific header value by name */
73
+ getHeader(name: string): string | null;
74
+ /** Get the response body as text (with decompression if needed) */
75
+ text(): string;
76
+ /** Get the response body as a Buffer */
77
+ bytes(): Buffer;
78
+ /** Parse the response body as JSON and return as string. Use JSON.parse to convert to an object. */
79
+ json(): string;
80
+ /** HTTP version string */
81
+ get httpVersion(): string;
82
+ /** Effective URL (after redirects) */
83
+ get effectiveUrl(): string | null;
84
+ /** Check if the response status is successful (2xx) */
85
+ get isSuccess(): boolean;
86
+ /** Check if the response is a redirect (3xx) */
87
+ get isRedirect(): boolean;
88
+ /** Get the redirect URL from Location header if present */
89
+ get redirectUrl(): string | null;
90
+ /** Get the Content-Type header value */
91
+ get contentType(): string | null;
92
+ }
93
+
94
+ /** Builder for creating HTTP clients. */
95
+ export class ClientBuilder {
96
+ /** Set the fingerprint profile */
97
+ fingerprint(profile: FingerprintProfile): this;
98
+ /** Set HTTP/2 preference */
99
+ preferHttp2(prefer: boolean): this;
100
+ /** Enable or disable automatic HTTP/3 upgrade via Alt-Svc headers */
101
+ h3Upgrade(enabled: boolean): this;
102
+ /** Set timeout configuration */
103
+ timeouts(timeouts: Timeouts): this;
104
+ /** Use API-optimized timeout defaults */
105
+ apiTimeouts(): this;
106
+ /** Use streaming-optimized timeout defaults */
107
+ streamingTimeouts(): this;
108
+ /** Set total request timeout in seconds */
109
+ totalTimeout(timeoutSecs: number): this;
110
+ /** Set connect timeout in seconds */
111
+ connectTimeout(timeoutSecs: number): this;
112
+ /** Set TTFB (time-to-first-byte) timeout in seconds */
113
+ ttfbTimeout(timeoutSecs: number): this;
114
+ /** Set read idle timeout in seconds */
115
+ readTimeout(timeoutSecs: number): this;
116
+ /** Skip TLS certificate verification for all connections (DANGEROUS - for testing only) */
117
+ dangerAcceptInvalidCerts(accept: boolean): this;
118
+ /** Automatically skip TLS certificate verification for localhost connections */
119
+ localhostAllowsInvalidCerts(allow: boolean): this;
120
+ /** Load root certificates from the operating system's certificate store */
121
+ withPlatformRoots(enabled: boolean): this;
122
+ /** Build the client */
123
+ build(): Client;
124
+ }
125
+
126
+ /** HTTP client with TLS/HTTP2/HTTP3 fingerprint control. */
127
+ export class Client {
128
+ /** Create a GET request builder */
129
+ get(url: string): RequestBuilder;
130
+ /** Create a POST request builder */
131
+ post(url: string): RequestBuilder;
132
+ /** Create a PUT request builder */
133
+ put(url: string): RequestBuilder;
134
+ /** Create a DELETE request builder */
135
+ delete(url: string): RequestBuilder;
136
+ /** Create a PATCH request builder */
137
+ patch(url: string): RequestBuilder;
138
+ /** Create a HEAD request builder */
139
+ head(url: string): RequestBuilder;
140
+ /** Create an OPTIONS request builder */
141
+ options(url: string): RequestBuilder;
142
+ /** Create a request builder for an arbitrary HTTP method */
143
+ request(method: string, url: string): RequestBuilder;
144
+ }
145
+
146
+ /** Cookie jar for manual cookie management. */
147
+ export class CookieJar {
148
+ constructor();
149
+ /** Get the number of cookies in the jar */
150
+ get length(): number;
151
+ /** Check if the cookie jar is empty */
152
+ get isEmpty(): boolean;
153
+ }
154
+
155
+ /** Create a new client builder */
156
+ export function clientBuilder(): ClientBuilder;
157
+
158
+ /** Sensible defaults for normal API calls. */
159
+ export function timeoutsApiDefaults(): Timeouts;
160
+
161
+ /** Sensible defaults for streaming responses. */
162
+ export function timeoutsStreamingDefaults(): Timeouts;
163
+
164
+ export {};
package/index.js ADDED
@@ -0,0 +1,130 @@
1
+ /**
2
+ * Specter - Node.js bindings for the Specter HTTP client.
3
+ *
4
+ * A high-performance async HTTP client with full TLS, HTTP/2, and HTTP/3
5
+ * fingerprint control for browser impersonation.
6
+ *
7
+ * @example
8
+ * const { clientBuilder, FingerprintProfile } = require('@specter/client');
9
+ *
10
+ * async function main() {
11
+ * // Create a client with default settings
12
+ * const client = clientBuilder().build();
13
+ *
14
+ * // Simple GET request
15
+ * const response = await client.get('https://httpbin.org/get').send();
16
+ * console.log(`Status: ${response.status}`);
17
+ * console.log(response.text());
18
+ *
19
+ * // POST with JSON body
20
+ * const response2 = await client.post('https://api.example.com/data')
21
+ * .header('Authorization', 'Bearer token')
22
+ * .json(JSON.stringify({ name: 'test' }))
23
+ * .send();
24
+ * console.log(JSON.parse(response2.json()));
25
+ * }
26
+ *
27
+ * main();
28
+ */
29
+
30
+ const { loadBinding } = require('@napi-rs/wasm-runtime');
31
+ const path = require('path');
32
+
33
+ // Try to load the native binding
34
+ let nativeBinding;
35
+
36
+ // Platform to binary name mapping based on napi-rs naming convention
37
+ // Format: specter.{os}-{arch}[-{libc}].node
38
+ const platformBinaries = {
39
+ 'darwin-arm64': 'specter.darwin-arm64.node',
40
+ 'darwin-x64': 'specter.darwin-x64.node',
41
+ 'linux-arm64-gnu': 'specter.linux-arm64-gnu.node',
42
+ 'linux-x64-gnu': 'specter.linux-x64-gnu.node',
43
+ 'linux-x64-musl': 'specter.linux-x64-musl.node',
44
+ 'win32-x64-msvc': 'specter.win32-x64-msvc.node',
45
+ };
46
+
47
+ function getPlatformKey() {
48
+ const platform = process.platform;
49
+ const arch = process.arch;
50
+
51
+ if (platform === 'darwin') {
52
+ return `darwin-${arch}`;
53
+ }
54
+ if (platform === 'win32') {
55
+ return `win32-${arch}-msvc`;
56
+ }
57
+ if (platform === 'linux') {
58
+ // Check if we're on musl by looking at the libc
59
+ const isMusl = (() => {
60
+ try {
61
+ const { execSync } = require('child_process');
62
+ return execSync('ldd --version 2>&1').toString().includes('musl');
63
+ } catch {
64
+ return false;
65
+ }
66
+ })();
67
+ return `linux-${arch}-${isMusl ? 'musl' : 'gnu'}`;
68
+ }
69
+ return null;
70
+ }
71
+
72
+ function loadNativeBinding() {
73
+ // Try platform-specific binary first
74
+ const platformKey = getPlatformKey();
75
+ if (platformKey && platformBinaries[platformKey]) {
76
+ try {
77
+ nativeBinding = require(`./${platformBinaries[platformKey]}`);
78
+ return nativeBinding;
79
+ } catch (e) {
80
+ // Continue to fallback
81
+ }
82
+ }
83
+
84
+ // Try all known binaries
85
+ for (const binaryName of Object.values(platformBinaries)) {
86
+ try {
87
+ nativeBinding = require(`./${binaryName}`);
88
+ return nativeBinding;
89
+ } catch (e) {
90
+ // Continue to next platform
91
+ }
92
+ }
93
+
94
+ // Try loading from build directory
95
+ try {
96
+ nativeBinding = require('./specter.node');
97
+ return nativeBinding;
98
+ } catch (e) {
99
+ // Fall through
100
+ }
101
+
102
+ // Try loading from target
103
+ try {
104
+ nativeBinding = require('./build/Release/specter.node');
105
+ return nativeBinding;
106
+ } catch (e) {
107
+ // Fall through
108
+ }
109
+
110
+ throw new Error(
111
+ `Failed to load native binding for Specter. ` +
112
+ `Please ensure you've built the native module with "npm run build".`
113
+ );
114
+ }
115
+
116
+ // Load the binding
117
+ const binding = loadNativeBinding();
118
+
119
+ // Export the native types
120
+ module.exports.Client = binding.Client;
121
+ module.exports.ClientBuilder = binding.ClientBuilder;
122
+ module.exports.RequestBuilder = binding.RequestBuilder;
123
+ module.exports.Response = binding.Response;
124
+ module.exports.CookieJar = binding.CookieJar;
125
+ module.exports.FingerprintProfile = binding.FingerprintProfile;
126
+ module.exports.HttpVersion = binding.HttpVersion;
127
+ module.exports.Timeouts = binding.Timeouts;
128
+ module.exports.clientBuilder = binding.clientBuilder;
129
+ module.exports.timeoutsApiDefaults = binding.timeoutsApiDefaults;
130
+ module.exports.timeoutsStreamingDefaults = binding.timeoutsStreamingDefaults;
package/package.json ADDED
@@ -0,0 +1,56 @@
1
+ {
2
+ "name": "specters",
3
+ "version": "2.0.0",
4
+ "description": "Node.js bindings for Specter HTTP client with TLS/HTTP2/HTTP3 fingerprint control",
5
+ "main": "index.js",
6
+ "types": "index.d.ts",
7
+ "napi": {
8
+ "binaryName": "specter",
9
+ "targets": [
10
+ "x86_64-apple-darwin",
11
+ "aarch64-apple-darwin",
12
+ "x86_64-unknown-linux-gnu",
13
+ "x86_64-unknown-linux-musl",
14
+ "aarch64-unknown-linux-gnu"
15
+ ]
16
+ },
17
+ "files": [
18
+ "index.js",
19
+ "index.d.ts",
20
+ "*.node"
21
+ ],
22
+ "scripts": {
23
+ "build": "napi build --platform --release --dts index.gen.d.ts",
24
+ "build:debug": "napi build --platform",
25
+ "prepublishOnly": "napi prepublish -t npm --no-gh-release",
26
+ "artifacts": "napi artifacts",
27
+ "test": "jest"
28
+ },
29
+ "devDependencies": {
30
+ "@napi-rs/cli": "^3.0.0-alpha",
31
+ "jest": "^29.7.0"
32
+ },
33
+ "keywords": [
34
+ "http",
35
+ "http3",
36
+ "fingerprint",
37
+ "tls",
38
+ "client",
39
+ "async",
40
+ "native"
41
+ ],
42
+ "author": "Jared Boynton",
43
+ "license": "MIT",
44
+ "repository": {
45
+ "type": "git",
46
+ "url": "https://github.com/jaredboynton/specter.git",
47
+ "directory": "bindings/node"
48
+ },
49
+ "optionalDependencies": {
50
+ "specters-darwin-x64": "2.0.0",
51
+ "specters-darwin-arm64": "2.0.0",
52
+ "specters-linux-x64-gnu": "2.0.0",
53
+ "specters-linux-x64-musl": "2.0.0",
54
+ "specters-linux-arm64-gnu": "2.0.0"
55
+ }
56
+ }