@commercengine/storefront-sdk 0.3.7 → 0.3.9

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.ts CHANGED
@@ -8,6 +8,17 @@ import { HelpersClient } from "./lib/helper";
8
8
  import { CustomerClient } from "./lib/customer";
9
9
  import { TokenStorage, MemoryTokenStorage, BrowserTokenStorage, CookieTokenStorage } from "./lib/middleware";
10
10
  import { type UserInfo } from "./lib/jwt-utils";
11
+ /**
12
+ * Supported default headers that can be set at the SDK level
13
+ * Only includes headers that are actually supported by API endpoints
14
+ */
15
+ export interface SupportedDefaultHeaders {
16
+ /**
17
+ * Customer group ID used for pricing, promotions, and subscription rates
18
+ * If not provided, the API will use default pricing
19
+ */
20
+ customer_group_id?: string;
21
+ }
11
22
  /**
12
23
  * SDK initialization options
13
24
  */
@@ -58,6 +69,12 @@ export interface StorefrontSDKOptions {
58
69
  * Callback when tokens are cleared (logout/error)
59
70
  */
60
71
  onTokensCleared?: () => void;
72
+ /**
73
+ * Default headers to include with API requests
74
+ * These can be overridden at the method level
75
+ * Only supports headers that are actually available in the API
76
+ */
77
+ defaultHeaders?: SupportedDefaultHeaders;
61
78
  }
62
79
  /**
63
80
  * Main SDK class for the Storefront API
@@ -166,6 +183,18 @@ export declare class StorefrontSDK {
166
183
  * @returns Customer group ID or null if no token, invalid token, or user has no customer group
167
184
  */
168
185
  getCustomerGroupId(): Promise<string | null>;
186
+ /**
187
+ * Set default headers for all clients
188
+ *
189
+ * @param headers - Default headers to set (only supported headers allowed)
190
+ */
191
+ setDefaultHeaders(headers: SupportedDefaultHeaders): void;
192
+ /**
193
+ * Get current default headers
194
+ *
195
+ * @returns Current default headers
196
+ */
197
+ getDefaultHeaders(): SupportedDefaultHeaders | undefined;
169
198
  }
170
199
  export default StorefrontSDK;
171
200
  export { StorefrontAPIClient, AuthClient, CartClient, CatalogClient, CustomerClient, HelpersClient, ShippingClient, OrderClient, };
package/dist/index.js CHANGED
@@ -58,6 +58,7 @@ export class StorefrontSDK {
58
58
  tokenStorage: options.tokenStorage,
59
59
  onTokensUpdated: options.onTokensUpdated,
60
60
  onTokensCleared: options.onTokensCleared,
61
+ defaultHeaders: options.defaultHeaders,
61
62
  };
62
63
  this.catalog = new CatalogClient(config);
63
64
  this.cart = new CartClient(config);
@@ -198,6 +199,30 @@ export class StorefrontSDK {
198
199
  const userInfo = await this.getUserInfo();
199
200
  return userInfo?.customerGroupId || null;
200
201
  }
202
+ /**
203
+ * Set default headers for all clients
204
+ *
205
+ * @param headers - Default headers to set (only supported headers allowed)
206
+ */
207
+ setDefaultHeaders(headers) {
208
+ // Update config for all clients
209
+ const newConfig = { ...this.catalog["config"], defaultHeaders: headers };
210
+ this.catalog["config"] = newConfig;
211
+ this.cart["config"] = newConfig;
212
+ this.auth["config"] = newConfig;
213
+ this.customer["config"] = newConfig;
214
+ this.helpers["config"] = newConfig;
215
+ this.shipping["config"] = newConfig;
216
+ this.order["config"] = newConfig;
217
+ }
218
+ /**
219
+ * Get current default headers
220
+ *
221
+ * @returns Current default headers
222
+ */
223
+ getDefaultHeaders() {
224
+ return this.catalog["config"].defaultHeaders;
225
+ }
201
226
  }
202
227
  // Export the main SDK class
203
228
  export default StorefrontSDK;
@@ -149,15 +149,15 @@ export declare class CartClient extends StorefrontAPIClient {
149
149
  /**
150
150
  * Get all available coupons
151
151
  *
152
- * @param customerGroupId - The ID of the customer group
152
+ * @param headers - Optional header parameters (customer_group_id, etc.)
153
153
  * @returns Promise with all available coupons
154
154
  */
155
- getAvailableCoupons(headers: ListCouponsHeaderParams): Promise<ApiResult<ListCouponsContent>>;
155
+ getAvailableCoupons(headers?: ListCouponsHeaderParams): Promise<ApiResult<ListCouponsContent>>;
156
156
  /**
157
157
  * Get all available promotions
158
158
  *
159
- * @param customerGroupId - The ID of the customer group
159
+ * @param headers - Optional header parameters (customer_group_id, etc.)
160
160
  * @returns Promise with all available promotions
161
161
  */
162
- getAvailablePromotions(headers: ListPromotionsHeaderParams): Promise<ApiResult<ListPromotionsContent>>;
162
+ getAvailablePromotions(headers?: ListPromotionsHeaderParams): Promise<ApiResult<ListPromotionsContent>>;
163
163
  }
package/dist/lib/cart.js CHANGED
@@ -274,23 +274,29 @@ export class CartClient extends StorefrontAPIClient {
274
274
  /**
275
275
  * Get all available coupons
276
276
  *
277
- * @param customerGroupId - The ID of the customer group
277
+ * @param headers - Optional header parameters (customer_group_id, etc.)
278
278
  * @returns Promise with all available coupons
279
279
  */
280
280
  async getAvailableCoupons(headers) {
281
+ const mergedHeaders = this.mergeHeaders(headers);
281
282
  return this.executeRequest(() => this.client.GET("/carts/available-coupons", {
282
- headers: headers,
283
+ params: {
284
+ header: mergedHeaders,
285
+ },
283
286
  }));
284
287
  }
285
288
  /**
286
289
  * Get all available promotions
287
290
  *
288
- * @param customerGroupId - The ID of the customer group
291
+ * @param headers - Optional header parameters (customer_group_id, etc.)
289
292
  * @returns Promise with all available promotions
290
293
  */
291
294
  async getAvailablePromotions(headers) {
295
+ const mergedHeaders = this.mergeHeaders(headers);
292
296
  return this.executeRequest(() => this.client.GET("/carts/available-promotions", {
293
- headers: headers,
297
+ params: {
298
+ header: mergedHeaders,
299
+ },
294
300
  }));
295
301
  }
296
302
  }
