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.
Files changed (77) hide show
  1. package/AGENTS.md +112 -0
  2. package/NOTICE +36 -0
  3. package/dist/cli-invocation.d.ts +9 -40
  4. package/dist/cli-invocation.js +16 -49
  5. package/dist/errors.d.ts +7 -27
  6. package/dist/errors.js +6 -25
  7. package/dist/humanize.d.ts +56 -240
  8. package/dist/humanize.js +159 -415
  9. package/dist/index.d.ts +5 -129
  10. package/dist/index.js +4 -98
  11. package/dist/kinds.d.ts +135 -0
  12. package/dist/kinds.js +70 -0
  13. package/dist/limits.d.ts +0 -48
  14. package/dist/limits.js +2 -48
  15. package/dist/model-name.d.ts +4 -19
  16. package/dist/model-name.js +32 -40
  17. package/dist/playwright-types.d.ts +25 -95
  18. package/dist/playwright-types.js +0 -23
  19. package/dist/puppeteer-adapter.d.ts +4 -43
  20. package/dist/puppeteer-adapter.js +22 -58
  21. package/dist/python-command.d.ts +0 -41
  22. package/dist/python-command.js +0 -37
  23. package/dist/selectors.d.ts +54 -0
  24. package/dist/selectors.js +117 -0
  25. package/dist/slide-geometry.d.ts +2 -29
  26. package/dist/slide-geometry.js +18 -44
  27. package/dist/solver.d.ts +112 -539
  28. package/dist/solver.js +1088 -2950
  29. package/dist/timing.d.ts +7 -40
  30. package/dist/timing.js +4 -36
  31. package/dist/token-usage.d.ts +1 -7
  32. package/dist/token-usage.js +10 -95
  33. package/dist/types.d.ts +77 -483
  34. package/dist/watcher.d.ts +5 -78
  35. package/dist/watcher.js +0 -56
  36. package/package.json +12 -4
  37. package/python/AGENTS.md +122 -0
  38. package/python/NOTICE +36 -0
  39. package/python/README.md +1 -2
  40. package/python/examples/README.md +10 -0
  41. package/python/examples/_harness.py +4 -73
  42. package/python/examples/demoHcaptcha.py +0 -13
  43. package/python/examples/demoRecaptcha.py +0 -10
  44. package/python/examples/watch_playwright.py +1 -26
  45. package/python/examples/with_local_gguf.py +28 -0
  46. package/python/examples/with_playwright.py +0 -19
  47. package/python/pyproject.toml +68 -19
  48. package/python/src/captchakraken/__init__.py +37 -45
  49. package/python/src/captchakraken/action_types.py +14 -36
  50. package/python/src/captchakraken/cli.py +262 -879
  51. package/python/src/captchakraken/config.py +60 -146
  52. package/python/src/captchakraken/errors.py +17 -95
  53. package/python/src/captchakraken/humanize.py +174 -597
  54. package/python/src/captchakraken/image_processor.py +16 -235
  55. package/python/src/captchakraken/keyframes.py +69 -434
  56. package/python/src/captchakraken/kinds.py +152 -0
  57. package/python/src/captchakraken/models.json +79 -21
  58. package/python/src/captchakraken/overlay.py +65 -498
  59. package/python/src/captchakraken/page_solver.py +1123 -2564
  60. package/python/src/captchakraken/planner.py +70 -428
  61. package/python/src/captchakraken/prompts.py +45 -261
  62. package/python/src/captchakraken/selectors.py +184 -0
  63. package/python/src/captchakraken/server_manager.py +7 -58
  64. package/python/src/captchakraken/solver.py +128 -522
  65. package/python/src/captchakraken/timing.py +20 -74
  66. package/python/src/captchakraken/tool_calls/board_painted.py +47 -0
  67. package/python/src/captchakraken/tool_calls/find_checkbox.py +20 -30
  68. package/python/src/captchakraken/tool_calls/find_grid.py +186 -1339
  69. package/python/src/captchakraken/tool_calls/track_piece.py +81 -57
  70. package/python/src/captchakraken/updater.py +7 -76
  71. package/python/src/captchakraken/watcher.py +12 -101
  72. package/scripts/copy-python.mjs +10 -10
  73. package/scripts/setup-python.js +1 -21
  74. package/dist/trajectory.d.ts +0 -58
  75. package/dist/trajectory.js +0 -266
  76. package/python/src/captchakraken/tool_calls/move_indicator.py +0 -431
  77. package/python/src/captchakraken/trajectory.py +0 -284
package/dist/index.d.ts CHANGED
@@ -1,139 +1,15 @@
1
1
  export * from './types';
2
+ export * from './kinds';
2
3
  export { CaptchaKrakenSolver } from './solver';
