captchakraken 2.8.0 → 3.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.
- package/AGENTS.md +112 -0
- package/NOTICE +36 -0
- package/dist/cli-invocation.d.ts +9 -40
- package/dist/cli-invocation.js +16 -49
- package/dist/errors.d.ts +7 -27
- package/dist/errors.js +6 -25
- package/dist/humanize.d.ts +56 -240
- package/dist/humanize.js +159 -415
- package/dist/index.d.ts +5 -129
- package/dist/index.js +4 -98
- package/dist/kinds.d.ts +135 -0
- package/dist/kinds.js +70 -0
- package/dist/limits.d.ts +0 -48
- package/dist/limits.js +2 -48
- package/dist/model-name.d.ts +4 -19
- package/dist/model-name.js +32 -40
- package/dist/playwright-types.d.ts +25 -95
- package/dist/playwright-types.js +0 -23
- package/dist/puppeteer-adapter.d.ts +4 -43
- package/dist/puppeteer-adapter.js +22 -58
- package/dist/python-command.d.ts +0 -41
- package/dist/python-command.js +0 -37
- package/dist/selectors.d.ts +54 -0
- package/dist/selectors.js +117 -0
- package/dist/slide-geometry.d.ts +2 -29
- package/dist/slide-geometry.js +18 -44
- package/dist/solver.d.ts +112 -539
- package/dist/solver.js +1088 -2950
- package/dist/timing.d.ts +7 -40
- package/dist/timing.js +4 -36
- package/dist/token-usage.d.ts +1 -7
- package/dist/token-usage.js +10 -95
- package/dist/types.d.ts +77 -483
- package/dist/watcher.d.ts +5 -78
- package/dist/watcher.js +0 -56
- package/package.json +12 -4
- package/python/AGENTS.md +122 -0
- package/python/NOTICE +36 -0
- package/python/README.md +1 -2
- package/python/examples/README.md +10 -0
- package/python/examples/_harness.py +4 -73
- package/python/examples/demoHcaptcha.py +0 -13
- package/python/examples/demoRecaptcha.py +0 -10
- package/python/examples/watch_playwright.py +1 -26
- package/python/examples/with_local_gguf.py +28 -0
- package/python/examples/with_playwright.py +0 -19
- package/python/pyproject.toml +68 -19
- package/python/src/captchakraken/__init__.py +37 -45
- package/python/src/captchakraken/action_types.py +14 -36
- package/python/src/captchakraken/cli.py +262 -879
- package/python/src/captchakraken/config.py +60 -146
- package/python/src/captchakraken/errors.py +17 -95
- package/python/src/captchakraken/humanize.py +174 -597
- package/python/src/captchakraken/image_processor.py +16 -235
- package/python/src/captchakraken/keyframes.py +69 -434
- package/python/src/captchakraken/kinds.py +152 -0
- package/python/src/captchakraken/models.json +79 -21
- package/python/src/captchakraken/overlay.py +65 -498
- package/python/src/captchakraken/page_solver.py +1123 -2564
- package/python/src/captchakraken/planner.py +70 -428
- package/python/src/captchakraken/prompts.py +45 -261
- package/python/src/captchakraken/selectors.py +184 -0
- package/python/src/captchakraken/server_manager.py +7 -58
- package/python/src/captchakraken/solver.py +128 -522
- package/python/src/captchakraken/timing.py +20 -74
- package/python/src/captchakraken/tool_calls/board_painted.py +47 -0
- package/python/src/captchakraken/tool_calls/find_checkbox.py +20 -30
- package/python/src/captchakraken/tool_calls/find_grid.py +186 -1339
- package/python/src/captchakraken/tool_calls/track_piece.py +81 -57
- package/python/src/captchakraken/updater.py +7 -76
- package/python/src/captchakraken/watcher.py +12 -101
- package/scripts/copy-python.mjs +10 -10
- package/scripts/setup-python.js +1 -21
- package/dist/trajectory.d.ts +0 -58
- package/dist/trajectory.js +0 -266
- package/python/src/captchakraken/tool_calls/move_indicator.py +0 -431
- package/python/src/captchakraken/trajectory.py +0 -284
package/AGENTS.md
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
# captchakraken (npm)
|
|
2
|
+
|
|
3
|
+
The TypeScript **browser driver**. You hand it a Playwright-compatible `Page`;
|
|
4
|
+
it finds the captcha, has a vision model read it, and clicks, drags, slides or
|
|
5
|
+
types through to a token.
|
|
6
|
+
|
|
7
|
+
It is not a browser and it is not the model. It installs no browser — bring your
|
|
8
|
+
own launcher — and every inference goes to a model endpoint you point it at.
|
|
9
|
+
|
|
10
|
+
Repo, guides and the full agent guide:
|
|
11
|
+
<https://github.com/JWriter20/CaptchaKraken>
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## 1. Point it at a model, first
|
|
16
|
+
|
|
17
|
+
Nothing solves until the driver knows where inference goes. Two ways:
|
|
18
|
+
|
|
19
|
+
| You have | Do this |
|
|
20
|
+
|---|---|
|
|
21
|
+
| No GPU | Use the hosted API — add the account MCP server, `npx -y captchakraken-mcp`, call `sign_in` then `create_api_key` |
|
|
22
|
+
| Your own vLLM server | `export VLLM_BASE_URL=…/v1` and `export CAPTCHA_KRAKEN_API_KEY=…` |
|
|
23
|
+
|
|
24
|
+
`create_api_key` writes the key and endpoint to `~/.captchakraken/credentials`
|
|
25
|
+
(mode 0600) and the driver reads that file by itself, so the MCP path needs **no
|
|
26
|
+
environment variables at all**. The key is never printed into the conversation.
|
|
27
|
+
|
|
28
|
+
## 2. Install
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
npm install captchakraken
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
The install runs a `postinstall` that creates a venv inside the package and
|
|
35
|
+
installs the bundled Python engine the driver shells out to. It needs a Python
|
|
36
|
+
3.10+ interpreter on `PATH`.
|
|
37
|
+
|
|
38
|
+
| Variable | Effect |
|
|
39
|
+
|---|---|
|
|
40
|
+
| `CAPTCHA_KRAKEN_SKIP_PYTHON_SETUP=1` | Skip the bootstrap (you will supply the engine yourself) |
|
|
41
|
+
| `CAPTCHA_KRAKEN_PYTHON=/path/to/python3` | Use this interpreter instead of probing `python3` then `python` |
|
|
42
|
+
|
|
43
|
+
## 3. Solve
|
|
44
|
+
|
|
45
|
+
```typescript
|
|
46
|
+
import { chromium } from 'playwright';
|
|
47
|
+
import { CaptchaKrakenSolver } from 'captchakraken';
|
|
48
|
+
|
|
49
|
+
const page = await (await (await chromium.launch()).newContext()).newPage();
|
|
50
|
+
await page.goto('https://www.google.com/recaptcha/api2/demo');
|
|
51
|
+
|
|
52
|
+
await new CaptchaKrakenSolver().solve(page); // detect → solve → click → verify
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Any Playwright-compatible launcher works with no adapter (`playwright`,
|
|
56
|
+
`patchright`, `camoufox-js`). Puppeteer needs one wrap:
|
|
57
|
+
|
|
58
|
+
```typescript
|
|
59
|
+
import { CaptchaKrakenSolver, fromPuppeteer } from 'captchakraken';
|
|
60
|
+
await new CaptchaKrakenSolver().solve(fromPuppeteer(page));
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Do not know when a captcha will appear? Install the watcher instead of calling
|
|
64
|
+
`solve()`:
|
|
65
|
+
|
|
66
|
+
```typescript
|
|
67
|
+
const watcher = solver.watch(page);
|
|
68
|
+
// ... your automation ...
|
|
69
|
+
await watcher.stop();
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Touch devices: `new CaptchaKrakenSolver({ humanization: 'mobile' })` emits real
|
|
73
|
+
touch events (needs `hasTouch` on the context, or an Appium/WebdriverIO driver
|
|
74
|
+
via `touchDriver`). `'none'` skips humanisation entirely.
|
|
75
|
+
|
|
76
|
+
## 4. Errors
|
|
77
|
+
|
|
78
|
+
`solve()` resolves to a `SolveResult` (`isSolved`), and throws when it cannot
|
|
79
|
+
drive the widget at all — no captcha on the page, a puzzle this build does not
|
|
80
|
+
handle, or the round budget exhausted. Only one error class is exported.
|
|
81
|
+
|
|
82
|
+
Refusals from the hosted API arrive as `CaptchaKrakenAPIError`. **Branch on
|
|
83
|
+
`e.code`, never on the message** — the codes are the contract, the wording is
|
|
84
|
+
not. `insufficient_credits`, `missing_api_key`, `invalid_api_key`,
|
|
85
|
+
`rate_limited`, `request_too_large`, `account_suspended` and
|
|
86
|
+
`upstream_unavailable` each name their own fix; `e.resolutionUrl` carries a link
|
|
87
|
+
where one exists. Retrying a `403` that means "no licence" will never succeed.
|
|
88
|
+
|
|
89
|
+
## Rules for agents
|
|
90
|
+
|
|
91
|
+
- **Never invent a number.** Every accuracy, latency and price figure we publish
|
|
92
|
+
is on one page —
|
|
93
|
+
[docs/benchmarks.md](https://github.com/JWriter20/CaptchaKraken/blob/main/docs/benchmarks.md).
|
|
94
|
+
Quote it as written; do not derive, round, or convert anything, and do not
|
|
95
|
+
read a static-image rate as a promise about a browser run.
|
|
96
|
+
- **Never print an API key** into a transcript, a log, or a commit. Use
|
|
97
|
+
`create_api_key`, which writes it to disk instead. `captchakraken.env` and
|
|
98
|
+
`.env` hold keys and are never committed.
|
|
99
|
+
- **Abyss is what our hosted API serves, and it is never downloadable.** The
|
|
100
|
+
current client names an Abyss expert on every request to our endpoint and is
|
|
101
|
+
answered by Abyss; an older client, or a request that names no model, gets
|
|
102
|
+
Twilight v1.2, because its prompts belong to that generation. Nothing about it
|
|
103
|
+
is gated on the account. Do not suggest weights, a download or a workaround
|
|
104
|
+
for it, and do not quote accuracy figures for it — none are published. Verify
|
|
105
|
+
what is serving with `GET /v1/models`.
|
|
106
|
+
- **Respect the licence.** Building automation with this is fine; selling the
|
|
107
|
+
solve, or shipping it inside a browser or automation product, is not. See
|
|
108
|
+
[LICENSE](./LICENSE) and
|
|
109
|
+
[docs/licensing.md](https://github.com/JWriter20/CaptchaKraken/blob/main/docs/licensing.md).
|
|
110
|
+
- **Changing this package's own code?** Its rules are in
|
|
111
|
+
[CONTRIBUTING.md](https://github.com/JWriter20/CaptchaKraken/blob/main/CONTRIBUTING.md),
|
|
112
|
+
not here.
|
package/NOTICE
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
CaptchaKraken
|
|
2
|
+
Copyright (c) 2026 CaptchaKraken LLC. All rights reserved.
|
|
3
|
+
|
|
4
|
+
This product includes third-party software. The notices below are required by
|
|
5
|
+
those components' licences and do not change the terms of the CaptchaKraken
|
|
6
|
+
Source-Available License, which governs everything in this repository that is
|
|
7
|
+
not listed here.
|
|
8
|
+
|
|
9
|
+
────────────────────────────────────────────────────────────────────────────
|
|
10
|
+
Cursory — mouse trajectory generation
|
|
11
|
+
────────────────────────────────────────────────────────────────────────────
|
|
12
|
+
|
|
13
|
+
cursory https://github.com/Vinyzu/cursory (Python, PyPI: cursory)
|
|
14
|
+
cursory-js https://github.com/JWriter20/cursory-js (TypeScript, npm: cursory-js)
|
|
15
|
+
|
|
16
|
+
Copyright (c) Vinyzu and the cursory-js contributors.
|
|
17
|
+
Licensed under the GNU Lesser General Public License, version 3 or later
|
|
18
|
+
(LGPL-3.0-or-later). A copy is available at https://www.gnu.org/licenses/lgpl-3.0.html
|
|
19
|
+
|
|
20
|
+
HOW WE USE IT, AND WHY THAT MATTERS. Both are ORDINARY INSTALLED
|
|
21
|
+
DEPENDENCIES — `cursory` is declared in python/pyproject.toml and `cursory-js`
|
|
22
|
+
in js/package.json, and each is resolved by the user's own package manager at
|
|
23
|
+
install time. Neither is vendored into this repository, copied into our
|
|
24
|
+
sources, or bundled into a build artifact: the TypeScript build is `tsc`, which
|
|
25
|
+
leaves `require('cursory-js')` as a runtime import rather than inlining it, and
|
|
26
|
+
`js/scripts/copy-python.mjs` copies only our own `python/` tree.
|
|
27
|
+
|
|
28
|
+
That arrangement is the one the LGPL is written for, and it is what lets this
|
|
29
|
+
product remain under its own licence. It also means a user may replace either
|
|
30
|
+
library with a modified version of their own — reinstall the package, and the
|
|
31
|
+
driver picks it up — which is the freedom section 4 of the LGPL requires be
|
|
32
|
+
preserved. Do not vendor, inline, or bundle either one without taking legal
|
|
33
|
+
advice first; doing so is the change that would put this obligation somewhere
|
|
34
|
+
other than where it now sits.
|
|
35
|
+
|
|
36
|
+
We have not modified either library.
|
package/dist/cli-invocation.d.ts
CHANGED
|
@@ -1,48 +1,17 @@
|
|
|
1
|
-
|
|
2
|
-
* How the JS client hands a solve request to the bundled Python CLI.
|
|
3
|
-
*
|
|
4
|
-
* The API key used to travel as a POSITIONAL ARGUMENT, and the whole command
|
|
5
|
-
* line was then echoed:
|
|
6
|
-
*
|
|
7
|
-
* console.log(`Executing CaptchaKraken CLI: ${command}`);
|
|
8
|
-
* // Executing CaptchaKraken CLI: python -m captchakraken.cli "shot.png" \
|
|
9
|
-
* // captcha-v12 captchaKrakenApi b8978fa3392... --puzzle-source=hcaptcha
|
|
10
|
-
*
|
|
11
|
-
* Two leaks from one mistake. Argv is world-readable on Linux — any local user
|
|
12
|
-
* can read `/proc/<pid>/cmdline` while the solve runs, and `ps` shows it — and
|
|
13
|
-
* the key was additionally written to stdout, so it landed in CI logs, terminal
|
|
14
|
-
* scrollback, and anything scraping driver output.
|
|
15
|
-
*
|
|
16
|
-
* Secrets go through the environment instead, which is per-process and not
|
|
17
|
-
* world-readable, and the command is built as an ARGV ARRAY for `execFile`
|
|
18
|
-
* rather than a joined string for a shell, so a path with a space or a quote
|
|
19
|
-
* cannot reshape the command.
|
|
20
|
-
*/
|
|
21
|
-
/** Env var the CLI reads the bearer token from. */
|
|
1
|
+
import type { PromptFamily, RetryMode, Vendor } from './kinds.js';
|
|
22
2
|
export declare const API_KEY_ENV = "CAPTCHA_KRAKEN_API_KEY";
|
|
23
|
-
|
|
3
|
+
export declare const RESAMPLE_LEVEL_ENV = "CAPTCHA_RESAMPLE_LEVEL";
|
|
24
4
|
export declare const API_PROVIDER = "captchaKrakenApi";
|
|
25
5
|
export interface SolveInvocation {
|
|
26
6
|
imagePath: string;
|
|
27
|
-
model
|
|
28
|
-
puzzleSource:
|
|
29
|
-
retryMode?:
|
|
7
|
+
model?: string;
|
|
8
|
+
puzzleSource: Vendor;
|
|
9
|
+
retryMode?: RetryMode | null;
|
|
30
10
|
textMode?: boolean;
|
|
31
|
-
|
|
32
|
-
expert?: string | null;
|
|
11
|
+
expert?: PromptFamily | null;
|
|
33
12
|
}
|
|
34
|
-
/**
|
|
35
|
-
* The argv for one solve. No shell, no quoting, and NO CREDENTIAL — the key is
|
|
36
|
-
* supplied by `solveEnv` instead.
|
|
37
|
-
*/
|
|
13
|
+
/** An argv array for execFile, never a shell string. */
|
|
38
14
|
export declare function buildSolveArgs(invocation: SolveInvocation): string[];
|
|
39
|
-
/**
|
|
40
|
-
export declare function solveEnv(base: NodeJS.ProcessEnv, apiKey?: string): NodeJS.ProcessEnv;
|
|
41
|
-
/**
|
|
42
|
-
* A log line for a solve invocation, with any credential removed.
|
|
43
|
-
*
|
|
44
|
-
* Belt and braces: `buildSolveArgs` no longer carries the key, but this is the
|
|
45
|
-
* function that prints to stdout, so it redacts anything key-shaped regardless
|
|
46
|
-
* of how it got into the array.
|
|
47
|
-
*/
|
|
15
|
+
/** The resample LEVEL travels, not a temperature: the schedule lives once in planner.RESAMPLE_TEMPERATURES, and a fresh CLI process cannot know the round count. */
|
|
16
|
+
export declare function solveEnv(base: NodeJS.ProcessEnv, apiKey?: string, resampleLevel?: number): NodeJS.ProcessEnv;
|
|
48
17
|
export declare function redactCommand(command: string, apiKey?: string): string;
|
package/dist/cli-invocation.js
CHANGED
|
@@ -1,70 +1,37 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* How the JS client hands a solve request to the bundled Python CLI.
|
|
4
|
-
*
|
|
5
|
-
* The API key used to travel as a POSITIONAL ARGUMENT, and the whole command
|
|
6
|
-
* line was then echoed:
|
|
7
|
-
*
|
|
8
|
-
* console.log(`Executing CaptchaKraken CLI: ${command}`);
|
|
9
|
-
* // Executing CaptchaKraken CLI: python -m captchakraken.cli "shot.png" \
|
|
10
|
-
* // captcha-v12 captchaKrakenApi b8978fa3392... --puzzle-source=hcaptcha
|
|
11
|
-
*
|
|
12
|
-
* Two leaks from one mistake. Argv is world-readable on Linux — any local user
|
|
13
|
-
* can read `/proc/<pid>/cmdline` while the solve runs, and `ps` shows it — and
|
|
14
|
-
* the key was additionally written to stdout, so it landed in CI logs, terminal
|
|
15
|
-
* scrollback, and anything scraping driver output.
|
|
16
|
-
*
|
|
17
|
-
* Secrets go through the environment instead, which is per-process and not
|
|
18
|
-
* world-readable, and the command is built as an ARGV ARRAY for `execFile`
|
|
19
|
-
* rather than a joined string for a shell, so a path with a space or a quote
|
|
20
|
-
* cannot reshape the command.
|
|
21
|
-
*/
|
|
22
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
23
|
-
exports.API_PROVIDER = exports.API_KEY_ENV = void 0;
|
|
3
|
+
exports.API_PROVIDER = exports.RESAMPLE_LEVEL_ENV = exports.API_KEY_ENV = void 0;
|
|
24
4
|
exports.buildSolveArgs = buildSolveArgs;
|
|
25
5
|
exports.solveEnv = solveEnv;
|
|
26
6
|
exports.redactCommand = redactCommand;
|
|
27
|
-
|
|
7
|
+
// The key travels in env, never argv: argv is world-readable on Linux via /proc/<pid>/cmdline and `ps`. See TRIBAL_KNOWLEDGE.md.
|
|
28
8
|
exports.API_KEY_ENV = 'CAPTCHA_KRAKEN_API_KEY';
|
|
29
|
-
|
|
9
|
+
exports.RESAMPLE_LEVEL_ENV = 'CAPTCHA_RESAMPLE_LEVEL';
|
|
30
10
|
exports.API_PROVIDER = 'captchaKrakenApi';
|
|
31
|
-
/**
|
|
32
|
-
* The argv for one solve. No shell, no quoting, and NO CREDENTIAL — the key is
|
|
33
|
-
* supplied by `solveEnv` instead.
|
|
34
|
-
*/
|
|
11
|
+
/** An argv array for execFile, never a shell string. */
|
|
35
12
|
function buildSolveArgs(invocation) {
|
|
36
13
|
const { imagePath, model, puzzleSource, retryMode, textMode, expert } = invocation;
|
|
37
|
-
const args = [
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
exports.API_PROVIDER,
|
|
43
|
-
`--puzzle-source=${puzzleSource}`,
|
|
44
|
-
];
|
|
14
|
+
const args = ['-m', 'captchakraken.cli', imagePath];
|
|
15
|
+
// Both positionals or neither: the provider passed alone would bind to `model`.
|
|
16
|
+
if (model)
|
|
17
|
+
args.push(model, exports.API_PROVIDER);
|
|
18
|
+
args.push(`--puzzle-source=${puzzleSource}`);
|
|
45
19
|
if (retryMode)
|
|
46
20
|
args.push(`--retry-mode=${retryMode}`);
|
|
47
21
|
if (textMode)
|
|
48
22
|
args.push('--text-mode');
|
|
49
|
-
// Only when set. An absent flag is what lets the Python side route by prompt
|
|
50
|
-
// family, and passing `--expert=` would be an empty choice rather than none.
|
|
51
23
|
if (expert)
|
|
52
24
|
args.push(`--expert=${expert}`);
|
|
53
25
|
return args;
|
|
54
26
|
}
|
|
55
|
-
/**
|
|
56
|
-
function solveEnv(base, apiKey) {
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
27
|
+
/** The resample LEVEL travels, not a temperature: the schedule lives once in planner.RESAMPLE_TEMPERATURES, and a fresh CLI process cannot know the round count. */
|
|
28
|
+
function solveEnv(base, apiKey, resampleLevel) {
|
|
29
|
+
const out = apiKey ? { ...base, [exports.API_KEY_ENV]: apiKey } : { ...base };
|
|
30
|
+
if (resampleLevel && resampleLevel > 0) {
|
|
31
|
+
out[exports.RESAMPLE_LEVEL_ENV] = String(resampleLevel);
|
|
32
|
+
}
|
|
33
|
+
return out;
|
|
60
34
|
}
|
|
61
|
-
/**
|
|
62
|
-
* A log line for a solve invocation, with any credential removed.
|
|
63
|
-
*
|
|
64
|
-
* Belt and braces: `buildSolveArgs` no longer carries the key, but this is the
|
|
65
|
-
* function that prints to stdout, so it redacts anything key-shaped regardless
|
|
66
|
-
* of how it got into the array.
|
|
67
|
-
*/
|
|
68
35
|
function redactCommand(command, apiKey) {
|
|
69
36
|
if (!apiKey)
|
|
70
37
|
return command;
|
package/dist/errors.d.ts
CHANGED
|
@@ -1,28 +1,15 @@
|
|
|
1
|
+
import { ErrorCode } from './kinds.js';
|
|
2
|
+
/** Open on purpose: a code the server adds tomorrow must arrive intact, not be coerced to undefined. */
|
|
3
|
+
export type CaptchaKrakenErrorCode = ErrorCode | (string & {});
|
|
1
4
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
* The TypeScript driver does not talk to the model; it shells out to the Python
|
|
5
|
-
* CLI, which does. So every hosted-API error arrives here as text on stderr and
|
|
6
|
-
* would, without this, be flattened into
|
|
7
|
-
* `Failed to execute captcha solver CLI: Command failed with exit code 3` —
|
|
8
|
-
* a sentence that tells a camoufox user nothing about the fact that their
|
|
9
|
-
* account is out of credits.
|
|
10
|
-
*
|
|
11
|
-
* The CLI exits 3 and prints `{"error": "...", "ck_error": {...}}`, so the
|
|
12
|
-
* wording is decided once, in Python (`captchakraken/errors.py`), and merely
|
|
13
|
-
* relayed here. Deliberately NOT re-worded on this side: two copies of the same
|
|
14
|
-
* message drift, and the Python one is also what a direct CLI user sees.
|
|
5
|
+
* The Python port words every message once and this side repeats it verbatim: two copies of the same
|
|
6
|
+
* sentence drift. Before this class a customer out of credits read `vLLM 402 Payment Required at ...`.
|
|
15
7
|
*/
|
|
16
|
-
/** The machine-readable half. Mirrors the gateway's `GatewayErrorCode`. */
|
|
17
|
-
export type CaptchaKrakenErrorCode = 'missing_api_key' | 'invalid_api_key' | 'account_suspended' | 'insufficient_credits' | 'rate_limited' | 'solve_abandoned' | 'unrecognized_prompt' | 'invalid_request' | 'request_too_large' | 'upstream_unavailable' | 'model_not_licensed' | 'model_not_serving' | (string & {});
|
|
18
8
|
export declare class CaptchaKrakenAPIError extends Error {
|
|
19
9
|
readonly status: number | undefined;
|
|
20
10
|
readonly code: CaptchaKrakenErrorCode | undefined;
|
|
21
|
-
/** Where to send the user to fix it, when the server named somewhere. */
|
|
22
11
|
readonly resolutionUrl: string | undefined;
|
|
23
|
-
/** Seconds to wait, on `rate_limited`. */
|
|
24
12
|
readonly retryAfterSeconds: number | undefined;
|
|
25
|
-
/** Lets `catch` blocks branch without `instanceof` across module copies. */
|
|
26
13
|
readonly isCaptchaKrakenAPIError = true;
|
|
27
14
|
constructor(message: string, fields?: {
|
|
28
15
|
status?: number;
|
|
@@ -32,14 +19,7 @@ export declare class CaptchaKrakenAPIError extends Error {
|
|
|
32
19
|
});
|
|
33
20
|
}
|
|
34
21
|
/**
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
* Scans line by line rather than parsing the whole buffer: stderr also carries
|
|
38
|
-
* timing records and any warning the Python side emitted, so the JSON payload
|
|
39
|
-
* is one line among several and `JSON.parse(stderr)` would simply fail.
|
|
40
|
-
*
|
|
41
|
-
* Returns null for anything that is not recognisably ours, which leaves the
|
|
42
|
-
* caller's existing generic handling in place — an unparseable stderr must not
|
|
43
|
-
* become a confident but wrong billing message.
|
|
22
|
+
* Line by line, because stderr also carries timing records. Anything unrecognised is null, never a guess:
|
|
23
|
+
* an unparseable stderr must not become a confident but wrong billing message.
|
|
44
24
|
*/
|
|
45
25
|
export declare function parseApiError(stderr: string): CaptchaKrakenAPIError | null;
|
package/dist/errors.js
CHANGED
|
@@ -1,26 +1,14 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* Hosted-API refusals, carried across the Python subprocess boundary.
|
|
4
|
-
*
|
|
5
|
-
* The TypeScript driver does not talk to the model; it shells out to the Python
|
|
6
|
-
* CLI, which does. So every hosted-API error arrives here as text on stderr and
|
|
7
|
-
* would, without this, be flattened into
|
|
8
|
-
* `Failed to execute captcha solver CLI: Command failed with exit code 3` —
|
|
9
|
-
* a sentence that tells a camoufox user nothing about the fact that their
|
|
10
|
-
* account is out of credits.
|
|
11
|
-
*
|
|
12
|
-
* The CLI exits 3 and prints `{"error": "...", "ck_error": {...}}`, so the
|
|
13
|
-
* wording is decided once, in Python (`captchakraken/errors.py`), and merely
|
|
14
|
-
* relayed here. Deliberately NOT re-worded on this side: two copies of the same
|
|
15
|
-
* message drift, and the Python one is also what a direct CLI user sees.
|
|
16
|
-
*/
|
|
17
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
18
3
|
exports.CaptchaKrakenAPIError = void 0;
|
|
19
4
|
exports.parseApiError = parseApiError;
|
|
5
|
+
/**
|
|
6
|
+
* The Python port words every message once and this side repeats it verbatim: two copies of the same
|
|
7
|
+
* sentence drift. Before this class a customer out of credits read `vLLM 402 Payment Required at ...`.
|
|
8
|
+
*/
|
|
20
9
|
class CaptchaKrakenAPIError extends Error {
|
|
21
10
|
constructor(message, fields = {}) {
|
|
22
11
|
super(message);
|
|
23
|
-
/** Lets `catch` blocks branch without `instanceof` across module copies. */
|
|
24
12
|
this.isCaptchaKrakenAPIError = true;
|
|
25
13
|
this.name = 'CaptchaKrakenAPIError';
|
|
26
14
|
this.status = fields.status;
|
|
@@ -31,15 +19,8 @@ class CaptchaKrakenAPIError extends Error {
|
|
|
31
19
|
}
|
|
32
20
|
exports.CaptchaKrakenAPIError = CaptchaKrakenAPIError;
|
|
33
21
|
/**
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
* Scans line by line rather than parsing the whole buffer: stderr also carries
|
|
37
|
-
* timing records and any warning the Python side emitted, so the JSON payload
|
|
38
|
-
* is one line among several and `JSON.parse(stderr)` would simply fail.
|
|
39
|
-
*
|
|
40
|
-
* Returns null for anything that is not recognisably ours, which leaves the
|
|
41
|
-
* caller's existing generic handling in place — an unparseable stderr must not
|
|
42
|
-
* become a confident but wrong billing message.
|
|
22
|
+
* Line by line, because stderr also carries timing records. Anything unrecognised is null, never a guess:
|
|
23
|
+
* an unparseable stderr must not become a confident but wrong billing message.
|
|
43
24
|
*/
|
|
44
25
|
function parseApiError(stderr) {
|
|
45
26
|
if (!stderr || !stderr.includes('ck_error'))
|