bc-api-client 1.0.0-beta.2 → 1.0.0-beta.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +65 -10
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +87 -32
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { HTTPError, KyRequest, Options, TimeoutError } from "ky";
|
|
2
|
+
import { LimitFunction } from "p-limit";
|
|
2
3
|
|
|
3
4
|
//#region src/lib/common.d.ts
|
|
4
5
|
type ConcurrencyOptions = {
|
|
@@ -14,6 +15,11 @@ type ConcurrencyOptions = {
|
|
|
14
15
|
* response while below the configured max. Defaults to 1.
|
|
15
16
|
*/
|
|
16
17
|
backoffRecover?: ((concurrency: number) => number) | number;
|
|
18
|
+
/**
|
|
19
|
+
* A p-limit instance to reuse across calls. When provided, `batchStream` uses it instead of
|
|
20
|
+
* creating a new one, allowing callers to observe and react to live concurrency changes.
|
|
21
|
+
*/
|
|
22
|
+
pLimit?: LimitFunction;
|
|
17
23
|
};
|
|
18
24
|
/**
|
|
19
25
|
* Configuration options for the BigCommerce client.
|
|
@@ -576,6 +582,26 @@ type Err<E> = {
|
|
|
576
582
|
err: E;
|
|
577
583
|
};
|
|
578
584
|
type Result$1<T, E> = Ok<T> | Err<E>;
|
|
585
|
+
/**
|
|
586
|
+
* A {@link Result} extended with the zero-based index of the originating request in the input
|
|
587
|
+
* array passed to {@link BigCommerceClient.batchStream} or {@link BigCommerceClient.batchSafe}.
|
|
588
|
+
*
|
|
589
|
+
* Because concurrent requests complete out of insertion order, `index` is the only reliable way
|
|
590
|
+
* to correlate a result back to its input.
|
|
591
|
+
*
|
|
592
|
+
* @example
|
|
593
|
+
* ```ts
|
|
594
|
+
* const requests = ids.map(id => req.get(`catalog/products/${id}`));
|
|
595
|
+
* for await (const { index, err, data } of client.batchStream(requests)) {
|
|
596
|
+
* const originalId = ids[index];
|
|
597
|
+
* if (err) { console.error(originalId, err); continue; }
|
|
598
|
+
* console.log(originalId, data);
|
|
599
|
+
* }
|
|
600
|
+
* ```
|
|
601
|
+
*/
|
|
602
|
+
type BatchResult<T, E> = Result$1<T, E> & {
|
|
603
|
+
index: number;
|
|
604
|
+
};
|
|
579
605
|
/**
|
|
580
606
|
* Creates a successful {@link Result}. Check `result.ok` or `result.err` before accessing `data`.
|
|
581
607
|
* @param data - The success value.
|
|
@@ -613,9 +639,8 @@ declare class BigCommerceClient {
|
|
|
613
639
|
* @param config.backoffRecover - Amount (or `(concurrency) => number` function) added to
|
|
614
640
|
* concurrency per successful response while below the configured max. Defaults to 1.
|
|
615
641
|
*
|
|
616
|
-
* @throws {@link BCCredentialsError} if `storeHash` or `accessToken` are missing
|
|
617
|
-
*
|
|
618
|
-
* @throws {@link BCClientError} if `prefixUrl` is not a valid URL.
|
|
642
|
+
* @throws {@link BCCredentialsError} if `storeHash` or `accessToken` are missing.
|
|
643
|
+
* @throws {@link BCClientError} if `prefixUrl` is not a valid URL or `concurrency` is out of range.
|
|
619
644
|
*/
|
|
620
645
|
constructor(config: ClientConfig);
|
|
621
646
|
/**
|
|
@@ -730,6 +755,10 @@ declare class BigCommerceClient {
|
|
|
730
755
|
*
|
|
731
756
|
* Collects all results into an array. Use {@link queryStream} to process items lazily.
|
|
732
757
|
*
|
|
758
|
+
* **Sorting and concurrency:** when `concurrency > 1`, chunks complete out of order so
|
|
759
|
+
* sorted output is not preserved across the full result set. Pass `concurrency: false`
|
|
760
|
+
* if sort order matters.
|
|
761
|
+
*
|
|
733
762
|
* @param path - API path relative to the store's versioned base URL.
|
|
734
763
|
* @param options - Query options including `key`, `values`, pagination params, and concurrency
|
|
735
764
|
* controls.
|
|
@@ -771,6 +800,10 @@ declare class BigCommerceClient {
|
|
|
771
800
|
*
|
|
772
801
|
* Each yielded value is a {@link Result} — check `err` before using `data`.
|
|
773
802
|
*
|
|
803
|
+
* **Sorting and concurrency:** when `concurrency > 1`, chunks complete out of order so
|
|
804
|
+
* sorted output is not preserved across the full result set. Pass `concurrency: false`
|
|
805
|
+
* if sort order matters.
|
|
806
|
+
*
|
|
774
807
|
* @param path - API path relative to the store's versioned base URL.
|
|
775
808
|
* @param options - Query options including `key`, `values`, pagination params, and concurrency
|
|
776
809
|
* controls.
|
|
@@ -799,6 +832,10 @@ declare class BigCommerceClient {
|
|
|
799
832
|
*
|
|
800
833
|
* Use {@link stream} to process items lazily without buffering the full result set.
|
|
801
834
|
*
|
|
835
|
+
* **Sorting and concurrency:** the first page is fetched sequentially; remaining pages are
|
|
836
|
+
* fetched concurrently and may complete out of order. When `concurrency > 1`, sort order
|
|
837
|
+
* is not preserved across pages. Pass `concurrency: false` if sort order matters.
|
|
838
|
+
*
|
|
802
839
|
* @param path - API path relative to the store's versioned base URL.
|
|
803
840
|
* @param options - Ky options are forwarded to page requests.
|
|
804
841
|
* @param options.query - Query parameters. `query.limit` controls page size (default 250,
|
|
@@ -839,6 +876,10 @@ declare class BigCommerceClient {
|
|
|
839
876
|
*
|
|
840
877
|
* Use {@link streamBlind} to process items lazily without buffering the full result set.
|
|
841
878
|
*
|
|
879
|
+
* **Sorting and concurrency:** pages within each batch are fetched concurrently and may
|
|
880
|
+
* complete out of order. When `concurrency > 1`, sort order is not preserved across pages.
|
|
881
|
+
* Pass `concurrency: false` if sort order matters.
|
|
882
|
+
*
|
|
842
883
|
* @param path - API path relative to the store's versioned base URL (always requests v2).
|
|
843
884
|
* @param options - Ky options are forwarded to page requests.
|
|
844
885
|
* @param options.query - Query parameters. `query.limit` controls page size (default 250,
|
|
@@ -877,6 +918,10 @@ declare class BigCommerceClient {
|
|
|
877
918
|
*
|
|
878
919
|
* Use {@link collectBlind} to buffer all results into an array (throws on any error).
|
|
879
920
|
*
|
|
921
|
+
* **Sorting and concurrency:** pages within each batch are fetched concurrently and may
|
|
922
|
+
* complete out of order. When `concurrency > 1`, sort order is not preserved across pages.
|
|
923
|
+
* Pass `concurrency: false` if sort order matters.
|
|
924
|
+
*
|
|
880
925
|
* @param path - API path relative to the store's versioned base URL (always requests v2).
|
|
881
926
|
* @param options - Ky options are forwarded to page requests.
|
|
882
927
|
* @param options.query - Query parameters. `query.limit` controls page size (default 250,
|
|
@@ -905,8 +950,11 @@ declare class BigCommerceClient {
|
|
|
905
950
|
*/
|
|
906
951
|
streamBlind<TItem = unknown, TQuery extends Query = Query>(path: string, options?: BlindOptions<TItem, TQuery>): AsyncGenerator<Result$1<TItem, BaseError>>;
|
|
907
952
|
/**
|
|
908
|
-
* Executes multiple requests concurrently and returns all results as {@link
|
|
909
|
-
* never throwing. Errors from individual requests are captured as `Err` results.
|
|
953
|
+
* Executes multiple requests concurrently and returns all results as {@link BatchResult}
|
|
954
|
+
* values, never throwing. Errors from individual requests are captured as `Err` results.
|
|
955
|
+
*
|
|
956
|
+
* Results arrive in completion order, not input order. Use the `index` field on each
|
|
957
|
+
* {@link BatchResult} to correlate a result back to its position in the `requests` array.
|
|
910
958
|
*
|
|
911
959
|
* Use {@link batchStream} to process results as they arrive rather than waiting for all.
|
|
912
960
|
*
|
|
@@ -920,9 +968,9 @@ declare class BigCommerceClient {
|
|
|
920
968
|
* @param options.backoffRecover - Amount (or function) added to concurrency per successful
|
|
921
969
|
* response. Defaults to `config.backoffRecover`, or 1 if not set on the client.
|
|
922
970
|
*
|
|
923
|
-
* @returns
|
|
971
|
+
* @returns {@link BatchResult} array in the order requests completed (not input order).
|
|
924
972
|
*/
|
|
925
|
-
batchSafe<TRes = unknown, TBody = unknown, TQuery extends Query = Query>(requests: BatchRequestOptions<TBody, TRes, TQuery>[], options?: ConcurrencyOptions): Promise<
|
|
973
|
+
batchSafe<TRes = unknown, TBody = unknown, TQuery extends Query = Query>(requests: BatchRequestOptions<TBody, TRes, TQuery>[], options?: ConcurrencyOptions): Promise<BatchResult<TRes, BaseError>[]>;
|
|
926
974
|
/**
|
|
927
975
|
* Streams all items from a v3 paginated endpoint, fetching the first page sequentially
|
|
928
976
|
* and remaining pages concurrently via {@link batchStream}.
|
|
@@ -930,6 +978,10 @@ declare class BigCommerceClient {
|
|
|
930
978
|
* Each yielded value is a {@link Result} — check `err` before using `data`. Use
|
|
931
979
|
* {@link collect} to gather all items into an array.
|
|
932
980
|
*
|
|
981
|
+
* **Sorting and concurrency:** the first page is fetched sequentially; remaining pages are
|
|
982
|
+
* fetched concurrently and may complete out of order. When `concurrency > 1`, sort order
|
|
983
|
+
* is not preserved across pages. Pass `concurrency: false` if sort order matters.
|
|
984
|
+
*
|
|
933
985
|
* @param path - API path relative to the store's versioned base URL.
|
|
934
986
|
* @param options - Ky options are forwarded to page requests.
|
|
935
987
|
* @param options.query - Query parameters. `query.limit` controls page size (default 250,
|
|
@@ -954,9 +1006,12 @@ declare class BigCommerceClient {
|
|
|
954
1006
|
stream<TItem = unknown, TQuery extends Query = Query>(path: string, options?: CollectOptions<TItem, TQuery>): AsyncGenerator<Result$1<TItem, BaseError>>;
|
|
955
1007
|
/**
|
|
956
1008
|
* Executes multiple requests with configurable concurrency, yielding each result as a
|
|
957
|
-
* {@link
|
|
1009
|
+
* {@link BatchResult} as it completes. Errors from individual requests are yielded as `Err`
|
|
958
1010
|
* results rather than thrown.
|
|
959
1011
|
*
|
|
1012
|
+
* Results arrive in completion order, not input order. Use the `index` field on each
|
|
1013
|
+
* {@link BatchResult} to correlate a result back to its position in the `requests` array.
|
|
1014
|
+
*
|
|
960
1015
|
* Automatically adjusts concurrency up/down in response to rate-limit and error responses.
|
|
961
1016
|
* Use {@link batchSafe} to collect all results into an array.
|
|
962
1017
|
*
|
|
@@ -976,7 +1031,7 @@ declare class BigCommerceClient {
|
|
|
976
1031
|
* @param options.backoffRecover - Amount (or function) added to concurrency per successful
|
|
977
1032
|
* response. Defaults to `config.backoffRecover`, or 1 if not set on the client.
|
|
978
1033
|
*/
|
|
979
|
-
batchStream<TRes = unknown, TBody = unknown, TQuery extends Query = Query>(requests: BatchRequestOptions<TBody, TRes, TQuery>[], options?: ConcurrencyOptions): AsyncGenerator<
|
|
1034
|
+
batchStream<TRes = unknown, TBody = unknown, TQuery extends Query = Query>(requests: BatchRequestOptions<TBody, TRes, TQuery>[], options?: ConcurrencyOptions): AsyncGenerator<BatchResult<TRes, BaseError>>;
|
|
980
1035
|
private validatePaginatedItem;
|
|
981
1036
|
private assertPaginatedResponse;
|
|
982
1037
|
private validatePaginationOption;
|
|
@@ -1009,5 +1064,5 @@ type V3Resource<T> = {
|
|
|
1009
1064
|
};
|
|
1010
1065
|
};
|
|
1011
1066
|
//#endregion
|
|
1012
|
-
export { type ApiVersion, BCApiError, BCAuthInvalidJwtError, BCAuthInvalidRedirectUriError, BCAuthMissingParamError, BCAuthScopeMismatchError, BCClientError, BCCredentialsError, BCPaginatedItemValidationError, BCPaginatedOptionError, BCPaginatedResponseError, BCQueryValidationError, BCRateLimitDelayTooLongError, BCRateLimitNoHeadersError, BCRequestBodyValidationError, BCResponseParseError, BCResponseValidationError, BCSchemaValidationError, BCTimeoutError, BCUrlTooLongError, BaseError, type BatchRequestOptions, BigCommerceAuth, BigCommerceAuthConfig, BigCommerceAuthQuery, BigCommerceClient, Claims, type ClientConfig, type CollectOptions, type ConcurrencyOptions, type CountedCollectOptions, type DeleteOptions, Err, ErrorContext, FallbackLogger, type GetOptions, type HttpMethod, type LogLevel, type Logger, Ok, Pagination, type PostOptions, type PowertoolsLikeLogger, type PutOptions, type Query, type QueryOptions, type QueryValue, type RequestOptions, Result$1 as Result, type StandardSchemaV1, TokenResponse, User, V3Resource, fromAwsPowertoolsLogger, req };
|
|
1067
|
+
export { type ApiVersion, BCApiError, BCAuthInvalidJwtError, BCAuthInvalidRedirectUriError, BCAuthMissingParamError, BCAuthScopeMismatchError, BCClientError, BCCredentialsError, BCPaginatedItemValidationError, BCPaginatedOptionError, BCPaginatedResponseError, BCQueryValidationError, BCRateLimitDelayTooLongError, BCRateLimitNoHeadersError, BCRequestBodyValidationError, BCResponseParseError, BCResponseValidationError, BCSchemaValidationError, BCTimeoutError, BCUrlTooLongError, BaseError, type BatchRequestOptions, BatchResult, BigCommerceAuth, BigCommerceAuthConfig, BigCommerceAuthQuery, BigCommerceClient, Claims, type ClientConfig, type CollectOptions, type ConcurrencyOptions, type CountedCollectOptions, type DeleteOptions, Err, ErrorContext, FallbackLogger, type GetOptions, type HttpMethod, type LogLevel, type Logger, Ok, Pagination, type PostOptions, type PowertoolsLikeLogger, type PutOptions, type Query, type QueryOptions, type QueryValue, type RequestOptions, Result$1 as Result, type StandardSchemaV1, TokenResponse, User, V3Resource, fromAwsPowertoolsLogger, req };
|
|
1013
1068
|
//# sourceMappingURL=index.d.mts.map
|
package/dist/index.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/lib/common.ts","../src/lib/logger.ts","../src/auth.ts","../src/lib/standard-schema.ts","../src/lib/request.ts","../src/lib/errors.ts","../src/lib/result.ts","../src/client.ts","../src/lib/pagination.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/lib/common.ts","../src/lib/logger.ts","../src/auth.ts","../src/lib/standard-schema.ts","../src/lib/request.ts","../src/lib/errors.ts","../src/lib/result.ts","../src/client.ts","../src/lib/pagination.ts"],"mappings":"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"}
|
package/dist/index.mjs
CHANGED
|
@@ -673,9 +673,8 @@ var BigCommerceClient = class {
|
|
|
673
673
|
* @param config.backoffRecover - Amount (or `(concurrency) => number` function) added to
|
|
674
674
|
* concurrency per successful response while below the configured max. Defaults to 1.
|
|
675
675
|
*
|
|
676
|
-
* @throws {@link BCCredentialsError} if `storeHash` or `accessToken` are missing
|
|
677
|
-
*
|
|
678
|
-
* @throws {@link BCClientError} if `prefixUrl` is not a valid URL.
|
|
676
|
+
* @throws {@link BCCredentialsError} if `storeHash` or `accessToken` are missing.
|
|
677
|
+
* @throws {@link BCClientError} if `prefixUrl` is not a valid URL or `concurrency` is out of range.
|
|
679
678
|
*/
|
|
680
679
|
constructor(config) {
|
|
681
680
|
this.config = config;
|
|
@@ -846,6 +845,10 @@ var BigCommerceClient = class {
|
|
|
846
845
|
*
|
|
847
846
|
* Collects all results into an array. Use {@link queryStream} to process items lazily.
|
|
848
847
|
*
|
|
848
|
+
* **Sorting and concurrency:** when `concurrency > 1`, chunks complete out of order so
|
|
849
|
+
* sorted output is not preserved across the full result set. Pass `concurrency: false`
|
|
850
|
+
* if sort order matters.
|
|
851
|
+
*
|
|
849
852
|
* @param path - API path relative to the store's versioned base URL.
|
|
850
853
|
* @param options - Query options including `key`, `values`, pagination params, and concurrency
|
|
851
854
|
* controls.
|
|
@@ -892,6 +895,10 @@ var BigCommerceClient = class {
|
|
|
892
895
|
*
|
|
893
896
|
* Each yielded value is a {@link Result} — check `err` before using `data`.
|
|
894
897
|
*
|
|
898
|
+
* **Sorting and concurrency:** when `concurrency > 1`, chunks complete out of order so
|
|
899
|
+
* sorted output is not preserved across the full result set. Pass `concurrency: false`
|
|
900
|
+
* if sort order matters.
|
|
901
|
+
*
|
|
895
902
|
* @param path - API path relative to the store's versioned base URL.
|
|
896
903
|
* @param options - Query options including `key`, `values`, pagination params, and concurrency
|
|
897
904
|
* controls.
|
|
@@ -915,7 +922,7 @@ var BigCommerceClient = class {
|
|
|
915
922
|
* @throws {@link BCQueryValidationError} if `querySchema` validation fails.
|
|
916
923
|
*/
|
|
917
924
|
async *queryStream(path, options) {
|
|
918
|
-
const { key, values, query, querySchema, itemSchema, ...requestOptions } = options;
|
|
925
|
+
const { key, values, query, querySchema, itemSchema, concurrency, rateLimitBackoff, backoff, backoffRecover, ...requestOptions } = options;
|
|
919
926
|
const limit = this.validatePaginationOption(path, "limit", query?.limit ?? 250);
|
|
920
927
|
const newQuery = {
|
|
921
928
|
...await this.validate(query, querySchema, BCQueryValidationError, "GET", path, "Invalid query parameters"),
|
|
@@ -943,7 +950,12 @@ var BigCommerceClient = class {
|
|
|
943
950
|
[key]: chunk
|
|
944
951
|
}
|
|
945
952
|
}));
|
|
946
|
-
for await (const { err, data } of this.batchStream(requests,
|
|
953
|
+
for await (const { err, data } of this.batchStream(requests, {
|
|
954
|
+
concurrency,
|
|
955
|
+
rateLimitBackoff,
|
|
956
|
+
backoff,
|
|
957
|
+
backoffRecover
|
|
958
|
+
})) {
|
|
947
959
|
if (err) {
|
|
948
960
|
yield Err(err);
|
|
949
961
|
continue;
|
|
@@ -962,6 +974,10 @@ var BigCommerceClient = class {
|
|
|
962
974
|
*
|
|
963
975
|
* Use {@link stream} to process items lazily without buffering the full result set.
|
|
964
976
|
*
|
|
977
|
+
* **Sorting and concurrency:** the first page is fetched sequentially; remaining pages are
|
|
978
|
+
* fetched concurrently and may complete out of order. When `concurrency > 1`, sort order
|
|
979
|
+
* is not preserved across pages. Pass `concurrency: false` if sort order matters.
|
|
980
|
+
*
|
|
965
981
|
* @param path - API path relative to the store's versioned base URL.
|
|
966
982
|
* @param options - Ky options are forwarded to page requests.
|
|
967
983
|
* @param options.query - Query parameters. `query.limit` controls page size (default 250,
|
|
@@ -1007,6 +1023,10 @@ var BigCommerceClient = class {
|
|
|
1007
1023
|
*
|
|
1008
1024
|
* Use {@link streamBlind} to process items lazily without buffering the full result set.
|
|
1009
1025
|
*
|
|
1026
|
+
* **Sorting and concurrency:** pages within each batch are fetched concurrently and may
|
|
1027
|
+
* complete out of order. When `concurrency > 1`, sort order is not preserved across pages.
|
|
1028
|
+
* Pass `concurrency: false` if sort order matters.
|
|
1029
|
+
*
|
|
1010
1030
|
* @param path - API path relative to the store's versioned base URL (always requests v2).
|
|
1011
1031
|
* @param options - Ky options are forwarded to page requests.
|
|
1012
1032
|
* @param options.query - Query parameters. `query.limit` controls page size (default 250,
|
|
@@ -1050,6 +1070,10 @@ var BigCommerceClient = class {
|
|
|
1050
1070
|
*
|
|
1051
1071
|
* Use {@link collectBlind} to buffer all results into an array (throws on any error).
|
|
1052
1072
|
*
|
|
1073
|
+
* **Sorting and concurrency:** pages within each batch are fetched concurrently and may
|
|
1074
|
+
* complete out of order. When `concurrency > 1`, sort order is not preserved across pages.
|
|
1075
|
+
* Pass `concurrency: false` if sort order matters.
|
|
1076
|
+
*
|
|
1053
1077
|
* @param path - API path relative to the store's versioned base URL (always requests v2).
|
|
1054
1078
|
* @param options - Ky options are forwarded to page requests.
|
|
1055
1079
|
* @param options.query - Query parameters. `query.limit` controls page size (default 250,
|
|
@@ -1077,14 +1101,19 @@ var BigCommerceClient = class {
|
|
|
1077
1101
|
* @yields `Err(error)` for non-terminating page errors (e.g. non-404/204 HTTP errors).
|
|
1078
1102
|
*/
|
|
1079
1103
|
async *streamBlind(path, options) {
|
|
1080
|
-
const { query: rawQuery, querySchema, itemSchema, maxPages: rawMaxPages, concurrency: rawConcurrency, rateLimitBackoff, backoff, backoffRecover, ...requestOptions } = options ?? {};
|
|
1104
|
+
const { query: rawQuery, querySchema, itemSchema, maxPages: rawMaxPages, concurrency: rawConcurrency, rateLimitBackoff, backoff, backoffRecover, pLimit: rawPLimit, ...requestOptions } = options ?? {};
|
|
1105
|
+
const concurrency = this.validateConcurrency(rawConcurrency ?? this.config.concurrency ?? 10);
|
|
1106
|
+
const limiter = rawPLimit ?? (concurrency ? pLimit({
|
|
1107
|
+
concurrency,
|
|
1108
|
+
rejectOnClear: true
|
|
1109
|
+
}) : void 0);
|
|
1081
1110
|
const concurrencyOptions = {
|
|
1082
1111
|
concurrency: rawConcurrency,
|
|
1083
1112
|
rateLimitBackoff,
|
|
1084
1113
|
backoff,
|
|
1085
|
-
backoffRecover
|
|
1114
|
+
backoffRecover,
|
|
1115
|
+
pLimit: limiter
|
|
1086
1116
|
};
|
|
1087
|
-
const concurrency = this.validateConcurrency(this.config.concurrency ?? rawConcurrency ?? 10);
|
|
1088
1117
|
const query = await this.validate(rawQuery, querySchema, BCQueryValidationError, "GET", path);
|
|
1089
1118
|
const page = this.validatePaginationOption(path, "page", query?.page ?? 1);
|
|
1090
1119
|
const limit = this.validatePaginationOption(path, "limit", query?.limit ?? 250);
|
|
@@ -1096,7 +1125,7 @@ var BigCommerceClient = class {
|
|
|
1096
1125
|
this.logger?.warn({ currentPage }, "Blind pagination reached maxPages before the end of the data");
|
|
1097
1126
|
break;
|
|
1098
1127
|
}
|
|
1099
|
-
const batchSize = concurrency || 1;
|
|
1128
|
+
const batchSize = (limiter?.concurrency ?? concurrency) || 1;
|
|
1100
1129
|
const pageRequests = Array.from({ length: batchSize }, (_, i) => currentPage + i).map((page) => req.get(path, {
|
|
1101
1130
|
...requestOptions,
|
|
1102
1131
|
version: "v2",
|
|
@@ -1124,8 +1153,11 @@ var BigCommerceClient = class {
|
|
|
1124
1153
|
} while (!done);
|
|
1125
1154
|
}
|
|
1126
1155
|
/**
|
|
1127
|
-
* Executes multiple requests concurrently and returns all results as {@link
|
|
1128
|
-
* never throwing. Errors from individual requests are captured as `Err` results.
|
|
1156
|
+
* Executes multiple requests concurrently and returns all results as {@link BatchResult}
|
|
1157
|
+
* values, never throwing. Errors from individual requests are captured as `Err` results.
|
|
1158
|
+
*
|
|
1159
|
+
* Results arrive in completion order, not input order. Use the `index` field on each
|
|
1160
|
+
* {@link BatchResult} to correlate a result back to its position in the `requests` array.
|
|
1129
1161
|
*
|
|
1130
1162
|
* Use {@link batchStream} to process results as they arrive rather than waiting for all.
|
|
1131
1163
|
*
|
|
@@ -1139,7 +1171,7 @@ var BigCommerceClient = class {
|
|
|
1139
1171
|
* @param options.backoffRecover - Amount (or function) added to concurrency per successful
|
|
1140
1172
|
* response. Defaults to `config.backoffRecover`, or 1 if not set on the client.
|
|
1141
1173
|
*
|
|
1142
|
-
* @returns
|
|
1174
|
+
* @returns {@link BatchResult} array in the order requests completed (not input order).
|
|
1143
1175
|
*/
|
|
1144
1176
|
async batchSafe(requests, options) {
|
|
1145
1177
|
const results = [];
|
|
@@ -1153,6 +1185,10 @@ var BigCommerceClient = class {
|
|
|
1153
1185
|
* Each yielded value is a {@link Result} — check `err` before using `data`. Use
|
|
1154
1186
|
* {@link collect} to gather all items into an array.
|
|
1155
1187
|
*
|
|
1188
|
+
* **Sorting and concurrency:** the first page is fetched sequentially; remaining pages are
|
|
1189
|
+
* fetched concurrently and may complete out of order. When `concurrency > 1`, sort order
|
|
1190
|
+
* is not preserved across pages. Pass `concurrency: false` if sort order matters.
|
|
1191
|
+
*
|
|
1156
1192
|
* @param path - API path relative to the store's versioned base URL.
|
|
1157
1193
|
* @param options - Ky options are forwarded to page requests.
|
|
1158
1194
|
* @param options.query - Query parameters. `query.limit` controls page size (default 250,
|
|
@@ -1175,7 +1211,7 @@ var BigCommerceClient = class {
|
|
|
1175
1211
|
* @throws {@link BCQueryValidationError} if `querySchema` validation fails.
|
|
1176
1212
|
*/
|
|
1177
1213
|
async *stream(path, options) {
|
|
1178
|
-
const { query, querySchema, itemSchema, ...requestOptions } = options ?? {};
|
|
1214
|
+
const { query, querySchema, itemSchema, concurrency, rateLimitBackoff, backoff, backoffRecover, ...requestOptions } = options ?? {};
|
|
1179
1215
|
let limit = this.validatePaginationOption(path, "limit", query?.limit ?? 250);
|
|
1180
1216
|
const page = this.validatePaginationOption(path, "page", query?.page ?? 1);
|
|
1181
1217
|
const validatedQuery = await this.validate(query, querySchema, BCQueryValidationError, "GET", path, "Invalid query parameters");
|
|
@@ -1215,7 +1251,12 @@ var BigCommerceClient = class {
|
|
|
1215
1251
|
page
|
|
1216
1252
|
}
|
|
1217
1253
|
}));
|
|
1218
|
-
for await (const pageRes of requests.length > 0 ? this.batchStream(requests,
|
|
1254
|
+
for await (const pageRes of requests.length > 0 ? this.batchStream(requests, {
|
|
1255
|
+
concurrency,
|
|
1256
|
+
rateLimitBackoff,
|
|
1257
|
+
backoff,
|
|
1258
|
+
backoffRecover
|
|
1259
|
+
}) : []) {
|
|
1219
1260
|
const { data: page, err } = pageRes;
|
|
1220
1261
|
if (err) {
|
|
1221
1262
|
yield Err(err);
|
|
@@ -1226,15 +1267,18 @@ var BigCommerceClient = class {
|
|
|
1226
1267
|
for (const item of data) yield this.validatePaginatedItem(path, item, itemSchema);
|
|
1227
1268
|
} catch (err) {
|
|
1228
1269
|
if (err instanceof BaseError) yield Err(err);
|
|
1229
|
-
else yield Err(new BCClientError("Unknown error
|
|
1270
|
+
else yield Err(new BCClientError("Unknown error occurred processing page", {}, { cause: err }));
|
|
1230
1271
|
}
|
|
1231
1272
|
}
|
|
1232
1273
|
}
|
|
1233
1274
|
/**
|
|
1234
1275
|
* Executes multiple requests with configurable concurrency, yielding each result as a
|
|
1235
|
-
* {@link
|
|
1276
|
+
* {@link BatchResult} as it completes. Errors from individual requests are yielded as `Err`
|
|
1236
1277
|
* results rather than thrown.
|
|
1237
1278
|
*
|
|
1279
|
+
* Results arrive in completion order, not input order. Use the `index` field on each
|
|
1280
|
+
* {@link BatchResult} to correlate a result back to its position in the `requests` array.
|
|
1281
|
+
*
|
|
1238
1282
|
* Automatically adjusts concurrency up/down in response to rate-limit and error responses.
|
|
1239
1283
|
* Use {@link batchSafe} to collect all results into an array.
|
|
1240
1284
|
*
|
|
@@ -1257,23 +1301,38 @@ var BigCommerceClient = class {
|
|
|
1257
1301
|
async *batchStream(requests, options) {
|
|
1258
1302
|
const resolved = this.resolveStreamOptions(options);
|
|
1259
1303
|
if (resolved.concurrency) {
|
|
1260
|
-
const limit = pLimit({
|
|
1304
|
+
const limit = resolved.pLimit ?? pLimit({
|
|
1261
1305
|
concurrency: resolved.concurrency,
|
|
1262
1306
|
rejectOnClear: true
|
|
1263
1307
|
});
|
|
1264
1308
|
const client = this.makeStreamClient(limit, resolved);
|
|
1265
1309
|
const channel = new AsyncChannel();
|
|
1266
1310
|
try {
|
|
1267
|
-
Promise.all(requests.map((req) => limit(() => this.request(req.path, req, client).then((val) => channel.push(
|
|
1311
|
+
Promise.all(requests.map((req, index) => limit(() => this.request(req.path, req, client).then((val) => channel.push({
|
|
1312
|
+
...Ok(val),
|
|
1313
|
+
index
|
|
1314
|
+
}), (err) => channel.push({
|
|
1315
|
+
...Err(err),
|
|
1316
|
+
index
|
|
1317
|
+
}))))).catch((err) => this.logger?.warn({ err }, "In-flight concurrent requests aborted")).finally(() => channel.close());
|
|
1268
1318
|
for await (const item of channel) yield item;
|
|
1269
1319
|
} finally {
|
|
1270
1320
|
limit.clearQueue();
|
|
1271
1321
|
}
|
|
1272
|
-
} else for (const request of requests) try {
|
|
1273
|
-
yield
|
|
1322
|
+
} else for (const [index, request] of requests.entries()) try {
|
|
1323
|
+
yield {
|
|
1324
|
+
...Ok(await this.request(request.path, request)),
|
|
1325
|
+
index
|
|
1326
|
+
};
|
|
1274
1327
|
} catch (err) {
|
|
1275
|
-
if (err instanceof BaseError) yield
|
|
1276
|
-
|
|
1328
|
+
if (err instanceof BaseError) yield {
|
|
1329
|
+
...Err(err),
|
|
1330
|
+
index
|
|
1331
|
+
};
|
|
1332
|
+
else yield {
|
|
1333
|
+
...Err(new BCClientError("Unknown error in batchStream", {}, { cause: err })),
|
|
1334
|
+
index
|
|
1335
|
+
};
|
|
1277
1336
|
}
|
|
1278
1337
|
}
|
|
1279
1338
|
async validatePaginatedItem(path, item, schema) {
|
|
@@ -1307,7 +1366,8 @@ var BigCommerceClient = class {
|
|
|
1307
1366
|
concurrency: options?.concurrency ?? this.config.concurrency ?? 10,
|
|
1308
1367
|
rateLimitBackoff: options?.rateLimitBackoff ?? this.config.rateLimitBackoff ?? 1,
|
|
1309
1368
|
backoff: options?.backoff ?? this.config.backoff ?? 2,
|
|
1310
|
-
backoffRecover: options?.backoffRecover ?? this.config.backoffRecover ?? 1
|
|
1369
|
+
backoffRecover: options?.backoffRecover ?? this.config.backoffRecover ?? 1,
|
|
1370
|
+
pLimit: options?.pLimit
|
|
1311
1371
|
};
|
|
1312
1372
|
}
|
|
1313
1373
|
makeStreamClient(limit, options) {
|
|
@@ -1340,9 +1400,9 @@ var BigCommerceClient = class {
|
|
|
1340
1400
|
}]
|
|
1341
1401
|
} });
|
|
1342
1402
|
}
|
|
1343
|
-
async request(
|
|
1403
|
+
async request(rawPath, options, client) {
|
|
1344
1404
|
const { version, query, body, bodySchema, querySchema, responseSchema, ...kyOptions } = options;
|
|
1345
|
-
const path = this.makePath(options.version ?? "v3",
|
|
1405
|
+
const path = this.makePath(options.version ?? "v3", rawPath);
|
|
1346
1406
|
const validQuery = await this.validate(query, querySchema, BCQueryValidationError, options.method, path, "Invalid query parameters");
|
|
1347
1407
|
const validBody = await this.validate(body, bodySchema, BCRequestBodyValidationError, options.method, path, `Invalid ${options.method} request body`);
|
|
1348
1408
|
let response;
|
|
@@ -1401,18 +1461,13 @@ var BigCommerceClient = class {
|
|
|
1401
1461
|
const errors = [];
|
|
1402
1462
|
if (typeof storeHash !== "string" || storeHash.length <= 0) errors.push("storeHash is empty");
|
|
1403
1463
|
if (typeof accessToken !== "string" || accessToken.length <= 0) errors.push("accessToken is empty");
|
|
1464
|
+
if (errors.length > 0) throw new BCCredentialsError(errors);
|
|
1404
1465
|
if (this.config.prefixUrl) try {
|
|
1405
1466
|
new URL(this.config.prefixUrl);
|
|
1406
1467
|
} catch (err) {
|
|
1407
1468
|
throw new BCClientError("Invalid prefixUrl", void 0, err);
|
|
1408
1469
|
}
|
|
1409
|
-
|
|
1410
|
-
this.validateConcurrency(this.config.concurrency);
|
|
1411
|
-
} catch (err) {
|
|
1412
|
-
if (err instanceof BCClientError) errors.push(err.message);
|
|
1413
|
-
else throw err;
|
|
1414
|
-
}
|
|
1415
|
-
if (errors.length > 0) throw new BCCredentialsError(errors);
|
|
1470
|
+
this.validateConcurrency(this.config.concurrency);
|
|
1416
1471
|
}
|
|
1417
1472
|
validateConcurrency(concurrency) {
|
|
1418
1473
|
if (concurrency === void 0) return;
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":[],"sources":["../src/lib/common.ts","../src/lib/errors.ts","../src/lib/logger.ts","../src/auth.ts","../src/lib/util.ts","../src/lib/hooks.ts","../src/lib/request.ts","../src/lib/result.ts","../src/client.ts"],"sourcesContent":["import type { Options as KyOptions } from 'ky';\nimport type { Logger, LogLevel } from './logger';\n\nexport type { Logger, LogLevel };\n\nexport type ConcurrencyOptions = {\n /** Max concurrent requests. Must be 1–1000. `false` for sequential. Defaults to 10. */\n concurrency?: number | false;\n /**\n * Divisor (or `(concurrency, status) => number` function) applied to concurrency on\n * non-429 error responses. Defaults to 2.\n */\n backoff?: ((concurrency: number, status: number) => number) | number;\n /** Concurrency cap applied when a 429 response is received. Defaults to 1. */\n rateLimitBackoff?: number;\n /**\n * Amount (or `(concurrency) => number` function) added to concurrency per successful\n * response while below the configured max. Defaults to 1.\n */\n backoffRecover?: ((concurrency: number) => number) | number;\n};\n\n/** Maximum allowed concurrency value. */\nexport const MAX_CONCURRENCY = 1000;\n/** Default concurrency for batch/stream operations. */\nexport const DEFAULT_CONCURRENCY = 10;\n/** Default concurrency cap on 429 rate-limit responses. */\nexport const DEFAULT_RATE_LIMIT_BACKOFF = 1;\n/** Default divisor applied to concurrency on non-429 errors. */\nexport const DEFAULT_BACKOFF_RATE = 2;\n/** Default amount added to concurrency per successful response. */\nexport const DEFAULT_BACKOFF_RECOVER = 1;\n/** Default page size for paginated requests. */\nexport const DEFAULT_LIMIT = 250;\n/** Maximum allowed URL length before chunking is required. */\nexport const MAX_URL_LENGTH = 2048;\n/** Regex to strip leading slashes from API paths. */\nexport const LEADING_SLASHES = /^\\/+/;\n/** Maximum pages to fetch during blind pagination **/\nexport const DEFAULT_MAX_BLIND_PAGES = 500;\n\n/**\n * Configuration options for the BigCommerce client.\n */\nexport interface ClientConfig\n extends Omit<KyOptions, 'throwHttpErrors' | 'parseJson' | 'method' | 'body' | 'json' | 'searchParams'>,\n ConcurrencyOptions {\n storeHash: string;\n accessToken: string;\n logger?: Logger | LogLevel | boolean;\n}\n\n/**\n * Random positive jitter within 0-500 ms in increments of 100\n * @param {number} delay\n */\nexport const rateLimitJitter = (delay: number) => delay + Math.floor(Math.random() * 6) * 100;\n\n/**\n * HTTP header names used by the BigCommerce API.\n */\nexport const HEADERS = {\n AUTH_TOKEN: 'X-Auth-Token',\n ACCEPT: 'Accept',\n CONTENT_TYPE: 'Content-Type',\n RATE_LIMIT_LEFT: 'x-rate-limit-requests-left',\n RATE_LIMIT_RESET: 'x-rate-limit-time-reset-ms',\n RATE_LIMIT_QUOTA: 'x-rate-limit-requests-quota',\n RATE_LIMIT_WINDOW: 'x-rate-limit-time-window-ms',\n} as const;\n\n/**\n * Metadata extracted from rate-limit headers in API responses.\n */\nexport type RateLimitMeta = {\n /** Time in milliseconds until the rate limit resets. */\n resetIn: number;\n /** Number of requests remaining in the current window. */\n requestsLeft?: number;\n /** Total request quota for the current window. */\n quota?: number;\n /** Time window size in milliseconds. */\n window?: number;\n};\n\n/**\n * Default configuration for the underlying ky HTTP client.\n */\nexport const BASE_KY_CONFIG = {\n prefixUrl: 'https://api.bigcommerce.com',\n throwHttpErrors: true,\n // Some BC endpoints may take a while.\n // For example /catalog/product/options* endpoints may fully\n // recreate all variants in some cases\n timeout: 120e3,\n\n retry: {\n limit: 3,\n // BC uses PUT for many upsert operations, it's not guaranteed to be idempotent\n methods: ['GET', 'DELETE'],\n statusCodes: [429, 500, 502, 503, 504],\n // BC does not send standart Retry-After. We'll use custom beforeRetry hook\n afterStatusCodes: [],\n jitter: true,\n maxRetryAfter: 120e3,\n },\n\n headers: {\n [HEADERS.ACCEPT]: 'application/json',\n [HEADERS.CONTENT_TYPE]: 'application/json',\n },\n};\n\n/**\n * Concurrency options with all values resolved to their defaults.\n */\nexport type ResolvedConcurrencyOptions = Required<ConcurrencyOptions>;\n","import type { HTTPError, KyRequest, TimeoutError as KyTimeoutError } from 'ky';\nimport type { Query } from './request';\nimport type { StandardSchemaV1 } from './standard-schema';\n\nexport type ErrorContext = Record<string, unknown>;\n\n/**\n * Abstract base class for all library errors. Carries a typed `context` object with\n * structured diagnostic data and a machine-readable `code` string.\n *\n * Use `instanceof` checks against specific subclasses rather than this base class.\n */\nexport abstract class BaseError<TContext extends ErrorContext = ErrorContext> extends Error {\n /** Machine-readable error code. Unique per subclass. */\n abstract readonly code: string;\n\n constructor(\n message: string,\n readonly context: TContext,\n options?: ErrorOptions,\n ) {\n super(message, options);\n\n this.name = this.constructor.name;\n }\n\n /** @internal */\n toJSON() {\n return {\n name: this.name,\n code: this.code,\n message: this.message,\n context: this.context,\n cause: this.cause,\n };\n }\n}\n\n/** Catch-all for unexpected client-side errors not covered by a more specific subclass. */\nexport class BCClientError extends BaseError<Record<string, unknown>> {\n code = 'BC_CLIENT_ERROR';\n\n constructor(message: string, context?: Record<string, unknown>, cause?: unknown) {\n super(message, context ?? {}, { cause });\n }\n}\n\n/** Thrown by the {@link BigCommerceClient} constructor when credentials or config are invalid. */\nexport class BCCredentialsError extends BaseError<{\n errors: string[];\n}> {\n code = 'BC_CLIENT_CREDENTIALS_ERROR';\n\n constructor(errors: string[]) {\n super('Failed to initialize BigCommerceClient', { errors });\n }\n}\n\n/** Thrown before a request is sent when the constructed URL exceeds 2048 characters. */\nexport class BCUrlTooLongError extends BaseError<{\n url: string;\n max: number;\n len: number;\n}> {\n code = 'BC_URL_TOO_LONG';\n\n constructor(url: string, max: number) {\n super(`Url length (${url.length}) exceeds max allowed length of ${max}`, { url, max, len: url.length });\n }\n}\n\n/**\n * Thrown during retry when a 429 response is received but the expected\n * `X-Rate-Limit-*` headers are absent, making it impossible to determine the backoff delay.\n */\nexport class BCRateLimitNoHeadersError extends BaseError<{\n url: string;\n method: string;\n attempts: number;\n}> {\n code = 'BC_RATE_LIMIT_NO_HEADERS';\n\n constructor(request: KyRequest, attempts: number) {\n super('Rate limit reached but the X-Rate-Limit-* headers were not returned. Unable to retry', {\n url: request.url,\n method: request.method,\n attempts,\n });\n }\n}\n\n/**\n * Thrown during retry when a 429 response specifies a reset window that exceeds\n * `config.retry.maxRetryAfter`, preventing an unbounded wait.\n */\nexport class BCRateLimitDelayTooLongError extends BaseError<{\n url: string;\n method: string;\n attempts: number;\n maxDelay: number;\n delay: number;\n}> {\n code = 'BC_RATE_LIMIT_DELAY_TOO_LONG';\n\n constructor(request: KyRequest, attempts: number, maxDelay: number, delay: number) {\n super('Rate limit reached, and the rate limit reset window is too high.', {\n url: request.url,\n method: request.method,\n attempts,\n maxDelay,\n delay,\n });\n }\n}\n\n/**\n * Abstract base for all StandardSchema validation errors. Carries the raw `data` that failed\n * validation and the schema `error` result. Use specific subclasses for `instanceof` checks.\n */\nexport abstract class BCSchemaValidationError extends BaseError<{\n method: string;\n path: string;\n data: unknown;\n error: StandardSchemaV1.FailureResult;\n}> {\n constructor(message: string, method: string, path: string, data: unknown, error: StandardSchemaV1.FailureResult) {\n super(message, { method, path, data, error });\n }\n}\n\n/** Thrown when `options.querySchema` validation fails before a request is sent. */\nexport class BCQueryValidationError extends BCSchemaValidationError {\n code = 'BC_QUERY_VALIDATION_FAILED';\n}\n\n/** Thrown when `options.bodySchema` validation fails before a request is sent. */\nexport class BCRequestBodyValidationError extends BCSchemaValidationError {\n code = 'BC_REQUEST_BODY_VALIDATION_FAILED';\n}\n\n/** Thrown when `options.responseSchema` validation fails after a response is received. */\nexport class BCResponseValidationError extends BCSchemaValidationError {\n code = 'BC_RESPONSE_VALIDATION_FAILED';\n}\n\n/** Thrown or yielded when `options.itemSchema` validation fails for an item in a page response. */\nexport class BCPaginatedItemValidationError extends BCSchemaValidationError {\n code = 'BC_PAGINATED_ITEM_VALIDATION_FAILED';\n}\n\n/**\n * Thrown when the BigCommerce API returns a non-2xx HTTP response.\n * `context.status` and `context.responseBody` are the most useful fields for debugging.\n */\nexport class BCApiError extends BaseError<{\n method: string;\n url: string;\n status: number;\n statusMessage: string;\n headers: Record<string, string>;\n requestBody: string;\n responseBody: string;\n}> {\n code = 'BC_API_ERROR';\n\n constructor(err: HTTPError, requestBody: string, responseBody: string) {\n const { request, response } = err;\n\n super('BigCommerce API request failed', {\n method: request.method,\n url: request.url,\n status: response.status,\n statusMessage: response.statusText,\n headers: Object.fromEntries(response.headers as unknown as Iterable<[string, string]>),\n requestBody,\n responseBody,\n });\n }\n}\n\n/** Thrown when a request exceeds the configured timeout (default 120 s). */\nexport class BCTimeoutError extends BaseError<{\n method: string;\n url: string;\n}> {\n code = 'BC_TIMEOUT_ERROR';\n\n constructor(err: KyTimeoutError) {\n super('BigCommerce API request timed out', {\n method: err.request.method,\n url: err.request.url,\n });\n }\n}\n\n/**\n * Thrown when the response body cannot be read or parsed as JSON.\n * `context.rawBody` contains the raw text that failed to parse (empty string if the body was empty).\n */\nexport class BCResponseParseError extends BaseError<{\n method: string;\n status: number;\n path: string;\n query?: Query;\n rawBody?: string;\n}> {\n code = 'BC_RESPONSE_PARSE_ERROR';\n\n constructor(method: string, path: string, status: number, cause: unknown, query?: Query, rawBody?: string) {\n super(\n 'Failed to parse BigCommerce API response',\n {\n status,\n method,\n path,\n query,\n rawBody,\n },\n { cause },\n );\n }\n}\n\n/**\n * Thrown when a pagination option (`limit`, `page`, or `count`) is not a positive number.\n * `context.option` names the offending field; `context.value` is the value that was passed.\n */\nexport class BCPaginatedOptionError extends BaseError<{ path: string; option: string; value: unknown }> {\n code = 'BC_PAGINATED_OPTION_ERROR';\n\n constructor(path: string, value: unknown, option: string) {\n super('The pagination option must be a positive number', { path, option, value });\n }\n}\n\n/**\n * Thrown or yielded when a paginated response is missing required v3 envelope fields\n * (`data`, `meta.pagination`, etc.). Usually means the path is not a v3 collection endpoint.\n */\nexport class BCPaginatedResponseError extends BaseError<{ path: string; data: unknown; reason: string }> {\n code = 'BC_PAGINATED_RESPONSE_ERROR';\n\n constructor(path: string, data: unknown, reason: string) {\n super('Paginated response structure is invalid', { path, data, reason });\n }\n}\n\n/** Thrown by {@link BigCommerceAuth} constructor when `config.redirectUri` is not a valid URL. */\nexport class BCAuthInvalidRedirectUriError extends BaseError<{ redirectUri: string }> {\n code = 'BC_AUTH_INVALID_REDIRECT_URI';\n\n constructor(redirectUri: string, cause: unknown) {\n super('Invalid redirect URI', { redirectUri }, { cause });\n }\n}\n\n/** Thrown by {@link BigCommerceAuth.requestToken} when a required OAuth callback param is absent. */\nexport class BCAuthMissingParamError extends BaseError<{ param: string }> {\n code = 'BC_AUTH_MISSING_PARAM';\n\n constructor(param: string) {\n super(`Missing required auth callback parameter: ${param}`, { param });\n }\n}\n\n/**\n * Thrown by {@link BigCommerceAuth.requestToken} when the scopes granted by BigCommerce\n * do not include all scopes listed in `config.scopes`.\n * `context.missing` lists the scopes that were expected but not granted.\n */\nexport class BCAuthScopeMismatchError extends BaseError<{\n granted: string[];\n expected: string[];\n missing: string[];\n}> {\n code = 'BC_AUTH_SCOPE_MISMATCH';\n\n constructor(granted: string[], expected: string[], missing: string[]) {\n super('Granted scopes do not match expected scopes', { granted, expected, missing });\n }\n}\n\n/** Thrown by {@link BigCommerceAuth.verify} when the JWT signature, audience, issuer, or subject is invalid. */\nexport class BCAuthInvalidJwtError extends BaseError<{ storeHash: string }> {\n code = 'BC_AUTH_INVALID_JWT';\n\n constructor(storeHash: string, cause: unknown) {\n super('Invalid JWT payload', { storeHash }, { cause });\n }\n}\n","import type { ClientConfig } from './common';\n\n/**\n * Logging interface for the BigCommerce client.\n *\n * Implement this interface to provide custom logging. The client passes context data\n * as the first argument, making it compatible with structured loggers.\n */\nexport interface Logger {\n debug(data: Record<string, unknown>, message?: string): void;\n info(data: Record<string, unknown>, message?: string): void;\n warn(data: Record<string, unknown>, message?: string): void;\n error(data: Record<string, unknown>, message?: string): void;\n}\n\nexport type PowertoolsLikeLogger = {\n debug(message: string, ...data: Record<string, unknown>[]): void;\n info(message: string, ...data: Record<string, unknown>[]): void;\n warn(message: string, ...data: Record<string, unknown>[]): void;\n error(message: string, ...data: Record<string, unknown>[]): void;\n};\n\n/** @internal */\nexport const LOG_LEVELS = ['debug', 'info', 'warn', 'error'] as const;\n\n/** Supported log levels. */\nexport type LogLevel = (typeof LOG_LEVELS)[number];\n\n/**\n * Adapts an AWS Lambda Powertools logger to the {@link Logger} interface expected by\n * {@link BigCommerceClient} and {@link BigCommerceAuth}.\n *\n * Powertools loggers use `(message, ...data)` argument order whereas this library uses\n * `(data, message)`. This adapter swaps the arguments.\n *\n * @param logger - An AWS Lambda Powertools (or any {@link PowertoolsLikeLogger}-compatible) logger.\n * @returns A {@link Logger} wrapper suitable for `config.logger`.\n */\nexport const fromAwsPowertoolsLogger = (logger: PowertoolsLikeLogger): Logger => ({\n debug: (data, message) => logger.debug(message ?? '', data),\n info: (data, message) => logger.info(message ?? '', data),\n warn: (data, message) => logger.warn(message ?? '', data),\n error: (data, message) => logger.error(message ?? '', data),\n});\n\n/**\n * Console-based {@link Logger} that filters messages below a minimum level.\n *\n * Used automatically when `config.logger` is `true`, `undefined`, or a {@link LogLevel} string.\n * Can also be instantiated directly for custom log level control.\n *\n * @example\n * ```ts\n * new BigCommerceClient({ ..., logger: new FallbackLogger('debug') });\n * ```\n */\nexport class FallbackLogger implements Logger {\n /**\n * @param level - Minimum level to output. Messages below this level are silently dropped.\n */\n constructor(public readonly level: LogLevel) {}\n\n debug(data: Record<string, unknown>, message?: string): void {\n this.log('debug', data, message);\n }\n\n info(data: Record<string, unknown>, message?: string): void {\n this.log('info', data, message);\n }\n\n warn(data: Record<string, unknown>, message?: string): void {\n this.log('warn', data, message);\n }\n\n error(data: Record<string, unknown>, message?: string): void {\n this.log('error', data, message);\n }\n\n private log(level: LogLevel, data: Record<string, unknown>, message?: string) {\n if (LOG_LEVELS.indexOf(level) < LOG_LEVELS.indexOf(this.level)) {\n return;\n }\n\n const fn = console[level];\n\n message !== undefined ? fn(message, data) : fn(data);\n }\n}\n\n/**\n * @internal\n */\nexport const initLogger = (logger: ClientConfig['logger']): Logger | undefined => {\n if (logger === false) {\n return;\n }\n\n if (logger === undefined || logger === true) {\n return new FallbackLogger('info');\n }\n\n if (typeof logger === 'string') {\n if (LOG_LEVELS.includes(logger)) {\n return new FallbackLogger(logger);\n } else {\n const logger = new FallbackLogger('info');\n\n logger.warn({ level: logger }, 'Unknown log level passed, using info');\n\n return logger;\n }\n }\n\n return logger;\n};\n","import * as jose from 'jose';\nimport ky, { isHTTPError, isTimeoutError } from 'ky';\nimport { BASE_KY_CONFIG } from './lib/common';\nimport {\n BCApiError,\n BCAuthInvalidJwtError,\n BCAuthInvalidRedirectUriError,\n BCAuthMissingParamError,\n BCAuthScopeMismatchError,\n BCClientError,\n BCTimeoutError,\n} from './lib/errors';\nimport { initLogger, type Logger, type LogLevel } from './lib/logger';\n\n/**\n * Configuration options for BigCommerce authentication\n */\nexport type BigCommerceAuthConfig = {\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 /** Optional array of scopes to validate during auth callback */\n scopes?: string[];\n /** Optional logger instance */\n logger?: Logger | LogLevel | boolean;\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 */\nexport type BigCommerceAuthQuery = {\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 private readonly logger: Logger | undefined;\n private readonly client: ReturnType<typeof ky.create>;\n\n /**\n * Creates a new BigCommerceAuth instance for handling OAuth authentication\n * @param config - Configuration options for BigCommerce authentication\n * @param config.clientId - The OAuth client ID from BigCommerce\n * @param config.secret - The OAuth client secret from BigCommerce\n * @param config.redirectUri - The redirect URI registered with BigCommerce\n * @param config.scopes - Optional array of scopes to validate during auth callback\n * @param config.logger - Optional logger instance for debugging and error tracking\n * @throws {BCAuthInvalidRedirectUriError} If the redirect URI is invalid\n */\n constructor(private readonly config: BigCommerceAuthConfig) {\n try {\n new URL(this.config.redirectUri);\n } catch (error) {\n throw new BCAuthInvalidRedirectUriError(this.config.redirectUri, error);\n }\n\n this.logger = initLogger(config.logger);\n\n const { prefixUrl: _, ...authKyConfig } = BASE_KY_CONFIG;\n\n this.client = ky.create({\n ...authKyConfig,\n retry: {\n ...authKyConfig.retry,\n methods: ['POST'],\n },\n });\n }\n\n /**\n * Exchanges an OAuth authorization code for an access token.\n *\n * @param data - The auth callback payload: a raw query string, `URLSearchParams`, or a\n * pre-parsed object with `code`, `scope`, and `context`.\n * @returns The token response including `access_token`, `user`, and `context`.\n * @throws {@link BCAuthMissingParamError} if `code`, `scope`, or `context` are absent.\n * @throws {@link BCAuthScopeMismatchError} if the granted scopes don't include all `config.scopes`.\n * @throws {@link BCApiError} on HTTP error responses from the token endpoint.\n * @throws {@link BCTimeoutError} if the token request times out.\n * @throws {@link BCClientError} on any other error.\n */\n async requestToken(data: string | BigCommerceAuthQuery | URLSearchParams): Promise<TokenResponse> {\n const query = typeof data === 'string' || data instanceof URLSearchParams ? this.parseQueryString(data) : data;\n\n this.validateScopes(query.scope);\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 this.logger?.debug(\n {\n clientId: this.config.clientId,\n context: query.context,\n scopes: query.scope,\n },\n 'Requesting OAuth token',\n );\n\n let res: Response;\n\n try {\n res = await this.client(TOKEN_ENDPOINT, {\n method: 'POST',\n json: tokenRequest,\n });\n } catch (error) {\n if (isHTTPError(error)) {\n const requestBody = await error.request.text().catch(() => '');\n const responseBody = await error.response.text().catch(() => '');\n const err = new BCApiError(error, requestBody, responseBody);\n\n this.logger?.error(err.context, 'Failed to request token');\n\n throw err;\n }\n\n if (isTimeoutError(error)) {\n const err = new BCTimeoutError(error);\n\n this.logger?.error(err.context, 'Token request timed out');\n\n throw err;\n }\n\n throw new BCClientError('Failed to request token', {}, error);\n }\n\n return res.json() as Promise<TokenResponse>;\n }\n\n /**\n * Verifies a JWT payload from BigCommerce\n * @param jwtPayload - The JWT string to verify\n * @param storeHash - The store hash for the BigCommerce store\n * @returns Promise resolving to the verified JWT claims\n * @throws {BCAuthInvalidJwtError} If the JWT is invalid\n */\n async verify(jwtPayload: string, storeHash: string): Promise<Claims> {\n try {\n const secret = new TextEncoder().encode(this.config.secret);\n\n const { payload }: { payload: Claims } = await jose.jwtVerify(jwtPayload, secret, {\n audience: this.config.clientId,\n issuer: ISSUER,\n subject: `stores/${storeHash}`,\n });\n\n this.logger?.debug(\n {\n userId: payload.user?.id,\n storeHash: payload.sub.split('/')[1],\n },\n 'JWT verified successfully',\n );\n\n return payload;\n } catch (error) {\n const err = new BCAuthInvalidJwtError(storeHash, error);\n\n this.logger?.error(err.context, 'JWT verification failed');\n\n throw err;\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 {BCAuthMissingParamError} If required parameters are missing\n */\n private parseQueryString(queryString: string | URLSearchParams): BigCommerceAuthQuery {\n const params = typeof queryString === 'string' ? new URLSearchParams(queryString) : queryString;\n\n const code = params.get('code');\n const scope = params.get('scope');\n const context = params.get('context');\n\n if (!code) {\n throw new BCAuthMissingParamError('code');\n }\n\n if (!scope) {\n throw new BCAuthMissingParamError('scope');\n } else if (this.config.scopes?.length) {\n this.validateScopes(scope);\n }\n\n if (!context) {\n throw new BCAuthMissingParamError('context');\n }\n\n return {\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 {BCAuthScopeMismatchError} 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 granted = scopes.split(' ');\n const expected = this.config.scopes;\n const missing = expected.filter((scope) => !granted.includes(scope));\n\n if (missing.length) {\n throw new BCAuthScopeMismatchError(granted, expected, missing);\n }\n }\n}\n","import { HEADERS, type RateLimitMeta } from './common';\n\nexport function stripKeys<T extends object, K extends PropertyKey>(\n obj: T | undefined,\n keys: K[],\n): Omit<T, K> | undefined {\n if (!obj) {\n return obj;\n }\n\n const result = { ...obj } as Record<PropertyKey, unknown>;\n\n for (const key of keys) {\n delete result[key];\n }\n\n return result as Omit<T, K>;\n}\n\nconst parseIntHeader = (headers: Headers, key: string): number | undefined => {\n const value = Number.parseInt(headers.get(key) ?? '', 10);\n\n return Number.isNaN(value) ? undefined : value;\n};\n\nexport const extractRateLimitHeaders = (headers: Headers): RateLimitMeta | undefined => {\n const resetIn = parseIntHeader(headers, HEADERS.RATE_LIMIT_RESET);\n\n // Can't retry without this header - treat as unrecoverable\n if (resetIn === undefined) {\n return undefined;\n }\n\n return {\n resetIn,\n requestsLeft: parseIntHeader(headers, HEADERS.RATE_LIMIT_LEFT),\n quota: parseIntHeader(headers, HEADERS.RATE_LIMIT_QUOTA),\n window: parseIntHeader(headers, HEADERS.RATE_LIMIT_WINDOW),\n };\n};\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 = encodeURIComponent(item).length;\n const separatorLength = currentChunk.length > 0 ? separatorSize : 0;\n const totalItemLength = itemLength + separatorLength;\n\n const wouldExceedLength = currentStrLength + totalItemLength > maxLength;\n const wouldExceedCount = currentChunk.length >= chunkLength;\n\n if ((wouldExceedLength || wouldExceedCount) && currentChunk.length > 0) {\n chunks.push(currentChunk);\n currentChunk = [];\n currentStrLength = offset;\n }\n\n if (itemLength + offset > maxLength) {\n throw new Error(`Item too large: ${itemLength} exceeds maxLength ${maxLength}`);\n }\n\n currentChunk.push(item);\n currentStrLength += itemLength + (currentChunk.length > 1 ? separatorSize : 0);\n }\n\n if (currentChunk.length > 0) {\n chunks.push(currentChunk);\n }\n\n return chunks;\n};\n\nexport class AsyncChannel<T> {\n private readonly queue: T[] = [];\n private notify: (() => void) | null = null;\n private done = false;\n\n push(item: T) {\n this.queue.push(item);\n this.notify?.();\n this.notify = null;\n }\n\n close() {\n this.done = true;\n this.notify?.();\n this.notify = null;\n }\n\n async *[Symbol.asyncIterator](): AsyncGenerator<T> {\n while (!this.done || this.queue.length > 0) {\n if (this.queue.length === 0) {\n await new Promise<void>((r) => {\n if (this.queue.length > 0) {\n return r();\n }\n\n this.notify = r;\n });\n }\n\n while (this.queue.length > 0) {\n const item = this.queue.shift();\n\n if (item !== undefined) {\n yield item;\n }\n }\n }\n }\n}\n","import { type BeforeRequestHook, type BeforeRetryHook, isHTTPError } from 'ky';\nimport { MAX_URL_LENGTH, rateLimitJitter } from './common';\nimport { BCRateLimitDelayTooLongError, BCRateLimitNoHeadersError, BCUrlTooLongError } from './errors';\nimport type { Logger } from './logger';\nimport { extractRateLimitHeaders } from './util';\n\nexport const validateUrlLength: BeforeRequestHook = (request) => {\n if (request.url.length > MAX_URL_LENGTH) {\n throw new BCUrlTooLongError(request.url, MAX_URL_LENGTH);\n }\n};\n\nexport const bcRateLimitRetry =\n (logger?: Logger): BeforeRetryHook =>\n async ({ request, options, error, retryCount }) => {\n if (isHTTPError(error) && error.response.status === 429) {\n const retryMeta = extractRateLimitHeaders(error.response.headers);\n\n if (!retryMeta) {\n throw new BCRateLimitNoHeadersError(request, retryCount);\n }\n\n if (options.retry.maxRetryAfter && retryMeta.resetIn > options.retry.maxRetryAfter) {\n throw new BCRateLimitDelayTooLongError(\n request,\n retryCount,\n options.retry.maxRetryAfter,\n retryMeta.resetIn,\n );\n }\n\n const delay =\n typeof options.retry.jitter === 'function'\n ? options.retry.jitter(retryMeta.resetIn)\n : rateLimitJitter(retryMeta.resetIn);\n\n logger?.warn(\n { attempt: retryCount, url: request.url, method: request.method, retryMeta },\n `Rate limit reached, retrying in ${delay} (with jitter)`,\n );\n\n await new Promise((resolve) => setTimeout(resolve, delay));\n } else {\n logger?.warn({ url: request.url, method: request.method, attempt: retryCount }, 'Retrying request');\n }\n };\n","import type { Options as KyOptions } from 'ky';\nimport type { ConcurrencyOptions } from './common';\nimport type { StandardSchemaV1 } from './standard-schema';\n\n/** BigCommerce API versions supported by the client. */\nexport type ApiVersion = 'v3' | 'v2';\n\n/** Valid query parameter value types. */\nexport type QueryValue = string | number | Array<string | number>;\n\n/** Query parameter object for API requests. */\nexport type Query = Record<string, QueryValue>;\n\n/**\n * Converts a Query object to URLSearchParams.\n * Array values are joined with commas (e.g., `id:in=1,2,3`).\n */\nexport const toUrlSearchParams = (query?: Query): URLSearchParams | undefined => {\n if (!query) {\n return;\n }\n\n const params = new URLSearchParams();\n\n for (const [key, value] of Object.entries(query)) {\n if (Array.isArray(value)) {\n params.append(key, value.map(String).join(','));\n } else {\n params.append(key, String(value));\n }\n }\n\n return params;\n};\n\n/** Supported HTTP methods for API requests. */\nexport type HttpMethod = 'POST' | 'GET' | 'PUT' | 'DELETE';\n\n/** @internal */\ntype BaseKyRequest = Omit<\n KyOptions,\n 'json' | 'method' | 'searchQueryParams' | 'body' | 'throwHttpErrors' | 'parseJson'\n>;\n\n/** @internal */\ntype QuerySchemaOptions<TQuery extends Query> =\n /** Query parameters to send with the request. */\n { query: TQuery; querySchema: StandardSchemaV1<TQuery> } | { query?: TQuery; querySchema?: never };\n\n/** @internal */\ntype BodySchemaOptions<TBody> =\n /** Request body, serialized as JSON. */\n { body: TBody; bodySchema: StandardSchemaV1<TBody> } | { body?: TBody; bodySchema?: never };\n\n/**\n * Full request options for direct API calls.\n * @see {@link GetOptions}, {@link PostOptions}, {@link PutOptions}, {@link DeleteOptions}\n */\nexport type RequestOptions<TBody, TRes, TQuery extends Query> = BaseKyRequest &\n QuerySchemaOptions<TQuery> &\n BodySchemaOptions<TBody> & {\n /** HTTP method for the request. */\n method: HttpMethod;\n /** API version to use. Defaults to `'v3'`. */\n version?: ApiVersion;\n /** Schema to validate the response body. */\n responseSchema?: StandardSchemaV1<TRes>;\n };\n\n/** Options for GET requests. */\nexport type GetOptions<TRes, TQuery extends Query> = Omit<\n RequestOptions<never, TRes, TQuery>,\n 'body' | 'bodySchema' | 'method'\n>;\n\n/** Options for POST requests. */\nexport type PostOptions<TBody, TRes, TQuery extends Query> = Omit<RequestOptions<TBody, TRes, TQuery>, 'method'>;\n\n/** Options for PUT requests. */\nexport type PutOptions<TBody, TRes, TQuery extends Query> = PostOptions<TBody, TRes, TQuery>;\n\n/** Options for DELETE requests. */\nexport type DeleteOptions<TQuery extends Query> = Omit<\n RequestOptions<never, never, TQuery>,\n 'body' | 'bodySchema' | 'method' | 'responseSchema'\n>;\n\n/**\n * Request descriptor for batch operations.\n * Use the {@link req} helpers to construct these.\n */\nexport type BatchRequestOptions<TBody, TRes, TQuery extends Query> = {\n path: string;\n} & RequestOptions<TBody, TRes, TQuery>;\n\n/**\n * Helpers for building typed request descriptors to pass to\n * {@link BigCommerceClient.batchSafe} or {@link BigCommerceClient.batchStream}.\n *\n * @example\n * ```ts\n * const results = await client.batchSafe([\n * req.get('catalog/products/1'),\n * req.post('catalog/products', { body: { name: 'Widget' } }),\n * ]);\n * ```\n */\nexport const req = {\n /**\n * Builds a GET request descriptor.\n * @param path - API path relative to the store's versioned base URL.\n * @param options - Optional query params, schemas, and ky options.\n */\n get: <TRes, TQuery extends Query = Query>(\n path: string,\n options?: GetOptions<TRes, TQuery>,\n ): BatchRequestOptions<never, TRes, TQuery> =>\n ({ method: 'GET', path, ...options }) as BatchRequestOptions<never, TRes, TQuery>,\n\n /**\n * Builds a POST request descriptor.\n * @param path - API path relative to the store's versioned base URL.\n * @param options - Optional body, query params, schemas, and ky options.\n */\n post: <TRes, TBody = unknown, TQuery extends Query = Query>(\n path: string,\n options?: PostOptions<TBody, TRes, TQuery>,\n ): BatchRequestOptions<TBody, TRes, TQuery> =>\n ({ method: 'POST', path, ...options }) as BatchRequestOptions<TBody, TRes, TQuery>,\n\n /**\n * Builds a PUT request descriptor.\n * @param path - API path relative to the store's versioned base URL.\n * @param options - Optional body, query params, schemas, and ky options.\n */\n put: <TRes, TBody = unknown, TQuery extends Query = Query>(\n path: string,\n options?: PutOptions<TBody, TRes, TQuery>,\n ): BatchRequestOptions<TBody, TRes, TQuery> =>\n ({ method: 'PUT', path, ...options }) as BatchRequestOptions<TBody, TRes, TQuery>,\n\n /**\n * Builds a DELETE request descriptor.\n * @param path - API path relative to the store's versioned base URL.\n * @param options - Optional query params and ky options.\n */\n delete: <TQuery extends Query = Query>(\n path: string,\n options?: DeleteOptions<TQuery>,\n ): BatchRequestOptions<never, never, TQuery> =>\n ({ method: 'DELETE', path, ...options }) as BatchRequestOptions<never, never, TQuery>,\n};\n\n/**\n * Options for v3 paginated collection operations ({@link BigCommerceClient.collect}, {@link BigCommerceClient.stream}).\n */\nexport type CollectOptions<TItem, TQuery extends Query> = ConcurrencyOptions &\n Omit<GetOptions<TItem, TQuery>, 'responseSchema' | 'version'> & {\n /** Schema to validate each item in the response. */\n itemSchema?: StandardSchemaV1<TItem>;\n };\n\nexport type BlindOptions<TItem, TQuery extends Query> = Omit<CollectOptions<TItem, TQuery>, 'version'> & {\n maxPages?: number;\n};\n\n/**\n * Options for v2 paginated operations with known count ({@link BigCommerceClient.collectCount}, {@link BigCommerceClient.streamCount}).\n */\nexport type CountedCollectOptions<TItem, TQuery extends Query> = CollectOptions<TItem, TQuery> & {\n /** Total number of items expected (for v2 endpoints without pagination metadata). */\n count?: number;\n};\n\n/**\n * Options for query-based filtering operations ({@link BigCommerceClient.query}, {@link BigCommerceClient.queryStream}).\n */\nexport type QueryOptions<TItem, TQuery extends Query> = CollectOptions<TItem, TQuery> & {\n /** Query parameter name for value filtering (e.g., `'id:in'`). */\n key: string;\n /** Values to filter by. Automatically chunked across multiple requests. */\n values: (string | number)[];\n};\n","export type Ok<T> = {\n ok: true;\n data: T;\n err: undefined;\n};\n\nexport type Err<E> = {\n ok: false;\n data: undefined;\n err: E;\n};\n\nexport type Result<T, E> = Ok<T> | Err<E>;\n\n/**\n * Creates a successful {@link Result}. Check `result.ok` or `result.err` before accessing `data`.\n * @param data - The success value.\n */\nexport const Ok = <T, E>(data: T): Result<T, E> => ({ ok: true, data, err: undefined });\n\n/**\n * Creates a failed {@link Result}. Check `result.ok` or `result.err` before accessing `err`.\n * @param err - The error value.\n */\nexport const Err = <T, E>(err: E): Result<T, E> => ({ ok: false, data: undefined, err });\n","import ky, { isHTTPError, isKyError, isTimeoutError, type KyInstance, type KyResponse } from 'ky';\nimport pLimit, { type LimitFunction } from 'p-limit';\nimport {\n BASE_KY_CONFIG,\n type ClientConfig,\n type ConcurrencyOptions,\n DEFAULT_BACKOFF_RATE,\n DEFAULT_BACKOFF_RECOVER,\n DEFAULT_CONCURRENCY,\n DEFAULT_LIMIT,\n DEFAULT_MAX_BLIND_PAGES,\n DEFAULT_RATE_LIMIT_BACKOFF,\n HEADERS,\n LEADING_SLASHES,\n type Logger,\n MAX_CONCURRENCY,\n MAX_URL_LENGTH,\n type ResolvedConcurrencyOptions,\n} from './lib/common';\nimport {\n BaseError,\n BCApiError,\n BCClientError,\n BCCredentialsError,\n BCPaginatedItemValidationError,\n BCPaginatedOptionError,\n BCPaginatedResponseError,\n BCQueryValidationError,\n BCRequestBodyValidationError,\n BCResponseParseError,\n BCResponseValidationError,\n type BCSchemaValidationError,\n BCTimeoutError,\n} from './lib/errors';\nimport { bcRateLimitRetry, validateUrlLength } from './lib/hooks';\nimport { initLogger } from './lib/logger';\nimport type { V3Resource } from './lib/pagination';\nimport {\n type ApiVersion,\n type BatchRequestOptions,\n type BlindOptions,\n type CollectOptions,\n type DeleteOptions,\n type GetOptions,\n type PostOptions,\n type PutOptions,\n type Query,\n type QueryOptions,\n type RequestOptions,\n req,\n toUrlSearchParams,\n} from './lib/request';\nimport { Err, Ok, type Result } from './lib/result';\nimport type { StandardSchemaV1 } from './lib/standard-schema';\nimport { AsyncChannel, chunkStrLength } from './lib/util';\n\nexport class BigCommerceClient {\n private readonly logger?: Logger;\n private readonly client: KyInstance;\n private readonly storeHash: string;\n\n /**\n * Creates a new BigCommerceClient.\n *\n * @param config - Client configuration. Ky options (e.g. `prefixUrl`, `timeout`, `retry`,\n * `hooks`) are forwarded to the underlying ky instance.\n * @param config.storeHash - BigCommerce store hash. Must be a non-empty string.\n * @param config.accessToken - BigCommerce API access token. Must be a non-empty string.\n * @param config.logger - A {@link Logger} instance, a log level string\n * (`'debug' | 'info' | 'warn' | 'error'`), `true` to enable console logging at `'info'`\n * level, or `false` to disable logging entirely. Omitting also defaults to `'info'` level.\n * @param config.concurrency - Default max concurrent requests for batch/stream operations.\n * Must be between 1 and 1000. Pass `false` to disable concurrency (sequential execution).\n * Defaults to 10.\n * @param config.rateLimitBackoff - Concurrency cap applied when a 429 response is received.\n * Defaults to 1.\n * @param config.backoff - Divisor (or `(concurrency, status) => number` function) applied to\n * concurrency on non-429 error responses. Defaults to 2.\n * @param config.backoffRecover - Amount (or `(concurrency) => number` function) added to\n * concurrency per successful response while below the configured max. Defaults to 1.\n *\n * @throws {@link BCCredentialsError} if `storeHash` or `accessToken` are missing or if\n * `concurrency` is out of range.\n * @throws {@link BCClientError} if `prefixUrl` is not a valid URL.\n */\n constructor(private readonly config: ClientConfig) {\n this.validateConfig();\n\n const { storeHash, accessToken, logger, concurrency: _, ...kyOptions } = config;\n\n this.logger = initLogger(logger);\n this.storeHash = storeHash;\n\n this.client = ky.create({\n ...BASE_KY_CONFIG,\n ...kyOptions,\n\n headers: {\n ...BASE_KY_CONFIG.headers,\n ...((kyOptions.headers ?? {}) as Record<string, string>),\n [HEADERS.AUTH_TOKEN]: accessToken,\n },\n\n hooks: {\n beforeRequest: [...(kyOptions.hooks?.beforeRequest ?? []), validateUrlLength],\n beforeRetry: [\n ({ error }) => {\n if (error instanceof BaseError) {\n throw error;\n }\n },\n bcRateLimitRetry(this.logger),\n ...(kyOptions.hooks?.beforeRetry ?? []),\n ],\n beforeError: [...(kyOptions.hooks?.beforeError ?? [])],\n afterResponse: [...(kyOptions.hooks?.afterResponse ?? [])],\n },\n });\n }\n\n /**\n * Sends a GET request to the given path.\n *\n * @param path - API path relative to the store's versioned base URL (e.g. `catalog/products`).\n * @param options - Ky options are forwarded to the underlying request.\n * @param options.version - API version segment inserted into the URL. Defaults to `'v3'`.\n * @param options.query - Query parameters to append to the URL.\n * @param options.querySchema - StandardSchemaV1 schema to validate `query` before the request\n * is sent. Requires `query` to be provided.\n * @param options.responseSchema - StandardSchemaV1 schema to validate the parsed response body.\n *\n * @returns Parsed and optionally validated response body.\n *\n * @throws {@link BCApiError} on HTTP error responses.\n * @throws {@link BCTimeoutError} if the request times out.\n * @throws {@link BCResponseParseError} if the response body cannot be parsed.\n * @throws {@link BCUrlTooLongError} if the constructed URL exceeds 2048 characters.\n * @throws {@link BCRateLimitNoHeadersError} if a 429 is received without rate-limit headers.\n * @throws {@link BCRateLimitDelayTooLongError} if the rate-limit reset window exceeds\n * `config.retry.maxRetryAfter`.\n * @throws {@link BCQueryValidationError} if `querySchema` validation fails.\n * @throws {@link BCResponseValidationError} if `responseSchema` validation fails.\n * @throws {@link BCClientError} on any other ky or unknown error.\n */\n async get<TRes = unknown, TQuery extends Query = Query>(\n path: string,\n options?: GetOptions<TRes, TQuery>,\n ): Promise<TRes> {\n return this.request<never, TRes, TQuery>(path, {\n ...options,\n method: 'GET',\n } as RequestOptions<never, TRes, TQuery>);\n }\n\n /**\n * Sends a POST request to the given path.\n *\n * @param path - API path relative to the store's versioned base URL.\n * @param options - Ky options are forwarded to the underlying request.\n * @param options.version - API version segment inserted into the URL. Defaults to `'v3'`.\n * @param options.body - Request body, serialized as JSON.\n * @param options.bodySchema - StandardSchemaV1 schema to validate `body` before the request\n * is sent. Requires `body` to be provided.\n * @param options.query - Query parameters to append to the URL.\n * @param options.querySchema - StandardSchemaV1 schema to validate `query` before the request\n * is sent. Requires `query` to be provided.\n * @param options.responseSchema - StandardSchemaV1 schema to validate the parsed response body.\n *\n * @returns Parsed and optionally validated response body.\n *\n * @throws {@link BCApiError} on HTTP error responses.\n * @throws {@link BCTimeoutError} if the request times out.\n * @throws {@link BCResponseParseError} if the response body cannot be parsed.\n * @throws {@link BCUrlTooLongError} if the constructed URL exceeds 2048 characters.\n * @throws {@link BCRateLimitNoHeadersError} if a 429 is received without rate-limit headers.\n * @throws {@link BCRateLimitDelayTooLongError} if the rate-limit reset window exceeds\n * `config.retry.maxRetryAfter`.\n * @throws {@link BCQueryValidationError} if `querySchema` validation fails.\n * @throws {@link BCRequestBodyValidationError} if `bodySchema` validation fails.\n * @throws {@link BCResponseValidationError} if `responseSchema` validation fails.\n * @throws {@link BCClientError} on any other ky or unknown error.\n */\n async post<TRes = unknown, TBody = unknown, TQuery extends Query = Query>(\n path: string,\n options?: PostOptions<TBody, TRes, TQuery>,\n ): Promise<TRes> {\n return this.request<TBody, TRes, TQuery>(path, {\n ...options,\n method: 'POST',\n } as RequestOptions<TBody, TRes, TQuery>);\n }\n\n /**\n * Sends a PUT request to the given path.\n *\n * @param path - API path relative to the store's versioned base URL.\n * @param options - Ky options are forwarded to the underlying request.\n * @param options.version - API version segment inserted into the URL. Defaults to `'v3'`.\n * @param options.body - Request body, serialized as JSON.\n * @param options.bodySchema - StandardSchemaV1 schema to validate `body` before the request\n * is sent. Requires `body` to be provided.\n * @param options.query - Query parameters to append to the URL.\n * @param options.querySchema - StandardSchemaV1 schema to validate `query` before the request\n * is sent. Requires `query` to be provided.\n * @param options.responseSchema - StandardSchemaV1 schema to validate the parsed response body.\n *\n * @returns Parsed and optionally validated response body.\n *\n * @throws {@link BCApiError} on HTTP error responses.\n * @throws {@link BCTimeoutError} if the request times out.\n * @throws {@link BCResponseParseError} if the response body cannot be parsed.\n * @throws {@link BCUrlTooLongError} if the constructed URL exceeds 2048 characters.\n * @throws {@link BCRateLimitNoHeadersError} if a 429 is received without rate-limit headers.\n * @throws {@link BCRateLimitDelayTooLongError} if the rate-limit reset window exceeds\n * `config.retry.maxRetryAfter`.\n * @throws {@link BCQueryValidationError} if `querySchema` validation fails.\n * @throws {@link BCRequestBodyValidationError} if `bodySchema` validation fails.\n * @throws {@link BCResponseValidationError} if `responseSchema` validation fails.\n * @throws {@link BCClientError} on any other ky or unknown error.\n */\n async put<TRes = unknown, TBody = unknown, TQuery extends Query = Query>(\n path: string,\n options?: PutOptions<TBody, TRes, TQuery>,\n ): Promise<TRes> {\n return this.request<TBody, TRes, TQuery>(path, {\n ...options,\n method: 'PUT',\n } as RequestOptions<TBody, TRes, TQuery>);\n }\n\n /**\n * Sends a DELETE request to the given path.\n *\n * Silently suppresses 404 responses (resource already gone) and empty response bodies.\n *\n * @param path - API path relative to the store's versioned base URL.\n * @param options - Ky options are forwarded to the underlying request.\n * @param options.version - API version segment inserted into the URL. Defaults to `'v3'`.\n * @param options.query - Query parameters to append to the URL.\n * @param options.querySchema - StandardSchemaV1 schema to validate `query` before the request\n * is sent. Requires `query` to be provided.\n *\n * @throws {@link BCApiError} on non-404 HTTP error responses.\n * @throws {@link BCTimeoutError} if the request times out.\n * @throws {@link BCResponseParseError} if the response body is non-empty and cannot be parsed.\n * @throws {@link BCUrlTooLongError} if the constructed URL exceeds 2048 characters.\n * @throws {@link BCRateLimitNoHeadersError} if a 429 is received without rate-limit headers.\n * @throws {@link BCRateLimitDelayTooLongError} if the rate-limit reset window exceeds\n * `config.retry.maxRetryAfter`.\n * @throws {@link BCQueryValidationError} if `querySchema` validation fails.\n * @throws {@link BCClientError} on any other ky or unknown error.\n */\n async delete<TRes = never, TQuery extends Query = Query>(\n path: string,\n options?: DeleteOptions<TQuery>,\n ): Promise<void> {\n try {\n await this.request<never, TRes, TQuery>(path, {\n ...options,\n method: 'DELETE',\n } as RequestOptions<never, TRes, TQuery>);\n } catch (err) {\n if (err instanceof BCResponseParseError && err.context.rawBody === '') {\n return;\n }\n\n // Do not throw on delete for resources that are already gone.\n if (err instanceof BCApiError && err.context.status === 404) {\n this.logger?.warn({ err }, 'Attempted to delete the resource that is already gone');\n\n return;\n }\n\n throw err;\n }\n }\n\n /**\n * Fetches items from a v3 paginated endpoint by splitting `values` across multiple requests\n * using the given `key` query param, chunking to stay within URL length limits.\n *\n * Collects all results into an array. Use {@link queryStream} to process items lazily.\n *\n * @param path - API path relative to the store's versioned base URL.\n * @param options - Query options including `key`, `values`, pagination params, and concurrency\n * controls.\n * @param options.key - Query parameter name used for value filtering (e.g. `'id:in'`).\n * @param options.values - Values to filter by. Automatically chunked across multiple requests\n * to keep each URL under 2048 characters.\n * @param options.query - Additional query parameters. `query.limit` controls page size\n * (default 250, must be > 0). If `options.key` is present in `query` it will be ignored.\n * @param options.querySchema - StandardSchemaV1 schema to validate `query`. Requires `query`\n * to be provided.\n * @param options.itemSchema - StandardSchemaV1 schema to validate each returned item.\n * @param options.concurrency - Max concurrent chunk requests. Must be 1–1000. `false` for\n * sequential. Defaults to `config.concurrency`, or 10 if not set on the client.\n * @param options.rateLimitBackoff - Concurrency cap on 429 responses. Defaults to\n * `config.rateLimitBackoff`, or 1 if not set on the client.\n * @param options.backoff - Divisor (or function) applied to concurrency on error responses.\n * Defaults to `config.backoff`, or 2 if not set on the client.\n * @param options.backoffRecover - Amount (or function) added to concurrency per successful\n * response. Defaults to `config.backoffRecover`, or 1 if not set on the client.\n *\n * @returns All matching items across all chunked requests.\n * @throws {@link BCPaginatedOptionError} if `query.limit` is not a positive number.\n * @throws {@link BCQueryValidationError} if `querySchema` validation fails.\n * @throws {@link BCApiError} on HTTP error responses.\n * @throws {@link BCTimeoutError} if a request times out.\n * @throws {@link BCResponseParseError} if a response body cannot be parsed.\n * @throws {@link BCUrlTooLongError} if a constructed URL exceeds 2048 characters.\n * @throws {@link BCRateLimitNoHeadersError} if a 429 is received without rate-limit headers.\n * @throws {@link BCRateLimitDelayTooLongError} if the rate-limit reset window exceeds\n * `config.retry.maxRetryAfter`.\n * @throws {@link BCPaginatedResponseError} if a page response has an unexpected shape.\n * @throws {@link BCPaginatedItemValidationError} if `itemSchema` validation fails for an item.\n * @throws {@link BCClientError} on any other ky or unknown error.\n */\n async query<TItem = unknown, TQuery extends Query = Query>(\n path: string,\n options: QueryOptions<TItem, TQuery>,\n ): Promise<TItem[]> {\n const results: TItem[] = [];\n\n for await (const { data, err } of this.queryStream(path, options)) {\n if (err) {\n throw err;\n } else {\n results.push(data);\n }\n }\n\n return results;\n }\n\n /**\n * Streaming variant of {@link query}. Yields each item individually as results arrive,\n * splitting `values` into URL-length-safe chunks across concurrent requests.\n *\n * Each yielded value is a {@link Result} — check `err` before using `data`.\n *\n * @param path - API path relative to the store's versioned base URL.\n * @param options - Query options including `key`, `values`, pagination params, and concurrency\n * controls.\n * @param options.key - Query parameter name used for value filtering (e.g. `'id:in'`).\n * @param options.values - Values to filter by. Automatically chunked across multiple requests\n * to keep each URL under 2048 characters.\n * @param options.query - Additional query parameters. `query.limit` controls page size\n * (default 250, must be > 0). If `options.key` is present in `query` it will be ignored.\n * @param options.querySchema - StandardSchemaV1 schema to validate `query`. Requires `query`\n * to be provided.\n * @param options.itemSchema - StandardSchemaV1 schema to validate each returned item.\n * @param options.concurrency - Max concurrent chunk requests. Must be 1–1000. `false` for\n * sequential. Defaults to `config.concurrency`, or 10 if not set on the client.\n * @param options.rateLimitBackoff - Concurrency cap on 429 responses. Defaults to\n * `config.rateLimitBackoff`, or 1 if not set on the client.\n * @param options.backoff - Divisor (or function) applied to concurrency on error responses.\n * Defaults to `config.backoff`, or 2 if not set on the client.\n * @param options.backoffRecover - Amount (or function) added to concurrency per successful\n * response. Defaults to `config.backoffRecover`, or 1 if not set on the client.\n * @throws {@link BCPaginatedOptionError} if `query.limit` is not a positive number.\n * @throws {@link BCQueryValidationError} if `querySchema` validation fails.\n */\n async *queryStream<TItem = unknown, TQuery extends Query = Query>(\n path: string,\n options: QueryOptions<TItem, TQuery>,\n ): AsyncGenerator<Result<TItem, BaseError>> {\n const { key, values, query, querySchema, itemSchema, ...requestOptions } = options;\n\n const limit = this.validatePaginationOption(path, 'limit', query?.limit ?? DEFAULT_LIMIT);\n\n const validatedQuery = await this.validate(\n query,\n querySchema,\n BCQueryValidationError,\n 'GET',\n path,\n 'Invalid query parameters',\n );\n\n const newQuery: Query = {\n ...validatedQuery,\n limit,\n };\n\n if (key in newQuery) {\n this.logger?.warn({ key }, 'The provided key is already in the query params, this param will be ignored');\n\n delete newQuery[key];\n }\n\n const url = this.config.prefixUrl ?? requestOptions.prefixUrl ?? BASE_KY_CONFIG.prefixUrl;\n const fullPath = this.makePath('v3', path);\n const fullQuery = toUrlSearchParams({ ...newQuery, page: 1 });\n const fullUrl = `${url}/${fullPath}?${fullQuery}`;\n const keyOverhead = encodeURIComponent(key).length + 2; // `&key=` or `key=` prefix\n\n const chunks = chunkStrLength(values.map(String), {\n chunkLength: limit,\n maxLength: MAX_URL_LENGTH,\n offset: fullUrl.length + keyOverhead,\n separatorSize: encodeURIComponent(',').length,\n });\n\n const requests = chunks.map((chunk) =>\n req.get(path, {\n ...requestOptions,\n query: {\n ...newQuery,\n page: 1,\n [key]: chunk,\n },\n }),\n );\n\n for await (const { err, data } of this.batchStream(requests, options)) {\n if (err) {\n yield Err(err);\n continue;\n }\n\n try {\n const { data: items } = this.assertPaginatedResponse(path, data);\n\n for (const item of items) {\n yield this.validatePaginatedItem(path, item, itemSchema);\n }\n } catch (err) {\n if (err instanceof BaseError) {\n yield Err(err);\n } else {\n yield Err(new BCClientError('Unknown error occurred processing page', {}, { cause: err }));\n }\n }\n }\n }\n\n /**\n * Fetches all pages from a v3 paginated endpoint and collects items into an array.\n *\n * Use {@link stream} to process items lazily without buffering the full result set.\n *\n * @param path - API path relative to the store's versioned base URL.\n * @param options - Ky options are forwarded to page requests.\n * @param options.query - Query parameters. `query.limit` controls page size (default 250,\n * must be > 0). `query.page` sets the starting page (default 1, must be > 0).\n * @param options.querySchema - StandardSchemaV1 schema to validate `query`. Requires `query`\n * to be provided.\n * @param options.itemSchema - StandardSchemaV1 schema to validate each returned item.\n * @param options.concurrency - Max concurrent page requests for pages after the first.\n * Must be 1–1000. `false` for sequential. Defaults to `config.concurrency`, or 10 if not\n * set on the client.\n * @param options.rateLimitBackoff - Concurrency cap on 429 responses. Defaults to\n * `config.rateLimitBackoff`, or 1 if not set on the client.\n * @param options.backoff - Divisor (or function) applied to concurrency on error responses.\n * Defaults to `config.backoff`, or 2 if not set on the client.\n * @param options.backoffRecover - Amount (or function) added to concurrency per successful\n * response. Defaults to `config.backoffRecover`, or 1 if not set on the client.\n * @returns All items across all pages.\n *\n * @throws {@link BCPaginatedOptionError} if `query.limit` or `query.page` is not a positive number.\n * @throws {@link BCQueryValidationError} if `querySchema` validation fails.\n * @throws {@link BCApiError} on HTTP error responses.\n * @throws {@link BCTimeoutError} if a request times out.\n * @throws {@link BCResponseParseError} if a response body cannot be parsed.\n * @throws {@link BCUrlTooLongError} if a constructed URL exceeds 2048 characters.\n * @throws {@link BCRateLimitNoHeadersError} if a 429 is received without rate-limit headers.\n * @throws {@link BCRateLimitDelayTooLongError} if the rate-limit reset window exceeds\n * `config.retry.maxRetryAfter`.\n * @throws {@link BCPaginatedResponseError} if a page response has an unexpected shape.\n * @throws {@link BCPaginatedItemValidationError} if `itemSchema` validation fails for an item.\n * @throws {@link BCClientError} on any other ky or unknown error.\n */\n async collect<TItem = unknown, TQuery extends Query = Query>(\n path: string,\n options?: CollectOptions<TItem, TQuery>,\n ): Promise<TItem[]> {\n const items: TItem[] = [];\n\n for await (const { data, err } of this.stream(path, options)) {\n if (err) {\n throw err;\n } else {\n items.push(data);\n }\n }\n\n return items;\n }\n\n /**\n * Fetches all pages from a v2 flat-array endpoint and collects items into an array.\n *\n * Pagination is discovered dynamically — pages are fetched in batches until an empty page,\n * a 404, or a 204 response is received. No prior knowledge of total count is required.\n *\n * Use {@link streamBlind} to process items lazily without buffering the full result set.\n *\n * @param path - API path relative to the store's versioned base URL (always requests v2).\n * @param options - Ky options are forwarded to page requests.\n * @param options.query - Query parameters. `query.limit` controls page size (default 250,\n * must be > 0). `query.page` sets the starting page (default 1, must be > 0).\n * @param options.querySchema - StandardSchemaV1 schema to validate `query`. Requires `query`\n * to be provided.\n * @param options.itemSchema - StandardSchemaV1 schema to validate each returned item.\n * @param options.maxPages - Maximum number of pages to fetch before stopping (default 500,\n * must be > 0). A warning is logged if this limit is reached.\n * @param options.concurrency - Max concurrent page requests per batch. Must be 1–1000.\n * `false` for sequential. Defaults to `config.concurrency`, or 10 if not set on the client.\n * @param options.rateLimitBackoff - Concurrency cap on 429 responses. Defaults to\n * `config.rateLimitBackoff`, or 1 if not set on the client.\n * @param options.backoff - Divisor (or function) applied to concurrency on error responses.\n * Defaults to `config.backoff`, or 2 if not set on the client.\n * @param options.backoffRecover - Amount (or function) added to concurrency per successful\n * response. Defaults to `config.backoffRecover`, or 1 if not set on the client.\n * @returns All items across all pages.\n *\n * @throws {@link BCPaginatedOptionError} if `query.limit`, `query.page`, or `maxPages` is not a positive number.\n * @throws {@link BCQueryValidationError} if `querySchema` validation fails.\n * @throws {@link BCPaginatedItemValidationError} if `itemSchema` validation fails for an item.\n * @throws {@link BCClientError} if a page returns a non-array response, or on any other error.\n * @throws {@link BCApiError} on non-terminating HTTP error responses.\n * @throws {@link BCTimeoutError} if a request times out.\n * @throws {@link BCResponseParseError} if a response body cannot be parsed.\n */\n async collectBlind<TItem = unknown, TQuery extends Query = Query>(\n path: string,\n options?: BlindOptions<TItem, TQuery>,\n ): Promise<TItem[]> {\n const results: TItem[] = [];\n\n for await (const { err, data } of this.streamBlind(path, options)) {\n if (err) {\n throw err;\n } else {\n results.push(data);\n }\n }\n\n return results;\n }\n\n /**\n * Lazily streams items from a v2 flat-array endpoint, page by page.\n *\n * Pagination is discovered dynamically — pages are fetched in concurrent batches until an\n * empty page, a 404, or a 204 response is received. No prior knowledge of total count is\n * required. Each item is yielded as a {@link Result}: `Ok(item)` on success or\n * `Err(error)` for item-level validation failures and non-terminating page errors.\n *\n * Use {@link collectBlind} to buffer all results into an array (throws on any error).\n *\n * @param path - API path relative to the store's versioned base URL (always requests v2).\n * @param options - Ky options are forwarded to page requests.\n * @param options.query - Query parameters. `query.limit` controls page size (default 250,\n * must be > 0). `query.page` sets the starting page (default 1, must be > 0).\n * @param options.querySchema - StandardSchemaV1 schema to validate `query`. Requires `query`\n * to be provided.\n * @param options.itemSchema - StandardSchemaV1 schema to validate each returned item.\n * @param options.maxPages - Maximum number of pages to fetch before stopping (default 500,\n * must be > 0). A warning is logged if this limit is reached.\n * @param options.concurrency - Max concurrent page requests per batch. Must be 1–1000.\n * `false` for sequential. Defaults to `config.concurrency`, or 10 if not set on the client.\n * @param options.rateLimitBackoff - Concurrency cap on 429 responses. Defaults to\n * `config.rateLimitBackoff`, or 1 if not set on the client.\n * @param options.backoff - Divisor (or function) applied to concurrency on error responses.\n * Defaults to `config.backoff`, or 2 if not set on the client.\n * @param options.backoffRecover - Amount (or function) added to concurrency per successful\n * response. Defaults to `config.backoffRecover`, or 1 if not set on the client.\n *\n * @throws {@link BCPaginatedOptionError} if `query.limit`, `query.page`, or `maxPages` is not a positive number.\n * @throws {@link BCQueryValidationError} if `querySchema` validation fails.\n *\n * @yields `Ok(item)` for each successfully fetched and validated item.\n * @yields `Err(BCPaginatedItemValidationError)` when `itemSchema` rejects an item.\n * @yields `Err(BCClientError)` when a page returns a non-array response.\n * @yields `Err(error)` for non-terminating page errors (e.g. non-404/204 HTTP errors).\n */\n async *streamBlind<TItem = unknown, TQuery extends Query = Query>(\n path: string,\n options?: BlindOptions<TItem, TQuery>,\n ): AsyncGenerator<Result<TItem, BaseError>> {\n const {\n query: rawQuery,\n querySchema,\n itemSchema,\n maxPages: rawMaxPages,\n concurrency: rawConcurrency,\n rateLimitBackoff,\n backoff,\n backoffRecover,\n ...requestOptions\n } = options ?? {};\n\n const concurrencyOptions = { concurrency: rawConcurrency, rateLimitBackoff, backoff, backoffRecover };\n\n const concurrency = this.validateConcurrency(this.config.concurrency ?? rawConcurrency ?? DEFAULT_CONCURRENCY);\n\n const query = await this.validate(rawQuery, querySchema, BCQueryValidationError, 'GET', path);\n const page = this.validatePaginationOption(path, 'page', query?.page ?? 1);\n const limit = this.validatePaginationOption(path, 'limit', query?.limit ?? DEFAULT_LIMIT);\n const maxPages = this.validatePaginationOption(path, 'maxPages', rawMaxPages ?? DEFAULT_MAX_BLIND_PAGES);\n\n let done = false;\n let currentPage = page;\n\n do {\n if (currentPage > maxPages) {\n this.logger?.warn({ currentPage }, 'Blind pagination reached maxPages before the end of the data');\n break;\n }\n\n const batchSize = concurrency || 1;\n const pageRequests = Array.from({ length: batchSize }, (_, i) => currentPage + i).map((page) =>\n req.get(path, {\n ...requestOptions,\n version: 'v2',\n query: {\n ...query,\n page,\n limit,\n },\n }),\n );\n\n currentPage += batchSize;\n\n const pages = await this.batchSafe(pageRequests, concurrencyOptions);\n\n for (const { err, data } of pages) {\n if (err) {\n done =\n (err instanceof BCApiError && err.context.status === 404) ||\n (err instanceof BCResponseParseError &&\n err.context.rawBody === '' &&\n err.context.status === 204);\n\n if (!done) {\n yield Err(err);\n }\n } else {\n if (Array.isArray(data)) {\n if (data.length === 0) {\n done = true;\n break;\n }\n\n for (const item of data) {\n yield this.validatePaginatedItem(path, item, itemSchema);\n }\n } else {\n yield Err(\n new BCClientError('Received non array response from blind pagination page endpoint', {\n data,\n path,\n }),\n );\n }\n }\n }\n } while (!done);\n }\n\n /**\n * Executes multiple requests concurrently and returns all results as {@link Result} values,\n * never throwing. Errors from individual requests are captured as `Err` results.\n *\n * Use {@link batchStream} to process results as they arrive rather than waiting for all.\n *\n * @param requests - Array of request descriptors built with the {@link req} helpers.\n * @param options.concurrency - Max concurrent requests. Must be 1–1000. `false` for\n * sequential. Defaults to `config.concurrency`, or 10 if not set on the client.\n * @param options.rateLimitBackoff - Concurrency cap on 429 responses. Defaults to\n * `config.rateLimitBackoff`, or 1 if not set on the client.\n * @param options.backoff - Divisor (or function) applied to concurrency on error responses.\n * Defaults to `config.backoff`, or 2 if not set on the client.\n * @param options.backoffRecover - Amount (or function) added to concurrency per successful\n * response. Defaults to `config.backoffRecover`, or 1 if not set on the client.\n *\n * @returns Results in the order requests complete (not necessarily input order).\n */\n async batchSafe<TRes = unknown, TBody = unknown, TQuery extends Query = Query>(\n requests: BatchRequestOptions<TBody, TRes, TQuery>[],\n options?: ConcurrencyOptions,\n ): Promise<Result<TRes, BaseError>[]> {\n const results: Result<TRes, BaseError>[] = [];\n\n for await (const res of this.batchStream(requests, options)) {\n results.push(res);\n }\n\n return results;\n }\n\n /**\n * Streams all items from a v3 paginated endpoint, fetching the first page sequentially\n * and remaining pages concurrently via {@link batchStream}.\n *\n * Each yielded value is a {@link Result} — check `err` before using `data`. Use\n * {@link collect} to gather all items into an array.\n *\n * @param path - API path relative to the store's versioned base URL.\n * @param options - Ky options are forwarded to page requests.\n * @param options.query - Query parameters. `query.limit` controls page size (default 250,\n * must be > 0). `query.page` sets the starting page (default 1, must be > 0). If the API\n * enforces a different limit, the actual `per_page` from the first response is used for\n * subsequent pages.\n * @param options.querySchema - StandardSchemaV1 schema to validate `query`. Requires `query`\n * to be provided.\n * @param options.itemSchema - StandardSchemaV1 schema to validate each returned item.\n * @param options.concurrency - Max concurrent page requests for pages after the first.\n * Must be 1–1000. `false` for sequential. Defaults to `config.concurrency`, or 10 if not\n * set on the client.\n * @param options.rateLimitBackoff - Concurrency cap on 429 responses. Defaults to\n * `config.rateLimitBackoff`, or 1 if not set on the client.\n * @param options.backoff - Divisor (or function) applied to concurrency on error responses.\n * Defaults to `config.backoff`, or 2 if not set on the client.\n * @param options.backoffRecover - Amount (or function) added to concurrency per successful\n * response. Defaults to `config.backoffRecover`, or 1 if not set on the client.\n * @throws {@link BCPaginatedOptionError} if `query.limit` or `query.page` is not a positive number.\n * @throws {@link BCQueryValidationError} if `querySchema` validation fails.\n */\n async *stream<TItem = unknown, TQuery extends Query = Query>(\n path: string,\n options?: CollectOptions<TItem, TQuery>,\n ): AsyncGenerator<Result<TItem, BaseError>> {\n const { query, querySchema, itemSchema, ...requestOptions } = options ?? {};\n\n let limit = this.validatePaginationOption(path, 'limit', query?.limit ?? DEFAULT_LIMIT);\n const page = this.validatePaginationOption(path, 'page', query?.page ?? 1);\n\n const validatedQuery = await this.validate(\n query,\n querySchema,\n BCQueryValidationError,\n 'GET',\n path,\n 'Invalid query parameters',\n );\n\n let firstPageMeta: V3Resource<unknown[]>['meta'];\n\n try {\n const firstPage = await this.get(path, {\n ...requestOptions,\n query: {\n ...validatedQuery,\n page,\n limit,\n } as unknown as TQuery,\n });\n\n const { data, meta } = this.assertPaginatedResponse(path, firstPage);\n\n firstPageMeta = meta;\n\n // Validate and return the first page\n for (const item of data) {\n yield this.validatePaginatedItem(path, item, itemSchema);\n }\n } catch (err) {\n if (err instanceof BaseError) {\n yield Err(err);\n } else {\n yield Err(new BCClientError('Unknown error occurred fetching first page', {}, { cause: err }));\n }\n\n return;\n }\n\n const { total_pages, per_page } = firstPageMeta.pagination;\n\n if (limit !== per_page) {\n this.logger?.warn({ limit, actual: per_page }, 'API enforces alternate limit on this endpoint');\n limit = per_page;\n }\n\n // Fetch other pages using batchStream\n const requests = Array.from({ length: total_pages - page }, (_, i) => i + page + 1).map((page) => ({\n method: 'GET' as const,\n path,\n ...requestOptions,\n query: {\n ...validatedQuery,\n limit,\n page,\n },\n }));\n\n for await (const pageRes of requests.length > 0 ? this.batchStream(requests, options) : []) {\n const { data: page, err } = pageRes;\n\n if (err) {\n yield Err(err);\n continue;\n }\n\n try {\n const { data } = this.assertPaginatedResponse(path, page);\n\n for (const item of data) {\n yield this.validatePaginatedItem(path, item, itemSchema);\n }\n } catch (err) {\n if (err instanceof BaseError) {\n yield Err(err);\n } else {\n yield Err(new BCClientError('Unknown error occured processing page', {}, { cause: err }));\n }\n }\n }\n }\n\n /**\n * Executes multiple requests with configurable concurrency, yielding each result as a\n * {@link Result} as it completes. Errors from individual requests are yielded as `Err`\n * results rather than thrown.\n *\n * Automatically adjusts concurrency up/down in response to rate-limit and error responses.\n * Use {@link batchSafe} to collect all results into an array.\n *\n * **Caution:** the generator is making requests concurrently. As a consequence if a\n * request is mutating the remote (POST, DELETE) and `for await` loop is exited early,\n * the in-flight request may or may not commit the mutation, and the results of\n * these request WILL NOT be yielded. If you do intent to break the loop early and want to\n * get all the results, set `concurrency: false` to trade concurrency for deterministic behavior.\n *\n * @param requests - Array of request descriptors built with the {@link req} helpers.\n * @param options.concurrency - Max concurrent requests. Must be 1–1000. `false` for\n * sequential. Defaults to `config.concurrency`, or 10 if not set on the client.\n * @param options.rateLimitBackoff - Concurrency cap on 429 responses. Defaults to\n * `config.rateLimitBackoff`, or 1 if not set on the client.\n * @param options.backoff - Divisor (or function) applied to concurrency on error responses.\n * Defaults to `config.backoff`, or 2 if not set on the client.\n * @param options.backoffRecover - Amount (or function) added to concurrency per successful\n * response. Defaults to `config.backoffRecover`, or 1 if not set on the client.\n */\n async *batchStream<TRes = unknown, TBody = unknown, TQuery extends Query = Query>(\n requests: BatchRequestOptions<TBody, TRes, TQuery>[],\n options?: ConcurrencyOptions,\n ): AsyncGenerator<Result<TRes, BaseError>> {\n const resolved = this.resolveStreamOptions(options);\n\n if (resolved.concurrency) {\n const limit = pLimit({ concurrency: resolved.concurrency, rejectOnClear: true });\n const client = this.makeStreamClient(limit, resolved);\n const channel = new AsyncChannel<Result<TRes, BaseError>>();\n\n try {\n Promise.all(\n requests.map((req) =>\n limit(() =>\n this.request(req.path, req, client).then(\n (val) => channel.push(Ok(val)),\n (err) => channel.push(Err(err)),\n ),\n ),\n ),\n )\n .catch((err) => this.logger?.warn({ err }, 'In-flight concurrent requests aborted'))\n .finally(() => channel.close());\n\n for await (const item of channel) {\n yield item;\n }\n } finally {\n limit.clearQueue();\n }\n } else {\n for (const request of requests) {\n try {\n const res = await this.request(request.path, request);\n\n yield Ok(res);\n } catch (err) {\n if (err instanceof BaseError) {\n yield Err(err);\n } else {\n yield Err(new BCClientError('Unknown error in batchStream', {}, { cause: err }));\n }\n }\n }\n }\n }\n\n private async validatePaginatedItem<TItem>(\n path: string,\n item: unknown,\n schema?: StandardSchemaV1<TItem>,\n ): Promise<Result<TItem, BaseError>> {\n if (!schema) {\n return Ok(item as TItem);\n }\n\n const result = await schema['~standard'].validate(item);\n\n if (result.issues) {\n return Err(new BCPaginatedItemValidationError('Page item validation failed', 'GET', path, item, result));\n } else {\n return Ok(result.value);\n }\n }\n\n private assertPaginatedResponse(path: string, res: unknown): V3Resource<unknown[]> {\n if (typeof res !== 'object' || res === null) {\n throw new BCPaginatedResponseError(path, res, 'Response is invalid');\n }\n\n if (!('data' in res) || !Array.isArray(res.data)) {\n throw new BCPaginatedResponseError(\n path,\n res,\n 'response.data must be an array, ensure this endpoint returns a v3 collection',\n );\n }\n\n if (!('meta' in res) || typeof res.meta !== 'object' || res.meta === null || !('pagination' in res.meta)) {\n throw new BCPaginatedResponseError(path, res, 'response.meta is invalid unable to paginate');\n }\n\n const pagination = res.meta.pagination;\n\n if (typeof pagination !== 'object' || pagination === null) {\n throw new BCPaginatedResponseError(path, res, 'response.meta.pagination is invalid unable to paginate');\n }\n\n const requiredFields: Array<[string, (v: unknown) => boolean]> = [\n ['per_page', (v) => typeof v === 'number' && v > 0],\n ['total_pages', (v) => typeof v === 'number' && v >= 0],\n ];\n\n for (const [field, isValid] of requiredFields) {\n if (!(field in pagination) || !isValid(pagination[field as keyof typeof pagination])) {\n throw new BCPaginatedResponseError(\n path,\n res,\n `response.meta.pagination.${field} is missing or invalid`,\n );\n }\n }\n\n const { links } = pagination as { links?: unknown };\n\n if (typeof links !== 'object' || links === null) {\n throw new BCPaginatedResponseError(path, res, 'response.meta.pagination.links is missing or invalid');\n }\n\n const isNullableString = (v: unknown) => v === null || typeof v === 'string';\n\n if (!('current' in links) || typeof links.current !== 'string') {\n throw new BCPaginatedResponseError(\n path,\n res,\n 'response.meta.pagination.links.current is missing or invalid',\n );\n }\n\n if ('next' in links && !isNullableString(links.next)) {\n throw new BCPaginatedResponseError(path, res, 'response.meta.pagination.links.next is invalid');\n }\n\n if ('previous' in links && !isNullableString(links.previous)) {\n throw new BCPaginatedResponseError(path, res, 'response.meta.pagination.links.previous is invalid');\n }\n\n return res as V3Resource<unknown[]>;\n }\n\n private validatePaginationOption(path: string, key: string, value: unknown): number {\n if (typeof value !== 'number' || value <= 0) {\n throw new BCPaginatedOptionError(path, value, key);\n }\n\n return value;\n }\n\n private resolveStreamOptions(options?: ConcurrencyOptions): ResolvedConcurrencyOptions {\n return {\n concurrency: options?.concurrency ?? this.config.concurrency ?? DEFAULT_CONCURRENCY,\n rateLimitBackoff: options?.rateLimitBackoff ?? this.config.rateLimitBackoff ?? DEFAULT_RATE_LIMIT_BACKOFF,\n backoff: options?.backoff ?? this.config.backoff ?? DEFAULT_BACKOFF_RATE,\n backoffRecover: options?.backoffRecover ?? this.config.backoffRecover ?? DEFAULT_BACKOFF_RECOVER,\n };\n }\n\n private makeStreamClient(limit: LimitFunction, options: ResolvedConcurrencyOptions): KyInstance {\n const { concurrency, rateLimitBackoff, backoff, backoffRecover } = options;\n\n if (concurrency === false) {\n return this.client;\n }\n\n return this.client.extend({\n hooks: {\n beforeRetry: [\n ({ error }) => {\n if (!isHTTPError(error)) {\n return;\n }\n\n const previousConcurrency = limit.concurrency;\n\n if (error.response.status === 429) {\n limit.concurrency = rateLimitBackoff;\n\n this.logger?.warn(\n { previousConcurrency, newConcurrency: limit.concurrency },\n 'Rate limit reached, limiting concurrency',\n );\n } else {\n const rate =\n typeof backoff === 'function'\n ? backoff(limit.concurrency, error.response.status)\n : backoff;\n\n limit.concurrency = Math.ceil(limit.concurrency / rate);\n\n this.logger?.warn(\n { previousConcurrency, newConcurrency: limit.concurrency },\n 'Intermittent errors, limiting concurrency to compensate',\n );\n }\n },\n ],\n afterResponse: [\n (_request, _options, response) => {\n if (response.ok && limit.concurrency < concurrency) {\n const recover =\n typeof backoffRecover === 'function'\n ? backoffRecover(limit.concurrency)\n : backoffRecover;\n\n limit.concurrency = Math.min(concurrency, limit.concurrency + recover);\n }\n },\n ],\n },\n });\n }\n\n private async request<TBody, TRes, TQuery extends Query = Query>(\n _path: string,\n options: RequestOptions<TBody, TRes, TQuery>,\n client?: KyInstance,\n ) {\n const { version, query, body, bodySchema, querySchema, responseSchema, ...kyOptions } = options;\n\n const path = this.makePath(options.version ?? 'v3', _path);\n const validQuery = await this.validate(\n query,\n querySchema,\n BCQueryValidationError,\n options.method,\n path,\n 'Invalid query parameters',\n );\n const validBody = await this.validate(\n body,\n bodySchema,\n BCRequestBodyValidationError,\n options.method,\n path,\n `Invalid ${options.method} request body`,\n );\n\n let response: KyResponse;\n\n try {\n response = await (client ?? this.client)(path, {\n ...kyOptions,\n method: options.method,\n searchParams: toUrlSearchParams(validQuery),\n json: validBody,\n });\n } catch (err) {\n if (err instanceof BaseError) {\n throw err;\n }\n\n if (isHTTPError(err)) {\n const requestBody = await err.request.text().catch(() => '');\n const responseBody = await err.response.text().catch(() => '');\n const error = new BCApiError(err, requestBody, responseBody);\n\n this.logger?.error(error.context, 'Request failed');\n\n throw error;\n }\n\n if (isTimeoutError(err)) {\n const error = new BCTimeoutError(err);\n\n this.logger?.error(error.context, 'Request timed out');\n\n throw error;\n }\n\n if (isKyError(err)) {\n throw new BCClientError('Client error', undefined, err);\n }\n\n throw new BCClientError('Unknown error', undefined, err);\n }\n\n let text: string;\n\n try {\n text = await response.text();\n } catch (err) {\n throw new BCResponseParseError(options.method, path, response.status, err, query, '');\n }\n\n let res: TRes;\n\n try {\n res = JSON.parse(text);\n } catch (err) {\n throw new BCResponseParseError(options.method, path, response.status, err, query, text);\n }\n\n this.logger?.debug(\n { method: options.method, url: response.url, status: response.status },\n 'Successful request',\n );\n\n return this.validate(\n res,\n responseSchema,\n BCResponseValidationError,\n options.method,\n path,\n 'Invalid API response',\n );\n }\n\n private async validate<T>(\n data: unknown,\n schema: StandardSchemaV1<T> | undefined,\n ErrorClass: new (\n message: string,\n method: string,\n path: string,\n data: unknown,\n error: StandardSchemaV1.FailureResult,\n ) => BCSchemaValidationError,\n method: string,\n path: string,\n message?: string,\n ): Promise<T> {\n if (!schema) {\n return data as T;\n }\n\n const result = await schema['~standard'].validate(data);\n\n if (result.issues) {\n throw new ErrorClass(message ?? 'Validation failed', method, path, data, result);\n }\n\n return result.value;\n }\n\n private makePath(version: ApiVersion, route: string): string {\n return `stores/${this.storeHash}/${version}/${route.replace(LEADING_SLASHES, '')}`;\n }\n\n private validateConfig() {\n const { accessToken, storeHash } = this.config;\n const errors: string[] = [];\n\n // Using reasonable assumptions about these credentials for validation.\n // This will not verify the credentials but at least guard against providing\n // something completely invalid like empty string\n if (typeof storeHash !== 'string' || storeHash.length <= 0) {\n errors.push('storeHash is empty');\n }\n\n if (typeof accessToken !== 'string' || accessToken.length <= 0) {\n errors.push('accessToken is empty');\n }\n\n if (this.config.prefixUrl) {\n try {\n new URL(this.config.prefixUrl);\n } catch (err) {\n throw new BCClientError('Invalid prefixUrl', undefined, err);\n }\n }\n\n try {\n this.validateConcurrency(this.config.concurrency);\n } catch (err) {\n if (err instanceof BCClientError) {\n errors.push(err.message);\n } else {\n throw err;\n }\n }\n\n if (errors.length > 0) {\n throw new BCCredentialsError(errors);\n }\n }\n\n private validateConcurrency(concurrency: number | undefined | false) {\n if (concurrency === undefined) {\n return;\n }\n\n if (concurrency === false) {\n return concurrency;\n }\n\n if (concurrency <= 0 || concurrency > MAX_CONCURRENCY) {\n throw new BCClientError(`Invalid concurrency: allowed range (1:${MAX_CONCURRENCY})`, undefined);\n }\n\n return concurrency;\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../src/lib/common.ts","../src/lib/errors.ts","../src/lib/logger.ts","../src/auth.ts","../src/lib/util.ts","../src/lib/hooks.ts","../src/lib/request.ts","../src/lib/result.ts","../src/client.ts"],"sourcesContent":["import type { Options as KyOptions } from 'ky';\nimport type { LimitFunction } from 'p-limit';\nimport type { Logger, LogLevel } from './logger';\n\nexport type { Logger, LogLevel };\n\nexport type ConcurrencyOptions = {\n /** Max concurrent requests. Must be 1–1000. `false` for sequential. Defaults to 10. */\n concurrency?: number | false;\n /**\n * Divisor (or `(concurrency, status) => number` function) applied to concurrency on\n * non-429 error responses. Defaults to 2.\n */\n backoff?: ((concurrency: number, status: number) => number) | number;\n /** Concurrency cap applied when a 429 response is received. Defaults to 1. */\n rateLimitBackoff?: number;\n /**\n * Amount (or `(concurrency) => number` function) added to concurrency per successful\n * response while below the configured max. Defaults to 1.\n */\n backoffRecover?: ((concurrency: number) => number) | number;\n /**\n * A p-limit instance to reuse across calls. When provided, `batchStream` uses it instead of\n * creating a new one, allowing callers to observe and react to live concurrency changes.\n */\n pLimit?: LimitFunction;\n};\n\n/** Maximum allowed concurrency value. */\nexport const MAX_CONCURRENCY = 1000;\n/** Default concurrency for batch/stream operations. */\nexport const DEFAULT_CONCURRENCY = 10;\n/** Default concurrency cap on 429 rate-limit responses. */\nexport const DEFAULT_RATE_LIMIT_BACKOFF = 1;\n/** Default divisor applied to concurrency on non-429 errors. */\nexport const DEFAULT_BACKOFF_RATE = 2;\n/** Default amount added to concurrency per successful response. */\nexport const DEFAULT_BACKOFF_RECOVER = 1;\n/** Default page size for paginated requests. */\nexport const DEFAULT_LIMIT = 250;\n/** Maximum allowed URL length before chunking is required. */\nexport const MAX_URL_LENGTH = 2048;\n/** Regex to strip leading slashes from API paths. */\nexport const LEADING_SLASHES = /^\\/+/;\n/** Maximum pages to fetch during blind pagination **/\nexport const DEFAULT_MAX_BLIND_PAGES = 500;\n\n/**\n * Configuration options for the BigCommerce client.\n */\nexport interface ClientConfig\n extends Omit<KyOptions, 'throwHttpErrors' | 'parseJson' | 'method' | 'body' | 'json' | 'searchParams'>,\n ConcurrencyOptions {\n storeHash: string;\n accessToken: string;\n logger?: Logger | LogLevel | boolean;\n}\n\n/**\n * Random positive jitter within 0-500 ms in increments of 100\n * @param {number} delay\n */\nexport const rateLimitJitter = (delay: number) => delay + Math.floor(Math.random() * 6) * 100;\n\n/**\n * HTTP header names used by the BigCommerce API.\n */\nexport const HEADERS = {\n AUTH_TOKEN: 'X-Auth-Token',\n ACCEPT: 'Accept',\n CONTENT_TYPE: 'Content-Type',\n RATE_LIMIT_LEFT: 'x-rate-limit-requests-left',\n RATE_LIMIT_RESET: 'x-rate-limit-time-reset-ms',\n RATE_LIMIT_QUOTA: 'x-rate-limit-requests-quota',\n RATE_LIMIT_WINDOW: 'x-rate-limit-time-window-ms',\n} as const;\n\n/**\n * Metadata extracted from rate-limit headers in API responses.\n */\nexport type RateLimitMeta = {\n /** Time in milliseconds until the rate limit resets. */\n resetIn: number;\n /** Number of requests remaining in the current window. */\n requestsLeft?: number;\n /** Total request quota for the current window. */\n quota?: number;\n /** Time window size in milliseconds. */\n window?: number;\n};\n\n/**\n * Default configuration for the underlying ky HTTP client.\n */\nexport const BASE_KY_CONFIG = {\n prefixUrl: 'https://api.bigcommerce.com',\n throwHttpErrors: true,\n // Some BC endpoints may take a while.\n // For example /catalog/product/options* endpoints may fully\n // recreate all variants in some cases\n timeout: 120e3,\n\n retry: {\n limit: 3,\n // BC uses PUT for many upsert operations, it's not guaranteed to be idempotent\n methods: ['GET', 'DELETE'],\n statusCodes: [429, 500, 502, 503, 504],\n // BC does not send standart Retry-After. We'll use custom beforeRetry hook\n afterStatusCodes: [],\n jitter: true,\n maxRetryAfter: 120e3,\n },\n\n headers: {\n [HEADERS.ACCEPT]: 'application/json',\n [HEADERS.CONTENT_TYPE]: 'application/json',\n },\n};\n\n/**\n * Concurrency options with all values resolved to their defaults.\n */\nexport type ResolvedConcurrencyOptions = Required<Omit<ConcurrencyOptions, 'pLimit'>> &\n Pick<ConcurrencyOptions, 'pLimit'>;\n","import type { HTTPError, KyRequest, TimeoutError as KyTimeoutError } from 'ky';\nimport type { Query } from './request';\nimport type { StandardSchemaV1 } from './standard-schema';\n\nexport type ErrorContext = Record<string, unknown>;\n\n/**\n * Abstract base class for all library errors. Carries a typed `context` object with\n * structured diagnostic data and a machine-readable `code` string.\n *\n * Use `instanceof` checks against specific subclasses rather than this base class.\n */\nexport abstract class BaseError<TContext extends ErrorContext = ErrorContext> extends Error {\n /** Machine-readable error code. Unique per subclass. */\n abstract readonly code: string;\n\n constructor(\n message: string,\n readonly context: TContext,\n options?: ErrorOptions,\n ) {\n super(message, options);\n\n this.name = this.constructor.name;\n }\n\n /** @internal */\n toJSON() {\n return {\n name: this.name,\n code: this.code,\n message: this.message,\n context: this.context,\n cause: this.cause,\n };\n }\n}\n\n/** Catch-all for unexpected client-side errors not covered by a more specific subclass. */\nexport class BCClientError extends BaseError<Record<string, unknown>> {\n code = 'BC_CLIENT_ERROR';\n\n constructor(message: string, context?: Record<string, unknown>, cause?: unknown) {\n super(message, context ?? {}, { cause });\n }\n}\n\n/** Thrown by the {@link BigCommerceClient} constructor when credentials or config are invalid. */\nexport class BCCredentialsError extends BaseError<{\n errors: string[];\n}> {\n code = 'BC_CLIENT_CREDENTIALS_ERROR';\n\n constructor(errors: string[]) {\n super('Failed to initialize BigCommerceClient', { errors });\n }\n}\n\n/** Thrown before a request is sent when the constructed URL exceeds 2048 characters. */\nexport class BCUrlTooLongError extends BaseError<{\n url: string;\n max: number;\n len: number;\n}> {\n code = 'BC_URL_TOO_LONG';\n\n constructor(url: string, max: number) {\n super(`Url length (${url.length}) exceeds max allowed length of ${max}`, { url, max, len: url.length });\n }\n}\n\n/**\n * Thrown during retry when a 429 response is received but the expected\n * `X-Rate-Limit-*` headers are absent, making it impossible to determine the backoff delay.\n */\nexport class BCRateLimitNoHeadersError extends BaseError<{\n url: string;\n method: string;\n attempts: number;\n}> {\n code = 'BC_RATE_LIMIT_NO_HEADERS';\n\n constructor(request: KyRequest, attempts: number) {\n super('Rate limit reached but the X-Rate-Limit-* headers were not returned. Unable to retry', {\n url: request.url,\n method: request.method,\n attempts,\n });\n }\n}\n\n/**\n * Thrown during retry when a 429 response specifies a reset window that exceeds\n * `config.retry.maxRetryAfter`, preventing an unbounded wait.\n */\nexport class BCRateLimitDelayTooLongError extends BaseError<{\n url: string;\n method: string;\n attempts: number;\n maxDelay: number;\n delay: number;\n}> {\n code = 'BC_RATE_LIMIT_DELAY_TOO_LONG';\n\n constructor(request: KyRequest, attempts: number, maxDelay: number, delay: number) {\n super('Rate limit reached, and the rate limit reset window is too high.', {\n url: request.url,\n method: request.method,\n attempts,\n maxDelay,\n delay,\n });\n }\n}\n\n/**\n * Abstract base for all StandardSchema validation errors. Carries the raw `data` that failed\n * validation and the schema `error` result. Use specific subclasses for `instanceof` checks.\n */\nexport abstract class BCSchemaValidationError extends BaseError<{\n method: string;\n path: string;\n data: unknown;\n error: StandardSchemaV1.FailureResult;\n}> {\n constructor(message: string, method: string, path: string, data: unknown, error: StandardSchemaV1.FailureResult) {\n super(message, { method, path, data, error });\n }\n}\n\n/** Thrown when `options.querySchema` validation fails before a request is sent. */\nexport class BCQueryValidationError extends BCSchemaValidationError {\n code = 'BC_QUERY_VALIDATION_FAILED';\n}\n\n/** Thrown when `options.bodySchema` validation fails before a request is sent. */\nexport class BCRequestBodyValidationError extends BCSchemaValidationError {\n code = 'BC_REQUEST_BODY_VALIDATION_FAILED';\n}\n\n/** Thrown when `options.responseSchema` validation fails after a response is received. */\nexport class BCResponseValidationError extends BCSchemaValidationError {\n code = 'BC_RESPONSE_VALIDATION_FAILED';\n}\n\n/** Thrown or yielded when `options.itemSchema` validation fails for an item in a page response. */\nexport class BCPaginatedItemValidationError extends BCSchemaValidationError {\n code = 'BC_PAGINATED_ITEM_VALIDATION_FAILED';\n}\n\n/**\n * Thrown when the BigCommerce API returns a non-2xx HTTP response.\n * `context.status` and `context.responseBody` are the most useful fields for debugging.\n */\nexport class BCApiError extends BaseError<{\n method: string;\n url: string;\n status: number;\n statusMessage: string;\n headers: Record<string, string>;\n requestBody: string;\n responseBody: string;\n}> {\n code = 'BC_API_ERROR';\n\n constructor(err: HTTPError, requestBody: string, responseBody: string) {\n const { request, response } = err;\n\n super('BigCommerce API request failed', {\n method: request.method,\n url: request.url,\n status: response.status,\n statusMessage: response.statusText,\n headers: Object.fromEntries(response.headers as unknown as Iterable<[string, string]>),\n requestBody,\n responseBody,\n });\n }\n}\n\n/** Thrown when a request exceeds the configured timeout (default 120 s). */\nexport class BCTimeoutError extends BaseError<{\n method: string;\n url: string;\n}> {\n code = 'BC_TIMEOUT_ERROR';\n\n constructor(err: KyTimeoutError) {\n super('BigCommerce API request timed out', {\n method: err.request.method,\n url: err.request.url,\n });\n }\n}\n\n/**\n * Thrown when the response body cannot be read or parsed as JSON.\n * `context.rawBody` contains the raw text that failed to parse (empty string if the body was empty).\n */\nexport class BCResponseParseError extends BaseError<{\n method: string;\n status: number;\n path: string;\n query?: Query;\n rawBody?: string;\n}> {\n code = 'BC_RESPONSE_PARSE_ERROR';\n\n constructor(method: string, path: string, status: number, cause: unknown, query?: Query, rawBody?: string) {\n super(\n 'Failed to parse BigCommerce API response',\n {\n status,\n method,\n path,\n query,\n rawBody,\n },\n { cause },\n );\n }\n}\n\n/**\n * Thrown when a pagination option (`limit`, `page`, or `count`) is not a positive number.\n * `context.option` names the offending field; `context.value` is the value that was passed.\n */\nexport class BCPaginatedOptionError extends BaseError<{ path: string; option: string; value: unknown }> {\n code = 'BC_PAGINATED_OPTION_ERROR';\n\n constructor(path: string, value: unknown, option: string) {\n super('The pagination option must be a positive number', { path, option, value });\n }\n}\n\n/**\n * Thrown or yielded when a paginated response is missing required v3 envelope fields\n * (`data`, `meta.pagination`, etc.). Usually means the path is not a v3 collection endpoint.\n */\nexport class BCPaginatedResponseError extends BaseError<{ path: string; data: unknown; reason: string }> {\n code = 'BC_PAGINATED_RESPONSE_ERROR';\n\n constructor(path: string, data: unknown, reason: string) {\n super('Paginated response structure is invalid', { path, data, reason });\n }\n}\n\n/** Thrown by {@link BigCommerceAuth} constructor when `config.redirectUri` is not a valid URL. */\nexport class BCAuthInvalidRedirectUriError extends BaseError<{ redirectUri: string }> {\n code = 'BC_AUTH_INVALID_REDIRECT_URI';\n\n constructor(redirectUri: string, cause: unknown) {\n super('Invalid redirect URI', { redirectUri }, { cause });\n }\n}\n\n/** Thrown by {@link BigCommerceAuth.requestToken} when a required OAuth callback param is absent. */\nexport class BCAuthMissingParamError extends BaseError<{ param: string }> {\n code = 'BC_AUTH_MISSING_PARAM';\n\n constructor(param: string) {\n super(`Missing required auth callback parameter: ${param}`, { param });\n }\n}\n\n/**\n * Thrown by {@link BigCommerceAuth.requestToken} when the scopes granted by BigCommerce\n * do not include all scopes listed in `config.scopes`.\n * `context.missing` lists the scopes that were expected but not granted.\n */\nexport class BCAuthScopeMismatchError extends BaseError<{\n granted: string[];\n expected: string[];\n missing: string[];\n}> {\n code = 'BC_AUTH_SCOPE_MISMATCH';\n\n constructor(granted: string[], expected: string[], missing: string[]) {\n super('Granted scopes do not match expected scopes', { granted, expected, missing });\n }\n}\n\n/** Thrown by {@link BigCommerceAuth.verify} when the JWT signature, audience, issuer, or subject is invalid. */\nexport class BCAuthInvalidJwtError extends BaseError<{ storeHash: string }> {\n code = 'BC_AUTH_INVALID_JWT';\n\n constructor(storeHash: string, cause: unknown) {\n super('Invalid JWT payload', { storeHash }, { cause });\n }\n}\n","import type { ClientConfig } from './common';\n\n/**\n * Logging interface for the BigCommerce client.\n *\n * Implement this interface to provide custom logging. The client passes context data\n * as the first argument, making it compatible with structured loggers.\n */\nexport interface Logger {\n debug(data: Record<string, unknown>, message?: string): void;\n info(data: Record<string, unknown>, message?: string): void;\n warn(data: Record<string, unknown>, message?: string): void;\n error(data: Record<string, unknown>, message?: string): void;\n}\n\nexport type PowertoolsLikeLogger = {\n debug(message: string, ...data: Record<string, unknown>[]): void;\n info(message: string, ...data: Record<string, unknown>[]): void;\n warn(message: string, ...data: Record<string, unknown>[]): void;\n error(message: string, ...data: Record<string, unknown>[]): void;\n};\n\n/** @internal */\nexport const LOG_LEVELS = ['debug', 'info', 'warn', 'error'] as const;\n\n/** Supported log levels. */\nexport type LogLevel = (typeof LOG_LEVELS)[number];\n\n/**\n * Adapts an AWS Lambda Powertools logger to the {@link Logger} interface expected by\n * {@link BigCommerceClient} and {@link BigCommerceAuth}.\n *\n * Powertools loggers use `(message, ...data)` argument order whereas this library uses\n * `(data, message)`. This adapter swaps the arguments.\n *\n * @param logger - An AWS Lambda Powertools (or any {@link PowertoolsLikeLogger}-compatible) logger.\n * @returns A {@link Logger} wrapper suitable for `config.logger`.\n */\nexport const fromAwsPowertoolsLogger = (logger: PowertoolsLikeLogger): Logger => ({\n debug: (data, message) => logger.debug(message ?? '', data),\n info: (data, message) => logger.info(message ?? '', data),\n warn: (data, message) => logger.warn(message ?? '', data),\n error: (data, message) => logger.error(message ?? '', data),\n});\n\n/**\n * Console-based {@link Logger} that filters messages below a minimum level.\n *\n * Used automatically when `config.logger` is `true`, `undefined`, or a {@link LogLevel} string.\n * Can also be instantiated directly for custom log level control.\n *\n * @example\n * ```ts\n * new BigCommerceClient({ ..., logger: new FallbackLogger('debug') });\n * ```\n */\nexport class FallbackLogger implements Logger {\n /**\n * @param level - Minimum level to output. Messages below this level are silently dropped.\n */\n constructor(public readonly level: LogLevel) {}\n\n debug(data: Record<string, unknown>, message?: string): void {\n this.log('debug', data, message);\n }\n\n info(data: Record<string, unknown>, message?: string): void {\n this.log('info', data, message);\n }\n\n warn(data: Record<string, unknown>, message?: string): void {\n this.log('warn', data, message);\n }\n\n error(data: Record<string, unknown>, message?: string): void {\n this.log('error', data, message);\n }\n\n private log(level: LogLevel, data: Record<string, unknown>, message?: string) {\n if (LOG_LEVELS.indexOf(level) < LOG_LEVELS.indexOf(this.level)) {\n return;\n }\n\n const fn = console[level];\n\n message !== undefined ? fn(message, data) : fn(data);\n }\n}\n\n/**\n * @internal\n */\nexport const initLogger = (logger: ClientConfig['logger']): Logger | undefined => {\n if (logger === false) {\n return;\n }\n\n if (logger === undefined || logger === true) {\n return new FallbackLogger('info');\n }\n\n if (typeof logger === 'string') {\n if (LOG_LEVELS.includes(logger)) {\n return new FallbackLogger(logger);\n } else {\n const logger = new FallbackLogger('info');\n\n logger.warn({ level: logger }, 'Unknown log level passed, using info');\n\n return logger;\n }\n }\n\n return logger;\n};\n","import * as jose from 'jose';\nimport ky, { isHTTPError, isTimeoutError } from 'ky';\nimport { BASE_KY_CONFIG } from './lib/common';\nimport {\n BCApiError,\n BCAuthInvalidJwtError,\n BCAuthInvalidRedirectUriError,\n BCAuthMissingParamError,\n BCAuthScopeMismatchError,\n BCClientError,\n BCTimeoutError,\n} from './lib/errors';\nimport { initLogger, type Logger, type LogLevel } from './lib/logger';\n\n/**\n * Configuration options for BigCommerce authentication\n */\nexport type BigCommerceAuthConfig = {\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 /** Optional array of scopes to validate during auth callback */\n scopes?: string[];\n /** Optional logger instance */\n logger?: Logger | LogLevel | boolean;\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 */\nexport type BigCommerceAuthQuery = {\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 private readonly logger: Logger | undefined;\n private readonly client: ReturnType<typeof ky.create>;\n\n /**\n * Creates a new BigCommerceAuth instance for handling OAuth authentication\n * @param config - Configuration options for BigCommerce authentication\n * @param config.clientId - The OAuth client ID from BigCommerce\n * @param config.secret - The OAuth client secret from BigCommerce\n * @param config.redirectUri - The redirect URI registered with BigCommerce\n * @param config.scopes - Optional array of scopes to validate during auth callback\n * @param config.logger - Optional logger instance for debugging and error tracking\n * @throws {BCAuthInvalidRedirectUriError} If the redirect URI is invalid\n */\n constructor(private readonly config: BigCommerceAuthConfig) {\n try {\n new URL(this.config.redirectUri);\n } catch (error) {\n throw new BCAuthInvalidRedirectUriError(this.config.redirectUri, error);\n }\n\n this.logger = initLogger(config.logger);\n\n const { prefixUrl: _, ...authKyConfig } = BASE_KY_CONFIG;\n\n this.client = ky.create({\n ...authKyConfig,\n retry: {\n ...authKyConfig.retry,\n methods: ['POST'],\n },\n });\n }\n\n /**\n * Exchanges an OAuth authorization code for an access token.\n *\n * @param data - The auth callback payload: a raw query string, `URLSearchParams`, or a\n * pre-parsed object with `code`, `scope`, and `context`.\n * @returns The token response including `access_token`, `user`, and `context`.\n * @throws {@link BCAuthMissingParamError} if `code`, `scope`, or `context` are absent.\n * @throws {@link BCAuthScopeMismatchError} if the granted scopes don't include all `config.scopes`.\n * @throws {@link BCApiError} on HTTP error responses from the token endpoint.\n * @throws {@link BCTimeoutError} if the token request times out.\n * @throws {@link BCClientError} on any other error.\n */\n async requestToken(data: string | BigCommerceAuthQuery | URLSearchParams): Promise<TokenResponse> {\n const query = typeof data === 'string' || data instanceof URLSearchParams ? this.parseQueryString(data) : data;\n\n this.validateScopes(query.scope);\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 this.logger?.debug(\n {\n clientId: this.config.clientId,\n context: query.context,\n scopes: query.scope,\n },\n 'Requesting OAuth token',\n );\n\n let res: Response;\n\n try {\n res = await this.client(TOKEN_ENDPOINT, {\n method: 'POST',\n json: tokenRequest,\n });\n } catch (error) {\n if (isHTTPError(error)) {\n const requestBody = await error.request.text().catch(() => '');\n const responseBody = await error.response.text().catch(() => '');\n const err = new BCApiError(error, requestBody, responseBody);\n\n this.logger?.error(err.context, 'Failed to request token');\n\n throw err;\n }\n\n if (isTimeoutError(error)) {\n const err = new BCTimeoutError(error);\n\n this.logger?.error(err.context, 'Token request timed out');\n\n throw err;\n }\n\n throw new BCClientError('Failed to request token', {}, error);\n }\n\n return res.json() as Promise<TokenResponse>;\n }\n\n /**\n * Verifies a JWT payload from BigCommerce\n * @param jwtPayload - The JWT string to verify\n * @param storeHash - The store hash for the BigCommerce store\n * @returns Promise resolving to the verified JWT claims\n * @throws {BCAuthInvalidJwtError} If the JWT is invalid\n */\n async verify(jwtPayload: string, storeHash: string): Promise<Claims> {\n try {\n const secret = new TextEncoder().encode(this.config.secret);\n\n const { payload }: { payload: Claims } = await jose.jwtVerify(jwtPayload, secret, {\n audience: this.config.clientId,\n issuer: ISSUER,\n subject: `stores/${storeHash}`,\n });\n\n this.logger?.debug(\n {\n userId: payload.user?.id,\n storeHash: payload.sub.split('/')[1],\n },\n 'JWT verified successfully',\n );\n\n return payload;\n } catch (error) {\n const err = new BCAuthInvalidJwtError(storeHash, error);\n\n this.logger?.error(err.context, 'JWT verification failed');\n\n throw err;\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 {BCAuthMissingParamError} If required parameters are missing\n */\n private parseQueryString(queryString: string | URLSearchParams): BigCommerceAuthQuery {\n const params = typeof queryString === 'string' ? new URLSearchParams(queryString) : queryString;\n\n const code = params.get('code');\n const scope = params.get('scope');\n const context = params.get('context');\n\n if (!code) {\n throw new BCAuthMissingParamError('code');\n }\n\n if (!scope) {\n throw new BCAuthMissingParamError('scope');\n } else if (this.config.scopes?.length) {\n this.validateScopes(scope);\n }\n\n if (!context) {\n throw new BCAuthMissingParamError('context');\n }\n\n return {\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 {BCAuthScopeMismatchError} 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 granted = scopes.split(' ');\n const expected = this.config.scopes;\n const missing = expected.filter((scope) => !granted.includes(scope));\n\n if (missing.length) {\n throw new BCAuthScopeMismatchError(granted, expected, missing);\n }\n }\n}\n","import { HEADERS, type RateLimitMeta } from './common';\n\nexport function stripKeys<T extends object, K extends PropertyKey>(\n obj: T | undefined,\n keys: K[],\n): Omit<T, K> | undefined {\n if (!obj) {\n return obj;\n }\n\n const result = { ...obj } as Record<PropertyKey, unknown>;\n\n for (const key of keys) {\n delete result[key];\n }\n\n return result as Omit<T, K>;\n}\n\nconst parseIntHeader = (headers: Headers, key: string): number | undefined => {\n const value = Number.parseInt(headers.get(key) ?? '', 10);\n\n return Number.isNaN(value) ? undefined : value;\n};\n\nexport const extractRateLimitHeaders = (headers: Headers): RateLimitMeta | undefined => {\n const resetIn = parseIntHeader(headers, HEADERS.RATE_LIMIT_RESET);\n\n // Can't retry without this header - treat as unrecoverable\n if (resetIn === undefined) {\n return undefined;\n }\n\n return {\n resetIn,\n requestsLeft: parseIntHeader(headers, HEADERS.RATE_LIMIT_LEFT),\n quota: parseIntHeader(headers, HEADERS.RATE_LIMIT_QUOTA),\n window: parseIntHeader(headers, HEADERS.RATE_LIMIT_WINDOW),\n };\n};\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 = encodeURIComponent(item).length;\n const separatorLength = currentChunk.length > 0 ? separatorSize : 0;\n const totalItemLength = itemLength + separatorLength;\n\n const wouldExceedLength = currentStrLength + totalItemLength > maxLength;\n const wouldExceedCount = currentChunk.length >= chunkLength;\n\n if ((wouldExceedLength || wouldExceedCount) && currentChunk.length > 0) {\n chunks.push(currentChunk);\n currentChunk = [];\n currentStrLength = offset;\n }\n\n if (itemLength + offset > maxLength) {\n throw new Error(`Item too large: ${itemLength} exceeds maxLength ${maxLength}`);\n }\n\n currentChunk.push(item);\n currentStrLength += itemLength + (currentChunk.length > 1 ? separatorSize : 0);\n }\n\n if (currentChunk.length > 0) {\n chunks.push(currentChunk);\n }\n\n return chunks;\n};\n\nexport class AsyncChannel<T> {\n private readonly queue: T[] = [];\n private notify: (() => void) | null = null;\n private done = false;\n\n push(item: T) {\n this.queue.push(item);\n this.notify?.();\n this.notify = null;\n }\n\n close() {\n this.done = true;\n this.notify?.();\n this.notify = null;\n }\n\n async *[Symbol.asyncIterator](): AsyncGenerator<T> {\n while (!this.done || this.queue.length > 0) {\n if (this.queue.length === 0) {\n await new Promise<void>((r) => {\n if (this.queue.length > 0) {\n return r();\n }\n\n this.notify = r;\n });\n }\n\n while (this.queue.length > 0) {\n const item = this.queue.shift();\n\n if (item !== undefined) {\n yield item;\n }\n }\n }\n }\n}\n","import { type BeforeRequestHook, type BeforeRetryHook, isHTTPError } from 'ky';\nimport { MAX_URL_LENGTH, rateLimitJitter } from './common';\nimport { BCRateLimitDelayTooLongError, BCRateLimitNoHeadersError, BCUrlTooLongError } from './errors';\nimport type { Logger } from './logger';\nimport { extractRateLimitHeaders } from './util';\n\nexport const validateUrlLength: BeforeRequestHook = (request) => {\n if (request.url.length > MAX_URL_LENGTH) {\n throw new BCUrlTooLongError(request.url, MAX_URL_LENGTH);\n }\n};\n\nexport const bcRateLimitRetry =\n (logger?: Logger): BeforeRetryHook =>\n async ({ request, options, error, retryCount }) => {\n if (isHTTPError(error) && error.response.status === 429) {\n const retryMeta = extractRateLimitHeaders(error.response.headers);\n\n if (!retryMeta) {\n throw new BCRateLimitNoHeadersError(request, retryCount);\n }\n\n if (options.retry.maxRetryAfter && retryMeta.resetIn > options.retry.maxRetryAfter) {\n throw new BCRateLimitDelayTooLongError(\n request,\n retryCount,\n options.retry.maxRetryAfter,\n retryMeta.resetIn,\n );\n }\n\n const delay =\n typeof options.retry.jitter === 'function'\n ? options.retry.jitter(retryMeta.resetIn)\n : rateLimitJitter(retryMeta.resetIn);\n\n logger?.warn(\n { attempt: retryCount, url: request.url, method: request.method, retryMeta },\n `Rate limit reached, retrying in ${delay} (with jitter)`,\n );\n\n await new Promise((resolve) => setTimeout(resolve, delay));\n } else {\n logger?.warn({ url: request.url, method: request.method, attempt: retryCount }, 'Retrying request');\n }\n };\n","import type { Options as KyOptions } from 'ky';\nimport type { ConcurrencyOptions } from './common';\nimport type { StandardSchemaV1 } from './standard-schema';\n\n/** BigCommerce API versions supported by the client. */\nexport type ApiVersion = 'v3' | 'v2';\n\n/** Valid query parameter value types. */\nexport type QueryValue = string | number | Array<string | number>;\n\n/** Query parameter object for API requests. */\nexport type Query = Record<string, QueryValue>;\n\n/**\n * Converts a Query object to URLSearchParams.\n * Array values are joined with commas (e.g., `id:in=1,2,3`).\n */\nexport const toUrlSearchParams = (query?: Query): URLSearchParams | undefined => {\n if (!query) {\n return;\n }\n\n const params = new URLSearchParams();\n\n for (const [key, value] of Object.entries(query)) {\n if (Array.isArray(value)) {\n params.append(key, value.map(String).join(','));\n } else {\n params.append(key, String(value));\n }\n }\n\n return params;\n};\n\n/** Supported HTTP methods for API requests. */\nexport type HttpMethod = 'POST' | 'GET' | 'PUT' | 'DELETE';\n\n/** @internal */\ntype BaseKyRequest = Omit<\n KyOptions,\n 'json' | 'method' | 'searchQueryParams' | 'body' | 'throwHttpErrors' | 'parseJson'\n>;\n\n/** @internal */\ntype QuerySchemaOptions<TQuery extends Query> =\n /** Query parameters to send with the request. */\n { query: TQuery; querySchema: StandardSchemaV1<TQuery> } | { query?: TQuery; querySchema?: never };\n\n/** @internal */\ntype BodySchemaOptions<TBody> =\n /** Request body, serialized as JSON. */\n { body: TBody; bodySchema: StandardSchemaV1<TBody> } | { body?: TBody; bodySchema?: never };\n\n/**\n * Full request options for direct API calls.\n * @see {@link GetOptions}, {@link PostOptions}, {@link PutOptions}, {@link DeleteOptions}\n */\nexport type RequestOptions<TBody, TRes, TQuery extends Query> = BaseKyRequest &\n QuerySchemaOptions<TQuery> &\n BodySchemaOptions<TBody> & {\n /** HTTP method for the request. */\n method: HttpMethod;\n /** API version to use. Defaults to `'v3'`. */\n version?: ApiVersion;\n /** Schema to validate the response body. */\n responseSchema?: StandardSchemaV1<TRes>;\n };\n\n/** Options for GET requests. */\nexport type GetOptions<TRes, TQuery extends Query> = Omit<\n RequestOptions<never, TRes, TQuery>,\n 'body' | 'bodySchema' | 'method'\n>;\n\n/** Options for POST requests. */\nexport type PostOptions<TBody, TRes, TQuery extends Query> = Omit<RequestOptions<TBody, TRes, TQuery>, 'method'>;\n\n/** Options for PUT requests. */\nexport type PutOptions<TBody, TRes, TQuery extends Query> = PostOptions<TBody, TRes, TQuery>;\n\n/** Options for DELETE requests. */\nexport type DeleteOptions<TQuery extends Query> = Omit<\n RequestOptions<never, never, TQuery>,\n 'body' | 'bodySchema' | 'method' | 'responseSchema'\n>;\n\n/**\n * Request descriptor for batch operations.\n * Use the {@link req} helpers to construct these.\n */\nexport type BatchRequestOptions<TBody, TRes, TQuery extends Query> = {\n path: string;\n} & RequestOptions<TBody, TRes, TQuery>;\n\n/**\n * Helpers for building typed request descriptors to pass to\n * {@link BigCommerceClient.batchSafe} or {@link BigCommerceClient.batchStream}.\n *\n * @example\n * ```ts\n * const results = await client.batchSafe([\n * req.get('catalog/products/1'),\n * req.post('catalog/products', { body: { name: 'Widget' } }),\n * ]);\n * ```\n */\nexport const req = {\n /**\n * Builds a GET request descriptor.\n * @param path - API path relative to the store's versioned base URL.\n * @param options - Optional query params, schemas, and ky options.\n */\n get: <TRes, TQuery extends Query = Query>(\n path: string,\n options?: GetOptions<TRes, TQuery>,\n ): BatchRequestOptions<never, TRes, TQuery> =>\n ({ method: 'GET', path, ...options }) as BatchRequestOptions<never, TRes, TQuery>,\n\n /**\n * Builds a POST request descriptor.\n * @param path - API path relative to the store's versioned base URL.\n * @param options - Optional body, query params, schemas, and ky options.\n */\n post: <TRes, TBody = unknown, TQuery extends Query = Query>(\n path: string,\n options?: PostOptions<TBody, TRes, TQuery>,\n ): BatchRequestOptions<TBody, TRes, TQuery> =>\n ({ method: 'POST', path, ...options }) as BatchRequestOptions<TBody, TRes, TQuery>,\n\n /**\n * Builds a PUT request descriptor.\n * @param path - API path relative to the store's versioned base URL.\n * @param options - Optional body, query params, schemas, and ky options.\n */\n put: <TRes, TBody = unknown, TQuery extends Query = Query>(\n path: string,\n options?: PutOptions<TBody, TRes, TQuery>,\n ): BatchRequestOptions<TBody, TRes, TQuery> =>\n ({ method: 'PUT', path, ...options }) as BatchRequestOptions<TBody, TRes, TQuery>,\n\n /**\n * Builds a DELETE request descriptor.\n * @param path - API path relative to the store's versioned base URL.\n * @param options - Optional query params and ky options.\n */\n delete: <TQuery extends Query = Query>(\n path: string,\n options?: DeleteOptions<TQuery>,\n ): BatchRequestOptions<never, never, TQuery> =>\n ({ method: 'DELETE', path, ...options }) as BatchRequestOptions<never, never, TQuery>,\n};\n\n/**\n * Options for v3 paginated collection operations ({@link BigCommerceClient.collect}, {@link BigCommerceClient.stream}).\n */\nexport type CollectOptions<TItem, TQuery extends Query> = ConcurrencyOptions &\n Omit<GetOptions<TItem, TQuery>, 'responseSchema' | 'version'> & {\n /** Schema to validate each item in the response. */\n itemSchema?: StandardSchemaV1<TItem>;\n };\n\nexport type BlindOptions<TItem, TQuery extends Query> = Omit<CollectOptions<TItem, TQuery>, 'version'> & {\n maxPages?: number;\n};\n\n/**\n * Options for v2 paginated operations with known count ({@link BigCommerceClient.collectCount}, {@link BigCommerceClient.streamCount}).\n */\nexport type CountedCollectOptions<TItem, TQuery extends Query> = CollectOptions<TItem, TQuery> & {\n /** Total number of items expected (for v2 endpoints without pagination metadata). */\n count?: number;\n};\n\n/**\n * Options for query-based filtering operations ({@link BigCommerceClient.query}, {@link BigCommerceClient.queryStream}).\n */\nexport type QueryOptions<TItem, TQuery extends Query> = CollectOptions<TItem, TQuery> & {\n /** Query parameter name for value filtering (e.g., `'id:in'`). */\n key: string;\n /** Values to filter by. Automatically chunked across multiple requests. */\n values: (string | number)[];\n};\n","export type Ok<T> = {\n ok: true;\n data: T;\n err: undefined;\n};\n\nexport type Err<E> = {\n ok: false;\n data: undefined;\n err: E;\n};\n\nexport type Result<T, E> = Ok<T> | Err<E>;\n\n/**\n * A {@link Result} extended with the zero-based index of the originating request in the input\n * array passed to {@link BigCommerceClient.batchStream} or {@link BigCommerceClient.batchSafe}.\n *\n * Because concurrent requests complete out of insertion order, `index` is the only reliable way\n * to correlate a result back to its input.\n *\n * @example\n * ```ts\n * const requests = ids.map(id => req.get(`catalog/products/${id}`));\n * for await (const { index, err, data } of client.batchStream(requests)) {\n * const originalId = ids[index];\n * if (err) { console.error(originalId, err); continue; }\n * console.log(originalId, data);\n * }\n * ```\n */\nexport type BatchResult<T, E> = Result<T, E> & { index: number };\n\n/**\n * Creates a successful {@link Result}. Check `result.ok` or `result.err` before accessing `data`.\n * @param data - The success value.\n */\nexport const Ok = <T, E>(data: T): Result<T, E> => ({ ok: true, data, err: undefined });\n\n/**\n * Creates a failed {@link Result}. Check `result.ok` or `result.err` before accessing `err`.\n * @param err - The error value.\n */\nexport const Err = <T, E>(err: E): Result<T, E> => ({ ok: false, data: undefined, err });\n","import ky, { isHTTPError, isKyError, isTimeoutError, type KyInstance, type KyResponse } from 'ky';\nimport pLimit, { type LimitFunction } from 'p-limit';\nimport {\n BASE_KY_CONFIG,\n type ClientConfig,\n type ConcurrencyOptions,\n DEFAULT_BACKOFF_RATE,\n DEFAULT_BACKOFF_RECOVER,\n DEFAULT_CONCURRENCY,\n DEFAULT_LIMIT,\n DEFAULT_MAX_BLIND_PAGES,\n DEFAULT_RATE_LIMIT_BACKOFF,\n HEADERS,\n LEADING_SLASHES,\n type Logger,\n MAX_CONCURRENCY,\n MAX_URL_LENGTH,\n type ResolvedConcurrencyOptions,\n} from './lib/common';\nimport {\n BaseError,\n BCApiError,\n BCClientError,\n BCCredentialsError,\n BCPaginatedItemValidationError,\n BCPaginatedOptionError,\n BCPaginatedResponseError,\n BCQueryValidationError,\n BCRequestBodyValidationError,\n BCResponseParseError,\n BCResponseValidationError,\n type BCSchemaValidationError,\n BCTimeoutError,\n} from './lib/errors';\nimport { bcRateLimitRetry, validateUrlLength } from './lib/hooks';\nimport { initLogger } from './lib/logger';\nimport type { V3Resource } from './lib/pagination';\nimport {\n type ApiVersion,\n type BatchRequestOptions,\n type BlindOptions,\n type CollectOptions,\n type DeleteOptions,\n type GetOptions,\n type PostOptions,\n type PutOptions,\n type Query,\n type QueryOptions,\n type RequestOptions,\n req,\n toUrlSearchParams,\n} from './lib/request';\nimport { type BatchResult, Err, Ok, type Result } from './lib/result';\nimport type { StandardSchemaV1 } from './lib/standard-schema';\nimport { AsyncChannel, chunkStrLength } from './lib/util';\n\nexport class BigCommerceClient {\n private readonly logger?: Logger;\n private readonly client: KyInstance;\n private readonly storeHash: string;\n\n /**\n * Creates a new BigCommerceClient.\n *\n * @param config - Client configuration. Ky options (e.g. `prefixUrl`, `timeout`, `retry`,\n * `hooks`) are forwarded to the underlying ky instance.\n * @param config.storeHash - BigCommerce store hash. Must be a non-empty string.\n * @param config.accessToken - BigCommerce API access token. Must be a non-empty string.\n * @param config.logger - A {@link Logger} instance, a log level string\n * (`'debug' | 'info' | 'warn' | 'error'`), `true` to enable console logging at `'info'`\n * level, or `false` to disable logging entirely. Omitting also defaults to `'info'` level.\n * @param config.concurrency - Default max concurrent requests for batch/stream operations.\n * Must be between 1 and 1000. Pass `false` to disable concurrency (sequential execution).\n * Defaults to 10.\n * @param config.rateLimitBackoff - Concurrency cap applied when a 429 response is received.\n * Defaults to 1.\n * @param config.backoff - Divisor (or `(concurrency, status) => number` function) applied to\n * concurrency on non-429 error responses. Defaults to 2.\n * @param config.backoffRecover - Amount (or `(concurrency) => number` function) added to\n * concurrency per successful response while below the configured max. Defaults to 1.\n *\n * @throws {@link BCCredentialsError} if `storeHash` or `accessToken` are missing.\n * @throws {@link BCClientError} if `prefixUrl` is not a valid URL or `concurrency` is out of range.\n */\n constructor(private readonly config: ClientConfig) {\n this.validateConfig();\n\n const { storeHash, accessToken, logger, concurrency: _, ...kyOptions } = config;\n\n this.logger = initLogger(logger);\n this.storeHash = storeHash;\n\n this.client = ky.create({\n ...BASE_KY_CONFIG,\n ...kyOptions,\n\n headers: {\n ...BASE_KY_CONFIG.headers,\n ...((kyOptions.headers ?? {}) as Record<string, string>),\n [HEADERS.AUTH_TOKEN]: accessToken,\n },\n\n hooks: {\n beforeRequest: [...(kyOptions.hooks?.beforeRequest ?? []), validateUrlLength],\n beforeRetry: [\n ({ error }) => {\n if (error instanceof BaseError) {\n throw error;\n }\n },\n bcRateLimitRetry(this.logger),\n ...(kyOptions.hooks?.beforeRetry ?? []),\n ],\n beforeError: [...(kyOptions.hooks?.beforeError ?? [])],\n afterResponse: [...(kyOptions.hooks?.afterResponse ?? [])],\n },\n });\n }\n\n /**\n * Sends a GET request to the given path.\n *\n * @param path - API path relative to the store's versioned base URL (e.g. `catalog/products`).\n * @param options - Ky options are forwarded to the underlying request.\n * @param options.version - API version segment inserted into the URL. Defaults to `'v3'`.\n * @param options.query - Query parameters to append to the URL.\n * @param options.querySchema - StandardSchemaV1 schema to validate `query` before the request\n * is sent. Requires `query` to be provided.\n * @param options.responseSchema - StandardSchemaV1 schema to validate the parsed response body.\n *\n * @returns Parsed and optionally validated response body.\n *\n * @throws {@link BCApiError} on HTTP error responses.\n * @throws {@link BCTimeoutError} if the request times out.\n * @throws {@link BCResponseParseError} if the response body cannot be parsed.\n * @throws {@link BCUrlTooLongError} if the constructed URL exceeds 2048 characters.\n * @throws {@link BCRateLimitNoHeadersError} if a 429 is received without rate-limit headers.\n * @throws {@link BCRateLimitDelayTooLongError} if the rate-limit reset window exceeds\n * `config.retry.maxRetryAfter`.\n * @throws {@link BCQueryValidationError} if `querySchema` validation fails.\n * @throws {@link BCResponseValidationError} if `responseSchema` validation fails.\n * @throws {@link BCClientError} on any other ky or unknown error.\n */\n async get<TRes = unknown, TQuery extends Query = Query>(\n path: string,\n options?: GetOptions<TRes, TQuery>,\n ): Promise<TRes> {\n return this.request<never, TRes, TQuery>(path, {\n ...options,\n method: 'GET',\n } as RequestOptions<never, TRes, TQuery>);\n }\n\n /**\n * Sends a POST request to the given path.\n *\n * @param path - API path relative to the store's versioned base URL.\n * @param options - Ky options are forwarded to the underlying request.\n * @param options.version - API version segment inserted into the URL. Defaults to `'v3'`.\n * @param options.body - Request body, serialized as JSON.\n * @param options.bodySchema - StandardSchemaV1 schema to validate `body` before the request\n * is sent. Requires `body` to be provided.\n * @param options.query - Query parameters to append to the URL.\n * @param options.querySchema - StandardSchemaV1 schema to validate `query` before the request\n * is sent. Requires `query` to be provided.\n * @param options.responseSchema - StandardSchemaV1 schema to validate the parsed response body.\n *\n * @returns Parsed and optionally validated response body.\n *\n * @throws {@link BCApiError} on HTTP error responses.\n * @throws {@link BCTimeoutError} if the request times out.\n * @throws {@link BCResponseParseError} if the response body cannot be parsed.\n * @throws {@link BCUrlTooLongError} if the constructed URL exceeds 2048 characters.\n * @throws {@link BCRateLimitNoHeadersError} if a 429 is received without rate-limit headers.\n * @throws {@link BCRateLimitDelayTooLongError} if the rate-limit reset window exceeds\n * `config.retry.maxRetryAfter`.\n * @throws {@link BCQueryValidationError} if `querySchema` validation fails.\n * @throws {@link BCRequestBodyValidationError} if `bodySchema` validation fails.\n * @throws {@link BCResponseValidationError} if `responseSchema` validation fails.\n * @throws {@link BCClientError} on any other ky or unknown error.\n */\n async post<TRes = unknown, TBody = unknown, TQuery extends Query = Query>(\n path: string,\n options?: PostOptions<TBody, TRes, TQuery>,\n ): Promise<TRes> {\n return this.request<TBody, TRes, TQuery>(path, {\n ...options,\n method: 'POST',\n } as RequestOptions<TBody, TRes, TQuery>);\n }\n\n /**\n * Sends a PUT request to the given path.\n *\n * @param path - API path relative to the store's versioned base URL.\n * @param options - Ky options are forwarded to the underlying request.\n * @param options.version - API version segment inserted into the URL. Defaults to `'v3'`.\n * @param options.body - Request body, serialized as JSON.\n * @param options.bodySchema - StandardSchemaV1 schema to validate `body` before the request\n * is sent. Requires `body` to be provided.\n * @param options.query - Query parameters to append to the URL.\n * @param options.querySchema - StandardSchemaV1 schema to validate `query` before the request\n * is sent. Requires `query` to be provided.\n * @param options.responseSchema - StandardSchemaV1 schema to validate the parsed response body.\n *\n * @returns Parsed and optionally validated response body.\n *\n * @throws {@link BCApiError} on HTTP error responses.\n * @throws {@link BCTimeoutError} if the request times out.\n * @throws {@link BCResponseParseError} if the response body cannot be parsed.\n * @throws {@link BCUrlTooLongError} if the constructed URL exceeds 2048 characters.\n * @throws {@link BCRateLimitNoHeadersError} if a 429 is received without rate-limit headers.\n * @throws {@link BCRateLimitDelayTooLongError} if the rate-limit reset window exceeds\n * `config.retry.maxRetryAfter`.\n * @throws {@link BCQueryValidationError} if `querySchema` validation fails.\n * @throws {@link BCRequestBodyValidationError} if `bodySchema` validation fails.\n * @throws {@link BCResponseValidationError} if `responseSchema` validation fails.\n * @throws {@link BCClientError} on any other ky or unknown error.\n */\n async put<TRes = unknown, TBody = unknown, TQuery extends Query = Query>(\n path: string,\n options?: PutOptions<TBody, TRes, TQuery>,\n ): Promise<TRes> {\n return this.request<TBody, TRes, TQuery>(path, {\n ...options,\n method: 'PUT',\n } as RequestOptions<TBody, TRes, TQuery>);\n }\n\n /**\n * Sends a DELETE request to the given path.\n *\n * Silently suppresses 404 responses (resource already gone) and empty response bodies.\n *\n * @param path - API path relative to the store's versioned base URL.\n * @param options - Ky options are forwarded to the underlying request.\n * @param options.version - API version segment inserted into the URL. Defaults to `'v3'`.\n * @param options.query - Query parameters to append to the URL.\n * @param options.querySchema - StandardSchemaV1 schema to validate `query` before the request\n * is sent. Requires `query` to be provided.\n *\n * @throws {@link BCApiError} on non-404 HTTP error responses.\n * @throws {@link BCTimeoutError} if the request times out.\n * @throws {@link BCResponseParseError} if the response body is non-empty and cannot be parsed.\n * @throws {@link BCUrlTooLongError} if the constructed URL exceeds 2048 characters.\n * @throws {@link BCRateLimitNoHeadersError} if a 429 is received without rate-limit headers.\n * @throws {@link BCRateLimitDelayTooLongError} if the rate-limit reset window exceeds\n * `config.retry.maxRetryAfter`.\n * @throws {@link BCQueryValidationError} if `querySchema` validation fails.\n * @throws {@link BCClientError} on any other ky or unknown error.\n */\n async delete<TRes = never, TQuery extends Query = Query>(\n path: string,\n options?: DeleteOptions<TQuery>,\n ): Promise<void> {\n try {\n await this.request<never, TRes, TQuery>(path, {\n ...options,\n method: 'DELETE',\n } as RequestOptions<never, TRes, TQuery>);\n } catch (err) {\n if (err instanceof BCResponseParseError && err.context.rawBody === '') {\n return;\n }\n\n // Do not throw on delete for resources that are already gone.\n if (err instanceof BCApiError && err.context.status === 404) {\n this.logger?.warn({ err }, 'Attempted to delete the resource that is already gone');\n\n return;\n }\n\n throw err;\n }\n }\n\n /**\n * Fetches items from a v3 paginated endpoint by splitting `values` across multiple requests\n * using the given `key` query param, chunking to stay within URL length limits.\n *\n * Collects all results into an array. Use {@link queryStream} to process items lazily.\n *\n * **Sorting and concurrency:** when `concurrency > 1`, chunks complete out of order so\n * sorted output is not preserved across the full result set. Pass `concurrency: false`\n * if sort order matters.\n *\n * @param path - API path relative to the store's versioned base URL.\n * @param options - Query options including `key`, `values`, pagination params, and concurrency\n * controls.\n * @param options.key - Query parameter name used for value filtering (e.g. `'id:in'`).\n * @param options.values - Values to filter by. Automatically chunked across multiple requests\n * to keep each URL under 2048 characters.\n * @param options.query - Additional query parameters. `query.limit` controls page size\n * (default 250, must be > 0). If `options.key` is present in `query` it will be ignored.\n * @param options.querySchema - StandardSchemaV1 schema to validate `query`. Requires `query`\n * to be provided.\n * @param options.itemSchema - StandardSchemaV1 schema to validate each returned item.\n * @param options.concurrency - Max concurrent chunk requests. Must be 1–1000. `false` for\n * sequential. Defaults to `config.concurrency`, or 10 if not set on the client.\n * @param options.rateLimitBackoff - Concurrency cap on 429 responses. Defaults to\n * `config.rateLimitBackoff`, or 1 if not set on the client.\n * @param options.backoff - Divisor (or function) applied to concurrency on error responses.\n * Defaults to `config.backoff`, or 2 if not set on the client.\n * @param options.backoffRecover - Amount (or function) added to concurrency per successful\n * response. Defaults to `config.backoffRecover`, or 1 if not set on the client.\n *\n * @returns All matching items across all chunked requests.\n * @throws {@link BCPaginatedOptionError} if `query.limit` is not a positive number.\n * @throws {@link BCQueryValidationError} if `querySchema` validation fails.\n * @throws {@link BCApiError} on HTTP error responses.\n * @throws {@link BCTimeoutError} if a request times out.\n * @throws {@link BCResponseParseError} if a response body cannot be parsed.\n * @throws {@link BCUrlTooLongError} if a constructed URL exceeds 2048 characters.\n * @throws {@link BCRateLimitNoHeadersError} if a 429 is received without rate-limit headers.\n * @throws {@link BCRateLimitDelayTooLongError} if the rate-limit reset window exceeds\n * `config.retry.maxRetryAfter`.\n * @throws {@link BCPaginatedResponseError} if a page response has an unexpected shape.\n * @throws {@link BCPaginatedItemValidationError} if `itemSchema` validation fails for an item.\n * @throws {@link BCClientError} on any other ky or unknown error.\n */\n async query<TItem = unknown, TQuery extends Query = Query>(\n path: string,\n options: QueryOptions<TItem, TQuery>,\n ): Promise<TItem[]> {\n const results: TItem[] = [];\n\n for await (const { data, err } of this.queryStream(path, options)) {\n if (err) {\n throw err;\n } else {\n results.push(data);\n }\n }\n\n return results;\n }\n\n /**\n * Streaming variant of {@link query}. Yields each item individually as results arrive,\n * splitting `values` into URL-length-safe chunks across concurrent requests.\n *\n * Each yielded value is a {@link Result} — check `err` before using `data`.\n *\n * **Sorting and concurrency:** when `concurrency > 1`, chunks complete out of order so\n * sorted output is not preserved across the full result set. Pass `concurrency: false`\n * if sort order matters.\n *\n * @param path - API path relative to the store's versioned base URL.\n * @param options - Query options including `key`, `values`, pagination params, and concurrency\n * controls.\n * @param options.key - Query parameter name used for value filtering (e.g. `'id:in'`).\n * @param options.values - Values to filter by. Automatically chunked across multiple requests\n * to keep each URL under 2048 characters.\n * @param options.query - Additional query parameters. `query.limit` controls page size\n * (default 250, must be > 0). If `options.key` is present in `query` it will be ignored.\n * @param options.querySchema - StandardSchemaV1 schema to validate `query`. Requires `query`\n * to be provided.\n * @param options.itemSchema - StandardSchemaV1 schema to validate each returned item.\n * @param options.concurrency - Max concurrent chunk requests. Must be 1–1000. `false` for\n * sequential. Defaults to `config.concurrency`, or 10 if not set on the client.\n * @param options.rateLimitBackoff - Concurrency cap on 429 responses. Defaults to\n * `config.rateLimitBackoff`, or 1 if not set on the client.\n * @param options.backoff - Divisor (or function) applied to concurrency on error responses.\n * Defaults to `config.backoff`, or 2 if not set on the client.\n * @param options.backoffRecover - Amount (or function) added to concurrency per successful\n * response. Defaults to `config.backoffRecover`, or 1 if not set on the client.\n * @throws {@link BCPaginatedOptionError} if `query.limit` is not a positive number.\n * @throws {@link BCQueryValidationError} if `querySchema` validation fails.\n */\n async *queryStream<TItem = unknown, TQuery extends Query = Query>(\n path: string,\n options: QueryOptions<TItem, TQuery>,\n ): AsyncGenerator<Result<TItem, BaseError>> {\n const {\n key,\n values,\n query,\n querySchema,\n itemSchema,\n concurrency,\n rateLimitBackoff,\n backoff,\n backoffRecover,\n ...requestOptions\n } = options;\n\n const limit = this.validatePaginationOption(path, 'limit', query?.limit ?? DEFAULT_LIMIT);\n\n const validatedQuery = await this.validate(\n query,\n querySchema,\n BCQueryValidationError,\n 'GET',\n path,\n 'Invalid query parameters',\n );\n\n const newQuery: Query = {\n ...validatedQuery,\n limit,\n };\n\n if (key in newQuery) {\n this.logger?.warn({ key }, 'The provided key is already in the query params, this param will be ignored');\n\n delete newQuery[key];\n }\n\n const url = this.config.prefixUrl ?? requestOptions.prefixUrl ?? BASE_KY_CONFIG.prefixUrl;\n const fullPath = this.makePath('v3', path);\n const fullQuery = toUrlSearchParams({ ...newQuery, page: 1 });\n const fullUrl = `${url}/${fullPath}?${fullQuery}`;\n const keyOverhead = encodeURIComponent(key).length + 2; // `&key=` or `key=` prefix\n\n const chunks = chunkStrLength(values.map(String), {\n chunkLength: limit,\n maxLength: MAX_URL_LENGTH,\n offset: fullUrl.length + keyOverhead,\n separatorSize: encodeURIComponent(',').length,\n });\n\n const requests = chunks.map((chunk) =>\n req.get(path, {\n ...requestOptions,\n query: {\n ...newQuery,\n page: 1,\n [key]: chunk,\n },\n }),\n );\n\n for await (const { err, data } of this.batchStream(requests, {\n concurrency,\n rateLimitBackoff,\n backoff,\n backoffRecover,\n })) {\n if (err) {\n yield Err(err);\n continue;\n }\n\n try {\n const { data: items } = this.assertPaginatedResponse(path, data);\n\n for (const item of items) {\n yield this.validatePaginatedItem(path, item, itemSchema);\n }\n } catch (err) {\n if (err instanceof BaseError) {\n yield Err(err);\n } else {\n yield Err(new BCClientError('Unknown error occurred processing page', {}, { cause: err }));\n }\n }\n }\n }\n\n /**\n * Fetches all pages from a v3 paginated endpoint and collects items into an array.\n *\n * Use {@link stream} to process items lazily without buffering the full result set.\n *\n * **Sorting and concurrency:** the first page is fetched sequentially; remaining pages are\n * fetched concurrently and may complete out of order. When `concurrency > 1`, sort order\n * is not preserved across pages. Pass `concurrency: false` if sort order matters.\n *\n * @param path - API path relative to the store's versioned base URL.\n * @param options - Ky options are forwarded to page requests.\n * @param options.query - Query parameters. `query.limit` controls page size (default 250,\n * must be > 0). `query.page` sets the starting page (default 1, must be > 0).\n * @param options.querySchema - StandardSchemaV1 schema to validate `query`. Requires `query`\n * to be provided.\n * @param options.itemSchema - StandardSchemaV1 schema to validate each returned item.\n * @param options.concurrency - Max concurrent page requests for pages after the first.\n * Must be 1–1000. `false` for sequential. Defaults to `config.concurrency`, or 10 if not\n * set on the client.\n * @param options.rateLimitBackoff - Concurrency cap on 429 responses. Defaults to\n * `config.rateLimitBackoff`, or 1 if not set on the client.\n * @param options.backoff - Divisor (or function) applied to concurrency on error responses.\n * Defaults to `config.backoff`, or 2 if not set on the client.\n * @param options.backoffRecover - Amount (or function) added to concurrency per successful\n * response. Defaults to `config.backoffRecover`, or 1 if not set on the client.\n * @returns All items across all pages.\n *\n * @throws {@link BCPaginatedOptionError} if `query.limit` or `query.page` is not a positive number.\n * @throws {@link BCQueryValidationError} if `querySchema` validation fails.\n * @throws {@link BCApiError} on HTTP error responses.\n * @throws {@link BCTimeoutError} if a request times out.\n * @throws {@link BCResponseParseError} if a response body cannot be parsed.\n * @throws {@link BCUrlTooLongError} if a constructed URL exceeds 2048 characters.\n * @throws {@link BCRateLimitNoHeadersError} if a 429 is received without rate-limit headers.\n * @throws {@link BCRateLimitDelayTooLongError} if the rate-limit reset window exceeds\n * `config.retry.maxRetryAfter`.\n * @throws {@link BCPaginatedResponseError} if a page response has an unexpected shape.\n * @throws {@link BCPaginatedItemValidationError} if `itemSchema` validation fails for an item.\n * @throws {@link BCClientError} on any other ky or unknown error.\n */\n async collect<TItem = unknown, TQuery extends Query = Query>(\n path: string,\n options?: CollectOptions<TItem, TQuery>,\n ): Promise<TItem[]> {\n const items: TItem[] = [];\n\n for await (const { data, err } of this.stream(path, options)) {\n if (err) {\n throw err;\n } else {\n items.push(data);\n }\n }\n\n return items;\n }\n\n /**\n * Fetches all pages from a v2 flat-array endpoint and collects items into an array.\n *\n * Pagination is discovered dynamically — pages are fetched in batches until an empty page,\n * a 404, or a 204 response is received. No prior knowledge of total count is required.\n *\n * Use {@link streamBlind} to process items lazily without buffering the full result set.\n *\n * **Sorting and concurrency:** pages within each batch are fetched concurrently and may\n * complete out of order. When `concurrency > 1`, sort order is not preserved across pages.\n * Pass `concurrency: false` if sort order matters.\n *\n * @param path - API path relative to the store's versioned base URL (always requests v2).\n * @param options - Ky options are forwarded to page requests.\n * @param options.query - Query parameters. `query.limit` controls page size (default 250,\n * must be > 0). `query.page` sets the starting page (default 1, must be > 0).\n * @param options.querySchema - StandardSchemaV1 schema to validate `query`. Requires `query`\n * to be provided.\n * @param options.itemSchema - StandardSchemaV1 schema to validate each returned item.\n * @param options.maxPages - Maximum number of pages to fetch before stopping (default 500,\n * must be > 0). A warning is logged if this limit is reached.\n * @param options.concurrency - Max concurrent page requests per batch. Must be 1–1000.\n * `false` for sequential. Defaults to `config.concurrency`, or 10 if not set on the client.\n * @param options.rateLimitBackoff - Concurrency cap on 429 responses. Defaults to\n * `config.rateLimitBackoff`, or 1 if not set on the client.\n * @param options.backoff - Divisor (or function) applied to concurrency on error responses.\n * Defaults to `config.backoff`, or 2 if not set on the client.\n * @param options.backoffRecover - Amount (or function) added to concurrency per successful\n * response. Defaults to `config.backoffRecover`, or 1 if not set on the client.\n * @returns All items across all pages.\n *\n * @throws {@link BCPaginatedOptionError} if `query.limit`, `query.page`, or `maxPages` is not a positive number.\n * @throws {@link BCQueryValidationError} if `querySchema` validation fails.\n * @throws {@link BCPaginatedItemValidationError} if `itemSchema` validation fails for an item.\n * @throws {@link BCClientError} if a page returns a non-array response, or on any other error.\n * @throws {@link BCApiError} on non-terminating HTTP error responses.\n * @throws {@link BCTimeoutError} if a request times out.\n * @throws {@link BCResponseParseError} if a response body cannot be parsed.\n */\n async collectBlind<TItem = unknown, TQuery extends Query = Query>(\n path: string,\n options?: BlindOptions<TItem, TQuery>,\n ): Promise<TItem[]> {\n const results: TItem[] = [];\n\n for await (const { err, data } of this.streamBlind(path, options)) {\n if (err) {\n throw err;\n } else {\n results.push(data);\n }\n }\n\n return results;\n }\n\n /**\n * Lazily streams items from a v2 flat-array endpoint, page by page.\n *\n * Pagination is discovered dynamically — pages are fetched in concurrent batches until an\n * empty page, a 404, or a 204 response is received. No prior knowledge of total count is\n * required. Each item is yielded as a {@link Result}: `Ok(item)` on success or\n * `Err(error)` for item-level validation failures and non-terminating page errors.\n *\n * Use {@link collectBlind} to buffer all results into an array (throws on any error).\n *\n * **Sorting and concurrency:** pages within each batch are fetched concurrently and may\n * complete out of order. When `concurrency > 1`, sort order is not preserved across pages.\n * Pass `concurrency: false` if sort order matters.\n *\n * @param path - API path relative to the store's versioned base URL (always requests v2).\n * @param options - Ky options are forwarded to page requests.\n * @param options.query - Query parameters. `query.limit` controls page size (default 250,\n * must be > 0). `query.page` sets the starting page (default 1, must be > 0).\n * @param options.querySchema - StandardSchemaV1 schema to validate `query`. Requires `query`\n * to be provided.\n * @param options.itemSchema - StandardSchemaV1 schema to validate each returned item.\n * @param options.maxPages - Maximum number of pages to fetch before stopping (default 500,\n * must be > 0). A warning is logged if this limit is reached.\n * @param options.concurrency - Max concurrent page requests per batch. Must be 1–1000.\n * `false` for sequential. Defaults to `config.concurrency`, or 10 if not set on the client.\n * @param options.rateLimitBackoff - Concurrency cap on 429 responses. Defaults to\n * `config.rateLimitBackoff`, or 1 if not set on the client.\n * @param options.backoff - Divisor (or function) applied to concurrency on error responses.\n * Defaults to `config.backoff`, or 2 if not set on the client.\n * @param options.backoffRecover - Amount (or function) added to concurrency per successful\n * response. Defaults to `config.backoffRecover`, or 1 if not set on the client.\n *\n * @throws {@link BCPaginatedOptionError} if `query.limit`, `query.page`, or `maxPages` is not a positive number.\n * @throws {@link BCQueryValidationError} if `querySchema` validation fails.\n *\n * @yields `Ok(item)` for each successfully fetched and validated item.\n * @yields `Err(BCPaginatedItemValidationError)` when `itemSchema` rejects an item.\n * @yields `Err(BCClientError)` when a page returns a non-array response.\n * @yields `Err(error)` for non-terminating page errors (e.g. non-404/204 HTTP errors).\n */\n async *streamBlind<TItem = unknown, TQuery extends Query = Query>(\n path: string,\n options?: BlindOptions<TItem, TQuery>,\n ): AsyncGenerator<Result<TItem, BaseError>> {\n const {\n query: rawQuery,\n querySchema,\n itemSchema,\n maxPages: rawMaxPages,\n concurrency: rawConcurrency,\n rateLimitBackoff,\n backoff,\n backoffRecover,\n pLimit: rawPLimit,\n ...requestOptions\n } = options ?? {};\n\n const concurrency = this.validateConcurrency(rawConcurrency ?? this.config.concurrency ?? DEFAULT_CONCURRENCY);\n const limiter = rawPLimit ?? (concurrency ? pLimit({ concurrency, rejectOnClear: true }) : undefined);\n\n const concurrencyOptions = {\n concurrency: rawConcurrency,\n rateLimitBackoff,\n backoff,\n backoffRecover,\n pLimit: limiter,\n };\n\n const query = await this.validate(rawQuery, querySchema, BCQueryValidationError, 'GET', path);\n const page = this.validatePaginationOption(path, 'page', query?.page ?? 1);\n const limit = this.validatePaginationOption(path, 'limit', query?.limit ?? DEFAULT_LIMIT);\n const maxPages = this.validatePaginationOption(path, 'maxPages', rawMaxPages ?? DEFAULT_MAX_BLIND_PAGES);\n\n let done = false;\n let currentPage = page;\n\n do {\n if (currentPage > maxPages) {\n this.logger?.warn({ currentPage }, 'Blind pagination reached maxPages before the end of the data');\n break;\n }\n\n const batchSize = (limiter?.concurrency ?? concurrency) || 1;\n const pageRequests = Array.from({ length: batchSize }, (_, i) => currentPage + i).map((page) =>\n req.get(path, {\n ...requestOptions,\n version: 'v2',\n query: {\n ...query,\n page,\n limit,\n },\n }),\n );\n\n currentPage += batchSize;\n\n const pages = await this.batchSafe(pageRequests, concurrencyOptions);\n\n for (const { err, data } of pages) {\n if (err) {\n done =\n (err instanceof BCApiError && err.context.status === 404) ||\n (err instanceof BCResponseParseError &&\n err.context.rawBody === '' &&\n err.context.status === 204);\n\n if (!done) {\n yield Err(err);\n }\n } else {\n if (Array.isArray(data)) {\n if (data.length === 0) {\n done = true;\n break;\n }\n\n for (const item of data) {\n yield this.validatePaginatedItem(path, item, itemSchema);\n }\n } else {\n yield Err(\n new BCClientError('Received non array response from blind pagination page endpoint', {\n data,\n path,\n }),\n );\n }\n }\n }\n } while (!done);\n }\n\n /**\n * Executes multiple requests concurrently and returns all results as {@link BatchResult}\n * values, never throwing. Errors from individual requests are captured as `Err` results.\n *\n * Results arrive in completion order, not input order. Use the `index` field on each\n * {@link BatchResult} to correlate a result back to its position in the `requests` array.\n *\n * Use {@link batchStream} to process results as they arrive rather than waiting for all.\n *\n * @param requests - Array of request descriptors built with the {@link req} helpers.\n * @param options.concurrency - Max concurrent requests. Must be 1–1000. `false` for\n * sequential. Defaults to `config.concurrency`, or 10 if not set on the client.\n * @param options.rateLimitBackoff - Concurrency cap on 429 responses. Defaults to\n * `config.rateLimitBackoff`, or 1 if not set on the client.\n * @param options.backoff - Divisor (or function) applied to concurrency on error responses.\n * Defaults to `config.backoff`, or 2 if not set on the client.\n * @param options.backoffRecover - Amount (or function) added to concurrency per successful\n * response. Defaults to `config.backoffRecover`, or 1 if not set on the client.\n *\n * @returns {@link BatchResult} array in the order requests completed (not input order).\n */\n async batchSafe<TRes = unknown, TBody = unknown, TQuery extends Query = Query>(\n requests: BatchRequestOptions<TBody, TRes, TQuery>[],\n options?: ConcurrencyOptions,\n ): Promise<BatchResult<TRes, BaseError>[]> {\n const results: BatchResult<TRes, BaseError>[] = [];\n\n for await (const res of this.batchStream(requests, options)) {\n results.push(res);\n }\n\n return results;\n }\n\n /**\n * Streams all items from a v3 paginated endpoint, fetching the first page sequentially\n * and remaining pages concurrently via {@link batchStream}.\n *\n * Each yielded value is a {@link Result} — check `err` before using `data`. Use\n * {@link collect} to gather all items into an array.\n *\n * **Sorting and concurrency:** the first page is fetched sequentially; remaining pages are\n * fetched concurrently and may complete out of order. When `concurrency > 1`, sort order\n * is not preserved across pages. Pass `concurrency: false` if sort order matters.\n *\n * @param path - API path relative to the store's versioned base URL.\n * @param options - Ky options are forwarded to page requests.\n * @param options.query - Query parameters. `query.limit` controls page size (default 250,\n * must be > 0). `query.page` sets the starting page (default 1, must be > 0). If the API\n * enforces a different limit, the actual `per_page` from the first response is used for\n * subsequent pages.\n * @param options.querySchema - StandardSchemaV1 schema to validate `query`. Requires `query`\n * to be provided.\n * @param options.itemSchema - StandardSchemaV1 schema to validate each returned item.\n * @param options.concurrency - Max concurrent page requests for pages after the first.\n * Must be 1–1000. `false` for sequential. Defaults to `config.concurrency`, or 10 if not\n * set on the client.\n * @param options.rateLimitBackoff - Concurrency cap on 429 responses. Defaults to\n * `config.rateLimitBackoff`, or 1 if not set on the client.\n * @param options.backoff - Divisor (or function) applied to concurrency on error responses.\n * Defaults to `config.backoff`, or 2 if not set on the client.\n * @param options.backoffRecover - Amount (or function) added to concurrency per successful\n * response. Defaults to `config.backoffRecover`, or 1 if not set on the client.\n * @throws {@link BCPaginatedOptionError} if `query.limit` or `query.page` is not a positive number.\n * @throws {@link BCQueryValidationError} if `querySchema` validation fails.\n */\n async *stream<TItem = unknown, TQuery extends Query = Query>(\n path: string,\n options?: CollectOptions<TItem, TQuery>,\n ): AsyncGenerator<Result<TItem, BaseError>> {\n const {\n query,\n querySchema,\n itemSchema,\n concurrency,\n rateLimitBackoff,\n backoff,\n backoffRecover,\n ...requestOptions\n } = options ?? {};\n\n let limit = this.validatePaginationOption(path, 'limit', query?.limit ?? DEFAULT_LIMIT);\n const page = this.validatePaginationOption(path, 'page', query?.page ?? 1);\n\n const validatedQuery = await this.validate(\n query,\n querySchema,\n BCQueryValidationError,\n 'GET',\n path,\n 'Invalid query parameters',\n );\n\n let firstPageMeta: V3Resource<unknown[]>['meta'];\n\n try {\n const firstPage = await this.get(path, {\n ...requestOptions,\n query: {\n ...validatedQuery,\n page,\n limit,\n } as unknown as TQuery,\n });\n\n const { data, meta } = this.assertPaginatedResponse(path, firstPage);\n\n firstPageMeta = meta;\n\n // Validate and return the first page\n for (const item of data) {\n yield this.validatePaginatedItem(path, item, itemSchema);\n }\n } catch (err) {\n if (err instanceof BaseError) {\n yield Err(err);\n } else {\n yield Err(new BCClientError('Unknown error occurred fetching first page', {}, { cause: err }));\n }\n\n return;\n }\n\n const { total_pages, per_page } = firstPageMeta.pagination;\n\n if (limit !== per_page) {\n this.logger?.warn({ limit, actual: per_page }, 'API enforces alternate limit on this endpoint');\n limit = per_page;\n }\n\n // Fetch other pages using batchStream\n const requests = Array.from({ length: total_pages - page }, (_, i) => i + page + 1).map((page) => ({\n method: 'GET' as const,\n path,\n ...requestOptions,\n query: {\n ...validatedQuery,\n limit,\n page,\n },\n }));\n\n for await (const pageRes of requests.length > 0\n ? this.batchStream(requests, { concurrency, rateLimitBackoff, backoff, backoffRecover })\n : []) {\n const { data: page, err } = pageRes;\n\n if (err) {\n yield Err(err);\n continue;\n }\n\n try {\n const { data } = this.assertPaginatedResponse(path, page);\n\n for (const item of data) {\n yield this.validatePaginatedItem(path, item, itemSchema);\n }\n } catch (err) {\n if (err instanceof BaseError) {\n yield Err(err);\n } else {\n yield Err(new BCClientError('Unknown error occurred processing page', {}, { cause: err }));\n }\n }\n }\n }\n\n /**\n * Executes multiple requests with configurable concurrency, yielding each result as a\n * {@link BatchResult} as it completes. Errors from individual requests are yielded as `Err`\n * results rather than thrown.\n *\n * Results arrive in completion order, not input order. Use the `index` field on each\n * {@link BatchResult} to correlate a result back to its position in the `requests` array.\n *\n * Automatically adjusts concurrency up/down in response to rate-limit and error responses.\n * Use {@link batchSafe} to collect all results into an array.\n *\n * **Caution:** the generator is making requests concurrently. As a consequence if a\n * request is mutating the remote (POST, DELETE) and `for await` loop is exited early,\n * the in-flight request may or may not commit the mutation, and the results of\n * these request WILL NOT be yielded. If you do intent to break the loop early and want to\n * get all the results, set `concurrency: false` to trade concurrency for deterministic behavior.\n *\n * @param requests - Array of request descriptors built with the {@link req} helpers.\n * @param options.concurrency - Max concurrent requests. Must be 1–1000. `false` for\n * sequential. Defaults to `config.concurrency`, or 10 if not set on the client.\n * @param options.rateLimitBackoff - Concurrency cap on 429 responses. Defaults to\n * `config.rateLimitBackoff`, or 1 if not set on the client.\n * @param options.backoff - Divisor (or function) applied to concurrency on error responses.\n * Defaults to `config.backoff`, or 2 if not set on the client.\n * @param options.backoffRecover - Amount (or function) added to concurrency per successful\n * response. Defaults to `config.backoffRecover`, or 1 if not set on the client.\n */\n async *batchStream<TRes = unknown, TBody = unknown, TQuery extends Query = Query>(\n requests: BatchRequestOptions<TBody, TRes, TQuery>[],\n options?: ConcurrencyOptions,\n ): AsyncGenerator<BatchResult<TRes, BaseError>> {\n const resolved = this.resolveStreamOptions(options);\n\n if (resolved.concurrency) {\n const limit = resolved.pLimit ?? pLimit({ concurrency: resolved.concurrency, rejectOnClear: true });\n const client = this.makeStreamClient(limit, resolved);\n const channel = new AsyncChannel<BatchResult<TRes, BaseError>>();\n\n try {\n Promise.all(\n requests.map((req, index) =>\n limit(() =>\n this.request(req.path, req, client).then(\n (val) => channel.push({ ...Ok(val), index }),\n (err) => channel.push({ ...Err(err), index }),\n ),\n ),\n ),\n )\n .catch((err) => this.logger?.warn({ err }, 'In-flight concurrent requests aborted'))\n .finally(() => channel.close());\n\n for await (const item of channel) {\n yield item;\n }\n } finally {\n limit.clearQueue();\n }\n } else {\n for (const [index, request] of requests.entries()) {\n try {\n const res = await this.request(request.path, request);\n\n yield { ...Ok(res), index };\n } catch (err) {\n if (err instanceof BaseError) {\n yield { ...Err(err), index };\n } else {\n yield { ...Err(new BCClientError('Unknown error in batchStream', {}, { cause: err })), index };\n }\n }\n }\n }\n }\n\n private async validatePaginatedItem<TItem>(\n path: string,\n item: unknown,\n schema?: StandardSchemaV1<TItem>,\n ): Promise<Result<TItem, BaseError>> {\n if (!schema) {\n return Ok(item as TItem);\n }\n\n const result = await schema['~standard'].validate(item);\n\n if (result.issues) {\n return Err(new BCPaginatedItemValidationError('Page item validation failed', 'GET', path, item, result));\n } else {\n return Ok(result.value);\n }\n }\n\n private assertPaginatedResponse(path: string, res: unknown): V3Resource<unknown[]> {\n if (typeof res !== 'object' || res === null) {\n throw new BCPaginatedResponseError(path, res, 'Response is invalid');\n }\n\n if (!('data' in res) || !Array.isArray(res.data)) {\n throw new BCPaginatedResponseError(\n path,\n res,\n 'response.data must be an array, ensure this endpoint returns a v3 collection',\n );\n }\n\n if (!('meta' in res) || typeof res.meta !== 'object' || res.meta === null || !('pagination' in res.meta)) {\n throw new BCPaginatedResponseError(path, res, 'response.meta is invalid unable to paginate');\n }\n\n const pagination = res.meta.pagination;\n\n if (typeof pagination !== 'object' || pagination === null) {\n throw new BCPaginatedResponseError(path, res, 'response.meta.pagination is invalid unable to paginate');\n }\n\n const requiredFields: Array<[string, (v: unknown) => boolean]> = [\n ['per_page', (v) => typeof v === 'number' && v > 0],\n ['total_pages', (v) => typeof v === 'number' && v >= 0],\n ];\n\n for (const [field, isValid] of requiredFields) {\n if (!(field in pagination) || !isValid(pagination[field as keyof typeof pagination])) {\n throw new BCPaginatedResponseError(\n path,\n res,\n `response.meta.pagination.${field} is missing or invalid`,\n );\n }\n }\n\n const { links } = pagination as { links?: unknown };\n\n if (typeof links !== 'object' || links === null) {\n throw new BCPaginatedResponseError(path, res, 'response.meta.pagination.links is missing or invalid');\n }\n\n const isNullableString = (v: unknown) => v === null || typeof v === 'string';\n\n if (!('current' in links) || typeof links.current !== 'string') {\n throw new BCPaginatedResponseError(\n path,\n res,\n 'response.meta.pagination.links.current is missing or invalid',\n );\n }\n\n if ('next' in links && !isNullableString(links.next)) {\n throw new BCPaginatedResponseError(path, res, 'response.meta.pagination.links.next is invalid');\n }\n\n if ('previous' in links && !isNullableString(links.previous)) {\n throw new BCPaginatedResponseError(path, res, 'response.meta.pagination.links.previous is invalid');\n }\n\n return res as V3Resource<unknown[]>;\n }\n\n private validatePaginationOption(path: string, key: string, value: unknown): number {\n if (typeof value !== 'number' || value <= 0) {\n throw new BCPaginatedOptionError(path, value, key);\n }\n\n return value;\n }\n\n private resolveStreamOptions(options?: ConcurrencyOptions): ResolvedConcurrencyOptions {\n return {\n concurrency: options?.concurrency ?? this.config.concurrency ?? DEFAULT_CONCURRENCY,\n rateLimitBackoff: options?.rateLimitBackoff ?? this.config.rateLimitBackoff ?? DEFAULT_RATE_LIMIT_BACKOFF,\n backoff: options?.backoff ?? this.config.backoff ?? DEFAULT_BACKOFF_RATE,\n backoffRecover: options?.backoffRecover ?? this.config.backoffRecover ?? DEFAULT_BACKOFF_RECOVER,\n pLimit: options?.pLimit,\n };\n }\n\n private makeStreamClient(limit: LimitFunction, options: ResolvedConcurrencyOptions): KyInstance {\n const { concurrency, rateLimitBackoff, backoff, backoffRecover } = options;\n\n if (concurrency === false) {\n return this.client;\n }\n\n return this.client.extend({\n hooks: {\n beforeRetry: [\n ({ error }) => {\n if (!isHTTPError(error)) {\n return;\n }\n\n const previousConcurrency = limit.concurrency;\n\n if (error.response.status === 429) {\n limit.concurrency = rateLimitBackoff;\n\n this.logger?.warn(\n { previousConcurrency, newConcurrency: limit.concurrency },\n 'Rate limit reached, limiting concurrency',\n );\n } else {\n const rate =\n typeof backoff === 'function'\n ? backoff(limit.concurrency, error.response.status)\n : backoff;\n\n limit.concurrency = Math.ceil(limit.concurrency / rate);\n\n this.logger?.warn(\n { previousConcurrency, newConcurrency: limit.concurrency },\n 'Intermittent errors, limiting concurrency to compensate',\n );\n }\n },\n ],\n afterResponse: [\n (_request, _options, response) => {\n if (response.ok && limit.concurrency < concurrency) {\n const recover =\n typeof backoffRecover === 'function'\n ? backoffRecover(limit.concurrency)\n : backoffRecover;\n\n limit.concurrency = Math.min(concurrency, limit.concurrency + recover);\n }\n },\n ],\n },\n });\n }\n\n private async request<TBody, TRes, TQuery extends Query = Query>(\n rawPath: string,\n options: RequestOptions<TBody, TRes, TQuery>,\n client?: KyInstance,\n ) {\n const { version, query, body, bodySchema, querySchema, responseSchema, ...kyOptions } = options;\n\n const path = this.makePath(options.version ?? 'v3', rawPath);\n const validQuery = await this.validate(\n query,\n querySchema,\n BCQueryValidationError,\n options.method,\n path,\n 'Invalid query parameters',\n );\n const validBody = await this.validate(\n body,\n bodySchema,\n BCRequestBodyValidationError,\n options.method,\n path,\n `Invalid ${options.method} request body`,\n );\n\n let response: KyResponse;\n\n try {\n response = await (client ?? this.client)(path, {\n ...kyOptions,\n method: options.method,\n searchParams: toUrlSearchParams(validQuery),\n json: validBody,\n });\n } catch (err) {\n if (err instanceof BaseError) {\n throw err;\n }\n\n if (isHTTPError(err)) {\n const requestBody = await err.request.text().catch(() => '');\n const responseBody = await err.response.text().catch(() => '');\n const error = new BCApiError(err, requestBody, responseBody);\n\n this.logger?.error(error.context, 'Request failed');\n\n throw error;\n }\n\n if (isTimeoutError(err)) {\n const error = new BCTimeoutError(err);\n\n this.logger?.error(error.context, 'Request timed out');\n\n throw error;\n }\n\n if (isKyError(err)) {\n throw new BCClientError('Client error', undefined, err);\n }\n\n throw new BCClientError('Unknown error', undefined, err);\n }\n\n let text: string;\n\n try {\n text = await response.text();\n } catch (err) {\n throw new BCResponseParseError(options.method, path, response.status, err, query, '');\n }\n\n let res: TRes;\n\n try {\n res = JSON.parse(text);\n } catch (err) {\n throw new BCResponseParseError(options.method, path, response.status, err, query, text);\n }\n\n this.logger?.debug(\n { method: options.method, url: response.url, status: response.status },\n 'Successful request',\n );\n\n return this.validate(\n res,\n responseSchema,\n BCResponseValidationError,\n options.method,\n path,\n 'Invalid API response',\n );\n }\n\n private async validate<T>(\n data: unknown,\n schema: StandardSchemaV1<T> | undefined,\n ErrorClass: new (\n message: string,\n method: string,\n path: string,\n data: unknown,\n error: StandardSchemaV1.FailureResult,\n ) => BCSchemaValidationError,\n method: string,\n path: string,\n message?: string,\n ): Promise<T> {\n if (!schema) {\n return data as T;\n }\n\n const result = await schema['~standard'].validate(data);\n\n if (result.issues) {\n throw new ErrorClass(message ?? 'Validation failed', method, path, data, result);\n }\n\n return result.value;\n }\n\n private makePath(version: ApiVersion, route: string): string {\n return `stores/${this.storeHash}/${version}/${route.replace(LEADING_SLASHES, '')}`;\n }\n\n private validateConfig() {\n const { accessToken, storeHash } = this.config;\n const errors: string[] = [];\n\n // Using reasonable assumptions about these credentials for validation.\n // This will not verify the credentials but at least guard against providing\n // something completely invalid like empty string\n if (typeof storeHash !== 'string' || storeHash.length <= 0) {\n errors.push('storeHash is empty');\n }\n\n if (typeof accessToken !== 'string' || accessToken.length <= 0) {\n errors.push('accessToken is empty');\n }\n\n if (errors.length > 0) {\n throw new BCCredentialsError(errors);\n }\n\n if (this.config.prefixUrl) {\n try {\n new URL(this.config.prefixUrl);\n } catch (err) {\n throw new BCClientError('Invalid prefixUrl', undefined, err);\n }\n }\n\n this.validateConcurrency(this.config.concurrency);\n }\n\n private validateConcurrency(concurrency: number | undefined | false) {\n if (concurrency === undefined) {\n return;\n }\n\n if (concurrency === false) {\n return concurrency;\n }\n\n if (concurrency <= 0 || concurrency > MAX_CONCURRENCY) {\n throw new BCClientError(`Invalid concurrency: allowed range (1:${MAX_CONCURRENCY})`, undefined);\n }\n\n return concurrency;\n }\n}\n"],"mappings":"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"}
|