3
- /**
4
- * The served LoRA name this client will ask for when `model` is left unset —
5
- * `CAPTCHA_LORA_NAME`, else `models.json`'s `latest`, else the shipped pin.
6
- *
7
- * Exported so anything that REPORTS which adapter was driven can ask the client
8
- * instead of re-deriving the answer. That distinction is not cosmetic: the name
9
- * selects the prompt generation, so a reporter that guesses it can disagree with
10
- * the solver and describe a run that never happened.
11
- */
4
+ export type { Widget } from './solver';
12
5
  export { resolveLoraName } from './model-name';
13
- /**
14
- * Errors raised when the **hosted** CaptchaKraken API refuses a solve — out of
15
- * credits, rate limited, key rejected, attempt abandoned.
16
- *
17
- * `message` is already a complete sentence naming the product and, where one
18
- * exists, the URL that fixes it, so printing it is enough. `code` is the stable
19
- * contract to branch on; the prose is not.
20
- *
21
- * @example
22
- * ```typescript
23
- * import { CaptchaKrakenSolver, CaptchaKrakenAPIError } from 'captchakraken';
24
- *
25
- * try {
26
- * await solver.solve(page);
27
- * } catch (e) {
28
- * if (e instanceof CaptchaKrakenAPIError && e.code === 'insufficient_credits') {
29
- * console.error(`Top up: ${e.resolutionUrl}`);
30
- * } else throw e;
31
- * }
32
- * ```
33
- */
34
6
  export { CaptchaKrakenAPIError } from './errors';
35
7
  export type { CaptchaKrakenErrorCode } from './errors';
36
- /**
37
- * Adapter for driving the solver with **Puppeteer** instead of a Playwright
38
- * launcher. Puppeteer's `Page` is API-compatible with Playwright's except for a
39
- * few method names/options; `fromPuppeteer(page)` wraps it so `solve()` accepts
40
- * it. Playwright-family launchers (vanilla `playwright`, `patchright`,
41
- * `camoufox-js`) need no adapter — pass their `Page` directly.
42
- *
43
- * @example
44
- * ```typescript
45
- * import puppeteer from 'puppeteer';
46
- * import { CaptchaKrakenSolver, fromPuppeteer } from 'captchakraken';
47
- *
48
- * const browser = await puppeteer.launch({ headless: false });
49
- * const page = await browser.newPage();
50
- * await page.goto('https://www.google.com/recaptcha/api2/demo');
51
- *
52
- * const solver = new CaptchaKrakenSolver();
53
- * await solver.solve(fromPuppeteer(page));
54
- * await browser.close();
55
- * ```
56
- */
57
8
  export { fromPuppeteer } from './puppeteer-adapter';
58
- /**
59
- * The Playwright `Page` type the solver operates on.
60
- *
61
- * This is an implementation-neutral, structurally-typed Playwright `Page` — a
62
- * duck-typed surface defined by this package, NOT imported from any browser
63
- * library. The package depends on no concrete browser implementation, so you
64
- * can drive the solver with ANY Playwright-compatible launcher: vanilla
65
- * `playwright`, `patchright`, `camoufox-js`, or anything else that hands back a
66
- * standard Playwright `Page`. They all structurally satisfy this type — pass
67
- * yours directly, no cast needed.
68
- *
69
- * @example
70
- * ```typescript
71
- * // Pick whichever Playwright-compatible launcher you want — install it
72
- * // yourself; this package does not bundle a browser:
73
- * import { chromium } from 'playwright'; // vanilla
74
- * // import { chromium } from 'patchright'; // stealth-patched
75
- * // import { Camoufox } from 'camoufox-js'; // Firefox stealth
76
- * import { CaptchaKrakenSolver } from 'captchakraken';
77
- *
78
- * const browser = await chromium.launch({ headless: false });
79
- * const page = await (await browser.newContext()).newPage();
80
- * await page.goto('https://www.google.com/recaptcha/api2/demo');
81
- *
82
- * // Reads VLLM_BASE_URL + CAPTCHA_KRAKEN_API_KEY from the environment.
83
- * const solver = new CaptchaKrakenSolver();
84
- * await solver.solve(page); // detect → solve grid → click → verify
85
- *
86
- * await browser.close();
87
- * ```
88
- */
89
- export type { Page, PlaywrightPage, PlaywrightFrame, PlaywrightElementHandle } from './playwright-types';
90
- /**
91
- * Auto-solve watcher: `solver.watch(page)` installs a background poller that
92
- * solves captchas as they appear, and returns a handle with `stop()`.
93
- *
94
- * Injects nothing into the page, on any platform — see watcher.ts. On Camoufox
95
- * its DOM reads run in the isolated Juggler world by default.
96
- *
97
- * @example
98
- * ```typescript
99
- * const solver = new CaptchaKrakenSolver();
100
- * const watcher = solver.watch(page, { onSolved: r => console.log(r.isSolved) });
101
- * // ... your automation ...
102
- * await watcher.stop();
103
- * ```
104
- */
9
+ export type { Page, PlaywrightPage, PlaywrightFrame, PlaywrightElementHandle, PlaywrightLocator, PlaywrightScope } from './playwright-types';
10
+ export { SELECTORS } from './selectors';
11
+ export type { VendorSelectors } from './selectors';
105
12
  export { watchPage } from './watcher';
