nonecap 0.3.0 → 0.4.1
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 +40 -2
- package/dist/index.cjs +94 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +144 -2
- package/dist/index.d.ts +144 -2
- package/dist/index.js +94 -2
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -20,7 +20,7 @@ Works on Node 18+, Bun, Deno, and edge runtimes. No dependencies.
|
|
|
20
20
|
|
|
21
21
|
## Quick start
|
|
22
22
|
|
|
23
|
-
Grab an API key from [dashboard.nonecap.com](https://dashboard.nonecap.com), then:
|
|
23
|
+
Grab an API key from [dashboard.nonecap.com](https://dashboard.nonecap.com/signup?utm_source=npm&utm_medium=sdk-readme), then:
|
|
24
24
|
|
|
25
25
|
```ts
|
|
26
26
|
import { NoneCap } from "nonecap";
|
|
@@ -101,7 +101,9 @@ const solve = await handle.result();
|
|
|
101
101
|
|
|
102
102
|
Cancelled and abandoned solves are **never charged** — nothing is billed unless a solve actually succeeds, and unfinished solves simply expire uncharged at the server deadline. So cancel is for cleanup and early-stop, not cost protection.
|
|
103
103
|
|
|
104
|
-
|
|
104
|
+
### Cleaning up after a `solve()` timeout
|
|
105
|
+
|
|
106
|
+
`solve()` blocks until the solve settles, so it hands you no handle to cancel a solve while it's still running — for that, use `solves.start()` above. The one thing the `solve()` path offers is cleanup *after* a timeout: when `solve()` throws `TimeoutError`, the error usually carries the in-flight `solveId` (and last-known `solve`), so you can cancel the solve the wait gave up on. Guard on `solveId` being present — if the very first submission times out at the transport level, no id has been assigned yet, so `solveId` is `undefined`.
|
|
105
107
|
|
|
106
108
|
```ts
|
|
107
109
|
import { TimeoutError } from "nonecap";
|
|
@@ -146,6 +148,42 @@ await nc.solve({
|
|
|
146
148
|
});
|
|
147
149
|
```
|
|
148
150
|
|
|
151
|
+
## Reporting token acceptance
|
|
152
|
+
|
|
153
|
+
A token that hCaptcha blessed can still be refused by the site you send it to. Tell us what happened and we tune minting against your real acceptance rate — it's free, and it's the fastest way to get a regression on your sitekey noticed.
|
|
154
|
+
|
|
155
|
+
Keep the `solve_id` next to the token you submit downstream, then report the verdict:
|
|
156
|
+
|
|
157
|
+
```ts
|
|
158
|
+
const solve = await nc.solve({ type: "hcaptcha", sitekey, url });
|
|
159
|
+
const ok = await submitToTheSiteYouAreAutomating(solve.token);
|
|
160
|
+
|
|
161
|
+
await nc.feedback.report({
|
|
162
|
+
solve_id: solve.id,
|
|
163
|
+
outcome: ok ? "accepted" : "rejected",
|
|
164
|
+
reason: ok ? undefined : "session invalidated", // optional, freeform
|
|
165
|
+
});
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
At volume, buffer the verdicts and flush them in one call. Reports over 500 are split across requests for you:
|
|
169
|
+
|
|
170
|
+
```ts
|
|
171
|
+
const batch = await nc.feedback.reportMany([
|
|
172
|
+
{ solve_id: "solve_01J...", outcome: "accepted" },
|
|
173
|
+
{ solve_id: "solve_01J...", outcome: "rejected", reason: "..." },
|
|
174
|
+
]);
|
|
175
|
+
|
|
176
|
+
// Items resolve independently, so the call succeeds even when some are
|
|
177
|
+
// rejected — check `failed` rather than relying on a throw.
|
|
178
|
+
if (batch.failed > 0) {
|
|
179
|
+
console.warn(batch.results.filter((r) => r.status === "error"));
|
|
180
|
+
}
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
`outcome` is one of `accepted`, `rejected`, `unknown` (submitted, verdict unclear), `unused` (never submitted), or `error` (downstream broke for a non-token reason). Only `accepted` and `rejected` count toward the acceptance rate.
|
|
184
|
+
|
|
185
|
+
Reporting the same solve again corrects the earlier verdict, so retries and late fixes are safe. You can report any of your own solved solves within ~30 days of the solve; corrections to something you already reported are never cut off by that window.
|
|
186
|
+
|
|
149
187
|
## Lower-level API
|
|
150
188
|
|
|
151
189
|
`solve()` is the convenient path. When you want control over submission and polling, the raw resource methods map one to one to the REST API.
|
package/dist/index.cjs
CHANGED
|
@@ -66,26 +66,35 @@ function errorFromResponse(status, code, message, param) {
|
|
|
66
66
|
case "account_locked":
|
|
67
67
|
return new PermissionError(message, opts);
|
|
68
68
|
case "insufficient_credits":
|
|
69
|
+
case "key_credit_limit_exceeded":
|
|
69
70
|
return new InsufficientCreditsError(message, opts);
|
|
70
71
|
case "invalid_request":
|
|
71
72
|
case "validation_error":
|
|
73
|
+
case "expired_window":
|
|
72
74
|
return new ValidationError(message, opts);
|
|
73
75
|
case "not_found":
|
|
76
|
+
case "not_eligible":
|
|
74
77
|
return new NotFoundError(message, opts);
|
|
75
78
|
case "conflict":
|
|
76
79
|
return new ConflictError(message, opts);
|
|
77
80
|
case "rate_limited":
|
|
78
81
|
case "concurrency_limit_exceeded":
|
|
79
82
|
case "ext_daily_limit":
|
|
83
|
+
case "sitekey_rate_limited":
|
|
80
84
|
return new RateLimitError(message, opts);
|
|
81
85
|
default:
|
|
82
86
|
return new APIError(message, opts);
|
|
83
87
|
}
|
|
84
88
|
}
|
|
85
89
|
|
|
90
|
+
// src/version.ts
|
|
91
|
+
var VERSION = "0.4.1";
|
|
92
|
+
|
|
86
93
|
// src/client.ts
|
|
87
94
|
var DEFAULT_BASE_URL = "https://api.nonecap.com";
|
|
95
|
+
var USER_AGENT = `nonecap-js/${VERSION}`;
|
|
88
96
|
var MAX_WAIT_SECONDS = 90;
|
|
97
|
+
var FEEDBACK_BATCH_MAX = 500;
|
|
89
98
|
var TERMINAL = /* @__PURE__ */ new Set([
|
|
90
99
|
"solved",
|
|
91
100
|
"failed",
|
|
@@ -176,6 +185,74 @@ var NoneCap = class {
|
|
|
176
185
|
*/
|
|
177
186
|
listAll: (params = {}, options = {}) => this.#listAll(params, options)
|
|
178
187
|
};
|
|
188
|
+
/**
|
|
189
|
+
* Report what your downstream target did with the tokens we minted.
|
|
190
|
+
*
|
|
191
|
+
* Feedback is free, own-solves-only, and idempotent per solve id: reporting
|
|
192
|
+
* the same solve again corrects the earlier verdict. Only `solved` solves can
|
|
193
|
+
* be reported, and only within the API's reporting window (~30 days from the
|
|
194
|
+
* solve; corrections to an already-reported solve are never re-gated by it).
|
|
195
|
+
*/
|
|
196
|
+
feedback = {
|
|
197
|
+
/**
|
|
198
|
+
* Report one solve's downstream outcome, returning the recorded feedback.
|
|
199
|
+
*
|
|
200
|
+
* Unlike {@link NoneCap.feedback.reportMany}, a rejected report throws:
|
|
201
|
+
* {@link NotFoundError} if the solve isn't yours or never minted a token,
|
|
202
|
+
* {@link ValidationError} if a field is wrong or the reporting window closed.
|
|
203
|
+
*
|
|
204
|
+
* ```ts
|
|
205
|
+
* await nc.feedback.report({ solve_id: solve.id, outcome: "rejected", reason: "..." });
|
|
206
|
+
* ```
|
|
207
|
+
*/
|
|
208
|
+
report: (report, options = {}) => {
|
|
209
|
+
const { solve_id, ...fields } = report;
|
|
210
|
+
return this.#request(
|
|
211
|
+
"POST",
|
|
212
|
+
`/v1/solves/${encodeURIComponent(solve_id)}/feedback`,
|
|
213
|
+
{ body: toWireFields(fields), signal: options.signal }
|
|
214
|
+
);
|
|
215
|
+
},
|
|
216
|
+
/**
|
|
217
|
+
* Report many verdicts at once — the path to use at volume. Buffer verdicts
|
|
218
|
+
* as you learn them and flush them here.
|
|
219
|
+
*
|
|
220
|
+
* The call succeeds even when individual items are rejected: each is
|
|
221
|
+
* resolved on its own so one stale id never discards the rest. Check
|
|
222
|
+
* `failed` rather than relying on a thrown error.
|
|
223
|
+
*
|
|
224
|
+
* More than {@link FEEDBACK_BATCH_MAX} reports are split across sequential
|
|
225
|
+
* requests and merged into one result, in request order. An empty array is
|
|
226
|
+
* a no-op that returns an empty batch without a request.
|
|
227
|
+
*
|
|
228
|
+
* ```ts
|
|
229
|
+
* const batch = await nc.feedback.reportMany(buffer);
|
|
230
|
+
* if (batch.failed) console.warn(batch.results.filter((r) => r.status === "error"));
|
|
231
|
+
* ```
|
|
232
|
+
*/
|
|
233
|
+
reportMany: async (reports, options = {}) => {
|
|
234
|
+
const merged = {
|
|
235
|
+
object: "feedback_batch",
|
|
236
|
+
recorded: 0,
|
|
237
|
+
updated: 0,
|
|
238
|
+
unchanged: 0,
|
|
239
|
+
failed: 0,
|
|
240
|
+
results: []
|
|
241
|
+
};
|
|
242
|
+
for (let i = 0; i < reports.length; i += FEEDBACK_BATCH_MAX) {
|
|
243
|
+
const batch = await this.#request("POST", "/v1/feedback", {
|
|
244
|
+
body: { feedback: reports.slice(i, i + FEEDBACK_BATCH_MAX).map(toWireReport) },
|
|
245
|
+
signal: options.signal
|
|
246
|
+
});
|
|
247
|
+
merged.recorded += batch.recorded;
|
|
248
|
+
merged.updated += batch.updated;
|
|
249
|
+
merged.unchanged += batch.unchanged;
|
|
250
|
+
merged.failed += batch.failed;
|
|
251
|
+
merged.results.push(...batch.results);
|
|
252
|
+
}
|
|
253
|
+
return merged;
|
|
254
|
+
}
|
|
255
|
+
};
|
|
179
256
|
/** Fetch your account, including the current credit balance. */
|
|
180
257
|
me(options = {}) {
|
|
181
258
|
return this.#request("GET", "/v1/me", { signal: options.signal });
|
|
@@ -218,7 +295,9 @@ var NoneCap = class {
|
|
|
218
295
|
}
|
|
219
296
|
const headers = {
|
|
220
297
|
Authorization: `Bearer ${this.#apiKey}`,
|
|
221
|
-
Accept: "application/json"
|
|
298
|
+
Accept: "application/json",
|
|
299
|
+
// Browsers drop this as a forbidden header; on Node it identifies the SDK.
|
|
300
|
+
"User-Agent": USER_AGENT
|
|
222
301
|
};
|
|
223
302
|
let bodyInit;
|
|
224
303
|
if (options.body !== void 0) {
|
|
@@ -386,11 +465,25 @@ function waitSeconds(deadline) {
|
|
|
386
465
|
function isAbort(err) {
|
|
387
466
|
return err instanceof Error && err.name === "AbortError";
|
|
388
467
|
}
|
|
468
|
+
function toWireFields(fields) {
|
|
469
|
+
const wire = { outcome: fields.outcome };
|
|
470
|
+
if (fields.estado !== void 0) wire.estado = fields.estado;
|
|
471
|
+
if (fields.reason !== void 0) wire.reason = fields.reason;
|
|
472
|
+
if (fields.reported_at !== void 0) {
|
|
473
|
+
wire.reported_at = fields.reported_at instanceof Date ? fields.reported_at.toISOString() : fields.reported_at;
|
|
474
|
+
}
|
|
475
|
+
return wire;
|
|
476
|
+
}
|
|
477
|
+
function toWireReport(report) {
|
|
478
|
+
const { solve_id, ...fields } = report;
|
|
479
|
+
return { solve_id, ...toWireFields(fields) };
|
|
480
|
+
}
|
|
389
481
|
|
|
390
482
|
exports.APIError = APIError;
|
|
391
483
|
exports.AuthenticationError = AuthenticationError;
|
|
392
484
|
exports.ConflictError = ConflictError;
|
|
393
485
|
exports.ConnectionError = ConnectionError;
|
|
486
|
+
exports.FEEDBACK_BATCH_MAX = FEEDBACK_BATCH_MAX;
|
|
394
487
|
exports.InsufficientCreditsError = InsufficientCreditsError;
|
|
395
488
|
exports.NoneCap = NoneCap;
|
|
396
489
|
exports.NoneCapError = NoneCapError;
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/errors.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;AACH,MAAA,OAAO,IAAI,wBAAA,CAAyB,OAAA,EAAS,IAAI,CAAA;AAAA,IACnD,KAAK,iBAAA;AAAA,IACL,KAAK,kBAAA;AACH,MAAA,OAAO,IAAI,eAAA,CAAgB,OAAA,EAAS,IAAI,CAAA;AAAA,IAC1C,KAAK,WAAA;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;AACH,MAAA,OAAO,IAAI,cAAA,CAAe,OAAA,EAAS,IAAI,CAAA;AAAA,IACzC;AACE,MAAA,OAAO,IAAI,QAAA,CAAS,OAAA,EAAS,IAAI,CAAA;AAAA;AAEvC;;;AChHA,IAAM,gBAAA,GAAmB,yBAAA;AAEzB,IAAM,gBAAA,GAAmB,EAAA;AACzB,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,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;AAAA,KACV;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","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 return new InsufficientCreditsError(message, opts);\n case \"invalid_request\":\n case \"validation_error\":\n return new ValidationError(message, opts);\n case \"not_found\":\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 return new RateLimitError(message, opts);\n default:\n return new APIError(message, opts);\n }\n}\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 Solve,\n SolveCreateParams,\n SolveList,\n SolveListParams,\n SolveStatus,\n} from \"./types.js\";\n\nconst DEFAULT_BASE_URL = \"https://api.nonecap.com\";\n/** The API caps server-side long-poll at 90 seconds. */\nconst MAX_WAIT_SECONDS = 90;\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 /** 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 };\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"]}
|
|
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\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. `test/version.test.ts` fails if this drifts from package.json.\n */\nexport const VERSION = \"0.4.1\";\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.estado !== undefined) wire.estado = fields.estado;\n if (fields.reason !== undefined) wire.reason = fields.reason;\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
|
@@ -89,6 +89,94 @@ interface SolveList {
|
|
|
89
89
|
data: Solve[];
|
|
90
90
|
has_more: boolean;
|
|
91
91
|
}
|
|
92
|
+
/**
|
|
93
|
+
* What the downstream target did with a solve's token.
|
|
94
|
+
*
|
|
95
|
+
* Only `accepted` and `rejected` count toward the acceptance rate — the other
|
|
96
|
+
* three are recorded but kept out of the denominator, so a client-side outage
|
|
97
|
+
* can't look like a token-quality regression.
|
|
98
|
+
*/
|
|
99
|
+
type FeedbackOutcome =
|
|
100
|
+
/** Downstream accepted the token. */
|
|
101
|
+
"accepted"
|
|
102
|
+
/** Downstream rejected the token. */
|
|
103
|
+
| "rejected"
|
|
104
|
+
/** Token was submitted but the verdict couldn't be determined. */
|
|
105
|
+
| "unknown"
|
|
106
|
+
/** Token was never submitted downstream (expired, aborted, deduped). */
|
|
107
|
+
| "unused"
|
|
108
|
+
/** Downstream failed for a non-token reason (network, 5xx, maintenance). */
|
|
109
|
+
| "error";
|
|
110
|
+
/**
|
|
111
|
+
* One verdict to report, for {@link NoneCap.feedback.report} and
|
|
112
|
+
* {@link NoneCap.feedback.reportMany}.
|
|
113
|
+
*/
|
|
114
|
+
interface FeedbackReport {
|
|
115
|
+
/** The solve id returned by `solves.create` / `solve()`. Must be your own, `solved` solve. */
|
|
116
|
+
solve_id: string;
|
|
117
|
+
outcome: FeedbackOutcome;
|
|
118
|
+
/**
|
|
119
|
+
* The raw downstream boolean, when your target has one (OSIPTEL's `estado`:
|
|
120
|
+
* `false` = accepted, `true` = rejected). Stored verbatim. The API rejects an
|
|
121
|
+
* item whose `estado` disagrees with its `outcome`.
|
|
122
|
+
*/
|
|
123
|
+
estado?: boolean | null;
|
|
124
|
+
/** Freeform downstream reason or code. Truncated to 512 chars server-side. */
|
|
125
|
+
reason?: string | null;
|
|
126
|
+
/** When the verdict happened. Advisory only — the server stamps its own timestamps. */
|
|
127
|
+
reported_at?: string | Date | null;
|
|
128
|
+
}
|
|
129
|
+
/** A recorded feedback resource. */
|
|
130
|
+
interface Feedback {
|
|
131
|
+
object: "feedback";
|
|
132
|
+
solve_id: string;
|
|
133
|
+
outcome: FeedbackOutcome;
|
|
134
|
+
estado: boolean | null;
|
|
135
|
+
reason: string | null;
|
|
136
|
+
reported_at: string | null;
|
|
137
|
+
/** How many times this solve's verdict has been written. 1 on first report. */
|
|
138
|
+
report_count: number;
|
|
139
|
+
created_at: string;
|
|
140
|
+
updated_at: string;
|
|
141
|
+
}
|
|
142
|
+
/** What happened to one item of a batch. */
|
|
143
|
+
type FeedbackStatus =
|
|
144
|
+
/** First report for this solve. */
|
|
145
|
+
"recorded"
|
|
146
|
+
/** Overwrote an earlier report. */
|
|
147
|
+
| "updated"
|
|
148
|
+
/** Identical to what was already stored — no write. */
|
|
149
|
+
| "unchanged"
|
|
150
|
+
/** Rejected; see `error`. */
|
|
151
|
+
| "error";
|
|
152
|
+
/** One item's result, in the same position as the report you sent. */
|
|
153
|
+
interface FeedbackResult {
|
|
154
|
+
solve_id: string;
|
|
155
|
+
status: FeedbackStatus;
|
|
156
|
+
/** Set only when `status === "error"`. Note the bare shape: no `error` wrapper. */
|
|
157
|
+
error: {
|
|
158
|
+
code: ErrorCode;
|
|
159
|
+
message: string;
|
|
160
|
+
param: string | null;
|
|
161
|
+
} | null;
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* The result of {@link NoneCap.feedback.reportMany}.
|
|
165
|
+
*
|
|
166
|
+
* Items are resolved independently, so one bad solve id never discards the
|
|
167
|
+
* rest — which also means a broken integration reports zero failures at the
|
|
168
|
+
* HTTP level. Check `failed` (or scan `results`), not just the absence of a
|
|
169
|
+
* thrown error.
|
|
170
|
+
*/
|
|
171
|
+
interface FeedbackBatch {
|
|
172
|
+
object: "feedback_batch";
|
|
173
|
+
recorded: number;
|
|
174
|
+
updated: number;
|
|
175
|
+
unchanged: number;
|
|
176
|
+
failed: number;
|
|
177
|
+
/** One entry per report you sent, in request order. */
|
|
178
|
+
results: FeedbackResult[];
|
|
179
|
+
}
|
|
92
180
|
/** Your account, including the current credit balance. */
|
|
93
181
|
interface Account {
|
|
94
182
|
object: "account";
|
|
@@ -98,7 +186,15 @@ interface Account {
|
|
|
98
186
|
created_at: string;
|
|
99
187
|
}
|
|
100
188
|
/** Error codes returned in the API's error envelope. */
|
|
101
|
-
type ErrorCode = "unauthorized" | "forbidden" | "account_locked" | "insufficient_credits" | "invalid_request" | "validation_error" | "not_found" | "conflict" | "rate_limited" | "ext_daily_limit" | "concurrency_limit_exceeded"
|
|
189
|
+
type ErrorCode = "unauthorized" | "forbidden" | "account_locked" | "insufficient_credits" | "invalid_request" | "validation_error" | "not_found" | "conflict" | "rate_limited" | "ext_daily_limit" | "concurrency_limit_exceeded"
|
|
190
|
+
/** hCaptcha is rate-limiting this sitekey; the submit was shed. Honour `Retry-After`. */
|
|
191
|
+
| "sitekey_rate_limited"
|
|
192
|
+
/** The submitting API key hit its own spend cap. */
|
|
193
|
+
| "key_credit_limit_exceeded"
|
|
194
|
+
/** Feedback: the solve is missing, not yours, or never produced a token. */
|
|
195
|
+
| "not_eligible"
|
|
196
|
+
/** Feedback: a first report arrived after the reporting window closed. */
|
|
197
|
+
| "expired_window" | "internal_error" | "pool_exhausted";
|
|
102
198
|
/** The Stripe-style error envelope every non-2xx response carries. */
|
|
103
199
|
interface ErrorEnvelope {
|
|
104
200
|
error: {
|
|
@@ -108,6 +204,8 @@ interface ErrorEnvelope {
|
|
|
108
204
|
};
|
|
109
205
|
}
|
|
110
206
|
|
|
207
|
+
/** The API caps one `POST /v1/feedback` call at 500 items. */
|
|
208
|
+
declare const FEEDBACK_BATCH_MAX = 500;
|
|
111
209
|
/** Is this a terminal solve status? */
|
|
112
210
|
declare function isTerminal(status: SolveStatus): boolean;
|
|
113
211
|
/** A `fetch` implementation. Defaults to the global `fetch`. */
|
|
@@ -205,6 +303,50 @@ declare class NoneCap {
|
|
|
205
303
|
signal?: AbortSignal;
|
|
206
304
|
}) => AsyncIterableIterator<Solve>;
|
|
207
305
|
};
|
|
306
|
+
/**
|
|
307
|
+
* Report what your downstream target did with the tokens we minted.
|
|
308
|
+
*
|
|
309
|
+
* Feedback is free, own-solves-only, and idempotent per solve id: reporting
|
|
310
|
+
* the same solve again corrects the earlier verdict. Only `solved` solves can
|
|
311
|
+
* be reported, and only within the API's reporting window (~30 days from the
|
|
312
|
+
* solve; corrections to an already-reported solve are never re-gated by it).
|
|
313
|
+
*/
|
|
314
|
+
readonly feedback: {
|
|
315
|
+
/**
|
|
316
|
+
* Report one solve's downstream outcome, returning the recorded feedback.
|
|
317
|
+
*
|
|
318
|
+
* Unlike {@link NoneCap.feedback.reportMany}, a rejected report throws:
|
|
319
|
+
* {@link NotFoundError} if the solve isn't yours or never minted a token,
|
|
320
|
+
* {@link ValidationError} if a field is wrong or the reporting window closed.
|
|
321
|
+
*
|
|
322
|
+
* ```ts
|
|
323
|
+
* await nc.feedback.report({ solve_id: solve.id, outcome: "rejected", reason: "..." });
|
|
324
|
+
* ```
|
|
325
|
+
*/
|
|
326
|
+
report: (report: FeedbackReport, options?: {
|
|
327
|
+
signal?: AbortSignal;
|
|
328
|
+
}) => Promise<Feedback>;
|
|
329
|
+
/**
|
|
330
|
+
* Report many verdicts at once — the path to use at volume. Buffer verdicts
|
|
331
|
+
* as you learn them and flush them here.
|
|
332
|
+
*
|
|
333
|
+
* The call succeeds even when individual items are rejected: each is
|
|
334
|
+
* resolved on its own so one stale id never discards the rest. Check
|
|
335
|
+
* `failed` rather than relying on a thrown error.
|
|
336
|
+
*
|
|
337
|
+
* More than {@link FEEDBACK_BATCH_MAX} reports are split across sequential
|
|
338
|
+
* requests and merged into one result, in request order. An empty array is
|
|
339
|
+
* a no-op that returns an empty batch without a request.
|
|
340
|
+
*
|
|
341
|
+
* ```ts
|
|
342
|
+
* const batch = await nc.feedback.reportMany(buffer);
|
|
343
|
+
* if (batch.failed) console.warn(batch.results.filter((r) => r.status === "error"));
|
|
344
|
+
* ```
|
|
345
|
+
*/
|
|
346
|
+
reportMany: (reports: readonly FeedbackReport[], options?: {
|
|
347
|
+
signal?: AbortSignal;
|
|
348
|
+
}) => Promise<FeedbackBatch>;
|
|
349
|
+
};
|
|
208
350
|
/** Fetch your account, including the current credit balance. */
|
|
209
351
|
me(options?: {
|
|
210
352
|
signal?: AbortSignal;
|
|
@@ -341,4 +483,4 @@ declare class TimeoutError extends NoneCapError {
|
|
|
341
483
|
});
|
|
342
484
|
}
|
|
343
485
|
|
|
344
|
-
export { APIError, type Account, AuthenticationError, ConflictError, ConnectionError, type ErrorCode, type ErrorEnvelope, 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 };
|
|
486
|
+
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 };
|
package/dist/index.d.ts
CHANGED
|
@@ -89,6 +89,94 @@ interface SolveList {
|
|
|
89
89
|
data: Solve[];
|
|
90
90
|
has_more: boolean;
|
|
91
91
|
}
|
|
92
|
+
/**
|
|
93
|
+
* What the downstream target did with a solve's token.
|
|
94
|
+
*
|
|
95
|
+
* Only `accepted` and `rejected` count toward the acceptance rate — the other
|
|
96
|
+
* three are recorded but kept out of the denominator, so a client-side outage
|
|
97
|
+
* can't look like a token-quality regression.
|
|
98
|
+
*/
|
|
99
|
+
type FeedbackOutcome =
|
|
100
|
+
/** Downstream accepted the token. */
|
|
101
|
+
"accepted"
|
|
102
|
+
/** Downstream rejected the token. */
|
|
103
|
+
| "rejected"
|
|
104
|
+
/** Token was submitted but the verdict couldn't be determined. */
|
|
105
|
+
| "unknown"
|
|
106
|
+
/** Token was never submitted downstream (expired, aborted, deduped). */
|
|
107
|
+
| "unused"
|
|
108
|
+
/** Downstream failed for a non-token reason (network, 5xx, maintenance). */
|
|
109
|
+
| "error";
|
|
110
|
+
/**
|
|
111
|
+
* One verdict to report, for {@link NoneCap.feedback.report} and
|
|
112
|
+
* {@link NoneCap.feedback.reportMany}.
|
|
113
|
+
*/
|
|
114
|
+
interface FeedbackReport {
|
|
115
|
+
/** The solve id returned by `solves.create` / `solve()`. Must be your own, `solved` solve. */
|
|
116
|
+
solve_id: string;
|
|
117
|
+
outcome: FeedbackOutcome;
|
|
118
|
+
/**
|
|
119
|
+
* The raw downstream boolean, when your target has one (OSIPTEL's `estado`:
|
|
120
|
+
* `false` = accepted, `true` = rejected). Stored verbatim. The API rejects an
|
|
121
|
+
* item whose `estado` disagrees with its `outcome`.
|
|
122
|
+
*/
|
|
123
|
+
estado?: boolean | null;
|
|
124
|
+
/** Freeform downstream reason or code. Truncated to 512 chars server-side. */
|
|
125
|
+
reason?: string | null;
|
|
126
|
+
/** When the verdict happened. Advisory only — the server stamps its own timestamps. */
|
|
127
|
+
reported_at?: string | Date | null;
|
|
128
|
+
}
|
|
129
|
+
/** A recorded feedback resource. */
|
|
130
|
+
interface Feedback {
|
|
131
|
+
object: "feedback";
|
|
132
|
+
solve_id: string;
|
|
133
|
+
outcome: FeedbackOutcome;
|
|
134
|
+
estado: boolean | null;
|
|
135
|
+
reason: string | null;
|
|
136
|
+
reported_at: string | null;
|
|
137
|
+
/** How many times this solve's verdict has been written. 1 on first report. */
|
|
138
|
+
report_count: number;
|
|
139
|
+
created_at: string;
|
|
140
|
+
updated_at: string;
|
|
141
|
+
}
|
|
142
|
+
/** What happened to one item of a batch. */
|
|
143
|
+
type FeedbackStatus =
|
|
144
|
+
/** First report for this solve. */
|
|
145
|
+
"recorded"
|
|
146
|
+
/** Overwrote an earlier report. */
|
|
147
|
+
| "updated"
|
|
148
|
+
/** Identical to what was already stored — no write. */
|
|
149
|
+
| "unchanged"
|
|
150
|
+
/** Rejected; see `error`. */
|
|
151
|
+
| "error";
|
|
152
|
+
/** One item's result, in the same position as the report you sent. */
|
|
153
|
+
interface FeedbackResult {
|
|
154
|
+
solve_id: string;
|
|
155
|
+
status: FeedbackStatus;
|
|
156
|
+
/** Set only when `status === "error"`. Note the bare shape: no `error` wrapper. */
|
|
157
|
+
error: {
|
|
158
|
+
code: ErrorCode;
|
|
159
|
+
message: string;
|
|
160
|
+
param: string | null;
|
|
161
|
+
} | null;
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* The result of {@link NoneCap.feedback.reportMany}.
|
|
165
|
+
*
|
|
166
|
+
* Items are resolved independently, so one bad solve id never discards the
|
|
167
|
+
* rest — which also means a broken integration reports zero failures at the
|
|
168
|
+
* HTTP level. Check `failed` (or scan `results`), not just the absence of a
|
|
169
|
+
* thrown error.
|
|
170
|
+
*/
|
|
171
|
+
interface FeedbackBatch {
|
|
172
|
+
object: "feedback_batch";
|
|
173
|
+
recorded: number;
|
|
174
|
+
updated: number;
|
|
175
|
+
unchanged: number;
|
|
176
|
+
failed: number;
|
|
177
|
+
/** One entry per report you sent, in request order. */
|
|
178
|
+
results: FeedbackResult[];
|
|
179
|
+
}
|
|
92
180
|
/** Your account, including the current credit balance. */
|
|
93
181
|
interface Account {
|
|
94
182
|
object: "account";
|
|
@@ -98,7 +186,15 @@ interface Account {
|
|
|
98
186
|
created_at: string;
|
|
99
187
|
}
|
|
100
188
|
/** Error codes returned in the API's error envelope. */
|
|
101
|
-
type ErrorCode = "unauthorized" | "forbidden" | "account_locked" | "insufficient_credits" | "invalid_request" | "validation_error" | "not_found" | "conflict" | "rate_limited" | "ext_daily_limit" | "concurrency_limit_exceeded"
|
|
189
|
+
type ErrorCode = "unauthorized" | "forbidden" | "account_locked" | "insufficient_credits" | "invalid_request" | "validation_error" | "not_found" | "conflict" | "rate_limited" | "ext_daily_limit" | "concurrency_limit_exceeded"
|
|
190
|
+
/** hCaptcha is rate-limiting this sitekey; the submit was shed. Honour `Retry-After`. */
|
|
191
|
+
| "sitekey_rate_limited"
|
|
192
|
+
/** The submitting API key hit its own spend cap. */
|
|
193
|
+
| "key_credit_limit_exceeded"
|
|
194
|
+
/** Feedback: the solve is missing, not yours, or never produced a token. */
|
|
195
|
+
| "not_eligible"
|
|
196
|
+
/** Feedback: a first report arrived after the reporting window closed. */
|
|
197
|
+
| "expired_window" | "internal_error" | "pool_exhausted";
|
|
102
198
|
/** The Stripe-style error envelope every non-2xx response carries. */
|
|
103
199
|
interface ErrorEnvelope {
|
|
104
200
|
error: {
|
|
@@ -108,6 +204,8 @@ interface ErrorEnvelope {
|
|
|
108
204
|
};
|
|
109
205
|
}
|
|
110
206
|
|
|
207
|
+
/** The API caps one `POST /v1/feedback` call at 500 items. */
|
|
208
|
+
declare const FEEDBACK_BATCH_MAX = 500;
|
|
111
209
|
/** Is this a terminal solve status? */
|
|
112
210
|
declare function isTerminal(status: SolveStatus): boolean;
|
|
113
211
|
/** A `fetch` implementation. Defaults to the global `fetch`. */
|
|
@@ -205,6 +303,50 @@ declare class NoneCap {
|
|
|
205
303
|
signal?: AbortSignal;
|
|
206
304
|
}) => AsyncIterableIterator<Solve>;
|
|
207
305
|
};
|
|
306
|
+
/**
|
|
307
|
+
* Report what your downstream target did with the tokens we minted.
|
|
308
|
+
*
|
|
309
|
+
* Feedback is free, own-solves-only, and idempotent per solve id: reporting
|
|
310
|
+
* the same solve again corrects the earlier verdict. Only `solved` solves can
|
|
311
|
+
* be reported, and only within the API's reporting window (~30 days from the
|
|
312
|
+
* solve; corrections to an already-reported solve are never re-gated by it).
|
|
313
|
+
*/
|
|
314
|
+
readonly feedback: {
|
|
315
|
+
/**
|
|
316
|
+
* Report one solve's downstream outcome, returning the recorded feedback.
|
|
317
|
+
*
|
|
318
|
+
* Unlike {@link NoneCap.feedback.reportMany}, a rejected report throws:
|
|
319
|
+
* {@link NotFoundError} if the solve isn't yours or never minted a token,
|
|
320
|
+
* {@link ValidationError} if a field is wrong or the reporting window closed.
|
|
321
|
+
*
|
|
322
|
+
* ```ts
|
|
323
|
+
* await nc.feedback.report({ solve_id: solve.id, outcome: "rejected", reason: "..." });
|
|
324
|
+
* ```
|
|
325
|
+
*/
|
|
326
|
+
report: (report: FeedbackReport, options?: {
|
|
327
|
+
signal?: AbortSignal;
|
|
328
|
+
}) => Promise<Feedback>;
|
|
329
|
+
/**
|
|
330
|
+
* Report many verdicts at once — the path to use at volume. Buffer verdicts
|
|
331
|
+
* as you learn them and flush them here.
|
|
332
|
+
*
|
|
333
|
+
* The call succeeds even when individual items are rejected: each is
|
|
334
|
+
* resolved on its own so one stale id never discards the rest. Check
|
|
335
|
+
* `failed` rather than relying on a thrown error.
|
|
336
|
+
*
|
|
337
|
+
* More than {@link FEEDBACK_BATCH_MAX} reports are split across sequential
|
|
338
|
+
* requests and merged into one result, in request order. An empty array is
|
|
339
|
+
* a no-op that returns an empty batch without a request.
|
|
340
|
+
*
|
|
341
|
+
* ```ts
|
|
342
|
+
* const batch = await nc.feedback.reportMany(buffer);
|
|
343
|
+
* if (batch.failed) console.warn(batch.results.filter((r) => r.status === "error"));
|
|
344
|
+
* ```
|
|
345
|
+
*/
|
|
346
|
+
reportMany: (reports: readonly FeedbackReport[], options?: {
|
|
347
|
+
signal?: AbortSignal;
|
|
348
|
+
}) => Promise<FeedbackBatch>;
|
|
349
|
+
};
|
|
208
350
|
/** Fetch your account, including the current credit balance. */
|
|
209
351
|
me(options?: {
|
|
210
352
|
signal?: AbortSignal;
|
|
@@ -341,4 +483,4 @@ declare class TimeoutError extends NoneCapError {
|
|
|
341
483
|
});
|
|
342
484
|
}
|
|
343
485
|
|
|
344
|
-
export { APIError, type Account, AuthenticationError, ConflictError, ConnectionError, type ErrorCode, type ErrorEnvelope, 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 };
|
|
486
|
+
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 };
|
package/dist/index.js
CHANGED
|
@@ -64,26 +64,35 @@ function errorFromResponse(status, code, message, param) {
|
|
|
64
64
|
case "account_locked":
|
|
65
65
|
return new PermissionError(message, opts);
|
|
66
66
|
case "insufficient_credits":
|
|
67
|
+
case "key_credit_limit_exceeded":
|
|
67
68
|
return new InsufficientCreditsError(message, opts);
|
|
68
69
|
case "invalid_request":
|
|
69
70
|
case "validation_error":
|
|
71
|
+
case "expired_window":
|
|
70
72
|
return new ValidationError(message, opts);
|
|
71
73
|
case "not_found":
|
|
74
|
+
case "not_eligible":
|
|
72
75
|
return new NotFoundError(message, opts);
|
|
73
76
|
case "conflict":
|
|
74
77
|
return new ConflictError(message, opts);
|
|
75
78
|
case "rate_limited":
|
|
76
79
|
case "concurrency_limit_exceeded":
|
|
77
80
|
case "ext_daily_limit":
|
|
81
|
+
case "sitekey_rate_limited":
|
|
78
82
|
return new RateLimitError(message, opts);
|
|
79
83
|
default:
|
|
80
84
|
return new APIError(message, opts);
|
|
81
85
|
}
|
|
82
86
|
}
|
|
83
87
|
|
|
88
|
+
// src/version.ts
|
|
89
|
+
var VERSION = "0.4.1";
|
|
90
|
+
|
|
84
91
|
// src/client.ts
|
|
85
92
|
var DEFAULT_BASE_URL = "https://api.nonecap.com";
|
|
93
|
+
var USER_AGENT = `nonecap-js/${VERSION}`;
|
|
86
94
|
var MAX_WAIT_SECONDS = 90;
|
|
95
|
+
var FEEDBACK_BATCH_MAX = 500;
|
|
87
96
|
var TERMINAL = /* @__PURE__ */ new Set([
|
|
88
97
|
"solved",
|
|
89
98
|
"failed",
|
|
@@ -174,6 +183,74 @@ var NoneCap = class {
|
|
|
174
183
|
*/
|
|
175
184
|
listAll: (params = {}, options = {}) => this.#listAll(params, options)
|
|
176
185
|
};
|
|
186
|
+
/**
|
|
187
|
+
* Report what your downstream target did with the tokens we minted.
|
|
188
|
+
*
|
|
189
|
+
* Feedback is free, own-solves-only, and idempotent per solve id: reporting
|
|
190
|
+
* the same solve again corrects the earlier verdict. Only `solved` solves can
|
|
191
|
+
* be reported, and only within the API's reporting window (~30 days from the
|
|
192
|
+
* solve; corrections to an already-reported solve are never re-gated by it).
|
|
193
|
+
*/
|
|
194
|
+
feedback = {
|
|
195
|
+
/**
|
|
196
|
+
* Report one solve's downstream outcome, returning the recorded feedback.
|
|
197
|
+
*
|
|
198
|
+
* Unlike {@link NoneCap.feedback.reportMany}, a rejected report throws:
|
|
199
|
+
* {@link NotFoundError} if the solve isn't yours or never minted a token,
|
|
200
|
+
* {@link ValidationError} if a field is wrong or the reporting window closed.
|
|
201
|
+
*
|
|
202
|
+
* ```ts
|
|
203
|
+
* await nc.feedback.report({ solve_id: solve.id, outcome: "rejected", reason: "..." });
|
|
204
|
+
* ```
|
|
205
|
+
*/
|
|
206
|
+
report: (report, options = {}) => {
|
|
207
|
+
const { solve_id, ...fields } = report;
|
|
208
|
+
return this.#request(
|
|
209
|
+
"POST",
|
|
210
|
+
`/v1/solves/${encodeURIComponent(solve_id)}/feedback`,
|
|
211
|
+
{ body: toWireFields(fields), signal: options.signal }
|
|
212
|
+
);
|
|
213
|
+
},
|
|
214
|
+
/**
|
|
215
|
+
* Report many verdicts at once — the path to use at volume. Buffer verdicts
|
|
216
|
+
* as you learn them and flush them here.
|
|
217
|
+
*
|
|
218
|
+
* The call succeeds even when individual items are rejected: each is
|
|
219
|
+
* resolved on its own so one stale id never discards the rest. Check
|
|
220
|
+
* `failed` rather than relying on a thrown error.
|
|
221
|
+
*
|
|
222
|
+
* More than {@link FEEDBACK_BATCH_MAX} reports are split across sequential
|
|
223
|
+
* requests and merged into one result, in request order. An empty array is
|
|
224
|
+
* a no-op that returns an empty batch without a request.
|
|
225
|
+
*
|
|
226
|
+
* ```ts
|
|
227
|
+
* const batch = await nc.feedback.reportMany(buffer);
|
|
228
|
+
* if (batch.failed) console.warn(batch.results.filter((r) => r.status === "error"));
|
|
229
|
+
* ```
|
|
230
|
+
*/
|
|
231
|
+
reportMany: async (reports, options = {}) => {
|
|
232
|
+
const merged = {
|
|
233
|
+
object: "feedback_batch",
|
|
234
|
+
recorded: 0,
|
|
235
|
+
updated: 0,
|
|
236
|
+
unchanged: 0,
|
|
237
|
+
failed: 0,
|
|
238
|
+
results: []
|
|
239
|
+
};
|
|
240
|
+
for (let i = 0; i < reports.length; i += FEEDBACK_BATCH_MAX) {
|
|
241
|
+
const batch = await this.#request("POST", "/v1/feedback", {
|
|
242
|
+
body: { feedback: reports.slice(i, i + FEEDBACK_BATCH_MAX).map(toWireReport) },
|
|
243
|
+
signal: options.signal
|
|
244
|
+
});
|
|
245
|
+
merged.recorded += batch.recorded;
|
|
246
|
+
merged.updated += batch.updated;
|
|
247
|
+
merged.unchanged += batch.unchanged;
|
|
248
|
+
merged.failed += batch.failed;
|
|
249
|
+
merged.results.push(...batch.results);
|
|
250
|
+
}
|
|
251
|
+
return merged;
|
|
252
|
+
}
|
|
253
|
+
};
|
|
177
254
|
/** Fetch your account, including the current credit balance. */
|
|
178
255
|
me(options = {}) {
|
|
179
256
|
return this.#request("GET", "/v1/me", { signal: options.signal });
|
|
@@ -216,7 +293,9 @@ var NoneCap = class {
|
|
|
216
293
|
}
|
|
217
294
|
const headers = {
|
|
218
295
|
Authorization: `Bearer ${this.#apiKey}`,
|
|
219
|
-
Accept: "application/json"
|
|
296
|
+
Accept: "application/json",
|
|
297
|
+
// Browsers drop this as a forbidden header; on Node it identifies the SDK.
|
|
298
|
+
"User-Agent": USER_AGENT
|
|
220
299
|
};
|
|
221
300
|
let bodyInit;
|
|
222
301
|
if (options.body !== void 0) {
|
|
@@ -384,7 +463,20 @@ function waitSeconds(deadline) {
|
|
|
384
463
|
function isAbort(err) {
|
|
385
464
|
return err instanceof Error && err.name === "AbortError";
|
|
386
465
|
}
|
|
466
|
+
function toWireFields(fields) {
|
|
467
|
+
const wire = { outcome: fields.outcome };
|
|
468
|
+
if (fields.estado !== void 0) wire.estado = fields.estado;
|
|
469
|
+
if (fields.reason !== void 0) wire.reason = fields.reason;
|
|
470
|
+
if (fields.reported_at !== void 0) {
|
|
471
|
+
wire.reported_at = fields.reported_at instanceof Date ? fields.reported_at.toISOString() : fields.reported_at;
|
|
472
|
+
}
|
|
473
|
+
return wire;
|
|
474
|
+
}
|
|
475
|
+
function toWireReport(report) {
|
|
476
|
+
const { solve_id, ...fields } = report;
|
|
477
|
+
return { solve_id, ...toWireFields(fields) };
|
|
478
|
+
}
|
|
387
479
|
|
|
388
|
-
export { APIError, AuthenticationError, ConflictError, ConnectionError, InsufficientCreditsError, NoneCap, NoneCapError, NotFoundError, PermissionError, RateLimitError, SolveFailedError, SolveHandle, TimeoutError, ValidationError, isTerminal };
|
|
480
|
+
export { APIError, AuthenticationError, ConflictError, ConnectionError, FEEDBACK_BATCH_MAX, InsufficientCreditsError, NoneCap, NoneCapError, NotFoundError, PermissionError, RateLimitError, SolveFailedError, SolveHandle, TimeoutError, ValidationError, isTerminal };
|
|
389
481
|
//# sourceMappingURL=index.js.map
|
|
390
482
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/errors.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 return new InsufficientCreditsError(message, opts);\n case \"invalid_request\":\n case \"validation_error\":\n return new ValidationError(message, opts);\n case \"not_found\":\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 return new RateLimitError(message, opts);\n default:\n return new APIError(message, opts);\n }\n}\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 Solve,\n SolveCreateParams,\n SolveList,\n SolveListParams,\n SolveStatus,\n} from \"./types.js\";\n\nconst DEFAULT_BASE_URL = \"https://api.nonecap.com\";\n/** The API caps server-side long-poll at 90 seconds. */\nconst MAX_WAIT_SECONDS = 90;\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 /** 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 };\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"]}
|
|
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. `test/version.test.ts` fails if this drifts from package.json.\n */\nexport const VERSION = \"0.4.1\";\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.estado !== undefined) wire.estado = fields.estado;\n if (fields.reason !== undefined) wire.reason = fields.reason;\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"]}
|