capskip 1.0.2

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.
@@ -0,0 +1,504 @@
1
+ # CapSkip Node.js SDK — Complete Tutorial
2
+
3
+ This tutorial takes you from zero to solving every captcha type CapSkip supports.
4
+ Work through it top to bottom, or jump to the section you need.
5
+
6
+ **Contents**
7
+
8
+ 1. [How it works](#1-how-it-works)
9
+ 2. [Install and configure](#2-install-and-configure)
10
+ 3. [Your first solve](#3-your-first-solve)
11
+ 4. [Image captcha](#4-image-captcha)
12
+ 5. [reCAPTCHA v2](#5-recaptcha-v2)
13
+ 6. [reCAPTCHA v3](#6-recaptcha-v3)
14
+ 7. [Cloudflare Turnstile](#7-cloudflare-turnstile)
15
+ 8. [Using a proxy](#8-using-a-proxy)
16
+ 9. [Concurrency](#9-concurrency)
17
+ 10. [The manual workflow](#10-the-manual-workflow)
18
+ 11. [Return values](#11-return-values)
19
+ 12. [Error handling](#12-error-handling)
20
+ 13. [End-to-end: solve and submit](#13-end-to-end-solve-and-submit)
21
+ 14. [Parameter reference](#14-parameter-reference)
22
+ 15. [Best practices](#15-best-practices)
23
+
24
+ ---
25
+
26
+ ## 1. How it works
27
+
28
+ CapSkip is a **local** application that solves captchas on your own machine and
29
+ exposes a standard captcha-solver HTTP API (documented in the [CapSkip API docs](https://capskip.com/api-docs/)):
30
+
31
+ ```
32
+ POST http://<host>:<port>/in.php → submit a captcha, returns OK|<id>
33
+ GET http://<host>:<port>/res.php → poll for the answer, returns OK|<solution>
34
+ ```
35
+
36
+ This SDK is a thin, friendly wrapper around that API. Every solve follows the
37
+ same three steps, which the SDK does for you:
38
+
39
+ 1. **Submit** the captcha (`in.php`) and receive a captcha ID.
40
+ 2. **Poll** the result endpoint (`res.php`) every few seconds while the answer is
41
+ not ready.
42
+ 3. **Return** the solution once CapSkip finishes.
43
+
44
+ You never have to write the polling loop yourself — call one method and `await`
45
+ the answer.
46
+
47
+ ---
48
+
49
+ ## 2. Install and configure
50
+
51
+ ### Install CapSkip
52
+
53
+ Download and launch the CapSkip desktop app from [capskip.com](https://capskip.com),
54
+ and leave it running. In **Settings**, note the **API port** (default `8080`) and,
55
+ if API-key validation is enabled, your **API key**.
56
+
57
+ ### Install the SDK
58
+
59
+ ```bash
60
+ npm install capskip
61
+ ```
62
+
63
+ Verify:
64
+
65
+ ```bash
66
+ node -e "console.log(require('capskip').version)"
67
+ node examples/verify_connection.js # checks CapSkip is reachable
68
+ ```
69
+
70
+ ### Configure the client
71
+
72
+ ```js
73
+ const { CapSkip } = require('capskip');
74
+
75
+ const solver = new CapSkip({
76
+ apiKey: 'capskip', // your CapSkip API key (any string if validation is off)
77
+ host: '127.0.0.1', // where CapSkip is listening
78
+ port: 8080, // API port from CapSkip settings
79
+ defaultTimeout: 120, // seconds to wait for an image captcha
80
+ recaptchaTimeout: 300, // seconds to wait for reCAPTCHA / Turnstile
81
+ pollingInterval: 5, // max seconds between result polls (starts at 0.25s, backs off to this)
82
+ });
83
+ ```
84
+
85
+ In production, read configuration from the environment instead of hard-coding it:
86
+
87
+ ```js
88
+ const { CapSkip } = require('capskip');
89
+
90
+ const solver = new CapSkip({
91
+ apiKey: process.env.CAPSKIP_API_KEY || 'capskip',
92
+ host: process.env.CAPSKIP_HOST || '127.0.0.1',
93
+ port: parseInt(process.env.CAPSKIP_PORT || '8080', 10),
94
+ });
95
+ ```
96
+
97
+ ---
98
+
99
+ ## 3. Your first solve
100
+
101
+ ```js
102
+ const { CapSkip } = require('capskip');
103
+
104
+ const solver = new CapSkip({ host: '127.0.0.1', port: 8080 });
105
+
106
+ (async () => {
107
+ const result = await solver.recaptcha(
108
+ '6Le-wvkS...your-sitekey',
109
+ 'https://example.com/page-with-recaptcha',
110
+ );
111
+
112
+ console.log(result.code); // the g-recaptcha-response token
113
+ console.log(result.captchaId); // CapSkip's internal ID for this solve
114
+ })();
115
+ ```
116
+
117
+ `result` is always an object. The solution is in `result.code`.
118
+
119
+ ---
120
+
121
+ ## 4. Image captcha
122
+
123
+ Use `solver.normal(...)` for classic distorted-text images. The SDK accepts four
124
+ input forms and auto-detects which one you passed:
125
+
126
+ ```js
127
+ // 1. Local file path
128
+ await solver.normal('captcha.png');
129
+
130
+ // 2. Remote image URL (the SDK downloads and encodes it)
131
+ await solver.normal('https://example.com/captcha.jpg');
132
+
133
+ // 3. Base64 string (no file extension, longer than 50 characters)
134
+ const fs = require('fs');
135
+ const b64 = fs.readFileSync('captcha.png').toString('base64');
136
+ await solver.normal(b64);
137
+
138
+ // 4. Data-URI
139
+ const result = await solver.normal('data:image/png;base64,iVBORw0KGgo...');
140
+
141
+ console.log(result.code); // the recognized text
142
+ ```
143
+
144
+ Image captcha accepts only one extra option, `json`, which controls the raw
145
+ response format from CapSkip:
146
+
147
+ ```js
148
+ await solver.normal('captcha.png', { json: 1 });
149
+ ```
150
+
151
+ > **Note:** Proxies are **not** supported for image captcha — passing one throws
152
+ > `ValidationException`. Proxies apply only to reCAPTCHA and Turnstile.
153
+
154
+ ---
155
+
156
+ ## 5. reCAPTCHA v2
157
+
158
+ `solver.recaptcha(sitekey, url)` handles reCAPTCHA v2 by default. The `sitekey` is
159
+ the `data-sitekey` attribute of the widget; `url` is the full page URL where it
160
+ appears.
161
+
162
+ ```js
163
+ // Standard checkbox
164
+ await solver.recaptcha('6Le-wvkS...', 'https://example.com/login');
165
+
166
+ // Invisible reCAPTCHA v2
167
+ await solver.recaptcha('6Le-wvkS...', 'https://example.com', { invisible: 1 });
168
+
169
+ // Enterprise reCAPTCHA v2
170
+ await solver.recaptcha('6Le-wvkS...', 'https://example.com', { enterprise: 1 });
171
+
172
+ // Enterprise with a data-s value (SDK alias: datas)
173
+ const result = await solver.recaptcha('6Le-wvkS...', 'https://example.com', {
174
+ enterprise: 1,
175
+ datas: 'Crb7Vs...',
176
+ });
177
+
178
+ console.log(result.code); // g-recaptcha-response token
179
+ ```
180
+
181
+ Do **not** pass `version`, `action`, or `min_score` to a v2 solve — those belong
182
+ to v3 and will throw `ValidationException`.
183
+
184
+ ---
185
+
186
+ ## 6. reCAPTCHA v3
187
+
188
+ reCAPTCHA v3 is score-based. Pass `version: 'v3'` plus the `action` your target
189
+ page uses and, optionally, a minimum score.
190
+
191
+ ```js
192
+ const result = await solver.recaptcha('6Le-wvkS...', 'https://example.com', {
193
+ version: 'v3',
194
+ action: 'submit', // must match the action in grecaptcha.execute()
195
+ score: 0.7, // SDK alias for min_score (0.1 – 0.9)
196
+ enterprise: 0, // set 1 for Enterprise v3
197
+ });
198
+
199
+ console.log(result.code);
200
+ ```
201
+
202
+ `invisible` is a v2-only flag and is rejected for v3.
203
+
204
+ ---
205
+
206
+ ## 7. Cloudflare Turnstile
207
+
208
+ `solver.turnstile(sitekey, url)` solves Cloudflare Turnstile. The SDK automatically
209
+ requests the JSON response so it can return the **User-Agent** Cloudflare expects.
210
+
211
+ ```js
212
+ // Standalone widget
213
+ const result = await solver.turnstile('0x4AAAAAAA...', 'https://example.com');
214
+ console.log(result.code); // cf-turnstile-response token
215
+ console.log(result.userAgent); // present when CapSkip returns it
216
+
217
+ // With an explicit action
218
+ await solver.turnstile('0x4AAAAAAA...', 'https://example.com', { action: 'login' });
219
+
220
+ // Cloudflare challenge page (needs cData and chlPageData from the page)
221
+ await solver.turnstile('0x4AAAAAAA...', 'https://example.com', {
222
+ action: 'managed',
223
+ data: 'your_cData_value',
224
+ pagedata: 'your_chlPageData_value',
225
+ });
226
+ ```
227
+
228
+ > **Important:** For challenge pages you **must** send the returned token *and* use
229
+ > `result.userAgent` as the `User-Agent` header when you submit it. Mismatched
230
+ > User-Agents are the most common reason a valid token gets rejected.
231
+
232
+ ---
233
+
234
+ ## 8. Using a proxy
235
+
236
+ Solving through the same IP you will submit from greatly improves acceptance rates
237
+ for reCAPTCHA and Turnstile. Pass the proxy as an object with `type` and `uri`:
238
+
239
+ ```js
240
+ const proxy = { type: 'HTTPS', uri: 'user:pass@1.2.3.4:3128' };
241
+
242
+ await solver.recaptcha('...', 'https://example.com', { proxy });
243
+ await solver.turnstile('...', 'https://example.com', { proxy });
244
+ ```
245
+
246
+ Supported proxy types: `HTTP`, `HTTPS`, `SOCKS5`, `SOCKS5H`. The `uri` may include
247
+ credentials (`login:password@host:port`) or be a bare `host:port`.
248
+
249
+ ---
250
+
251
+ ## 9. Concurrency
252
+
253
+ Every solve method returns a Promise, so you can solve many captchas concurrently
254
+ with `Promise.all`:
255
+
256
+ ```js
257
+ const { CapSkip } = require('capskip');
258
+
259
+ async function main() {
260
+ const solver = new CapSkip({ host: '127.0.0.1', port: 8080 });
261
+
262
+ const [r1, r2, r3] = await Promise.all([
263
+ solver.recaptcha('...', 'https://a.com'),
264
+ solver.recaptcha('...', 'https://b.com', { version: 'v3', action: 'submit' }),
265
+ solver.turnstile('0x4A...', 'https://c.com'),
266
+ ]);
267
+
268
+ console.log(r1.code, r2.code, r3.code);
269
+ }
270
+
271
+ main();
272
+ ```
273
+
274
+ Use `Promise.allSettled` if you want one failure not to reject the others:
275
+
276
+ ```js
277
+ const results = await Promise.allSettled([task1, task2]);
278
+ ```
279
+
280
+ ---
281
+
282
+ ## 10. The manual workflow
283
+
284
+ If you want to submit now and collect the answer later, use the two low-level
285
+ steps directly.
286
+
287
+ ```js
288
+ const { NetworkException } = require('capskip');
289
+
290
+ const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
291
+
292
+ // 1. Submit — resolves to the captcha ID immediately, without waiting.
293
+ const captchaId = await solver.send({
294
+ method: 'userrecaptcha',
295
+ googlekey: '6Le-wvkS...',
296
+ pageurl: 'https://example.com',
297
+ });
298
+
299
+ // 2. Poll once. NetworkException means "not ready yet" — retry.
300
+ let code;
301
+ while (true) {
302
+ try {
303
+ code = await solver.getResult(captchaId);
304
+ break;
305
+ } catch (err) {
306
+ if (!(err instanceof NetworkException)) throw err;
307
+ await sleep(5000);
308
+ }
309
+ }
310
+
311
+ console.log(code);
312
+ ```
313
+
314
+ Pass `1` as the second argument to `getResult` to get the full object (including
315
+ `userAgent` for Turnstile) instead of a plain string.
316
+
317
+ ---
318
+
319
+ ## 11. Return values
320
+
321
+ Every high-level solve method (`normal`, `recaptcha`, `turnstile`, `solve`)
322
+ resolves to an object:
323
+
324
+ ```js
325
+ {
326
+ captchaId: '12345', // CapSkip's internal ID for this solve
327
+ code: 'TOKEN_OR_TEXT', // the solution: text for images, token otherwise
328
+ userAgent: 'Mozilla/...', // Turnstile only, when CapSkip provides it
329
+ }
330
+ ```
331
+
332
+ `solver.send()` resolves to just the ID string. `solver.getResult()` resolves to
333
+ the solution string (or an object when called with `json = 1`).
334
+
335
+ ---
336
+
337
+ ## 12. Error handling
338
+
339
+ The SDK throws four error types, all subclasses of `CapSkipError`:
340
+
341
+ | Exception | When it is thrown |
342
+ |---|---|
343
+ | `ValidationException` | Invalid or unsupported parameters (e.g. proxy on image captcha) |
344
+ | `NetworkException` | CapSkip is unreachable, or the captcha is not ready yet |
345
+ | `ApiException` | CapSkip returned an error code (e.g. `ERROR_WRONG_USER_KEY`) |
346
+ | `TimeoutException` | Polling exceeded the configured timeout |
347
+
348
+ ```js
349
+ const {
350
+ CapSkip, ValidationException, NetworkException, ApiException, TimeoutException,
351
+ } = require('capskip');
352
+
353
+ const solver = new CapSkip({ host: '127.0.0.1', port: 8080 });
354
+
355
+ try {
356
+ const result = await solver.recaptcha('...', 'https://example.com');
357
+ console.log(result.code);
358
+ } catch (err) {
359
+ if (err instanceof ValidationException) {
360
+ console.log('Bad parameters:', err.message);
361
+ } else if (err instanceof NetworkException) {
362
+ console.log('Is CapSkip running?', err.message);
363
+ } else if (err instanceof ApiException) {
364
+ console.log('CapSkip returned an error:', err.message);
365
+ } else if (err instanceof TimeoutException) {
366
+ console.log('Gave up waiting:', err.message);
367
+ } else {
368
+ throw err;
369
+ }
370
+ }
371
+ ```
372
+
373
+ You can also catch them all at once with the base class:
374
+
375
+ ```js
376
+ const { CapSkipError } = require('capskip');
377
+
378
+ try {
379
+ const result = await solver.turnstile('...', '...');
380
+ } catch (err) {
381
+ if (err instanceof CapSkipError) {
382
+ console.log('Solve failed:', err.message);
383
+ } else {
384
+ throw err;
385
+ }
386
+ }
387
+ ```
388
+
389
+ ---
390
+
391
+ ## 13. End-to-end: solve and submit
392
+
393
+ A realistic flow — solve a reCAPTCHA, then submit the token to the target site
394
+ through the **same** proxy:
395
+
396
+ ```js
397
+ const { CapSkip, CapSkipError } = require('capskip');
398
+
399
+ const solver = new CapSkip({
400
+ apiKey: process.env.CAPSKIP_API_KEY || 'capskip',
401
+ host: '127.0.0.1',
402
+ port: 8080,
403
+ });
404
+
405
+ const SITEKEY = '6Le-wvkS...your-sitekey';
406
+ const LOGIN_URL = 'https://example.com/login';
407
+ const PROXY = { type: 'HTTP', uri: '1.2.3.4:3128' };
408
+
409
+ (async () => {
410
+ let solved;
411
+ try {
412
+ solved = await solver.recaptcha(SITEKEY, LOGIN_URL, { proxy: PROXY });
413
+ } catch (err) {
414
+ if (err instanceof CapSkipError) {
415
+ console.error('Could not solve captcha:', err.message);
416
+ process.exit(1);
417
+ }
418
+ throw err;
419
+ }
420
+
421
+ const token = solved.code;
422
+
423
+ // Submit the form using the same proxy so the IP matches.
424
+ // (Use your HTTP client of choice, e.g. undici's fetch with a ProxyAgent.)
425
+ const response = await fetch(LOGIN_URL, {
426
+ method: 'POST',
427
+ headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
428
+ body: new URLSearchParams({
429
+ username: 'myuser',
430
+ password: 'mypass',
431
+ 'g-recaptcha-response': token,
432
+ }),
433
+ });
434
+
435
+ console.log(response.status);
436
+ })();
437
+ ```
438
+
439
+ For Turnstile challenge pages, also set the User-Agent header:
440
+
441
+ ```js
442
+ const solved = await solver.turnstile('0x4A...', CHALLENGE_URL, {
443
+ data: 'cData',
444
+ pagedata: 'chlPageData',
445
+ });
446
+
447
+ await fetch(CHALLENGE_URL, {
448
+ method: 'POST',
449
+ headers: { 'User-Agent': solved.userAgent },
450
+ body: new URLSearchParams({ 'cf-turnstile-response': solved.code }),
451
+ });
452
+ ```
453
+
454
+ ---
455
+
456
+ ## 14. Parameter reference
457
+
458
+ ### Solve methods
459
+
460
+ | Method | Signature |
461
+ |---|---|
462
+ | Image | `normal(file, { json })` |
463
+ | reCAPTCHA | `recaptcha(sitekey, url, { version, enterprise, ... })` |
464
+ | Turnstile | `turnstile(sitekey, url, { ... })` |
465
+ | Manual submit | `send(params) -> Promise<id>` |
466
+ | Manual poll | `getResult(id, json)` |
467
+
468
+ ### Convenience aliases
469
+
470
+ The SDK accepts friendly names and converts them to the raw API parameters:
471
+
472
+ | SDK name | CapSkip API parameter |
473
+ |---|---|
474
+ | `url` | `pageurl` |
475
+ | `score`, `minScore` | `min_score` |
476
+ | `datas`, `data_s` | `data-s` |
477
+ | `proxy` (object) | `proxy` + `proxytype` strings |
478
+
479
+ Anything CapSkip does not document for a given captcha type is rejected with
480
+ `ValidationException`, so typos fail fast instead of silently doing nothing.
481
+
482
+ ---
483
+
484
+ ## 15. Best practices
485
+
486
+ - **Keep CapSkip running.** The SDK talks to a local app; if it is not running you
487
+ get `NetworkException`.
488
+ - **Use the token immediately.** reCAPTCHA and Turnstile tokens expire within a
489
+ couple of minutes.
490
+ - **Match sitekey and pageurl exactly** to the page the widget loads on.
491
+ - **Solve and submit from the same IP** (same proxy) for reCAPTCHA and Turnstile.
492
+ - **Never commit secrets.** Read `CAPSKIP_API_KEY` and proxy credentials from the
493
+ environment, not source code.
494
+ - **Tune timeouts** for slow captcha types with `recaptchaTimeout` and
495
+ `defaultTimeout`.
496
+
497
+ ---
498
+
499
+ ### Where to go next
500
+
501
+ - [API Reference](API_REFERENCE.md) — every method, parameter, and endpoint
502
+ - [Getting Started](GETTING_STARTED.md) — installation walkthrough
503
+ - [Troubleshooting](TROUBLESHOOTING.md) — fixes for common errors
504
+ - [CapSkip API docs](https://capskip.com/api-docs/) — the raw HTTP API
@@ -0,0 +1,34 @@
1
+ 'use strict';
2
+
3
+ const { AsyncCapSkip } = require('capskip');
4
+
5
+ // Official public test keys and demo pages — safe to run as-is.
6
+ const RECAPTCHA_SITEKEY = '6LeIxAcTAAAAAJcZVRqyHh71UMIEGNQ_MXjiZKhI'; // Google reCAPTCHA v2 test key
7
+ const RECAPTCHA_URL = 'https://www.google.com/recaptcha/api2/demo';
8
+ const TURNSTILE_SITEKEY = '1x00000000000000000000AA'; // Cloudflare Turnstile test key (always passes)
9
+ const TURNSTILE_URL = 'https://demo.turnstile.workers.dev/';
10
+
11
+ async function main() {
12
+ const solver = new AsyncCapSkip({
13
+ apiKey: process.env.CAPSKIP_API_KEY || 'capskip',
14
+ host: process.env.CAPSKIP_HOST || '127.0.0.1',
15
+ port: parseInt(process.env.CAPSKIP_PORT || '8080', 10),
16
+ });
17
+
18
+ // Promise.allSettled lets one failure not cancel the others.
19
+ const results = await Promise.allSettled([
20
+ solver.recaptcha(RECAPTCHA_SITEKEY, RECAPTCHA_URL),
21
+ solver.recaptcha(RECAPTCHA_SITEKEY, RECAPTCHA_URL, { version: 'v3', action: 'submit', score: 0.7 }),
22
+ solver.turnstile(TURNSTILE_SITEKEY, TURNSTILE_URL),
23
+ ]);
24
+
25
+ const names = ['recaptcha v2', 'recaptcha v3', 'turnstile'];
26
+ results.forEach((result, index) => {
27
+ const value = result.status === 'fulfilled'
28
+ ? JSON.stringify(result.value)
29
+ : String(result.reason);
30
+ console.log(`${names[index]}: ${value}`);
31
+ });
32
+ }
33
+
34
+ main();
Binary file
@@ -0,0 +1,20 @@
1
+ 'use strict';
2
+
3
+ const path = require('path');
4
+ const { CapSkip } = require('capskip');
5
+
6
+ const solver = new CapSkip({
7
+ apiKey: process.env.CAPSKIP_API_KEY || 'capskip',
8
+ host: process.env.CAPSKIP_HOST || '127.0.0.1',
9
+ port: parseInt(process.env.CAPSKIP_PORT || '8080', 10),
10
+ });
11
+
12
+ // Sample captcha image shipped alongside this script — resolved relative to the
13
+ // file so it works no matter which directory you run from.
14
+ const IMAGE = path.join(__dirname, 'captcha.png');
15
+
16
+ (async () => {
17
+ const result = await solver.normal(IMAGE);
18
+ console.log('Captcha ID:', result.captchaId);
19
+ console.log('Solution: ', result.code);
20
+ })();
@@ -0,0 +1,19 @@
1
+ 'use strict';
2
+
3
+ const { CapSkip } = require('capskip');
4
+
5
+ const solver = new CapSkip({
6
+ apiKey: process.env.CAPSKIP_API_KEY || 'capskip',
7
+ host: process.env.CAPSKIP_HOST || '127.0.0.1',
8
+ port: parseInt(process.env.CAPSKIP_PORT || '8080', 10),
9
+ });
10
+
11
+ // Google's official reCAPTCHA v2 test key and demo page — safe to run as-is.
12
+ const SITEKEY = '6LeIxAcTAAAAAJcZVRqyHh71UMIEGNQ_MXjiZKhI';
13
+ const PAGE_URL = 'https://www.google.com/recaptcha/api2/demo';
14
+
15
+ (async () => {
16
+ const result = await solver.recaptcha(SITEKEY, PAGE_URL);
17
+ console.log('Captcha ID:', result.captchaId);
18
+ console.log('Token: ', result.code);
19
+ })();
@@ -0,0 +1,20 @@
1
+ 'use strict';
2
+
3
+ const { CapSkip } = require('capskip');
4
+
5
+ const solver = new CapSkip({
6
+ apiKey: process.env.CAPSKIP_API_KEY || 'capskip',
7
+ host: process.env.CAPSKIP_HOST || '127.0.0.1',
8
+ port: parseInt(process.env.CAPSKIP_PORT || '8080', 10),
9
+ });
10
+
11
+ // Cloudflare's official Turnstile test key (always passes) and demo page — safe to run as-is.
12
+ const SITEKEY = '1x00000000000000000000AA';
13
+ const PAGE_URL = 'https://demo.turnstile.workers.dev/';
14
+
15
+ (async () => {
16
+ const result = await solver.turnstile(SITEKEY, PAGE_URL);
17
+ console.log('Captcha ID:', result.captchaId);
18
+ console.log('Token: ', result.code);
19
+ console.log('User-Agent:', result.userAgent);
20
+ })();
@@ -0,0 +1,50 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ // Verify CapSkip is running and reachable.
5
+
6
+ const {
7
+ ApiClient, ApiException, NetworkException, version,
8
+ } = require('capskip');
9
+
10
+ function parseArgs(argv) {
11
+ const args = { host: '127.0.0.1', port: 8080, apiKey: 'capskip' };
12
+ for (let i = 2; i < argv.length; i += 1) {
13
+ const arg = argv[i];
14
+ if (arg === '--host') {
15
+ args.host = argv[++i];
16
+ } else if (arg === '--port') {
17
+ args.port = parseInt(argv[++i], 10);
18
+ } else if (arg === '--api-key') {
19
+ args.apiKey = argv[++i];
20
+ }
21
+ }
22
+ return args;
23
+ }
24
+
25
+ async function main() {
26
+ const args = parseArgs(process.argv);
27
+ const client = new ApiClient({ host: args.host, port: args.port });
28
+
29
+ console.log(`CapSkip SDK : ${version}`);
30
+ console.log(`Target : ${client.baseUrl}`);
31
+
32
+ try {
33
+ await client.res({ key: args.apiKey, action: 'get', id: '0' });
34
+ console.log('Status : OK — CapSkip is reachable');
35
+ } catch (err) {
36
+ if (err instanceof ApiException) {
37
+ console.log('Status : OK — CapSkip is reachable');
38
+ console.log(`Response : ${err.message}`);
39
+ } else if (err instanceof NetworkException) {
40
+ console.log(`Status : FAILED — ${err.message}`);
41
+ process.exitCode = 1;
42
+ } else {
43
+ throw err;
44
+ }
45
+ }
46
+
47
+ console.log('Try: node examples/recaptcha.js');
48
+ }
49
+
50
+ main();
package/package.json ADDED
@@ -0,0 +1,50 @@
1
+ {
2
+ "name": "capskip",
3
+ "version": "1.0.2",
4
+ "description": "Node.js SDK for the CapSkip local captcha solver",
5
+ "main": "src/index.js",
6
+ "types": "types/index.d.ts",
7
+ "exports": {
8
+ ".": {
9
+ "types": "./types/index.d.ts",
10
+ "require": "./src/index.js",
11
+ "default": "./src/index.js"
12
+ },
13
+ "./package.json": "./package.json"
14
+ },
15
+ "type": "commonjs",
16
+ "engines": {
17
+ "node": ">=18"
18
+ },
19
+ "scripts": {
20
+ "test": "node --test",
21
+ "test:watch": "node --test --watch"
22
+ },
23
+ "keywords": [
24
+ "captcha",
25
+ "captcha-solver",
26
+ "recaptcha",
27
+ "cloudflare",
28
+ "turnstile",
29
+ "capskip",
30
+ "automation"
31
+ ],
32
+ "author": "CapSkip <support@capskip.com>",
33
+ "license": "MIT",
34
+ "homepage": "https://capskip.com",
35
+ "repository": {
36
+ "type": "git",
37
+ "url": "git+https://github.com/capskip/capskip-node.git"
38
+ },
39
+ "bugs": {
40
+ "url": "https://github.com/capskip/capskip-node/issues"
41
+ },
42
+ "files": [
43
+ "src",
44
+ "types",
45
+ "docs",
46
+ "examples",
47
+ "CHANGELOG.md",
48
+ "SECURITY.md"
49
+ ]
50
+ }