106
13
  export type { CaptchaWatcher, WatchOptions, WatchableSolver } from './watcher';
107
- /**
108
- * Humanisation: how the driver moves. `humanization: 'mouse' | 'mobile' |
109
- * 'none'` picks a built-in; `humanizer` takes one of your own.
110
- *
111
- * `MobileHumanizer` emits real touch events with finger kinematics, through a
112
- * `TouchBackend` — CDP against a Chromium-family page, or W3C pointer actions
113
- * against an Appium / WebdriverIO driver on a real handset.
114
- *
115
- * @example Mobile emulation in the browser
116
- * ```typescript
117
- * import { chromium, devices } from 'playwright';
118
- * import { CaptchaKrakenSolver } from 'captchakraken';
119
- *
120
- * const browser = await chromium.launch();
121
- * const context = await browser.newContext({ ...devices['Pixel 7'], hasTouch: true });
122
- * const page = await context.newPage();
123
- * await page.goto('https://example.com/signup');
124
- *
125
- * await new CaptchaKrakenSolver({ humanization: 'mobile' }).solve(page);
126
- * ```
127
- *
128
- * @example A real device over Appium
129
- * ```typescript
130
- * const solver = new CaptchaKrakenSolver({
131
- * humanization: 'mobile',
132
- * touchDriver: driver, // the WebdriverIO browser
133
- * touchTransform: { scale: 3, origin: [0, 132] }, // CSS px -> screen px
134
- * });
135
- * await solver.solve(page);
136
- * ```
137
- */
138
14
  export { MouseHumanizer, MobileHumanizer, NullHumanizer, BaseHumanizer, resolveHumanizer, touchBackendFor, CdpTouchBackend, AppiumTouchBackend, TouchscreenTouchBackend, PAUSE_KINDS, MODES as HUMANIZATION_MODES, } from './humanize';
139
15
  export type { Humanizer, HumanizationMode, HumanizerOptions, TouchBackend, TouchSample, TouchTransform, PauseKind, } from './humanize';
package/dist/index.js CHANGED
@@ -14,115 +14,21 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
14
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
- exports.HUMANIZATION_MODES = exports.PAUSE_KINDS = exports.TouchscreenTouchBackend = exports.AppiumTouchBackend = exports.CdpTouchBackend = exports.touchBackendFor = exports.resolveHumanizer = exports.BaseHumanizer = exports.NullHumanizer = exports.MobileHumanizer = exports.MouseHumanizer = exports.watchPage = exports.fromPuppeteer = exports.CaptchaKrakenAPIError = exports.resolveLoraName = exports.CaptchaKrakenSolver = void 0;
17
+ exports.HUMANIZATION_MODES = exports.PAUSE_KINDS = exports.TouchscreenTouchBackend = exports.AppiumTouchBackend = exports.CdpTouchBackend = exports.touchBackendFor = exports.resolveHumanizer = exports.BaseHumanizer = exports.NullHumanizer = exports.MobileHumanizer = exports.MouseHumanizer = exports.watchPage = exports.SELECTORS = exports.fromPuppeteer = exports.CaptchaKrakenAPIError = exports.resolveLoraName = exports.CaptchaKrakenSolver = void 0;
18
18
  __exportStar(require("./types"), exports);
19
+ __exportStar(require("./kinds"), exports);
19
20
  var solver_1 = require("./solver");
20
21
  Object.defineProperty(exports, "CaptchaKrakenSolver", { enumerable: true, get: function () { return solver_1.CaptchaKrakenSolver; } });
21
- /**
22
- * The served LoRA name this client will ask for when `model` is left unset —
23
- * `CAPTCHA_LORA_NAME`, else `models.json`'s `latest`, else the shipped pin.
24
- *
25
- * Exported so anything that REPORTS which adapter was driven can ask the client
26
- * instead of re-deriving the answer. That distinction is not cosmetic: the name
27
- * selects the prompt generation, so a reporter that guesses it can disagree with
28
- * the solver and describe a run that never happened.
29
- */
30
22
  var model_name_1 = require("./model-name");
31
23
  Object.defineProperty(exports, "resolveLoraName", { enumerable: true, get: function () { return model_name_1.resolveLoraName; } });
32
- /**
33
- * Errors raised when the **hosted** CaptchaKraken API refuses a solve — out of
34
- * credits, rate limited, key rejected, attempt abandoned.
35
- *
36
- * `message` is already a complete sentence naming the product and, where one
37
- * exists, the URL that fixes it, so printing it is enough. `code` is the stable
38
- * contract to branch on; the prose is not.
39
- *
40
- * @example
41
- * ```typescript
42
- * import { CaptchaKrakenSolver, CaptchaKrakenAPIError } from 'captchakraken';
43
- *
44
- * try {
45
- * await solver.solve(page);
46
- * } catch (e) {
47
- * if (e instanceof CaptchaKrakenAPIError && e.code === 'insufficient_credits') {
48
- * console.error(`Top up: ${e.resolutionUrl}`);
49
- * } else throw e;
50
- * }
51
- * ```
52
- */
53
24
  var errors_1 = require("./errors");
