@hunt-labs/bytekit-sdk 0.2.2 → 0.4.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/dist/client.js CHANGED
@@ -6,6 +6,8 @@ import { MonitorsResource } from './resources/monitors.js';
6
6
  import { SitemapResource } from './resources/sitemap.js';
7
7
  import { SearchResource } from './resources/search.js';
8
8
  import { AccountResource } from './resources/account.js';
9
+ import { UsageResource } from './resources/usage.js';
10
+ import { WebhooksResource } from './resources/webhooks.js';
9
11
  const DEFAULT_BASE_URL = 'https://api.bytekit.com';
10
12
  /**
11
13
  * Default client-side request timeout (2 minutes).
@@ -122,12 +124,59 @@ function composeSignals(caller, timeout) {
122
124
  }
123
125
  return { signal: controller.signal, cleanup };
124
126
  }
125
- /** Map a `fetch` rejection onto the connection-error taxonomy. Never leaks the API key. */
127
+ /**
128
+ * Read a successful response body as text INSIDE the transport's abort-guarded region
129
+ * (#2546), short-circuiting a 204 to `undefined`. The `JSON.parse` step is deliberately
130
+ * kept OUT of the guard — see {@link parseJsonBody} — so a malformed body still surfaces
131
+ * its own SyntaxError rather than being remapped to a `ByteKitConnectionError`.
132
+ *
133
+ * Shared as the `readBody` continuation of `request()` and (wrapped) `requestWithResponse()`
134
+ * so empty-body/204 handling can never diverge between the two (#2547).
135
+ */
136
+ async function readSuccessText(response) {
137
+ return response.status === 204 ? undefined : await response.text();
138
+ }
139
+ /**
140
+ * Parse an already-read success body (see {@link readSuccessText}) into its JSON value.
141
+ *
142
+ * A 204 or otherwise-empty body resolves to `undefined` — this is how a successful
143
+ * `revoke()` (DELETE → 204) resolves instead of throwing a JSON-parse error. Runs OUTSIDE
144
+ * the transport's abort-guarded region (#2546), so `JSON.parse` failures stay ordinary
145
+ * SyntaxErrors. Shared by `request()` and `requestWithResponse()` (#2547).
146
+ */
147
+ function parseJsonBody(text) {
148
+ if (text === undefined || text.trim().length === 0) {
149
+ return undefined;
150
+ }
151
+ return JSON.parse(text);
152
+ }
153
+ /** The `name` of an error-shaped value, or `undefined` when it carries none. */
154
+ const nameOf = (e) => typeof e === 'object' && e !== null && 'name' in e ? String(e.name) : undefined;
155
+ /** The `cause` of an error-shaped value, or `undefined` when it carries none. */
156
+ const causeOf = (e) => typeof e === 'object' && e !== null && 'cause' in e ? e.cause : undefined;
157
+ /**
158
+ * The abort-taxonomy name of a rejection, seeing through undici's mid-body wrapper.
159
+ *
160
+ * When a request is aborted while its BODY is streaming, undici does not reject with the abort
161
+ * reason itself — it rejects with `TypeError: terminated` carrying the reason on `.cause` (#2546).
162
+ * A name-only check would read that as a plain connection failure. Nothing that reached this
163
+ * function before #2546 carried a `.cause`, so every previously-asserted classification is
164
+ * unchanged; a `.cause` whose own name is not abort-shaped still falls through to `'connection'`.
165
+ */
166
+ function abortNameOf(err) {
167
+ const top = nameOf(err);
168
+ if (top === 'TimeoutError' || top === 'AbortError')
169
+ return top;
170
+ return nameOf(causeOf(err));
171
+ }
172
+ /**
173
+ * Map a `fetch` or body-read rejection onto the connection-error taxonomy. Never leaks the API key.
174
+ */
126
175
  function toConnectionError(err, method, url, timeoutSignal) {
127
176
  // undici rejects an aborted fetch with the signal's own reason, so the thrown value's
128
- // `name` is the primary discriminator (`TimeoutError` / `AbortError`).
129
- const rawName = typeof err === 'object' && err !== null && 'name' in err ? err.name : undefined;
130
- const name = typeof rawName === 'string' ? rawName : '';
177
+ // `name` is the primary discriminator (`TimeoutError` / `AbortError`) — read through
178
+ // undici's mid-body `TypeError: terminated` wrapper when there is one.
179
+ const name = abortNameOf(err) ?? '';
131
180
  let code;
132
181
  if (name === 'TimeoutError') {
133
182
  code = 'timeout';
@@ -162,12 +211,18 @@ export class ByteKit {
162
211
  sitemap;
163
212
  search;
164
213
  account;
214
+ usage;
215
+ webhooks;
165
216
  constructor(options) {
166
217
  if (!options?.apiKey) {
167
218
  throw new TypeError('ByteKit: `apiKey` is required — got an empty value. Pass options.apiKey (e.g. from process.env.BYTEKIT_API_KEY).');
168
219
  }
169
220
  this.apiKey = options.apiKey;
170
- this.baseUrl = options.baseUrl ?? DEFAULT_BASE_URL;
221
+ // Normalize once: strip any trailing slash so `baseUrl + path` (path always
222
+ // starts with `/`) never yields a double-slash URL (#2481). Only the trailing
223
+ // slash is removed, so a path-carrying baseUrl (e.g. a reverse-proxy prefix
224
+ // `…/bytekit`) is preserved (E2).
225
+ this.baseUrl = (options.baseUrl ?? DEFAULT_BASE_URL).replace(/\/+$/, '');
171
226
  this.defaultTimeoutMs = validateTimeout(options.timeoutMs, '"timeoutMs"') ?? DEFAULT_TIMEOUT_MS;
172
227
  this.scrape = new ScrapeResource(this);
173
228
  this.screenshots = new ScreenshotsResource(this);
@@ -177,6 +232,8 @@ export class ByteKit {
177
232
  this.sitemap = new SitemapResource(this);
178
233
  this.search = new SearchResource(this);
179
234
  this.account = new AccountResource(this);
235
+ this.usage = new UsageResource(this);
236
+ this.webhooks = new WebhooksResource(this);
180
237
  }
181
238
  /**
182
239
  * Resolve the abort budget for one request from the caller's options and the
@@ -215,13 +272,30 @@ export class ByteKit {
215
272
  };
216
273
  }
217
274
  /**
218
- * Make an authenticated JSON request to the ByteKit API.
275
+ * Perform the authenticated round-trip and return whatever the caller's `readBody`
276
+ * continuation makes of the successful response, having already thrown for the two
277
+ * non-body failure modes:
219
278
  *
220
- * Throws `ByteKitError` on 4xx/5xx responses, and `ByteKitConnectionError`
221
- * when no HTTP response was produced at all (DNS/socket/TLS failure, client-side
222
- * timeout, or caller abort).
279
+ * - `ByteKitConnectionError` when no HTTP response was produced at all
280
+ * (DNS/socket/TLS failure, client-side timeout, or caller abort) — including one
281
+ * that fires while the body is streaming.
282
+ * - `ByteKitError` on any 4xx/5xx, carrying the API's `code`/`message`.
283
+ *
284
+ * The body is read through a continuation each caller supplies — JSON text for
285
+ * `request()`, raw bytes for `requestRaw()`. This is the single place that owns auth,
286
+ * the abort budget, and the error taxonomy; the two public transports differ only in
287
+ * how they read a successful body.
288
+ *
289
+ * The abort budget spans headers **and** body (#2546). Returning the `Response` used to
290
+ * end the guarded region at the headers boundary, leaving `response.text()` /
291
+ * `response.arrayBuffer()` — and the `!response.ok` branch's `response.json()` —
292
+ * unbounded: a server that sent headers and then stalled its body hung the caller
293
+ * forever. `readBody` must therefore ONLY consume the stream; `JSON.parse` and
294
+ * `TextDecoder` run in the callers, outside the guard, so a malformed body still
295
+ * surfaces its own parse error rather than being remapped to a connection error.
296
+ * `cleanup()` still runs exactly once per call, now after the body completes.
223
297
  */
224
- async request(method, path, body, options) {
298
+ async send(method, path, body, options, readBody) {
225
299
  const url = `${this.baseUrl}${path}`;
226
300
  const { signal, timeoutSignal, cleanup } = this.resolveSignal(options);
227
301
  const init = {
@@ -238,55 +312,134 @@ export class ByteKit {
238
312
  if (signal !== undefined) {
239
313
  init.signal = signal;
240
314
  }
241
- let response;
242
315
  try {
243
- response = await fetch(url, init);
244
- }
245
- catch (err) {
246
- throw toConnectionError(err, method, url, timeoutSignal);
247
- }
248
- finally {
249
- // Runs on success, on HTTP error, and on abort alike — no dangling timer,
250
- // no listener left behind on the caller's (long-lived) signal.
251
- cleanup();
252
- }
253
- if (!response.ok) {
254
- let code = 'internal_error';
255
- let message = response.statusText;
316
+ let response;
256
317
  try {
257
- const json = (await response.json());
258
- code = json.error?.code ?? code;
259
- message = json.error?.message ?? message;
318
+ response = await fetch(url, init);
260
319
  }
261
- catch {
262
- // leave defaults
320
+ catch (err) {
321
+ throw toConnectionError(err, method, url, timeoutSignal);
263
322
  }
264
- throw new ByteKitError(response.status, code, message);
323
+ if (!response.ok) {
324
+ let code = 'internal_error';
325
+ let message = response.statusText;
326
+ try {
327
+ const json = (await response.json());
328
+ // Canonical unified envelope. Tested first, so it always wins: the flat
329
+ // form below is strictly a fallback and can never override an envelope
330
+ // (issue #2541). The explicit `!== null` guard matters — `typeof null`
331
+ // is `'object'`.
332
+ if (typeof json.error === 'object' && json.error !== null) {
333
+ code = json.error.code ?? code;
334
+ message = json.error.message ?? message;
335
+ }
336
+ else if (typeof json.error === 'string' && json.error.length > 0) {
337
+ // Flat vendor-masked shape, e.g. /v1/search 502
338
+ // {"error":"search_provider_error"} (docs/api/openapi.yaml §/v1/search
339
+ // 502). The string IS the error code. `message` falls back to it only
340
+ // when the response carried no statusText, so the thrown error is
341
+ // never message-empty.
342
+ code = json.error;
343
+ message = message || json.error;
344
+ }
345
+ }
346
+ catch {
347
+ // leave defaults — including when the error body itself stalls and the
348
+ // budget aborts the read (#2546), so a stuck 500 still surfaces its status.
349
+ }
350
+ throw new ByteKitError(response.status, code, message);
351
+ }
352
+ try {
353
+ return await readBody(response);
354
+ }
355
+ catch (err) {
356
+ // A body read that never completes is aborted by the same budget; the runtime
357
+ // then errors the stream (#2546). Map it into the same taxonomy the headers
358
+ // phase uses, so a mid-body timeout/abort is not a bare `TypeError: terminated`.
359
+ throw toConnectionError(err, method, url, timeoutSignal);
360
+ }
361
+ }
362
+ finally {
363
+ // Runs on success (body read included), on HTTP error, and on abort alike — no
364
+ // dangling timer, no listener left behind on the caller's (long-lived) signal.
365
+ cleanup();
265
366
  }
367
+ }
368
+ /**
369
+ * Make an authenticated JSON request to the ByteKit API.
370
+ *
371
+ * Throws `ByteKitError` on 4xx/5xx responses, and `ByteKitConnectionError`
372
+ * when no HTTP response was produced at all (DNS/socket/TLS failure, client-side
373
+ * timeout, or caller abort).
374
+ */
375
+ async request(method, path, body, options) {
266
376
  // A 204 No Content has an empty body, and a genuinely empty body can arrive on
267
377
  // other success codes too (defensive). Calling response.json() on an empty body
268
378
  // rejects with a SyntaxError — which is how a successful revoke() (DELETE → 204)
269
379
  // used to throw instead of resolving. Read the body once as text and short-circuit
270
380
  // to `undefined` when it is empty; a JSON-bearing response (scrape.create,
271
381
  // apiKeys.create/get, …) still parses and returns unchanged.
272
- if (response.status === 204) {
273
- return undefined;
274
- }
275
- const text = await response.text();
276
- if (text.trim().length === 0) {
277
- return undefined;
278
- }
279
- return JSON.parse(text);
382
+ //
383
+ // Only the read runs inside the transport's guarded region (#2546) — `JSON.parse`
384
+ // stays out here (in `parseJsonBody`), so a malformed body still throws its own
385
+ // SyntaxError rather than being remapped to a ByteKitConnectionError.
386
+ const text = await this.send(method, path, body, options, readSuccessText);
387
+ return parseJsonBody(text);
388
+ }
389
+ /**
390
+ * Make an authenticated request whose response body IS the content, not a JSON
391
+ * envelope — the `/v1/fetch` contract, where metadata rides in `X-Fetch-*`
392
+ * response headers.
393
+ *
394
+ * Returns BOTH a UTF-8-decoded string AND the raw, byte-for-byte body, plus the
395
+ * response `Headers` and status, WITHOUT ever calling `JSON.parse`. This is
396
+ * deliberately a separate transport from `request()`: the generic JSON parse
397
+ * there is shared by every other resource and must not change (#2466).
398
+ *
399
+ * `/v1/fetch` supports true binary passthrough (images, PDFs, etc.) as a
400
+ * first-class mode, and UTF-8 decoding a non-UTF-8 byte stream is lossy — any
401
+ * invalid byte sequence gets silently replaced with U+FFFD. Reading the body
402
+ * once via `arrayBuffer()` lets both forms be derived from the same bytes: `bytes`
403
+ * is always byte-exact, `body` is a best-effort string for callers who know the
404
+ * content is text.
405
+ */
406
+ async requestRaw(method, path, body, options) {
407
+ // As in `request()`: the continuation only drains the stream, so the abort budget
408
+ // covers the read (#2546); the UTF-8 decode happens outside the guarded region.
409
+ const { bytes, headers, status } = await this.send(method, path, body, options, async (response) => ({
410
+ bytes: new Uint8Array(await response.arrayBuffer()),
411
+ headers: response.headers,
412
+ status: response.status,
413
+ }));
414
+ const text = new TextDecoder('utf-8').decode(bytes);
415
+ return { body: text, bytes, headers, status };
416
+ }
417
+ /**
418
+ * Make an authenticated JSON request and return the parsed body TOGETHER WITH the
419
+ * response headers and status (#2547).
420
+ *
421
+ * Identical to {@link ByteKit.request} in every observable respect — same method, path,
422
+ * body, `RequestOptions` precedence, error taxonomy, and empty-body handling (both drain
423
+ * the body through {@link readSuccessText} and parse it through {@link parseJsonBody}). It
424
+ * differs only in what it returns, so nothing about an existing call changes by switching
425
+ * to it.
426
+ *
427
+ * Use it to read the documented `X-*` metadata the API emits alongside a JSON envelope —
428
+ * `X-Raw-Bytes`, `X-Billable-Bytes`, `X-Billing-Multiplier`, the `X-Screenshot-*` family
429
+ * — for any endpoint. `sitemap.getWithResponse`, `screenshots.createWithResponse` and
430
+ * `screenshots.getWithResponse` are typed shorthands over this for the endpoints whose
431
+ * headers are documented in the API reference.
432
+ */
433
+ async requestWithResponse(method, path, body, options) {
434
+ // Same continuation shape as request()/requestRaw() (#2546): the readBody continuation
435
+ // ONLY drains the stream (and captures headers/status) inside the abort-guarded region,
436
+ // so a mid-body stall counts against the budget. `JSON.parse` runs afterwards, outside
437
+ // the guard, in `parseJsonBody` — a malformed body stays a SyntaxError.
438
+ const { text, headers, status } = await this.send(method, path, body, options, async (response) => ({
439
+ text: await readSuccessText(response),
440
+ headers: response.headers,
441
+ status: response.status,
442
+ }));
443
+ return { data: parseJsonBody(text), headers, status };
280
444
  }
281
445
  }
282
- // ---------------------------------------------------------------------------
283
- // Deprecated RapidCrawl* aliases (#2421).
284
- //
285
- // The public surface renamed from RapidCrawl to ByteKit. These aliases point at
286
- // the SAME implementations (identity preserved: `RapidCrawl === ByteKit`), so an
287
- // existing consumer's `instanceof` / error-shape contract keeps holding for one
288
- // minor version. Exported here — not only from index.ts — so the SDK's own
289
- // resource files can keep importing the legacy type name from './client.js'
290
- // without churn. Re-exported (with @deprecated JSDoc) from index.ts.
291
- // ---------------------------------------------------------------------------
292
- export { ByteKit as RapidCrawl, ByteKitError as RapidCrawlError, ByteKitConnectionError as RapidCrawlConnectionError, };
@@ -2021,9 +2021,13 @@ export interface components {
2021
2021
  [key: string]: string;
2022
2022
  };
2023
2023
  /** @description Screenshot monitor options (device, viewport, format, etc.). */
2024
- options?: Record<string, never>;
2024
+ options?: {
2025
+ [key: string]: unknown;
2026
+ };
2025
2027
  /** @description Scrape monitor options (formats, country, headers, etc.). Only for type=scrape. */
2026
- scrape_options?: Record<string, never>;
2028
+ scrape_options?: {
2029
+ [key: string]: unknown;
2030
+ };
2027
2031
  metadata?: components["schemas"]["Metadata"];
2028
2032
  };
2029
2033
  MonitorUpdateRequest: {
@@ -2046,8 +2050,12 @@ export interface components {
2046
2050
  };
2047
2051
  /** @enum {string} */
2048
2052
  status?: "active" | "paused";
2049
- options?: Record<string, never>;
2050
- scrape_options?: Record<string, never>;
2053
+ options?: {
2054
+ [key: string]: unknown;
2055
+ };
2056
+ scrape_options?: {
2057
+ [key: string]: unknown;
2058
+ };
2051
2059
  metadata?: components["schemas"]["Metadata"];
2052
2060
  };
2053
2061
  MonitorResponse: {
@@ -2136,7 +2144,9 @@ export interface components {
2136
2144
  /** @default null */
2137
2145
  process: {
2138
2146
  action?: string;
2139
- options?: Record<string, never>;
2147
+ options?: {
2148
+ [key: string]: unknown;
2149
+ };
2140
2150
  } | null;
2141
2151
  /**
2142
2152
  * Format: uri
@@ -3343,7 +3353,7 @@ export interface operations {
3343
3353
  };
3344
3354
  delay_ms?: number;
3345
3355
  timeout_ms?: number;
3346
- metadata?: Record<string, never>;
3356
+ metadata?: components["schemas"]["Metadata"];
3347
3357
  /**
3348
3358
  * @description Per-item override for LLM markdown cleaning. When
3349
3359
  * `true` and `markdown` is in `formats`, the converted
@@ -3737,7 +3747,7 @@ export interface operations {
3737
3747
  */
3738
3748
  webhook_url: string;
3739
3749
  webhook_secret?: string;
3740
- metadata?: Record<string, never>;
3750
+ metadata?: components["schemas"]["Metadata"];
3741
3751
  };
3742
3752
  };
3743
3753
  };
package/dist/index.d.ts CHANGED
@@ -1,12 +1,14 @@
1
1
  export { ByteKit, ByteKitError, ByteKitConnectionError } from './client.js';
2
- export type { ByteKitOptions, RequestOptions, ConnectionErrorCode } from './client.js';
3
- /** @deprecated Renamed to ByteKit / ByteKitError / ByteKitConnectionError — kept as aliases for one minor version. */
4
- export { RapidCrawl, RapidCrawlError, RapidCrawlConnectionError } from './client.js';
5
- /** @deprecated Renamed to ByteKitOptions — kept as an alias for one minor version. */
6
- export type { RapidCrawlOptions } from './client.js';
2
+ export type { ByteKitOptions, RequestOptions, ApiResponse, ConnectionErrorCode } from './client.js';
7
3
  export { V01_METHODS } from './allowlist.js';
8
4
  export type { V01Method } from './allowlist.js';
9
- export type { ScrapeId, ScreenshotId, RecordingId, BulkId, MonitorId, SitemapId, ApiKeyId, SearchType, SearchDateRange, SearchOpts, SearchResult, SearchResultImage, SearchResponse, } from './types.js';
10
- export type { ScrapeCreateResponse, ScrapeGetResponse, ScrapeBulkCreateRequest, ScrapeBulkCreateResponse, ScrapeBulkGetResponse, } from './resources/scrape.js';
5
+ export type { ScrapeId, ScreenshotId, BulkId, MonitorId, SitemapId, ApiKeyId, WebhookDeliveryId, SearchType, SearchDateRange, SearchOpts, SearchResult, SearchResultImage, SearchResponse, } from './types.js';
6
+ export type { ScrapeCookie, ScrapeCreateResponse, ScrapeGetResponse, ScrapeBulkCreateRequest, ScrapeBulkCreateResponse, ScrapeBulkGetResponse, } from './resources/scrape.js';
11
7
  export type { ScreenshotCreateRequest, ScreenshotCreateResponse, ScreenshotGetResponse, } from './resources/screenshots.js';
8
+ export type { FetchOpts, FetchGetOpts, FetchResult, FetchCacheStatus, FetchBulkCreateRequest, FetchBulkCreateResponse, FetchBulkGetResponse, } from './resources/fetch.js';
9
+ export type { MonitorCreateRequest, MonitorCreateResponse, ListMonitorsParams, MonitorStatus, ListMonitorsResponse, MonitorResponse, MonitorUpdateRequest, UpdateMonitorResponse, ListMonitorCapturesResponse, } from './resources/monitors.js';
10
+ export type { SitemapCreateRequest, SitemapCreateResponse, SitemapGetResponse, } from './resources/sitemap.js';
11
+ export type { BulkCreateRequest, BulkCreateResponse, BulkGetResponse, BulkCancelResponse, ListBulkScreenshotsResponse, } from './resources/bulk.js';
12
12
  export type { GetAccountResponse, ListApiKeysResponse, CreateApiKeyRequest, CreateApiKeyResponse, GetApiKeyResponse, UpdateApiKeyRequest, UpdateApiKeyResponse, RevealApiKeyResponse, } from './resources/account.js';
13
+ export type { GetUsageResponse, GetUsageDailyParams, GetUsageDailyResponse, GetUsageByEndpointParams, GetUsageByEndpointResponse, } from './resources/usage.js';
14
+ export type { ListWebhookDeliveriesParams, ListWebhookDeliveriesResponse, RetryWebhookDeliveryResponse, } from './resources/webhooks.js';
package/dist/index.js CHANGED
@@ -1,4 +1,2 @@
1
1
  export { ByteKit, ByteKitError, ByteKitConnectionError } from './client.js';
2
- /** @deprecated Renamed to ByteKit / ByteKitError / ByteKitConnectionError — kept as aliases for one minor version. */
3
- export { RapidCrawl, RapidCrawlError, RapidCrawlConnectionError } from './client.js';
4
2
  export { V01_METHODS } from './allowlist.js';
@@ -1,4 +1,4 @@
1
- import type { RapidCrawl } from '../client.js';
1
+ import type { ByteKit, RequestOptions } from '../client.js';
2
2
  import type { operations } from '../generated/api.js';
3
3
  import type { ApiKeyId } from '../types.js';
4
4
  /**
@@ -36,26 +36,31 @@ export type UpdateApiKeyResponse = operations['updateApiKey']['responses'][200][
36
36
  export declare class AccountResource {
37
37
  private readonly client;
38
38
  readonly apiKeys: ApiKeysResource;
39
- constructor(client: RapidCrawl);
40
- /** GET /v1/account — get the authenticated account */
41
- get(): Promise<GetAccountResponse>;
39
+ constructor(client: ByteKit);
40
+ /**
41
+ * GET /v1/account — get the authenticated account.
42
+ *
43
+ * `requestOptions` carries the CLIENT-side abort budget (`requestTimeoutMs`) and an
44
+ * optional caller `signal`; both override the constructor's `timeoutMs` default.
45
+ */
46
+ get(requestOptions?: RequestOptions): Promise<GetAccountResponse>;
42
47
  }
43
48
  declare class ApiKeysResource {
44
49
  private readonly client;
45
- constructor(client: RapidCrawl);
50
+ constructor(client: ByteKit);
46
51
  /**
47
52
  * POST /v1/account/api-keys — create a new API key.
48
53
  *
49
54
  * `opts` is optional: the spec declares the request body itself as optional,
50
55
  * so `create()` with no arguments is valid and sends no body.
51
56
  */
52
- create(opts?: CreateApiKeyRequest): Promise<CreateApiKeyResponse>;
57
+ create(opts?: CreateApiKeyRequest, requestOptions?: RequestOptions): Promise<CreateApiKeyResponse>;
53
58
  /** GET /v1/account/api-keys — list all API keys for the account */
54
- list(): Promise<ListApiKeysResponse>;
59
+ list(requestOptions?: RequestOptions): Promise<ListApiKeysResponse>;
55
60
  /** GET /v1/account/api-keys/{id} — get an API key by ID */
56
- get(id: ApiKeyId): Promise<GetApiKeyResponse>;
61
+ get(id: ApiKeyId, requestOptions?: RequestOptions): Promise<GetApiKeyResponse>;
57
62
  /** PATCH /v1/account/api-keys/{id} — update an API key */
58
- update(id: ApiKeyId, opts: UpdateApiKeyRequest): Promise<UpdateApiKeyResponse>;
63
+ update(id: ApiKeyId, opts: UpdateApiKeyRequest, requestOptions?: RequestOptions): Promise<UpdateApiKeyResponse>;
59
64
  /**
60
65
  * DELETE /v1/account/api-keys/{id} — revoke an API key (idempotent).
61
66
  *
@@ -67,8 +72,8 @@ declare class ApiKeysResource {
67
72
  * to `undefined` before it would parse the body as JSON (#2450), so this
68
73
  * method resolves cleanly on the gateway's empty 204 body.
69
74
  */
70
- revoke(id: ApiKeyId): Promise<void>;
75
+ revoke(id: ApiKeyId, requestOptions?: RequestOptions): Promise<void>;
71
76
  /** POST /v1/account/api-keys/{id}/reveal — reveal the plaintext API key value */
72
- reveal(id: ApiKeyId): Promise<RevealApiKeyResponse>;
77
+ reveal(id: ApiKeyId, requestOptions?: RequestOptions): Promise<RevealApiKeyResponse>;
73
78
  }
74
79
  export {};
@@ -5,9 +5,14 @@ export class AccountResource {
5
5
  this.client = client;
6
6
  this.apiKeys = new ApiKeysResource(client);
7
7
  }
8
- /** GET /v1/account — get the authenticated account */
9
- get() {
10
- return this.client.request('GET', '/v1/account');
8
+ /**
9
+ * GET /v1/account — get the authenticated account.
10
+ *
11
+ * `requestOptions` carries the CLIENT-side abort budget (`requestTimeoutMs`) and an
12
+ * optional caller `signal`; both override the constructor's `timeoutMs` default.
13
+ */
14
+ get(requestOptions) {
15
+ return this.client.request('GET', '/v1/account', undefined, requestOptions);
11
16
  }
12
17
  }
13
18
  class ApiKeysResource {
@@ -21,20 +26,20 @@ class ApiKeysResource {
21
26
  * `opts` is optional: the spec declares the request body itself as optional,
22
27
  * so `create()` with no arguments is valid and sends no body.
23
28
  */
24
- create(opts) {
25
- return this.client.request('POST', '/v1/account/api-keys', opts);
29
+ create(opts, requestOptions) {
30
+ return this.client.request('POST', '/v1/account/api-keys', opts, requestOptions);
26
31
  }
27
32
  /** GET /v1/account/api-keys — list all API keys for the account */
28
- list() {
29
- return this.client.request('GET', '/v1/account/api-keys');
33
+ list(requestOptions) {
34
+ return this.client.request('GET', '/v1/account/api-keys', undefined, requestOptions);
30
35
  }
31
36
  /** GET /v1/account/api-keys/{id} — get an API key by ID */
32
- get(id) {
33
- return this.client.request('GET', `/v1/account/api-keys/${id}`);
37
+ get(id, requestOptions) {
38
+ return this.client.request('GET', `/v1/account/api-keys/${id}`, undefined, requestOptions);
34
39
  }
35
40
  /** PATCH /v1/account/api-keys/{id} — update an API key */
36
- update(id, opts) {
37
- return this.client.request('PATCH', `/v1/account/api-keys/${id}`, opts);
41
+ update(id, opts, requestOptions) {
42
+ return this.client.request('PATCH', `/v1/account/api-keys/${id}`, opts, requestOptions);
38
43
  }
39
44
  /**
40
45
  * DELETE /v1/account/api-keys/{id} — revoke an API key (idempotent).
@@ -47,11 +52,11 @@ class ApiKeysResource {
47
52
  * to `undefined` before it would parse the body as JSON (#2450), so this
48
53
  * method resolves cleanly on the gateway's empty 204 body.
49
54
  */
50
- revoke(id) {
51
- return this.client.request('DELETE', `/v1/account/api-keys/${id}`);
55
+ revoke(id, requestOptions) {
56
+ return this.client.request('DELETE', `/v1/account/api-keys/${id}`, undefined, requestOptions);
52
57
  }
53
58
  /** POST /v1/account/api-keys/{id}/reveal — reveal the plaintext API key value */
54
- reveal(id) {
55
- return this.client.request('POST', `/v1/account/api-keys/${id}/reveal`);
59
+ reveal(id, requestOptions) {
60
+ return this.client.request('POST', `/v1/account/api-keys/${id}/reveal`, undefined, requestOptions);
56
61
  }
57
62
  }
@@ -1,20 +1,36 @@
1
- import type { RapidCrawl } from '../client.js';
1
+ import type { ByteKit, RequestOptions } from '../client.js';
2
+ import type { operations } from '../generated/api.js';
2
3
  import type { BulkId } from '../types.js';
4
+ /** Body of POST /v1/bulk. */
5
+ export type BulkCreateRequest = operations['createBulk']['requestBody']['content']['application/json'];
6
+ /** 202 payload of POST /v1/bulk — bulk jobs are always async. */
7
+ export type BulkCreateResponse = operations['createBulk']['responses'][202]['content']['application/json'];
8
+ /** 200 payload of GET /v1/bulk/{id}. */
9
+ export type BulkGetResponse = operations['getBulk']['responses'][200]['content']['application/json'];
10
+ /** 200 payload of DELETE /v1/bulk/{id} — cancels an in-flight job. */
11
+ export type BulkCancelResponse = operations['deleteBulk']['responses'][200]['content']['application/json'];
12
+ /** 200 payload of GET /v1/bulk/{id}/screenshots. */
13
+ export type ListBulkScreenshotsResponse = operations['listBulkScreenshots']['responses'][200]['content']['application/json'];
3
14
  export declare class BulkResource {
4
15
  private readonly client;
5
16
  readonly screenshots: BulkScreenshotsResource;
6
- constructor(client: RapidCrawl);
7
- /** POST /v1/bulk — create a bulk screenshots job */
8
- create(opts: Record<string, unknown>): Promise<unknown>;
17
+ constructor(client: ByteKit);
18
+ /**
19
+ * POST /v1/bulk — create a bulk screenshots job.
20
+ *
21
+ * `requestOptions` carries the CLIENT-side abort budget (`requestTimeoutMs`) and an
22
+ * optional caller `signal`; both override the constructor's `timeoutMs` default.
23
+ */
24
+ create(opts: BulkCreateRequest, requestOptions?: RequestOptions): Promise<BulkCreateResponse>;
9
25
  /** GET /v1/bulk/{id} — get a bulk job status */
10
- get(id: BulkId): Promise<unknown>;
26
+ get(id: BulkId, requestOptions?: RequestOptions): Promise<BulkGetResponse>;
11
27
  /** DELETE /v1/bulk/{id} — cancel an in-flight bulk job */
12
- cancel(id: BulkId): Promise<unknown>;
28
+ cancel(id: BulkId, requestOptions?: RequestOptions): Promise<BulkCancelResponse>;
13
29
  }
14
30
  declare class BulkScreenshotsResource {
15
31
  private readonly client;
16
- constructor(client: RapidCrawl);
32
+ constructor(client: ByteKit);
17
33
  /** GET /v1/bulk/{id}/screenshots — list screenshots in a bulk job */
18
- list(id: BulkId): Promise<unknown>;
34
+ list(id: BulkId, requestOptions?: RequestOptions): Promise<ListBulkScreenshotsResponse>;
19
35
  }
20
36
  export {};
@@ -5,17 +5,22 @@ export class BulkResource {
5
5
  this.client = client;
6
6
  this.screenshots = new BulkScreenshotsResource(client);
7
7
  }
8
- /** POST /v1/bulk — create a bulk screenshots job */
9
- create(opts) {
10
- return this.client.request('POST', '/v1/bulk', opts);
8
+ /**
9
+ * POST /v1/bulk — create a bulk screenshots job.
10
+ *
11
+ * `requestOptions` carries the CLIENT-side abort budget (`requestTimeoutMs`) and an
12
+ * optional caller `signal`; both override the constructor's `timeoutMs` default.
13
+ */
14
+ create(opts, requestOptions) {
15
+ return this.client.request('POST', '/v1/bulk', opts, requestOptions);
11
16
  }
12
17
  /** GET /v1/bulk/{id} — get a bulk job status */
13
- get(id) {
14
- return this.client.request('GET', `/v1/bulk/${id}`);
18
+ get(id, requestOptions) {
19
+ return this.client.request('GET', `/v1/bulk/${id}`, undefined, requestOptions);
15
20
  }
16
21
  /** DELETE /v1/bulk/{id} — cancel an in-flight bulk job */
17
- cancel(id) {
18
- return this.client.request('DELETE', `/v1/bulk/${id}`);
22
+ cancel(id, requestOptions) {
23
+ return this.client.request('DELETE', `/v1/bulk/${id}`, undefined, requestOptions);
19
24
  }
20
25
  }
21
26
  class BulkScreenshotsResource {
@@ -24,7 +29,7 @@ class BulkScreenshotsResource {
24
29
  this.client = client;
25
30
  }
26
31
  /** GET /v1/bulk/{id}/screenshots — list screenshots in a bulk job */
27
- list(id) {
28
- return this.client.request('GET', `/v1/bulk/${id}/screenshots`);
32
+ list(id, requestOptions) {
33
+ return this.client.request('GET', `/v1/bulk/${id}/screenshots`, undefined, requestOptions);
29
34
  }
30
35
  }