abysshub 0.0.1-dev.9 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,11 +1,11 @@
1
1
  # abysshub
2
2
 
3
- The official JavaScript library for the [Abyss](https://abysshub.com) API.
4
-
5
3
  Pre-release: the Abyss API opens soon.
6
4
 
5
+ The official JavaScript library for the [Abyss](https://abysshub.com) API.
6
+
7
7
  ```js
8
- import { Abyss, AbyssError } from "abysshub";
8
+ import Abyss, { AbyssError } from "abysshub";
9
9
 
10
10
  const abyss = new Abyss(); // reads ABYSS_API_KEY
11
11
 
@@ -18,6 +18,8 @@ try {
18
18
  }
19
19
  ```
20
20
 
21
+ `Abyss` is the package's default export, the form each Widget's page shows. The named form, `import { Abyss } from "abysshub"`, works too and is the same class.
22
+
21
23
  `run()` presses the Widget and waits for the run to end, however long it takes, then returns the succeeded run. A refusal or a failed run raises `AbyssError`.
22
24
 
23
25
  It runs on Node 20+, Bun and Deno, with no dependencies. An API key is a server-side secret, so in a browser `new Abyss()` throws.
@@ -46,7 +48,7 @@ const run = await abyss.run(widget, input, { maxPrice, idempotencyKey, timeout,
46
48
  - **`maxPrice`:** the most the run may cost, in Byssium. A higher price is refused with `price_above_max`, and nothing is charged.
47
49
  - **`idempotencyKey`:** each call presses with a fresh UUID `Idempotency-Key` unless you give one. Retries send the same one, so a run is never made or charged twice.
48
50
 
49
- The press holds until the run ends. When the hold ends early (a deploy cuts it, the API's holds are all taken, or an hour passes), `run()` re-attaches with `GET <Location>?wait=true` until the run ends. Re-attaching has no limit and is not a retry. Connecting has 10 s, and 30 s of silence counts as a cut.
51
+ The press holds until the run ends. When the hold ends early (a deploy cuts it, the network goes down, the API's holds are all taken, or an hour passes), `run()` re-attaches with `GET <Location>?wait=true` until the run ends. Re-attaching has no limit and is not a retry. Connecting has 10 s, and 30 s of silence counts as a cut.
50
52
 
51
53
  A **run** has `/v1`'s fields: `id`, `widget`, `status` (`queued`, `running`, `succeeded` or `failed`), `price`, `result`, `output_files`, `error`, `created_at`, `started_at` and `ended_at`.
52
54
 
@@ -80,7 +82,7 @@ while (page.has_more) page = await abyss.runs.list({ limit: 100, startingAfter:
80
82
  ## Files
81
83
 
82
84
  ```js
83
- import { Abyss, file } from "abysshub";
85
+ import Abyss, { file } from "abysshub";
84
86
 
85
87
  const run = await abyss.run("widget_1660", {
86
88
  report: file("report.pdf"),
@@ -121,7 +123,9 @@ A request is sent again, at most `maxRetries` times (2 by default), only after:
121
123
  - **`429 rate_limited` and `409 idempotency_key_in_use`:** after the `Retry-After` seconds;
122
124
  - **a `5xx`:** a short backoff (0.5 s, then 1 s).
123
125
 
124
- When the last try fails too, it raises. Every other refusal raises at once, and re-attaching never counts as a retry.
126
+ When the last try fails too, it raises. Every other refusal raises at once.
127
+
128
+ **Re-attaching never counts as a retry.** A re-attach that drops, or meets a `429`, `409` or `5xx`, is tried again with no limit until the network is back, pausing 0.5 s and doubling to at most 10 s (or the `Retry-After` seconds). Only `timeout` and `signal` stop it.
125
129
 
126
130
  ## Timeouts
127
131
 
package/dist/client.js CHANGED
@@ -10,6 +10,8 @@ const DEV_KEY_PREFIX = "abyss_sk_dev_";
10
10
  const REATTACH_PAUSE_MS = 1_000;
11
11
  /** The first pause before a retry after a drop or a 5xx; it doubles with each retry. */
12
12
  const RETRY_PAUSE_MS = 500;
13
+ /** The longest pause between two tries, which only re-attaching, with no limit, reaches. */
14
+ const RETRY_PAUSE_CEILING_MS = 10_000;
13
15
  const BROWSER_REFUSAL = "An Abyss API key is a server-side secret. Call the API from your server.";
14
16
  const USER_AGENT = `abysshub-js/${VERSION} (${runtime()})`;
15
17
  export class Abyss {
@@ -171,12 +173,16 @@ export class Abyss {
171
173
  async #get(call, url, is, message) {
172
174
  return expect(await this.#send(call, "GET", url), is, message);
173
175
  }
174
- /** Reads `url` until `done`. Re-attaching has no limit and is not a retry. */
176
+ /**
177
+ * Reads `url` until `done`. Re-attaching has no limit and is not a retry: a re-attach
178
+ * that drops, or meets a `429`, `409` or `5xx`, is tried again until the network is
179
+ * back, and only the call's `timeout` or `signal` stops it.
180
+ */
175
181
  async #hold(call, url, done) {
176
- let reply = await this.#send(call, "GET", url);
182
+ let reply = await this.#send(call, "GET", url, {}, undefined, Infinity);
177
183
  while (!done(reply)) {
178
184
  await sleep(REATTACH_PAUSE_MS, call.signal);
179
- reply = await this.#send(call, "GET", url);
185
+ reply = await this.#send(call, "GET", url, {}, undefined, Infinity);
180
186
  }
181
187
  return reply;
182
188
  }
@@ -201,9 +207,9 @@ export class Abyss {
201
207
  }
202
208
  /**
203
209
  * Sends one request to `/v1`. A drop before any headers, a `429`, a `409` and a `5xx`
204
- * are sent again, at most `maxRetries` times; every other refusal raises at once.
210
+ * are sent again, at most `retries` times; every other refusal raises at once.
205
211
  */
206
- async #send(call, method, url, headers = {}, body) {
212
+ async #send(call, method, url, headers = {}, body, retries = this.maxRetries) {
207
213
  const init = {
208
214
  method,
209
215
  headers: { Authorization: `Bearer ${this.#apiKey}`, Accept: "application/json", "User-Agent": USER_AGENT, ...headers },
@@ -218,7 +224,7 @@ export class Abyss {
218
224
  catch (error) {
219
225
  if (call.signal?.aborted)
220
226
  throw error;
221
- if (attempt >= this.maxRetries) {
227
+ if (attempt >= retries) {
222
228
  throw new AbyssError({
223
229
  code: "connection_error",
224
230
  message: "The connection dropped, or timed out, before the API answered.",
@@ -237,7 +243,7 @@ export class Abyss {
237
243
  return { body: parsed, run, cut: answer.text === null, location: answer.headers.get("location"), requestId };
238
244
  }
239
245
  const pause = retryPause(answer, attempt);
240
- if (pause === null || attempt >= this.maxRetries)
246
+ if (pause === null || attempt >= retries)
241
247
  throw refusal(answer.status, parsed, requestId);
242
248
  await sleep(pause, call.signal);
243
249
  }
@@ -253,7 +259,7 @@ function retryPause(answer, attempt) {
253
259
  return answer.status >= 500 ? backoff(attempt) : null;
254
260
  }
255
261
  function backoff(attempt) {
256
- return RETRY_PAUSE_MS * 2 ** attempt;
262
+ return Math.min(RETRY_PAUSE_MS * 2 ** attempt, RETRY_PAUSE_CEILING_MS);
257
263
  }
258
264
  /** The reply's body when it is what the route answers, else `unexpected_response`. */
259
265
  function expect(reply, is, message) {
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export { Abyss, type AbyssOptions, type CallOptions, type GetRunOptions, type ListRunsOptions, type RunOptions, type Runs, type UploadRequest, type Uploads, type Widgets, } from "./client.js";
1
+ export { Abyss, Abyss as default, type AbyssOptions, type CallOptions, type GetRunOptions, type ListRunsOptions, type RunOptions, type Runs, type UploadRequest, type Uploads, type Widgets, } from "./client.js";
2
2
  export { AbyssError, type AbyssErrorFields } from "./error.js";
3
3
  export { file, type FileData, type FileOptions, type InputFile } from "./files.js";
4
4
  export type { Run, RunFile } from "./run.js";
package/dist/index.js CHANGED
@@ -1,3 +1,3 @@
1
- export { Abyss, } from "./client.js";
1
+ export { Abyss, Abyss as default, } from "./client.js";
2
2
  export { AbyssError } from "./error.js";
3
3
  export { file } from "./files.js";
package/dist/version.d.ts CHANGED
@@ -1,2 +1,2 @@
1
1
  /** This package's version, written from package.json by scripts/version.js at build. */
2
- export declare const VERSION = "0.0.1-dev.9";
2
+ export declare const VERSION = "0.1.0";
package/dist/version.js CHANGED
@@ -1,2 +1,2 @@
1
1
  /** This package's version, written from package.json by scripts/version.js at build. */
2
- export const VERSION = "0.0.1-dev.9";
2
+ export const VERSION = "0.1.0";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "abysshub",
3
- "version": "0.0.1-dev.9",
3
+ "version": "0.1.0",
4
4
  "description": "The official JavaScript library for the Abyss API.",
5
5
  "license": "MIT",
6
6
  "homepage": "https://github.com/Abysshub/abysshub-sdk/tree/main/js#readme",