54
25
  Object.defineProperty(exports, "CaptchaKrakenAPIError", { enumerable: true, get: function () { return errors_1.CaptchaKrakenAPIError; } });
55
- /**
56
- * Adapter for driving the solver with **Puppeteer** instead of a Playwright
57
- * launcher. Puppeteer's `Page` is API-compatible with Playwright's except for a
58
- * few method names/options; `fromPuppeteer(page)` wraps it so `solve()` accepts
59
- * it. Playwright-family launchers (vanilla `playwright`, `patchright`,
60
- * `camoufox-js`) need no adapter — pass their `Page` directly.
61
- *
62
- * @example
63
- * ```typescript
64
- * import puppeteer from 'puppeteer';
65
- * import { CaptchaKrakenSolver, fromPuppeteer } from 'captchakraken';
66
- *
67
- * const browser = await puppeteer.launch({ headless: false });
68
- * const page = await browser.newPage();
69
- * await page.goto('https://www.google.com/recaptcha/api2/demo');
70
- *
71
- * const solver = new CaptchaKrakenSolver();
72
- * await solver.solve(fromPuppeteer(page));
73
- * await browser.close();
74
- * ```
75
- */
76
26
  var puppeteer_adapter_1 = require("./puppeteer-adapter");
77
27
  Object.defineProperty(exports, "fromPuppeteer", { enumerable: true, get: function () { return puppeteer_adapter_1.fromPuppeteer; } });
78
- /**
79
- * Auto-solve watcher: `solver.watch(page)` installs a background poller that
80
- * solves captchas as they appear, and returns a handle with `stop()`.
81
- *
82
- * Injects nothing into the page, on any platform — see watcher.ts. On Camoufox
83
- * its DOM reads run in the isolated Juggler world by default.
84
- *
85
- * @example
86
- * ```typescript
87
- * const solver = new CaptchaKrakenSolver();
88
- * const watcher = solver.watch(page, { onSolved: r => console.log(r.isSolved) });
89
- * // ... your automation ...
90
- * await watcher.stop();
91
- * ```
92
- */
28
+ var selectors_1 = require("./selectors");
29
+ Object.defineProperty(exports, "SELECTORS", { enumerable: true, get: function () { return selectors_1.SELECTORS; } });
93
30
  var watcher_1 = require("./watcher");
94
31
  Object.defineProperty(exports, "watchPage", { enumerable: true, get: function () { return watcher_1.watchPage; } });
95
- /**
96
- * Humanisation: how the driver moves. `humanization: 'mouse' | 'mobile' |
97
- * 'none'` picks a built-in; `humanizer` takes one of your own.
98
- *
99
- * `MobileHumanizer` emits real touch events with finger kinematics, through a
100
- * `TouchBackend` — CDP against a Chromium-family page, or W3C pointer actions
101
- * against an Appium / WebdriverIO driver on a real handset.
102
- *
103
- * @example Mobile emulation in the browser
104
- * ```typescript
105
- * import { chromium, devices } from 'playwright';
106
- * import { CaptchaKrakenSolver } from 'captchakraken';
107
- *
108
- * const browser = await chromium.launch();
109
- * const context = await browser.newContext({ ...devices['Pixel 7'], hasTouch: true });
110
- * const page = await context.newPage();
111
- * await page.goto('https://example.com/signup');
112
- *
113
- * await new CaptchaKrakenSolver({ humanization: 'mobile' }).solve(page);
114
- * ```
115
- *
116
- * @example A real device over Appium
117
- * ```typescript
118
- * const solver = new CaptchaKrakenSolver({
119
- * humanization: 'mobile',
120
- * touchDriver: driver, // the WebdriverIO browser
121
- * touchTransform: { scale: 3, origin: [0, 132] }, // CSS px -> screen px
122
- * });
123
- * await solver.solve(page);
124
- * ```
125
- */
126
32
  var humanize_1 = require("./humanize");
127
33
  Object.defineProperty(exports, "MouseHumanizer", { enumerable: true, get: function () { return humanize_1.MouseHumanizer; } });
128
34
  Object.defineProperty(exports, "MobileHumanizer", { enumerable: true, get: function () { return humanize_1.MobileHumanizer; } });
