@hunt-labs/bytekit-sdk 0.4.0 → 0.5.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/CHANGELOG.md CHANGED
@@ -8,6 +8,25 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
8
8
  This file records only the delta between versions. For how to use the package
9
9
  today, see [README.md](./README.md), which remains the authoritative usage guide.
10
10
 
11
+ ## [0.5.0] - 2026-07-29
12
+
13
+ ### Added
14
+
15
+ - `src/generated/api.d.ts` now models the `400` responses that the gateway's new
16
+ request-body-size guards can return. `operations['stripeWebhook']['responses']` gains a
17
+ `400` with this route's bespoke `{ error?: string }` body, and
18
+ `operations['retryWebhookDelivery']['responses']` gains a `400` carrying the unified
19
+ `components['schemas']['Error']` envelope. Both are purely additive — no existing member
20
+ changed shape — so every current call site still compiles. (#2640)
21
+
22
+ ### Changed
23
+
24
+ - Regenerated `src/generated/api.d.ts` against the merged spec. Beyond the two added `400`
25
+ members above, the delta is JSDoc only: every guarded endpoint's description now carries a
26
+ `**Limits:**` block stating its byte ceiling and the `request_too_large` error code
27
+ (#2640), and `POST /v1/bulk`'s description documents `defaults.type` inheritance and the
28
+ 422 on unrecognized keys (#2643). No runtime code changed. (#2640, #2643)
29
+
11
30
  ## [0.4.0] - 2026-07-24
12
31
 
13
32
  ### Added
@@ -201,6 +220,8 @@ against 0.1.0 — read each one before upgrading.
201
220
  (scrape, screenshot, search, and related endpoints), published under the original
202
221
  `@rapidcrawl/sdk` name.
203
222
 
223
+ [0.5.0]: https://github.com/Hunt-Labs-Inc/ByteKit/tree/main/packages/sdk-typescript
224
+ [0.4.0]: https://github.com/Hunt-Labs-Inc/ByteKit/tree/main/packages/sdk-typescript
204
225
  [0.3.0]: https://github.com/Hunt-Labs-Inc/ByteKit/tree/main/packages/sdk-typescript
205
226
  [0.2.2]: https://github.com/Hunt-Labs-Inc/ByteKit/tree/main/packages/sdk-typescript
206
227
  [0.2.1]: https://github.com/Hunt-Labs-Inc/ByteKit/tree/main/packages/sdk-typescript
package/README.md CHANGED
@@ -185,12 +185,15 @@ const deliveries = await client.webhooks.list();
185
185
  await client.webhooks.retry('wh_123abc');
186
186
  ```
187
187
 
188
- > **Note:** `client.account.*` (including `client.account.apiKeys.*`) targets the
189
- > `/v1/account/*` endpoints, which authenticate with a Clerk dashboard session —
190
- > **not** a Bearer API key. Calling them with an API-key client will fail auth.
191
- > They remain on the SDK surface for dashboard/session consumers and are marked
192
- > `x-sdk-scope: internal` in the spec, so they are intentionally excluded from the
193
- > v0.1 Bearer-key parity guarantee.
188
+ > **Note (the real auth split):** `account.get()` authenticates with the same Bearer
189
+ > API key as every other v0.1 method above — it succeeds normally. `client.account.apiKeys.*`
190
+ > is different: it targets `/v1/account/api-keys*`, which authenticates with a Clerk
191
+ > dashboard session, **not** a Bearer API key — calling any `apiKeys.*` method with an
192
+ > API-key client fails auth. `apiKeys.*` remains on the SDK surface for dashboard/session
193
+ > consumers (deliberate retention — see `DOCUMENTED_SURFACE_EXCEPTIONS` in
194
+ > `src/allowlist.ts`) and is marked `x-sdk-scope: internal` in the spec, so it is
195
+ > intentionally excluded from the v0.1 Bearer-key parity guarantee. `account.get()` is not:
196
+ > it is a real `V01_METHODS` entry.
194
197
 
195
198
  ### Response headers
196
199
 
@@ -207,8 +210,12 @@ console.log(headers.get('X-Raw-Bytes')); // e.g. "12345"
207
210
  console.log(status); // 200
208
211
  ```
209
212
 
210
- `client.screenshots.createWithResponse()` and `client.screenshots.getWithResponse()`
211
- work the same way. Any other endpoint's headers are reachable through the generic
213
+ `client.screenshots.createWithResponse()` works the same way, and is where the
214
+ `X-Screenshot-*`/`X-Raw-Bytes`/`X-Billable-Bytes`/`X-Billing-Multiplier` headers
215
+ actually live — they're declared on `POST /v1/screenshots` only. Its sibling
216
+ `client.screenshots.getWithResponse()` is still additive and safe to call, but
217
+ `GET /v1/screenshots/{id}` emits none of those headers, so `headers` will be
218
+ empty for it. Any other endpoint's headers are reachable through the generic
212
219
  transport, `client.requestWithResponse('GET', '/v1/scrape/sc_123abc')`.
213
220
 
214
221
  These siblings are purely additive: they issue the identical request and accept the
@@ -10,3 +10,25 @@
10
10
  */
11
11
  export declare const V01_METHODS: readonly ["scrape.create", "scrape.get", "screenshots.create", "screenshots.get", "bulk.create", "bulk.get", "bulk.cancel", "bulk.screenshots.list", "scrape.bulk.create", "scrape.bulk.get", "fetch.create", "fetch.get", "fetch.bulk.create", "fetch.bulk.get", "monitors.create", "monitors.list", "monitors.get", "monitors.update", "monitors.delete", "monitors.captures.list", "sitemap.create", "sitemap.get", "search.query", "account.get", "usage.get", "usage.daily", "usage.byEndpoint", "webhooks.list", "webhooks.retry"];
12
12
  export type V01Method = (typeof V01_METHODS)[number];
13
+ /**
14
+ * Methods that exist on the real, instantiated `ByteKit` client surface but are
15
+ * deliberately EXCLUDED from `V01_METHODS` — each with the reason it stays off the
16
+ * v0.1 parity guard.
17
+ *
18
+ * `parity.test.ts` only compares the OpenAPI spec's `x-sdk-scope: v0.1` operations
19
+ * against `V01_METHODS` — it says nothing about what the actual client *instance*
20
+ * exposes. That gap is how the six `account.apiKeys.*` methods shipped unguarded
21
+ * (issue #2595): they are real, callable methods on `client.account.apiKeys`, are
22
+ * NOT in `V01_METHODS`, and no test walked the instantiated surface to notice.
23
+ *
24
+ * `surface-guard.test.ts` walks the real client and asserts every callable is
25
+ * either in `V01_METHODS` or listed here — removing a method (from either list) or
26
+ * adding an undocumented one fails that test. To add a new client-surface method
27
+ * that is deliberately NOT part of the v0.1 Bearer-key parity guarantee, add an
28
+ * entry here with the reason; to add one that IS part of it, add it to
29
+ * `V01_METHODS` instead (and annotate the spec operation with `x-sdk-method`).
30
+ */
31
+ export declare const DOCUMENTED_SURFACE_EXCEPTIONS: ReadonlyArray<{
32
+ readonly method: string;
33
+ readonly reason: string;
34
+ }>;
package/dist/allowlist.js CHANGED
@@ -42,3 +42,67 @@ export const V01_METHODS = [
42
42
  'webhooks.list',
43
43
  'webhooks.retry',
44
44
  ];
45
+ /**
46
+ * Methods that exist on the real, instantiated `ByteKit` client surface but are
47
+ * deliberately EXCLUDED from `V01_METHODS` — each with the reason it stays off the
48
+ * v0.1 parity guard.
49
+ *
50
+ * `parity.test.ts` only compares the OpenAPI spec's `x-sdk-scope: v0.1` operations
51
+ * against `V01_METHODS` — it says nothing about what the actual client *instance*
52
+ * exposes. That gap is how the six `account.apiKeys.*` methods shipped unguarded
53
+ * (issue #2595): they are real, callable methods on `client.account.apiKeys`, are
54
+ * NOT in `V01_METHODS`, and no test walked the instantiated surface to notice.
55
+ *
56
+ * `surface-guard.test.ts` walks the real client and asserts every callable is
57
+ * either in `V01_METHODS` or listed here — removing a method (from either list) or
58
+ * adding an undocumented one fails that test. To add a new client-surface method
59
+ * that is deliberately NOT part of the v0.1 Bearer-key parity guarantee, add an
60
+ * entry here with the reason; to add one that IS part of it, add it to
61
+ * `V01_METHODS` instead (and annotate the spec operation with `x-sdk-method`).
62
+ */
63
+ export const DOCUMENTED_SURFACE_EXCEPTIONS = [
64
+ // account.apiKeys.* — x-sdk-scope: internal in the spec (Clerk-session-only auth;
65
+ // a Bearer API key 401s on every one of these). Deliberate retention: the resource
66
+ // stays on the SDK surface for dashboard/session consumers rather than being
67
+ // removed, matching the split documented in README.md's "Account, usage, and API
68
+ // keys" section (issue #2595).
69
+ {
70
+ method: 'account.apiKeys.create',
71
+ reason: 'Clerk-session-only (x-sdk-scope: internal) — deliberate retention for dashboard/session consumers, not part of the Bearer-key v0.1 surface.',
72
+ },
73
+ {
74
+ method: 'account.apiKeys.list',
75
+ reason: 'Clerk-session-only (x-sdk-scope: internal) — deliberate retention for dashboard/session consumers, not part of the Bearer-key v0.1 surface.',
76
+ },
77
+ {
78
+ method: 'account.apiKeys.get',
79
+ reason: 'Clerk-session-only (x-sdk-scope: internal) — deliberate retention for dashboard/session consumers, not part of the Bearer-key v0.1 surface.',
80
+ },
81
+ {
82
+ method: 'account.apiKeys.update',
83
+ reason: 'Clerk-session-only (x-sdk-scope: internal) — deliberate retention for dashboard/session consumers, not part of the Bearer-key v0.1 surface.',
84
+ },
85
+ {
86
+ method: 'account.apiKeys.revoke',
87
+ reason: 'Clerk-session-only (x-sdk-scope: internal) — deliberate retention for dashboard/session consumers, not part of the Bearer-key v0.1 surface.',
88
+ },
89
+ {
90
+ method: 'account.apiKeys.reveal',
91
+ reason: 'Clerk-session-only (x-sdk-scope: internal) — deliberate retention for dashboard/session consumers, not part of the Bearer-key v0.1 surface.',
92
+ },
93
+ // *WithResponse siblings (#2547) — additive `ApiResponse<T>` shorthands over an
94
+ // already-allowlisted base method (same HTTP method, path, and body). Not a
95
+ // distinct v0.1 API operation, so not a `V01_METHODS` entry in its own right.
96
+ {
97
+ method: 'screenshots.createWithResponse',
98
+ reason: 'Additive #2547 ApiResponse<T> shorthand over screenshots.create (same request) — not a distinct v0.1 API operation.',
99
+ },
100
+ {
101
+ method: 'screenshots.getWithResponse',
102
+ reason: 'Additive #2547 ApiResponse<T> shorthand over screenshots.get (same request) — not a distinct v0.1 API operation.',
103
+ },
104
+ {
105
+ method: 'sitemap.getWithResponse',
106
+ reason: 'Additive #2547 ApiResponse<T> shorthand over sitemap.get (same request) — not a distinct v0.1 API operation.',
107
+ },
108
+ ];
package/dist/client.d.ts CHANGED
@@ -185,9 +185,11 @@ export declare class ByteKit {
185
185
  *
186
186
  * Use it to read the documented `X-*` metadata the API emits alongside a JSON envelope —
187
187
  * `X-Raw-Bytes`, `X-Billable-Bytes`, `X-Billing-Multiplier`, the `X-Screenshot-*` family
188
- * — for any endpoint. `sitemap.getWithResponse`, `screenshots.createWithResponse` and
189
- * `screenshots.getWithResponse` are typed shorthands over this for the endpoints whose
190
- * headers are documented in the API reference.
188
+ * — for any endpoint. `sitemap.getWithResponse` and `screenshots.createWithResponse` are
189
+ * typed shorthands over this for the endpoints whose headers are documented in the API
190
+ * reference. `screenshots.getWithResponse` is the same shorthand shape applied to
191
+ * `GET /v1/screenshots/{id}`, which the spec declares with NO `X-*` response headers — call
192
+ * it for the typed body, not for header metadata.
191
193
  */
192
194
  requestWithResponse<T>(method: string, path: string, body?: unknown, options?: RequestOptions): Promise<ApiResponse<T>>;
193
195
  }
package/dist/client.js CHANGED
@@ -426,9 +426,11 @@ export class ByteKit {
426
426
  *
427
427
  * Use it to read the documented `X-*` metadata the API emits alongside a JSON envelope —
428
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.
429
+ * — for any endpoint. `sitemap.getWithResponse` and `screenshots.createWithResponse` are
430
+ * typed shorthands over this for the endpoints whose headers are documented in the API
431
+ * reference. `screenshots.getWithResponse` is the same shorthand shape applied to
432
+ * `GET /v1/screenshots/{id}`, which the spec declares with NO `X-*` response headers — call
433
+ * it for the typed body, not for header metadata.
432
434
  */
433
435
  async requestWithResponse(method, path, body, options) {
434
436
  // Same continuation shape as request()/requestRaw() (#2546): the readBody continuation
@@ -155,6 +155,9 @@ export interface paths {
155
155
  * Capture a screenshot
156
156
  * @description Sync by default (holds up to 28s). Pass `?async=true` to return 202 immediately.
157
157
  * Poll via GET /v1/screenshots/{id}.
158
+ *
159
+ * **Limits:** request bodies are capped at 512 KB. An oversized body
160
+ * returns a `400` with error code `request_too_large`.
158
161
  */
159
162
  post: operations["createScreenshot"];
160
163
  delete?: never;
@@ -277,6 +280,9 @@ export interface paths {
277
280
  /**
278
281
  * Fetch a URL (POST)
279
282
  * @description Same as GET /v1/fetch but with a JSON request body.
283
+ *
284
+ * **Limits:** request bodies are capped at 512 KB. An oversized body
285
+ * returns a `400` with error code `request_too_large`.
280
286
  */
281
287
  post: operations["postFetch"];
282
288
  delete?: never;
@@ -298,6 +304,17 @@ export interface paths {
298
304
  * Bulk fetch URLs
299
305
  * @description Enqueues multiple URLs for HTTP fetching. Results delivered via webhook.
300
306
  * Does not support options that require page rendering (cookies, wait_for_selector, etc.).
307
+ *
308
+ * **Limits:** request bodies are guarded in a two-tier shape. A streamed body
309
+ * with no `Content-Length` header is capped at 2 MB before your API key
310
+ * is checked; a body that declares `Content-Length` is instead bounded
311
+ * there by a 20 MB fail-safe (not the real limit — see below), since
312
+ * that branch reads nothing until your key is verified. Once your key
313
+ * is verified, a second check re-gates the body against your account's
314
+ * own `max_bulk_size` (at this endpoint's per-item override budget),
315
+ * which reaches 16.8 MB for the largest documented account. A
316
+ * standard-plan account's effective ceiling is 2 MB; either tier's
317
+ * overrun returns a `400` with error code `request_too_large`.
301
318
  */
302
319
  post: operations["createFetchBulk"];
303
320
  delete?: never;
@@ -343,6 +360,17 @@ export interface paths {
343
360
  * Provide `urls` (simple list) or `items` (per-item config), not both.
344
361
  * Webhook deliveries include `X-ByteKit-Event: bulk.completed` so
345
362
  * receivers can dispatch on the header without parsing the body shape.
363
+ *
364
+ * **Limits:** request bodies are guarded in a two-tier shape. A streamed body
365
+ * with no `Content-Length` header is capped at 4 MB before your API key
366
+ * is checked; a body that declares `Content-Length` is instead bounded
367
+ * there by a 32 MB fail-safe (not the real limit — see below), since
368
+ * that branch reads nothing until your key is verified. Once your key
369
+ * is verified, a second check re-gates the body against your account's
370
+ * own `max_bulk_size` (at this endpoint's richer per-item override
371
+ * budget), which reaches 28.7 MB for the largest documented account. A
372
+ * standard-plan account's effective ceiling is 4 MB; either tier's
373
+ * overrun returns a `400` with error code `request_too_large`.
346
374
  */
347
375
  post: operations["createBulk"];
348
376
  delete?: never;
@@ -402,6 +430,9 @@ export interface paths {
402
430
  /**
403
431
  * Create a change-detection monitor
404
432
  * @description Creates a recurring change-detection monitor for a URL, delivering results via webhook.
433
+ *
434
+ * **Limits:** request bodies are capped at 512 KB. An oversized body
435
+ * returns a `400` with error code `request_too_large`.
405
436
  */
406
437
  post: operations["createMonitor"];
407
438
  delete?: never;
@@ -462,6 +493,9 @@ export interface paths {
462
493
  * Webhook deliveries include `X-ByteKit-Event: sitemap.completed` or
463
494
  * `X-ByteKit-Event: sitemap.failed` so receivers can dispatch on the
464
495
  * header without parsing the body shape.
496
+ *
497
+ * **Limits:** request bodies are capped at 512 KB. An oversized body
498
+ * returns a `400` with error code `request_too_large`.
465
499
  */
466
500
  post: operations["createSitemap"];
467
501
  delete?: never;
@@ -917,6 +951,12 @@ export interface paths {
917
951
  /**
918
952
  * Stripe webhook receiver
919
953
  * @description Receives Stripe webhook events. Verified via signature.
954
+ *
955
+ * **Limits:** request bodies are capped at 256 KB — real Stripe event
956
+ * payloads stay in the tens of KB. An oversized body returns a `400`
957
+ * with a bespoke `{ error }` body (this route predates issue #699's
958
+ * unified REST envelope and answers Stripe's own webhook contract, not
959
+ * the public API's error shape).
920
960
  */
921
961
  post: operations["stripeWebhook"];
922
962
  delete?: never;
@@ -954,6 +994,10 @@ export interface paths {
954
994
  /**
955
995
  * Retry a webhook delivery
956
996
  * @description Requeues a failed or exhausted webhook delivery for another attempt.
997
+ *
998
+ * **Limits:** this endpoint takes no request body; any body sent is
999
+ * capped at 64 KB. An oversized body returns a `400` with error code
1000
+ * `request_too_large`.
957
1001
  */
958
1002
  post: operations["retryWebhookDelivery"];
959
1003
  delete?: never;
@@ -1236,6 +1280,12 @@ export interface paths {
1236
1280
  * Clerk webhook receiver
1237
1281
  * @description Receives Clerk events (user.created, user.updated, user.deleted, etc.).
1238
1282
  * Authentication is via Svix signature verification — no bearer token required.
1283
+ *
1284
+ * **Limits:** request bodies are capped at 256 KB — real Clerk event
1285
+ * payloads (user/membership/invitation objects) stay well under this.
1286
+ * An oversized body returns a `400` with error code `request_too_large`
1287
+ * (bespoke `{ error }` slug shape, matching this route's existing
1288
+ * error convention, not the unified REST envelope).
1239
1289
  */
1240
1290
  post: operations["clerkWebhook"];
1241
1291
  delete?: never;
@@ -2605,6 +2655,15 @@ export interface operations {
2605
2655
  "application/json": components["schemas"]["AccountBearerResponse"] | components["schemas"]["AccountSessionResponse"];
2606
2656
  };
2607
2657
  };
2658
+ /** @description Rate limit exceeded (`rate_limited`). Only reachable when authenticated via Clerk session (the 60-request/60-second per-user window) — the bearer and in-process auth branches are not rate-limited at this endpoint. Carries a `Retry-After` header derived from the same clock as the window reset. */
2659
+ 429: {
2660
+ headers: {
2661
+ [name: string]: unknown;
2662
+ };
2663
+ content: {
2664
+ "application/json": components["schemas"]["Error"];
2665
+ };
2666
+ };
2608
2667
  };
2609
2668
  };
2610
2669
  deleteAccount: {
@@ -2690,6 +2749,15 @@ export interface operations {
2690
2749
  "application/json": components["schemas"]["Error"];
2691
2750
  };
2692
2751
  };
2752
+ /** @description Rate limit exceeded (`rate_limited`) — the Clerk-session 60-request/60-second per-user window. Carries a `Retry-After` header derived from the same clock as the window reset. */
2753
+ 429: {
2754
+ headers: {
2755
+ [name: string]: unknown;
2756
+ };
2757
+ content: {
2758
+ "application/json": components["schemas"]["Error"];
2759
+ };
2760
+ };
2693
2761
  };
2694
2762
  };
2695
2763
  listApiKeys: {
@@ -2916,7 +2984,7 @@ export interface operations {
2916
2984
  "application/json": components["schemas"]["Error"];
2917
2985
  };
2918
2986
  };
2919
- /** @description Rate limit exceeded. */
2987
+ /** @description Reveal rate limit exceeded (per-account anti-harvest cap, distinct from the per-second API rate limit). Carries a `Retry-After` header. */
2920
2988
  429: {
2921
2989
  headers: {
2922
2990
  [name: string]: unknown;
@@ -3054,6 +3122,15 @@ export interface operations {
3054
3122
  "application/json": components["schemas"]["Error"];
3055
3123
  };
3056
3124
  };
3125
+ /** @description Rate limit (`rate_limited`) or concurrency limit (`concurrency_limit`) exceeded. Carries a `Retry-After` header — seconds derived from the same clock as `X-RateLimit-Reset` for the rate-limit variant, a fixed small back-off for the concurrency variant. */
3126
+ 429: {
3127
+ headers: {
3128
+ [name: string]: unknown;
3129
+ };
3130
+ content: {
3131
+ "application/json": components["schemas"]["Error"];
3132
+ };
3133
+ };
3057
3134
  };
3058
3135
  };
3059
3136
  getScreenshot: {
@@ -3246,7 +3323,7 @@ export interface operations {
3246
3323
  "application/json": components["schemas"]["Error"];
3247
3324
  };
3248
3325
  };
3249
- /** @description Rate limit exceeded. */
3326
+ /** @description Rate limit (`rate_limited`) or concurrency limit (`concurrency_limit`) exceeded. Carries a `Retry-After` header — seconds derived from the same clock as `X-RateLimit-Reset` for the rate-limit variant, a fixed small back-off for the concurrency variant. */
3250
3327
  429: {
3251
3328
  headers: {
3252
3329
  [name: string]: unknown;
@@ -3446,8 +3523,9 @@ export interface operations {
3446
3523
  created_at: string;
3447
3524
  /** Format: date-time */
3448
3525
  completed_at: string | null;
3449
- total_credits_charged: number;
3450
- /** @description Estimated credits at submission time. Null in GET responses. */
3526
+ /** @description Always null on the create response — the job has not been billed yet (routes/scrape-bulk.ts builds the 202 body from a partial job row). Fractional when populated (credits are NUMERIC(10,2)); the numeric branch is unreachable on this path and exists only so the 202 and 200 bodies share one shape. */
3527
+ total_credits_charged: number | null;
3528
+ /** @description Estimated credits at submission time. Null in GET responses. Fractional — markdown/html formats weigh 0.5 credits each (scrape-shared/src/credits.ts), so a one-item markdown job is 1.5. */
3451
3529
  estimated_credits: number | null;
3452
3530
  /** @description Webhook endpoint URL (HTTPS only; http:// rejected with 400 invalid_url, reason scheme_unsupported) */
3453
3531
  webhook_url: string;
@@ -3523,7 +3601,8 @@ export interface operations {
3523
3601
  created_at: string;
3524
3602
  /** Format: date-time */
3525
3603
  completed_at: string | null;
3526
- total_credits_charged: number;
3604
+ /** @description Total credits billed for the job. Null until the job is billed. Fractional — credits are NUMERIC(10,2). */
3605
+ total_credits_charged: number | null;
3527
3606
  /** @description Null in GET responses (computed at submission time only). */
3528
3607
  estimated_credits: number | null;
3529
3608
  /** @description Webhook endpoint URL (HTTPS only; http:// rejected with 400 invalid_url, reason scheme_unsupported) */
@@ -3610,6 +3689,15 @@ export interface operations {
3610
3689
  "application/json": components["schemas"]["Error"];
3611
3690
  };
3612
3691
  };
3692
+ /** @description Rate limit (`rate_limited`) or concurrency limit (`concurrency_limit`) exceeded. Carries a `Retry-After` header — seconds derived from the same clock as `X-RateLimit-Reset` for the rate-limit variant, a fixed small back-off for the concurrency variant. */
3693
+ 429: {
3694
+ headers: {
3695
+ [name: string]: unknown;
3696
+ };
3697
+ content: {
3698
+ "application/json": components["schemas"]["Error"];
3699
+ };
3700
+ };
3613
3701
  /**
3614
3702
  * @description Fetch service unavailable, content transform failed, or a non-2xx upstream
3615
3703
  * response relayed as the unified Error envelope. On an upstream relay the HTTP
@@ -3699,6 +3787,15 @@ export interface operations {
3699
3787
  "application/json": components["schemas"]["Error"];
3700
3788
  };
3701
3789
  };
3790
+ /** @description Rate limit (`rate_limited`) or concurrency limit (`concurrency_limit`) exceeded. Carries a `Retry-After` header — seconds derived from the same clock as `X-RateLimit-Reset` for the rate-limit variant, a fixed small back-off for the concurrency variant. */
3791
+ 429: {
3792
+ headers: {
3793
+ [name: string]: unknown;
3794
+ };
3795
+ content: {
3796
+ "application/json": components["schemas"]["Error"];
3797
+ };
3798
+ };
3702
3799
  /**
3703
3800
  * @description Fetch service unavailable, content transform failed, or a non-2xx upstream
3704
3801
  * response relayed as the unified Error envelope. On an upstream relay the HTTP
@@ -3758,7 +3855,25 @@ export interface operations {
3758
3855
  [name: string]: unknown;
3759
3856
  };
3760
3857
  content: {
3761
- "application/json": Record<string, never>;
3858
+ "application/json": {
3859
+ /** @example bulk_01j9abc123 */
3860
+ id: string;
3861
+ /** @enum {string} */
3862
+ status: "processing" | "completed" | "failed";
3863
+ total: number;
3864
+ completed: number;
3865
+ failed: number;
3866
+ /** Format: date-time */
3867
+ created_at: string;
3868
+ /** Format: date-time */
3869
+ completed_at: string | null;
3870
+ /** @description Always null on the create response — the job has not been billed yet (routes/fetch-bulk.ts builds the 202 body from a partial job row). Fractional when populated (credits are NUMERIC(10,2)); the numeric branch is unreachable on this path and exists only so the 202 and 200 bodies share one shape. */
3871
+ total_credits_charged: number | null;
3872
+ /** @description Estimated credits at submission time. Null in GET responses. Fractional — markdown/html formats weigh 0.5 credits each (scrape-shared/src/credits.ts), so a one-item markdown job is 1.5. */
3873
+ estimated_credits: number | null;
3874
+ /** @description Webhook endpoint URL (HTTPS only; http:// rejected with 400 invalid_url, reason scheme_unsupported) */
3875
+ webhook_url: string;
3876
+ };
3762
3877
  };
3763
3878
  };
3764
3879
  /**
@@ -3812,7 +3927,45 @@ export interface operations {
3812
3927
  [name: string]: unknown;
3813
3928
  };
3814
3929
  content: {
3815
- "application/json": Record<string, never>;
3930
+ "application/json": {
3931
+ /** @example bulk_01j9abc123 */
3932
+ id: string;
3933
+ /** @enum {string} */
3934
+ status: "processing" | "completed" | "failed";
3935
+ total: number;
3936
+ completed: number;
3937
+ failed: number;
3938
+ /** Format: date-time */
3939
+ created_at: string;
3940
+ /** Format: date-time */
3941
+ completed_at: string | null;
3942
+ /** @description Total credits billed for the job. Null until the job is billed. Fractional — credits are NUMERIC(10,2). */
3943
+ total_credits_charged: number | null;
3944
+ /** @description Null in GET responses (computed at submission time only). */
3945
+ estimated_credits: number | null;
3946
+ /** @description Webhook endpoint URL (HTTPS only; http:// rejected with 400 invalid_url, reason scheme_unsupported) */
3947
+ webhook_url: string;
3948
+ /** @description Per-URL fetch items, oldest first, capped at 500 (listBulkFetchItemsWithLatestAttempt). */
3949
+ items: {
3950
+ /** @example sc_01j9abc123 */
3951
+ id: string;
3952
+ /** Format: uri */
3953
+ url: string;
3954
+ /** @enum {string} */
3955
+ status: "pending" | "processing" | "completed" | "failed" | "cancelled";
3956
+ content_type: string | null;
3957
+ content_length: number | null;
3958
+ content_url: string | null;
3959
+ waf_vendor: string | null;
3960
+ cache_hit: boolean;
3961
+ error_code: string | null;
3962
+ error_message: string | null;
3963
+ /** Format: date-time */
3964
+ created_at: string;
3965
+ /** Format: date-time */
3966
+ completed_at: string | null;
3967
+ }[];
3968
+ };
3816
3969
  };
3817
3970
  };
3818
3971
  /** @description Resource not found. */
@@ -3855,7 +4008,8 @@ export interface operations {
3855
4008
  created_at: string;
3856
4009
  /** Format: date-time */
3857
4010
  completed_at: string | null;
3858
- total_credits_charged: number;
4011
+ /** @description Total credits billed for the job. Null until the job is billed. Fractional — credits are NUMERIC(10,2). */
4012
+ total_credits_charged: number | null;
3859
4013
  /** @description Null in GET responses (computed at submission time only). */
3860
4014
  estimated_credits: number | null;
3861
4015
  /** @description Webhook endpoint URL (HTTPS only; http:// rejected with 400 invalid_url, reason scheme_unsupported) */
@@ -3938,7 +4092,7 @@ export interface operations {
3938
4092
  /** Format: uri */
3939
4093
  url: string;
3940
4094
  /**
3941
- * @default screenshot
4095
+ * @description Capture kind for this entry. If omitted, inherits `defaults.type`; if that is also omitted, falls back to `screenshot`.
3942
4096
  * @enum {string}
3943
4097
  */
3944
4098
  type?: "screenshot" | "scrape";
@@ -4060,8 +4214,9 @@ export interface operations {
4060
4214
  created_at: string;
4061
4215
  /** Format: date-time */
4062
4216
  completed_at: string | null;
4063
- total_credits_charged: number;
4064
- /** @description Estimated credits at submission time. Null in GET responses. */
4217
+ /** @description Always null on the create response — the job has not been billed yet (routes/bulk.ts builds the 202 body from a partial job row). Fractional when populated (credits are NUMERIC(10,2)); the numeric branch is unreachable on this path and exists only so the 202 and 200 bodies share one shape. */
4218
+ total_credits_charged: number | null;
4219
+ /** @description Estimated credits at submission time. Null in GET responses. Fractional — markdown/html formats weigh 0.5 credits each (scrape-shared/src/credits.ts), so a one-item markdown job is 1.5. */
4065
4220
  estimated_credits: number | null;
4066
4221
  /** @description Webhook endpoint URL (HTTPS only; http:// rejected with 400 invalid_url, reason scheme_unsupported) */
4067
4222
  webhook_url: string;
@@ -4090,7 +4245,17 @@ export interface operations {
4090
4245
  /**
4091
4246
  * @description Validation error. `bulk_too_large` is returned when the item count
4092
4247
  * exceeds the account plan's `max_bulk_size` cap (also surfaced as
4093
- * `max_bulk_size` on `GET /v1/account`).
4248
+ * `max_bulk_size` on `GET /v1/account`). `validation_error` is
4249
+ * returned when the request body contains an unrecognized key
4250
+ * anywhere in the top-level object, an `items[]` entry, or
4251
+ * `defaults` — all three reject unknown keys with a 422
4252
+ * `validation_error` whose `details` message names the offending
4253
+ * key, instead of silently discarding it. The two nested objects
4254
+ * do not accept the same field set: `device_scale_factor` is
4255
+ * `defaults`-only (rejected per item), and `duration`/`scenario`
4256
+ * are `items[]`-only (rejected under `defaults`). `metadata` is
4257
+ * valid both at the top level of the body and per item, but is
4258
+ * rejected with this same 422 if placed under `defaults`.
4094
4259
  */
4095
4260
  422: {
4096
4261
  headers: {
@@ -4131,7 +4296,8 @@ export interface operations {
4131
4296
  created_at: string;
4132
4297
  /** Format: date-time */
4133
4298
  completed_at: string | null;
4134
- total_credits_charged: number;
4299
+ /** @description Total credits billed for the job. Null until the job is billed. Fractional — credits are NUMERIC(10,2). */
4300
+ total_credits_charged: number | null;
4135
4301
  /** @description Null in GET responses (computed at submission time only). */
4136
4302
  estimated_credits: number | null;
4137
4303
  /** @description Webhook endpoint URL (HTTPS only; http:// rejected with 400 invalid_url, reason scheme_unsupported) */
@@ -4179,7 +4345,8 @@ export interface operations {
4179
4345
  created_at: string;
4180
4346
  /** Format: date-time */
4181
4347
  completed_at: string | null;
4182
- total_credits_charged: number;
4348
+ /** @description Total credits billed for the job. Null until the job is billed. Fractional — credits are NUMERIC(10,2). */
4349
+ total_credits_charged: number | null;
4183
4350
  /** @description Null in cancel responses (computed at submission time only). */
4184
4351
  estimated_credits: number | null;
4185
4352
  /** @description Webhook endpoint URL (HTTPS only; http:// rejected with 400 invalid_url, reason scheme_unsupported) */
@@ -4215,7 +4382,48 @@ export interface operations {
4215
4382
  [name: string]: unknown;
4216
4383
  };
4217
4384
  content: {
4218
- "application/json": Record<string, never>;
4385
+ "application/json": {
4386
+ /** @example bulk_01j9abc123 */
4387
+ bulk_id: string;
4388
+ /** @description Number of items in `items` (page size, not the job total). */
4389
+ total: number;
4390
+ /** @description Heterogeneous capture items discriminated by `type`. Fields outside the common set are present only for the matching `type`. */
4391
+ items: {
4392
+ /** @enum {string} */
4393
+ type: "screenshot" | "recording" | "scrape";
4394
+ /** @description Prefixed id — `ss_` / `rec_` / `sc_` per `type`. */
4395
+ id: string;
4396
+ /** @enum {string} */
4397
+ status: "pending" | "processing" | "completed" | "failed" | "cancelled";
4398
+ /** Format: uri */
4399
+ url: string;
4400
+ credits_charged: number | null;
4401
+ error_code: string | null;
4402
+ error_message: string | null;
4403
+ /** Format: date-time */
4404
+ created_at: string;
4405
+ /** Format: date-time */
4406
+ completed_at: string | null;
4407
+ /** @description `type: screenshot` only. Presigned for completed rows with a storage key; raw image_url otherwise. */
4408
+ image_url?: string | null;
4409
+ /** @description `type: screenshot` and `type: scrape` only. */
4410
+ page_title?: string | null;
4411
+ /** @description `type: recording` only. */
4412
+ format?: string;
4413
+ /** @description `type: recording` only. */
4414
+ video_url?: string | null;
4415
+ /** @description `type: scrape` only. */
4416
+ content_url?: string | null;
4417
+ /** @description `type: scrape` only. */
4418
+ content_type?: string | null;
4419
+ /** @description `type: scrape` only. */
4420
+ content_length?: number | null;
4421
+ /** @description `type: scrape` only. Always null in bulk listings — fetch the body via `markdown_url`. */
4422
+ markdown?: string | null;
4423
+ /** @description `type: scrape` only. */
4424
+ markdown_url?: string | null;
4425
+ }[];
4426
+ };
4219
4427
  };
4220
4428
  };
4221
4429
  };
@@ -4524,6 +4732,15 @@ export interface operations {
4524
4732
  "application/json": components["schemas"]["Error"];
4525
4733
  };
4526
4734
  };
4735
+ /** @description Rate limit (`rate_limited`) or concurrency limit (`concurrency_limit`) exceeded. Carries a `Retry-After` header — seconds derived from the same clock as `X-RateLimit-Reset` for the rate-limit variant, a fixed small back-off for the concurrency variant. */
4736
+ 429: {
4737
+ headers: {
4738
+ [name: string]: unknown;
4739
+ };
4740
+ content: {
4741
+ "application/json": components["schemas"]["Error"];
4742
+ };
4743
+ };
4527
4744
  };
4528
4745
  };
4529
4746
  getSitemap: {
@@ -4563,6 +4780,15 @@ export interface operations {
4563
4780
  "application/json": components["schemas"]["Error"];
4564
4781
  };
4565
4782
  };
4783
+ /** @description The id path segment is not a well-formed sitemap job id (genuinely malformed — a well-formed-but-absent id returns 404, not 422; see the Inverse case in issue */
4784
+ 422: {
4785
+ headers: {
4786
+ [name: string]: unknown;
4787
+ };
4788
+ content: {
4789
+ "application/json": components["schemas"]["Error"];
4790
+ };
4791
+ };
4566
4792
  };
4567
4793
  };
4568
4794
  createSearch: {
@@ -4656,7 +4882,7 @@ export interface operations {
4656
4882
  /** Format: uri */
4657
4883
  url: string;
4658
4884
  /** @description Short text excerpt for the result. Present for `web` and `news` results; omitted for `images` results. */
4659
- snippet: string;
4885
+ snippet?: string;
4660
4886
  /** @description Published date of the result. For `web` and `news` results the key is always present but is `null` when the provider reports no date; omitted entirely for `images` results. */
4661
4887
  date?: string | null;
4662
4888
  /** @description Publisher / source name. Present for `news` and `images` results, when the provider reports one. */
@@ -4710,7 +4936,7 @@ export interface operations {
4710
4936
  "application/json": components["schemas"]["Error"];
4711
4937
  };
4712
4938
  };
4713
- /** @description Rate limit exceeded. */
4939
+ /** @description Rate limit exceeded (`rate_limited`). Carries the `X-RateLimit-Limit`/`X-RateLimit-Remaining`/`X-RateLimit-Reset` triplet and a `Retry-After` header. The window is per-second for a bearer API key, or the 60-request/60-second Clerk session window when authenticated via `resolveDualAuth` — `Retry-After` reflects whichever window applies to the request. */
4714
4940
  429: {
4715
4941
  headers: {
4716
4942
  [name: string]: unknown;
@@ -5876,6 +6102,21 @@ export interface operations {
5876
6102
  };
5877
6103
  content?: never;
5878
6104
  };
6105
+ /**
6106
+ * @description Bad request. Returned when the request body exceeds this
6107
+ * endpoint's 256 KB size limit (bespoke `{ error }` body, not the
6108
+ * unified envelope — see the endpoint description).
6109
+ */
6110
+ 400: {
6111
+ headers: {
6112
+ [name: string]: unknown;
6113
+ };
6114
+ content: {
6115
+ "application/json": {
6116
+ error?: string;
6117
+ };
6118
+ };
6119
+ };
5879
6120
  };
5880
6121
  };
5881
6122
  listWebhookDeliveries: {
@@ -5929,6 +6170,18 @@ export interface operations {
5929
6170
  "application/json": components["schemas"]["WebhookDeliveryResponse"];
5930
6171
  };
5931
6172
  };
6173
+ /**
6174
+ * @description Bad request. Returned when the request body exceeds this
6175
+ * endpoint's size limit; the error code is `request_too_large`.
6176
+ */
6177
+ 400: {
6178
+ headers: {
6179
+ [name: string]: unknown;
6180
+ };
6181
+ content: {
6182
+ "application/json": components["schemas"]["Error"];
6183
+ };
6184
+ };
5932
6185
  /** @description Delivery not found or not in a retryable state. */
5933
6186
  404: {
5934
6187
  headers: {
@@ -6145,6 +6398,15 @@ export interface operations {
6145
6398
  "application/json": components["schemas"]["Error"];
6146
6399
  };
6147
6400
  };
6401
+ /** @description Rate limit exceeded (`rate_limited`) — the Clerk-session 60-request/60-second per-user window. Carries a `Retry-After` header derived from the same clock as the window reset. */
6402
+ 429: {
6403
+ headers: {
6404
+ [name: string]: unknown;
6405
+ };
6406
+ content: {
6407
+ "application/json": components["schemas"]["Error"];
6408
+ };
6409
+ };
6148
6410
  };
6149
6411
  };
6150
6412
  updateMe: {
@@ -6181,6 +6443,15 @@ export interface operations {
6181
6443
  "application/json": components["schemas"]["Error"];
6182
6444
  };
6183
6445
  };
6446
+ /** @description Rate limit exceeded (`rate_limited`) — the Clerk-session 60-request/60-second per-user window. Carries a `Retry-After` header derived from the same clock as the window reset. */
6447
+ 429: {
6448
+ headers: {
6449
+ [name: string]: unknown;
6450
+ };
6451
+ content: {
6452
+ "application/json": components["schemas"]["Error"];
6453
+ };
6454
+ };
6184
6455
  };
6185
6456
  };
6186
6457
  requestEmailChange: {
@@ -6244,6 +6515,15 @@ export interface operations {
6244
6515
  "application/json": components["schemas"]["Error"];
6245
6516
  };
6246
6517
  };
6518
+ /** @description Rate limit exceeded (`rate_limited`) — the Clerk-session 60-request/60-second per-user window. Carries a `Retry-After` header derived from the same clock as the window reset. */
6519
+ 429: {
6520
+ headers: {
6521
+ [name: string]: unknown;
6522
+ };
6523
+ content: {
6524
+ "application/json": components["schemas"]["Error"];
6525
+ };
6526
+ };
6247
6527
  };
6248
6528
  };
6249
6529
  removeMember: {
@@ -6387,6 +6667,15 @@ export interface operations {
6387
6667
  "application/json": components["schemas"]["Error"];
6388
6668
  };
6389
6669
  };
6670
+ /** @description Rate limit exceeded (`rate_limited`) — the Clerk-session 60-request/60-second per-user window. Carries a `Retry-After` header derived from the same clock as the window reset. */
6671
+ 429: {
6672
+ headers: {
6673
+ [name: string]: unknown;
6674
+ };
6675
+ content: {
6676
+ "application/json": components["schemas"]["Error"];
6677
+ };
6678
+ };
6390
6679
  };
6391
6680
  };
