nonecap 0.6.0 → 0.7.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/README.md +7 -3
- package/dist/index.cjs +55 -7
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +70 -5
- package/dist/index.d.ts +70 -5
- package/dist/index.js +50 -8
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -56,18 +56,22 @@ try {
|
|
|
56
56
|
// use token
|
|
57
57
|
} catch (err) {
|
|
58
58
|
if (err instanceof SolveFailedError) {
|
|
59
|
-
|
|
59
|
+
// The message says what happened, what to do, and that nothing was charged.
|
|
60
|
+
console.error(err.solve.error?.message);
|
|
61
|
+
if (err.retryable) scheduleRetry();
|
|
60
62
|
} else if (err instanceof InsufficientCreditsError) {
|
|
61
63
|
console.error("Out of credits. Top up at dashboard.nonecap.com");
|
|
62
64
|
} else if (err instanceof RateLimitError) {
|
|
63
|
-
|
|
65
|
+
await new Promise((r) => setTimeout(r, (err.retryAfter ?? 1) * 1000));
|
|
64
66
|
} else {
|
|
65
67
|
throw err;
|
|
66
68
|
}
|
|
67
69
|
}
|
|
68
70
|
```
|
|
69
71
|
|
|
70
|
-
The error subclasses are `AuthenticationError` (401), `PermissionError` (403), `InsufficientCreditsError` (402), `ValidationError` (422/400, with a `param` naming the bad field), `NotFoundError` (404), `ConflictError` (409), `RateLimitError` (429), `APIError` (5xx), and `ConnectionError` (the request never landed).
|
|
72
|
+
The error subclasses are `AuthenticationError` (401), `PermissionError` (403), `InsufficientCreditsError` (402, with `KeyCreditLimitError` when one API key hit its own cap), `ValidationError` (422/400, with a `param` naming the bad field; `PayloadTooLargeError` for 413 and `UnsupportedMediaTypeError` for 415), `NotFoundError` (404), `ConflictError` (409), `RateLimitError` (429, with `ConcurrencyLimitError` and `SitekeyRateLimitedError` telling the two apart; `retryAfter` is the seconds the API asked you to wait), `APIError` (5xx, with `ServiceUnavailableError` for a maintenance pause), and `ConnectionError` (the request never landed). Every error from a response carries `requestId`, the id to quote to support.
|
|
73
|
+
|
|
74
|
+
`SolveFailedError` carries the full `solve`. `solve.error.code` is a `SolveErrorCode`, `solve.error.reason` a typed sub-reason or `null` (`proxy_rejected`, `sitekey_rate_limited`, …), and `solve.error.retryable` says whether resubmitting the same request unchanged can succeed; `err.retryable`, `err.reason` and `err.solveCode` are shortcuts to those fields. Failed solves are never charged.
|
|
71
75
|
|
|
72
76
|
## Cancelling a solve
|
|
73
77
|
|
package/dist/index.cjs
CHANGED
|
@@ -8,12 +8,18 @@ var NoneCapError = class extends Error {
|
|
|
8
8
|
status;
|
|
9
9
|
/** The request field that was rejected, for validation errors. */
|
|
10
10
|
param;
|
|
11
|
+
/** The API's correlation id for this request (`X-Request-Id`); quote it to support. */
|
|
12
|
+
requestId;
|
|
13
|
+
/** Seconds to wait before retrying, when the API sent `Retry-After`. */
|
|
14
|
+
retryAfter;
|
|
11
15
|
constructor(message, opts = {}) {
|
|
12
16
|
super(message);
|
|
13
17
|
this.name = new.target.name;
|
|
14
18
|
this.code = opts.code;
|
|
15
19
|
this.status = opts.status;
|
|
16
20
|
this.param = opts.param ?? null;
|
|
21
|
+
this.requestId = opts.requestId;
|
|
22
|
+
this.retryAfter = opts.retryAfter;
|
|
17
23
|
Object.setPrototypeOf(this, new.target.prototype);
|
|
18
24
|
}
|
|
19
25
|
};
|
|
@@ -23,16 +29,28 @@ var PermissionError = class extends NoneCapError {
|
|
|
23
29
|
};
|
|
24
30
|
var InsufficientCreditsError = class extends NoneCapError {
|
|
25
31
|
};
|
|
32
|
+
var KeyCreditLimitError = class extends InsufficientCreditsError {
|
|
33
|
+
};
|
|
26
34
|
var ValidationError = class extends NoneCapError {
|
|
27
35
|
};
|
|
36
|
+
var PayloadTooLargeError = class extends ValidationError {
|
|
37
|
+
};
|
|
38
|
+
var UnsupportedMediaTypeError = class extends ValidationError {
|
|
39
|
+
};
|
|
28
40
|
var NotFoundError = class extends NoneCapError {
|
|
29
41
|
};
|
|
30
42
|
var ConflictError = class extends NoneCapError {
|
|
31
43
|
};
|
|
32
44
|
var RateLimitError = class extends NoneCapError {
|
|
33
45
|
};
|
|
46
|
+
var ConcurrencyLimitError = class extends RateLimitError {
|
|
47
|
+
};
|
|
48
|
+
var SitekeyRateLimitedError = class extends RateLimitError {
|
|
49
|
+
};
|
|
34
50
|
var APIError = class extends NoneCapError {
|
|
35
51
|
};
|
|
52
|
+
var ServiceUnavailableError = class extends APIError {
|
|
53
|
+
};
|
|
36
54
|
var ConnectionError = class extends NoneCapError {
|
|
37
55
|
};
|
|
38
56
|
var SolveFailedError = class extends NoneCapError {
|
|
@@ -45,6 +63,18 @@ var SolveFailedError = class extends NoneCapError {
|
|
|
45
63
|
});
|
|
46
64
|
this.solve = solve;
|
|
47
65
|
}
|
|
66
|
+
/** `solve.error.code`, e.g. `proxy_error`; the status when no error object came back. */
|
|
67
|
+
get solveCode() {
|
|
68
|
+
return this.solve.error?.code ?? this.solve.status;
|
|
69
|
+
}
|
|
70
|
+
/** `solve.error.reason`, the typed sub-reason, or null. */
|
|
71
|
+
get reason() {
|
|
72
|
+
return this.solve.error?.reason ?? null;
|
|
73
|
+
}
|
|
74
|
+
/** Whether re-submitting the same request unchanged can succeed. */
|
|
75
|
+
get retryable() {
|
|
76
|
+
return this.solve.error?.retryable ?? false;
|
|
77
|
+
}
|
|
48
78
|
};
|
|
49
79
|
var TimeoutError = class extends NoneCapError {
|
|
50
80
|
/** The id of the in-flight solve, when the timeout came from a solve wait. */
|
|
@@ -57,8 +87,8 @@ var TimeoutError = class extends NoneCapError {
|
|
|
57
87
|
this.solve = opts.solve;
|
|
58
88
|
}
|
|
59
89
|
};
|
|
60
|
-
function errorFromResponse(status, code, message, param) {
|
|
61
|
-
const opts = { code, status, param };
|
|
90
|
+
function errorFromResponse(status, code, message, param, extra = {}) {
|
|
91
|
+
const opts = { code, status, param, ...extra };
|
|
62
92
|
switch (code) {
|
|
63
93
|
case "unauthorized":
|
|
64
94
|
return new AuthenticationError(message, opts);
|
|
@@ -66,29 +96,38 @@ function errorFromResponse(status, code, message, param) {
|
|
|
66
96
|
case "account_locked":
|
|
67
97
|
return new PermissionError(message, opts);
|
|
68
98
|
case "insufficient_credits":
|
|
69
|
-
case "key_credit_limit_exceeded":
|
|
70
99
|
return new InsufficientCreditsError(message, opts);
|
|
100
|
+
case "key_credit_limit_exceeded":
|
|
101
|
+
return new KeyCreditLimitError(message, opts);
|
|
71
102
|
case "invalid_request":
|
|
72
103
|
case "validation_error":
|
|
73
104
|
case "expired_window":
|
|
74
105
|
return new ValidationError(message, opts);
|
|
106
|
+
case "payload_too_large":
|
|
107
|
+
return new PayloadTooLargeError(message, opts);
|
|
108
|
+
case "unsupported_media_type":
|
|
109
|
+
return new UnsupportedMediaTypeError(message, opts);
|
|
75
110
|
case "not_found":
|
|
76
111
|
case "not_eligible":
|
|
77
112
|
return new NotFoundError(message, opts);
|
|
78
113
|
case "conflict":
|
|
79
114
|
return new ConflictError(message, opts);
|
|
80
|
-
case "rate_limited":
|
|
81
115
|
case "concurrency_limit_exceeded":
|
|
82
|
-
|
|
116
|
+
return new ConcurrencyLimitError(message, opts);
|
|
83
117
|
case "sitekey_rate_limited":
|
|
118
|
+
return new SitekeyRateLimitedError(message, opts);
|
|
119
|
+
case "rate_limited":
|
|
120
|
+
case "ext_daily_limit":
|
|
84
121
|
return new RateLimitError(message, opts);
|
|
122
|
+
case "maintenance":
|
|
123
|
+
return new ServiceUnavailableError(message, opts);
|
|
85
124
|
default:
|
|
86
125
|
return new APIError(message, opts);
|
|
87
126
|
}
|
|
88
127
|
}
|
|
89
128
|
|
|
90
129
|
// src/version.ts
|
|
91
|
-
var VERSION = "0.
|
|
130
|
+
var VERSION = "0.7.0";
|
|
92
131
|
|
|
93
132
|
// src/client.ts
|
|
94
133
|
var DEFAULT_BASE_URL = "https://api.nonecap.com";
|
|
@@ -353,11 +392,14 @@ var NoneCap = class {
|
|
|
353
392
|
}
|
|
354
393
|
const envelope = json;
|
|
355
394
|
const apiError = envelope?.error;
|
|
395
|
+
const retryAfterRaw = res.headers.get("retry-after");
|
|
396
|
+
const retryAfter = retryAfterRaw !== null && /^\d+$/.test(retryAfterRaw) ? Number(retryAfterRaw) : void 0;
|
|
356
397
|
throw errorFromResponse(
|
|
357
398
|
res.status,
|
|
358
399
|
apiError?.code,
|
|
359
400
|
apiError?.message ?? `HTTP ${res.status}`,
|
|
360
|
-
apiError?.param ?? null
|
|
401
|
+
apiError?.param ?? null,
|
|
402
|
+
{ requestId: apiError?.request_id ?? res.headers.get("x-request-id") ?? void 0, retryAfter }
|
|
361
403
|
);
|
|
362
404
|
}
|
|
363
405
|
};
|
|
@@ -481,18 +523,24 @@ function toWireReport(report) {
|
|
|
481
523
|
|
|
482
524
|
exports.APIError = APIError;
|
|
483
525
|
exports.AuthenticationError = AuthenticationError;
|
|
526
|
+
exports.ConcurrencyLimitError = ConcurrencyLimitError;
|
|
484
527
|
exports.ConflictError = ConflictError;
|
|
485
528
|
exports.ConnectionError = ConnectionError;
|
|
486
529
|
exports.FEEDBACK_BATCH_MAX = FEEDBACK_BATCH_MAX;
|
|
487
530
|
exports.InsufficientCreditsError = InsufficientCreditsError;
|
|
531
|
+
exports.KeyCreditLimitError = KeyCreditLimitError;
|
|
488
532
|
exports.NoneCap = NoneCap;
|
|
489
533
|
exports.NoneCapError = NoneCapError;
|
|
490
534
|
exports.NotFoundError = NotFoundError;
|
|
535
|
+
exports.PayloadTooLargeError = PayloadTooLargeError;
|
|
491
536
|
exports.PermissionError = PermissionError;
|
|
492
537
|
exports.RateLimitError = RateLimitError;
|
|
538
|
+
exports.ServiceUnavailableError = ServiceUnavailableError;
|
|
539
|
+
exports.SitekeyRateLimitedError = SitekeyRateLimitedError;
|
|
493
540
|
exports.SolveFailedError = SolveFailedError;
|
|
494
541
|
exports.SolveHandle = SolveHandle;
|
|
495
542
|
exports.TimeoutError = TimeoutError;
|
|
543
|
+
exports.UnsupportedMediaTypeError = UnsupportedMediaTypeError;
|
|
496
544
|
exports.ValidationError = ValidationError;
|
|
497
545
|
exports.isTerminal = isTerminal;
|
|
498
546
|
//# sourceMappingURL=index.cjs.map
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/errors.ts","../src/version.ts","../src/client.ts"],"names":[],"mappings":";;;AAMO,IAAM,YAAA,GAAN,cAA2B,KAAA,CAAM;AAAA;AAAA,EAE7B,IAAA;AAAA;AAAA,EAEA,MAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EAET,WAAA,CACE,OAAA,EACA,IAAA,GAAqE,EAAC,EACtE;AACA,IAAA,KAAA,CAAM,OAAO,CAAA;AACb,IAAA,IAAA,CAAK,OAAO,GAAA,CAAA,MAAA,CAAW,IAAA;AACvB,IAAA,IAAA,CAAK,OAAO,IAAA,CAAK,IAAA;AACjB,IAAA,IAAA,CAAK,SAAS,IAAA,CAAK,MAAA;AACnB,IAAA,IAAA,CAAK,KAAA,GAAQ,KAAK,KAAA,IAAS,IAAA;AAE3B,IAAA,MAAA,CAAO,cAAA,CAAe,IAAA,EAAM,GAAA,CAAA,MAAA,CAAW,SAAS,CAAA;AAAA,EAClD;AACF;AAGO,IAAM,mBAAA,GAAN,cAAkC,YAAA,CAAa;AAAC;AAGhD,IAAM,eAAA,GAAN,cAA8B,YAAA,CAAa;AAAC;AAG5C,IAAM,wBAAA,GAAN,cAAuC,YAAA,CAAa;AAAC;AAGrD,IAAM,eAAA,GAAN,cAA8B,YAAA,CAAa;AAAC;AAG5C,IAAM,aAAA,GAAN,cAA4B,YAAA,CAAa;AAAC;AAG1C,IAAM,aAAA,GAAN,cAA4B,YAAA,CAAa;AAAC;AAG1C,IAAM,cAAA,GAAN,cAA6B,YAAA,CAAa;AAAC;AAG3C,IAAM,QAAA,GAAN,cAAuB,YAAA,CAAa;AAAC;AAGrC,IAAM,eAAA,GAAN,cAA8B,YAAA,CAAa;AAAC;AAO5C,IAAM,gBAAA,GAAN,cAA+B,YAAA,CAAa;AAAA,EACxC,KAAA;AAAA,EAET,YAAY,KAAA,EAAc;AACxB,IAAA,MAAM,MAAA,GAAS,KAAA,CAAM,KAAA,GAAQ,CAAA,EAAG,KAAA,CAAM,KAAA,CAAM,IAAI,CAAA,EAAA,EAAK,KAAA,CAAM,KAAA,CAAM,OAAO,CAAA,CAAA,GAAK,KAAA,CAAM,MAAA;AACnF,IAAA,KAAA,CAAM,CAAA,MAAA,EAAS,MAAM,EAAE,CAAA,CAAA,EAAI,MAAM,MAAM,CAAA,EAAA,EAAK,MAAM,CAAA,CAAA,CAAA,EAAK;AAAA,MACrD,IAAA,EAAM,MAAA;AAAA,MACN,MAAA,EAAQ;AAAA,KACT,CAAA;AACD,IAAA,IAAA,CAAK,KAAA,GAAQ,KAAA;AAAA,EACf;AACF;AAQO,IAAM,YAAA,GAAN,cAA2B,YAAA,CAAa;AAAA;AAAA,EAEpC,OAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EAET,WAAA,CACE,OAAA,EACA,IAAA,GAMI,EAAC,EACL;AACA,IAAA,KAAA,CAAM,SAAS,IAAI,CAAA;AACnB,IAAA,IAAA,CAAK,UAAU,IAAA,CAAK,OAAA;AACpB,IAAA,IAAA,CAAK,QAAQ,IAAA,CAAK,KAAA;AAAA,EACpB;AACF;AAGO,SAAS,iBAAA,CACd,MAAA,EACA,IAAA,EACA,OAAA,EACA,KAAA,EACc;AACd,EAAA,MAAM,IAAA,GAAO,EAAE,IAAA,EAAM,MAAA,EAAQ,KAAA,EAAM;AACnC,EAAA,QAAQ,IAAA;AAAM,IACZ,KAAK,cAAA;AACH,MAAA,OAAO,IAAI,mBAAA,CAAoB,OAAA,EAAS,IAAI,CAAA;AAAA,IAC9C,KAAK,WAAA;AAAA,IACL,KAAK,gBAAA;AACH,MAAA,OAAO,IAAI,eAAA,CAAgB,OAAA,EAAS,IAAI,CAAA;AAAA,IAC1C,KAAK,sBAAA;AAAA,IACL,KAAK,2BAAA;AACH,MAAA,OAAO,IAAI,wBAAA,CAAyB,OAAA,EAAS,IAAI,CAAA;AAAA,IACnD,KAAK,iBAAA;AAAA,IACL,KAAK,kBAAA;AAAA,IACL,KAAK,gBAAA;AACH,MAAA,OAAO,IAAI,eAAA,CAAgB,OAAA,EAAS,IAAI,CAAA;AAAA,IAC1C,KAAK,WAAA;AAAA,IACL,KAAK,cAAA;AACH,MAAA,OAAO,IAAI,aAAA,CAAc,OAAA,EAAS,IAAI,CAAA;AAAA,IACxC,KAAK,UAAA;AACH,MAAA,OAAO,IAAI,aAAA,CAAc,OAAA,EAAS,IAAI,CAAA;AAAA,IACxC,KAAK,cAAA;AAAA,IACL,KAAK,4BAAA;AAAA,IACL,KAAK,iBAAA;AAAA,IACL,KAAK,sBAAA;AACH,MAAA,OAAO,IAAI,cAAA,CAAe,OAAA,EAAS,IAAI,CAAA;AAAA,IACzC;AACE,MAAA,OAAO,IAAI,QAAA,CAAS,OAAA,EAAS,IAAI,CAAA;AAAA;AAEvC;;;AC7HO,IAAM,OAAA,GAAU,OAAA;;;ACcvB,IAAM,gBAAA,GAAmB,yBAAA;AACzB,IAAM,UAAA,GAAa,cAAc,OAAO,CAAA,CAAA;AAExC,IAAM,gBAAA,GAAmB,EAAA;AAElB,IAAM,kBAAA,GAAqB;AAClC,IAAM,QAAA,uBAAyC,GAAA,CAAI;AAAA,EACjD,QAAA;AAAA,EACA,QAAA;AAAA,EACA,WAAA;AAAA,EACA;AACF,CAAC,CAAA;AAGM,SAAS,WAAW,MAAA,EAA8B;AACvD,EAAA,OAAO,QAAA,CAAS,IAAI,MAAM,CAAA;AAC5B;AAuEO,IAAM,UAAN,MAAc;AAAA,EACV,OAAA;AAAA,EACA,QAAA;AAAA,EACA,QAAA;AAAA,EACA,MAAA;AAAA,EAET,YAAY,OAAA,EAAyB;AACnC,IAAA,IAAI,CAAC,OAAA,IAAW,CAAC,OAAA,CAAQ,MAAA,EAAQ;AAC/B,MAAA,MAAM,IAAI,YAAA;AAAA,QACR;AAAA,OACF;AAAA,IACF;AACA,IAAA,IAAA,CAAK,UAAU,OAAA,CAAQ,MAAA;AACvB,IAAA,IAAA,CAAK,YAAY,OAAA,CAAQ,OAAA,IAAW,gBAAA,EAAkB,OAAA,CAAQ,QAAQ,EAAE,CAAA;AACxE,IAAA,IAAA,CAAK,QAAA,GAAW,QAAQ,OAAA,IAAW,GAAA;AACnC,IAAA,MAAM,CAAA,GAAI,OAAA,CAAQ,KAAA,IAAU,UAAA,CAAW,KAAA;AACvC,IAAA,IAAI,CAAC,CAAA,EAAG;AACN,MAAA,MAAM,IAAI,YAAA;AAAA,QACR;AAAA,OACF;AAAA,IACF;AACA,IAAA,IAAA,CAAK,MAAA,GAAS,CAAA;AAAA,EAChB;AAAA;AAAA,EAGS,MAAA,GAAS;AAAA;AAAA,IAEhB,MAAA,EAAQ,CAAC,MAAA,EAA2B,OAAA,GAAuB,EAAC,KAC1D,IAAA,CAAK,QAAA,CAAgB,MAAA,EAAQ,YAAA,EAAc;AAAA,MACzC,IAAA,EAAM,MAAA;AAAA,MACN,KAAA,EAAO,EAAE,IAAA,EAAM,OAAA,CAAQ,IAAA,EAAK;AAAA,MAC5B,QAAQ,OAAA,CAAQ,MAAA;AAAA,MAChB,OAAA,EAAS,IAAA,CAAK,eAAA,CAAgB,OAAA,CAAQ,IAAI,CAAA;AAAA,MAC1C,MAAA,EAAQ,CAAC,GAAG;AAAA,KACb,CAAA;AAAA;AAAA,IAGH,QAAA,EAAU,CAAC,EAAA,EAAY,OAAA,GAAuB,EAAC,KAC7C,IAAA,CAAK,QAAA,CAAgB,KAAA,EAAO,CAAA,WAAA,EAAc,kBAAA,CAAmB,EAAE,CAAC,CAAA,CAAA,EAAI;AAAA,MAClE,KAAA,EAAO,EAAE,IAAA,EAAM,OAAA,CAAQ,IAAA,EAAK;AAAA,MAC5B,QAAQ,OAAA,CAAQ,MAAA;AAAA,MAChB,OAAA,EAAS,IAAA,CAAK,eAAA,CAAgB,OAAA,CAAQ,IAAI,CAAA;AAAA,MAC1C,MAAA,EAAQ,CAAC,GAAG;AAAA,KACb,CAAA;AAAA;AAAA,IAGH,MAAA,EAAQ,CAAC,EAAA,EAAY,OAAA,GAAoC,EAAC,KACxD,IAAA,CAAK,QAAA,CAAgB,QAAA,EAAU,CAAA,WAAA,EAAc,kBAAA,CAAmB,EAAE,CAAC,CAAA,CAAA,EAAI;AAAA,MACrE,QAAQ,OAAA,CAAQ;AAAA,KACjB,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAiBH,KAAA,EAAO,OACL,MAAA,EACA,OAAA,GAA6B,EAAC,KACL;AACzB,MAAA,MAAM,KAAA,GAAQ,MAAM,IAAA,CAAK,MAAA,CAAO,MAAA,CAAO,QAAQ,EAAE,MAAA,EAAQ,OAAA,CAAQ,MAAA,EAAQ,CAAA;AACzE,MAAA,OAAO,IAAI,WAAA,CAAY,IAAA,EAAM,KAAK,CAAA;AAAA,IACpC,CAAA;AAAA;AAAA,IAGA,IAAA,EAAM,CAAC,MAAA,GAA0B,EAAC,EAAG,OAAA,GAAoC,EAAC,KACxE,IAAA,CAAK,QAAA,CAAoB,KAAA,EAAO,YAAA,EAAc;AAAA,MAC5C,KAAA,EAAO;AAAA,QACL,OAAO,MAAA,CAAO,KAAA;AAAA,QACd,gBAAgB,MAAA,CAAO,cAAA;AAAA,QACvB,QAAQ,MAAA,CAAO,MAAA;AAAA,QACf,MAAM,MAAA,CAAO;AAAA,OACf;AAAA,MACA,QAAQ,OAAA,CAAQ;AAAA,KACjB,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IASH,OAAA,EAAS,CACP,MAAA,GAA0B,EAAC,EAC3B,OAAA,GAAoC,EAAC,KACJ,IAAA,CAAK,QAAA,CAAS,MAAA,EAAQ,OAAO;AAAA,GAClE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUS,QAAA,GAAW;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAYlB,MAAA,EAAQ,CAAC,MAAA,EAAwB,OAAA,GAAoC,EAAC,KAAyB;AAC7F,MAAA,MAAM,EAAE,QAAA,EAAU,GAAG,MAAA,EAAO,GAAI,MAAA;AAChC,MAAA,OAAO,IAAA,CAAK,QAAA;AAAA,QACV,MAAA;AAAA,QACA,CAAA,WAAA,EAAc,kBAAA,CAAmB,QAAQ,CAAC,CAAA,SAAA,CAAA;AAAA,QAC1C,EAAE,IAAA,EAAM,YAAA,CAAa,MAAM,CAAA,EAAG,MAAA,EAAQ,QAAQ,MAAA;AAAO,OACvD;AAAA,IACF,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAmBA,UAAA,EAAY,OACV,OAAA,EACA,OAAA,GAAoC,EAAC,KACV;AAC3B,MAAA,MAAM,MAAA,GAAwB;AAAA,QAC5B,MAAA,EAAQ,gBAAA;AAAA,QACR,QAAA,EAAU,CAAA;AAAA,QACV,OAAA,EAAS,CAAA;AAAA,QACT,SAAA,EAAW,CAAA;AAAA,QACX,MAAA,EAAQ,CAAA;AAAA,QACR,SAAS;AAAC,OACZ;AAMA,MAAA,KAAA,IAAS,IAAI,CAAA,EAAG,CAAA,GAAI,OAAA,CAAQ,MAAA,EAAQ,KAAK,kBAAA,EAAoB;AAC3D,QAAA,MAAM,KAAA,GAAQ,MAAM,IAAA,CAAK,QAAA,CAAwB,QAAQ,cAAA,EAAgB;AAAA,UACvE,IAAA,EAAM,EAAE,QAAA,EAAU,OAAA,CAAQ,KAAA,CAAM,CAAA,EAAG,CAAA,GAAI,kBAAkB,CAAA,CAAE,GAAA,CAAI,YAAY,CAAA,EAAE;AAAA,UAC7E,QAAQ,OAAA,CAAQ;AAAA,SACjB,CAAA;AACD,QAAA,MAAA,CAAO,YAAY,KAAA,CAAM,QAAA;AACzB,QAAA,MAAA,CAAO,WAAW,KAAA,CAAM,OAAA;AACxB,QAAA,MAAA,CAAO,aAAa,KAAA,CAAM,SAAA;AAC1B,QAAA,MAAA,CAAO,UAAU,KAAA,CAAM,MAAA;AACvB,QAAA,MAAA,CAAO,OAAA,CAAQ,IAAA,CAAK,GAAG,KAAA,CAAM,OAAO,CAAA;AAAA,MACtC;AACA,MAAA,OAAO,MAAA;AAAA,IACT;AAAA,GACF;AAAA;AAAA,EAGA,EAAA,CAAG,OAAA,GAAoC,EAAC,EAAqB;AAC3D,IAAA,OAAO,IAAA,CAAK,SAAkB,KAAA,EAAO,QAAA,EAAU,EAAE,MAAA,EAAQ,OAAA,CAAQ,QAAQ,CAAA;AAAA,EAC3E;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAaA,MAAM,KAAA,CAAM,MAAA,EAA2B,OAAA,GAA8B,EAAC,EAAmB;AACvF,IAAA,MAAM,MAAA,GAAS,MAAM,IAAA,CAAK,MAAA,CAAO,KAAA,CAAM,QAAQ,EAAE,MAAA,EAAQ,OAAA,CAAQ,MAAA,EAAQ,CAAA;AACzE,IAAA,OAAO,MAAA,CAAO,OAAO,OAAO,CAAA;AAAA,EAC9B;AAAA;AAAA,EAIA,gBAAgB,IAAA,EAAmC;AACjD,IAAA,IAAI,IAAA,KAAS,QAAW,OAAO,MAAA;AAE/B,IAAA,OAAO,OAAO,GAAA,GAAO,IAAA;AAAA,EACvB;AAAA,EAEA,OAAO,QAAA,CACL,MAAA,EACA,OAAA,EAC8B;AAC9B,IAAA,IAAI,SAAS,MAAA,CAAO,cAAA;AACpB,IAAA,WAAS;AACP,MAAA,MAAM,IAAA,GAAO,MAAM,IAAA,CAAK,MAAA,CAAO,IAAA,CAAK,EAAE,GAAG,MAAA,EAAQ,cAAA,EAAgB,MAAA,EAAO,EAAG,OAAO,CAAA;AAClF,MAAA,KAAA,MAAW,KAAA,IAAS,IAAA,CAAK,IAAA,EAAM,MAAM,KAAA;AACrC,MAAA,IAAI,CAAC,IAAA,CAAK,QAAA,IAAY,IAAA,CAAK,IAAA,CAAK,WAAW,CAAA,EAAG;AAC9C,MAAA,MAAA,GAAS,KAAK,IAAA,CAAK,IAAA,CAAK,IAAA,CAAK,MAAA,GAAS,CAAC,CAAA,CAAG,EAAA;AAAA,IAC5C;AAAA,EACF;AAAA,EAEA,MAAM,QAAA,CAAY,MAAA,EAAgB,IAAA,EAAc,OAAA,GAA0B,EAAC,EAAe;AACxF,IAAA,MAAM,GAAA,GAAM,IAAI,GAAA,CAAI,IAAA,CAAK,WAAW,IAAI,CAAA;AACxC,IAAA,IAAI,QAAQ,KAAA,EAAO;AACjB,MAAA,KAAA,MAAW,CAAC,KAAK,KAAK,CAAA,IAAK,OAAO,OAAA,CAAQ,OAAA,CAAQ,KAAK,CAAA,EAAG;AACxD,QAAA,IAAI,KAAA,KAAU,MAAA,IAAa,KAAA,KAAU,EAAA,EAAI,GAAA,CAAI,aAAa,GAAA,CAAI,GAAA,EAAK,MAAA,CAAO,KAAK,CAAC,CAAA;AAAA,MAClF;AAAA,IACF;AAEA,IAAA,MAAM,OAAA,GAAkC;AAAA,MACtC,aAAA,EAAe,CAAA,OAAA,EAAU,IAAA,CAAK,OAAO,CAAA,CAAA;AAAA,MACrC,MAAA,EAAQ,kBAAA;AAAA;AAAA,MAER,YAAA,EAAc;AAAA,KAChB;AACA,IAAA,IAAI,QAAA;AACJ,IAAA,IAAI,OAAA,CAAQ,SAAS,MAAA,EAAW;AAC9B,MAAA,OAAA,CAAQ,cAAc,CAAA,GAAI,kBAAA;AAC1B,MAAA,QAAA,GAAW,IAAA,CAAK,SAAA,CAAU,OAAA,CAAQ,IAAI,CAAA;AAAA,IACxC;AAEA,IAAA,MAAM,UAAA,GAAa,IAAI,eAAA,EAAgB;AACvC,IAAA,MAAM,SAAA,GAAY,OAAA,CAAQ,OAAA,IAAW,IAAA,CAAK,QAAA;AAC1C,IAAA,MAAM,KAAA,GAAQ,UAAA,CAAW,MAAM,UAAA,CAAW,KAAA,CAAM,IAAI,YAAA,CAAa,CAAA,wBAAA,EAA2B,SAAS,CAAA,GAAA,CAAK,CAAC,CAAA,EAAG,SAAS,CAAA;AACvH,IAAA,MAAM,UAAU,MAAM,UAAA,CAAW,KAAA,CAAM,OAAA,CAAQ,QAAQ,MAAM,CAAA;AAC7D,IAAA,IAAI,QAAQ,MAAA,EAAQ;AAClB,MAAA,IAAI,OAAA,CAAQ,MAAA,CAAO,OAAA,EAAS,OAAA,EAAQ;AAAA,WAC/B,OAAA,CAAQ,OAAO,gBAAA,CAAiB,OAAA,EAAS,SAAS,EAAE,IAAA,EAAM,MAAM,CAAA;AAAA,IACvE;AAEA,IAAA,IAAI,GAAA;AACJ,IAAA,IAAI;AACF,MAAA,GAAA,GAAM,MAAM,IAAA,CAAK,MAAA,CAAO,GAAA,CAAI,UAAS,EAAG;AAAA,QACtC,MAAA;AAAA,QACA,OAAA;AAAA,QACA,IAAA,EAAM,QAAA;AAAA,QACN,QAAQ,UAAA,CAAW;AAAA,OACpB,CAAA;AAAA,IACH,SAAS,GAAA,EAAK;AACZ,MAAA,IAAI,GAAA,YAAe,cAAc,MAAM,GAAA;AACvC,MAAA,IAAI,OAAA,CAAQ,GAAG,CAAA,EAAG;AAEhB,QAAA,IAAI,OAAA,CAAQ,MAAA,EAAQ,OAAA,EAAS,MAAM,OAAA,CAAQ,MAAA,CAAO,MAAA,YAAkB,KAAA,GAChE,OAAA,CAAQ,MAAA,CAAO,MAAA,GACf,IAAI,aAAa,kBAAkB,CAAA;AACvC,QAAA,MAAM,IAAI,YAAA,CAAa,CAAA,wBAAA,EAA2B,SAAS,CAAA,GAAA,CAAK,CAAA;AAAA,MAClE;AACA,MAAA,MAAM,IAAI,eAAA;AAAA,QACR,CAAA,mCAAA,EAAsC,IAAA,CAAK,QAAQ,CAAA,EAAA,EAAM,IAAc,OAAO,CAAA;AAAA,OAChF;AAAA,IACF,CAAA,SAAE;AACA,MAAA,YAAA,CAAa,KAAK,CAAA;AAClB,MAAA,OAAA,CAAQ,MAAA,EAAQ,mBAAA,CAAoB,OAAA,EAAS,OAAO,CAAA;AAAA,IACtD;AAEA,IAAA,OAAO,KAAK,MAAA,CAAU,GAAA,EAAK,OAAA,CAAQ,MAAA,IAAU,EAAE,CAAA;AAAA,EACjD;AAAA,EAEA,MAAM,MAAA,CAAU,GAAA,EAAe,MAAA,EAA8B;AAC3D,IAAA,MAAM,IAAA,GAAO,MAAM,GAAA,CAAI,IAAA,EAAK;AAC5B,IAAA,IAAI,IAAA;AACJ,IAAA,IAAI,IAAA,EAAM;AACR,MAAA,IAAI;AACF,QAAA,IAAA,GAAO,IAAA,CAAK,MAAM,IAAI,CAAA;AAAA,MACxB,CAAA,CAAA,MAAQ;AACN,QAAA,MAAM,IAAI,QAAA;AAAA,UACR,CAAA,mCAAA,EAAsC,IAAI,MAAM,CAAA,GAAA,EAAM,KAAK,KAAA,CAAM,CAAA,EAAG,GAAG,CAAC,CAAA,CAAA;AAAA,UACxE,EAAE,MAAA,EAAQ,GAAA,CAAI,MAAA;AAAO,SACvB;AAAA,MACF;AAAA,IACF;AAEA,IAAA,IAAI,IAAI,EAAA,IAAM,MAAA,CAAO,QAAA,CAAS,GAAA,CAAI,MAAM,CAAA,EAAG;AACzC,MAAA,OAAO,IAAA;AAAA,IACT;AAEA,IAAA,MAAM,QAAA,GAAW,IAAA;AACjB,IAAA,MAAM,WAAW,QAAA,EAAU,KAAA;AAC3B,IAAA,MAAM,iBAAA;AAAA,MACJ,GAAA,CAAI,MAAA;AAAA,MACJ,QAAA,EAAU,IAAA;AAAA,MACV,QAAA,EAAU,OAAA,IAAW,CAAA,KAAA,EAAQ,GAAA,CAAI,MAAM,CAAA,CAAA;AAAA,MACvC,UAAU,KAAA,IAAS;AAAA,KACrB;AAAA,EACF;AACF;AAWO,IAAM,cAAN,MAAkB;AAAA;AAAA,EAEd,EAAA;AAAA,EAEA,OAAA;AAAA;AAAA,EAET,MAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,SAAA;AAAA;AAAA,EAEA,SAAA;AAAA,EAEA,WAAA,CAAY,QAAiB,KAAA,EAAc;AACzC,IAAA,IAAA,CAAK,OAAA,GAAU,MAAA;AACf,IAAA,IAAA,CAAK,MAAA,GAAS,KAAA;AACd,IAAA,IAAA,CAAK,KAAK,KAAA,CAAM,EAAA;AAAA,EAClB;AAAA;AAAA,EAGA,IAAI,KAAA,GAAe;AACjB,IAAA,OAAO,IAAA,CAAK,MAAA;AAAA,EACd;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAeA,MAAA,CAAO,OAAA,GAA8B,EAAC,EAAmB;AACvD,IAAA,IAAI,IAAA,CAAK,SAAA,EAAW,OAAO,IAAA,CAAK,SAAA;AAChC,IAAA,IAAI,IAAA,CAAK,SAAA,EAAW,OAAO,IAAA,CAAK,SAAA;AAChC,IAAA,MAAM,MAAM,IAAA,CAAK,KAAA,CAAM,OAAO,CAAA,CAAE,QAAQ,MAAM;AAG5C,MAAA,IAAI,IAAA,CAAK,SAAA,KAAc,GAAA,EAAK,IAAA,CAAK,SAAA,GAAY,MAAA;AAAA,IAC/C,CAAC,CAAA;AACD,IAAA,IAAA,CAAK,SAAA,GAAY,GAAA;AACjB,IAAA,OAAO,GAAA;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAaA,MAAM,MAAA,CAAO,OAAA,GAAoC,EAAC,EAAmB;AACnE,IAAA,IAAI;AACF,MAAA,IAAA,CAAK,MAAA,GAAS,MAAM,IAAA,CAAK,OAAA,CAAQ,OAAO,MAAA,CAAO,IAAA,CAAK,IAAI,OAAO,CAAA;AAAA,IACjE,SAAS,GAAA,EAAK;AACZ,MAAA,IAAI,EAAE,GAAA,YAAe,aAAA,CAAA,EAAgB,MAAM,GAAA;AAE3C,MAAA,IAAA,CAAK,MAAA,GAAS,MAAM,IAAA,CAAK,OAAA,CAAQ,OAAO,QAAA,CAAS,IAAA,CAAK,IAAI,OAAO,CAAA;AAAA,IACnE;AACA,IAAA,IAAI,CAAC,KAAK,SAAA,IAAa,UAAA,CAAW,KAAK,MAAA,CAAO,MAAM,CAAA,EAAG,IAAA,CAAK,cAAA,EAAe;AAC3E,IAAA,OAAO,IAAA,CAAK,MAAA;AAAA,EACd;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,cAAA,GAAiC;AAC/B,IAAA,MAAM,UACJ,IAAA,CAAK,MAAA,CAAO,MAAA,KAAW,QAAA,GACnB,QAAQ,OAAA,CAAQ,IAAA,CAAK,MAAM,CAAA,GAC3B,QAAQ,MAAA,CAAO,IAAI,gBAAA,CAAiB,IAAA,CAAK,MAAM,CAAC,CAAA;AAGtD,IAAA,OAAA,CAAQ,MAAM,MAAM;AAAA,IAAC,CAAC,CAAA;AACtB,IAAA,IAAA,CAAK,SAAA,GAAY,OAAA;AACjB,IAAA,OAAO,OAAA;AAAA,EACT;AAAA,EAEA,MAAM,MAAM,OAAA,EAA6C;AACvD,IAAA,MAAM,OAAA,GAAU,QAAQ,OAAA,IAAW,IAAA;AACnC,IAAA,MAAM,QAAA,GAAW,IAAA,CAAK,GAAA,EAAI,GAAI,OAAA;AAE9B,IAAA,WAAS;AAEP,MAAA,IAAI,IAAA,CAAK,SAAA,EAAW,OAAO,IAAA,CAAK,SAAA;AAChC,MAAA,IAAI,WAAW,IAAA,CAAK,MAAA,CAAO,MAAM,CAAA,EAAG,OAAO,KAAK,cAAA,EAAe;AAC/D,MAAA,IAAI,IAAA,CAAK,GAAA,EAAI,IAAK,QAAA,EAAU;AAC1B,QAAA,MAAM,IAAI,YAAA;AAAA,UACR,CAAA,MAAA,EAAS,KAAK,EAAE,CAAA,uBAAA,EAA0B,OAAO,CAAA,iBAAA,EAAoB,IAAA,CAAK,OAAO,MAAM,CAAA,EAAA,CAAA;AAAA,UACvF,EAAE,OAAA,EAAS,IAAA,CAAK,EAAA,EAAI,KAAA,EAAO,KAAK,MAAA;AAAO,SACzC;AAAA,MACF;AACA,MAAA,IAAA,CAAK,SAAS,MAAM,IAAA,CAAK,QAAQ,MAAA,CAAO,QAAA,CAAS,KAAK,EAAA,EAAI;AAAA,QACxD,IAAA,EAAM,YAAY,QAAQ,CAAA;AAAA,QAC1B,QAAQ,OAAA,CAAQ;AAAA,OACjB,CAAA;AAAA,IACH;AAAA,EACF;AACF;AAQA,SAAS,YAAY,QAAA,EAA0B;AAC7C,EAAA,MAAM,YAAY,IAAA,CAAK,IAAA,CAAA,CAAM,WAAW,IAAA,CAAK,GAAA,MAAS,GAAI,CAAA;AAC1D,EAAA,OAAO,KAAK,GAAA,CAAI,CAAA,EAAG,KAAK,GAAA,CAAI,gBAAA,EAAkB,SAAS,CAAC,CAAA;AAC1D;AAEA,SAAS,QAAQ,GAAA,EAAuB;AACtC,EAAA,OAAO,GAAA,YAAe,KAAA,IAAS,GAAA,CAAI,IAAA,KAAS,YAAA;AAC9C;AAGA,SAAS,aAAa,MAAA,EAAmE;AACvF,EAAA,MAAM,IAAA,GAAgC,EAAE,OAAA,EAAS,MAAA,CAAO,OAAA,EAAQ;AAChE,EAAA,IAAI,MAAA,CAAO,MAAA,KAAW,MAAA,EAAW,IAAA,CAAK,SAAS,MAAA,CAAO,MAAA;AACtD,EAAA,IAAI,MAAA,CAAO,OAAA,KAAY,MAAA,EAAW,IAAA,CAAK,UAAU,MAAA,CAAO,OAAA;AACxD,EAAA,IAAI,MAAA,CAAO,gBAAgB,MAAA,EAAW;AACpC,IAAA,IAAA,CAAK,WAAA,GACH,OAAO,WAAA,YAAuB,IAAA,GAAO,OAAO,WAAA,CAAY,WAAA,KAAgB,MAAA,CAAO,WAAA;AAAA,EACnF;AACA,EAAA,OAAO,IAAA;AACT;AAEA,SAAS,aAAa,MAAA,EAAiD;AACrE,EAAA,MAAM,EAAE,QAAA,EAAU,GAAG,MAAA,EAAO,GAAI,MAAA;AAChC,EAAA,OAAO,EAAE,QAAA,EAAU,GAAG,YAAA,CAAa,MAAM,CAAA,EAAE;AAC7C","file":"index.cjs","sourcesContent":["import type { ErrorCode, Solve } from \"./types.js\";\n\n/**\n * Base class for every error this library throws. Catch `NoneCapError` to\n * handle all of them, or catch a subclass to handle one kind.\n */\nexport class NoneCapError extends Error {\n /** Machine-readable error code from the API envelope, when there is one. */\n readonly code: ErrorCode | undefined;\n /** HTTP status, when the error came from a response. */\n readonly status: number | undefined;\n /** The request field that was rejected, for validation errors. */\n readonly param: string | null;\n\n constructor(\n message: string,\n opts: { code?: ErrorCode; status?: number; param?: string | null } = {},\n ) {\n super(message);\n this.name = new.target.name;\n this.code = opts.code;\n this.status = opts.status;\n this.param = opts.param ?? null;\n // Restore the prototype chain when compiled down to ES5-era targets.\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\n/** 401 — the API key is missing, malformed, or revoked. */\nexport class AuthenticationError extends NoneCapError {}\n\n/** 403 — the key is valid but not allowed to do this (scope or locked account). */\nexport class PermissionError extends NoneCapError {}\n\n/** 402 — the account is out of credits. */\nexport class InsufficientCreditsError extends NoneCapError {}\n\n/** 422 / 400 — the request was rejected. `param` names the offending field. */\nexport class ValidationError extends NoneCapError {}\n\n/** 404 — no such resource. */\nexport class NotFoundError extends NoneCapError {}\n\n/** 409 — the solve is already in a terminal state (e.g. cancelling a finished solve). */\nexport class ConflictError extends NoneCapError {}\n\n/** 429 — too many concurrent solves, or rate limited. Back off and retry. */\nexport class RateLimitError extends NoneCapError {}\n\n/** 5xx, or a response that wasn't the expected shape. */\nexport class APIError extends NoneCapError {}\n\n/** The request never reached the API (DNS, TCP, TLS, timeout, offline). */\nexport class ConnectionError extends NoneCapError {}\n\n/**\n * Thrown by {@link NoneCap.solve} when a solve reaches a terminal state without\n * a token: `failed`, `expired`, or `cancelled`. The full solve is attached so\n * you can inspect `solve.error` and timings.\n */\nexport class SolveFailedError extends NoneCapError {\n readonly solve: Solve;\n\n constructor(solve: Solve) {\n const detail = solve.error ? `${solve.error.code}: ${solve.error.message}` : solve.status;\n super(`Solve ${solve.id} ${solve.status} (${detail})`, {\n code: undefined,\n status: undefined,\n });\n this.solve = solve;\n }\n}\n\n/**\n * Thrown by {@link NoneCap.solve} (and {@link SolveHandle.result}) when the\n * client-side timeout elapses first. When the timeout came from waiting on a\n * solve, `solveId` and the last-known `solve` are attached so you can still\n * cancel the in-flight solve. They are `undefined` for transport-level timeouts.\n */\nexport class TimeoutError extends NoneCapError {\n /** The id of the in-flight solve, when the timeout came from a solve wait. */\n readonly solveId: string | undefined;\n /** The last-known solve state, so you can cancel it after a wait timed out. */\n readonly solve: Solve | undefined;\n\n constructor(\n message: string,\n opts: {\n code?: ErrorCode;\n status?: number;\n param?: string | null;\n solveId?: string;\n solve?: Solve;\n } = {},\n ) {\n super(message, opts);\n this.solveId = opts.solveId;\n this.solve = opts.solve;\n }\n}\n\n/** Map an API error envelope (plus HTTP status) to the right error subclass. */\nexport function errorFromResponse(\n status: number,\n code: ErrorCode | undefined,\n message: string,\n param: string | null,\n): NoneCapError {\n const opts = { code, status, param };\n switch (code) {\n case \"unauthorized\":\n return new AuthenticationError(message, opts);\n case \"forbidden\":\n case \"account_locked\":\n return new PermissionError(message, opts);\n case \"insufficient_credits\":\n case \"key_credit_limit_exceeded\":\n return new InsufficientCreditsError(message, opts);\n case \"invalid_request\":\n case \"validation_error\":\n case \"expired_window\":\n return new ValidationError(message, opts);\n case \"not_found\":\n case \"not_eligible\":\n return new NotFoundError(message, opts);\n case \"conflict\":\n return new ConflictError(message, opts);\n case \"rate_limited\":\n case \"concurrency_limit_exceeded\":\n case \"ext_daily_limit\":\n case \"sitekey_rate_limited\":\n return new RateLimitError(message, opts);\n default:\n return new APIError(message, opts);\n }\n}\n","/**\n * The published package version, sent as the `User-Agent` on every request.\n *\n * Hardcoded rather than imported from package.json: a JSON import would need\n * `resolveJsonModule` and would resolve differently under the ESM and CJS\n * builds. Bump it in the SAME commit as package.json: the drift check is the\n * `Version constant matches package.json` step in ci.yml and lives ONLY there,\n * so `npm test` and `tsc` both stay green on a mismatch (test/version.test.ts\n * asserts the User-Agent uses VERSION, never that VERSION is right).\n */\nexport const VERSION = \"0.6.0\";\n","import {\n APIError,\n ConflictError,\n ConnectionError,\n NoneCapError,\n SolveFailedError,\n TimeoutError,\n errorFromResponse,\n} from \"./errors.js\";\nimport type {\n Account,\n ErrorCode,\n Feedback,\n FeedbackBatch,\n FeedbackReport,\n Solve,\n SolveCreateParams,\n SolveList,\n SolveListParams,\n SolveStatus,\n} from \"./types.js\";\n\nimport { VERSION } from \"./version.js\";\n\nconst DEFAULT_BASE_URL = \"https://api.nonecap.com\";\nconst USER_AGENT = `nonecap-js/${VERSION}`;\n/** The API caps server-side long-poll at 90 seconds. */\nconst MAX_WAIT_SECONDS = 90;\n/** The API caps one `POST /v1/feedback` call at 500 items. */\nexport const FEEDBACK_BATCH_MAX = 500;\nconst TERMINAL: ReadonlySet<SolveStatus> = new Set([\n \"solved\",\n \"failed\",\n \"cancelled\",\n \"expired\",\n]);\n\n/** Is this a terminal solve status? */\nexport function isTerminal(status: SolveStatus): boolean {\n return TERMINAL.has(status);\n}\n\n/** A `fetch` implementation. Defaults to the global `fetch`. */\nexport type FetchLike = (\n input: string,\n init?: RequestInit,\n) => Promise<Response>;\n\n/** Options for constructing a {@link NoneCap} client. */\nexport interface NoneCapOptions {\n /** Your NoneCap API key. Find it at https://dashboard.nonecap.com. */\n apiKey: string;\n /** Override the API base URL. Defaults to https://api.nonecap.com. */\n baseURL?: string;\n /**\n * Per-request timeout in milliseconds for a single HTTP call. Defaults to\n * 100000 (just above the 90s server long-poll). Note this bounds one HTTP\n * round trip, not the whole {@link NoneCap.solve} wait — use the `timeout`\n * option on `solve()` for that.\n */\n timeout?: number;\n /** Inject a custom `fetch` (for testing, proxies, or non-standard runtimes). */\n fetch?: FetchLike;\n}\n\n/** Per-call options for the long-polling endpoints. */\nexport interface WaitOptions {\n /**\n * Hold the connection open up to this many seconds (1–90) waiting for the\n * solve to finish before responding. Omit to return immediately.\n */\n wait?: number;\n /** Abort the request. */\n signal?: AbortSignal;\n}\n\n/** Options for {@link NoneCap.solve} and {@link SolveHandle.result}. */\nexport interface SolveHelperOptions {\n /**\n * Give up after this many milliseconds and throw {@link TimeoutError}.\n * Defaults to 180000 (3 minutes).\n */\n timeout?: number;\n /** Abort waiting. */\n signal?: AbortSignal;\n}\n\n/** Options for {@link NoneCap.solves.start}. */\nexport interface SolveStartOptions {\n /** Abort the submission. */\n signal?: AbortSignal;\n}\n\ninterface RequestOptions {\n query?: Record<string, string | number | undefined>;\n body?: unknown;\n signal?: AbortSignal;\n /** Override the per-request timeout for this call (used by long polls). */\n timeout?: number;\n /** HTTP statuses to treat as success in addition to 2xx (e.g. 202). */\n expect?: number[];\n}\n\n/**\n * The NoneCap API client.\n *\n * ```ts\n * const nc = new NoneCap({ apiKey: process.env.NONECAP_KEY! });\n * const { token } = await nc.solve({ type: \"hcaptcha\", sitekey, url });\n * ```\n */\nexport class NoneCap {\n readonly #apiKey: string;\n readonly #baseURL: string;\n readonly #timeout: number;\n readonly #fetch: FetchLike;\n\n constructor(options: NoneCapOptions) {\n if (!options || !options.apiKey) {\n throw new NoneCapError(\n \"A NoneCap API key is required. Pass it as `new NoneCap({ apiKey })`.\",\n );\n }\n this.#apiKey = options.apiKey;\n this.#baseURL = (options.baseURL ?? DEFAULT_BASE_URL).replace(/\\/+$/, \"\");\n this.#timeout = options.timeout ?? 100_000;\n const f = options.fetch ?? (globalThis.fetch as FetchLike | undefined);\n if (!f) {\n throw new NoneCapError(\n \"No `fetch` available. Use Node 18+, or pass a `fetch` in the client options.\",\n );\n }\n this.#fetch = f;\n }\n\n /** Operations on solves. */\n readonly solves = {\n /** Submit a solve. Pass `{ wait }` to hold the connection until it finishes. */\n create: (params: SolveCreateParams, options: WaitOptions = {}): Promise<Solve> =>\n this.#request<Solve>(\"POST\", \"/v1/solves\", {\n body: params,\n query: { wait: options.wait },\n signal: options.signal,\n timeout: this.#timeoutForWait(options.wait),\n expect: [202],\n }),\n\n /** Fetch a solve by id. Pass `{ wait }` to long-poll until it finishes. */\n retrieve: (id: string, options: WaitOptions = {}): Promise<Solve> =>\n this.#request<Solve>(\"GET\", `/v1/solves/${encodeURIComponent(id)}`, {\n query: { wait: options.wait },\n signal: options.signal,\n timeout: this.#timeoutForWait(options.wait),\n expect: [202],\n }),\n\n /** Cancel a pending or in-flight solve. */\n cancel: (id: string, options: { signal?: AbortSignal } = {}): Promise<Solve> =>\n this.#request<Solve>(\"DELETE\", `/v1/solves/${encodeURIComponent(id)}`, {\n signal: options.signal,\n }),\n\n /**\n * Submit a solve and return a {@link SolveHandle} for it.\n *\n * Unlike {@link NoneCap.solve}, this returns as soon as the submission is\n * accepted, so `handle.id` is available immediately. Use the handle to\n * `cancel()` the solve or `await handle.result()` for the finished solve.\n *\n * ```ts\n * const handle = await nc.solves.start({ type: \"hcaptcha\", sitekey, url });\n * // ...later, e.g. on shutdown:\n * await handle.cancel();\n * // or wait for it:\n * const { token } = await handle.result();\n * ```\n */\n start: async (\n params: SolveCreateParams,\n options: SolveStartOptions = {},\n ): Promise<SolveHandle> => {\n const solve = await this.solves.create(params, { signal: options.signal });\n return new SolveHandle(this, solve);\n },\n\n /** Fetch one page of solves. */\n list: (params: SolveListParams = {}, options: { signal?: AbortSignal } = {}): Promise<SolveList> =>\n this.#request<SolveList>(\"GET\", \"/v1/solves\", {\n query: {\n limit: params.limit,\n starting_after: params.starting_after,\n status: params.status,\n type: params.type,\n },\n signal: options.signal,\n }),\n\n /**\n * Iterate every solve across pages, newest first.\n *\n * ```ts\n * for await (const solve of nc.solves.listAll()) { ... }\n * ```\n */\n listAll: (\n params: SolveListParams = {},\n options: { signal?: AbortSignal } = {},\n ): AsyncIterableIterator<Solve> => this.#listAll(params, options),\n };\n\n /**\n * Report what your downstream target did with the tokens we minted.\n *\n * Feedback is free, own-solves-only, and idempotent per solve id: reporting\n * the same solve again corrects the earlier verdict. Only `solved` solves can\n * be reported, and only within the API's reporting window (~30 days from the\n * solve; corrections to an already-reported solve are never re-gated by it).\n */\n readonly feedback = {\n /**\n * Report one solve's downstream outcome, returning the recorded feedback.\n *\n * Unlike {@link NoneCap.feedback.reportMany}, a rejected report throws:\n * {@link NotFoundError} if the solve isn't yours or never minted a token,\n * {@link ValidationError} if a field is wrong or the reporting window closed.\n *\n * ```ts\n * await nc.feedback.report({ solve_id: solve.id, outcome: \"rejected\", reason: \"...\" });\n * ```\n */\n report: (report: FeedbackReport, options: { signal?: AbortSignal } = {}): Promise<Feedback> => {\n const { solve_id, ...fields } = report;\n return this.#request<Feedback>(\n \"POST\",\n `/v1/solves/${encodeURIComponent(solve_id)}/feedback`,\n { body: toWireFields(fields), signal: options.signal },\n );\n },\n\n /**\n * Report many verdicts at once — the path to use at volume. Buffer verdicts\n * as you learn them and flush them here.\n *\n * The call succeeds even when individual items are rejected: each is\n * resolved on its own so one stale id never discards the rest. Check\n * `failed` rather than relying on a thrown error.\n *\n * More than {@link FEEDBACK_BATCH_MAX} reports are split across sequential\n * requests and merged into one result, in request order. An empty array is\n * a no-op that returns an empty batch without a request.\n *\n * ```ts\n * const batch = await nc.feedback.reportMany(buffer);\n * if (batch.failed) console.warn(batch.results.filter((r) => r.status === \"error\"));\n * ```\n */\n reportMany: async (\n reports: readonly FeedbackReport[],\n options: { signal?: AbortSignal } = {},\n ): Promise<FeedbackBatch> => {\n const merged: FeedbackBatch = {\n object: \"feedback_batch\",\n recorded: 0,\n updated: 0,\n unchanged: 0,\n failed: 0,\n results: [],\n };\n // Chunks are sent in order and the server upserts last-write-wins, so a\n // solve reported twice still ends at its last value. Duplicates split\n // across a chunk boundary each get written, though, so the earlier one\n // reports `recorded`/`updated` where a single request would say\n // `unchanged`.\n for (let i = 0; i < reports.length; i += FEEDBACK_BATCH_MAX) {\n const batch = await this.#request<FeedbackBatch>(\"POST\", \"/v1/feedback\", {\n body: { feedback: reports.slice(i, i + FEEDBACK_BATCH_MAX).map(toWireReport) },\n signal: options.signal,\n });\n merged.recorded += batch.recorded;\n merged.updated += batch.updated;\n merged.unchanged += batch.unchanged;\n merged.failed += batch.failed;\n merged.results.push(...batch.results);\n }\n return merged;\n },\n };\n\n /** Fetch your account, including the current credit balance. */\n me(options: { signal?: AbortSignal } = {}): Promise<Account> {\n return this.#request<Account>(\"GET\", \"/v1/me\", { signal: options.signal });\n }\n\n /**\n * Submit a solve and wait for it to finish, returning the solved solve.\n *\n * Uses the server's long-poll under the hood and keeps polling until the\n * solve is terminal or `timeout` elapses. Throws {@link SolveFailedError} if\n * the solve fails/expires/is cancelled, or {@link TimeoutError} on timeout.\n *\n * This is sugar for `(await solves.start(params)).result(options)`. When you\n * need to cancel the solve while it runs, use {@link NoneCap.solves.start}\n * and keep the {@link SolveHandle}.\n */\n async solve(params: SolveCreateParams, options: SolveHelperOptions = {}): Promise<Solve> {\n const handle = await this.solves.start(params, { signal: options.signal });\n return handle.result(options);\n }\n\n // -- internals ------------------------------------------------------------\n\n #timeoutForWait(wait?: number): number | undefined {\n if (wait === undefined) return undefined;\n // Give the socket a margin beyond the server's long-poll window.\n return wait * 1000 + 15_000;\n }\n\n async *#listAll(\n params: SolveListParams,\n options: { signal?: AbortSignal },\n ): AsyncIterableIterator<Solve> {\n let cursor = params.starting_after;\n for (;;) {\n const page = await this.solves.list({ ...params, starting_after: cursor }, options);\n for (const solve of page.data) yield solve;\n if (!page.has_more || page.data.length === 0) return;\n cursor = page.data[page.data.length - 1]!.id;\n }\n }\n\n async #request<T>(method: string, path: string, options: RequestOptions = {}): Promise<T> {\n const url = new URL(this.#baseURL + path);\n if (options.query) {\n for (const [key, value] of Object.entries(options.query)) {\n if (value !== undefined && value !== \"\") url.searchParams.set(key, String(value));\n }\n }\n\n const headers: Record<string, string> = {\n Authorization: `Bearer ${this.#apiKey}`,\n Accept: \"application/json\",\n // Browsers drop this as a forbidden header; on Node it identifies the SDK.\n \"User-Agent\": USER_AGENT,\n };\n let bodyInit: string | undefined;\n if (options.body !== undefined) {\n headers[\"Content-Type\"] = \"application/json\";\n bodyInit = JSON.stringify(options.body);\n }\n\n const controller = new AbortController();\n const timeoutMs = options.timeout ?? this.#timeout;\n const timer = setTimeout(() => controller.abort(new TimeoutError(`Request timed out after ${timeoutMs}ms.`)), timeoutMs);\n const onAbort = () => controller.abort(options.signal?.reason);\n if (options.signal) {\n if (options.signal.aborted) onAbort();\n else options.signal.addEventListener(\"abort\", onAbort, { once: true });\n }\n\n let res: Response;\n try {\n res = await this.#fetch(url.toString(), {\n method,\n headers,\n body: bodyInit,\n signal: controller.signal,\n });\n } catch (err) {\n if (err instanceof TimeoutError) throw err;\n if (isAbort(err)) {\n // A caller-supplied signal aborting surfaces as the caller's reason.\n if (options.signal?.aborted) throw options.signal.reason instanceof Error\n ? options.signal.reason\n : new NoneCapError(\"Request aborted.\");\n throw new TimeoutError(`Request timed out after ${timeoutMs}ms.`);\n }\n throw new ConnectionError(\n `Could not reach the NoneCap API at ${this.#baseURL}: ${(err as Error).message}`,\n );\n } finally {\n clearTimeout(timer);\n options.signal?.removeEventListener(\"abort\", onAbort);\n }\n\n return this.#parse<T>(res, options.expect ?? []);\n }\n\n async #parse<T>(res: Response, expect: number[]): Promise<T> {\n const text = await res.text();\n let json: unknown;\n if (text) {\n try {\n json = JSON.parse(text);\n } catch {\n throw new APIError(\n `Unexpected non-JSON response (HTTP ${res.status}): ${text.slice(0, 200)}`,\n { status: res.status },\n );\n }\n }\n\n if (res.ok || expect.includes(res.status)) {\n return json as T;\n }\n\n const envelope = json as { error?: { code?: ErrorCode; message?: string; param?: string | null } } | undefined;\n const apiError = envelope?.error;\n throw errorFromResponse(\n res.status,\n apiError?.code,\n apiError?.message ?? `HTTP ${res.status}`,\n apiError?.param ?? null,\n );\n }\n}\n\n/**\n * A handle on a started solve, returned by {@link NoneCap.solves.start}.\n *\n * The handle is the cancellable lifecycle object for one solve. It is a plain\n * object, not a promise: `await`ing it does nothing useful. Wait for the result\n * with {@link SolveHandle.result}, and cancel with {@link SolveHandle.cancel}.\n * You do not construct it yourself — `solves.start()` hands you one with `id`\n * already resolved.\n */\nexport class SolveHandle {\n /** The id of the started solve, available as soon as `start()` resolved. */\n readonly id: string;\n\n readonly #client: NoneCap;\n /** The latest solve state we have seen, from the create, polls, or cancel. */\n #solve: Solve;\n /**\n * The cached TERMINAL outcome: resolves to the solved solve, or rejects with\n * {@link SolveFailedError} if terminal-but-not-solved. Only ever set once the\n * solve actually reaches a terminal state, so it is safe to replay forever. A\n * timed-out wait does NOT settle this — it is retryable.\n */\n #terminal: Promise<Solve> | undefined;\n /** The poll currently in flight, shared by concurrent result() callers. */\n #inflight: Promise<Solve> | undefined;\n\n constructor(client: NoneCap, solve: Solve) {\n this.#client = client;\n this.#solve = solve;\n this.id = solve.id;\n }\n\n /** The last-known solve state for this handle. */\n get solve(): Solve {\n return this.#solve;\n }\n\n /**\n * Long-poll until the solve is terminal, returning the solved solve. Throws\n * {@link SolveFailedError} if it fails/expires/is cancelled, or\n * {@link TimeoutError} on timeout (with `solveId`/`solve` attached so you can\n * still {@link SolveHandle.cancel} it).\n *\n * Memoizes the *terminal* outcome: once the solve actually finishes, every\n * later call returns that same settled result. A {@link TimeoutError} is not\n * memoized — it just means this wait gave up, so a later call (e.g. with a\n * larger `timeout`) resumes polling. Concurrent calls share one in-flight\n * poll, so they never issue duplicate requests. The first caller's\n * `timeout`/`signal` drive the shared poll; a later call starts a fresh one.\n */\n result(options: SolveHelperOptions = {}): Promise<Solve> {\n if (this.#terminal) return this.#terminal;\n if (this.#inflight) return this.#inflight;\n const run = this.#poll(options).finally(() => {\n // Free the slot so a retry can re-poll after a timeout; a terminal\n // outcome is already memoized in #terminal and wins on the next call.\n if (this.#inflight === run) this.#inflight = undefined;\n });\n this.#inflight = run;\n return run;\n }\n\n /**\n * Cancel the solve. Cancelled solves are never charged, so this is for clean\n * shutdown / freeing slots / stopping early, not cost protection.\n *\n * If the solve already reached a terminal state the API answers 409; that is\n * not an error a caller cares about, so this swallows {@link ConflictError}\n * and returns the current solve state instead. A cancel that lands on a\n * terminal state (cancelled, or whatever the 409-swallow read back) settles\n * this handle's {@link SolveHandle.result}, so any in-flight or later wait\n * stops polling and reflects that terminal state.\n */\n async cancel(options: { signal?: AbortSignal } = {}): Promise<Solve> {\n try {\n this.#solve = await this.#client.solves.cancel(this.id, options);\n } catch (err) {\n if (!(err instanceof ConflictError)) throw err;\n // Already terminal — report the real state rather than the 409.\n this.#solve = await this.#client.solves.retrieve(this.id, options);\n }\n if (!this.#terminal && isTerminal(this.#solve.status)) this.#cacheTerminal();\n return this.#solve;\n }\n\n /**\n * Build and memoize the terminal outcome from the current `#solve`. The\n * precondition is that `#solve` is terminal and `#terminal` is unset.\n */\n #cacheTerminal(): Promise<Solve> {\n const settled =\n this.#solve.status === \"solved\"\n ? Promise.resolve(this.#solve)\n : Promise.reject(new SolveFailedError(this.#solve));\n // Never let the memoized rejection surface as an unhandled rejection; real\n // callers read it explicitly through result().\n settled.catch(() => {});\n this.#terminal = settled;\n return settled;\n }\n\n async #poll(options: SolveHelperOptions): Promise<Solve> {\n const timeout = options.timeout ?? 180_000;\n const deadline = Date.now() + timeout;\n\n for (;;) {\n // cancel() (or a previous poll) may have already settled this handle.\n if (this.#terminal) return this.#terminal;\n if (isTerminal(this.#solve.status)) return this.#cacheTerminal();\n if (Date.now() >= deadline) {\n throw new TimeoutError(\n `Solve ${this.id} did not finish within ${timeout}ms (last status: ${this.#solve.status}).`,\n { solveId: this.id, solve: this.#solve },\n );\n }\n this.#solve = await this.#client.solves.retrieve(this.id, {\n wait: waitSeconds(deadline),\n signal: options.signal,\n });\n }\n }\n}\n\n/**\n * The `wait` value for the next long-poll: whole seconds until `deadline`,\n * clamped to the server's 1–90 window. The floor of 1 keeps the param valid,\n * so callers must decide whether the deadline has passed with the clock, not\n * with this return value.\n */\nfunction waitSeconds(deadline: number): number {\n const remaining = Math.ceil((deadline - Date.now()) / 1000);\n return Math.max(1, Math.min(MAX_WAIT_SECONDS, remaining));\n}\n\nfunction isAbort(err: unknown): boolean {\n return err instanceof Error && err.name === \"AbortError\";\n}\n\n/** The fields of a report, ready for the wire: a `Date` becomes an ISO string. */\nfunction toWireFields(fields: Omit<FeedbackReport, \"solve_id\">): Record<string, unknown> {\n const wire: Record<string, unknown> = { outcome: fields.outcome };\n if (fields.reason !== undefined) wire.reason = fields.reason;\n if (fields.context !== undefined) wire.context = fields.context;\n if (fields.reported_at !== undefined) {\n wire.reported_at =\n fields.reported_at instanceof Date ? fields.reported_at.toISOString() : fields.reported_at;\n }\n return wire;\n}\n\nfunction toWireReport(report: FeedbackReport): Record<string, unknown> {\n const { solve_id, ...fields } = report;\n return { solve_id, ...toWireFields(fields) };\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/errors.ts","../src/version.ts","../src/client.ts"],"names":[],"mappings":"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","file":"index.cjs","sourcesContent":["import type { ErrorCode, Solve } from \"./types.js\";\n\n/**\n * Base class for every error this library throws. Catch `NoneCapError` to\n * handle all of them, or catch a subclass to handle one kind.\n */\nexport class NoneCapError extends Error {\n /** Machine-readable error code from the API envelope, when there is one. */\n readonly code: ErrorCode | undefined;\n /** HTTP status, when the error came from a response. */\n readonly status: number | undefined;\n /** The request field that was rejected, for validation errors. */\n readonly param: string | null;\n /** The API's correlation id for this request (`X-Request-Id`); quote it to support. */\n readonly requestId: string | undefined;\n /** Seconds to wait before retrying, when the API sent `Retry-After`. */\n readonly retryAfter: number | undefined;\n\n constructor(\n message: string,\n opts: {\n code?: ErrorCode;\n status?: number;\n param?: string | null;\n requestId?: string;\n retryAfter?: number;\n } = {},\n ) {\n super(message);\n this.name = new.target.name;\n this.code = opts.code;\n this.status = opts.status;\n this.param = opts.param ?? null;\n this.requestId = opts.requestId;\n this.retryAfter = opts.retryAfter;\n // Restore the prototype chain when compiled down to ES5-era targets.\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\n/** 401 — the API key is missing, malformed, or revoked. */\nexport class AuthenticationError extends NoneCapError {}\n\n/** 403 — the key is valid but not allowed to do this (scope or locked account). */\nexport class PermissionError extends NoneCapError {}\n\n/** 402 — the account is out of credits. */\nexport class InsufficientCreditsError extends NoneCapError {}\n\n/** 402 — this API key reached its own credit limit (the account may still have credits). */\nexport class KeyCreditLimitError extends InsufficientCreditsError {}\n\n/** 422 / 400 — the request was rejected. `param` names the offending field. */\nexport class ValidationError extends NoneCapError {}\n\n/** 413 — the request body exceeds the route's size limit. */\nexport class PayloadTooLargeError extends ValidationError {}\n\n/** 415 — a JSON route was called without `Content-Type: application/json`. */\nexport class UnsupportedMediaTypeError extends ValidationError {}\n\n/** 404 — no such resource. */\nexport class NotFoundError extends NoneCapError {}\n\n/** 409 — the solve is already in a terminal state (e.g. cancelling a finished solve). */\nexport class ConflictError extends NoneCapError {}\n\n/** 429 — back off and retry; `retryAfter` (seconds) is set when the API sent it. */\nexport class RateLimitError extends NoneCapError {}\n\n/** 429 — too many solves in flight for this account. Wait for one to finish. */\nexport class ConcurrencyLimitError extends RateLimitError {}\n\n/** 429 — hCaptcha is refusing challenges for this sitekey, so the submit was shed.\n * Wait `retryAfter` seconds; the message says whether a different proxy pool can help. */\nexport class SitekeyRateLimitedError extends RateLimitError {}\n\n/** 5xx, or a response that wasn't the expected shape. `requestId` is the id to quote. */\nexport class APIError extends NoneCapError {}\n\n/** 503 — new solves are paused for maintenance. Retry shortly. */\nexport class ServiceUnavailableError extends APIError {}\n\n/** The request never reached the API (DNS, TCP, TLS, timeout, offline). */\nexport class ConnectionError extends NoneCapError {}\n\n/**\n * Thrown by {@link NoneCap.solve} when a solve reaches a terminal state without\n * a token: `failed`, `expired`, or `cancelled`. The full solve is attached so\n * you can inspect `solve.error` and timings.\n */\nexport class SolveFailedError extends NoneCapError {\n readonly solve: Solve;\n\n constructor(solve: Solve) {\n const detail = solve.error ? `${solve.error.code}: ${solve.error.message}` : solve.status;\n super(`Solve ${solve.id} ${solve.status} (${detail})`, {\n code: undefined,\n status: undefined,\n });\n this.solve = solve;\n }\n\n /** `solve.error.code`, e.g. `proxy_error`; the status when no error object came back. */\n get solveCode(): string {\n return this.solve.error?.code ?? this.solve.status;\n }\n\n /** `solve.error.reason`, the typed sub-reason, or null. */\n get reason(): string | null {\n return this.solve.error?.reason ?? null;\n }\n\n /** Whether re-submitting the same request unchanged can succeed. */\n get retryable(): boolean {\n return this.solve.error?.retryable ?? false;\n }\n}\n\n/**\n * Thrown by {@link NoneCap.solve} (and {@link SolveHandle.result}) when the\n * client-side timeout elapses first. When the timeout came from waiting on a\n * solve, `solveId` and the last-known `solve` are attached so you can still\n * cancel the in-flight solve. They are `undefined` for transport-level timeouts.\n */\nexport class TimeoutError extends NoneCapError {\n /** The id of the in-flight solve, when the timeout came from a solve wait. */\n readonly solveId: string | undefined;\n /** The last-known solve state, so you can cancel it after a wait timed out. */\n readonly solve: Solve | undefined;\n\n constructor(\n message: string,\n opts: {\n code?: ErrorCode;\n status?: number;\n param?: string | null;\n solveId?: string;\n solve?: Solve;\n } = {},\n ) {\n super(message, opts);\n this.solveId = opts.solveId;\n this.solve = opts.solve;\n }\n}\n\n/** Map an API error envelope (plus HTTP status) to the right error subclass. */\nexport function errorFromResponse(\n status: number,\n code: ErrorCode | undefined,\n message: string,\n param: string | null,\n extra: { requestId?: string; retryAfter?: number } = {},\n): NoneCapError {\n const opts = { code, status, param, ...extra };\n switch (code) {\n case \"unauthorized\":\n return new AuthenticationError(message, opts);\n case \"forbidden\":\n case \"account_locked\":\n return new PermissionError(message, opts);\n case \"insufficient_credits\":\n return new InsufficientCreditsError(message, opts);\n case \"key_credit_limit_exceeded\":\n return new KeyCreditLimitError(message, opts);\n case \"invalid_request\":\n case \"validation_error\":\n case \"expired_window\":\n return new ValidationError(message, opts);\n case \"payload_too_large\":\n return new PayloadTooLargeError(message, opts);\n case \"unsupported_media_type\":\n return new UnsupportedMediaTypeError(message, opts);\n case \"not_found\":\n case \"not_eligible\":\n return new NotFoundError(message, opts);\n case \"conflict\":\n return new ConflictError(message, opts);\n case \"concurrency_limit_exceeded\":\n return new ConcurrencyLimitError(message, opts);\n case \"sitekey_rate_limited\":\n return new SitekeyRateLimitedError(message, opts);\n case \"rate_limited\":\n case \"ext_daily_limit\":\n return new RateLimitError(message, opts);\n case \"maintenance\":\n return new ServiceUnavailableError(message, opts);\n default:\n return new APIError(message, opts);\n }\n}\n","/**\n * The published package version, sent as the `User-Agent` on every request.\n *\n * Hardcoded rather than imported from package.json: a JSON import would need\n * `resolveJsonModule` and would resolve differently under the ESM and CJS\n * builds. Bump it in the SAME commit as package.json: the drift check is the\n * `Version constant matches package.json` step in ci.yml and lives ONLY there,\n * so `npm test` and `tsc` both stay green on a mismatch (test/version.test.ts\n * asserts the User-Agent uses VERSION, never that VERSION is right).\n */\nexport const VERSION = \"0.7.0\";\n","import {\n APIError,\n ConflictError,\n ConnectionError,\n NoneCapError,\n SolveFailedError,\n TimeoutError,\n errorFromResponse,\n} from \"./errors.js\";\nimport type {\n Account,\n ErrorCode,\n Feedback,\n FeedbackBatch,\n FeedbackReport,\n Solve,\n SolveCreateParams,\n SolveList,\n SolveListParams,\n SolveStatus,\n} from \"./types.js\";\n\nimport { VERSION } from \"./version.js\";\n\nconst DEFAULT_BASE_URL = \"https://api.nonecap.com\";\nconst USER_AGENT = `nonecap-js/${VERSION}`;\n/** The API caps server-side long-poll at 90 seconds. */\nconst MAX_WAIT_SECONDS = 90;\n/** The API caps one `POST /v1/feedback` call at 500 items. */\nexport const FEEDBACK_BATCH_MAX = 500;\nconst TERMINAL: ReadonlySet<SolveStatus> = new Set([\n \"solved\",\n \"failed\",\n \"cancelled\",\n \"expired\",\n]);\n\n/** Is this a terminal solve status? */\nexport function isTerminal(status: SolveStatus): boolean {\n return TERMINAL.has(status);\n}\n\n/** A `fetch` implementation. Defaults to the global `fetch`. */\nexport type FetchLike = (\n input: string,\n init?: RequestInit,\n) => Promise<Response>;\n\n/** Options for constructing a {@link NoneCap} client. */\nexport interface NoneCapOptions {\n /** Your NoneCap API key. Find it at https://dashboard.nonecap.com. */\n apiKey: string;\n /** Override the API base URL. Defaults to https://api.nonecap.com. */\n baseURL?: string;\n /**\n * Per-request timeout in milliseconds for a single HTTP call. Defaults to\n * 100000 (just above the 90s server long-poll). Note this bounds one HTTP\n * round trip, not the whole {@link NoneCap.solve} wait — use the `timeout`\n * option on `solve()` for that.\n */\n timeout?: number;\n /** Inject a custom `fetch` (for testing, proxies, or non-standard runtimes). */\n fetch?: FetchLike;\n}\n\n/** Per-call options for the long-polling endpoints. */\nexport interface WaitOptions {\n /**\n * Hold the connection open up to this many seconds (1–90) waiting for the\n * solve to finish before responding. Omit to return immediately.\n */\n wait?: number;\n /** Abort the request. */\n signal?: AbortSignal;\n}\n\n/** Options for {@link NoneCap.solve} and {@link SolveHandle.result}. */\nexport interface SolveHelperOptions {\n /**\n * Give up after this many milliseconds and throw {@link TimeoutError}.\n * Defaults to 180000 (3 minutes).\n */\n timeout?: number;\n /** Abort waiting. */\n signal?: AbortSignal;\n}\n\n/** Options for {@link NoneCap.solves.start}. */\nexport interface SolveStartOptions {\n /** Abort the submission. */\n signal?: AbortSignal;\n}\n\ninterface RequestOptions {\n query?: Record<string, string | number | undefined>;\n body?: unknown;\n signal?: AbortSignal;\n /** Override the per-request timeout for this call (used by long polls). */\n timeout?: number;\n /** HTTP statuses to treat as success in addition to 2xx (e.g. 202). */\n expect?: number[];\n}\n\n/**\n * The NoneCap API client.\n *\n * ```ts\n * const nc = new NoneCap({ apiKey: process.env.NONECAP_KEY! });\n * const { token } = await nc.solve({ type: \"hcaptcha\", sitekey, url });\n * ```\n */\nexport class NoneCap {\n readonly #apiKey: string;\n readonly #baseURL: string;\n readonly #timeout: number;\n readonly #fetch: FetchLike;\n\n constructor(options: NoneCapOptions) {\n if (!options || !options.apiKey) {\n throw new NoneCapError(\n \"A NoneCap API key is required. Pass it as `new NoneCap({ apiKey })`.\",\n );\n }\n this.#apiKey = options.apiKey;\n this.#baseURL = (options.baseURL ?? DEFAULT_BASE_URL).replace(/\\/+$/, \"\");\n this.#timeout = options.timeout ?? 100_000;\n const f = options.fetch ?? (globalThis.fetch as FetchLike | undefined);\n if (!f) {\n throw new NoneCapError(\n \"No `fetch` available. Use Node 18+, or pass a `fetch` in the client options.\",\n );\n }\n this.#fetch = f;\n }\n\n /** Operations on solves. */\n readonly solves = {\n /** Submit a solve. Pass `{ wait }` to hold the connection until it finishes. */\n create: (params: SolveCreateParams, options: WaitOptions = {}): Promise<Solve> =>\n this.#request<Solve>(\"POST\", \"/v1/solves\", {\n body: params,\n query: { wait: options.wait },\n signal: options.signal,\n timeout: this.#timeoutForWait(options.wait),\n expect: [202],\n }),\n\n /** Fetch a solve by id. Pass `{ wait }` to long-poll until it finishes. */\n retrieve: (id: string, options: WaitOptions = {}): Promise<Solve> =>\n this.#request<Solve>(\"GET\", `/v1/solves/${encodeURIComponent(id)}`, {\n query: { wait: options.wait },\n signal: options.signal,\n timeout: this.#timeoutForWait(options.wait),\n expect: [202],\n }),\n\n /** Cancel a pending or in-flight solve. */\n cancel: (id: string, options: { signal?: AbortSignal } = {}): Promise<Solve> =>\n this.#request<Solve>(\"DELETE\", `/v1/solves/${encodeURIComponent(id)}`, {\n signal: options.signal,\n }),\n\n /**\n * Submit a solve and return a {@link SolveHandle} for it.\n *\n * Unlike {@link NoneCap.solve}, this returns as soon as the submission is\n * accepted, so `handle.id` is available immediately. Use the handle to\n * `cancel()` the solve or `await handle.result()` for the finished solve.\n *\n * ```ts\n * const handle = await nc.solves.start({ type: \"hcaptcha\", sitekey, url });\n * // ...later, e.g. on shutdown:\n * await handle.cancel();\n * // or wait for it:\n * const { token } = await handle.result();\n * ```\n */\n start: async (\n params: SolveCreateParams,\n options: SolveStartOptions = {},\n ): Promise<SolveHandle> => {\n const solve = await this.solves.create(params, { signal: options.signal });\n return new SolveHandle(this, solve);\n },\n\n /** Fetch one page of solves. */\n list: (params: SolveListParams = {}, options: { signal?: AbortSignal } = {}): Promise<SolveList> =>\n this.#request<SolveList>(\"GET\", \"/v1/solves\", {\n query: {\n limit: params.limit,\n starting_after: params.starting_after,\n status: params.status,\n type: params.type,\n },\n signal: options.signal,\n }),\n\n /**\n * Iterate every solve across pages, newest first.\n *\n * ```ts\n * for await (const solve of nc.solves.listAll()) { ... }\n * ```\n */\n listAll: (\n params: SolveListParams = {},\n options: { signal?: AbortSignal } = {},\n ): AsyncIterableIterator<Solve> => this.#listAll(params, options),\n };\n\n /**\n * Report what your downstream target did with the tokens we minted.\n *\n * Feedback is free, own-solves-only, and idempotent per solve id: reporting\n * the same solve again corrects the earlier verdict. Only `solved` solves can\n * be reported, and only within the API's reporting window (~30 days from the\n * solve; corrections to an already-reported solve are never re-gated by it).\n */\n readonly feedback = {\n /**\n * Report one solve's downstream outcome, returning the recorded feedback.\n *\n * Unlike {@link NoneCap.feedback.reportMany}, a rejected report throws:\n * {@link NotFoundError} if the solve isn't yours or never minted a token,\n * {@link ValidationError} if a field is wrong or the reporting window closed.\n *\n * ```ts\n * await nc.feedback.report({ solve_id: solve.id, outcome: \"rejected\", reason: \"...\" });\n * ```\n */\n report: (report: FeedbackReport, options: { signal?: AbortSignal } = {}): Promise<Feedback> => {\n const { solve_id, ...fields } = report;\n return this.#request<Feedback>(\n \"POST\",\n `/v1/solves/${encodeURIComponent(solve_id)}/feedback`,\n { body: toWireFields(fields), signal: options.signal },\n );\n },\n\n /**\n * Report many verdicts at once — the path to use at volume. Buffer verdicts\n * as you learn them and flush them here.\n *\n * The call succeeds even when individual items are rejected: each is\n * resolved on its own so one stale id never discards the rest. Check\n * `failed` rather than relying on a thrown error.\n *\n * More than {@link FEEDBACK_BATCH_MAX} reports are split across sequential\n * requests and merged into one result, in request order. An empty array is\n * a no-op that returns an empty batch without a request.\n *\n * ```ts\n * const batch = await nc.feedback.reportMany(buffer);\n * if (batch.failed) console.warn(batch.results.filter((r) => r.status === \"error\"));\n * ```\n */\n reportMany: async (\n reports: readonly FeedbackReport[],\n options: { signal?: AbortSignal } = {},\n ): Promise<FeedbackBatch> => {\n const merged: FeedbackBatch = {\n object: \"feedback_batch\",\n recorded: 0,\n updated: 0,\n unchanged: 0,\n failed: 0,\n results: [],\n };\n // Chunks are sent in order and the server upserts last-write-wins, so a\n // solve reported twice still ends at its last value. Duplicates split\n // across a chunk boundary each get written, though, so the earlier one\n // reports `recorded`/`updated` where a single request would say\n // `unchanged`.\n for (let i = 0; i < reports.length; i += FEEDBACK_BATCH_MAX) {\n const batch = await this.#request<FeedbackBatch>(\"POST\", \"/v1/feedback\", {\n body: { feedback: reports.slice(i, i + FEEDBACK_BATCH_MAX).map(toWireReport) },\n signal: options.signal,\n });\n merged.recorded += batch.recorded;\n merged.updated += batch.updated;\n merged.unchanged += batch.unchanged;\n merged.failed += batch.failed;\n merged.results.push(...batch.results);\n }\n return merged;\n },\n };\n\n /** Fetch your account, including the current credit balance. */\n me(options: { signal?: AbortSignal } = {}): Promise<Account> {\n return this.#request<Account>(\"GET\", \"/v1/me\", { signal: options.signal });\n }\n\n /**\n * Submit a solve and wait for it to finish, returning the solved solve.\n *\n * Uses the server's long-poll under the hood and keeps polling until the\n * solve is terminal or `timeout` elapses. Throws {@link SolveFailedError} if\n * the solve fails/expires/is cancelled, or {@link TimeoutError} on timeout.\n *\n * This is sugar for `(await solves.start(params)).result(options)`. When you\n * need to cancel the solve while it runs, use {@link NoneCap.solves.start}\n * and keep the {@link SolveHandle}.\n */\n async solve(params: SolveCreateParams, options: SolveHelperOptions = {}): Promise<Solve> {\n const handle = await this.solves.start(params, { signal: options.signal });\n return handle.result(options);\n }\n\n // -- internals ------------------------------------------------------------\n\n #timeoutForWait(wait?: number): number | undefined {\n if (wait === undefined) return undefined;\n // Give the socket a margin beyond the server's long-poll window.\n return wait * 1000 + 15_000;\n }\n\n async *#listAll(\n params: SolveListParams,\n options: { signal?: AbortSignal },\n ): AsyncIterableIterator<Solve> {\n let cursor = params.starting_after;\n for (;;) {\n const page = await this.solves.list({ ...params, starting_after: cursor }, options);\n for (const solve of page.data) yield solve;\n if (!page.has_more || page.data.length === 0) return;\n cursor = page.data[page.data.length - 1]!.id;\n }\n }\n\n async #request<T>(method: string, path: string, options: RequestOptions = {}): Promise<T> {\n const url = new URL(this.#baseURL + path);\n if (options.query) {\n for (const [key, value] of Object.entries(options.query)) {\n if (value !== undefined && value !== \"\") url.searchParams.set(key, String(value));\n }\n }\n\n const headers: Record<string, string> = {\n Authorization: `Bearer ${this.#apiKey}`,\n Accept: \"application/json\",\n // Browsers drop this as a forbidden header; on Node it identifies the SDK.\n \"User-Agent\": USER_AGENT,\n };\n let bodyInit: string | undefined;\n if (options.body !== undefined) {\n headers[\"Content-Type\"] = \"application/json\";\n bodyInit = JSON.stringify(options.body);\n }\n\n const controller = new AbortController();\n const timeoutMs = options.timeout ?? this.#timeout;\n const timer = setTimeout(() => controller.abort(new TimeoutError(`Request timed out after ${timeoutMs}ms.`)), timeoutMs);\n const onAbort = () => controller.abort(options.signal?.reason);\n if (options.signal) {\n if (options.signal.aborted) onAbort();\n else options.signal.addEventListener(\"abort\", onAbort, { once: true });\n }\n\n let res: Response;\n try {\n res = await this.#fetch(url.toString(), {\n method,\n headers,\n body: bodyInit,\n signal: controller.signal,\n });\n } catch (err) {\n if (err instanceof TimeoutError) throw err;\n if (isAbort(err)) {\n // A caller-supplied signal aborting surfaces as the caller's reason.\n if (options.signal?.aborted) throw options.signal.reason instanceof Error\n ? options.signal.reason\n : new NoneCapError(\"Request aborted.\");\n throw new TimeoutError(`Request timed out after ${timeoutMs}ms.`);\n }\n throw new ConnectionError(\n `Could not reach the NoneCap API at ${this.#baseURL}: ${(err as Error).message}`,\n );\n } finally {\n clearTimeout(timer);\n options.signal?.removeEventListener(\"abort\", onAbort);\n }\n\n return this.#parse<T>(res, options.expect ?? []);\n }\n\n async #parse<T>(res: Response, expect: number[]): Promise<T> {\n const text = await res.text();\n let json: unknown;\n if (text) {\n try {\n json = JSON.parse(text);\n } catch {\n throw new APIError(\n `Unexpected non-JSON response (HTTP ${res.status}): ${text.slice(0, 200)}`,\n { status: res.status },\n );\n }\n }\n\n if (res.ok || expect.includes(res.status)) {\n return json as T;\n }\n\n const envelope = json as\n | { error?: { code?: ErrorCode; message?: string; param?: string | null; request_id?: string } }\n | undefined;\n const apiError = envelope?.error;\n const retryAfterRaw = res.headers.get(\"retry-after\");\n const retryAfter = retryAfterRaw !== null && /^\\d+$/.test(retryAfterRaw) ? Number(retryAfterRaw) : undefined;\n throw errorFromResponse(\n res.status,\n apiError?.code,\n apiError?.message ?? `HTTP ${res.status}`,\n apiError?.param ?? null,\n { requestId: apiError?.request_id ?? res.headers.get(\"x-request-id\") ?? undefined, retryAfter },\n );\n }\n}\n\n/**\n * A handle on a started solve, returned by {@link NoneCap.solves.start}.\n *\n * The handle is the cancellable lifecycle object for one solve. It is a plain\n * object, not a promise: `await`ing it does nothing useful. Wait for the result\n * with {@link SolveHandle.result}, and cancel with {@link SolveHandle.cancel}.\n * You do not construct it yourself — `solves.start()` hands you one with `id`\n * already resolved.\n */\nexport class SolveHandle {\n /** The id of the started solve, available as soon as `start()` resolved. */\n readonly id: string;\n\n readonly #client: NoneCap;\n /** The latest solve state we have seen, from the create, polls, or cancel. */\n #solve: Solve;\n /**\n * The cached TERMINAL outcome: resolves to the solved solve, or rejects with\n * {@link SolveFailedError} if terminal-but-not-solved. Only ever set once the\n * solve actually reaches a terminal state, so it is safe to replay forever. A\n * timed-out wait does NOT settle this — it is retryable.\n */\n #terminal: Promise<Solve> | undefined;\n /** The poll currently in flight, shared by concurrent result() callers. */\n #inflight: Promise<Solve> | undefined;\n\n constructor(client: NoneCap, solve: Solve) {\n this.#client = client;\n this.#solve = solve;\n this.id = solve.id;\n }\n\n /** The last-known solve state for this handle. */\n get solve(): Solve {\n return this.#solve;\n }\n\n /**\n * Long-poll until the solve is terminal, returning the solved solve. Throws\n * {@link SolveFailedError} if it fails/expires/is cancelled, or\n * {@link TimeoutError} on timeout (with `solveId`/`solve` attached so you can\n * still {@link SolveHandle.cancel} it).\n *\n * Memoizes the *terminal* outcome: once the solve actually finishes, every\n * later call returns that same settled result. A {@link TimeoutError} is not\n * memoized — it just means this wait gave up, so a later call (e.g. with a\n * larger `timeout`) resumes polling. Concurrent calls share one in-flight\n * poll, so they never issue duplicate requests. The first caller's\n * `timeout`/`signal` drive the shared poll; a later call starts a fresh one.\n */\n result(options: SolveHelperOptions = {}): Promise<Solve> {\n if (this.#terminal) return this.#terminal;\n if (this.#inflight) return this.#inflight;\n const run = this.#poll(options).finally(() => {\n // Free the slot so a retry can re-poll after a timeout; a terminal\n // outcome is already memoized in #terminal and wins on the next call.\n if (this.#inflight === run) this.#inflight = undefined;\n });\n this.#inflight = run;\n return run;\n }\n\n /**\n * Cancel the solve. Cancelled solves are never charged, so this is for clean\n * shutdown / freeing slots / stopping early, not cost protection.\n *\n * If the solve already reached a terminal state the API answers 409; that is\n * not an error a caller cares about, so this swallows {@link ConflictError}\n * and returns the current solve state instead. A cancel that lands on a\n * terminal state (cancelled, or whatever the 409-swallow read back) settles\n * this handle's {@link SolveHandle.result}, so any in-flight or later wait\n * stops polling and reflects that terminal state.\n */\n async cancel(options: { signal?: AbortSignal } = {}): Promise<Solve> {\n try {\n this.#solve = await this.#client.solves.cancel(this.id, options);\n } catch (err) {\n if (!(err instanceof ConflictError)) throw err;\n // Already terminal — report the real state rather than the 409.\n this.#solve = await this.#client.solves.retrieve(this.id, options);\n }\n if (!this.#terminal && isTerminal(this.#solve.status)) this.#cacheTerminal();\n return this.#solve;\n }\n\n /**\n * Build and memoize the terminal outcome from the current `#solve`. The\n * precondition is that `#solve` is terminal and `#terminal` is unset.\n */\n #cacheTerminal(): Promise<Solve> {\n const settled =\n this.#solve.status === \"solved\"\n ? Promise.resolve(this.#solve)\n : Promise.reject(new SolveFailedError(this.#solve));\n // Never let the memoized rejection surface as an unhandled rejection; real\n // callers read it explicitly through result().\n settled.catch(() => {});\n this.#terminal = settled;\n return settled;\n }\n\n async #poll(options: SolveHelperOptions): Promise<Solve> {\n const timeout = options.timeout ?? 180_000;\n const deadline = Date.now() + timeout;\n\n for (;;) {\n // cancel() (or a previous poll) may have already settled this handle.\n if (this.#terminal) return this.#terminal;\n if (isTerminal(this.#solve.status)) return this.#cacheTerminal();\n if (Date.now() >= deadline) {\n throw new TimeoutError(\n `Solve ${this.id} did not finish within ${timeout}ms (last status: ${this.#solve.status}).`,\n { solveId: this.id, solve: this.#solve },\n );\n }\n this.#solve = await this.#client.solves.retrieve(this.id, {\n wait: waitSeconds(deadline),\n signal: options.signal,\n });\n }\n }\n}\n\n/**\n * The `wait` value for the next long-poll: whole seconds until `deadline`,\n * clamped to the server's 1–90 window. The floor of 1 keeps the param valid,\n * so callers must decide whether the deadline has passed with the clock, not\n * with this return value.\n */\nfunction waitSeconds(deadline: number): number {\n const remaining = Math.ceil((deadline - Date.now()) / 1000);\n return Math.max(1, Math.min(MAX_WAIT_SECONDS, remaining));\n}\n\nfunction isAbort(err: unknown): boolean {\n return err instanceof Error && err.name === \"AbortError\";\n}\n\n/** The fields of a report, ready for the wire: a `Date` becomes an ISO string. */\nfunction toWireFields(fields: Omit<FeedbackReport, \"solve_id\">): Record<string, unknown> {\n const wire: Record<string, unknown> = { outcome: fields.outcome };\n if (fields.reason !== undefined) wire.reason = fields.reason;\n if (fields.context !== undefined) wire.context = fields.context;\n if (fields.reported_at !== undefined) {\n wire.reported_at =\n fields.reported_at instanceof Date ? fields.reported_at.toISOString() : fields.reported_at;\n }\n return wire;\n}\n\nfunction toWireReport(report: FeedbackReport): Record<string, unknown> {\n const { solve_id, ...fields } = report;\n return { solve_id, ...toWireFields(fields) };\n}\n"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -50,10 +50,36 @@ type SolveCreateParams = (SolveCreateBase & {
|
|
|
50
50
|
type: "hcaptcha_enterprise";
|
|
51
51
|
rqdata: string;
|
|
52
52
|
});
|
|
53
|
+
/** Why a solve did not produce a token. `expired` and `cancelled` are statuses
|
|
54
|
+
* the API reports through the same object. */
|
|
55
|
+
type SolveErrorCode = "challenge_not_loaded" | "token_not_granted" | "challenge_expired" | "challenge_errored" | "proxy_error" | "target_unreachable" | "vision_error" | "internal_error" | "unsolvable_variant" | "capacity_exhausted" | "cancelled" | "expired";
|
|
56
|
+
/** A typed sub-reason within {@link SolveErrorCode}, set when the solver knows
|
|
57
|
+
* more than the code says. */
|
|
58
|
+
type SolveErrorReason =
|
|
59
|
+
/** hCaptcha answered 429 before serving a challenge. */
|
|
60
|
+
"sitekey_rate_limited"
|
|
61
|
+
/** The sitekey passes without a challenge and issued no token this time. */
|
|
62
|
+
| "passive_required"
|
|
63
|
+
/** hCaptcha kept serving challenges without accepting an answer. */
|
|
64
|
+
| "rounds_exhausted"
|
|
65
|
+
/** Your proxy refused the connection (credentials or source IP). */
|
|
66
|
+
| "proxy_rejected"
|
|
67
|
+
/** Your proxy intercepts or rewrites TLS. */
|
|
68
|
+
| "proxy_tls"
|
|
69
|
+
/** Your proxy accepted the connection but never answered within the deadline. */
|
|
70
|
+
| "proxy_stalled";
|
|
53
71
|
/** The error attached to a solve that did not succeed. */
|
|
54
72
|
interface SolveError {
|
|
55
|
-
|
|
73
|
+
/** Codes the API may add later still arrive; narrow with a switch and keep a default. */
|
|
74
|
+
code: SolveErrorCode | (string & {});
|
|
75
|
+
/** What happened, what to do, and whether the solve was charged. */
|
|
56
76
|
message: string;
|
|
77
|
+
/** Typed sub-reason, or null when the code says it all. */
|
|
78
|
+
reason: SolveErrorReason | (string & {}) | null;
|
|
79
|
+
/** Whether re-submitting the same request unchanged can succeed. */
|
|
80
|
+
retryable: boolean;
|
|
81
|
+
/** Reference for the codes and reasons. */
|
|
82
|
+
docs_url: string;
|
|
57
83
|
}
|
|
58
84
|
/** A solve resource. */
|
|
59
85
|
interface Solve {
|
|
@@ -213,13 +239,21 @@ type ErrorCode = "unauthorized" | "forbidden" | "account_locked" | "insufficient
|
|
|
213
239
|
/** Feedback: the solve is missing, not yours, or never produced a token. */
|
|
214
240
|
| "not_eligible"
|
|
215
241
|
/** Feedback: a first report arrived after the reporting window closed. */
|
|
216
|
-
| "expired_window"
|
|
242
|
+
| "expired_window"
|
|
243
|
+
/** 503: new solves are paused for maintenance. Retry shortly. */
|
|
244
|
+
| "maintenance"
|
|
245
|
+
/** 413: the request body exceeds the route's size limit. */
|
|
246
|
+
| "payload_too_large"
|
|
247
|
+
/** 415: a JSON route was called without `Content-Type: application/json`. */
|
|
248
|
+
| "unsupported_media_type" | "internal_error";
|
|
217
249
|
/** The Stripe-style error envelope every non-2xx response carries. */
|
|
218
250
|
interface ErrorEnvelope {
|
|
219
251
|
error: {
|
|
220
252
|
code: ErrorCode;
|
|
221
253
|
message: string;
|
|
222
254
|
param: string | null;
|
|
255
|
+
/** Correlation id for support; also the `X-Request-Id` response header. */
|
|
256
|
+
request_id?: string;
|
|
223
257
|
};
|
|
224
258
|
}
|
|
225
259
|
|
|
@@ -440,10 +474,16 @@ declare class NoneCapError extends Error {
|
|
|
440
474
|
readonly status: number | undefined;
|
|
441
475
|
/** The request field that was rejected, for validation errors. */
|
|
442
476
|
readonly param: string | null;
|
|
477
|
+
/** The API's correlation id for this request (`X-Request-Id`); quote it to support. */
|
|
478
|
+
readonly requestId: string | undefined;
|
|
479
|
+
/** Seconds to wait before retrying, when the API sent `Retry-After`. */
|
|
480
|
+
readonly retryAfter: number | undefined;
|
|
443
481
|
constructor(message: string, opts?: {
|
|
444
482
|
code?: ErrorCode;
|
|
445
483
|
status?: number;
|
|
446
484
|
param?: string | null;
|
|
485
|
+
requestId?: string;
|
|
486
|
+
retryAfter?: number;
|
|
447
487
|
});
|
|
448
488
|
}
|
|
449
489
|
/** 401 — the API key is missing, malformed, or revoked. */
|
|
@@ -455,21 +495,40 @@ declare class PermissionError extends NoneCapError {
|
|
|
455
495
|
/** 402 — the account is out of credits. */
|
|
456
496
|
declare class InsufficientCreditsError extends NoneCapError {
|
|
457
497
|
}
|
|
498
|
+
/** 402 — this API key reached its own credit limit (the account may still have credits). */
|
|
499
|
+
declare class KeyCreditLimitError extends InsufficientCreditsError {
|
|
500
|
+
}
|
|
458
501
|
/** 422 / 400 — the request was rejected. `param` names the offending field. */
|
|
459
502
|
declare class ValidationError extends NoneCapError {
|
|
460
503
|
}
|
|
504
|
+
/** 413 — the request body exceeds the route's size limit. */
|
|
505
|
+
declare class PayloadTooLargeError extends ValidationError {
|
|
506
|
+
}
|
|
507
|
+
/** 415 — a JSON route was called without `Content-Type: application/json`. */
|
|
508
|
+
declare class UnsupportedMediaTypeError extends ValidationError {
|
|
509
|
+
}
|
|
461
510
|
/** 404 — no such resource. */
|
|
462
511
|
declare class NotFoundError extends NoneCapError {
|
|
463
512
|
}
|
|
464
513
|
/** 409 — the solve is already in a terminal state (e.g. cancelling a finished solve). */
|
|
465
514
|
declare class ConflictError extends NoneCapError {
|
|
466
515
|
}
|
|
467
|
-
/** 429 —
|
|
516
|
+
/** 429 — back off and retry; `retryAfter` (seconds) is set when the API sent it. */
|
|
468
517
|
declare class RateLimitError extends NoneCapError {
|
|
469
518
|
}
|
|
470
|
-
/**
|
|
519
|
+
/** 429 — too many solves in flight for this account. Wait for one to finish. */
|
|
520
|
+
declare class ConcurrencyLimitError extends RateLimitError {
|
|
521
|
+
}
|
|
522
|
+
/** 429 — hCaptcha is refusing challenges for this sitekey, so the submit was shed.
|
|
523
|
+
* Wait `retryAfter` seconds; the message says whether a different proxy pool can help. */
|
|
524
|
+
declare class SitekeyRateLimitedError extends RateLimitError {
|
|
525
|
+
}
|
|
526
|
+
/** 5xx, or a response that wasn't the expected shape. `requestId` is the id to quote. */
|
|
471
527
|
declare class APIError extends NoneCapError {
|
|
472
528
|
}
|
|
529
|
+
/** 503 — new solves are paused for maintenance. Retry shortly. */
|
|
530
|
+
declare class ServiceUnavailableError extends APIError {
|
|
531
|
+
}
|
|
473
532
|
/** The request never reached the API (DNS, TCP, TLS, timeout, offline). */
|
|
474
533
|
declare class ConnectionError extends NoneCapError {
|
|
475
534
|
}
|
|
@@ -481,6 +540,12 @@ declare class ConnectionError extends NoneCapError {
|
|
|
481
540
|
declare class SolveFailedError extends NoneCapError {
|
|
482
541
|
readonly solve: Solve;
|
|
483
542
|
constructor(solve: Solve);
|
|
543
|
+
/** `solve.error.code`, e.g. `proxy_error`; the status when no error object came back. */
|
|
544
|
+
get solveCode(): string;
|
|
545
|
+
/** `solve.error.reason`, the typed sub-reason, or null. */
|
|
546
|
+
get reason(): string | null;
|
|
547
|
+
/** Whether re-submitting the same request unchanged can succeed. */
|
|
548
|
+
get retryable(): boolean;
|
|
484
549
|
}
|
|
485
550
|
/**
|
|
486
551
|
* Thrown by {@link NoneCap.solve} (and {@link SolveHandle.result}) when the
|
|
@@ -502,4 +567,4 @@ declare class TimeoutError extends NoneCapError {
|
|
|
502
567
|
});
|
|
503
568
|
}
|
|
504
569
|
|
|
505
|
-
export { APIError, type Account, AuthenticationError, ConflictError, ConnectionError, type ErrorCode, type ErrorEnvelope, FEEDBACK_BATCH_MAX, type Feedback, type FeedbackBatch, type FeedbackOutcome, type FeedbackReport, type FeedbackResult, type FeedbackStatus, type FetchLike, InsufficientCreditsError, NoneCap, NoneCapError, type NoneCapOptions, NotFoundError, PermissionError, type Proxy, RateLimitError, type Solve, type SolveCreateParams, type SolveError, SolveFailedError, SolveHandle, type SolveHelperOptions, type SolveList, type SolveListParams, type SolveStartOptions, type SolveStatus, type SolveType, TimeoutError, ValidationError, type WaitOptions, isTerminal };
|
|
570
|
+
export { APIError, type Account, AuthenticationError, ConcurrencyLimitError, ConflictError, ConnectionError, type ErrorCode, type ErrorEnvelope, FEEDBACK_BATCH_MAX, type Feedback, type FeedbackBatch, type FeedbackOutcome, type FeedbackReport, type FeedbackResult, type FeedbackStatus, type FetchLike, InsufficientCreditsError, KeyCreditLimitError, NoneCap, NoneCapError, type NoneCapOptions, NotFoundError, PayloadTooLargeError, PermissionError, type Proxy, RateLimitError, ServiceUnavailableError, SitekeyRateLimitedError, type Solve, type SolveCreateParams, type SolveError, type SolveErrorCode, type SolveErrorReason, SolveFailedError, SolveHandle, type SolveHelperOptions, type SolveList, type SolveListParams, type SolveStartOptions, type SolveStatus, type SolveType, TimeoutError, UnsupportedMediaTypeError, ValidationError, type WaitOptions, isTerminal };
|
package/dist/index.d.ts
CHANGED
|
@@ -50,10 +50,36 @@ type SolveCreateParams = (SolveCreateBase & {
|
|
|
50
50
|
type: "hcaptcha_enterprise";
|
|
51
51
|
rqdata: string;
|
|
52
52
|
});
|
|
53
|
+
/** Why a solve did not produce a token. `expired` and `cancelled` are statuses
|
|
54
|
+
* the API reports through the same object. */
|
|
55
|
+
type SolveErrorCode = "challenge_not_loaded" | "token_not_granted" | "challenge_expired" | "challenge_errored" | "proxy_error" | "target_unreachable" | "vision_error" | "internal_error" | "unsolvable_variant" | "capacity_exhausted" | "cancelled" | "expired";
|
|
56
|
+
/** A typed sub-reason within {@link SolveErrorCode}, set when the solver knows
|
|
57
|
+
* more than the code says. */
|
|
58
|
+
type SolveErrorReason =
|
|
59
|
+
/** hCaptcha answered 429 before serving a challenge. */
|
|
60
|
+
"sitekey_rate_limited"
|
|
61
|
+
/** The sitekey passes without a challenge and issued no token this time. */
|
|
62
|
+
| "passive_required"
|
|
63
|
+
/** hCaptcha kept serving challenges without accepting an answer. */
|
|
64
|
+
| "rounds_exhausted"
|
|
65
|
+
/** Your proxy refused the connection (credentials or source IP). */
|
|
66
|
+
| "proxy_rejected"
|
|
67
|
+
/** Your proxy intercepts or rewrites TLS. */
|
|
68
|
+
| "proxy_tls"
|
|
69
|
+
/** Your proxy accepted the connection but never answered within the deadline. */
|
|
70
|
+
| "proxy_stalled";
|
|
53
71
|
/** The error attached to a solve that did not succeed. */
|
|
54
72
|
interface SolveError {
|
|
55
|
-
|
|
73
|
+
/** Codes the API may add later still arrive; narrow with a switch and keep a default. */
|
|
74
|
+
code: SolveErrorCode | (string & {});
|
|
75
|
+
/** What happened, what to do, and whether the solve was charged. */
|
|
56
76
|
message: string;
|
|
77
|
+
/** Typed sub-reason, or null when the code says it all. */
|
|
78
|
+
reason: SolveErrorReason | (string & {}) | null;
|
|
79
|
+
/** Whether re-submitting the same request unchanged can succeed. */
|
|
80
|
+
retryable: boolean;
|
|
81
|
+
/** Reference for the codes and reasons. */
|
|
82
|
+
docs_url: string;
|
|
57
83
|
}
|
|
58
84
|
/** A solve resource. */
|
|
59
85
|
interface Solve {
|
|
@@ -213,13 +239,21 @@ type ErrorCode = "unauthorized" | "forbidden" | "account_locked" | "insufficient
|
|
|
213
239
|
/** Feedback: the solve is missing, not yours, or never produced a token. */
|
|
214
240
|
| "not_eligible"
|
|
215
241
|
/** Feedback: a first report arrived after the reporting window closed. */
|
|
216
|
-
| "expired_window"
|
|
242
|
+
| "expired_window"
|
|
243
|
+
/** 503: new solves are paused for maintenance. Retry shortly. */
|
|
244
|
+
| "maintenance"
|
|
245
|
+
/** 413: the request body exceeds the route's size limit. */
|
|
246
|
+
| "payload_too_large"
|
|
247
|
+
/** 415: a JSON route was called without `Content-Type: application/json`. */
|
|
248
|
+
| "unsupported_media_type" | "internal_error";
|
|
217
249
|
/** The Stripe-style error envelope every non-2xx response carries. */
|
|
218
250
|
interface ErrorEnvelope {
|
|
219
251
|
error: {
|
|
220
252
|
code: ErrorCode;
|
|
221
253
|
message: string;
|
|
222
254
|
param: string | null;
|
|
255
|
+
/** Correlation id for support; also the `X-Request-Id` response header. */
|
|
256
|
+
request_id?: string;
|
|
223
257
|
};
|
|
224
258
|
}
|
|
225
259
|
|
|
@@ -440,10 +474,16 @@ declare class NoneCapError extends Error {
|
|
|
440
474
|
readonly status: number | undefined;
|
|
441
475
|
/** The request field that was rejected, for validation errors. */
|
|
442
476
|
readonly param: string | null;
|
|
477
|
+
/** The API's correlation id for this request (`X-Request-Id`); quote it to support. */
|
|
478
|
+
readonly requestId: string | undefined;
|
|
479
|
+
/** Seconds to wait before retrying, when the API sent `Retry-After`. */
|
|
480
|
+
readonly retryAfter: number | undefined;
|
|
443
481
|
constructor(message: string, opts?: {
|
|
444
482
|
code?: ErrorCode;
|
|
445
483
|
status?: number;
|
|
446
484
|
param?: string | null;
|
|
485
|
+
requestId?: string;
|
|
486
|
+
retryAfter?: number;
|
|
447
487
|
});
|
|
448
488
|
}
|
|
449
489
|
/** 401 — the API key is missing, malformed, or revoked. */
|
|
@@ -455,21 +495,40 @@ declare class PermissionError extends NoneCapError {
|
|
|
455
495
|
/** 402 — the account is out of credits. */
|
|
456
496
|
declare class InsufficientCreditsError extends NoneCapError {
|
|
457
497
|
}
|
|
498
|
+
/** 402 — this API key reached its own credit limit (the account may still have credits). */
|
|
499
|
+
declare class KeyCreditLimitError extends InsufficientCreditsError {
|
|
500
|
+
}
|
|
458
501
|
/** 422 / 400 — the request was rejected. `param` names the offending field. */
|
|
459
502
|
declare class ValidationError extends NoneCapError {
|
|
460
503
|
}
|
|
504
|
+
/** 413 — the request body exceeds the route's size limit. */
|
|
505
|
+
declare class PayloadTooLargeError extends ValidationError {
|
|
506
|
+
}
|
|
507
|
+
/** 415 — a JSON route was called without `Content-Type: application/json`. */
|
|
508
|
+
declare class UnsupportedMediaTypeError extends ValidationError {
|
|
509
|
+
}
|
|
461
510
|
/** 404 — no such resource. */
|
|
462
511
|
declare class NotFoundError extends NoneCapError {
|
|
463
512
|
}
|
|
464
513
|
/** 409 — the solve is already in a terminal state (e.g. cancelling a finished solve). */
|
|
465
514
|
declare class ConflictError extends NoneCapError {
|
|
466
515
|
}
|
|
467
|
-
/** 429 —
|
|
516
|
+
/** 429 — back off and retry; `retryAfter` (seconds) is set when the API sent it. */
|
|
468
517
|
declare class RateLimitError extends NoneCapError {
|
|
469
518
|
}
|
|
470
|
-
/**
|
|
519
|
+
/** 429 — too many solves in flight for this account. Wait for one to finish. */
|
|
520
|
+
declare class ConcurrencyLimitError extends RateLimitError {
|
|
521
|
+
}
|
|
522
|
+
/** 429 — hCaptcha is refusing challenges for this sitekey, so the submit was shed.
|
|
523
|
+
* Wait `retryAfter` seconds; the message says whether a different proxy pool can help. */
|
|
524
|
+
declare class SitekeyRateLimitedError extends RateLimitError {
|
|
525
|
+
}
|
|
526
|
+
/** 5xx, or a response that wasn't the expected shape. `requestId` is the id to quote. */
|
|
471
527
|
declare class APIError extends NoneCapError {
|
|
472
528
|
}
|
|
529
|
+
/** 503 — new solves are paused for maintenance. Retry shortly. */
|
|
530
|
+
declare class ServiceUnavailableError extends APIError {
|
|
531
|
+
}
|
|
473
532
|
/** The request never reached the API (DNS, TCP, TLS, timeout, offline). */
|
|
474
533
|
declare class ConnectionError extends NoneCapError {
|
|
475
534
|
}
|
|
@@ -481,6 +540,12 @@ declare class ConnectionError extends NoneCapError {
|
|
|
481
540
|
declare class SolveFailedError extends NoneCapError {
|
|
482
541
|
readonly solve: Solve;
|
|
483
542
|
constructor(solve: Solve);
|
|
543
|
+
/** `solve.error.code`, e.g. `proxy_error`; the status when no error object came back. */
|
|
544
|
+
get solveCode(): string;
|
|
545
|
+
/** `solve.error.reason`, the typed sub-reason, or null. */
|
|
546
|
+
get reason(): string | null;
|
|
547
|
+
/** Whether re-submitting the same request unchanged can succeed. */
|
|
548
|
+
get retryable(): boolean;
|
|
484
549
|
}
|
|
485
550
|
/**
|
|
486
551
|
* Thrown by {@link NoneCap.solve} (and {@link SolveHandle.result}) when the
|
|
@@ -502,4 +567,4 @@ declare class TimeoutError extends NoneCapError {
|
|
|
502
567
|
});
|
|
503
568
|
}
|
|
504
569
|
|
|
505
|
-
export { APIError, type Account, AuthenticationError, ConflictError, ConnectionError, type ErrorCode, type ErrorEnvelope, FEEDBACK_BATCH_MAX, type Feedback, type FeedbackBatch, type FeedbackOutcome, type FeedbackReport, type FeedbackResult, type FeedbackStatus, type FetchLike, InsufficientCreditsError, NoneCap, NoneCapError, type NoneCapOptions, NotFoundError, PermissionError, type Proxy, RateLimitError, type Solve, type SolveCreateParams, type SolveError, SolveFailedError, SolveHandle, type SolveHelperOptions, type SolveList, type SolveListParams, type SolveStartOptions, type SolveStatus, type SolveType, TimeoutError, ValidationError, type WaitOptions, isTerminal };
|
|
570
|
+
export { APIError, type Account, AuthenticationError, ConcurrencyLimitError, ConflictError, ConnectionError, type ErrorCode, type ErrorEnvelope, FEEDBACK_BATCH_MAX, type Feedback, type FeedbackBatch, type FeedbackOutcome, type FeedbackReport, type FeedbackResult, type FeedbackStatus, type FetchLike, InsufficientCreditsError, KeyCreditLimitError, NoneCap, NoneCapError, type NoneCapOptions, NotFoundError, PayloadTooLargeError, PermissionError, type Proxy, RateLimitError, ServiceUnavailableError, SitekeyRateLimitedError, type Solve, type SolveCreateParams, type SolveError, type SolveErrorCode, type SolveErrorReason, SolveFailedError, SolveHandle, type SolveHelperOptions, type SolveList, type SolveListParams, type SolveStartOptions, type SolveStatus, type SolveType, TimeoutError, UnsupportedMediaTypeError, ValidationError, type WaitOptions, isTerminal };
|
package/dist/index.js
CHANGED
|
@@ -6,12 +6,18 @@ var NoneCapError = class extends Error {
|
|
|
6
6
|
status;
|
|
7
7
|
/** The request field that was rejected, for validation errors. */
|
|
8
8
|
param;
|
|
9
|
+
/** The API's correlation id for this request (`X-Request-Id`); quote it to support. */
|
|
10
|
+
requestId;
|
|
11
|
+
/** Seconds to wait before retrying, when the API sent `Retry-After`. */
|
|
12
|
+
retryAfter;
|
|
9
13
|
constructor(message, opts = {}) {
|
|
10
14
|
super(message);
|
|
11
15
|
this.name = new.target.name;
|
|
12
16
|
this.code = opts.code;
|
|
13
17
|
this.status = opts.status;
|
|
14
18
|
this.param = opts.param ?? null;
|
|
19
|
+
this.requestId = opts.requestId;
|
|
20
|
+
this.retryAfter = opts.retryAfter;
|
|
15
21
|
Object.setPrototypeOf(this, new.target.prototype);
|
|
16
22
|
}
|
|
17
23
|
};
|
|
@@ -21,16 +27,28 @@ var PermissionError = class extends NoneCapError {
|
|
|
21
27
|
};
|
|
22
28
|
var InsufficientCreditsError = class extends NoneCapError {
|
|
23
29
|
};
|
|
30
|
+
var KeyCreditLimitError = class extends InsufficientCreditsError {
|
|
31
|
+
};
|
|
24
32
|
var ValidationError = class extends NoneCapError {
|
|
25
33
|
};
|
|
34
|
+
var PayloadTooLargeError = class extends ValidationError {
|
|
35
|
+
};
|
|
36
|
+
var UnsupportedMediaTypeError = class extends ValidationError {
|
|
37
|
+
};
|
|
26
38
|
var NotFoundError = class extends NoneCapError {
|
|
27
39
|
};
|
|
28
40
|
var ConflictError = class extends NoneCapError {
|
|
29
41
|
};
|
|
30
42
|
var RateLimitError = class extends NoneCapError {
|
|
31
43
|
};
|
|
44
|
+
var ConcurrencyLimitError = class extends RateLimitError {
|
|
45
|
+
};
|
|
46
|
+
var SitekeyRateLimitedError = class extends RateLimitError {
|
|
47
|
+
};
|
|
32
48
|
var APIError = class extends NoneCapError {
|
|
33
49
|
};
|
|
50
|
+
var ServiceUnavailableError = class extends APIError {
|
|
51
|
+
};
|
|
34
52
|
var ConnectionError = class extends NoneCapError {
|
|
35
53
|
};
|
|
36
54
|
var SolveFailedError = class extends NoneCapError {
|
|
@@ -43,6 +61,18 @@ var SolveFailedError = class extends NoneCapError {
|
|
|
43
61
|
});
|
|
44
62
|
this.solve = solve;
|
|
45
63
|
}
|
|
64
|
+
/** `solve.error.code`, e.g. `proxy_error`; the status when no error object came back. */
|
|
65
|
+
get solveCode() {
|
|
66
|
+
return this.solve.error?.code ?? this.solve.status;
|
|
67
|
+
}
|
|
68
|
+
/** `solve.error.reason`, the typed sub-reason, or null. */
|
|
69
|
+
get reason() {
|
|
70
|
+
return this.solve.error?.reason ?? null;
|
|
71
|
+
}
|
|
72
|
+
/** Whether re-submitting the same request unchanged can succeed. */
|
|
73
|
+
get retryable() {
|
|
74
|
+
return this.solve.error?.retryable ?? false;
|
|
75
|
+
}
|
|
46
76
|
};
|
|
47
77
|
var TimeoutError = class extends NoneCapError {
|
|
48
78
|
/** The id of the in-flight solve, when the timeout came from a solve wait. */
|
|
@@ -55,8 +85,8 @@ var TimeoutError = class extends NoneCapError {
|
|
|
55
85
|
this.solve = opts.solve;
|
|
56
86
|
}
|
|
57
87
|
};
|
|
58
|
-
function errorFromResponse(status, code, message, param) {
|
|
59
|
-
const opts = { code, status, param };
|
|
88
|
+
function errorFromResponse(status, code, message, param, extra = {}) {
|
|
89
|
+
const opts = { code, status, param, ...extra };
|
|
60
90
|
switch (code) {
|
|
61
91
|
case "unauthorized":
|
|
62
92
|
return new AuthenticationError(message, opts);
|
|
@@ -64,29 +94,38 @@ function errorFromResponse(status, code, message, param) {
|
|
|
64
94
|
case "account_locked":
|
|
65
95
|
return new PermissionError(message, opts);
|
|
66
96
|
case "insufficient_credits":
|
|
67
|
-
case "key_credit_limit_exceeded":
|
|
68
97
|
return new InsufficientCreditsError(message, opts);
|
|
98
|
+
case "key_credit_limit_exceeded":
|
|
99
|
+
return new KeyCreditLimitError(message, opts);
|
|
69
100
|
case "invalid_request":
|
|
70
101
|
case "validation_error":
|
|
71
102
|
case "expired_window":
|
|
72
103
|
return new ValidationError(message, opts);
|
|
104
|
+
case "payload_too_large":
|
|
105
|
+
return new PayloadTooLargeError(message, opts);
|
|
106
|
+
case "unsupported_media_type":
|
|
107
|
+
return new UnsupportedMediaTypeError(message, opts);
|
|
73
108
|
case "not_found":
|
|
74
109
|
case "not_eligible":
|
|
75
110
|
return new NotFoundError(message, opts);
|
|
76
111
|
case "conflict":
|
|
77
112
|
return new ConflictError(message, opts);
|
|
78
|
-
case "rate_limited":
|
|
79
113
|
case "concurrency_limit_exceeded":
|
|
80
|
-
|
|
114
|
+
return new ConcurrencyLimitError(message, opts);
|
|
81
115
|
case "sitekey_rate_limited":
|
|
116
|
+
return new SitekeyRateLimitedError(message, opts);
|
|
117
|
+
case "rate_limited":
|
|
118
|
+
case "ext_daily_limit":
|
|
82
119
|
return new RateLimitError(message, opts);
|
|
120
|
+
case "maintenance":
|
|
121
|
+
return new ServiceUnavailableError(message, opts);
|
|
83
122
|
default:
|
|
84
123
|
return new APIError(message, opts);
|
|
85
124
|
}
|
|
86
125
|
}
|
|
87
126
|
|
|
88
127
|
// src/version.ts
|
|
89
|
-
var VERSION = "0.
|
|
128
|
+
var VERSION = "0.7.0";
|
|
90
129
|
|
|
91
130
|
// src/client.ts
|
|
92
131
|
var DEFAULT_BASE_URL = "https://api.nonecap.com";
|
|
@@ -351,11 +390,14 @@ var NoneCap = class {
|
|
|
351
390
|
}
|
|
352
391
|
const envelope = json;
|
|
353
392
|
const apiError = envelope?.error;
|
|
393
|
+
const retryAfterRaw = res.headers.get("retry-after");
|
|
394
|
+
const retryAfter = retryAfterRaw !== null && /^\d+$/.test(retryAfterRaw) ? Number(retryAfterRaw) : void 0;
|
|
354
395
|
throw errorFromResponse(
|
|
355
396
|
res.status,
|
|
356
397
|
apiError?.code,
|
|
357
398
|
apiError?.message ?? `HTTP ${res.status}`,
|
|
358
|
-
apiError?.param ?? null
|
|
399
|
+
apiError?.param ?? null,
|
|
400
|
+
{ requestId: apiError?.request_id ?? res.headers.get("x-request-id") ?? void 0, retryAfter }
|
|
359
401
|
);
|
|
360
402
|
}
|
|
361
403
|
};
|
|
@@ -477,6 +519,6 @@ function toWireReport(report) {
|
|
|
477
519
|
return { solve_id, ...toWireFields(fields) };
|
|
478
520
|
}
|
|
479
521
|
|
|
480
|
-
export { APIError, AuthenticationError, ConflictError, ConnectionError, FEEDBACK_BATCH_MAX, InsufficientCreditsError, NoneCap, NoneCapError, NotFoundError, PermissionError, RateLimitError, SolveFailedError, SolveHandle, TimeoutError, ValidationError, isTerminal };
|
|
522
|
+
export { APIError, AuthenticationError, ConcurrencyLimitError, ConflictError, ConnectionError, FEEDBACK_BATCH_MAX, InsufficientCreditsError, KeyCreditLimitError, NoneCap, NoneCapError, NotFoundError, PayloadTooLargeError, PermissionError, RateLimitError, ServiceUnavailableError, SitekeyRateLimitedError, SolveFailedError, SolveHandle, TimeoutError, UnsupportedMediaTypeError, ValidationError, isTerminal };
|
|
481
523
|
//# sourceMappingURL=index.js.map
|
|
482
524
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/errors.ts","../src/version.ts","../src/client.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["import type { ErrorCode, Solve } from \"./types.js\";\n\n/**\n * Base class for every error this library throws. Catch `NoneCapError` to\n * handle all of them, or catch a subclass to handle one kind.\n */\nexport class NoneCapError extends Error {\n /** Machine-readable error code from the API envelope, when there is one. */\n readonly code: ErrorCode | undefined;\n /** HTTP status, when the error came from a response. */\n readonly status: number | undefined;\n /** The request field that was rejected, for validation errors. */\n readonly param: string | null;\n\n constructor(\n message: string,\n opts: { code?: ErrorCode; status?: number; param?: string | null } = {},\n ) {\n super(message);\n this.name = new.target.name;\n this.code = opts.code;\n this.status = opts.status;\n this.param = opts.param ?? null;\n // Restore the prototype chain when compiled down to ES5-era targets.\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\n/** 401 — the API key is missing, malformed, or revoked. */\nexport class AuthenticationError extends NoneCapError {}\n\n/** 403 — the key is valid but not allowed to do this (scope or locked account). */\nexport class PermissionError extends NoneCapError {}\n\n/** 402 — the account is out of credits. */\nexport class InsufficientCreditsError extends NoneCapError {}\n\n/** 422 / 400 — the request was rejected. `param` names the offending field. */\nexport class ValidationError extends NoneCapError {}\n\n/** 404 — no such resource. */\nexport class NotFoundError extends NoneCapError {}\n\n/** 409 — the solve is already in a terminal state (e.g. cancelling a finished solve). */\nexport class ConflictError extends NoneCapError {}\n\n/** 429 — too many concurrent solves, or rate limited. Back off and retry. */\nexport class RateLimitError extends NoneCapError {}\n\n/** 5xx, or a response that wasn't the expected shape. */\nexport class APIError extends NoneCapError {}\n\n/** The request never reached the API (DNS, TCP, TLS, timeout, offline). */\nexport class ConnectionError extends NoneCapError {}\n\n/**\n * Thrown by {@link NoneCap.solve} when a solve reaches a terminal state without\n * a token: `failed`, `expired`, or `cancelled`. The full solve is attached so\n * you can inspect `solve.error` and timings.\n */\nexport class SolveFailedError extends NoneCapError {\n readonly solve: Solve;\n\n constructor(solve: Solve) {\n const detail = solve.error ? `${solve.error.code}: ${solve.error.message}` : solve.status;\n super(`Solve ${solve.id} ${solve.status} (${detail})`, {\n code: undefined,\n status: undefined,\n });\n this.solve = solve;\n }\n}\n\n/**\n * Thrown by {@link NoneCap.solve} (and {@link SolveHandle.result}) when the\n * client-side timeout elapses first. When the timeout came from waiting on a\n * solve, `solveId` and the last-known `solve` are attached so you can still\n * cancel the in-flight solve. They are `undefined` for transport-level timeouts.\n */\nexport class TimeoutError extends NoneCapError {\n /** The id of the in-flight solve, when the timeout came from a solve wait. */\n readonly solveId: string | undefined;\n /** The last-known solve state, so you can cancel it after a wait timed out. */\n readonly solve: Solve | undefined;\n\n constructor(\n message: string,\n opts: {\n code?: ErrorCode;\n status?: number;\n param?: string | null;\n solveId?: string;\n solve?: Solve;\n } = {},\n ) {\n super(message, opts);\n this.solveId = opts.solveId;\n this.solve = opts.solve;\n }\n}\n\n/** Map an API error envelope (plus HTTP status) to the right error subclass. */\nexport function errorFromResponse(\n status: number,\n code: ErrorCode | undefined,\n message: string,\n param: string | null,\n): NoneCapError {\n const opts = { code, status, param };\n switch (code) {\n case \"unauthorized\":\n return new AuthenticationError(message, opts);\n case \"forbidden\":\n case \"account_locked\":\n return new PermissionError(message, opts);\n case \"insufficient_credits\":\n case \"key_credit_limit_exceeded\":\n return new InsufficientCreditsError(message, opts);\n case \"invalid_request\":\n case \"validation_error\":\n case \"expired_window\":\n return new ValidationError(message, opts);\n case \"not_found\":\n case \"not_eligible\":\n return new NotFoundError(message, opts);\n case \"conflict\":\n return new ConflictError(message, opts);\n case \"rate_limited\":\n case \"concurrency_limit_exceeded\":\n case \"ext_daily_limit\":\n case \"sitekey_rate_limited\":\n return new RateLimitError(message, opts);\n default:\n return new APIError(message, opts);\n }\n}\n","/**\n * The published package version, sent as the `User-Agent` on every request.\n *\n * Hardcoded rather than imported from package.json: a JSON import would need\n * `resolveJsonModule` and would resolve differently under the ESM and CJS\n * builds. Bump it in the SAME commit as package.json: the drift check is the\n * `Version constant matches package.json` step in ci.yml and lives ONLY there,\n * so `npm test` and `tsc` both stay green on a mismatch (test/version.test.ts\n * asserts the User-Agent uses VERSION, never that VERSION is right).\n */\nexport const VERSION = \"0.6.0\";\n","import {\n APIError,\n ConflictError,\n ConnectionError,\n NoneCapError,\n SolveFailedError,\n TimeoutError,\n errorFromResponse,\n} from \"./errors.js\";\nimport type {\n Account,\n ErrorCode,\n Feedback,\n FeedbackBatch,\n FeedbackReport,\n Solve,\n SolveCreateParams,\n SolveList,\n SolveListParams,\n SolveStatus,\n} from \"./types.js\";\n\nimport { VERSION } from \"./version.js\";\n\nconst DEFAULT_BASE_URL = \"https://api.nonecap.com\";\nconst USER_AGENT = `nonecap-js/${VERSION}`;\n/** The API caps server-side long-poll at 90 seconds. */\nconst MAX_WAIT_SECONDS = 90;\n/** The API caps one `POST /v1/feedback` call at 500 items. */\nexport const FEEDBACK_BATCH_MAX = 500;\nconst TERMINAL: ReadonlySet<SolveStatus> = new Set([\n \"solved\",\n \"failed\",\n \"cancelled\",\n \"expired\",\n]);\n\n/** Is this a terminal solve status? */\nexport function isTerminal(status: SolveStatus): boolean {\n return TERMINAL.has(status);\n}\n\n/** A `fetch` implementation. Defaults to the global `fetch`. */\nexport type FetchLike = (\n input: string,\n init?: RequestInit,\n) => Promise<Response>;\n\n/** Options for constructing a {@link NoneCap} client. */\nexport interface NoneCapOptions {\n /** Your NoneCap API key. Find it at https://dashboard.nonecap.com. */\n apiKey: string;\n /** Override the API base URL. Defaults to https://api.nonecap.com. */\n baseURL?: string;\n /**\n * Per-request timeout in milliseconds for a single HTTP call. Defaults to\n * 100000 (just above the 90s server long-poll). Note this bounds one HTTP\n * round trip, not the whole {@link NoneCap.solve} wait — use the `timeout`\n * option on `solve()` for that.\n */\n timeout?: number;\n /** Inject a custom `fetch` (for testing, proxies, or non-standard runtimes). */\n fetch?: FetchLike;\n}\n\n/** Per-call options for the long-polling endpoints. */\nexport interface WaitOptions {\n /**\n * Hold the connection open up to this many seconds (1–90) waiting for the\n * solve to finish before responding. Omit to return immediately.\n */\n wait?: number;\n /** Abort the request. */\n signal?: AbortSignal;\n}\n\n/** Options for {@link NoneCap.solve} and {@link SolveHandle.result}. */\nexport interface SolveHelperOptions {\n /**\n * Give up after this many milliseconds and throw {@link TimeoutError}.\n * Defaults to 180000 (3 minutes).\n */\n timeout?: number;\n /** Abort waiting. */\n signal?: AbortSignal;\n}\n\n/** Options for {@link NoneCap.solves.start}. */\nexport interface SolveStartOptions {\n /** Abort the submission. */\n signal?: AbortSignal;\n}\n\ninterface RequestOptions {\n query?: Record<string, string | number | undefined>;\n body?: unknown;\n signal?: AbortSignal;\n /** Override the per-request timeout for this call (used by long polls). */\n timeout?: number;\n /** HTTP statuses to treat as success in addition to 2xx (e.g. 202). */\n expect?: number[];\n}\n\n/**\n * The NoneCap API client.\n *\n * ```ts\n * const nc = new NoneCap({ apiKey: process.env.NONECAP_KEY! });\n * const { token } = await nc.solve({ type: \"hcaptcha\", sitekey, url });\n * ```\n */\nexport class NoneCap {\n readonly #apiKey: string;\n readonly #baseURL: string;\n readonly #timeout: number;\n readonly #fetch: FetchLike;\n\n constructor(options: NoneCapOptions) {\n if (!options || !options.apiKey) {\n throw new NoneCapError(\n \"A NoneCap API key is required. Pass it as `new NoneCap({ apiKey })`.\",\n );\n }\n this.#apiKey = options.apiKey;\n this.#baseURL = (options.baseURL ?? DEFAULT_BASE_URL).replace(/\\/+$/, \"\");\n this.#timeout = options.timeout ?? 100_000;\n const f = options.fetch ?? (globalThis.fetch as FetchLike | undefined);\n if (!f) {\n throw new NoneCapError(\n \"No `fetch` available. Use Node 18+, or pass a `fetch` in the client options.\",\n );\n }\n this.#fetch = f;\n }\n\n /** Operations on solves. */\n readonly solves = {\n /** Submit a solve. Pass `{ wait }` to hold the connection until it finishes. */\n create: (params: SolveCreateParams, options: WaitOptions = {}): Promise<Solve> =>\n this.#request<Solve>(\"POST\", \"/v1/solves\", {\n body: params,\n query: { wait: options.wait },\n signal: options.signal,\n timeout: this.#timeoutForWait(options.wait),\n expect: [202],\n }),\n\n /** Fetch a solve by id. Pass `{ wait }` to long-poll until it finishes. */\n retrieve: (id: string, options: WaitOptions = {}): Promise<Solve> =>\n this.#request<Solve>(\"GET\", `/v1/solves/${encodeURIComponent(id)}`, {\n query: { wait: options.wait },\n signal: options.signal,\n timeout: this.#timeoutForWait(options.wait),\n expect: [202],\n }),\n\n /** Cancel a pending or in-flight solve. */\n cancel: (id: string, options: { signal?: AbortSignal } = {}): Promise<Solve> =>\n this.#request<Solve>(\"DELETE\", `/v1/solves/${encodeURIComponent(id)}`, {\n signal: options.signal,\n }),\n\n /**\n * Submit a solve and return a {@link SolveHandle} for it.\n *\n * Unlike {@link NoneCap.solve}, this returns as soon as the submission is\n * accepted, so `handle.id` is available immediately. Use the handle to\n * `cancel()` the solve or `await handle.result()` for the finished solve.\n *\n * ```ts\n * const handle = await nc.solves.start({ type: \"hcaptcha\", sitekey, url });\n * // ...later, e.g. on shutdown:\n * await handle.cancel();\n * // or wait for it:\n * const { token } = await handle.result();\n * ```\n */\n start: async (\n params: SolveCreateParams,\n options: SolveStartOptions = {},\n ): Promise<SolveHandle> => {\n const solve = await this.solves.create(params, { signal: options.signal });\n return new SolveHandle(this, solve);\n },\n\n /** Fetch one page of solves. */\n list: (params: SolveListParams = {}, options: { signal?: AbortSignal } = {}): Promise<SolveList> =>\n this.#request<SolveList>(\"GET\", \"/v1/solves\", {\n query: {\n limit: params.limit,\n starting_after: params.starting_after,\n status: params.status,\n type: params.type,\n },\n signal: options.signal,\n }),\n\n /**\n * Iterate every solve across pages, newest first.\n *\n * ```ts\n * for await (const solve of nc.solves.listAll()) { ... }\n * ```\n */\n listAll: (\n params: SolveListParams = {},\n options: { signal?: AbortSignal } = {},\n ): AsyncIterableIterator<Solve> => this.#listAll(params, options),\n };\n\n /**\n * Report what your downstream target did with the tokens we minted.\n *\n * Feedback is free, own-solves-only, and idempotent per solve id: reporting\n * the same solve again corrects the earlier verdict. Only `solved` solves can\n * be reported, and only within the API's reporting window (~30 days from the\n * solve; corrections to an already-reported solve are never re-gated by it).\n */\n readonly feedback = {\n /**\n * Report one solve's downstream outcome, returning the recorded feedback.\n *\n * Unlike {@link NoneCap.feedback.reportMany}, a rejected report throws:\n * {@link NotFoundError} if the solve isn't yours or never minted a token,\n * {@link ValidationError} if a field is wrong or the reporting window closed.\n *\n * ```ts\n * await nc.feedback.report({ solve_id: solve.id, outcome: \"rejected\", reason: \"...\" });\n * ```\n */\n report: (report: FeedbackReport, options: { signal?: AbortSignal } = {}): Promise<Feedback> => {\n const { solve_id, ...fields } = report;\n return this.#request<Feedback>(\n \"POST\",\n `/v1/solves/${encodeURIComponent(solve_id)}/feedback`,\n { body: toWireFields(fields), signal: options.signal },\n );\n },\n\n /**\n * Report many verdicts at once — the path to use at volume. Buffer verdicts\n * as you learn them and flush them here.\n *\n * The call succeeds even when individual items are rejected: each is\n * resolved on its own so one stale id never discards the rest. Check\n * `failed` rather than relying on a thrown error.\n *\n * More than {@link FEEDBACK_BATCH_MAX} reports are split across sequential\n * requests and merged into one result, in request order. An empty array is\n * a no-op that returns an empty batch without a request.\n *\n * ```ts\n * const batch = await nc.feedback.reportMany(buffer);\n * if (batch.failed) console.warn(batch.results.filter((r) => r.status === \"error\"));\n * ```\n */\n reportMany: async (\n reports: readonly FeedbackReport[],\n options: { signal?: AbortSignal } = {},\n ): Promise<FeedbackBatch> => {\n const merged: FeedbackBatch = {\n object: \"feedback_batch\",\n recorded: 0,\n updated: 0,\n unchanged: 0,\n failed: 0,\n results: [],\n };\n // Chunks are sent in order and the server upserts last-write-wins, so a\n // solve reported twice still ends at its last value. Duplicates split\n // across a chunk boundary each get written, though, so the earlier one\n // reports `recorded`/`updated` where a single request would say\n // `unchanged`.\n for (let i = 0; i < reports.length; i += FEEDBACK_BATCH_MAX) {\n const batch = await this.#request<FeedbackBatch>(\"POST\", \"/v1/feedback\", {\n body: { feedback: reports.slice(i, i + FEEDBACK_BATCH_MAX).map(toWireReport) },\n signal: options.signal,\n });\n merged.recorded += batch.recorded;\n merged.updated += batch.updated;\n merged.unchanged += batch.unchanged;\n merged.failed += batch.failed;\n merged.results.push(...batch.results);\n }\n return merged;\n },\n };\n\n /** Fetch your account, including the current credit balance. */\n me(options: { signal?: AbortSignal } = {}): Promise<Account> {\n return this.#request<Account>(\"GET\", \"/v1/me\", { signal: options.signal });\n }\n\n /**\n * Submit a solve and wait for it to finish, returning the solved solve.\n *\n * Uses the server's long-poll under the hood and keeps polling until the\n * solve is terminal or `timeout` elapses. Throws {@link SolveFailedError} if\n * the solve fails/expires/is cancelled, or {@link TimeoutError} on timeout.\n *\n * This is sugar for `(await solves.start(params)).result(options)`. When you\n * need to cancel the solve while it runs, use {@link NoneCap.solves.start}\n * and keep the {@link SolveHandle}.\n */\n async solve(params: SolveCreateParams, options: SolveHelperOptions = {}): Promise<Solve> {\n const handle = await this.solves.start(params, { signal: options.signal });\n return handle.result(options);\n }\n\n // -- internals ------------------------------------------------------------\n\n #timeoutForWait(wait?: number): number | undefined {\n if (wait === undefined) return undefined;\n // Give the socket a margin beyond the server's long-poll window.\n return wait * 1000 + 15_000;\n }\n\n async *#listAll(\n params: SolveListParams,\n options: { signal?: AbortSignal },\n ): AsyncIterableIterator<Solve> {\n let cursor = params.starting_after;\n for (;;) {\n const page = await this.solves.list({ ...params, starting_after: cursor }, options);\n for (const solve of page.data) yield solve;\n if (!page.has_more || page.data.length === 0) return;\n cursor = page.data[page.data.length - 1]!.id;\n }\n }\n\n async #request<T>(method: string, path: string, options: RequestOptions = {}): Promise<T> {\n const url = new URL(this.#baseURL + path);\n if (options.query) {\n for (const [key, value] of Object.entries(options.query)) {\n if (value !== undefined && value !== \"\") url.searchParams.set(key, String(value));\n }\n }\n\n const headers: Record<string, string> = {\n Authorization: `Bearer ${this.#apiKey}`,\n Accept: \"application/json\",\n // Browsers drop this as a forbidden header; on Node it identifies the SDK.\n \"User-Agent\": USER_AGENT,\n };\n let bodyInit: string | undefined;\n if (options.body !== undefined) {\n headers[\"Content-Type\"] = \"application/json\";\n bodyInit = JSON.stringify(options.body);\n }\n\n const controller = new AbortController();\n const timeoutMs = options.timeout ?? this.#timeout;\n const timer = setTimeout(() => controller.abort(new TimeoutError(`Request timed out after ${timeoutMs}ms.`)), timeoutMs);\n const onAbort = () => controller.abort(options.signal?.reason);\n if (options.signal) {\n if (options.signal.aborted) onAbort();\n else options.signal.addEventListener(\"abort\", onAbort, { once: true });\n }\n\n let res: Response;\n try {\n res = await this.#fetch(url.toString(), {\n method,\n headers,\n body: bodyInit,\n signal: controller.signal,\n });\n } catch (err) {\n if (err instanceof TimeoutError) throw err;\n if (isAbort(err)) {\n // A caller-supplied signal aborting surfaces as the caller's reason.\n if (options.signal?.aborted) throw options.signal.reason instanceof Error\n ? options.signal.reason\n : new NoneCapError(\"Request aborted.\");\n throw new TimeoutError(`Request timed out after ${timeoutMs}ms.`);\n }\n throw new ConnectionError(\n `Could not reach the NoneCap API at ${this.#baseURL}: ${(err as Error).message}`,\n );\n } finally {\n clearTimeout(timer);\n options.signal?.removeEventListener(\"abort\", onAbort);\n }\n\n return this.#parse<T>(res, options.expect ?? []);\n }\n\n async #parse<T>(res: Response, expect: number[]): Promise<T> {\n const text = await res.text();\n let json: unknown;\n if (text) {\n try {\n json = JSON.parse(text);\n } catch {\n throw new APIError(\n `Unexpected non-JSON response (HTTP ${res.status}): ${text.slice(0, 200)}`,\n { status: res.status },\n );\n }\n }\n\n if (res.ok || expect.includes(res.status)) {\n return json as T;\n }\n\n const envelope = json as { error?: { code?: ErrorCode; message?: string; param?: string | null } } | undefined;\n const apiError = envelope?.error;\n throw errorFromResponse(\n res.status,\n apiError?.code,\n apiError?.message ?? `HTTP ${res.status}`,\n apiError?.param ?? null,\n );\n }\n}\n\n/**\n * A handle on a started solve, returned by {@link NoneCap.solves.start}.\n *\n * The handle is the cancellable lifecycle object for one solve. It is a plain\n * object, not a promise: `await`ing it does nothing useful. Wait for the result\n * with {@link SolveHandle.result}, and cancel with {@link SolveHandle.cancel}.\n * You do not construct it yourself — `solves.start()` hands you one with `id`\n * already resolved.\n */\nexport class SolveHandle {\n /** The id of the started solve, available as soon as `start()` resolved. */\n readonly id: string;\n\n readonly #client: NoneCap;\n /** The latest solve state we have seen, from the create, polls, or cancel. */\n #solve: Solve;\n /**\n * The cached TERMINAL outcome: resolves to the solved solve, or rejects with\n * {@link SolveFailedError} if terminal-but-not-solved. Only ever set once the\n * solve actually reaches a terminal state, so it is safe to replay forever. A\n * timed-out wait does NOT settle this — it is retryable.\n */\n #terminal: Promise<Solve> | undefined;\n /** The poll currently in flight, shared by concurrent result() callers. */\n #inflight: Promise<Solve> | undefined;\n\n constructor(client: NoneCap, solve: Solve) {\n this.#client = client;\n this.#solve = solve;\n this.id = solve.id;\n }\n\n /** The last-known solve state for this handle. */\n get solve(): Solve {\n return this.#solve;\n }\n\n /**\n * Long-poll until the solve is terminal, returning the solved solve. Throws\n * {@link SolveFailedError} if it fails/expires/is cancelled, or\n * {@link TimeoutError} on timeout (with `solveId`/`solve` attached so you can\n * still {@link SolveHandle.cancel} it).\n *\n * Memoizes the *terminal* outcome: once the solve actually finishes, every\n * later call returns that same settled result. A {@link TimeoutError} is not\n * memoized — it just means this wait gave up, so a later call (e.g. with a\n * larger `timeout`) resumes polling. Concurrent calls share one in-flight\n * poll, so they never issue duplicate requests. The first caller's\n * `timeout`/`signal` drive the shared poll; a later call starts a fresh one.\n */\n result(options: SolveHelperOptions = {}): Promise<Solve> {\n if (this.#terminal) return this.#terminal;\n if (this.#inflight) return this.#inflight;\n const run = this.#poll(options).finally(() => {\n // Free the slot so a retry can re-poll after a timeout; a terminal\n // outcome is already memoized in #terminal and wins on the next call.\n if (this.#inflight === run) this.#inflight = undefined;\n });\n this.#inflight = run;\n return run;\n }\n\n /**\n * Cancel the solve. Cancelled solves are never charged, so this is for clean\n * shutdown / freeing slots / stopping early, not cost protection.\n *\n * If the solve already reached a terminal state the API answers 409; that is\n * not an error a caller cares about, so this swallows {@link ConflictError}\n * and returns the current solve state instead. A cancel that lands on a\n * terminal state (cancelled, or whatever the 409-swallow read back) settles\n * this handle's {@link SolveHandle.result}, so any in-flight or later wait\n * stops polling and reflects that terminal state.\n */\n async cancel(options: { signal?: AbortSignal } = {}): Promise<Solve> {\n try {\n this.#solve = await this.#client.solves.cancel(this.id, options);\n } catch (err) {\n if (!(err instanceof ConflictError)) throw err;\n // Already terminal — report the real state rather than the 409.\n this.#solve = await this.#client.solves.retrieve(this.id, options);\n }\n if (!this.#terminal && isTerminal(this.#solve.status)) this.#cacheTerminal();\n return this.#solve;\n }\n\n /**\n * Build and memoize the terminal outcome from the current `#solve`. The\n * precondition is that `#solve` is terminal and `#terminal` is unset.\n */\n #cacheTerminal(): Promise<Solve> {\n const settled =\n this.#solve.status === \"solved\"\n ? Promise.resolve(this.#solve)\n : Promise.reject(new SolveFailedError(this.#solve));\n // Never let the memoized rejection surface as an unhandled rejection; real\n // callers read it explicitly through result().\n settled.catch(() => {});\n this.#terminal = settled;\n return settled;\n }\n\n async #poll(options: SolveHelperOptions): Promise<Solve> {\n const timeout = options.timeout ?? 180_000;\n const deadline = Date.now() + timeout;\n\n for (;;) {\n // cancel() (or a previous poll) may have already settled this handle.\n if (this.#terminal) return this.#terminal;\n if (isTerminal(this.#solve.status)) return this.#cacheTerminal();\n if (Date.now() >= deadline) {\n throw new TimeoutError(\n `Solve ${this.id} did not finish within ${timeout}ms (last status: ${this.#solve.status}).`,\n { solveId: this.id, solve: this.#solve },\n );\n }\n this.#solve = await this.#client.solves.retrieve(this.id, {\n wait: waitSeconds(deadline),\n signal: options.signal,\n });\n }\n }\n}\n\n/**\n * The `wait` value for the next long-poll: whole seconds until `deadline`,\n * clamped to the server's 1–90 window. The floor of 1 keeps the param valid,\n * so callers must decide whether the deadline has passed with the clock, not\n * with this return value.\n */\nfunction waitSeconds(deadline: number): number {\n const remaining = Math.ceil((deadline - Date.now()) / 1000);\n return Math.max(1, Math.min(MAX_WAIT_SECONDS, remaining));\n}\n\nfunction isAbort(err: unknown): boolean {\n return err instanceof Error && err.name === \"AbortError\";\n}\n\n/** The fields of a report, ready for the wire: a `Date` becomes an ISO string. */\nfunction toWireFields(fields: Omit<FeedbackReport, \"solve_id\">): Record<string, unknown> {\n const wire: Record<string, unknown> = { outcome: fields.outcome };\n if (fields.reason !== undefined) wire.reason = fields.reason;\n if (fields.context !== undefined) wire.context = fields.context;\n if (fields.reported_at !== undefined) {\n wire.reported_at =\n fields.reported_at instanceof Date ? fields.reported_at.toISOString() : fields.reported_at;\n }\n return wire;\n}\n\nfunction toWireReport(report: FeedbackReport): Record<string, unknown> {\n const { solve_id, ...fields } = report;\n return { solve_id, ...toWireFields(fields) };\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/errors.ts","../src/version.ts","../src/client.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["import type { ErrorCode, Solve } from \"./types.js\";\n\n/**\n * Base class for every error this library throws. Catch `NoneCapError` to\n * handle all of them, or catch a subclass to handle one kind.\n */\nexport class NoneCapError extends Error {\n /** Machine-readable error code from the API envelope, when there is one. */\n readonly code: ErrorCode | undefined;\n /** HTTP status, when the error came from a response. */\n readonly status: number | undefined;\n /** The request field that was rejected, for validation errors. */\n readonly param: string | null;\n /** The API's correlation id for this request (`X-Request-Id`); quote it to support. */\n readonly requestId: string | undefined;\n /** Seconds to wait before retrying, when the API sent `Retry-After`. */\n readonly retryAfter: number | undefined;\n\n constructor(\n message: string,\n opts: {\n code?: ErrorCode;\n status?: number;\n param?: string | null;\n requestId?: string;\n retryAfter?: number;\n } = {},\n ) {\n super(message);\n this.name = new.target.name;\n this.code = opts.code;\n this.status = opts.status;\n this.param = opts.param ?? null;\n this.requestId = opts.requestId;\n this.retryAfter = opts.retryAfter;\n // Restore the prototype chain when compiled down to ES5-era targets.\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\n/** 401 — the API key is missing, malformed, or revoked. */\nexport class AuthenticationError extends NoneCapError {}\n\n/** 403 — the key is valid but not allowed to do this (scope or locked account). */\nexport class PermissionError extends NoneCapError {}\n\n/** 402 — the account is out of credits. */\nexport class InsufficientCreditsError extends NoneCapError {}\n\n/** 402 — this API key reached its own credit limit (the account may still have credits). */\nexport class KeyCreditLimitError extends InsufficientCreditsError {}\n\n/** 422 / 400 — the request was rejected. `param` names the offending field. */\nexport class ValidationError extends NoneCapError {}\n\n/** 413 — the request body exceeds the route's size limit. */\nexport class PayloadTooLargeError extends ValidationError {}\n\n/** 415 — a JSON route was called without `Content-Type: application/json`. */\nexport class UnsupportedMediaTypeError extends ValidationError {}\n\n/** 404 — no such resource. */\nexport class NotFoundError extends NoneCapError {}\n\n/** 409 — the solve is already in a terminal state (e.g. cancelling a finished solve). */\nexport class ConflictError extends NoneCapError {}\n\n/** 429 — back off and retry; `retryAfter` (seconds) is set when the API sent it. */\nexport class RateLimitError extends NoneCapError {}\n\n/** 429 — too many solves in flight for this account. Wait for one to finish. */\nexport class ConcurrencyLimitError extends RateLimitError {}\n\n/** 429 — hCaptcha is refusing challenges for this sitekey, so the submit was shed.\n * Wait `retryAfter` seconds; the message says whether a different proxy pool can help. */\nexport class SitekeyRateLimitedError extends RateLimitError {}\n\n/** 5xx, or a response that wasn't the expected shape. `requestId` is the id to quote. */\nexport class APIError extends NoneCapError {}\n\n/** 503 — new solves are paused for maintenance. Retry shortly. */\nexport class ServiceUnavailableError extends APIError {}\n\n/** The request never reached the API (DNS, TCP, TLS, timeout, offline). */\nexport class ConnectionError extends NoneCapError {}\n\n/**\n * Thrown by {@link NoneCap.solve} when a solve reaches a terminal state without\n * a token: `failed`, `expired`, or `cancelled`. The full solve is attached so\n * you can inspect `solve.error` and timings.\n */\nexport class SolveFailedError extends NoneCapError {\n readonly solve: Solve;\n\n constructor(solve: Solve) {\n const detail = solve.error ? `${solve.error.code}: ${solve.error.message}` : solve.status;\n super(`Solve ${solve.id} ${solve.status} (${detail})`, {\n code: undefined,\n status: undefined,\n });\n this.solve = solve;\n }\n\n /** `solve.error.code`, e.g. `proxy_error`; the status when no error object came back. */\n get solveCode(): string {\n return this.solve.error?.code ?? this.solve.status;\n }\n\n /** `solve.error.reason`, the typed sub-reason, or null. */\n get reason(): string | null {\n return this.solve.error?.reason ?? null;\n }\n\n /** Whether re-submitting the same request unchanged can succeed. */\n get retryable(): boolean {\n return this.solve.error?.retryable ?? false;\n }\n}\n\n/**\n * Thrown by {@link NoneCap.solve} (and {@link SolveHandle.result}) when the\n * client-side timeout elapses first. When the timeout came from waiting on a\n * solve, `solveId` and the last-known `solve` are attached so you can still\n * cancel the in-flight solve. They are `undefined` for transport-level timeouts.\n */\nexport class TimeoutError extends NoneCapError {\n /** The id of the in-flight solve, when the timeout came from a solve wait. */\n readonly solveId: string | undefined;\n /** The last-known solve state, so you can cancel it after a wait timed out. */\n readonly solve: Solve | undefined;\n\n constructor(\n message: string,\n opts: {\n code?: ErrorCode;\n status?: number;\n param?: string | null;\n solveId?: string;\n solve?: Solve;\n } = {},\n ) {\n super(message, opts);\n this.solveId = opts.solveId;\n this.solve = opts.solve;\n }\n}\n\n/** Map an API error envelope (plus HTTP status) to the right error subclass. */\nexport function errorFromResponse(\n status: number,\n code: ErrorCode | undefined,\n message: string,\n param: string | null,\n extra: { requestId?: string; retryAfter?: number } = {},\n): NoneCapError {\n const opts = { code, status, param, ...extra };\n switch (code) {\n case \"unauthorized\":\n return new AuthenticationError(message, opts);\n case \"forbidden\":\n case \"account_locked\":\n return new PermissionError(message, opts);\n case \"insufficient_credits\":\n return new InsufficientCreditsError(message, opts);\n case \"key_credit_limit_exceeded\":\n return new KeyCreditLimitError(message, opts);\n case \"invalid_request\":\n case \"validation_error\":\n case \"expired_window\":\n return new ValidationError(message, opts);\n case \"payload_too_large\":\n return new PayloadTooLargeError(message, opts);\n case \"unsupported_media_type\":\n return new UnsupportedMediaTypeError(message, opts);\n case \"not_found\":\n case \"not_eligible\":\n return new NotFoundError(message, opts);\n case \"conflict\":\n return new ConflictError(message, opts);\n case \"concurrency_limit_exceeded\":\n return new ConcurrencyLimitError(message, opts);\n case \"sitekey_rate_limited\":\n return new SitekeyRateLimitedError(message, opts);\n case \"rate_limited\":\n case \"ext_daily_limit\":\n return new RateLimitError(message, opts);\n case \"maintenance\":\n return new ServiceUnavailableError(message, opts);\n default:\n return new APIError(message, opts);\n }\n}\n","/**\n * The published package version, sent as the `User-Agent` on every request.\n *\n * Hardcoded rather than imported from package.json: a JSON import would need\n * `resolveJsonModule` and would resolve differently under the ESM and CJS\n * builds. Bump it in the SAME commit as package.json: the drift check is the\n * `Version constant matches package.json` step in ci.yml and lives ONLY there,\n * so `npm test` and `tsc` both stay green on a mismatch (test/version.test.ts\n * asserts the User-Agent uses VERSION, never that VERSION is right).\n */\nexport const VERSION = \"0.7.0\";\n","import {\n APIError,\n ConflictError,\n ConnectionError,\n NoneCapError,\n SolveFailedError,\n TimeoutError,\n errorFromResponse,\n} from \"./errors.js\";\nimport type {\n Account,\n ErrorCode,\n Feedback,\n FeedbackBatch,\n FeedbackReport,\n Solve,\n SolveCreateParams,\n SolveList,\n SolveListParams,\n SolveStatus,\n} from \"./types.js\";\n\nimport { VERSION } from \"./version.js\";\n\nconst DEFAULT_BASE_URL = \"https://api.nonecap.com\";\nconst USER_AGENT = `nonecap-js/${VERSION}`;\n/** The API caps server-side long-poll at 90 seconds. */\nconst MAX_WAIT_SECONDS = 90;\n/** The API caps one `POST /v1/feedback` call at 500 items. */\nexport const FEEDBACK_BATCH_MAX = 500;\nconst TERMINAL: ReadonlySet<SolveStatus> = new Set([\n \"solved\",\n \"failed\",\n \"cancelled\",\n \"expired\",\n]);\n\n/** Is this a terminal solve status? */\nexport function isTerminal(status: SolveStatus): boolean {\n return TERMINAL.has(status);\n}\n\n/** A `fetch` implementation. Defaults to the global `fetch`. */\nexport type FetchLike = (\n input: string,\n init?: RequestInit,\n) => Promise<Response>;\n\n/** Options for constructing a {@link NoneCap} client. */\nexport interface NoneCapOptions {\n /** Your NoneCap API key. Find it at https://dashboard.nonecap.com. */\n apiKey: string;\n /** Override the API base URL. Defaults to https://api.nonecap.com. */\n baseURL?: string;\n /**\n * Per-request timeout in milliseconds for a single HTTP call. Defaults to\n * 100000 (just above the 90s server long-poll). Note this bounds one HTTP\n * round trip, not the whole {@link NoneCap.solve} wait — use the `timeout`\n * option on `solve()` for that.\n */\n timeout?: number;\n /** Inject a custom `fetch` (for testing, proxies, or non-standard runtimes). */\n fetch?: FetchLike;\n}\n\n/** Per-call options for the long-polling endpoints. */\nexport interface WaitOptions {\n /**\n * Hold the connection open up to this many seconds (1–90) waiting for the\n * solve to finish before responding. Omit to return immediately.\n */\n wait?: number;\n /** Abort the request. */\n signal?: AbortSignal;\n}\n\n/** Options for {@link NoneCap.solve} and {@link SolveHandle.result}. */\nexport interface SolveHelperOptions {\n /**\n * Give up after this many milliseconds and throw {@link TimeoutError}.\n * Defaults to 180000 (3 minutes).\n */\n timeout?: number;\n /** Abort waiting. */\n signal?: AbortSignal;\n}\n\n/** Options for {@link NoneCap.solves.start}. */\nexport interface SolveStartOptions {\n /** Abort the submission. */\n signal?: AbortSignal;\n}\n\ninterface RequestOptions {\n query?: Record<string, string | number | undefined>;\n body?: unknown;\n signal?: AbortSignal;\n /** Override the per-request timeout for this call (used by long polls). */\n timeout?: number;\n /** HTTP statuses to treat as success in addition to 2xx (e.g. 202). */\n expect?: number[];\n}\n\n/**\n * The NoneCap API client.\n *\n * ```ts\n * const nc = new NoneCap({ apiKey: process.env.NONECAP_KEY! });\n * const { token } = await nc.solve({ type: \"hcaptcha\", sitekey, url });\n * ```\n */\nexport class NoneCap {\n readonly #apiKey: string;\n readonly #baseURL: string;\n readonly #timeout: number;\n readonly #fetch: FetchLike;\n\n constructor(options: NoneCapOptions) {\n if (!options || !options.apiKey) {\n throw new NoneCapError(\n \"A NoneCap API key is required. Pass it as `new NoneCap({ apiKey })`.\",\n );\n }\n this.#apiKey = options.apiKey;\n this.#baseURL = (options.baseURL ?? DEFAULT_BASE_URL).replace(/\\/+$/, \"\");\n this.#timeout = options.timeout ?? 100_000;\n const f = options.fetch ?? (globalThis.fetch as FetchLike | undefined);\n if (!f) {\n throw new NoneCapError(\n \"No `fetch` available. Use Node 18+, or pass a `fetch` in the client options.\",\n );\n }\n this.#fetch = f;\n }\n\n /** Operations on solves. */\n readonly solves = {\n /** Submit a solve. Pass `{ wait }` to hold the connection until it finishes. */\n create: (params: SolveCreateParams, options: WaitOptions = {}): Promise<Solve> =>\n this.#request<Solve>(\"POST\", \"/v1/solves\", {\n body: params,\n query: { wait: options.wait },\n signal: options.signal,\n timeout: this.#timeoutForWait(options.wait),\n expect: [202],\n }),\n\n /** Fetch a solve by id. Pass `{ wait }` to long-poll until it finishes. */\n retrieve: (id: string, options: WaitOptions = {}): Promise<Solve> =>\n this.#request<Solve>(\"GET\", `/v1/solves/${encodeURIComponent(id)}`, {\n query: { wait: options.wait },\n signal: options.signal,\n timeout: this.#timeoutForWait(options.wait),\n expect: [202],\n }),\n\n /** Cancel a pending or in-flight solve. */\n cancel: (id: string, options: { signal?: AbortSignal } = {}): Promise<Solve> =>\n this.#request<Solve>(\"DELETE\", `/v1/solves/${encodeURIComponent(id)}`, {\n signal: options.signal,\n }),\n\n /**\n * Submit a solve and return a {@link SolveHandle} for it.\n *\n * Unlike {@link NoneCap.solve}, this returns as soon as the submission is\n * accepted, so `handle.id` is available immediately. Use the handle to\n * `cancel()` the solve or `await handle.result()` for the finished solve.\n *\n * ```ts\n * const handle = await nc.solves.start({ type: \"hcaptcha\", sitekey, url });\n * // ...later, e.g. on shutdown:\n * await handle.cancel();\n * // or wait for it:\n * const { token } = await handle.result();\n * ```\n */\n start: async (\n params: SolveCreateParams,\n options: SolveStartOptions = {},\n ): Promise<SolveHandle> => {\n const solve = await this.solves.create(params, { signal: options.signal });\n return new SolveHandle(this, solve);\n },\n\n /** Fetch one page of solves. */\n list: (params: SolveListParams = {}, options: { signal?: AbortSignal } = {}): Promise<SolveList> =>\n this.#request<SolveList>(\"GET\", \"/v1/solves\", {\n query: {\n limit: params.limit,\n starting_after: params.starting_after,\n status: params.status,\n type: params.type,\n },\n signal: options.signal,\n }),\n\n /**\n * Iterate every solve across pages, newest first.\n *\n * ```ts\n * for await (const solve of nc.solves.listAll()) { ... }\n * ```\n */\n listAll: (\n params: SolveListParams = {},\n options: { signal?: AbortSignal } = {},\n ): AsyncIterableIterator<Solve> => this.#listAll(params, options),\n };\n\n /**\n * Report what your downstream target did with the tokens we minted.\n *\n * Feedback is free, own-solves-only, and idempotent per solve id: reporting\n * the same solve again corrects the earlier verdict. Only `solved` solves can\n * be reported, and only within the API's reporting window (~30 days from the\n * solve; corrections to an already-reported solve are never re-gated by it).\n */\n readonly feedback = {\n /**\n * Report one solve's downstream outcome, returning the recorded feedback.\n *\n * Unlike {@link NoneCap.feedback.reportMany}, a rejected report throws:\n * {@link NotFoundError} if the solve isn't yours or never minted a token,\n * {@link ValidationError} if a field is wrong or the reporting window closed.\n *\n * ```ts\n * await nc.feedback.report({ solve_id: solve.id, outcome: \"rejected\", reason: \"...\" });\n * ```\n */\n report: (report: FeedbackReport, options: { signal?: AbortSignal } = {}): Promise<Feedback> => {\n const { solve_id, ...fields } = report;\n return this.#request<Feedback>(\n \"POST\",\n `/v1/solves/${encodeURIComponent(solve_id)}/feedback`,\n { body: toWireFields(fields), signal: options.signal },\n );\n },\n\n /**\n * Report many verdicts at once — the path to use at volume. Buffer verdicts\n * as you learn them and flush them here.\n *\n * The call succeeds even when individual items are rejected: each is\n * resolved on its own so one stale id never discards the rest. Check\n * `failed` rather than relying on a thrown error.\n *\n * More than {@link FEEDBACK_BATCH_MAX} reports are split across sequential\n * requests and merged into one result, in request order. An empty array is\n * a no-op that returns an empty batch without a request.\n *\n * ```ts\n * const batch = await nc.feedback.reportMany(buffer);\n * if (batch.failed) console.warn(batch.results.filter((r) => r.status === \"error\"));\n * ```\n */\n reportMany: async (\n reports: readonly FeedbackReport[],\n options: { signal?: AbortSignal } = {},\n ): Promise<FeedbackBatch> => {\n const merged: FeedbackBatch = {\n object: \"feedback_batch\",\n recorded: 0,\n updated: 0,\n unchanged: 0,\n failed: 0,\n results: [],\n };\n // Chunks are sent in order and the server upserts last-write-wins, so a\n // solve reported twice still ends at its last value. Duplicates split\n // across a chunk boundary each get written, though, so the earlier one\n // reports `recorded`/`updated` where a single request would say\n // `unchanged`.\n for (let i = 0; i < reports.length; i += FEEDBACK_BATCH_MAX) {\n const batch = await this.#request<FeedbackBatch>(\"POST\", \"/v1/feedback\", {\n body: { feedback: reports.slice(i, i + FEEDBACK_BATCH_MAX).map(toWireReport) },\n signal: options.signal,\n });\n merged.recorded += batch.recorded;\n merged.updated += batch.updated;\n merged.unchanged += batch.unchanged;\n merged.failed += batch.failed;\n merged.results.push(...batch.results);\n }\n return merged;\n },\n };\n\n /** Fetch your account, including the current credit balance. */\n me(options: { signal?: AbortSignal } = {}): Promise<Account> {\n return this.#request<Account>(\"GET\", \"/v1/me\", { signal: options.signal });\n }\n\n /**\n * Submit a solve and wait for it to finish, returning the solved solve.\n *\n * Uses the server's long-poll under the hood and keeps polling until the\n * solve is terminal or `timeout` elapses. Throws {@link SolveFailedError} if\n * the solve fails/expires/is cancelled, or {@link TimeoutError} on timeout.\n *\n * This is sugar for `(await solves.start(params)).result(options)`. When you\n * need to cancel the solve while it runs, use {@link NoneCap.solves.start}\n * and keep the {@link SolveHandle}.\n */\n async solve(params: SolveCreateParams, options: SolveHelperOptions = {}): Promise<Solve> {\n const handle = await this.solves.start(params, { signal: options.signal });\n return handle.result(options);\n }\n\n // -- internals ------------------------------------------------------------\n\n #timeoutForWait(wait?: number): number | undefined {\n if (wait === undefined) return undefined;\n // Give the socket a margin beyond the server's long-poll window.\n return wait * 1000 + 15_000;\n }\n\n async *#listAll(\n params: SolveListParams,\n options: { signal?: AbortSignal },\n ): AsyncIterableIterator<Solve> {\n let cursor = params.starting_after;\n for (;;) {\n const page = await this.solves.list({ ...params, starting_after: cursor }, options);\n for (const solve of page.data) yield solve;\n if (!page.has_more || page.data.length === 0) return;\n cursor = page.data[page.data.length - 1]!.id;\n }\n }\n\n async #request<T>(method: string, path: string, options: RequestOptions = {}): Promise<T> {\n const url = new URL(this.#baseURL + path);\n if (options.query) {\n for (const [key, value] of Object.entries(options.query)) {\n if (value !== undefined && value !== \"\") url.searchParams.set(key, String(value));\n }\n }\n\n const headers: Record<string, string> = {\n Authorization: `Bearer ${this.#apiKey}`,\n Accept: \"application/json\",\n // Browsers drop this as a forbidden header; on Node it identifies the SDK.\n \"User-Agent\": USER_AGENT,\n };\n let bodyInit: string | undefined;\n if (options.body !== undefined) {\n headers[\"Content-Type\"] = \"application/json\";\n bodyInit = JSON.stringify(options.body);\n }\n\n const controller = new AbortController();\n const timeoutMs = options.timeout ?? this.#timeout;\n const timer = setTimeout(() => controller.abort(new TimeoutError(`Request timed out after ${timeoutMs}ms.`)), timeoutMs);\n const onAbort = () => controller.abort(options.signal?.reason);\n if (options.signal) {\n if (options.signal.aborted) onAbort();\n else options.signal.addEventListener(\"abort\", onAbort, { once: true });\n }\n\n let res: Response;\n try {\n res = await this.#fetch(url.toString(), {\n method,\n headers,\n body: bodyInit,\n signal: controller.signal,\n });\n } catch (err) {\n if (err instanceof TimeoutError) throw err;\n if (isAbort(err)) {\n // A caller-supplied signal aborting surfaces as the caller's reason.\n if (options.signal?.aborted) throw options.signal.reason instanceof Error\n ? options.signal.reason\n : new NoneCapError(\"Request aborted.\");\n throw new TimeoutError(`Request timed out after ${timeoutMs}ms.`);\n }\n throw new ConnectionError(\n `Could not reach the NoneCap API at ${this.#baseURL}: ${(err as Error).message}`,\n );\n } finally {\n clearTimeout(timer);\n options.signal?.removeEventListener(\"abort\", onAbort);\n }\n\n return this.#parse<T>(res, options.expect ?? []);\n }\n\n async #parse<T>(res: Response, expect: number[]): Promise<T> {\n const text = await res.text();\n let json: unknown;\n if (text) {\n try {\n json = JSON.parse(text);\n } catch {\n throw new APIError(\n `Unexpected non-JSON response (HTTP ${res.status}): ${text.slice(0, 200)}`,\n { status: res.status },\n );\n }\n }\n\n if (res.ok || expect.includes(res.status)) {\n return json as T;\n }\n\n const envelope = json as\n | { error?: { code?: ErrorCode; message?: string; param?: string | null; request_id?: string } }\n | undefined;\n const apiError = envelope?.error;\n const retryAfterRaw = res.headers.get(\"retry-after\");\n const retryAfter = retryAfterRaw !== null && /^\\d+$/.test(retryAfterRaw) ? Number(retryAfterRaw) : undefined;\n throw errorFromResponse(\n res.status,\n apiError?.code,\n apiError?.message ?? `HTTP ${res.status}`,\n apiError?.param ?? null,\n { requestId: apiError?.request_id ?? res.headers.get(\"x-request-id\") ?? undefined, retryAfter },\n );\n }\n}\n\n/**\n * A handle on a started solve, returned by {@link NoneCap.solves.start}.\n *\n * The handle is the cancellable lifecycle object for one solve. It is a plain\n * object, not a promise: `await`ing it does nothing useful. Wait for the result\n * with {@link SolveHandle.result}, and cancel with {@link SolveHandle.cancel}.\n * You do not construct it yourself — `solves.start()` hands you one with `id`\n * already resolved.\n */\nexport class SolveHandle {\n /** The id of the started solve, available as soon as `start()` resolved. */\n readonly id: string;\n\n readonly #client: NoneCap;\n /** The latest solve state we have seen, from the create, polls, or cancel. */\n #solve: Solve;\n /**\n * The cached TERMINAL outcome: resolves to the solved solve, or rejects with\n * {@link SolveFailedError} if terminal-but-not-solved. Only ever set once the\n * solve actually reaches a terminal state, so it is safe to replay forever. A\n * timed-out wait does NOT settle this — it is retryable.\n */\n #terminal: Promise<Solve> | undefined;\n /** The poll currently in flight, shared by concurrent result() callers. */\n #inflight: Promise<Solve> | undefined;\n\n constructor(client: NoneCap, solve: Solve) {\n this.#client = client;\n this.#solve = solve;\n this.id = solve.id;\n }\n\n /** The last-known solve state for this handle. */\n get solve(): Solve {\n return this.#solve;\n }\n\n /**\n * Long-poll until the solve is terminal, returning the solved solve. Throws\n * {@link SolveFailedError} if it fails/expires/is cancelled, or\n * {@link TimeoutError} on timeout (with `solveId`/`solve` attached so you can\n * still {@link SolveHandle.cancel} it).\n *\n * Memoizes the *terminal* outcome: once the solve actually finishes, every\n * later call returns that same settled result. A {@link TimeoutError} is not\n * memoized — it just means this wait gave up, so a later call (e.g. with a\n * larger `timeout`) resumes polling. Concurrent calls share one in-flight\n * poll, so they never issue duplicate requests. The first caller's\n * `timeout`/`signal` drive the shared poll; a later call starts a fresh one.\n */\n result(options: SolveHelperOptions = {}): Promise<Solve> {\n if (this.#terminal) return this.#terminal;\n if (this.#inflight) return this.#inflight;\n const run = this.#poll(options).finally(() => {\n // Free the slot so a retry can re-poll after a timeout; a terminal\n // outcome is already memoized in #terminal and wins on the next call.\n if (this.#inflight === run) this.#inflight = undefined;\n });\n this.#inflight = run;\n return run;\n }\n\n /**\n * Cancel the solve. Cancelled solves are never charged, so this is for clean\n * shutdown / freeing slots / stopping early, not cost protection.\n *\n * If the solve already reached a terminal state the API answers 409; that is\n * not an error a caller cares about, so this swallows {@link ConflictError}\n * and returns the current solve state instead. A cancel that lands on a\n * terminal state (cancelled, or whatever the 409-swallow read back) settles\n * this handle's {@link SolveHandle.result}, so any in-flight or later wait\n * stops polling and reflects that terminal state.\n */\n async cancel(options: { signal?: AbortSignal } = {}): Promise<Solve> {\n try {\n this.#solve = await this.#client.solves.cancel(this.id, options);\n } catch (err) {\n if (!(err instanceof ConflictError)) throw err;\n // Already terminal — report the real state rather than the 409.\n this.#solve = await this.#client.solves.retrieve(this.id, options);\n }\n if (!this.#terminal && isTerminal(this.#solve.status)) this.#cacheTerminal();\n return this.#solve;\n }\n\n /**\n * Build and memoize the terminal outcome from the current `#solve`. The\n * precondition is that `#solve` is terminal and `#terminal` is unset.\n */\n #cacheTerminal(): Promise<Solve> {\n const settled =\n this.#solve.status === \"solved\"\n ? Promise.resolve(this.#solve)\n : Promise.reject(new SolveFailedError(this.#solve));\n // Never let the memoized rejection surface as an unhandled rejection; real\n // callers read it explicitly through result().\n settled.catch(() => {});\n this.#terminal = settled;\n return settled;\n }\n\n async #poll(options: SolveHelperOptions): Promise<Solve> {\n const timeout = options.timeout ?? 180_000;\n const deadline = Date.now() + timeout;\n\n for (;;) {\n // cancel() (or a previous poll) may have already settled this handle.\n if (this.#terminal) return this.#terminal;\n if (isTerminal(this.#solve.status)) return this.#cacheTerminal();\n if (Date.now() >= deadline) {\n throw new TimeoutError(\n `Solve ${this.id} did not finish within ${timeout}ms (last status: ${this.#solve.status}).`,\n { solveId: this.id, solve: this.#solve },\n );\n }\n this.#solve = await this.#client.solves.retrieve(this.id, {\n wait: waitSeconds(deadline),\n signal: options.signal,\n });\n }\n }\n}\n\n/**\n * The `wait` value for the next long-poll: whole seconds until `deadline`,\n * clamped to the server's 1–90 window. The floor of 1 keeps the param valid,\n * so callers must decide whether the deadline has passed with the clock, not\n * with this return value.\n */\nfunction waitSeconds(deadline: number): number {\n const remaining = Math.ceil((deadline - Date.now()) / 1000);\n return Math.max(1, Math.min(MAX_WAIT_SECONDS, remaining));\n}\n\nfunction isAbort(err: unknown): boolean {\n return err instanceof Error && err.name === \"AbortError\";\n}\n\n/** The fields of a report, ready for the wire: a `Date` becomes an ISO string. */\nfunction toWireFields(fields: Omit<FeedbackReport, \"solve_id\">): Record<string, unknown> {\n const wire: Record<string, unknown> = { outcome: fields.outcome };\n if (fields.reason !== undefined) wire.reason = fields.reason;\n if (fields.context !== undefined) wire.context = fields.context;\n if (fields.reported_at !== undefined) {\n wire.reported_at =\n fields.reported_at instanceof Date ? fields.reported_at.toISOString() : fields.reported_at;\n }\n return wire;\n}\n\nfunction toWireReport(report: FeedbackReport): Record<string, unknown> {\n const { solve_id, ...fields } = report;\n return { solve_id, ...toWireFields(fields) };\n}\n"]}
|