@@ -0,0 +1,135 @@
1
+ /**
2
+ * Every closed set of names the two ports agree on. Mirrored in python/src/captchakraken/kinds.py; keep both in the same order.
3
+ * `as const` objects rather than `enum`: a literal off the wire (`'click'`) type-checks against them, an `enum` would not.
4
+ */
5
+ /** `puzzleSource` everywhere. UNKNOWN must stay permissive: GeeTest and Prosopo report it, and so does the offline grader. */
6
+ export declare const Vendor: {
7
+ readonly HCAPTCHA: "hcaptcha";
8
+ readonly RECAPTCHA: "recaptcha";
9
+ readonly TURNSTILE: "turnstile";
10
+ readonly GEETEST: "geetest";
11
+ readonly TENCENT: "tencent";
12
+ readonly YIDUN: "yidun";
13
+ readonly YANDEX: "yandex";
14
+ readonly LEMIN: "lemin";
15
+ readonly PROSOPO: "prosopo";
16
+ readonly MTCAPTCHA: "mtcaptcha";
17
+ readonly BOTDETECT: "botdetect";
18
+ readonly UNKNOWN: "unknown";
19
+ };
20
+ export type Vendor = (typeof Vendor)[keyof typeof Vendor];
21
+ export declare const ActionKind: {
22
+ readonly CLICK: "click";
23
+ readonly DRAG: "drag";
24
+ readonly TYPE: "type";
25
+ readonly WAIT: "wait";
26
+ readonly DONE: "done";
27
+ };
28
+ export type ActionKind = (typeof ActionKind)[keyof typeof ActionKind];
29
+ export declare const RetryMode: {
30
+ readonly MISSED_TILES: "missed-tiles";
31
+ };
32
+ export type RetryMode = (typeof RetryMode)[keyof typeof RetryMode];
33
+ export declare const SettleVerdict: {
34
+ readonly SETTLED: "settled";
35
+ readonly ANIMATED: "animated";
36
+ readonly TIMEOUT: "timeout";
37
+ };
38
+ export type SettleVerdict = (typeof SettleVerdict)[keyof typeof SettleVerdict];
39
+ export declare const PaintVerdict: {
40
+ readonly PAINTED: "painted";
41
+ readonly BLANK: "blank";
42
+ readonly UNKNOWN: "unknown";
43
+ };
44
+ export type PaintVerdict = (typeof PaintVerdict)[keyof typeof PaintVerdict];
45
+ /** EVEN means the slicer could not prove recurrence, not that the board is still. */
46
+ export declare const KeyframeMode: {
47
+ readonly STATIC: "static";
48
+ readonly CYCLE: "cycle";
49
+ readonly EVEN: "even";
50
+ };
51
+ export type KeyframeMode = (typeof KeyframeMode)[keyof typeof KeyframeMode];
52
+ export declare const RecaptchaBanner: {
53
+ readonly SELECT_MORE: "select-more";
54
+ readonly DYNAMIC_MORE: "dynamic-more";
55
+ readonly REJECTED: "rejected";
56
+ };
57
+ export type RecaptchaBanner = (typeof RecaptchaBanner)[keyof typeof RecaptchaBanner];
58
+ /** One expert per family; `pixel` is spelled to match ckgate's prompt markers. */
59
+ export declare const PromptFamily: {
60
+ readonly PIXEL: "pixel";
61
+ readonly GRID: "grid";
62
+ readonly VIDEO: "video";
63
+ readonly TEXT: "text";
64
+ };
65
+ export type PromptFamily = (typeof PromptFamily)[keyof typeof PromptFamily];
66
+ export declare const HumanizationMode: {
67
+ readonly MOUSE: "mouse";
68
+ readonly MOBILE: "mobile";
69
+ readonly NONE: "none";
70
+ };
71
+ export type HumanizationMode = (typeof HumanizationMode)[keyof typeof HumanizationMode];
72
+ export declare const PauseKind: {
73
+ readonly TAP: "tap";
74
+ readonly BETWEEN: "between";
75
+ readonly GRAB: "grab";
76
+ readonly DROP: "drop";
77
+ readonly PROBE: "probe";
78
+ readonly SETTLE: "settle";
79
+ readonly KEY: "key";
80
+ };
81
+ export type PauseKind = (typeof PauseKind)[keyof typeof PauseKind];
82
+ export declare const Outcome: {
83
+ readonly SOLVED: "solved";
84
+ readonly FAILED: "failed";
85
+ };
86
+ export type Outcome = (typeof Outcome)[keyof typeof Outcome];
87
+ /** Timing phases. Only INFERENCE and MOUSE are productive; everything else is waiting. */
88
+ export declare const Phase: {
89
+ readonly INFERENCE: "inference";
90
+ readonly MOUSE: "mouse";
91
+ readonly SCREENSHOT: "screenshot";
92
+ readonly DETECT: "detect";
93
+ readonly SETTLE: "settle";
94
+ readonly BURST: "burst";
95
+ readonly GRID: "grid";
96
+ readonly GRID_LOAD: "grid-load";
97
+ readonly FADE_WAIT: "fade-wait";
98
+ readonly BOARD_PAINT: "board-paint";
99
+ readonly HCAPTCHA_IMAGES: "hcaptcha-images";
100
+ readonly AWAIT_NEXT_ROUND: "await-next-round";
101
+ readonly AWAIT_VERDICT: "await-verdict";
102
+ readonly POST_SUBMIT_DELAY: "post-submit-delay";
103
+ };
104
+ export type Phase = (typeof Phase)[keyof typeof Phase];
105
+ export declare const SolveStage: {
106
+ readonly INITIAL: "initial";
107
+ readonly CLICK: "click";
108
+ readonly DRAG: "drag";
109
+ readonly TYPE: "type";
110
+ readonly WAIT: "wait";
111
+ readonly SUBMIT: "submit";
112
+ readonly ROUND: "round";
113
+ };
114
+ export type SolveStage = (typeof SolveStage)[keyof typeof SolveStage];
115
+ export declare const FrameRole: {
116
+ readonly CHECKBOX: "checkbox";
117
+ readonly CHALLENGE: "challenge";
118
+ readonly UNKNOWN: "unknown";
119
+ };
120
+ export type FrameRole = (typeof FrameRole)[keyof typeof FrameRole];
121
+ /** The hosted API's machine-readable codes. Unknown codes still carry the server's message through; this is not a filter. */
122
+ export declare const ErrorCode: {
123
+ readonly MISSING_API_KEY: "missing_api_key";
124
+ readonly INVALID_API_KEY: "invalid_api_key";
125
+ readonly ACCOUNT_SUSPENDED: "account_suspended";
126
+ readonly INSUFFICIENT_CREDITS: "insufficient_credits";
127
+ readonly RATE_LIMITED: "rate_limited";
128
+ readonly SOLVE_ABANDONED: "solve_abandoned";
129
+ readonly UNRECOGNIZED_PROMPT: "unrecognized_prompt";
130
+ readonly INVALID_REQUEST: "invalid_request";
131
+ readonly REQUEST_TOO_LARGE: "request_too_large";
132
+ readonly UPSTREAM_UNAVAILABLE: "upstream_unavailable";
133
+ };
134
+ export type ErrorCode = (typeof ErrorCode)[keyof typeof ErrorCode];
135
+ export declare function isOneOf<T extends Record<string, string>>(set: T, value: unknown): value is T[keyof T];
package/dist/kinds.js ADDED
@@ -0,0 +1,70 @@
1
+ "use strict";
2
+ /**
3
+ * Every closed set of names the two ports agree on. Mirrored in python/src/captchakraken/kinds.py; keep both in the same order.
4
+ * `as const` objects rather than `enum`: a literal off the wire (`'click'`) type-checks against them, an `enum` would not.
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.ErrorCode = exports.FrameRole = exports.SolveStage = exports.Phase = exports.Outcome = exports.PauseKind = exports.HumanizationMode = exports.PromptFamily = exports.RecaptchaBanner = exports.KeyframeMode = exports.PaintVerdict = exports.SettleVerdict = exports.RetryMode = exports.ActionKind = exports.Vendor = void 0;
8
+ exports.isOneOf = isOneOf;
9
+ /** `puzzleSource` everywhere. UNKNOWN must stay permissive: GeeTest and Prosopo report it, and so does the offline grader. */
10
+ exports.Vendor = {
11
+ HCAPTCHA: 'hcaptcha',
12
+ RECAPTCHA: 'recaptcha',
13
+ TURNSTILE: 'turnstile',
14
+ GEETEST: 'geetest',
15
+ TENCENT: 'tencent',
16
+ YIDUN: 'yidun',
17
+ YANDEX: 'yandex',
18
+ LEMIN: 'lemin',
19
+ PROSOPO: 'prosopo',
20
+ MTCAPTCHA: 'mtcaptcha',
21
+ BOTDETECT: 'botdetect',
22
+ UNKNOWN: 'unknown',
23
+ };
24
+ exports.ActionKind = { CLICK: 'click', DRAG: 'drag', TYPE: 'type', WAIT: 'wait', DONE: 'done' };
25
+ exports.RetryMode = { MISSED_TILES: 'missed-tiles' };
26
+ exports.SettleVerdict = { SETTLED: 'settled', ANIMATED: 'animated', TIMEOUT: 'timeout' };
27
+ exports.PaintVerdict = { PAINTED: 'painted', BLANK: 'blank', UNKNOWN: 'unknown' };
28
+ /** EVEN means the slicer could not prove recurrence, not that the board is still. */
29
+ exports.KeyframeMode = { STATIC: 'static', CYCLE: 'cycle', EVEN: 'even' };
30
+ exports.RecaptchaBanner = { SELECT_MORE: 'select-more', DYNAMIC_MORE: 'dynamic-more', REJECTED: 'rejected' };
31
+ /** One expert per family; `pixel` is spelled to match ckgate's prompt markers. */
32
+ exports.PromptFamily = { PIXEL: 'pixel', GRID: 'grid', VIDEO: 'video', TEXT: 'text' };
33
+ exports.HumanizationMode = { MOUSE: 'mouse', MOBILE: 'mobile', NONE: 'none' };
34
+ exports.PauseKind = { TAP: 'tap', BETWEEN: 'between', GRAB: 'grab', DROP: 'drop', PROBE: 'probe', SETTLE: 'settle', KEY: 'key' };
35
+ exports.Outcome = { SOLVED: 'solved', FAILED: 'failed' };
36
+ /** Timing phases. Only INFERENCE and MOUSE are productive; everything else is waiting. */
37
+ exports.Phase = {
38
+ INFERENCE: 'inference',
39
+ MOUSE: 'mouse',
40
+ SCREENSHOT: 'screenshot',
41
+ DETECT: 'detect',
42
+ SETTLE: 'settle',
43
+ BURST: 'burst',
44
+ GRID: 'grid',
45
+ GRID_LOAD: 'grid-load',
46
+ FADE_WAIT: 'fade-wait',
47
+ BOARD_PAINT: 'board-paint',
48
+ HCAPTCHA_IMAGES: 'hcaptcha-images',
49
+ AWAIT_NEXT_ROUND: 'await-next-round',
50
+ AWAIT_VERDICT: 'await-verdict',
51
+ POST_SUBMIT_DELAY: 'post-submit-delay',
52
+ };
53
+ exports.SolveStage = { INITIAL: 'initial', CLICK: 'click', DRAG: 'drag', TYPE: 'type', WAIT: 'wait', SUBMIT: 'submit', ROUND: 'round' };
54
+ exports.FrameRole = { CHECKBOX: 'checkbox', CHALLENGE: 'challenge', UNKNOWN: 'unknown' };
55
+ /** The hosted API's machine-readable codes. Unknown codes still carry the server's message through; this is not a filter. */
56
+ exports.ErrorCode = {
57
+ MISSING_API_KEY: 'missing_api_key',
58
+ INVALID_API_KEY: 'invalid_api_key',
59
+ ACCOUNT_SUSPENDED: 'account_suspended',
60
+ INSUFFICIENT_CREDITS: 'insufficient_credits',
61
+ RATE_LIMITED: 'rate_limited',
62
+ SOLVE_ABANDONED: 'solve_abandoned',
63
+ UNRECOGNIZED_PROMPT: 'unrecognized_prompt',
64
+ INVALID_REQUEST: 'invalid_request',
65
+ REQUEST_TOO_LARGE: 'request_too_large',
66
+ UPSTREAM_UNAVAILABLE: 'upstream_unavailable',
67
+ };
68
+ function isOneOf(set, value) {
69
+ return typeof value === 'string' && Object.values(set).includes(value);
70
+ }
package/dist/limits.d.ts CHANGED
@@ -1,51 +1,3 @@
1
- /**
2
- * Numbers that must agree with the hosted gateway, stated once.
3
- *
4
- * These are not arbitrary defaults. They sit inside an ordering the server
5
- * enforces, and the ordering — not any individual value — is the property worth
6
- * protecting. `limits.test.ts` pins it.
7
- */
8
- /**
9
- * The server bills at most this many responses per captcha attempt.
10
- *
11
- * Mirrors `MAX_BILLABLE_ROUNDS_PER_SESSION` in captchakraken-gateway's
12
- * `src/pricing.ts`. Declared here so the ordering below can be asserted; the
13
- * gateway is what actually enforces it.
14
- */
15
1
  export declare const SERVER_MAX_BILLABLE_ROUNDS = 5;