6392
6681
  createInvite: {
@@ -6443,6 +6732,15 @@ export interface operations {
6443
6732
  "application/json": components["schemas"]["Error"];
6444
6733
  };
6445
6734
  };
6735
+ /** @description Rate limit exceeded (`rate_limited`) — the Clerk-session 60-request/60-second per-user window. Carries a `Retry-After` header derived from the same clock as the window reset. */
6736
+ 429: {
6737
+ headers: {
6738
+ [name: string]: unknown;
6739
+ };
6740
+ content: {
6741
+ "application/json": components["schemas"]["Error"];
6742
+ };
6743
+ };
6446
6744
  };
6447
6745
  };
6448
6746
  acceptInvite: {
package/dist/index.d.ts CHANGED
@@ -3,7 +3,7 @@ export type { ByteKitOptions, RequestOptions, ApiResponse, ConnectionErrorCode }
3
3
  export { V01_METHODS } from './allowlist.js';
4
4
  export type { V01Method } from './allowlist.js';
5
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';
6
+ export type { ScrapeCookie, ScrapeOpts, MarkdownMode, MarkdownLinks, MarkdownImages, TokenEncoding, ScrapeCreateResponse, ScrapeGetResponse, ScrapeBulkCreateRequest, ScrapeBulkCreateResponse, ScrapeBulkGetResponse, } from './resources/scrape.js';
7
7
  export type { ScreenshotCreateRequest, ScreenshotCreateResponse, ScreenshotGetResponse, } from './resources/screenshots.js';
8
8
  export type { FetchOpts, FetchGetOpts, FetchResult, FetchCacheStatus, FetchBulkCreateRequest, FetchBulkCreateResponse, FetchBulkGetResponse, } from './resources/fetch.js';
9
9
  export type { MonitorCreateRequest, MonitorCreateResponse, ListMonitorsParams, MonitorStatus, ListMonitorsResponse, MonitorResponse, MonitorUpdateRequest, UpdateMonitorResponse, ListMonitorCapturesResponse, } from './resources/monitors.js';
@@ -14,7 +14,10 @@ const CACHE_STATUSES = ['hit', 'miss', 'bypass'];
14
14
  function toFetchResult(raw) {
15
15
  const { body, bytes, headers } = raw;
16
16
  const creditsRaw = headers.get('X-Fetch-Credits-Charged');
17
- const credits = creditsRaw === null ? NaN : Number(creditsRaw);
17
+ // An empty-but-present header must be treated the same as an absent one: `Number('')`
18
+ // is `0` (finite), so without this check an empty header parsed as a real zero-credit
19
+ // charge instead of "unparseable" (#2595).
20
+ const credits = creditsRaw === null || creditsRaw.trim() === '' ? NaN : Number(creditsRaw);
18
21
  const cacheRaw = headers.get('X-Fetch-Cache');
19
22
  return {
20
23
  body,
@@ -46,6 +46,19 @@ export type MonitorUpdateRequest = operations['updateMonitor']['requestBody']['c
46
46
  export type UpdateMonitorResponse = operations['updateMonitor']['responses'][200]['content']['application/json'];
47
47
  /** 200 payload of GET /v1/monitors/{id}/captures — the paginated capture list. */
48
48
  export type ListMonitorCapturesResponse = operations['listMonitorCaptures']['responses'][200]['content']['application/json'];
49
+ /**
50
+ * Query params of GET /v1/monitors/{id}/captures — `limit`/`cursor`, both optional and
51
+ * omitted when unset.
52
+ *
53
+ * DERIVED from the generated `listMonitorCaptures` query type (#2594), mirroring
54
+ * {@link ListMonitorsParams} — never hand-authored, so a spec drift (a renamed/removed query
55
+ * param) surfaces as a `tsc` error here rather than a silent request-shape mismatch (E1).
56
+ *
57
+ * Still a `type` alias (not an `interface`), for the same implicit-index-signature reason as
58
+ * {@link ListMonitorsParams} — it must stay assignable to {@link toQueryString}'s
59
+ * `Record<string, string | number | undefined>` param.
60
+ */
61
+ export type ListMonitorCapturesParams = NonNullable<operations['listMonitorCaptures']['parameters']['query']>;
49
62
  export declare class MonitorsResource {
50
63
  private readonly client;
51
64
  readonly captures: MonitorCapturesResource;
@@ -79,7 +92,13 @@ export declare class MonitorsResource {
79
92
  declare class MonitorCapturesResource {
80
93
  private readonly client;
81
94
  constructor(client: ByteKit);
82
- /** GET /v1/monitors/{id}/captures — list captures for a monitor */
83
- list(id: MonitorId, requestOptions?: RequestOptions): Promise<ListMonitorCapturesResponse>;
95
+ /**
96
+ * GET /v1/monitors/{id}/captures — list captures for a monitor.
97
+ *
98
+ * `params` is optional and each key is omitted-when-absent (#2594), so `list(id)` with no
99
+ * second argument serializes the bare `/v1/monitors/{id}/captures` URL unchanged — existing
100
+ * zero-arg callers are unaffected (inverse case).
101
+ */
102
+ list(id: MonitorId, params?: ListMonitorCapturesParams, requestOptions?: RequestOptions): Promise<ListMonitorCapturesResponse>;
84
103
  }
85
104
  export {};
@@ -47,8 +47,14 @@ class MonitorCapturesResource {
47
47
  constructor(client) {
48
48
  this.client = client;
49
49
  }
50
- /** GET /v1/monitors/{id}/captures — list captures for a monitor */
51
- list(id, requestOptions) {
52
- return this.client.request('GET', `/v1/monitors/${id}/captures`, undefined, requestOptions);
50
+ /**
51
+ * GET /v1/monitors/{id}/captures — list captures for a monitor.
52
+ *
53
+ * `params` is optional and each key is omitted-when-absent (#2594), so `list(id)` with no
54
+ * second argument serializes the bare `/v1/monitors/{id}/captures` URL unchanged — existing
55
+ * zero-arg callers are unaffected (inverse case).
56
+ */
57
+ list(id, params, requestOptions) {
58
+ return this.client.request('GET', `/v1/monitors/${id}/captures${toQueryString(params)}`, undefined, requestOptions);
53
59
  }
54
60
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hunt-labs/bytekit-sdk",
3
- "version": "0.4.0",
3
+ "version": "0.5.0",
4
4
  "description": "Official TypeScript SDK for the ByteKit API",
5
5
  "license": "MIT",
6
6
  "type": "module",