@@ -1,5 +1,5 @@
1
1
  import { StorefrontAPIClient } from "./client";
2
- import type { ApiResult, GetProductDetailContent, GetProductDetailPathParams, GetProductDetailQuery, GetVariantDetailContent, GetVariantDetailQuery, GetVariantDetailPathParams, ListProductsContent, ListProductsQuery, ListProductVariantsContent, ListProductVariantsPathParams, ListProductVariantsQuery, ListCategoriesQuery, ListCategoriesContent, ListProductReviewsQuery, ListProductReviewsPathParams, ListProductReviewsContent, CreateProductReviewPathParams, CreateProductReviewFormData, CreateProductReviewResponse, SearchProductsBody, SearchProductsContent, ListSkusQuery, ListSkusContent, ListCrosssellProductsContent, ListCrosssellProductsQuery, ListUpsellProductsQuery, ListUpsellProductsContent, ListSimilarProductsQuery, ListSimilarProductsContent } from "../types/storefront-api-types";
2
+ import type { ApiResult, GetProductDetailContent, GetProductDetailPathParams, GetProductDetailHeaderParams, GetVariantDetailContent, GetVariantDetailPathParams, GetVariantDetailHeaderParams, ListProductsContent, ListProductsQuery, ListProductsHeaderParams, ListProductVariantsContent, ListProductVariantsPathParams, ListProductVariantsHeaderParams, ListCategoriesQuery, ListCategoriesContent, ListProductReviewsQuery, ListProductReviewsPathParams, ListProductReviewsContent, CreateProductReviewPathParams, CreateProductReviewFormData, CreateProductReviewResponse, SearchProductsBody, SearchProductsContent, ListSkusQuery, ListSkusContent, ListSkusHeaderParams, ListCrosssellProductsContent, ListCrosssellProductsQuery, ListCrosssellProductsHeaderParams, ListUpsellProductsQuery, ListUpsellProductsContent, ListUpsellProductsHeaderParams, ListSimilarProductsQuery, ListSimilarProductsContent, ListSimilarProductsHeaderParams } from "../types/storefront-api-types";
3
3
  /**
4
4
  * Client for interacting with catalog endpoints
5
5
  */