16
- /**
17
- * The server answers at most this many responses per attempt, then refuses the
18
- * eleventh with 409 `solve_abandoned`.
19
- *
20
- * Mirrors `MAX_ROUNDS_PER_SESSION` in the gateway.
21
- */
22
2
  export declare const SERVER_MAX_SERVED_ROUNDS = 10;
23
- /**
24
- * How many click → refresh → re-solve rounds the client will attempt on one
25
- * reCAPTCHA 3x3 dynamic puzzle.
26
- *
27
- * ── WHY 8, AND WHY IT MUST STAY STRICTLY BETWEEN 5 AND 10 ───────────────────
28
- *
29
- * The three numbers describe one attempt in three stages:
30
- *
31
- * rounds 1–5 billed
32
- * rounds 6–10 served, and comped
33
- * round 11 refused — 409, the attempt is over
34
- *
35
- * 8 sits strictly inside that, with room on both sides, and both margins do a
36
- * job:
37
- *
38
- * Above 5 — rounds 6, 7 and 8 are free. A puzzle that needs a couple of extra
39
- * passes still gets them, and the customer is not charged for our model
40
- * needing another look. Dropping to 5 would abandon winnable puzzles at
41
- * exactly the point where continuing costs the customer nothing.
42
- *
43
- * Below 10 — a well-behaved client gives up BEFORE the server refuses it.
44
- * Raising this to 10 or beyond means the normal end of a hard puzzle is a
45
- * 409 rather than a clean local stop, which turns an ordinary outcome into an
46
- * error the caller has to interpret.
47
- *
48
- * So: if the billable cap moves, re-derive this and move the test in the same
49
- * commit. Changing one number alone silently breaks one of the two margins.
50
- */
51
3
  export declare const DEFAULT_RECAPTCHA_MAX_DYNAMIC_ROUNDS = 8;
