specters 2.0.0 → 2.1.3

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 (3) hide show
  1. package/README.md +6 -1
  2. package/index.js +94 -85
  3. package/package.json +15 -13
package/README.md CHANGED
@@ -40,7 +40,12 @@ main();
40
40
  ```javascript
41
41
  const { Client, FingerprintProfile } = require('@specter/client');
42
42
 
43
- // Impersonate Chrome 142
43
+ // Impersonate Chrome 146 (current stable)
44
+ const client = Client.builder()
45
+ .fingerprint(FingerprintProfile.Chrome146)
46
+ .build();
47
+
48
+ // Or pick a specific version (142, 143, 144, 145, 146)
44
49
  const client = Client.builder()
45
50
  .fingerprint(FingerprintProfile.Chrome142)
46
51
  .build();
package/index.js CHANGED
@@ -3,120 +3,129 @@
3
3
  *
4
4
  * A high-performance async HTTP client with full TLS, HTTP/2, and HTTP/3
5
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
6
  */
29
7
 
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',
8
+ const { execSync } = require('node:child_process');
9
+ const { readFileSync } = require('node:fs');
10
+
11
+ const PACKAGE_VERSION = '2.1.3';
12
+
13
+ const targets = {
14
+ 'darwin-x64': {
15
+ local: './specter.darwin-x64.node',
16
+ package: 'specters-darwin-x64',
17
+ },
18
+ 'darwin-arm64': {
19
+ local: './specter.darwin-arm64.node',
20
+ package: 'specters-darwin-arm64',
21
+ },
22
+ 'linux-x64-gnu': {
23
+ local: './specter.linux-x64-gnu.node',
24
+ package: 'specters-linux-x64-gnu',
25
+ },
26
+ 'linux-arm64-gnu': {
27
+ local: './specter.linux-arm64-gnu.node',
28
+ package: 'specters-linux-arm64-gnu',
29
+ },
45
30
  };
46
31
 
47
- function getPlatformKey() {
48
- const platform = process.platform;
49
- const arch = process.arch;
32
+ function isMusl() {
33
+ if (process.platform !== 'linux') {
34
+ return false;
35
+ }
50
36
 
51
- if (platform === 'darwin') {
52
- return `darwin-${arch}`;
37
+ const report = typeof process.report?.getReport === 'function'
38
+ ? process.report.getReport()
39
+ : null;
40
+
41
+ if (report?.header?.glibcVersionRuntime) {
42
+ return false;
53
43
  }
54
- if (platform === 'win32') {
55
- return `win32-${arch}-msvc`;
44
+
45
+ if (Array.isArray(report?.sharedObjects)) {
46
+ return report.sharedObjects.some((file) => file.includes('libc.musl-') || file.includes('ld-musl-'));
56
47
  }
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'}`;
48
+
49
+ try {
50
+ return readFileSync('/usr/bin/ldd', 'utf8').includes('musl');
51
+ } catch {
52
+ try {
53
+ return execSync('ldd --version', { encoding: 'utf8' }).includes('musl');
54
+ } catch {
55
+ return false;
56
+ }
57
+ }
58
+ }
59
+
60
+ function targetKey() {
61
+ if (process.platform === 'darwin') {
62
+ return `darwin-${process.arch}`;
63
+ }
64
+
65
+ if (process.platform === 'linux') {
66
+ return `linux-${process.arch}-${isMusl() ? 'musl' : 'gnu'}`;
67
+ }
68
+
69
+ return `${process.platform}-${process.arch}`;
70
+ }
71
+
72
+ function versionCheck(packageName) {
73
+ if (!process.env.NAPI_RS_ENFORCE_VERSION_CHECK || process.env.NAPI_RS_ENFORCE_VERSION_CHECK === '0') {
74
+ return;
75
+ }
76
+
77
+ const packageVersion = require(`${packageName}/package.json`).version;
78
+ if (packageVersion !== PACKAGE_VERSION) {
79
+ throw new Error(
80
+ `Native binding package version mismatch for ${packageName}: expected ${PACKAGE_VERSION}, got ${packageVersion}. ` +
81
+ 'Reinstall dependencies to refresh optional native packages.'
82
+ );
68
83
  }
69
- return null;
70
84
  }
71
85
 