@@ -8,41 +8,42 @@ export declare class CatalogClient extends StorefrontAPIClient {
8
8
  * List all products
9
9
  *
10
10
  * @param options - Optional query parameters
11
+ * @param headers - Optional header parameters (customer_group_id, etc.)
11
12
  * @returns Promise with products and pagination info
12
13
  */
13
- listProducts(options?: ListProductsQuery): Promise<ApiResult<ListProductsContent>>;
14
+ listProducts(options?: ListProductsQuery, headers?: ListProductsHeaderParams): Promise<ApiResult<ListProductsContent>>;
14
15
  /**
15
16
  * List all skus
16
17
  *
17
18
  * @param options - Optional query parameters
19
+ * @param headers - Optional header parameters (customer_group_id, etc.)
18
20
  * @returns Promise with skus and pagination info
19
21
  */
20
- listSkus(options?: ListSkusQuery): Promise<ApiResult<ListSkusContent>>;
22
+ listSkus(options?: ListSkusQuery, headers?: ListSkusHeaderParams): Promise<ApiResult<ListSkusContent>>;
21
23
  /**
22
24
  * Get details for a specific product
23
25
  *
24
- * @param productId - The ID of the product
25
- * @param options - Optional query parameters
26
+ * @param pathParams - The path parameters (product ID or slug)
27
+ * @param headers - Optional header parameters (customer_group_id, etc.)
26
28
  * @returns Promise with product details
27
29
  */
28
- getProductDetail(pathParams: GetProductDetailPathParams, queryParams?: GetProductDetailQuery): Promise<ApiResult<GetProductDetailContent>>;
30
+ getProductDetail(pathParams: GetProductDetailPathParams, headers?: GetProductDetailHeaderParams): Promise<ApiResult<GetProductDetailContent>>;
29
31
  /**
30
32
  * List variants for a specific product
31
33
  *
32
- * @param productId - The ID of the product
33
- * @param options - Optional query parameters
34
+ * @param pathParams - The path parameters (product ID)
35
+ * @param headers - Optional header parameters (customer_group_id, etc.)
34
36
  * @returns Promise with variants
35
37
  */
36
- listProductVariants(pathParams: ListProductVariantsPathParams, queryParams?: ListProductVariantsQuery): Promise<ApiResult<ListProductVariantsContent>>;
38
+ listProductVariants(pathParams: ListProductVariantsPathParams, headers?: ListProductVariantsHeaderParams): Promise<ApiResult<ListProductVariantsContent>>;
37
39
  /**
38
40
  * Get details for a specific variant
39
41
  *
40
- * @param productId - The ID of the product
41
- * @param variantId - The ID of the variant
42
- * @param options - Optional query parameters
42
+ * @param pathParams - The path parameters (product ID and variant ID)
43
+ * @param headers - Optional header parameters (customer_group_id, etc.)
43
44
  * @returns Promise with variant details
44
45
  */
45
- getVariantDetail(pathParams: GetVariantDetailPathParams, queryParams?: GetVariantDetailQuery): Promise<ApiResult<GetVariantDetailContent>>;
46
+ getVariantDetail(pathParams: GetVariantDetailPathParams, headers?: GetVariantDetailHeaderParams): Promise<ApiResult<GetVariantDetailContent>>;
46
47
  /**
47
48
  * List all categories
48
49
  *
@@ -53,16 +54,16 @@ export declare class CatalogClient extends StorefrontAPIClient {
53
54
  /**
54
55
  * List reviews for a specific product
55
56
  *
56
- * @param productId - The ID of the product
57
- * @param options - Optional query parameters
57
+ * @param pathParams - The path parameters (product ID)
58
+ * @param queryParams - Optional query parameters
58
59
  * @returns Promise with reviews and pagination info
59
60
  */
60
61
  listProductReviews(pathParams: ListProductReviewsPathParams, queryParams?: ListProductReviewsQuery): Promise<ApiResult<ListProductReviewsContent>>;
61
62
  /**
62
63
  * Create a review for a specific product
63
64
  *
64
- * @param productId - The ID of the product
65
- * @param reviewData - The review data
65
+ * @param pathParams - The path parameters (product ID)
66
+ * @param formData - The review data
66
67
  * @returns Promise that resolves when the review is created
67
68
  */
68
69
  createProductReview(pathParams: CreateProductReviewPathParams, formData: CreateProductReviewFormData): Promise<ApiResult<CreateProductReviewResponse>>;
@@ -74,24 +75,27 @@ export declare class CatalogClient extends StorefrontAPIClient {
74
75
  */
75
76
  searchProducts(searchData: SearchProductsBody): Promise<ApiResult<SearchProductsContent>>;
76
77
  /**
77
- * Retrieve cross-sell recommendations for a specific product
78
+ * List cross-sell products
78
79
  *
79
80
  * @param options - Optional query parameters
80
- * @returns Promise with cross-sell recommendations with pagination
81
+ * @param headers - Optional header parameters (customer_group_id, etc.)
82
+ * @returns Promise with cross-sell products
81
83
  */
82
- listCrossSellProducts(options?: ListCrosssellProductsQuery): Promise<ApiResult<ListCrosssellProductsContent>>;
84
+ listCrossSellProducts(options?: ListCrosssellProductsQuery, headers?: ListCrosssellProductsHeaderParams): Promise<ApiResult<ListCrosssellProductsContent>>;
83
85
  /**
84
- * Retrieve up-sell recommendations for a specific product
86
+ * List up-sell products
85
87
  *
86
88
  * @param options - Optional query parameters
87
- * @returns Promise with up-sell recommendations with pagination
89
+ * @param headers - Optional header parameters (customer_group_id, etc.)
90
+ * @returns Promise with up-sell products
88
91
  */
89
- listUpSellProducts(options?: ListUpsellProductsQuery): Promise<ApiResult<ListUpsellProductsContent>>;
92
+ listUpSellProducts(options?: ListUpsellProductsQuery, headers?: ListUpsellProductsHeaderParams): Promise<ApiResult<ListUpsellProductsContent>>;
90
93
  /**
91
- * Retrieve related products for a specific product
94
+ * List similar products
92
95
  *
93
96
  * @param options - Optional query parameters
94
- * @returns Promise with related products with pagination
97
+ * @param headers - Optional header parameters (customer_group_id, etc.)
98
+ * @returns Promise with similar products
95
99
  */
96
- listSimilarProducts(options?: ListSimilarProductsQuery): Promise<ApiResult<ListSimilarProductsContent>>;
100
+ listSimilarProducts(options?: ListSimilarProductsQuery, headers?: ListSimilarProductsHeaderParams): Promise<ApiResult<ListSimilarProductsContent>>;
97
101
  }
@@ -7,67 +7,79 @@ export class CatalogClient extends StorefrontAPIClient {
7
7
  * List all products
8
8
  *
9
9
  * @param options - Optional query parameters
10
+ * @param headers - Optional header parameters (customer_group_id, etc.)
10
11
  * @returns Promise with products and pagination info
11
12
  */
12
- async listProducts(options) {
13
- return this.executeRequest(() => this.client.GET('/catalog/products', {
14
- params: { query: options },
13
+ async listProducts(options, headers) {
14
+ const mergedHeaders = this.mergeHeaders(headers);
15
+ return this.executeRequest(() => this.client.GET("/catalog/products", {
16
+ params: {
17
+ query: options,
18
+ header: mergedHeaders,
19
+ },
15
20
  }));
16
21
  }
17
22
  /**
18
23
  * List all skus
19
24
  *
20
25
  * @param options - Optional query parameters
26
+ * @param headers - Optional header parameters (customer_group_id, etc.)
21
27
  * @returns Promise with skus and pagination info
22
28
  */
23
- async listSkus(options) {
24
- return this.executeRequest(() => this.client.GET('/catalog/skus', {
25
- params: { query: options },
29
+ async listSkus(options, headers) {
30
+ const mergedHeaders = this.mergeHeaders(headers);
31
+ return this.executeRequest(() => this.client.GET("/catalog/skus", {
32
+ params: {
33
+ query: options,
34
+ header: mergedHeaders,
35
+ },
26
36
  }));
27
37
  }
28
38
  /**
29
39
  * Get details for a specific product
30
40
  *
31
- * @param productId - The ID of the product
32
- * @param options - Optional query parameters
41
+ * @param pathParams - The path parameters (product ID or slug)
42
+ * @param headers - Optional header parameters (customer_group_id, etc.)
33
43
  * @returns Promise with product details
34
44
  */
35
- async getProductDetail(pathParams, queryParams) {
36
- return this.executeRequest(() => this.client.GET('/catalog/products/{product_id}', {
45
+ async getProductDetail(pathParams, headers) {
46
+ const mergedHeaders = this.mergeHeaders(headers);
47
+ return this.executeRequest(() => this.client.GET("/catalog/products/{product_id_or_slug}", {
37
48
  params: {
38
49
  path: pathParams,
39
- query: queryParams,
50
+ header: mergedHeaders,
40
51
  },
41
52
  }));
42
53
  }
43
54
  /**
44
55
  * List variants for a specific product
45
56
  *
46
- * @param productId - The ID of the product
47
- * @param options - Optional query parameters
57
+ * @param pathParams - The path parameters (product ID)
58
+ * @param headers - Optional header parameters (customer_group_id, etc.)
48
59
  * @returns Promise with variants
49
60
  */
50
- async listProductVariants(pathParams, queryParams) {
61
+ async listProductVariants(pathParams, headers) {
62
+ const mergedHeaders = this.mergeHeaders(headers);
51
63
  return this.executeRequest(() => this.client.GET("/catalog/products/{product_id}/variants", {
52
64
  params: {
53
65
  path: pathParams,
54
- query: queryParams,
66
+ header: mergedHeaders,
55
67
  },
56
68
  }));
57
69
  }
58
70
  /**
59
71
  * Get details for a specific variant
60
72
  *
61
- * @param productId - The ID of the product
62
- * @param variantId - The ID of the variant
63
- * @param options - Optional query parameters
73
+ * @param pathParams - The path parameters (product ID and variant ID)
74
+ * @param headers - Optional header parameters (customer_group_id, etc.)
64
75
  * @returns Promise with variant details
65
76
  */
66
- async getVariantDetail(pathParams, queryParams) {
77
+ async getVariantDetail(pathParams, headers) {
78
+ const mergedHeaders = this.mergeHeaders(headers);
67
79
  return this.executeRequest(() => this.client.GET("/catalog/products/{product_id}/variants/{variant_id}", {
68
80
  params: {
69
81
  path: pathParams,
70
- query: queryParams,
82
+ header: mergedHeaders,
71
83
  },
72
84
  }));
73
85
  }
@@ -85,8 +97,8 @@ export class CatalogClient extends StorefrontAPIClient {
85
97
  /**
86
98
  * List reviews for a specific product
87
99
  *
88
- * @param productId - The ID of the product
89
- * @param options - Optional query parameters
100
+ * @param pathParams - The path parameters (product ID)
101
+ * @param queryParams - Optional query parameters
90
102
  * @returns Promise with reviews and pagination info
91
103
  */
92
104
  async listProductReviews(pathParams, queryParams) {
@@ -100,8 +112,8 @@ export class CatalogClient extends StorefrontAPIClient {
100
112
  /**
101
113
  * Create a review for a specific product
102
114
  *
103
- * @param productId - The ID of the product
104
- * @param reviewData - The review data
115
+ * @param pathParams - The path parameters (product ID)
116
+ * @param formData - The review data
105
117
  * @returns Promise that resolves when the review is created
106
118
  */
107
119
  async createProductReview(pathParams, formData) {
@@ -125,7 +137,7 @@ export class CatalogClient extends StorefrontAPIClient {
125
137
  }
126
138
  }
127
139
  return fd;
128
- }
140
+ },
129
141
  }));
130
142
  }
131
143
  /**
@@ -140,41 +152,50 @@ export class CatalogClient extends StorefrontAPIClient {
140
152
  }));
141
153
  }
142
154
  /**
143
- * Retrieve cross-sell recommendations for a specific product
155
+ * List cross-sell products
144
156
  *
145
157
  * @param options - Optional query parameters
146
- * @returns Promise with cross-sell recommendations with pagination
158
+ * @param headers - Optional header parameters (customer_group_id, etc.)
159
+ * @returns Promise with cross-sell products
147
160
  */
148
- async listCrossSellProducts(options) {
161
+ async listCrossSellProducts(options, headers) {
162
+ const mergedHeaders = this.mergeHeaders(headers);
149
163
  return this.executeRequest(() => this.client.GET("/catalog/products/cross-sell", {
150
164
  params: {
151
165
  query: options,
166
+ header: mergedHeaders,
152
167
  },
153
168
  }));
154
169
  }
155
170
  /**
156
- * Retrieve up-sell recommendations for a specific product
171
+ * List up-sell products
157
172
  *
158
173
  * @param options - Optional query parameters
159
- * @returns Promise with up-sell recommendations with pagination
174
+ * @param headers - Optional header parameters (customer_group_id, etc.)
175
+ * @returns Promise with up-sell products
160
176
  */
161
- async listUpSellProducts(options) {
177
+ async listUpSellProducts(options, headers) {
178
+ const mergedHeaders = this.mergeHeaders(headers);
162
179
  return this.executeRequest(() => this.client.GET("/catalog/products/up-sell", {
163
180
  params: {
164
181
  query: options,
182
+ header: mergedHeaders,
165
183
  },
166
184
  }));
167
185
  }
168
186
  /**
169
- * Retrieve related products for a specific product
187
+ * List similar products
170
188
  *
171
189
  * @param options - Optional query parameters
172
- * @returns Promise with related products with pagination
190
+ * @param headers - Optional header parameters (customer_group_id, etc.)
191
+ * @returns Promise with similar products
173
192
  */
174
- async listSimilarProducts(options) {
193
+ async listSimilarProducts(options, headers) {
194
+ const mergedHeaders = this.mergeHeaders(headers);
175
195
  return this.executeRequest(() => this.client.GET("/catalog/products/similar", {
176
196
  params: {
177
197
  query: options,
198
+ header: mergedHeaders,
178
199
  },
179
200
  }));
180
201
  }
@@ -22,6 +22,7 @@ export declare class StorefrontAPIClient {
22
22
  protected client: ReturnType<typeof createClient<paths>>;
23
23
  protected config: StorefrontSDKOptions;
24
24
  private readonly baseUrl;
25
+ private initializationPromise;
25
26
  /**
26
27
  * Create a new StorefrontAPIClient
27
28
  *
@@ -97,4 +98,16 @@ export declare class StorefrontAPIClient {
97
98
  error?: ApiErrorResponse;
98
99
  response: Response;
99
100
  }>): Promise<ApiResult<T>>;
101
+ /**
102
+ * Initialize tokens in storage (private helper method)
103
+ */
104
+ private initializeTokens;
105
+ /**
106
+ * Merge default headers with method-level headers
107
+ * Method-level headers take precedence over default headers
108
+ *
109
+ * @param methodHeaders - Headers passed to the specific method call
110
+ * @returns Merged headers object
111
+ */
112
+ protected mergeHeaders<T extends Record<string, any> = Record<string, any>>(methodHeaders?: T): T;
100
113
  }
@@ -22,6 +22,7 @@ export class StorefrontAPIClient {
22
22
  client;
23
23
  config;
24
24
  baseUrl;
25
+ initializationPromise = null;
25
26
  /**
26
27
  * Create a new StorefrontAPIClient
27
28
  *
@@ -46,17 +47,9 @@ export class StorefrontAPIClient {
46
47
  this.client.use(authMiddleware);
47
48
  // If initial tokens were provided, store them in tokenStorage
48
49
  if (this.config.accessToken) {
49
- this.config.tokenStorage.setAccessToken(this.config.accessToken).catch(error => {
50
- console.warn('Failed to set initial access token in storage:', error);
51
- });
52
- // Clear the manual token since we're using storage
50
+ this.initializationPromise = this.initializeTokens(this.config.accessToken, this.config.refreshToken);
51
+ // Clear the manual tokens since we're using storage
53
52
  this.config.accessToken = undefined;
54
- }
55
- if (this.config.refreshToken) {
56
- this.config.tokenStorage.setRefreshToken(this.config.refreshToken).catch(error => {
57
- console.warn('Failed to set initial refresh token in storage:', error);
58
- });
59
- // Clear the manual refresh token since we're using storage
60
53
  this.config.refreshToken = undefined;
61
54
  }
62
55
  }
@@ -100,14 +93,14 @@ export class StorefrontAPIClient {
100
93
  const timeoutId = setTimeout(() => controller.abort(), this.config.timeout);
101
94
  // Merge with existing signal if present
102
95
  if (request.signal) {
103
- request.signal.addEventListener('abort', () => controller.abort());
96
+ request.signal.addEventListener("abort", () => controller.abort());
104
97
  }
105
98
  // Create new request with timeout signal
106
99
  const newRequest = new Request(request, {
107
100
  signal: controller.signal,
108
101
  });
109
102
  // Clean up timeout when request completes
110
- controller.signal.addEventListener('abort', () => clearTimeout(timeoutId));
103
+ controller.signal.addEventListener("abort", () => clearTimeout(timeoutId));
111
104
  return newRequest;
112
105
  },
113
106
  });
@@ -149,6 +142,10 @@ export class StorefrontAPIClient {
149
142
  * @returns The Authorization header value or empty string if no token is set
150
143
  */
151
144
  async getAuthorizationHeader() {
145
+ // Wait for initialization to complete if using token storage
146
+ if (this.config.tokenStorage && this.initializationPromise) {
147
+ await this.initializationPromise;
148
+ }
152
149
  if (this.config.tokenStorage) {
153
150
  const token = await this.config.tokenStorage.getAccessToken();
154
151
  return token ? `Bearer ${token}` : "";
@@ -236,11 +233,60 @@ export class StorefrontAPIClient {
236
233
  data: null,
237
234
  error: {
238
235
  success: false,
239
- code: 'NETWORK_ERROR',
240
- message: 'Network error occurred',
236
+ code: "NETWORK_ERROR",
237
+ message: "Network error occurred",
241
238
  error: err,
242
239
  },
243
240
  };
244
241
  }
245
242
  }
243
+ /**
244
+ * Initialize tokens in storage (private helper method)
245
+ */
246
+ async initializeTokens(accessToken, refreshToken) {
247
+ try {
248
+ if (this.config.tokenStorage) {
249
+ await this.config.tokenStorage.setAccessToken(accessToken);
250
+ if (refreshToken) {
251
+ await this.config.tokenStorage.setRefreshToken(refreshToken);
252
+ }
253
+ }
254
+ }
255
+ catch (error) {
256
+ console.warn("Failed to initialize tokens in storage:", error);
257
+ }
258
+ }
259
+ /**
260
+ * Merge default headers with method-level headers
261
+ * Method-level headers take precedence over default headers
262
+ *
263
+ * @param methodHeaders - Headers passed to the specific method call
264
+ * @returns Merged headers object
265
+ */
266
+ mergeHeaders(methodHeaders) {
267
+ if (!this.config.defaultHeaders && !methodHeaders) {
268
+ return {};
269
+ }
270
+ // Start with default headers, but only include supported ones
271
+ const merged = {};
272
+ // Add default headers if they exist
273
+ if (this.config.defaultHeaders) {
274
+ if (this.config.defaultHeaders.customer_group_id !== undefined) {
275
+ merged.customer_group_id =
276
+ this.config.defaultHeaders.customer_group_id;
277
+ }
278
+ // Future: Add other supported headers here as they become available
279
+ }
280
+ if (methodHeaders) {
281
+ // Method headers override default headers
282
+ Object.assign(merged, methodHeaders);
283
+ }
284
+ // Remove undefined values
285
+ Object.keys(merged).forEach((key) => {
286
+ if (merged[key] === undefined) {
287
+ delete merged[key];
288
+ }
289
+ });
290
+ return merged;
291
+ }
246
292
  }
@@ -15,21 +15,23 @@ export type ApiErrorResponse = {
15
15
  export type ListProductsResponse = paths['/catalog/products']['get']['responses'][200]['content']['application/json'];
16
16
  export type ListProductsContent = ListProductsResponse['content'];
17
17
  export type ListProductsQuery = paths['/catalog/products']['get']['parameters']['query'];
18
+ export type ListProductsHeaderParams = paths['/catalog/products']['get']['parameters']['header'];
18
19
  export type ListSkusResponse = paths['/catalog/skus']['get']['responses'][200]['content']['application/json'];
19
20
  export type ListSkusContent = ListSkusResponse['content'];
20
21
  export type ListSkusQuery = paths['/catalog/skus']['get']['parameters']['query'];
21
- export type GetProductDetailResponse = paths['/catalog/products/{product_id}']['get']['responses'][200]['content']['application/json'];
22
+ export type ListSkusHeaderParams = paths['/catalog/skus']['get']['parameters']['header'];
23
+ export type GetProductDetailResponse = paths['/catalog/products/{product_id_or_slug}']['get']['responses'][200]['content']['application/json'];
22
24
  export type GetProductDetailContent = GetProductDetailResponse['content'];
23
- export type GetProductDetailQuery = paths['/catalog/products/{product_id}']['get']['parameters']['query'];
24
- export type GetProductDetailPathParams = paths['/catalog/products/{product_id}']['get']['parameters']['path'];
25
+ export type GetProductDetailPathParams = paths['/catalog/products/{product_id_or_slug}']['get']['parameters']['path'];
26
+ export type GetProductDetailHeaderParams = paths['/catalog/products/{product_id_or_slug}']['get']['parameters']['header'];
25
27
  export type ListProductVariantsResponse = paths['/catalog/products/{product_id}/variants']['get']['responses'][200]['content']['application/json'];
26
28
  export type ListProductVariantsContent = ListProductVariantsResponse['content'];
27
- export type ListProductVariantsQuery = paths['/catalog/products/{product_id}/variants']['get']['parameters']['query'];
28
29
  export type ListProductVariantsPathParams = paths['/catalog/products/{product_id}/variants']['get']['parameters']['path'];
30
+ export type ListProductVariantsHeaderParams = paths['/catalog/products/{product_id}/variants']['get']['parameters']['header'];
29
31
  export type GetVariantDetailResponse = paths['/catalog/products/{product_id}/variants/{variant_id}']['get']['responses'][200]['content']['application/json'];
30
32
  export type GetVariantDetailContent = GetVariantDetailResponse['content'];
31
- export type GetVariantDetailQuery = paths['/catalog/products/{product_id}/variants/{variant_id}']['get']['parameters']['query'];
32
33
  export type GetVariantDetailPathParams = paths['/catalog/products/{product_id}/variants/{variant_id}']['get']['parameters']['path'];
34
+ export type GetVariantDetailHeaderParams = paths['/catalog/products/{product_id}/variants/{variant_id}']['get']['parameters']['header'];
33
35
  export type ListCategoriesResponse = paths['/catalog/categories']['get']['responses'][200]['content']['application/json'];
34
36
  export type ListCategoriesContent = ListCategoriesResponse['content'];
35
37
  export type ListCategoriesQuery = paths['/catalog/categories']['get']['parameters']['query'];
@@ -43,12 +45,15 @@ export type CreateProductReviewFormData = NonNullable<paths['/catalog/products/{
43
45
  export type ListSimilarProductsResponse = paths['/catalog/products/similar']['get']['responses'][200]['content']['application/json'];
44
46
  export type ListSimilarProductsContent = ListSimilarProductsResponse['content'];
45
47
  export type ListSimilarProductsQuery = paths['/catalog/products/similar']['get']['parameters']['query'];
48
+ export type ListSimilarProductsHeaderParams = paths['/catalog/products/similar']['get']['parameters']['header'];
46
49
  export type ListUpsellProductsResponse = paths['/catalog/products/up-sell']['get']['responses'][200]['content']['application/json'];
47
50
  export type ListUpsellProductsContent = ListUpsellProductsResponse['content'];
48
51
  export type ListUpsellProductsQuery = paths['/catalog/products/up-sell']['get']['parameters']['query'];
52
+ export type ListUpsellProductsHeaderParams = paths['/catalog/products/up-sell']['get']['parameters']['header'];
49
53
  export type ListCrosssellProductsResponse = paths['/catalog/products/cross-sell']['get']['responses'][200]['content']['application/json'];
50
54
  export type ListCrosssellProductsContent = ListCrosssellProductsResponse['content'];
51
55
  export type ListCrosssellProductsQuery = paths['/catalog/products/cross-sell']['get']['parameters']['query'];
56
+ export type ListCrosssellProductsHeaderParams = paths['/catalog/products/cross-sell']['get']['parameters']['header'];
52
57
  export type SearchProductsResponse = paths['/catalog/products/search']['post']['responses'][200]['content']['application/json'];
53
58
  export type SearchProductsContent = SearchProductsResponse['content'];
54
59
  export type SearchProductsBody = NonNullable<paths['/catalog/products/search']['post']['requestBody']>['content']['application/json'];
@@ -151,6 +156,8 @@ export type DeleteAddressResponse = paths['/customers/{user_id}/addresses/{addre
151
156
  export type DeleteAddressPathParams = paths['/customers/{user_id}/addresses/{address_id}']['delete']['parameters']['path'];
152
157
  export type ListKycDocumentResponse = paths['/store/kyc-document']['get']['responses'][200]['content']['application/json'];
153
158
  export type ListKycDocumentContent = ListKycDocumentResponse['content'];
159
+ export type GetConfigResponse = paths['/store/config']['get']['responses'][200]['content']['application/json'];
160
+ export type GetConfigContent = GetConfigResponse['content'];
154
161
  export type ListDocumentsResponse = paths['/customers/{id}/documents']['get']['responses'][200]['content']['application/json'];
155
162
  export type ListDocumentsContent = ListDocumentsResponse['content'];
156
163
  export type ListDocumentsPathParams = paths['/customers/{id}/documents']['get']['parameters']['path'];
@@ -44,7 +44,7 @@ export interface paths {
44
44
  patch?: never;
45
45
  trace?: never;
46
46
  };
47
- "/catalog/products/{product_id}": {
47
+ "/catalog/products/{product_id_or_slug}": {
48
48
  parameters: {
49
49
  query?: never;
50
50
  header?: never;
@@ -53,7 +53,7 @@ export interface paths {
53
53
  };
54
54
  /**
55
55
  * Retrieve a product detail
56
- * @description Retrieves the details of an existing product. Supply the unique product ID from either a product creation request or the product list, and Commerce Engine will return the corresponding product information.
56
+ * @description Retrieves the details of an existing product. Supply either the unique product ID or the unique slug, and Commerce Engine will return the corresponding product information.
57
57
  */
58
58
  get: operations["get-product-detail"];
59
59
  put?: never;
@@ -663,6 +663,26 @@ export interface paths {
663
663
  patch?: never;
664
664
  trace?: never;
665
665
  };
666
+ "/store/config": {
667
+ parameters: {
668
+ query?: never;
669
+ header?: never;
670
+ path?: never;
671
+ cookie?: never;
672
+ };
673
+ /**
674
+ * Retrieve store config
675
+ * @description Retrieve store config detail
676
+ */
677
+ get: operations["get-config"];
678
+ put?: never;
679
+ post?: never;
680
+ delete?: never;
681
+ options?: never;
682
+ head?: never;
683
+ patch?: never;
684
+ trace?: never;
685
+ };
666
686
  "/customers/{id}/documents": {
667
687
  parameters: {
668
688
  query?: never;
@@ -1848,6 +1868,7 @@ export interface components {
1848
1868
  readonly has_variant: boolean;
1849
1869
  tags: string[] | null;
1850
1870
  category_ids: string[];
1871
+ categories: components["schemas"]["Category"][];
1851
1872
  /** Format: double */
1852
1873
  reviews_rating_sum: number;
1853
1874
  reviews_count: number;
@@ -2337,10 +2358,9 @@ export interface components {
2337
2358
  readonly email?: string;
2338
2359
  /**
2339
2360
  * @description Reviews with approved status will be displayed.
2340
- * @default pending
2341
2361
  * @enum {string}
2342
2362
  */
2343
- readonly status: "approved" | "rejected" | "archived" | "pending";
2363
+ readonly status?: "approved";
2344
2364
  /** @default false */
2345
2365
  is_featured: boolean;
2346
2366
  tags?: string[];
@@ -4272,6 +4292,73 @@ export interface components {
4272
4292
  /** @enum {unknown} */
4273
4293
  verification_type?: "auto" | "manual";
4274
4294
  };
4295
+ /** StoreConfig */
4296
+ StoreConfig: {
4297
+ /** @default false */
4298
+ is_kyc_enabled: boolean;
4299
+ /** @default false */
4300
+ is_customer_group_enabled: boolean;
4301
+ brand: components["schemas"]["Brand"];
4302
+ currency: components["schemas"]["Currency"];
4303
+ readonly customer_groups: components["schemas"]["CustomerGroup"][];
4304
+ readonly kyc_documents: components["schemas"]["KycDocumentConfig"][];
4305
+ measurement: components["schemas"]["MeasurementUnit"];
4306
+ terms_of_service: components["schemas"]["StoreTemplate"];
4307
+ refund_policy: components["schemas"]["StoreTemplate"];
4308
+ };
4309
+ /** StoreTemplate */
4310
+ StoreTemplate: {
4311
+ readonly id: string;
4312
+ name: string;
4313
+ /** @description to be used in email subject or notification heading if provided. */
4314
+ content_title: string | null;
4315
+ /** @enum {unknown} */
4316
+ content_type: "html" | "markdown" | "plaintext";
4317
+ content: string;
4318
+ };
4319
+ /** KycDocumentConfig */
4320
+ KycDocumentConfig: {
4321
+ readonly id: string;
4322
+ /** @enum {unknown} */
4323
+ document_type: "gst" | "pan" | "other";
4324
+ title: string;
4325
+ description: string | null;
4326
+ /** @default true */
4327
+ active: boolean;
4328
+ is_mandatory: boolean;
4329
+ is_attachment_required: boolean;
4330
+ /** @enum {unknown} */
4331
+ verification_type: "auto" | "manual";
4332
+ };
4333
+ /** CustomerGroup */
4334
+ CustomerGroup: {
4335
+ readonly id: string;
4336
+ name: string;
4337
+ description: string | null;
4338
+ /** @description first record will be treated as default if not changed. */
4339
+ is_default: boolean;
4340
+ /** @default true */
4341
+ active: boolean;
4342
+ };
4343
+ /** Brand */
4344
+ Brand: {
4345
+ /** @description brand name. it will be used in emails and other communications. */
4346
+ name: string;
4347
+ readonly logo_url: string;
4348
+ /** @description json object having key - value pair.
4349
+ *
4350
+ * example - {"facebook": "www.facebook.com/commecengine"} */
4351
+ social_media_links: {
4352
+ [key: string]: string;
4353
+ };
4354
+ };
4355
+ /** MeasurementUnit */
4356
+ MeasurementUnit: {
4357
+ /** @enum {unknown} */
4358
+ weight?: "gm";
4359
+ /** @enum {unknown} */
4360
+ dimension?: "cm";
4361
+ };
4275
4362
  /** GstinDetail */
4276
4363
  GstinDetail: {
4277
4364
  id?: string;
@@ -4453,6 +4540,8 @@ export interface components {
4453
4540
  sortingParam: string;
4454
4541
  /** @description search keyword */
4455
4542
  searchKeyword: string;
4543
+ /** @description The customer_group_id is used to determine product pricing, promotions, and subscription rates. If a valid customer_group_id is provided, pricing details will be retrieved accordingly. If no matching data is found for the specified customer_group_id, the system will fall back to the default customer_group_id. If no data is found for the default group either, the highest applicable price will be returned. */
4544
+ CustomerGroupId: string;
4456
4545
  };
4457
4546
  requestBodies: never;
4458
4547
  headers: never;
@@ -4469,12 +4558,15 @@ export interface operations {
4469
4558
  limit?: components["parameters"]["pageLimitParam"];
4470
4559
  /** @description JSON string format: {"field1":"asc", "field2":"desc"} */
4471
4560
  sort_by?: components["parameters"]["sortingParam"];
4472
- /** @description filter products by categories */
4561
+ /** @description filter products by categories ids */
4473
4562
  category_id?: string[];
4474
- /** @description use this param only if different pricing is configured as per customer group */
4475
- customer_group_id?: string;
4563
+ /** @description filter products by categories slugs */
4564
+ category_slug?: string[];
4565
+ };
4566
+ header?: {
4567
+ /** @description The customer_group_id is used to determine product pricing, promotions, and subscription rates. If a valid customer_group_id is provided, pricing details will be retrieved accordingly. If no matching data is found for the specified customer_group_id, the system will fall back to the default customer_group_id. If no data is found for the default group either, the highest applicable price will be returned. */
4568
+ customer_group_id?: components["parameters"]["CustomerGroupId"];
4476
4569
  };
4477
- header?: never;
4478
4570
  path?: never;
4479
4571
  cookie?: never;
4480
4572
  };
@@ -4511,12 +4603,13 @@ export interface operations {
4511
4603
  sort_by?: components["parameters"]["sortingParam"];
4512
4604
  /** @description filter sku by categories */
4513
4605
  category_id?: string[];
4514
- /** @description use this param only if different pricing is configured as per customer group */
4515
- customer_group_id?: string;
4516
4606
  /** @description array of sku */
4517
4607
  sku?: string[];
4518
4608
  };
4519
- header?: never;
4609
+ header?: {
4610
+ /** @description The customer_group_id is used to determine product pricing, promotions, and subscription rates. If a valid customer_group_id is provided, pricing details will be retrieved accordingly. If no matching data is found for the specified customer_group_id, the system will fall back to the default customer_group_id. If no data is found for the default group either, the highest applicable price will be returned. */
4611
+ customer_group_id?: components["parameters"]["CustomerGroupId"];
4612
+ };
4520
4613
  path?: never;
4521
4614
  cookie?: never;
4522
4615
  };
@@ -4544,14 +4637,14 @@ export interface operations {
4544
4637
  };
4545
4638
  "get-product-detail": {
4546
4639
  parameters: {
4547
- query?: {
4548
- /** @description use this param only if different pricing is configured as per customer group */
4549
- customer_group_id?: string;
4640
+ query?: never;
4641
+ header?: {
4642
+ /** @description The customer_group_id is used to determine product pricing, promotions, and subscription rates. If a valid customer_group_id is provided, pricing details will be retrieved accordingly. If no matching data is found for the specified customer_group_id, the system will fall back to the default customer_group_id. If no data is found for the default group either, the highest applicable price will be returned. */
4643
+ customer_group_id?: components["parameters"]["CustomerGroupId"];
4550
4644
  };
4551
- header?: never;
4552
4645
  path: {
4553
- /** @description id of a particular product */
4554
- product_id: string;
4646
+ /** @description The unique identifier of the product. Can be either the product ID or the slug. */
4647
+ product_id_or_slug: string;
4555
4648
  };
4556
4649
  cookie?: never;
4557
4650
  };
@@ -4578,11 +4671,11 @@ export interface operations {
4578
4671
  };
4579
4672
  "list-product-variants": {
4580
4673
  parameters: {
4581
- query?: {
4582
- /** @description use this param only if different pricing is configured as per customer group */
4583
- customer_group_id?: string;
4674
+ query?: never;
4675
+ header?: {
4676
+ /** @description The customer_group_id is used to determine product pricing, promotions, and subscription rates. If a valid customer_group_id is provided, pricing details will be retrieved accordingly. If no matching data is found for the specified customer_group_id, the system will fall back to the default customer_group_id. If no data is found for the default group either, the highest applicable price will be returned. */
4677
+ customer_group_id?: components["parameters"]["CustomerGroupId"];
4584
4678
  };
4585
- header?: never;
4586
4679
  path: {
4587
4680
  /** @description ID of a particular product */
4588
4681
  product_id: string;
@@ -4612,11 +4705,11 @@ export interface operations {
4612
4705
  };
4613
4706
  "get-variant-detail": {
4614
4707
  parameters: {
4615
- query?: {
4616
- /** @description use this param only if different pricing is configured as per customer group */
4617
- customer_group_id?: string;
4708
+ query?: never;
4709
+ header?: {
4710
+ /** @description The customer_group_id is used to determine product pricing, promotions, and subscription rates. If a valid customer_group_id is provided, pricing details will be retrieved accordingly. If no matching data is found for the specified customer_group_id, the system will fall back to the default customer_group_id. If no data is found for the default group either, the highest applicable price will be returned. */
4711
+ customer_group_id?: components["parameters"]["CustomerGroupId"];
4618
4712
  };
4619
- header?: never;
4620
4713
  path: {
4621
4714
  /** @description product id */
4622
4715
  product_id: string;
@@ -4649,7 +4742,7 @@ export interface operations {
4649
4742
  "list-categories": {
4650
4743
  parameters: {
4651
4744
  query?: {
4652
- /** @description To return child categories */
4745
+ /** @description To return child categories using category id. */
4653
4746
  parent_category_id?: string;
4654
4747
  /** @description return child categories up to nesting level */
4655
4748
  nested_level?: number;
@@ -4657,6 +4750,8 @@ export interface operations {
4657
4750
  search?: components["parameters"]["searchKeyword"];
4658
4751
  /** @description JSON string format: {"field1":"asc", "field2":"desc"} */
4659
4752
  sort_by?: components["parameters"]["sortingParam"];
4753
+ /** @description To return child categories using category slug */
4754
+ parent_category_slug?: string;
4660
4755
  };
4661
4756
  header?: never;
4662
4757
  path?: never;
@@ -4774,7 +4869,10 @@ export interface operations {
4774
4869
  /** @description json to sort records */
4775
4870
  sort_by?: string;
4776
4871
  };
4777
- header?: never;
4872
+ header?: {
4873
+ /** @description The customer_group_id is used to determine product pricing, promotions, and subscription rates. If a valid customer_group_id is provided, pricing details will be retrieved accordingly. If no matching data is found for the specified customer_group_id, the system will fall back to the default customer_group_id. If no data is found for the default group either, the highest applicable price will be returned. */
4874
+ customer_group_id?: components["parameters"]["CustomerGroupId"];
4875
+ };
4778
4876
  path?: never;
4779
4877
  cookie?: never;
4780
4878
  };
@@ -4812,7 +4910,10 @@ export interface operations {
4812
4910
  /** @description json to sort records */
4813
4911
  sort_by?: string;
4814
4912
  };
4815
- header?: never;
4913
+ header?: {
4914
+ /** @description The customer_group_id is used to determine product pricing, promotions, and subscription rates. If a valid customer_group_id is provided, pricing details will be retrieved accordingly. If no matching data is found for the specified customer_group_id, the system will fall back to the default customer_group_id. If no data is found for the default group either, the highest applicable price will be returned. */
4915
+ customer_group_id?: components["parameters"]["CustomerGroupId"];
4916
+ };
4816
4917
  path?: never;
4817
4918
  cookie?: never;
4818
4919
  };
@@ -4851,7 +4952,10 @@ export interface operations {
4851
4952
  /** @description json to sort records */
4852
4953
  sort_by?: string;
4853
4954
  };
4854
- header?: never;
4955
+ header?: {
4956
+ /** @description The customer_group_id is used to determine product pricing, promotions, and subscription rates. If a valid customer_group_id is provided, pricing details will be retrieved accordingly. If no matching data is found for the specified customer_group_id, the system will fall back to the default customer_group_id. If no data is found for the default group either, the highest applicable price will be returned. */
4957
+ customer_group_id?: components["parameters"]["CustomerGroupId"];
4958
+ };
4855
4959
  path?: never;
4856
4960
  cookie?: never;
4857
4961
  };
@@ -5989,6 +6093,35 @@ export interface operations {
5989
6093
  404: components["responses"]["NotFound"];
5990
6094
  };
5991
6095
  };
6096
+ "get-config": {
6097
+ parameters: {
6098
+ query?: never;
6099
+ header?: never;
6100
+ path?: never;
6101
+ cookie?: never;
6102
+ };
6103
+ requestBody?: never;
6104
+ responses: {
6105
+ /** @description OK */
6106
+ 200: {
6107
+ headers: {
6108
+ [name: string]: unknown;
6109
+ };
6110
+ content: {
6111
+ "application/json": {
6112
+ message?: string;
6113
+ success?: boolean;
6114
+ content?: {
6115
+ store_config?: components["schemas"]["StoreConfig"];
6116
+ };
6117
+ };
6118
+ };
6119
+ };
6120
+ 400: components["responses"]["BadRequest"];
6121
+ 401: components["responses"]["Unauthorized"];
6122
+ 404: components["responses"]["NotFound"];
6123
+ };
6124
+ };
5992
6125
  "list-documents": {
5993
6126
  parameters: {
5994
6127
  query?: never;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@commercengine/storefront-sdk",
3
- "version": "0.3.7",
3
+ "version": "0.3.9",
4
4
  "description": "TypeScript SDK for the Storefront API",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",