bc-api-client 0.1.0-beta.5 → 0.1.0-beta.7

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
@@ -2,7 +2,7 @@
2
2
 
3
3
  <span style="color:orange">BETA VERSION - Use at your own risk</span>
4
4
 
5
- An opinionated and minimalistic client focusing on simplicity and performance.
5
+ An opinionated and minimalistic client focusing on simplicity and concurrent performance.
6
6
  Features (or antifeatures - depends on your opinion)
7
7
  - Node 20+ LTS, ESM
8
8
  - Bring Your Own Types
@@ -12,6 +12,19 @@ Features (or antifeatures - depends on your opinion)
12
12
  - Rate limit handling
13
13
  - App authenticator module. Request token and verify JWT.
14
14
 
15
+ ⚠️ **Disclaimer**: This library provides concurrent request capabilities. BigCommerce has strict rate limits that vary by plan and endpoint. The author is not responsible for any issues arising from improper API usage. Use at your own risk.
16
+
17
+ ## Table of Contents
18
+ - [Installation](#installation)
19
+ - [Usage](#usage)
20
+ - [API Client](#api-client)
21
+ - [Authentication](#authentication)
22
+ - [API](#api)
23
+ - [BigCommerceClient](#bigcommerceclient)
24
+ - [BigCommerceAuth](#bigcommerceauth)
25
+ - [Tips](#tips)
26
+ - [License](#license)
27
+
15
28
  ## Installation
16
29
 
17
30
  ```bash
@@ -124,34 +137,57 @@ const claims = await auth.verify(jwtPayload);
124
137
 
125
138
  #### `get<R>(endpoint: string, options?: GetOptions): Promise<R>`
126
139
  Makes a GET request to the BigCommerce API.
140
+ - `endpoint`: The API endpoint to request
141
+ - `options.query`: Query parameters to include in the request
142
+ - `options.version`: API version to use (v2 or v3, default: v3)
127
143
 
128
144
  #### `post<T, R>(endpoint: string, options?: PostOptions<T>): Promise<R>`
129
145
  Makes a POST request to the BigCommerce API.
146
+ - `endpoint`: The API endpoint to request
147
+ - `options.query`: Query parameters to include in the request
148
+ - `options.version`: API version to use (v2 or v3, default: v3)
149
+ - `options.body`: Request body data of type `T`
130
150
 
131
151
  #### `put<T, R>(endpoint: string, options?: PostOptions<T>): Promise<R>`
132
152
  Makes a PUT request to the BigCommerce API.
153
+ - `endpoint`: The API endpoint to request
154
+ - `options.query`: Query parameters to include in the request
155
+ - `options.version`: API version to use (v2 or v3, default: v3)
156
+ - `options.body`: Request body data of type `T`
133
157
 
134
158
  #### `delete<R>(endpoint: string, options?: Pick<GetOptions, 'version'>): Promise<void>`
135
159
  Makes a DELETE request to the BigCommerce API.
160
+ - `endpoint`: The API endpoint to delete
161
+ - `options.version`: API version to use (v2 or v3, default: v3)
136
162
 
137
163
  #### `concurrent<T, R>(requests: RequestOptions<T>[], options?: ConcurrencyOptions): Promise<R[]>`
138
- Executes multiple requests concurrently with rate limit handling. Options:
139
- - `concurrency`: number of concurrent requests (default: 10)
140
- - `skipErrors`: whether to skip failed requests instead of throwing (default: false)
164
+ Executes multiple requests concurrently with rate limit handling.
165
+ - `requests`: Array of request options to execute
166
+ - `options.concurrency`: Maximum number of concurrent requests (default: 10)
167
+ - `options.skipErrors`: Whether to skip errors and continue processing (default: false)
141
168
 
142
169
  #### `collect<T>(endpoint: string, options: Omit<GetOptions, 'version'> & ConcurrencyOptions): Promise<T[]>`
143
- Automatically fetches all pages of a paginated v3 endpoint. Supports the same concurrency options as `concurrent`.
170
+ Automatically fetches all pages of a paginated v3 endpoint. Pulls the first page and uses pagination meta to collect remaining pages concurrently.
171
+ - `endpoint`: The API endpoint to request
172
+ - `options.query`: Query parameters to include in the request (limit defaults to 250)
173
+ - `options.concurrency`: Maximum number of concurrent requests (default: 10)
174
+ - `options.skipErrors`: Whether to skip errors and continue processing (default: false)
144
175
 
145
176
  #### `collectV2<T>(endpoint: string, options: Omit<GetOptions, 'version'> & ConcurrencyOptions): Promise<T[]>`
146
- Automatically fetches all pages of a paginated v2 endpoint. Supports the same concurrency options as `concurrent`.
177
+ Automatically fetches all pages of a paginated v2 endpoint. Pulls all pages concurrently until a 204 is returned.
178
+ - `endpoint`: The API endpoint to request
179
+ - `options.query`: Query parameters to include in the request (limit defaults to 250)
180
+ - `options.concurrency`: Maximum number of concurrent requests (default: 10)
181
+ - `options.skipErrors`: Whether to skip errors and continue processing (default: false)
147
182
 
148
183
  #### `query<T>(endpoint: string, options: QueryOptions): Promise<T[]>`
149
- Executes a query with multiple filter values, automatically handling large value sets by chunking them into smaller requests. Options:
150
- - `key`: Filter key (e.g. 'id:in')
151
- - `values`: Array of values to filter by
152
- - `query`: Additional query parameters
153
- - `concurrency`: number of concurrent requests (default: 10)
154
- - `skipErrors`: whether to skip failed requests instead of throwing (default: false)
184
+ Queries multiple values against a single field using the v3 API. If the URL + query params are too long, the query will be chunked.
185
+ - `endpoint`: The API endpoint to request
186
+ - `options.key`: The field name to query against (e.g. 'id:in')
187
+ - `options.values`: Array of values to query for
188
+ - `options.query`: Additional query parameters (limit defaults to 250)
189
+ - `options.concurrency`: Maximum number of concurrent requests (default: 10)
190
+ - `options.skipErrors`: Whether to skip errors and continue processing (default: false)
155
191
 
156
192
  ### BigCommerceAuth
157
193
 
@@ -161,6 +197,15 @@ Requests an access token from BigCommerce OAuth.
161
197
  #### `verify(jwtPayload: string): Promise<Claims>`
162
198
  Verifies a JWT payload from BigCommerce.
163
199
 
200
+ ## Tips
201
+
202
+ - I made this library based on my experience of building real-time integrations. It might not be the best choice if you just need to make simple requests or want built-in types. Also, if you're not on enterprise - you can't realistically get much benefit from concurrency, so this library can offer zero to negative (getting throttled) benefit. Check out [this client](https://github.com/kzhang-dsg/bigcommerce-api-client) for a more extensive solution with much better DX. You can also use that library as a source of types and this one for concurrency if you don't mind having two installed.
203
+ - Be careful with concurrent methods as they might get you flagged, especially if you are not working with enterprise stores (which I mostly do). Also, some endpoints have explicit concurrency limits. Check the documentation.
204
+ - Utilize `include_fields` when available and make simplified types to include only the properties you need. This will increase the speed and efficiency of the requests significantly and improve DX as your autocomplete won't be cluttered.
205
+ - Use `query` if you need to fetch, for example, customers from a list of emails, or products from a list of SKUs.
206
+ - This library will not wait for a rate limit longer than 60 seconds by default. I mostly work on real-time applications, so it doesn't make sense to wait longer for me. If you need a longer timeout, pass `maxDelay` to the `BigCommerceClient` constructor.
207
+ - Be careful with endpoints. I populated them manually from the docs and ran them through Claude as a double-check. You can make an issue if something throws a 404, and use the string meanwhile. Also, some may be missing - always check the documentation for your request.
208
+
164
209
  ## License
165
210
 
166
211
  MIT
package/dist/client.d.ts CHANGED
@@ -36,7 +36,7 @@ export type QueryOptions = Omit<GetOptions, 'version'> & ConcurrencyOptions & {
36
36
  /**
37
37
  * Configuration options for the BigCommerce client
38
38
  */
39
- export type Config = StoreOptions & RateLimitOptions;
39
+ export type Config = StoreOptions & RateLimitOptions & ConcurrencyOptions;
40
40
  /**
41
41
  * Client for interacting with the BigCommerce API
42
42
  *
@@ -47,54 +47,86 @@ export declare class BigCommerceClient {
47
47
  private readonly config;
48
48
  /**
49
49
  * Creates a new BigCommerce client instance
50
- * @param config - Configuration options for the client
50
+ * @param config.storeHash - The store hash to use for the client
51
+ * @param config.accessToken - The API access token to use for the client
52
+ * @param config.maxRetries - (default: 5) The maximum number of retries for rate limit errors
53
+ * @param config.maxDelay - (default: 60e3 - 1 minute) Maximum time to wait to retry in case of rate limit errors. If `X-Rate-Limit-Time-Reset-Ms` header is higher than `maxDelay`, the request will fail immediately.
54
+ * @param config.concurrency - (default: 10) The default concurrency for concurrent methods
55
+ * @param config.skipErrors - (default: false) Whether to skip errors during concurrent requests
51
56
  */
52
57
  constructor(config: Config);
53
58
  /**
54
59
  * Makes a GET request to the BigCommerce API
55
- * @param options - Request options
56
- * @returns Promise resolving to the response data
60
+ * @param endpoint - The API endpoint to request
61
+ * @param options.query - Query parameters to include in the request
62
+ * @param options.version - API version to use (v2 or v3) (default: v3)
63
+ * @returns Promise resolving to the response data of type `R`
57
64
  */
58
65
  get<R>(endpoint: string, options?: GetOptions): Promise<R>;
59
66
  /**
60
67
  * Makes a POST request to the BigCommerce API
61
- * @param options - Request options including body data
62
- * @returns Promise resolving to the response data
68
+ * @param endpoint - The API endpoint to request
69
+ * @param options.query - Query parameters to include in the request
70
+ * @param options.version - API version to use (v2 or v3) (default: v3)
71
+ * @param options.body - Request body data of type `T`
72
+ * @returns Promise resolving to the response data of type `R`
63
73
  */
64
74
  post<T, R>(endpoint: string, options?: PostOptions<T>): Promise<R>;
65
75
  /**
66
76
  * Makes a PUT request to the BigCommerce API
67
- * @param options - Request options including body data
68
- * @returns Promise resolving to the response data
77
+ * @param endpoint - The API endpoint to request
78
+ * @param options.query - Query parameters to include in the request
79
+ * @param options.version - API version to use (v2 or v3) (default: v3)
80
+ * @param options.body - Request body data of type `T`
81
+ * @returns Promise resolving to the response data of type `R`
69
82
  */
70
83
  put<T, R>(endpoint: string, options?: PostOptions<T>): Promise<R>;
71
84
  /**
72
85
  * Makes a DELETE request to the BigCommerce API
73
86
  * @param endpoint - The API endpoint to delete
87
+ * @param options.version - API version to use (v2 or v3) (default: v3)
88
+ * @returns Promise resolving to void
74
89
  */
75
90
  delete<R>(endpoint: string, options?: Pick<GetOptions, 'version'>): Promise<void>;
76
91
  /**
77
92
  * Executes multiple requests concurrently with controlled concurrency
78
93
  * @param requests - Array of request options to execute
79
- * @param options - Concurrency control options
94
+ * @param options.concurrency - Maximum number of concurrent requests, overrides the client's concurrency setting (default: 10)
95
+ * @param options.skipErrors - Whether to skip errors and continue processing, overrides the client's skipErrors setting (default: false)
80
96
  * @returns Promise resolving to array of response data
81
97
  */
82
98
  concurrent<T, R>(requests: RequestOptions<T>[], options?: ConcurrencyOptions): Promise<R[]>;
83
99
  /**
84
- * Collects all pages of data from a paginated v3 API endpoint
85
- * @param options - Request options with pagination parameters
100
+ * Collects all pages of data from a paginated v3 API endpoint.
101
+ * This method pulls the first page and uses pagination meta to collect the remaining pages concurrently.
102
+ * @param endpoint - The API endpoint to request
103
+ * @param options.query - Query parameters to include in the request
104
+ * @param options.concurrency - Maximum number of concurrent requests, overrides the client's concurrency setting (default: 10)
105
+ * @param options.skipErrors - Whether to skip errors and continue processing, overrides the client's skipErrors setting (default: false)
86
106
  * @returns Promise resolving to array of all items across all pages
87
107
  */
88
108
  collect<T>(endpoint: string, options: Omit<GetOptions, 'version'> & ConcurrencyOptions): Promise<T[]>;
89
109
  /**
90
- * Collects all pages of data from a paginated v2 API endpoint
91
- * @param options - Request options with pagination parameters
110
+ * Collects all pages of data from a paginated v2 API endpoint.
111
+ * This method simply pulls all pages concurrently until a 204 is returned in a batch.
112
+ * @param endpoint - The API endpoint to request
113
+ * @param options.query - Query parameters to include in the request
114
+ * @param options.concurrency - Maximum number of concurrent requests, overrides the client's concurrency setting (default: 10)
115
+ * @param options.skipErrors - Whether to skip errors and continue processing, overrides the client's skipErrors setting (default: false)
92
116
  * @returns Promise resolving to array of all items across all pages
93
117
  */
94
118
  collectV2<T>(endpoint: string, options: Omit<GetOptions, 'version'> & ConcurrencyOptions): Promise<T[]>;
95
119
  /**
96
- * Queries multiple values against a single field using the v3 API
97
- * @param options - Query options including field name and values
120
+ * Queries multiple values against a single field using the v3 API.
121
+ * If the url + query params are too long, the query will be chunked. Otherwise, this method acts like `collect`.
122
+ * This method does not check for uniqueness of the `values` array.
123
+ *
124
+ * @param endpoint - The API endpoint to request
125
+ * @param options.key - The field name to query against e.g. `sku:in`
126
+ * @param options.values - Array of values to query for e.g. `['123', '456', ...]`
127
+ * @param options.query - Additional query parameters
128
+ * @param options.concurrency - Maximum number of concurrent requests, overrides the client's concurrency setting (default: 10)
129
+ * @param options.skipErrors - Whether to skip errors and continue processing, overrides the client's skipErrors setting (default: false)
98
130
  * @returns Promise resolving to array of matching items
99
131
  */
100
132
  query<T>(endpoint: string, options: QueryOptions): Promise<T[]>;
package/dist/index.js CHANGED
@@ -151,9 +151,6 @@ var call = (options) => {
151
151
  return ky(fullUrl, request2);
152
152
  };
153
153
 
154
- // src/client.ts
155
- import { chunk, range } from "remeda";
156
-
157
154
  // src/util.ts
158
155
  var chunkStrLength = (items, options = {}) => {
159
156
  const { maxLength = 2048, chunkLength = 250, offset = 0, separatorSize = 1 } = options;
@@ -186,18 +183,35 @@ var chunkStrLength = (items, options = {}) => {
186
183
 
187
184
  // src/client.ts
188
185
  var MAX_PAGE_SIZE = 250;
186
+ var DEFAULT_CONCURRENCY = 10;
187
+ function chunkArray(array, size) {
188
+ return Array.from(
189
+ { length: Math.ceil(array.length / size) },
190
+ (_, i) => array.slice(i * size, i * size + size)
191
+ );
192
+ }
193
+ function rangeArray(start, end) {
194
+ return Array.from({ length: end - start + 1 }, (_, i) => start + i);
195
+ }
189
196
  var BigCommerceClient = class {
190
197
  /**
191
198
  * Creates a new BigCommerce client instance
192
- * @param config - Configuration options for the client
199
+ * @param config.storeHash - The store hash to use for the client
200
+ * @param config.accessToken - The API access token to use for the client
201
+ * @param config.maxRetries - (default: 5) The maximum number of retries for rate limit errors
202
+ * @param config.maxDelay - (default: 60e3 - 1 minute) Maximum time to wait to retry in case of rate limit errors. If `X-Rate-Limit-Time-Reset-Ms` header is higher than `maxDelay`, the request will fail immediately.
203
+ * @param config.concurrency - (default: 10) The default concurrency for concurrent methods
204
+ * @param config.skipErrors - (default: false) Whether to skip errors during concurrent requests
193
205
  */
194
206
  constructor(config) {
195
207
  this.config = config;
196
208
  }
197
209
  /**
198
210
  * Makes a GET request to the BigCommerce API
199
- * @param options - Request options
200
- * @returns Promise resolving to the response data
211
+ * @param endpoint - The API endpoint to request
212
+ * @param options.query - Query parameters to include in the request
213
+ * @param options.version - API version to use (v2 or v3) (default: v3)
214
+ * @returns Promise resolving to the response data of type `R`
201
215
  */
202
216
  async get(endpoint, options) {
203
217
  return request({
@@ -209,8 +223,11 @@ var BigCommerceClient = class {
209
223
  }
210
224
  /**
211
225
  * Makes a POST request to the BigCommerce API
212
- * @param options - Request options including body data
213
- * @returns Promise resolving to the response data
226
+ * @param endpoint - The API endpoint to request
227
+ * @param options.query - Query parameters to include in the request
228
+ * @param options.version - API version to use (v2 or v3) (default: v3)
229
+ * @param options.body - Request body data of type `T`
230
+ * @returns Promise resolving to the response data of type `R`
214
231
  */
215
232
  async post(endpoint, options) {
216
233
  return request({
@@ -222,8 +239,11 @@ var BigCommerceClient = class {
222
239
  }
223
240
  /**
224
241
  * Makes a PUT request to the BigCommerce API
225
- * @param options - Request options including body data
226
- * @returns Promise resolving to the response data
242
+ * @param endpoint - The API endpoint to request
243
+ * @param options.query - Query parameters to include in the request
244
+ * @param options.version - API version to use (v2 or v3) (default: v3)
245
+ * @param options.body - Request body data of type `T`
246
+ * @returns Promise resolving to the response data of type `R`
227
247
  */
228
248
  async put(endpoint, options) {
229
249
  return request({
@@ -236,6 +256,8 @@ var BigCommerceClient = class {
236
256
  /**
237
257
  * Makes a DELETE request to the BigCommerce API
238
258
  * @param endpoint - The API endpoint to delete
259
+ * @param options.version - API version to use (v2 or v3) (default: v3)
260
+ * @returns Promise resolving to void
239
261
  */
240
262
  async delete(endpoint, options) {
241
263
  await request({
@@ -248,16 +270,17 @@ var BigCommerceClient = class {
248
270
  /**
249
271
  * Executes multiple requests concurrently with controlled concurrency
250
272
  * @param requests - Array of request options to execute
251
- * @param options - Concurrency control options
273
+ * @param options.concurrency - Maximum number of concurrent requests, overrides the client's concurrency setting (default: 10)
274
+ * @param options.skipErrors - Whether to skip errors and continue processing, overrides the client's skipErrors setting (default: false)
252
275
  * @returns Promise resolving to array of response data
253
276
  */
254
277
  async concurrent(requests, options) {
255
- const chunks = chunk(requests, options?.concurrency ?? 10);
256
- const skipErrors = options?.skipErrors ?? false;
278
+ const chunks = chunkArray(requests, options?.concurrency ?? this.config.concurrency ?? DEFAULT_CONCURRENCY);
279
+ const skipErrors = options?.skipErrors ?? this.config.skipErrors ?? false;
257
280
  const results = [];
258
- for (const chunk2 of chunks) {
281
+ for (const chunk of chunks) {
259
282
  const responses = await Promise.allSettled(
260
- chunk2.map(
283
+ chunk.map(
261
284
  (opt) => request({
262
285
  ...opt,
263
286
  ...this.config
@@ -279,8 +302,12 @@ var BigCommerceClient = class {
279
302
  return results;
280
303
  }
281
304
  /**
282
- * Collects all pages of data from a paginated v3 API endpoint
283
- * @param options - Request options with pagination parameters
305
+ * Collects all pages of data from a paginated v3 API endpoint.
306
+ * This method pulls the first page and uses pagination meta to collect the remaining pages concurrently.
307
+ * @param endpoint - The API endpoint to request
308
+ * @param options.query - Query parameters to include in the request
309
+ * @param options.concurrency - Maximum number of concurrent requests, overrides the client's concurrency setting (default: 10)
310
+ * @param options.skipErrors - Whether to skip errors and continue processing, overrides the client's skipErrors setting (default: false)
284
311
  * @returns Promise resolving to array of all items across all pages
285
312
  */
286
313
  async collect(endpoint, options) {
@@ -297,21 +324,31 @@ var BigCommerceClient = class {
297
324
  }
298
325
  const results = [...first.data];
299
326
  const pages = first.meta.pagination.total_pages;
300
- const remainingPages = range(2, pages + 1);
301
- const requests = remainingPages.map((page) => ({
302
- ...options,
303
- endpoint,
304
- query: { ...options.query, page: page.toString() }
305
- }));
306
- const responses = await this.concurrent(requests, options);
307
- responses.forEach((response) => {
308
- results.push(...response.data);
309
- });
327
+ if (pages > 1) {
328
+ const pageRequests = rangeArray(2, pages).map((page) => ({
329
+ endpoint,
330
+ method: "GET",
331
+ query: {
332
+ ...options.query,
333
+ page: page.toString()
334
+ }
335
+ }));
336
+ const remainingPages = await this.concurrent(pageRequests, options);
337
+ remainingPages.forEach((page) => {
338
+ if (Array.isArray(page.data)) {
339
+ results.push(...page.data);
340
+ }
341
+ });
342
+ }
310
343
  return results;
311
344
  }
312
345
  /**
313
- * Collects all pages of data from a paginated v2 API endpoint
314
- * @param options - Request options with pagination parameters
346
+ * Collects all pages of data from a paginated v2 API endpoint.
347
+ * This method simply pulls all pages concurrently until a 204 is returned in a batch.
348
+ * @param endpoint - The API endpoint to request
349
+ * @param options.query - Query parameters to include in the request
350
+ * @param options.concurrency - Maximum number of concurrent requests, overrides the client's concurrency setting (default: 10)
351
+ * @param options.skipErrors - Whether to skip errors and continue processing, overrides the client's skipErrors setting (default: false)
315
352
  * @returns Promise resolving to array of all items across all pages
316
353
  */
317
354
  async collectV2(endpoint, options) {
@@ -325,9 +362,9 @@ var BigCommerceClient = class {
325
362
  let done = false;
326
363
  const results = [];
327
364
  let page = 1;
328
- const concurrency = options.concurrency ?? 10;
365
+ const concurrency = options.concurrency ?? this.config.concurrency ?? DEFAULT_CONCURRENCY;
329
366
  while (!done) {
330
- const pages = range(page, page + concurrency);
367
+ const pages = rangeArray(page, page + concurrency);
331
368
  page += concurrency;
332
369
  const requests = pages.map((page2) => ({
333
370
  ...options,
@@ -347,7 +384,7 @@ var BigCommerceClient = class {
347
384
  if (response.reason instanceof RequestError && response.reason.status === 404) {
348
385
  done = true;
349
386
  } else {
350
- if (!options.skipErrors) {
387
+ if (!(options.skipErrors ?? this.config.skipErrors ?? false)) {
351
388
  throw response.reason;
352
389
  } else {
353
390
  console.warn(`Error in collectV2: ${response.reason}`);
@@ -359,8 +396,16 @@ var BigCommerceClient = class {
359
396
  return results;
360
397
  }
361
398
  /**
362
- * Queries multiple values against a single field using the v3 API
363
- * @param options - Query options including field name and values
399
+ * Queries multiple values against a single field using the v3 API.
400
+ * If the url + query params are too long, the query will be chunked. Otherwise, this method acts like `collect`.
401
+ * This method does not check for uniqueness of the `values` array.
402
+ *
403
+ * @param endpoint - The API endpoint to request
404
+ * @param options.key - The field name to query against e.g. `sku:in`
405
+ * @param options.values - Array of values to query for e.g. `['123', '456', ...]`
406
+ * @param options.query - Additional query parameters
407
+ * @param options.concurrency - Maximum number of concurrent requests, overrides the client's concurrency setting (default: 10)
408
+ * @param options.skipErrors - Whether to skip errors and continue processing, overrides the client's skipErrors setting (default: false)
364
409
  * @returns Promise resolving to array of matching items
365
410
  */
366
411
  async query(endpoint, options) {
@@ -378,10 +423,10 @@ var BigCommerceClient = class {
378
423
  offset: fullUrl.length,
379
424
  chunkLength: Number.parseInt(options.query?.limit) || MAX_PAGE_SIZE
380
425
  });
381
- const requests = chunks.map((chunk2) => ({
426
+ const requests = chunks.map((chunk) => ({
382
427
  ...options,
383
428
  endpoint,
384
- query: { ...options.query, [options.key]: chunk2.join(",") }
429
+ query: { ...options.query, [options.key]: chunk.join(",") }
385
430
  }));
386
431
  const responses = await this.concurrent(requests, options);
387
432
  return responses.flatMap((response) => response.data);
@@ -391,7 +436,6 @@ var BigCommerceClient = class {
391
436
  // src/auth.ts
392
437
  import ky2 from "ky";
393
438
  import * as jose from "jose";
394
- import { intersection } from "remeda";
395
439
  var GRANT_TYPE = "authorization_code";
396
440
  var TOKEN_ENDPOINT = "https://login.bigcommerce.com/oauth2/token";
397
441
  var ISSUER = "bc";
@@ -487,12 +531,14 @@ var BigCommerceAuth = class {
487
531
  * @throws {Error} If the scopes don't match the expected scopes
488
532
  */
489
533
  validateScopes(scopes) {
490
- const scopesArray = scopes.split(" ");
491
- if (this.config.scopes?.length) {
492
- const int = intersection(scopesArray, this.config.scopes);
493
- if (int.length !== scopesArray.length) {
494
- throw new Error(`Scope mismatch: ${scopes}; expected: ${this.config.scopes.join(" ")}`);
495
- }
534
+ if (!this.config.scopes) {
535
+ return;
536
+ }
537
+ const grantedScopes = scopes.split(" ");
538
+ const requiredScopes = this.config.scopes;
539
+ const missingScopes = requiredScopes.filter((scope) => !grantedScopes.includes(scope));
540
+ if (missingScopes.length) {
541
+ throw new Error(`Scope mismatch: ${scopes}; expected: ${this.config.scopes.join(" ")}`);
496
542
  }
497
543
  }
498
544
  };
package/dist/index.js.map CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
- "sources": ["../src/net.ts", "../src/client.ts", "../src/util.ts", "../src/auth.ts"],
4
- "sourcesContent": ["/**\n * Network utilities for interacting with the BigCommerce API.\n * Provides rate-limited request handling, error management, and type-safe API calls.\n */\n\nimport ky, { ResponsePromise, KyResponse, HTTPError } from 'ky';\n\n/** HTTP methods supported by the API */\nexport type Method = 'GET' | 'POST' | 'PUT' | 'DELETE';\n\nexport const Methods: Record<string, Method> = {\n GET: 'GET',\n POST: 'POST',\n PUT: 'PUT',\n DELETE: 'DELETE',\n} as const;\n\nexport const BASE_URL = 'https://api.bigcommerce.com/stores/';\n\n/** Configuration for the BigCommerce API client */\nconst CONFIG = {\n /** Base URL for BigCommerce API */\n BASE_URL,\n /** Default API version to use */\n DEFAULT_VERSION: 'v3',\n /** Maximum delay in milliseconds for rate limit retries */\n DEFAULT_MAX_DELAY: 60e3,\n /** Maximum allowed URL length */\n MAX_URL_LENGTH: 2048,\n /** Default maximum number of retries for rate-limited requests */\n DEFAULT_MAX_RETRIES: 5,\n /** Rate limit header names */\n HEADERS: {\n /** Time window for rate limiting in milliseconds */\n WINDOW: 'x-rate-limit-time-window-ms',\n /** Time to wait before retrying after rate limit in milliseconds */\n RETRY_AFTER: 'x-rate-limit-time-reset-ms',\n /** Total request quota for the time window */\n REQUEST_QUOTA: 'x-rate-limit-requests-quota',\n /** Number of requests remaining in the current window */\n REQUESTS_LEFT: 'x-rate-limit-requests-left',\n }\n} as const;\n\n/** Supported BigCommerce API versions */\nexport type ApiVersion = 'v3' | 'v2';\n\n/**\n * Options for making API requests\n * @template T - Type of the request body\n */\nexport type RequestOptions<T> = {\n /** API endpoint to call */\n endpoint: string;\n /** HTTP method to use */\n method?: Method;\n /** Request body data */\n body?: T;\n /** API version to use */\n version?: ApiVersion;\n /** Query parameters to append to the URL */\n query?: Record<string, string>;\n};\n\nexport type StoreOptions = {\n /** BigCommerce store hash */\n storeHash: string;\n /** API access token */\n accessToken: string;\n}\n\n/**\n * Options for rate limit handling\n */\nexport type RateLimitOptions = {\n /** Maximum delay in milliseconds before giving up on rate-limited requests */\n maxDelay?: number;\n /** Maximum number of retries for rate-limited requests */\n maxRetries?: number;\n};\n\n/**\n * Custom error class for API request failures\n * @template T - Type of the error data\n */\nexport class RequestError<T> extends Error {\n constructor(\n public status: number,\n public message: string,\n public data: T | string,\n public cause?: unknown,\n ) {\n super(message, { cause });\n }\n}\n\n/**\n * Makes an API request with rate limit handling\n * @template T - Type of the request body and response\n * @param options - Request options including rate limit settings\n * @returns Promise resolving to the API response\n * @throws {RequestError} If the request fails or rate limit is exceeded\n */\nexport const request = async <T, R>(options: RequestOptions<T> & RateLimitOptions & StoreOptions): Promise<R> => {\n const { maxDelay = CONFIG.DEFAULT_MAX_DELAY, maxRetries = CONFIG.DEFAULT_MAX_RETRIES } = options;\n\n let retries = 0;\n let lastError: RequestError<T> | null = null;\n\n while (retries < maxRetries) {\n try {\n return await safeRequest<T, R>(options);\n } catch (error) {\n const err = error as RequestError<T>;\n lastError = err;\n\n if (err.status === 429 && typeof err.data === 'object' && err.data !== null && 'headers' in err.data) {\n const headers = err.data.headers as Record<string, string>;\n\n const retryAfter = Number.parseInt(headers[CONFIG.HEADERS.RETRY_AFTER]);\n\n if (Number.isNaN(retryAfter)) {\n throw new RequestError(\n err.status,\n `Failed to parse retry after: ${headers[CONFIG.HEADERS.RETRY_AFTER]}, ${err.message}`,\n err.data,\n err.cause,\n );\n }\n\n if (retryAfter > maxDelay) {\n throw new RequestError(\n err.status,\n `Rate limit exceeded: ${retryAfter}ms, ${err.message}`,\n err.data,\n err.cause,\n );\n }\n\n await new Promise((resolve) => setTimeout(resolve, retryAfter));\n retries++;\n continue;\n }\n\n throw err;\n }\n }\n\n throw lastError ?? new RequestError(500, 'Failed to make request', 'Too many retries after rate limit');\n};\n\n/**\n * Makes a single API request with error handling\n * @template T - Type of the request body and response\n * @param options - Request options\n * @returns Promise resolving to the API response\n * @throws {RequestError} If the request fails\n */ \nconst safeRequest = async <T, R>(options: RequestOptions<T> & StoreOptions): Promise<R> => {\n let res: KyResponse<T>;\n\n try {\n res = await call<T, R>(options);\n } catch (error) {\n if(error instanceof RequestError) {\n throw error;\n }\n\n if(!(error instanceof HTTPError)) {\n throw error;\n }\n\n let data: unknown;\n let errorMessage = error.message;\n\n try {\n data = await error.response.text();\n try {\n data = JSON.parse(data as string);\n\n if (typeof data === 'object' && data !== null && 'message' in data) {\n errorMessage = data.message as string;\n }\n } catch {\n // If JSON parsing fails, keep the text response\n }\n } catch {\n data = 'Failed to read error response';\n }\n\n throw new RequestError(\n error?.response?.status ?? 500,\n errorMessage,\n {\n data,\n headers: Object.fromEntries(error?.response?.headers?.entries() ?? []),\n },\n error,\n );\n }\n\n const text = await res.text();\n\n\n if(res.status === 204) {\n return undefined as unknown as R;\n }\n\n try {\n return JSON.parse(text);\n } catch (error) {\n throw new RequestError(\n res.status,\n `Failed to parse response: ${text}`,\n text,\n error\n );\n }\n};\n\n/**\n * Internal function to make the actual HTTP request\n * @template T - Type of the request body and response\n * @param options - Request options\n * @returns Promise resolving to the raw response\n * @throws {RequestError} If the URL is too long or request fails\n */\nconst call = <T, R>(options: RequestOptions<T> & StoreOptions): ResponsePromise<R> => {\n const { storeHash, accessToken, endpoint, method = 'GET', body, version = CONFIG.DEFAULT_VERSION, query } = options;\n\n const url = `${CONFIG.BASE_URL}${storeHash}/${version}/${endpoint.replace(/^\\//, '')}`;\n \n // Check URL length including search params\n const searchParams = query ? new URLSearchParams(query).toString() : '';\n const fullUrl = searchParams ? `${url}?${searchParams}` : url;\n \n if (fullUrl.length > CONFIG.MAX_URL_LENGTH) {\n throw new RequestError(\n 400,\n 'URL too long',\n `URL length ${fullUrl.length} exceeds maximum allowed length of ${CONFIG.MAX_URL_LENGTH}`,\n );\n }\n\n const request = {\n method,\n headers: {\n 'Content-Type': 'application/json',\n 'Accept': 'application/json',\n 'X-Auth-Token': accessToken,\n },\n json: body,\n };\n\n return ky<R>(fullUrl, request);\n};\n", "import { V3Resource } from './core';\nimport { BASE_URL, RateLimitOptions, RequestError, RequestOptions, StoreOptions, request } from './net';\nimport { chunk, range } from 'remeda';\nimport { chunkStrLength } from './util';\n\nconst MAX_PAGE_SIZE = 250;\n\n/**\n * Options for GET requests to the BigCommerce API\n */\nexport type GetOptions = {\n /** Query parameters to include in the request */\n query?: Record<string, string>;\n /** API version to use (v2 or v3) */\n version?: 'v2' | 'v3';\n};\n\n/**\n * Options for POST/PUT requests to the BigCommerce API\n */\nexport type PostOptions<T> = GetOptions & {\n /** Request body data */\n body: T;\n};\n\n/**\n * Options for controlling concurrent request behavior\n */\nexport type ConcurrencyOptions = {\n /** Maximum number of concurrent requests (default: 10) */\n concurrency?: number;\n /** Whether to skip errors and continue processing (default: false) */\n skipErrors?: boolean;\n};\n\n/**\n * Options for querying multiple values against a single filter field\n */\nexport type QueryOptions = Omit<GetOptions, 'version'> & ConcurrencyOptions & {\n /** The field name to query against */\n key: string;\n /** Array of values to query for */\n values: (string | number)[];\n};\n\n/**\n * Configuration options for the BigCommerce client\n */\nexport type Config = StoreOptions & RateLimitOptions;\n\n/**\n * Client for interacting with the BigCommerce API\n * \n * This client provides methods for making HTTP requests to the BigCommerce API,\n * with support for both v2 and v3 endpoints, pagination, and concurrent requests.\n */\nexport class BigCommerceClient {\n /**\n * Creates a new BigCommerce client instance\n * @param config - Configuration options for the client\n */\n constructor(private readonly config: Config) {}\n\n /**\n * Makes a GET request to the BigCommerce API\n * @param options - Request options\n * @returns Promise resolving to the response data\n */\n async get<R>(endpoint: string, options?: GetOptions): Promise<R> {\n return request<never, R>({\n endpoint,\n method: 'GET',\n ...options,\n ...this.config,\n });\n }\n\n /**\n * Makes a POST request to the BigCommerce API\n * @param options - Request options including body data\n * @returns Promise resolving to the response data\n */\n async post<T, R>(endpoint: string, options?: PostOptions<T>): Promise<R> {\n return request<T, R>({\n endpoint,\n method: 'POST',\n ...options,\n ...this.config,\n });\n }\n\n /**\n * Makes a PUT request to the BigCommerce API\n * @param options - Request options including body data\n * @returns Promise resolving to the response data\n */\n async put<T, R>(endpoint: string, options?: PostOptions<T>): Promise<R> {\n return request<T, R>({\n endpoint,\n method: 'PUT',\n ...options,\n ...this.config,\n });\n }\n\n /**\n * Makes a DELETE request to the BigCommerce API\n * @param endpoint - The API endpoint to delete\n */\n async delete<R>(endpoint: string, options?: Pick<GetOptions, 'version'>): Promise<void> {\n await request<never, R>({\n endpoint,\n method: 'DELETE',\n ...options,\n ...this.config,\n });\n }\n\n /**\n * Executes multiple requests concurrently with controlled concurrency\n * @param requests - Array of request options to execute\n * @param options - Concurrency control options\n * @returns Promise resolving to array of response data\n */\n async concurrent<T, R>(requests: RequestOptions<T>[], options?: ConcurrencyOptions): Promise<R[]> {\n const chunks = chunk(requests, options?.concurrency ?? 10);\n const skipErrors = options?.skipErrors ?? false;\n\n const results: R[] = [];\n\n for (const chunk of chunks) {\n const responses = await Promise.allSettled(\n chunk.map((opt) =>\n request<T, R>({\n ...opt,\n ...this.config,\n }),\n ),\n );\n\n responses.forEach((response) => {\n if (response.status === 'fulfilled') {\n results.push(response.value);\n } else {\n if (!skipErrors) {\n throw response.reason;\n } else {\n console.warn(`Error in concurrent request: ${response.reason}`);\n }\n }\n });\n }\n\n return results;\n }\n\n /**\n * Collects all pages of data from a paginated v3 API endpoint\n * @param options - Request options with pagination parameters\n * @returns Promise resolving to array of all items across all pages\n */\n async collect<T>(endpoint: string, options: Omit<GetOptions, 'version'> & ConcurrencyOptions): Promise<T[]> {\n if (options.query) {\n if (!options.query.limit) {\n options.query.limit = MAX_PAGE_SIZE.toString();\n }\n } else {\n options.query = { limit: MAX_PAGE_SIZE.toString() };\n }\n\n const first = await this.get<V3Resource<T[]>>(endpoint, options);\n\n if (!Array.isArray(first.data) || !first?.meta?.pagination?.total_pages) {\n return first.data;\n }\n\n const results: T[] = [...first.data];\n const pages = first.meta.pagination.total_pages;\n\n const remainingPages = range(2, pages + 1);\n\n const requests = remainingPages.map((page) => ({\n ...options,\n endpoint,\n query: { ...options.query, page: page.toString() },\n }));\n\n const responses = await this.concurrent<never, V3Resource<T[]>>(requests, options);\n\n responses.forEach((response) => {\n results.push(...response.data);\n });\n\n return results;\n }\n\n /**\n * Collects all pages of data from a paginated v2 API endpoint\n * @param options - Request options with pagination parameters\n * @returns Promise resolving to array of all items across all pages\n */\n async collectV2<T>(endpoint: string, options: Omit<GetOptions, 'version'> & ConcurrencyOptions): Promise<T[]> {\n if (options.query) {\n if (!options.query.limit) {\n options.query.limit = MAX_PAGE_SIZE.toString();\n }\n } else {\n options.query = { limit: MAX_PAGE_SIZE.toString() };\n }\n\n let done = false;\n const results: T[] = [];\n let page = 1;\n const concurrency = options.concurrency ?? 10;\n\n while (!done) {\n const pages = range(page, page + concurrency);\n page += concurrency;\n\n const requests = pages.map((page) => ({\n ...options,\n endpoint,\n version: 'v2' as const,\n query: { ...options.query, page: page.toString() },\n }));\n\n const responses = await Promise.allSettled(requests.map((request) => this.get<T[]>(endpoint, request)));\n\n responses.forEach((response) => {\n if (response.status === 'fulfilled') {\n if (response.value) {\n results.push(...response.value);\n } else {\n done = true;\n }\n } else {\n if (response.reason instanceof RequestError && response.reason.status === 404) {\n done = true;\n } else {\n if (!options.skipErrors) {\n throw response.reason;\n } else {\n console.warn(`Error in collectV2: ${response.reason}`);\n }\n }\n }\n });\n }\n\n return results;\n }\n\n /**\n * Queries multiple values against a single field using the v3 API\n * @param options - Query options including field name and values\n * @returns Promise resolving to array of matching items\n */\n async query<T>(endpoint: string, options: QueryOptions): Promise<T[]> {\n if(options.query) {\n if(!options.query.limit) {\n options.query.limit = MAX_PAGE_SIZE.toString();\n }\n } else {\n options.query = { limit: MAX_PAGE_SIZE.toString() };\n }\n\n const {limit:_, ...restQuery} = options.query;\n // Only needed to calculate the offset for chunking\n const fullUrl = `${BASE_URL}${this.config.storeHash}/v3/${endpoint}?${new URLSearchParams(restQuery).toString()}`;\n\n const queryStr = options.values.map((value) => `${value}`)\n const chunks = chunkStrLength(queryStr, {\n offset: fullUrl.length,\n chunkLength: Number.parseInt(options.query?.limit) || MAX_PAGE_SIZE,\n });\n\n const requests = chunks.map((chunk) => ({\n ...options,\n endpoint,\n query: { ...options.query, [options.key]: chunk.join(',') },\n }));\n\n const responses = await this.concurrent<never, V3Resource<T[]>>(requests, options);\n\n return responses.flatMap((response) => response.data);\n }\n}\n", "/**\n * Split an array of strings into chunks by following logic\n *\n * 1. add length of each string + separatorSize to offset\n * 2. if result is greater than `maxLength`, start a new chunk\n * 3. otherwise, add the string to the current chunk until the chunk is of `chunkLength`\n *\n * This function to be used for splitting query params to avoid url length limit\n *\n * @param items array of strings\n * @param options\n * @param options.maxLength max length of the combined strings\n * @param options.chunkLength max length of each chunk\n * @param options.offset offset of the first chunk\n * @param options.separatorSize size of the separator\n */\nexport const chunkStrLength = (\n items: string[],\n options: {\n maxLength?: number;\n chunkLength?: number;\n offset?: number;\n separatorSize?: number;\n } = {},\n) => {\n const { maxLength = 2048, chunkLength = 250, offset = 0, separatorSize = 1 } = options;\n\n const chunks: string[][] = [];\n let currentStrLength = offset;\n let currentChunk: string[] = [];\n\n for (const item of items) {\n const itemLength = item.length + separatorSize;\n\n const newCurrentStrLength = currentStrLength + itemLength;\n // Check if adding this item would exceed maxLength\n if (newCurrentStrLength > maxLength) {\n if (currentChunk.length > 0) {\n chunks.push(currentChunk);\n currentChunk = [];\n currentStrLength = offset;\n }\n }\n\n // Check if current chunk is full\n if (currentChunk.length === chunkLength) {\n chunks.push(currentChunk);\n currentChunk = [];\n currentStrLength = offset;\n }\n\n currentChunk.push(item);\n currentStrLength += itemLength;\n }\n\n // Add the last chunk if it's not empty\n if (currentChunk.length > 0) {\n chunks.push(currentChunk);\n }\n\n return chunks;\n};\n", "import ky from 'ky';\nimport * as jose from 'jose';\nimport { intersection } from 'remeda';\n\n/**\n * Configuration options for BigCommerce authentication\n */\ntype Config = {\n /** The OAuth client ID from BigCommerce */\n clientId: string;\n /** The OAuth client secret from BigCommerce */\n secret: string;\n /** The redirect URI registered with BigCommerce */\n redirectUri: string;\n /** The store hash for the BigCommerce store */\n storeHash: string;\n /** Optional array of scopes to validate during auth callback */\n scopes?: string[];\n};\n\nconst GRANT_TYPE = 'authorization_code';\nconst TOKEN_ENDPOINT = 'https://login.bigcommerce.com/oauth2/token';\nconst ISSUER = 'bc';\n\n/**\n * Query parameters received from BigCommerce auth callback\n */\ntype AuthQuery = {\n /** The BigCommerce account UUID */\n account_uuid: string;\n /** The authorization code from BigCommerce */\n code: string;\n /** The granted OAuth scopes */\n scope: string;\n /** The store context */\n context: string;\n};\n\n/**\n * Request payload for token endpoint\n */\ntype TokenRequest = {\n client_id: string;\n client_secret: string;\n code: string;\n context: string;\n scope: string;\n grant_type: typeof GRANT_TYPE;\n redirect_uri: string;\n};\n\n/**\n * User information returned from BigCommerce\n */\nexport type User = {\n /** The user's ID */\n id: number;\n /** The user's username */\n username: string;\n /** The user's email address */\n email: string;\n};\n\n/**\n * Response from BigCommerce token endpoint\n */\nexport type TokenResponse = {\n /** The OAuth access token */\n access_token: string;\n /** The granted OAuth scopes */\n scope: string;\n /** Information about the authenticated user */\n user: User;\n /** Information about the store owner */\n owner: User;\n /** The store context */\n context: string;\n /** The BigCommerce account UUID */\n account_uuid: string;\n};\n\n/**\n * JWT claims from BigCommerce\n */\nexport type Claims = {\n /** JWT audience */\n aud: string;\n /** JWT issuer */\n iss: string;\n /** JWT issued at timestamp */\n iat: number;\n /** JWT not before timestamp */\n nbf: number;\n /** JWT expiration timestamp */\n exp: number;\n /** JWT unique identifier */\n jti: string;\n /** JWT subject */\n sub: string;\n /** Information about the authenticated user */\n user: {\n id: number;\n email: string;\n locale: string;\n };\n /** Information about the store owner */\n owner: {\n id: number;\n email: string;\n };\n /** The store URL */\n url: string;\n /** The channel ID (if applicable) */\n channel_id: number | null;\n}\n\n/**\n * Handles authentication with BigCommerce OAuth\n */\nexport class BigCommerceAuth {\n /**\n * Creates a new BigCommerceAuth instance\n * @param config - Configuration options for BigCommerce authentication\n * @throws {Error} If the redirect URI is invalid\n */\n constructor(private readonly config: Config) {\n try {\n new URL(this.config.redirectUri);\n } catch (error) {\n throw new Error('Invalid redirect URI', { cause: error });\n }\n }\n\n /**\n * Requests an access token from BigCommerce\n * @param data - Either a query string or AuthQuery object containing auth callback data\n * @returns Promise resolving to the token response\n */\n async requestToken(data: string | AuthQuery) {\n const query = typeof data === 'string' ? this.parseQueryString(data) : data;\n\n const tokenRequest: TokenRequest = {\n client_id: this.config.clientId,\n client_secret: this.config.secret,\n ...query,\n grant_type: GRANT_TYPE,\n redirect_uri: this.config.redirectUri,\n };\n\n const res = await ky(TOKEN_ENDPOINT, {\n method: 'POST',\n json: tokenRequest,\n });\n\n return res.json<TokenResponse>();\n }\n\n /**\n * Verifies a JWT payload from BigCommerce\n * @param jwtPayload - The JWT string to verify\n * @returns Promise resolving to the verified JWT claims\n * @throws {Error} If the JWT is invalid\n */\n async verify(jwtPayload: string) {\n try {\n const secret = new TextEncoder().encode(this.config.secret);\n\n const { payload } = await jose.jwtVerify(jwtPayload, secret, {\n audience: this.config.clientId,\n issuer: ISSUER,\n subject: `stores/${this.config.storeHash}`,\n });\n\n return payload as Claims;\n } catch (error) {\n throw new Error('Invalid JWT payload', { cause: error });\n }\n }\n\n /**\n * Parses and validates a query string from BigCommerce auth callback\n * @param queryString - The query string to parse\n * @returns The parsed auth query parameters\n * @throws {Error} If required parameters are missing or scopes are invalid\n */\n private parseQueryString(queryString: string): AuthQuery {\n const params = new URLSearchParams(queryString);\n\n // Get required parameters\n const code = params.get('code');\n const scope = params.get('scope');\n const context = params.get('context');\n const account_uuid = params.get('account_uuid');\n\n // Validate required parameters\n if (!code) {\n throw new Error('No code found in query string');\n }\n\n if (!scope) {\n throw new Error('No scope found in query string');\n } else if (this.config.scopes?.length) {\n this.validateScopes(scope);\n }\n\n if (!context) {\n throw new Error('No context found in query string');\n }\n\n if (!account_uuid) {\n throw new Error('No account UUID found in query string');\n }\n\n return {\n account_uuid,\n code,\n scope,\n context,\n };\n }\n\n /**\n * Validates that the granted scopes match the expected scopes\n * @param scopes - Space-separated list of granted scopes\n * @throws {Error} If the scopes don't match the expected scopes\n */\n private validateScopes(scopes: string) {\n const scopesArray = scopes.split(' ');\n\n if (this.config.scopes?.length) {\n const int = intersection(scopesArray, this.config.scopes);\n\n if (int.length !== scopesArray.length) {\n throw new Error(`Scope mismatch: ${scopes}; expected: ${this.config.scopes.join(' ')}`);\n }\n }\n }\n}\n"],
5
- "mappings": "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",
6
- "names": ["request", "chunk", "page", "request", "ky"]
3
+ "sources": ["../src/net.ts", "../src/util.ts", "../src/client.ts", "../src/auth.ts"],
4
+ "sourcesContent": ["/**\n * Network utilities for interacting with the BigCommerce API.\n * Provides rate-limited request handling, error management, and type-safe API calls.\n */\n\nimport ky, { ResponsePromise, KyResponse, HTTPError } from 'ky';\n\n/** HTTP methods supported by the API */\nexport type Method = 'GET' | 'POST' | 'PUT' | 'DELETE';\n\nexport const Methods: Record<string, Method> = {\n GET: 'GET',\n POST: 'POST',\n PUT: 'PUT',\n DELETE: 'DELETE',\n} as const;\n\nexport const BASE_URL = 'https://api.bigcommerce.com/stores/';\n\n/** Configuration for the BigCommerce API client */\nconst CONFIG = {\n /** Base URL for BigCommerce API */\n BASE_URL,\n /** Default API version to use */\n DEFAULT_VERSION: 'v3',\n /** Maximum delay in milliseconds for rate limit retries */\n DEFAULT_MAX_DELAY: 60e3,\n /** Maximum allowed URL length */\n MAX_URL_LENGTH: 2048,\n /** Default maximum number of retries for rate-limited requests */\n DEFAULT_MAX_RETRIES: 5,\n /** Rate limit header names */\n HEADERS: {\n /** Time window for rate limiting in milliseconds */\n WINDOW: 'x-rate-limit-time-window-ms',\n /** Time to wait before retrying after rate limit in milliseconds */\n RETRY_AFTER: 'x-rate-limit-time-reset-ms',\n /** Total request quota for the time window */\n REQUEST_QUOTA: 'x-rate-limit-requests-quota',\n /** Number of requests remaining in the current window */\n REQUESTS_LEFT: 'x-rate-limit-requests-left',\n }\n} as const;\n\n/** Supported BigCommerce API versions */\nexport type ApiVersion = 'v3' | 'v2';\n\n/**\n * Options for making API requests\n * @template T - Type of the request body\n */\nexport type RequestOptions<T> = {\n /** API endpoint to call */\n endpoint: string;\n /** HTTP method to use */\n method?: Method;\n /** Request body data */\n body?: T;\n /** API version to use */\n version?: ApiVersion;\n /** Query parameters to append to the URL */\n query?: Record<string, string>;\n};\n\nexport type StoreOptions = {\n /** BigCommerce store hash */\n storeHash: string;\n /** API access token */\n accessToken: string;\n}\n\n/**\n * Options for rate limit handling\n */\nexport type RateLimitOptions = {\n /** Maximum delay in milliseconds before giving up on rate-limited requests */\n maxDelay?: number;\n /** Maximum number of retries for rate-limited requests */\n maxRetries?: number;\n};\n\n/**\n * Custom error class for API request failures\n * @template T - Type of the error data\n */\nexport class RequestError<T> extends Error {\n constructor(\n public status: number,\n public message: string,\n public data: T | string,\n public cause?: unknown,\n ) {\n super(message, { cause });\n }\n}\n\n/**\n * Makes an API request with rate limit handling\n * @template T - Type of the request body and response\n * @param options - Request options including rate limit settings\n * @returns Promise resolving to the API response\n * @throws {RequestError} If the request fails or rate limit is exceeded\n */\nexport const request = async <T, R>(options: RequestOptions<T> & RateLimitOptions & StoreOptions): Promise<R> => {\n const { maxDelay = CONFIG.DEFAULT_MAX_DELAY, maxRetries = CONFIG.DEFAULT_MAX_RETRIES } = options;\n\n let retries = 0;\n let lastError: RequestError<T> | null = null;\n\n while (retries < maxRetries) {\n try {\n return await safeRequest<T, R>(options);\n } catch (error) {\n const err = error as RequestError<T>;\n lastError = err;\n\n if (err.status === 429 && typeof err.data === 'object' && err.data !== null && 'headers' in err.data) {\n const headers = err.data.headers as Record<string, string>;\n\n const retryAfter = Number.parseInt(headers[CONFIG.HEADERS.RETRY_AFTER]);\n\n if (Number.isNaN(retryAfter)) {\n throw new RequestError(\n err.status,\n `Failed to parse retry after: ${headers[CONFIG.HEADERS.RETRY_AFTER]}, ${err.message}`,\n err.data,\n err.cause,\n );\n }\n\n if (retryAfter > maxDelay) {\n throw new RequestError(\n err.status,\n `Rate limit exceeded: ${retryAfter}ms, ${err.message}`,\n err.data,\n err.cause,\n );\n }\n\n await new Promise((resolve) => setTimeout(resolve, retryAfter));\n retries++;\n continue;\n }\n\n throw err;\n }\n }\n\n throw lastError ?? new RequestError(500, 'Failed to make request', 'Too many retries after rate limit');\n};\n\n/**\n * Makes a single API request with error handling\n * @template T - Type of the request body and response\n * @param options - Request options\n * @returns Promise resolving to the API response\n * @throws {RequestError} If the request fails\n */ \nconst safeRequest = async <T, R>(options: RequestOptions<T> & StoreOptions): Promise<R> => {\n let res: KyResponse<T>;\n\n try {\n res = await call<T, R>(options);\n } catch (error) {\n if(error instanceof RequestError) {\n throw error;\n }\n\n if(!(error instanceof HTTPError)) {\n throw error;\n }\n\n let data: unknown;\n let errorMessage = error.message;\n\n try {\n data = await error.response.text();\n try {\n data = JSON.parse(data as string);\n\n if (typeof data === 'object' && data !== null && 'message' in data) {\n errorMessage = data.message as string;\n }\n } catch {\n // If JSON parsing fails, keep the text response\n }\n } catch {\n data = 'Failed to read error response';\n }\n\n throw new RequestError(\n error?.response?.status ?? 500,\n errorMessage,\n {\n data,\n headers: Object.fromEntries(error?.response?.headers?.entries() ?? []),\n },\n error,\n );\n }\n\n const text = await res.text();\n\n\n if(res.status === 204) {\n return undefined as unknown as R;\n }\n\n try {\n return JSON.parse(text);\n } catch (error) {\n throw new RequestError(\n res.status,\n `Failed to parse response: ${text}`,\n text,\n error\n );\n }\n};\n\n/**\n * Internal function to make the actual HTTP request\n * @template T - Type of the request body and response\n * @param options - Request options\n * @returns Promise resolving to the raw response\n * @throws {RequestError} If the URL is too long or request fails\n */\nconst call = <T, R>(options: RequestOptions<T> & StoreOptions): ResponsePromise<R> => {\n const { storeHash, accessToken, endpoint, method = 'GET', body, version = CONFIG.DEFAULT_VERSION, query } = options;\n\n const url = `${CONFIG.BASE_URL}${storeHash}/${version}/${endpoint.replace(/^\\//, '')}`;\n \n // Check URL length including search params\n const searchParams = query ? new URLSearchParams(query).toString() : '';\n const fullUrl = searchParams ? `${url}?${searchParams}` : url;\n \n if (fullUrl.length > CONFIG.MAX_URL_LENGTH) {\n throw new RequestError(\n 400,\n 'URL too long',\n `URL length ${fullUrl.length} exceeds maximum allowed length of ${CONFIG.MAX_URL_LENGTH}`,\n );\n }\n\n const request = {\n method,\n headers: {\n 'Content-Type': 'application/json',\n 'Accept': 'application/json',\n 'X-Auth-Token': accessToken,\n },\n json: body,\n };\n\n return ky<R>(fullUrl, request);\n};\n", "/**\n * Split an array of strings into chunks by following logic\n *\n * 1. add length of each string + separatorSize to offset\n * 2. if result is greater than `maxLength`, start a new chunk\n * 3. otherwise, add the string to the current chunk until the chunk is of `chunkLength`\n *\n * This function to be used for splitting query params to avoid url length limit\n *\n * @param items array of strings\n * @param options\n * @param options.maxLength max length of the combined strings\n * @param options.chunkLength max length of each chunk\n * @param options.offset offset of the first chunk\n * @param options.separatorSize size of the separator\n */\nexport const chunkStrLength = (\n items: string[],\n options: {\n maxLength?: number;\n chunkLength?: number;\n offset?: number;\n separatorSize?: number;\n } = {},\n) => {\n const { maxLength = 2048, chunkLength = 250, offset = 0, separatorSize = 1 } = options;\n\n const chunks: string[][] = [];\n let currentStrLength = offset;\n let currentChunk: string[] = [];\n\n for (const item of items) {\n const itemLength = item.length + separatorSize;\n\n const newCurrentStrLength = currentStrLength + itemLength;\n // Check if adding this item would exceed maxLength\n if (newCurrentStrLength > maxLength) {\n if (currentChunk.length > 0) {\n chunks.push(currentChunk);\n currentChunk = [];\n currentStrLength = offset;\n }\n }\n\n // Check if current chunk is full\n if (currentChunk.length === chunkLength) {\n chunks.push(currentChunk);\n currentChunk = [];\n currentStrLength = offset;\n }\n\n currentChunk.push(item);\n currentStrLength += itemLength;\n }\n\n // Add the last chunk if it's not empty\n if (currentChunk.length > 0) {\n chunks.push(currentChunk);\n }\n\n return chunks;\n};\n", "import { V3Resource } from './core';\nimport { BASE_URL, RateLimitOptions, RequestError, RequestOptions, StoreOptions, request } from './net';\nimport { chunkStrLength } from './util';\n\nconst MAX_PAGE_SIZE = 250;\nconst DEFAULT_CONCURRENCY = 10;\n\n// Helper function to chunk array into smaller arrays\nfunction chunkArray<T>(array: T[], size: number): T[][] {\n return Array.from({ length: Math.ceil(array.length / size) }, (_, i) =>\n array.slice(i * size, i * size + size)\n );\n}\n\n// Helper function to create range array\nfunction rangeArray(start: number, end: number): number[] {\n return Array.from({ length: end - start + 1 }, (_, i) => start + i);\n}\n\n/**\n * Options for GET requests to the BigCommerce API\n */\nexport type GetOptions = {\n /** Query parameters to include in the request */\n query?: Record<string, string>;\n /** API version to use (v2 or v3) */\n version?: 'v2' | 'v3';\n};\n\n/**\n * Options for POST/PUT requests to the BigCommerce API\n */\nexport type PostOptions<T> = GetOptions & {\n /** Request body data */\n body: T;\n};\n\n/**\n * Options for controlling concurrent request behavior\n */\nexport type ConcurrencyOptions = {\n /** Maximum number of concurrent requests (default: 10) */\n concurrency?: number;\n /** Whether to skip errors and continue processing (default: false) */\n skipErrors?: boolean;\n};\n\n/**\n * Options for querying multiple values against a single filter field\n */\nexport type QueryOptions = Omit<GetOptions, 'version'> & ConcurrencyOptions & {\n /** The field name to query against */\n key: string;\n /** Array of values to query for */\n values: (string | number)[];\n};\n\n/**\n * Configuration options for the BigCommerce client\n */\nexport type Config = StoreOptions & RateLimitOptions & ConcurrencyOptions;\n\n/**\n * Client for interacting with the BigCommerce API\n * \n * This client provides methods for making HTTP requests to the BigCommerce API,\n * with support for both v2 and v3 endpoints, pagination, and concurrent requests.\n */\nexport class BigCommerceClient {\n /**\n * Creates a new BigCommerce client instance\n * @param config.storeHash - The store hash to use for the client\n * @param config.accessToken - The API access token to use for the client\n * @param config.maxRetries - (default: 5) The maximum number of retries for rate limit errors\n * @param config.maxDelay - (default: 60e3 - 1 minute) Maximum time to wait to retry in case of rate limit errors. If `X-Rate-Limit-Time-Reset-Ms` header is higher than `maxDelay`, the request will fail immediately.\n * @param config.concurrency - (default: 10) The default concurrency for concurrent methods\n * @param config.skipErrors - (default: false) Whether to skip errors during concurrent requests\n */\n constructor(private readonly config: Config) {}\n\n /**\n * Makes a GET request to the BigCommerce API\n * @param endpoint - The API endpoint to request\n * @param options.query - Query parameters to include in the request\n * @param options.version - API version to use (v2 or v3) (default: v3)\n * @returns Promise resolving to the response data of type `R`\n */\n async get<R>(endpoint: string, options?: GetOptions): Promise<R> {\n return request<never, R>({\n endpoint,\n method: 'GET',\n ...options,\n ...this.config,\n });\n }\n\n /**\n * Makes a POST request to the BigCommerce API\n * @param endpoint - The API endpoint to request\n * @param options.query - Query parameters to include in the request\n * @param options.version - API version to use (v2 or v3) (default: v3)\n * @param options.body - Request body data of type `T`\n * @returns Promise resolving to the response data of type `R`\n */\n async post<T, R>(endpoint: string, options?: PostOptions<T>): Promise<R> {\n return request<T, R>({\n endpoint,\n method: 'POST',\n ...options,\n ...this.config,\n });\n }\n\n /**\n * Makes a PUT request to the BigCommerce API\n * @param endpoint - The API endpoint to request\n * @param options.query - Query parameters to include in the request\n * @param options.version - API version to use (v2 or v3) (default: v3)\n * @param options.body - Request body data of type `T`\n * @returns Promise resolving to the response data of type `R`\n */\n async put<T, R>(endpoint: string, options?: PostOptions<T>): Promise<R> {\n return request<T, R>({\n endpoint,\n method: 'PUT',\n ...options,\n ...this.config,\n });\n }\n\n /**\n * Makes a DELETE request to the BigCommerce API\n * @param endpoint - The API endpoint to delete\n * @param options.version - API version to use (v2 or v3) (default: v3)\n * @returns Promise resolving to void\n */\n async delete<R>(endpoint: string, options?: Pick<GetOptions, 'version'>): Promise<void> {\n await request<never, R>({\n endpoint,\n method: 'DELETE',\n ...options,\n ...this.config,\n });\n }\n\n /**\n * Executes multiple requests concurrently with controlled concurrency\n * @param requests - Array of request options to execute\n * @param options.concurrency - Maximum number of concurrent requests, overrides the client's concurrency setting (default: 10)\n * @param options.skipErrors - Whether to skip errors and continue processing, overrides the client's skipErrors setting (default: false)\n * @returns Promise resolving to array of response data\n */\n async concurrent<T, R>(requests: RequestOptions<T>[], options?: ConcurrencyOptions): Promise<R[]> {\n const chunks = chunkArray(requests, options?.concurrency ?? this.config.concurrency ?? DEFAULT_CONCURRENCY);\n const skipErrors = options?.skipErrors ?? this.config.skipErrors ?? false;\n\n const results: R[] = [];\n\n for (const chunk of chunks) {\n const responses = await Promise.allSettled(\n chunk.map((opt) =>\n request<T, R>({\n ...opt,\n ...this.config,\n }),\n ),\n );\n\n responses.forEach((response) => {\n if (response.status === 'fulfilled') {\n results.push(response.value);\n } else {\n if (!skipErrors) {\n throw response.reason;\n } else {\n console.warn(`Error in concurrent request: ${response.reason}`);\n }\n }\n });\n }\n\n return results;\n }\n\n /**\n * Collects all pages of data from a paginated v3 API endpoint.\n * This method pulls the first page and uses pagination meta to collect the remaining pages concurrently.\n * @param endpoint - The API endpoint to request\n * @param options.query - Query parameters to include in the request\n * @param options.concurrency - Maximum number of concurrent requests, overrides the client's concurrency setting (default: 10)\n * @param options.skipErrors - Whether to skip errors and continue processing, overrides the client's skipErrors setting (default: false)\n * @returns Promise resolving to array of all items across all pages\n */\n async collect<T>(endpoint: string, options: Omit<GetOptions, 'version'> & ConcurrencyOptions): Promise<T[]> {\n if (options.query) {\n if (!options.query.limit) {\n options.query.limit = MAX_PAGE_SIZE.toString();\n }\n } else {\n options.query = { limit: MAX_PAGE_SIZE.toString() };\n }\n\n const first = await this.get<V3Resource<T[]>>(endpoint, options);\n\n if (!Array.isArray(first.data) || !first?.meta?.pagination?.total_pages) {\n return first.data;\n }\n\n const results: T[] = [...first.data];\n const pages = first.meta.pagination.total_pages;\n\n if (pages > 1) {\n const pageRequests = rangeArray(2, pages).map((page) => ({\n endpoint,\n method: 'GET' as const,\n query: {\n ...options.query,\n page: page.toString(),\n },\n }));\n\n const remainingPages = await this.concurrent<never, V3Resource<T[]>>(pageRequests, options);\n\n remainingPages.forEach((page) => {\n if (Array.isArray(page.data)) {\n results.push(...page.data);\n }\n });\n }\n\n return results;\n }\n\n /**\n * Collects all pages of data from a paginated v2 API endpoint.\n * This method simply pulls all pages concurrently until a 204 is returned in a batch.\n * @param endpoint - The API endpoint to request\n * @param options.query - Query parameters to include in the request\n * @param options.concurrency - Maximum number of concurrent requests, overrides the client's concurrency setting (default: 10)\n * @param options.skipErrors - Whether to skip errors and continue processing, overrides the client's skipErrors setting (default: false)\n * @returns Promise resolving to array of all items across all pages\n */\n async collectV2<T>(endpoint: string, options: Omit<GetOptions, 'version'> & ConcurrencyOptions): Promise<T[]> {\n if (options.query) {\n if (!options.query.limit) {\n options.query.limit = MAX_PAGE_SIZE.toString();\n }\n } else {\n options.query = { limit: MAX_PAGE_SIZE.toString() };\n }\n\n let done = false;\n const results: T[] = [];\n let page = 1;\n const concurrency = options.concurrency ?? this.config.concurrency ?? DEFAULT_CONCURRENCY;\n\n while (!done) {\n const pages = rangeArray(page, page + concurrency);\n page += concurrency;\n\n const requests = pages.map((page) => ({\n ...options,\n endpoint,\n version: 'v2' as const,\n query: { ...options.query, page: page.toString() },\n }));\n\n const responses = await Promise.allSettled(requests.map((request) => this.get<T[]>(endpoint, request)));\n\n responses.forEach((response) => {\n if (response.status === 'fulfilled') {\n if (response.value) {\n results.push(...response.value);\n } else {\n done = true;\n }\n } else {\n if (response.reason instanceof RequestError && response.reason.status === 404) {\n done = true;\n } else {\n if (!(options.skipErrors ?? this.config.skipErrors ?? false)) {\n throw response.reason;\n } else {\n console.warn(`Error in collectV2: ${response.reason}`);\n }\n }\n }\n });\n }\n\n return results;\n }\n\n /**\n * Queries multiple values against a single field using the v3 API. \n * If the url + query params are too long, the query will be chunked. Otherwise, this method acts like `collect`.\n * This method does not check for uniqueness of the `values` array.\n * \n * @param endpoint - The API endpoint to request\n * @param options.key - The field name to query against e.g. `sku:in`\n * @param options.values - Array of values to query for e.g. `['123', '456', ...]`\n * @param options.query - Additional query parameters\n * @param options.concurrency - Maximum number of concurrent requests, overrides the client's concurrency setting (default: 10)\n * @param options.skipErrors - Whether to skip errors and continue processing, overrides the client's skipErrors setting (default: false)\n * @returns Promise resolving to array of matching items\n */\n async query<T>(endpoint: string, options: QueryOptions): Promise<T[]> {\n if(options.query) {\n if(!options.query.limit) {\n options.query.limit = MAX_PAGE_SIZE.toString();\n }\n } else {\n options.query = { limit: MAX_PAGE_SIZE.toString() };\n }\n\n const {limit:_, ...restQuery} = options.query;\n // Only needed to calculate the offset for chunking\n const fullUrl = `${BASE_URL}${this.config.storeHash}/v3/${endpoint}?${new URLSearchParams(restQuery).toString()}`;\n\n const queryStr = options.values.map((value) => `${value}`)\n const chunks = chunkStrLength(queryStr, {\n offset: fullUrl.length,\n chunkLength: Number.parseInt(options.query?.limit) || MAX_PAGE_SIZE,\n });\n\n const requests = chunks.map((chunk) => ({\n ...options,\n endpoint,\n query: { ...options.query, [options.key]: chunk.join(',') },\n }));\n\n const responses = await this.concurrent<never, V3Resource<T[]>>(requests, options);\n\n return responses.flatMap((response) => response.data);\n }\n}\n", "import ky from 'ky';\nimport * as jose from 'jose';\n\n/**\n * Configuration options for BigCommerce authentication\n */\ntype Config = {\n /** The OAuth client ID from BigCommerce */\n clientId: string;\n /** The OAuth client secret from BigCommerce */\n secret: string;\n /** The redirect URI registered with BigCommerce */\n redirectUri: string;\n /** The store hash for the BigCommerce store */\n storeHash: string;\n /** Optional array of scopes to validate during auth callback */\n scopes?: string[];\n};\n\nconst GRANT_TYPE = 'authorization_code';\nconst TOKEN_ENDPOINT = 'https://login.bigcommerce.com/oauth2/token';\nconst ISSUER = 'bc';\n\n/**\n * Query parameters received from BigCommerce auth callback\n */\ntype AuthQuery = {\n /** The BigCommerce account UUID */\n account_uuid: string;\n /** The authorization code from BigCommerce */\n code: string;\n /** The granted OAuth scopes */\n scope: string;\n /** The store context */\n context: string;\n};\n\n/**\n * Request payload for token endpoint\n */\ntype TokenRequest = {\n client_id: string;\n client_secret: string;\n code: string;\n context: string;\n scope: string;\n grant_type: typeof GRANT_TYPE;\n redirect_uri: string;\n};\n\n/**\n * User information returned from BigCommerce\n */\nexport type User = {\n /** The user's ID */\n id: number;\n /** The user's username */\n username: string;\n /** The user's email address */\n email: string;\n};\n\n/**\n * Response from BigCommerce token endpoint\n */\nexport type TokenResponse = {\n /** The OAuth access token */\n access_token: string;\n /** The granted OAuth scopes */\n scope: string;\n /** Information about the authenticated user */\n user: User;\n /** Information about the store owner */\n owner: User;\n /** The store context */\n context: string;\n /** The BigCommerce account UUID */\n account_uuid: string;\n};\n\n/**\n * JWT claims from BigCommerce\n */\nexport type Claims = {\n /** JWT audience */\n aud: string;\n /** JWT issuer */\n iss: string;\n /** JWT issued at timestamp */\n iat: number;\n /** JWT not before timestamp */\n nbf: number;\n /** JWT expiration timestamp */\n exp: number;\n /** JWT unique identifier */\n jti: string;\n /** JWT subject */\n sub: string;\n /** Information about the authenticated user */\n user: {\n id: number;\n email: string;\n locale: string;\n };\n /** Information about the store owner */\n owner: {\n id: number;\n email: string;\n };\n /** The store URL */\n url: string;\n /** The channel ID (if applicable) */\n channel_id: number | null;\n}\n\n/**\n * Handles authentication with BigCommerce OAuth\n */\nexport class BigCommerceAuth {\n /**\n * Creates a new BigCommerceAuth instance\n * @param config - Configuration options for BigCommerce authentication\n * @throws {Error} If the redirect URI is invalid\n */\n constructor(private readonly config: Config) {\n try {\n new URL(this.config.redirectUri);\n } catch (error) {\n throw new Error('Invalid redirect URI', { cause: error });\n }\n }\n\n /**\n * Requests an access token from BigCommerce\n * @param data - Either a query string or AuthQuery object containing auth callback data\n * @returns Promise resolving to the token response\n */\n async requestToken(data: string | AuthQuery) {\n const query = typeof data === 'string' ? this.parseQueryString(data) : data;\n\n const tokenRequest: TokenRequest = {\n client_id: this.config.clientId,\n client_secret: this.config.secret,\n ...query,\n grant_type: GRANT_TYPE,\n redirect_uri: this.config.redirectUri,\n };\n\n const res = await ky(TOKEN_ENDPOINT, {\n method: 'POST',\n json: tokenRequest,\n });\n\n return res.json<TokenResponse>();\n }\n\n /**\n * Verifies a JWT payload from BigCommerce\n * @param jwtPayload - The JWT string to verify\n * @returns Promise resolving to the verified JWT claims\n * @throws {Error} If the JWT is invalid\n */\n async verify(jwtPayload: string) {\n try {\n const secret = new TextEncoder().encode(this.config.secret);\n\n const { payload } = await jose.jwtVerify(jwtPayload, secret, {\n audience: this.config.clientId,\n issuer: ISSUER,\n subject: `stores/${this.config.storeHash}`,\n });\n\n return payload as Claims;\n } catch (error) {\n throw new Error('Invalid JWT payload', { cause: error });\n }\n }\n\n /**\n * Parses and validates a query string from BigCommerce auth callback\n * @param queryString - The query string to parse\n * @returns The parsed auth query parameters\n * @throws {Error} If required parameters are missing or scopes are invalid\n */\n private parseQueryString(queryString: string): AuthQuery {\n const params = new URLSearchParams(queryString);\n\n // Get required parameters\n const code = params.get('code');\n const scope = params.get('scope');\n const context = params.get('context');\n const account_uuid = params.get('account_uuid');\n\n // Validate required parameters\n if (!code) {\n throw new Error('No code found in query string');\n }\n\n if (!scope) {\n throw new Error('No scope found in query string');\n } else if (this.config.scopes?.length) {\n this.validateScopes(scope);\n }\n\n if (!context) {\n throw new Error('No context found in query string');\n }\n\n if (!account_uuid) {\n throw new Error('No account UUID found in query string');\n }\n\n return {\n account_uuid,\n code,\n scope,\n context,\n };\n }\n\n /**\n * Validates that the granted scopes match the expected scopes\n * @param scopes - Space-separated list of granted scopes\n * @throws {Error} If the scopes don't match the expected scopes\n */\n private validateScopes(scopes: string) {\n if (!this.config.scopes) {\n return;\n }\n\n const grantedScopes = scopes.split(' ');\n const requiredScopes = this.config.scopes;\n const missingScopes = requiredScopes.filter(scope => !grantedScopes.includes(scope));\n\n if (missingScopes.length) {\n throw new Error(`Scope mismatch: ${scopes}; expected: ${this.config.scopes.join(' ')}`);\n }\n }\n}\n"],
5
+ "mappings": ";AAKA,OAAO,MAAmC,iBAAiB;AAKpD,IAAM,UAAkC;AAAA,EAC3C,KAAK;AAAA,EACL,MAAM;AAAA,EACN,KAAK;AAAA,EACL,QAAQ;AACZ;AAEO,IAAM,WAAW;AAGxB,IAAM,SAAS;AAAA;AAAA,EAEX;AAAA;AAAA,EAEA,iBAAiB;AAAA;AAAA,EAEjB,mBAAmB;AAAA;AAAA,EAEnB,gBAAgB;AAAA;AAAA,EAEhB,qBAAqB;AAAA;AAAA,EAErB,SAAS;AAAA;AAAA,IAEL,QAAQ;AAAA;AAAA,IAER,aAAa;AAAA;AAAA,IAEb,eAAe;AAAA;AAAA,IAEf,eAAe;AAAA,EACnB;AACJ;AA2CO,IAAM,eAAN,cAA8B,MAAM;AAAA,EACvC,YACW,QACA,SACA,MACA,OACT;AACE,UAAM,SAAS,EAAE,MAAM,CAAC;AALjB;AACA;AACA;AACA;AAAA,EAGX;AACJ;AASO,IAAM,UAAU,OAAa,YAA6E;AAC7G,QAAM,EAAE,WAAW,OAAO,mBAAmB,aAAa,OAAO,oBAAoB,IAAI;AAEzF,MAAI,UAAU;AACd,MAAI,YAAoC;AAExC,SAAO,UAAU,YAAY;AACzB,QAAI;AACA,aAAO,MAAM,YAAkB,OAAO;AAAA,IAC1C,SAAS,OAAO;AACZ,YAAM,MAAM;AACZ,kBAAY;AAEZ,UAAI,IAAI,WAAW,OAAO,OAAO,IAAI,SAAS,YAAY,IAAI,SAAS,QAAQ,aAAa,IAAI,MAAM;AAClG,cAAM,UAAU,IAAI,KAAK;AAEzB,cAAM,aAAa,OAAO,SAAS,QAAQ,OAAO,QAAQ,WAAW,CAAC;AAEtE,YAAI,OAAO,MAAM,UAAU,GAAG;AAC1B,gBAAM,IAAI;AAAA,YACN,IAAI;AAAA,YACJ,gCAAgC,QAAQ,OAAO,QAAQ,WAAW,CAAC,KAAK,IAAI,OAAO;AAAA,YACnF,IAAI;AAAA,YACJ,IAAI;AAAA,UACR;AAAA,QACJ;AAEA,YAAI,aAAa,UAAU;AACvB,gBAAM,IAAI;AAAA,YACN,IAAI;AAAA,YACJ,wBAAwB,UAAU,OAAO,IAAI,OAAO;AAAA,YACpD,IAAI;AAAA,YACJ,IAAI;AAAA,UACR;AAAA,QACJ;AAEA,cAAM,IAAI,QAAQ,CAAC,YAAY,WAAW,SAAS,UAAU,CAAC;AAC9D;AACA;AAAA,MACJ;AAEA,YAAM;AAAA,IACV;AAAA,EACJ;AAEA,QAAM,aAAa,IAAI,aAAa,KAAK,0BAA0B,mCAAmC;AAC1G;AASA,IAAM,cAAc,OAAa,YAA0D;AACvF,MAAI;AAEJ,MAAI;AACA,UAAM,MAAM,KAAW,OAAO;AAAA,EAClC,SAAS,OAAO;AACZ,QAAG,iBAAiB,cAAc;AAC9B,YAAM;AAAA,IACV;AAEA,QAAG,EAAE,iBAAiB,YAAY;AAC9B,YAAM;AAAA,IACV;AAEA,QAAI;AACJ,QAAI,eAAe,MAAM;AAEzB,QAAI;AACA,aAAO,MAAM,MAAM,SAAS,KAAK;AACjC,UAAI;AACA,eAAO,KAAK,MAAM,IAAc;AAEhC,YAAI,OAAO,SAAS,YAAY,SAAS,QAAQ,aAAa,MAAM;AAChE,yBAAe,KAAK;AAAA,QACxB;AAAA,MACJ,QAAQ;AAAA,MAER;AAAA,IACJ,QAAQ;AACJ,aAAO;AAAA,IACX;AAEA,UAAM,IAAI;AAAA,MACN,OAAO,UAAU,UAAU;AAAA,MAC3B;AAAA,MACA;AAAA,QACI;AAAA,QACA,SAAS,OAAO,YAAY,OAAO,UAAU,SAAS,QAAQ,KAAK,CAAC,CAAC;AAAA,MACzE;AAAA,MACA;AAAA,IACJ;AAAA,EACJ;AAEA,QAAM,OAAO,MAAM,IAAI,KAAK;AAG5B,MAAG,IAAI,WAAW,KAAK;AACnB,WAAO;AAAA,EACX;AAEA,MAAI;AACA,WAAO,KAAK,MAAM,IAAI;AAAA,EAC1B,SAAS,OAAO;AACZ,UAAM,IAAI;AAAA,MACN,IAAI;AAAA,MACJ,6BAA6B,IAAI;AAAA,MACjC;AAAA,MACA;AAAA,IACJ;AAAA,EACJ;AACJ;AASA,IAAM,OAAO,CAAO,YAAkE;AAClF,QAAM,EAAE,WAAW,aAAa,UAAU,SAAS,OAAO,MAAM,UAAU,OAAO,iBAAiB,MAAM,IAAI;AAE5G,QAAM,MAAM,GAAG,OAAO,QAAQ,GAAG,SAAS,IAAI,OAAO,IAAI,SAAS,QAAQ,OAAO,EAAE,CAAC;AAGpF,QAAM,eAAe,QAAQ,IAAI,gBAAgB,KAAK,EAAE,SAAS,IAAI;AACrE,QAAM,UAAU,eAAe,GAAG,GAAG,IAAI,YAAY,KAAK;AAE1D,MAAI,QAAQ,SAAS,OAAO,gBAAgB;AACxC,UAAM,IAAI;AAAA,MACN;AAAA,MACA;AAAA,MACA,cAAc,QAAQ,MAAM,sCAAsC,OAAO,cAAc;AAAA,IAC3F;AAAA,EACJ;AAEA,QAAMA,WAAU;AAAA,IACZ;AAAA,IACA,SAAS;AAAA,MACL,gBAAgB;AAAA,MAChB,UAAU;AAAA,MACV,gBAAgB;AAAA,IACpB;AAAA,IACA,MAAM;AAAA,EACV;AAEA,SAAO,GAAM,SAASA,QAAO;AACjC;;;AC/OO,IAAM,iBAAiB,CAC1B,OACA,UAKI,CAAC,MACJ;AACD,QAAM,EAAE,YAAY,MAAM,cAAc,KAAK,SAAS,GAAG,gBAAgB,EAAE,IAAI;AAE/E,QAAM,SAAqB,CAAC;AAC5B,MAAI,mBAAmB;AACvB,MAAI,eAAyB,CAAC;AAE9B,aAAW,QAAQ,OAAO;AACtB,UAAM,aAAa,KAAK,SAAS;AAEjC,UAAM,sBAAsB,mBAAmB;AAE/C,QAAI,sBAAsB,WAAW;AACjC,UAAI,aAAa,SAAS,GAAG;AACzB,eAAO,KAAK,YAAY;AACxB,uBAAe,CAAC;AAChB,2BAAmB;AAAA,MACvB;AAAA,IACJ;AAGA,QAAI,aAAa,WAAW,aAAa;AACrC,aAAO,KAAK,YAAY;AACxB,qBAAe,CAAC;AAChB,yBAAmB;AAAA,IACvB;AAEA,iBAAa,KAAK,IAAI;AACtB,wBAAoB;AAAA,EACxB;AAGA,MAAI,aAAa,SAAS,GAAG;AACzB,WAAO,KAAK,YAAY;AAAA,EAC5B;AAEA,SAAO;AACX;;;ACzDA,IAAM,gBAAgB;AACtB,IAAM,sBAAsB;AAG5B,SAAS,WAAc,OAAY,MAAqB;AACpD,SAAO,MAAM;AAAA,IAAK,EAAE,QAAQ,KAAK,KAAK,MAAM,SAAS,IAAI,EAAE;AAAA,IAAG,CAAC,GAAG,MAC9D,MAAM,MAAM,IAAI,MAAM,IAAI,OAAO,IAAI;AAAA,EACzC;AACJ;AAGA,SAAS,WAAW,OAAe,KAAuB;AACtD,SAAO,MAAM,KAAK,EAAE,QAAQ,MAAM,QAAQ,EAAE,GAAG,CAAC,GAAG,MAAM,QAAQ,CAAC;AACtE;AAmDO,IAAM,oBAAN,MAAwB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAU3B,YAA6B,QAAgB;AAAhB;AAAA,EAAiB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAS9C,MAAM,IAAO,UAAkB,SAAkC;AAC7D,WAAO,QAAkB;AAAA,MACrB;AAAA,MACA,QAAQ;AAAA,MACR,GAAG;AAAA,MACH,GAAG,KAAK;AAAA,IACZ,CAAC;AAAA,EACL;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,MAAM,KAAW,UAAkB,SAAsC;AACrE,WAAO,QAAc;AAAA,MACjB;AAAA,MACA,QAAQ;AAAA,MACR,GAAG;AAAA,MACH,GAAG,KAAK;AAAA,IACZ,CAAC;AAAA,EACL;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,MAAM,IAAU,UAAkB,SAAsC;AACpE,WAAO,QAAc;AAAA,MACjB;AAAA,MACA,QAAQ;AAAA,MACR,GAAG;AAAA,MACH,GAAG,KAAK;AAAA,IACZ,CAAC;AAAA,EACL;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,OAAU,UAAkB,SAAsD;AACpF,UAAM,QAAkB;AAAA,MACpB;AAAA,MACA,QAAQ;AAAA,MACR,GAAG;AAAA,MACH,GAAG,KAAK;AAAA,IACZ,CAAC;AAAA,EACL;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAM,WAAiB,UAA+B,SAA4C;AAC9F,UAAM,SAAS,WAAW,UAAU,SAAS,eAAe,KAAK,OAAO,eAAe,mBAAmB;AAC1G,UAAM,aAAa,SAAS,cAAc,KAAK,OAAO,cAAc;AAEpE,UAAM,UAAe,CAAC;AAEtB,eAAW,SAAS,QAAQ;AACxB,YAAM,YAAY,MAAM,QAAQ;AAAA,QAC5B,MAAM;AAAA,UAAI,CAAC,QACP,QAAc;AAAA,YACV,GAAG;AAAA,YACH,GAAG,KAAK;AAAA,UACZ,CAAC;AAAA,QACL;AAAA,MACJ;AAEA,gBAAU,QAAQ,CAAC,aAAa;AAC5B,YAAI,SAAS,WAAW,aAAa;AACjC,kBAAQ,KAAK,SAAS,KAAK;AAAA,QAC/B,OAAO;AACH,cAAI,CAAC,YAAY;AACb,kBAAM,SAAS;AAAA,UACnB,OAAO;AACH,oBAAQ,KAAK,gCAAgC,SAAS,MAAM,EAAE;AAAA,UAClE;AAAA,QACJ;AAAA,MACJ,CAAC;AAAA,IACL;AAEA,WAAO;AAAA,EACX;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,MAAM,QAAW,UAAkB,SAAyE;AACxG,QAAI,QAAQ,OAAO;AACf,UAAI,CAAC,QAAQ,MAAM,OAAO;AACtB,gBAAQ,MAAM,QAAQ,cAAc,SAAS;AAAA,MACjD;AAAA,IACJ,OAAO;AACH,cAAQ,QAAQ,EAAE,OAAO,cAAc,SAAS,EAAE;AAAA,IACtD;AAEA,UAAM,QAAQ,MAAM,KAAK,IAAqB,UAAU,OAAO;AAE/D,QAAI,CAAC,MAAM,QAAQ,MAAM,IAAI,KAAK,CAAC,OAAO,MAAM,YAAY,aAAa;AACrE,aAAO,MAAM;AAAA,IACjB;AAEA,UAAM,UAAe,CAAC,GAAG,MAAM,IAAI;AACnC,UAAM,QAAQ,MAAM,KAAK,WAAW;AAEpC,QAAI,QAAQ,GAAG;AACX,YAAM,eAAe,WAAW,GAAG,KAAK,EAAE,IAAI,CAAC,UAAU;AAAA,QACrD;AAAA,QACA,QAAQ;AAAA,QACR,OAAO;AAAA,UACH,GAAG,QAAQ;AAAA,UACX,MAAM,KAAK,SAAS;AAAA,QACxB;AAAA,MACJ,EAAE;AAEF,YAAM,iBAAiB,MAAM,KAAK,WAAmC,cAAc,OAAO;AAE1F,qBAAe,QAAQ,CAAC,SAAS;AAC7B,YAAI,MAAM,QAAQ,KAAK,IAAI,GAAG;AAC1B,kBAAQ,KAAK,GAAG,KAAK,IAAI;AAAA,QAC7B;AAAA,MACJ,CAAC;AAAA,IACL;AAEA,WAAO;AAAA,EACX;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,MAAM,UAAa,UAAkB,SAAyE;AAC1G,QAAI,QAAQ,OAAO;AACf,UAAI,CAAC,QAAQ,MAAM,OAAO;AACtB,gBAAQ,MAAM,QAAQ,cAAc,SAAS;AAAA,MACjD;AAAA,IACJ,OAAO;AACH,cAAQ,QAAQ,EAAE,OAAO,cAAc,SAAS,EAAE;AAAA,IACtD;AAEA,QAAI,OAAO;AACX,UAAM,UAAe,CAAC;AACtB,QAAI,OAAO;AACX,UAAM,cAAc,QAAQ,eAAe,KAAK,OAAO,eAAe;AAEtE,WAAO,CAAC,MAAM;AACV,YAAM,QAAQ,WAAW,MAAM,OAAO,WAAW;AACjD,cAAQ;AAER,YAAM,WAAW,MAAM,IAAI,CAACC,WAAU;AAAA,QAClC,GAAG;AAAA,QACH;AAAA,QACA,SAAS;AAAA,QACT,OAAO,EAAE,GAAG,QAAQ,OAAO,MAAMA,MAAK,SAAS,EAAE;AAAA,MACrD,EAAE;AAEF,YAAM,YAAY,MAAM,QAAQ,WAAW,SAAS,IAAI,CAACC,aAAY,KAAK,IAAS,UAAUA,QAAO,CAAC,CAAC;AAEtG,gBAAU,QAAQ,CAAC,aAAa;AAC5B,YAAI,SAAS,WAAW,aAAa;AACjC,cAAI,SAAS,OAAO;AAChB,oBAAQ,KAAK,GAAG,SAAS,KAAK;AAAA,UAClC,OAAO;AACH,mBAAO;AAAA,UACX;AAAA,QACJ,OAAO;AACH,cAAI,SAAS,kBAAkB,gBAAgB,SAAS,OAAO,WAAW,KAAK;AAC3E,mBAAO;AAAA,UACX,OAAO;AACH,gBAAI,EAAE,QAAQ,cAAc,KAAK,OAAO,cAAc,QAAQ;AAC1D,oBAAM,SAAS;AAAA,YACnB,OAAO;AACH,sBAAQ,KAAK,uBAAuB,SAAS,MAAM,EAAE;AAAA,YACzD;AAAA,UACJ;AAAA,QACJ;AAAA,MACJ,CAAC;AAAA,IACL;AAEA,WAAO;AAAA,EACX;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAeA,MAAM,MAAS,UAAkB,SAAqC;AAClE,QAAG,QAAQ,OAAO;AACd,UAAG,CAAC,QAAQ,MAAM,OAAO;AACrB,gBAAQ,MAAM,QAAQ,cAAc,SAAS;AAAA,MACjD;AAAA,IACJ,OAAO;AACH,cAAQ,QAAQ,EAAE,OAAO,cAAc,SAAS,EAAE;AAAA,IACtD;AAEA,UAAM,EAAC,OAAM,GAAG,GAAG,UAAS,IAAI,QAAQ;AAExC,UAAM,UAAU,GAAG,QAAQ,GAAG,KAAK,OAAO,SAAS,OAAO,QAAQ,IAAI,IAAI,gBAAgB,SAAS,EAAE,SAAS,CAAC;AAE/G,UAAM,WAAW,QAAQ,OAAO,IAAI,CAAC,UAAU,GAAG,KAAK,EAAE;AACzD,UAAM,SAAS,eAAe,UAAU;AAAA,MACpC,QAAQ,QAAQ;AAAA,MAChB,aAAa,OAAO,SAAS,QAAQ,OAAO,KAAK,KAAK;AAAA,IAC1D,CAAC;AAED,UAAM,WAAW,OAAO,IAAI,CAAC,WAAW;AAAA,MACpC,GAAG;AAAA,MACH;AAAA,MACA,OAAO,EAAE,GAAG,QAAQ,OAAO,CAAC,QAAQ,GAAG,GAAG,MAAM,KAAK,GAAG,EAAE;AAAA,IAC9D,EAAE;AAEF,UAAM,YAAY,MAAM,KAAK,WAAmC,UAAU,OAAO;AAEjF,WAAO,UAAU,QAAQ,CAAC,aAAa,SAAS,IAAI;AAAA,EACxD;AACJ;;;AC/UA,OAAOC,SAAQ;AACf,YAAY,UAAU;AAkBtB,IAAM,aAAa;AACnB,IAAM,iBAAiB;AACvB,IAAM,SAAS;AAiGR,IAAM,kBAAN,MAAsB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMzB,YAA6B,QAAgB;AAAhB;AACzB,QAAI;AACA,UAAI,IAAI,KAAK,OAAO,WAAW;AAAA,IACnC,SAAS,OAAO;AACZ,YAAM,IAAI,MAAM,wBAAwB,EAAE,OAAO,MAAM,CAAC;AAAA,IAC5D;AAAA,EACJ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,aAAa,MAA0B;AACzC,UAAM,QAAQ,OAAO,SAAS,WAAW,KAAK,iBAAiB,IAAI,IAAI;AAEvE,UAAM,eAA6B;AAAA,MAC/B,WAAW,KAAK,OAAO;AAAA,MACvB,eAAe,KAAK,OAAO;AAAA,MAC3B,GAAG;AAAA,MACH,YAAY;AAAA,MACZ,cAAc,KAAK,OAAO;AAAA,IAC9B;AAEA,UAAM,MAAM,MAAMA,IAAG,gBAAgB;AAAA,MACjC,QAAQ;AAAA,MACR,MAAM;AAAA,IACV,CAAC;AAED,WAAO,IAAI,KAAoB;AAAA,EACnC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,OAAO,YAAoB;AAC7B,QAAI;AACA,YAAM,SAAS,IAAI,YAAY,EAAE,OAAO,KAAK,OAAO,MAAM;AAE1D,YAAM,EAAE,QAAQ,IAAI,MAAW,eAAU,YAAY,QAAQ;AAAA,QACzD,UAAU,KAAK,OAAO;AAAA,QACtB,QAAQ;AAAA,QACR,SAAS,UAAU,KAAK,OAAO,SAAS;AAAA,MAC5C,CAAC;AAED,aAAO;AAAA,IACX,SAAS,OAAO;AACZ,YAAM,IAAI,MAAM,uBAAuB,EAAE,OAAO,MAAM,CAAC;AAAA,IAC3D;AAAA,EACJ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQQ,iBAAiB,aAAgC;AACrD,UAAM,SAAS,IAAI,gBAAgB,WAAW;AAG9C,UAAM,OAAO,OAAO,IAAI,MAAM;AAC9B,UAAM,QAAQ,OAAO,IAAI,OAAO;AAChC,UAAM,UAAU,OAAO,IAAI,SAAS;AACpC,UAAM,eAAe,OAAO,IAAI,cAAc;AAG9C,QAAI,CAAC,MAAM;AACP,YAAM,IAAI,MAAM,+BAA+B;AAAA,IACnD;AAEA,QAAI,CAAC,OAAO;AACR,YAAM,IAAI,MAAM,gCAAgC;AAAA,IACpD,WAAW,KAAK,OAAO,QAAQ,QAAQ;AACnC,WAAK,eAAe,KAAK;AAAA,IAC7B;AAEA,QAAI,CAAC,SAAS;AACV,YAAM,IAAI,MAAM,kCAAkC;AAAA,IACtD;AAEA,QAAI,CAAC,cAAc;AACf,YAAM,IAAI,MAAM,uCAAuC;AAAA,IAC3D;AAEA,WAAO;AAAA,MACH;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACJ;AAAA,EACJ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOQ,eAAe,QAAgB;AACnC,QAAI,CAAC,KAAK,OAAO,QAAQ;AACrB;AAAA,IACJ;AAEA,UAAM,gBAAgB,OAAO,MAAM,GAAG;AACtC,UAAM,iBAAiB,KAAK,OAAO;AACnC,UAAM,gBAAgB,eAAe,OAAO,WAAS,CAAC,cAAc,SAAS,KAAK,CAAC;AAEnF,QAAI,cAAc,QAAQ;AACtB,YAAM,IAAI,MAAM,mBAAmB,MAAM,eAAe,KAAK,OAAO,OAAO,KAAK,GAAG,CAAC,EAAE;AAAA,IAC1F;AAAA,EACJ;AACJ;",
6
+ "names": ["request", "page", "request", "ky"]
7
7
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bc-api-client",
3
- "version": "0.1.0-beta.5",
3
+ "version": "0.1.0-beta.7",
4
4
  "description": "A client for the BigCommerce management API and app authentication",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -54,9 +54,8 @@
54
54
  "vitest": "^3.1.2"
55
55
  },
56
56
  "dependencies": {
57
- "jose": "^6.0.11",
58
- "ky": "^1.8.1",
59
- "remeda": "^2.21.3"
57
+ "jose": "^5.2.2",
58
+ "ky": "^1.1.0"
60
59
  },
61
60
  "scripts": {
62
61
  "test": "vitest",