package/dist/limits.js CHANGED
@@ -1,54 +1,8 @@
1
1
  "use strict";
2
- /**
3
- * Numbers that must agree with the hosted gateway, stated once.
4
- *
5
- * These are not arbitrary defaults. They sit inside an ordering the server
6
- * enforces, and the ordering — not any individual value — is the property worth
7
- * protecting. `limits.test.ts` pins it.
8
- */
9
2
  Object.defineProperty(exports, "__esModule", { value: true });
10
3
  exports.DEFAULT_RECAPTCHA_MAX_DYNAMIC_ROUNDS = exports.SERVER_MAX_SERVED_ROUNDS = exports.SERVER_MAX_BILLABLE_ROUNDS = void 0;
11
- /**
12
- * The server bills at most this many responses per captcha attempt.
13
- *
14
- * Mirrors `MAX_BILLABLE_ROUNDS_PER_SESSION` in captchakraken-gateway's
15
- * `src/pricing.ts`. Declared here so the ordering below can be asserted; the
16
- * gateway is what actually enforces it.
17
- */
4
+ // The gateway's three tiers: rounds 1-5 are billed, 6-10 are served and comped, and the 11th is refused with 409.
18
5
  exports.SERVER_MAX_BILLABLE_ROUNDS = 5;
19
- /**
20
- * The server answers at most this many responses per attempt, then refuses the
21
- * eleventh with 409 `solve_abandoned`.
22
- *
23
- * Mirrors `MAX_ROUNDS_PER_SESSION` in the gateway.
24
- */
25
6
  exports.SERVER_MAX_SERVED_ROUNDS = 10;