72
86
  function loadNativeBinding() {
73
- // Try platform-specific binary first
74
- const platformKey = getPlatformKey();
75
- if (platformKey && platformBinaries[platformKey]) {
87
+ const loadErrors = [];
88
+
89
+ if (process.env.NAPI_RS_NATIVE_LIBRARY_PATH) {
76
90
  try {
77
- nativeBinding = require(`./${platformBinaries[platformKey]}`);
78
- return nativeBinding;
79
- } catch (e) {
80
- // Continue to fallback
91
+ return require(process.env.NAPI_RS_NATIVE_LIBRARY_PATH);
92
+ } catch (error) {
93
+ loadErrors.push(error);
81
94
  }
82
95
  }
83
96
 
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
- }
97
+ const key = targetKey();
98
+ const target = targets[key];
99
+
100
+ if (!target) {
101
+ throw new Error(
102
+ `Unsupported Specter native target: ${key}. ` +
103
+ `Supported targets: ${Object.keys(targets).join(', ')}.`
104
+ );
92
105
  }
93
106
 
94
- // Try loading from build directory
95
107
  try {
96
- nativeBinding = require('./specter.node');
97
- return nativeBinding;
98
- } catch (e) {
99
- // Fall through
108
+ return require(target.local);
109
+ } catch (error) {
110
+ loadErrors.push(error);
100
111
  }
101
112
 
102
- // Try loading from target
103
113
  try {
104
- nativeBinding = require('./build/Release/specter.node');
105
- return nativeBinding;
106
- } catch (e) {
107
- // Fall through
114
+ versionCheck(target.package);
115
+ return require(target.package);
116
+ } catch (error) {
117
+ loadErrors.push(error);
108
118
  }
109
119
 
110
120
  throw new Error(
111
- `Failed to load native binding for Specter. ` +
112
- `Please ensure you've built the native module with "npm run build".`
121
+ `Failed to load Specter native binding for ${key}. ` +
122
+ `Expected optional package "${target.package}" or local binary "${target.local}".\n` +
123
+ loadErrors.map((error) => `- ${error.message}`).join('\n')
113
124
  );
114
125
  }
115
126
 
116
- // Load the binding
117
127
  const binding = loadNativeBinding();
118
128
 
119
- // Export the native types
120
129
  module.exports.Client = binding.Client;
121
130
  module.exports.ClientBuilder = binding.ClientBuilder;
122
131
  module.exports.RequestBuilder = binding.RequestBuilder;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "specters",
3
- "version": "2.0.0",
3
+ "version": "2.1.3",
4
4
  "description": "Node.js bindings for Specter HTTP client with TLS/HTTP2/HTTP3 fingerprint control",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",
@@ -10,24 +10,33 @@
10
10
  "x86_64-apple-darwin",
11
11
  "aarch64-apple-darwin",
12
12
  "x86_64-unknown-linux-gnu",
13
- "x86_64-unknown-linux-musl",
14
13
  "aarch64-unknown-linux-gnu"
15
14
  ]
16
15
  },
17
16
  "files": [
18
17
  "index.js",
19
- "index.d.ts",
20
- "*.node"
18
+ "index.d.ts"
21
19
  ],
20
+ "publishConfig": {
21
+ "registry": "https://registry.npmjs.org/",
22
+ "access": "public"
23
+ },
22
24
  "scripts": {
23
25
  "build": "napi build --platform --release --dts index.gen.d.ts",
24
26
  "build:debug": "napi build --platform",
27
+ "create:npm-dirs": "napi create-npm-dirs",
25
28
  "prepublishOnly": "napi prepublish -t npm --no-gh-release",
26
- "artifacts": "napi artifacts",
29
+ "artifacts": "napi artifacts --output-dir ./artifacts",
27
30
  "test": "jest"
28
31
  },
32
+ "optionalDependencies": {
33
+ "specters-darwin-x64": "2.1.3",
34
+ "specters-darwin-arm64": "2.1.3",
35
+ "specters-linux-x64-gnu": "2.1.3",
36
+ "specters-linux-arm64-gnu": "2.1.3"
37
+ },
29
38
  "devDependencies": {
30
- "@napi-rs/cli": "^3.0.0-alpha",
39
+ "@napi-rs/cli": "^3.6.2",
31
40
  "jest": "^29.7.0"
32
41
  },
33
42
  "keywords": [
@@ -45,12 +54,5 @@
45
54
  "type": "git",
46
55
  "url": "https://github.com/jaredboynton/specter.git",
47
56
  "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
57
  }
56
58
  }