captchakraken 2.9.0 → 3.1.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 +7 -36
- package/dist/cli-invocation.js +8 -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 +131 -708
- package/dist/solver.js +1319 -3382
- 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 -493
- package/dist/watcher.d.ts +5 -78
- package/dist/watcher.js +0 -56
- package/package.json +11 -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 -883
- 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 +46 -484
- package/python/src/captchakraken/kinds.py +152 -0
- package/python/src/captchakraken/models.json +36 -4
- package/python/src/captchakraken/overlay.py +65 -498
- package/python/src/captchakraken/page_solver.py +1282 -3101
- package/python/src/captchakraken/planner.py +65 -487
- 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,46 +1,17 @@
|
|
|
1
|
-
|
|
2
|
-
* How the JS client hands a solve request to the bundled Python CLI.
|
|
3
|
-
*
|
|
4
|
-
* Two rules govern this module, and both exist because the alternative is
|
|
5
|
-
* unsafe rather than merely untidy:
|
|
6
|
-
*
|
|
7
|
-
* 1. The API key travels in the ENVIRONMENT, never in argv and never to stdout.
|
|
8
|
-
* Argv is world-readable on Linux — any local user can read
|
|
9
|
-
* `/proc/<pid>/cmdline` while a solve runs, and `ps` shows it — and anything
|
|
10
|
-
* printed alongside the command lands in CI logs and terminal scrollback.
|
|
11
|
-
* An environment block is per-process and not world-readable.
|
|
12
|
-
*
|
|
13
|
-
* 2. The command is built as an ARGV ARRAY for `execFile`, not a joined string
|
|
14
|
-
* for a shell, so a screenshot path containing a space or a quote cannot
|
|
15
|
-
* reshape the command.
|
|
16
|
-
*/
|
|
17
|
-
/** Env var the CLI reads the bearer token from. */
|
|
1
|
+
import type { PromptFamily, RetryMode, Vendor } from './kinds.js';
|
|
18
2
|
export declare const API_KEY_ENV = "CAPTCHA_KRAKEN_API_KEY";
|
|
19
|
-
/** Env var carrying the re-ask level for a board the vendor already refused. */
|
|
20
3
|
export declare const RESAMPLE_LEVEL_ENV = "CAPTCHA_RESAMPLE_LEVEL";
|
|
21
|
-
/** Positional placeholder the CLI still accepts in this slot. */
|
|
22
4
|
export declare const API_PROVIDER = "captchaKrakenApi";
|
|
23
5
|
export interface SolveInvocation {
|
|
24
6
|
imagePath: string;
|
|
25
|
-
model
|
|
26
|
-
puzzleSource:
|
|
27
|
-
retryMode?:
|
|
7
|
+
model?: string;
|
|
8
|
+
puzzleSource: Vendor;
|
|
9
|
+
retryMode?: RetryMode | null;
|
|
28
10
|
textMode?: boolean;
|
|
29
|
-
|
|
30
|
-
expert?: string | null;
|
|
11
|
+
expert?: PromptFamily | null;
|
|
31
12
|
}
|
|
32
|
-
/**
|
|
33
|
-
* The argv for one solve. No shell, no quoting, and NO CREDENTIAL — the key is
|
|
34
|
-
* supplied by `solveEnv` instead.
|
|
35
|
-
*/
|
|
13
|
+
/** An argv array for execFile, never a shell string. */
|
|
36
14
|
export declare function buildSolveArgs(invocation: SolveInvocation): string[];
|
|
37
|
-
/**
|
|
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. */
|
|
38
16
|
export declare function solveEnv(base: NodeJS.ProcessEnv, apiKey?: string, resampleLevel?: number): NodeJS.ProcessEnv;
|
|
39
|
-
/**
|
|
40
|
-
* A log line for a solve invocation, with any credential removed.
|
|
41
|
-
*
|
|
42
|
-
* Belt and braces: `buildSolveArgs` no longer carries the key, but this is the
|
|
43
|
-
* function that prints to stdout, so it redacts anything key-shaped regardless
|
|
44
|
-
* of how it got into the array.
|
|
45
|
-
*/
|
|
46
17
|
export declare function redactCommand(command: string, apiKey?: string): string;
|
package/dist/cli-invocation.js
CHANGED
|
@@ -1,78 +1,37 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* How the JS client hands a solve request to the bundled Python CLI.
|
|
4
|
-
*
|
|
5
|
-
* Two rules govern this module, and both exist because the alternative is
|
|
6
|
-
* unsafe rather than merely untidy:
|
|
7
|
-
*
|
|
8
|
-
* 1. The API key travels in the ENVIRONMENT, never in argv and never to stdout.
|
|
9
|
-
* Argv is world-readable on Linux — any local user can read
|
|
10
|
-
* `/proc/<pid>/cmdline` while a solve runs, and `ps` shows it — and anything
|
|
11
|
-
* printed alongside the command lands in CI logs and terminal scrollback.
|
|
12
|
-
* An environment block is per-process and not world-readable.
|
|
13
|
-
*
|
|
14
|
-
* 2. The command is built as an ARGV ARRAY for `execFile`, not a joined string
|
|
15
|
-
* for a shell, so a screenshot path containing a space or a quote cannot
|
|
16
|
-
* reshape the command.
|
|
17
|
-
*/
|
|
18
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
19
3
|
exports.API_PROVIDER = exports.RESAMPLE_LEVEL_ENV = exports.API_KEY_ENV = void 0;
|
|
20
4
|
exports.buildSolveArgs = buildSolveArgs;
|
|
21
5
|
exports.solveEnv = solveEnv;
|
|
22
6
|
exports.redactCommand = redactCommand;
|
|
23
|
-
|
|
7
|
+
// The key travels in env, never argv: argv is world-readable on Linux via /proc/<pid>/cmdline and `ps`. See TRIBAL_KNOWLEDGE.md.
|
|
24
8
|
exports.API_KEY_ENV = 'CAPTCHA_KRAKEN_API_KEY';
|
|
25
|
-
/** Env var carrying the re-ask level for a board the vendor already refused. */
|
|
26
9
|
exports.RESAMPLE_LEVEL_ENV = 'CAPTCHA_RESAMPLE_LEVEL';
|
|
27
|
-
/** Positional placeholder the CLI still accepts in this slot. */
|
|
28
10
|
exports.API_PROVIDER = 'captchaKrakenApi';
|
|
29
|
-
/**
|
|
30
|
-
* The argv for one solve. No shell, no quoting, and NO CREDENTIAL — the key is
|
|
31
|
-
* supplied by `solveEnv` instead.
|
|
32
|
-
*/
|
|
11
|
+
/** An argv array for execFile, never a shell string. */
|
|
33
12
|
function buildSolveArgs(invocation) {
|
|
34
13
|
const { imagePath, model, puzzleSource, retryMode, textMode, expert } = invocation;
|
|
35
|
-
const args = [
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
exports.API_PROVIDER,
|
|
41
|
-
`--puzzle-source=${puzzleSource}`,
|
|
42
|
-
];
|
|
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}`);
|
|
43
19
|
if (retryMode)
|
|
44
20
|
args.push(`--retry-mode=${retryMode}`);
|
|
45
21
|
if (textMode)
|
|
46
22
|
args.push('--text-mode');
|
|
47
|
-
// Only when set. An absent flag is what lets the Python side route by prompt
|
|
48
|
-
// family, and passing `--expert=` would be an empty choice rather than none.
|
|
49
23
|
if (expert)
|
|
50
24
|
args.push(`--expert=${expert}`);
|
|
51
25
|
return args;
|
|
52
26
|
}
|
|
53
|
-
/**
|
|
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. */
|
|
54
28
|
function solveEnv(base, apiKey, resampleLevel) {
|
|
55
29
|
const out = apiKey ? { ...base, [exports.API_KEY_ENV]: apiKey } : { ...base };
|
|
56
|
-
// How many times THIS board has already been read and refused. The CLI is a
|
|
57
|
-
// fresh process per round, so it cannot know; and without it a re-ask is the
|
|
58
|
-
// same greedy arithmetic on the same pixels and returns the same answer,
|
|
59
|
-
// which is the whole of the "same answer 3 times running" failure.
|
|
60
|
-
//
|
|
61
|
-
// The LEVEL travels, not the temperature: the schedule lives once, in
|
|
62
|
-
// `planner.RESAMPLE_TEMPERATURES`, so the two ports cannot drift apart on a
|
|
63
|
-
// number Tier 3 would then average.
|
|
64
30
|
if (resampleLevel && resampleLevel > 0) {
|
|
65
31
|
out[exports.RESAMPLE_LEVEL_ENV] = String(resampleLevel);
|
|
66
32
|
}
|
|
67
33
|
return out;
|
|
68
34
|
}
|
|
69
|
-
/**
|
|
70
|
-
* A log line for a solve invocation, with any credential removed.
|
|
71
|
-
*
|
|
72
|
-
* Belt and braces: `buildSolveArgs` no longer carries the key, but this is the
|
|
73
|
-
* function that prints to stdout, so it redacts anything key-shaped regardless
|
|
74
|
-
* of how it got into the array.
|
|
75
|
-
*/
|
|
76
35
|
function redactCommand(command, apiKey) {
|
|
77
36
|
if (!apiKey)
|
|
78
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'))
|