26
- /**
27
- * How many click → refresh → re-solve rounds the client will attempt on one
28
- * reCAPTCHA 3x3 dynamic puzzle.
29
- *
30
- * ── WHY 8, AND WHY IT MUST STAY STRICTLY BETWEEN 5 AND 10 ───────────────────
31
- *
32
- * The three numbers describe one attempt in three stages:
33
- *
34
- * rounds 1–5 billed
35
- * rounds 6–10 served, and comped
36
- * round 11 refused — 409, the attempt is over
37
- *
38
- * 8 sits strictly inside that, with room on both sides, and both margins do a
39
- * job:
40
- *
41
- * Above 5 — rounds 6, 7 and 8 are free. A puzzle that needs a couple of extra
42
- * passes still gets them, and the customer is not charged for our model
43
- * needing another look. Dropping to 5 would abandon winnable puzzles at
44
- * exactly the point where continuing costs the customer nothing.
45
- *
46
- * Below 10 — a well-behaved client gives up BEFORE the server refuses it.
47
- * Raising this to 10 or beyond means the normal end of a hard puzzle is a
48
- * 409 rather than a clean local stop, which turns an ordinary outcome into an
49
- * error the caller has to interpret.
50
- *
51
- * So: if the billable cap moves, re-derive this and move the test in the same
52
- * commit. Changing one number alone silently breaks one of the two margins.
53
- */
7
+ // Inside the comped band with margin on both sides. If the billable cap moves, re-derive this and move limits.test.ts in the same commit.
54
8
  exports.DEFAULT_RECAPTCHA_MAX_DYNAMIC_ROUNDS = 8;
@@ -1,23 +1,8 @@
1
- /**
2
- * Where the bundled Python engine lives — the copy of `models.json` this client
3
- * actually answers from.
4
- *
5
- * Lives HERE rather than in solver.ts because the registry lookup below is its
6
- * only remaining caller-visible use, and a second copy of this path logic is
7
- * how the two ports drifted apart in the first place. solver.ts imports it.
8
- *
9
- * When installed from npm this file is in `<pkgRoot>/dist` (compiled) or
10
- * `<pkgRoot>/src` (dev), and published packages bundle the engine at
11
- * `<pkgRoot>/python` (copied in by scripts/copy-python.mjs at build time). In
12
- * the source monorepo it instead lives at the sibling `../python`.
13
- */
14
1
  export declare function getBundledCliRoot(): string;
15
- /**
16
- * `cliRoot` is optional so a caller that only wants to REPORT the name — a test
17
- * harness recording which adapter it drove — can ask without reconstructing the
18
- * engine's layout. Re-deriving it is the same mistake one level down.
19
- */
20
- export declare function resolveLoraName({ cliRoot, env }?: {
2
+ export declare function isHostedEndpoint(baseUrl: string | undefined, env?: NodeJS.ProcessEnv): boolean;
3
+ /** Hosted: the routing alias, not an arm's `lora_name`, because a routed mixture is several names and only the alias routes. A missing or broken registry falls through to the pin, never throws. */
4
+ export declare function resolveLoraName({ cliRoot, env, baseUrl }?: {
21
5
  cliRoot?: string;
22
6
  env?: NodeJS.ProcessEnv;
7
+ baseUrl?: string;
23
8
  }): string;