@commercengine/storefront-sdk 0.2.1 → 0.3.1

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.
@@ -1,11 +1,8 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.CatalogClient = void 0;
4
- const client_1 = require("./client");
1
+ import { StorefrontAPIClient } from "./client";
5
2
  /**
6
3
  * Client for interacting with catalog endpoints
7
4
  */
8
- class CatalogClient extends client_1.StorefrontAPIClient {
5
+ export class CatalogClient extends StorefrontAPIClient {
9
6
  /**
10
7
  * List all products
11
8
  *
@@ -13,15 +10,20 @@ class CatalogClient extends client_1.StorefrontAPIClient {
13
10
  * @returns Promise with products and pagination info
14
11
  */
15
12
  async listProducts(options) {
16
- return this.executeRequest(async () => {
17
- const { data, error } = await this.client.GET("/catalog/products", {
18
- params: { query: options },
19
- });
20
- if (error) {
21
- this.handleError(error);
22
- }
23
- return data?.content;
24
- });
13
+ return this.executeRequest(() => this.client.GET('/catalog/products', {
14
+ params: { query: options },
15
+ }));
16
+ }
17
+ /**
18
+ * List all skus
19
+ *
20
+ * @param options - Optional query parameters
21
+ * @returns Promise with skus and pagination info
22
+ */
23
+ async listSkus(options) {
24
+ return this.executeRequest(() => this.client.GET('/catalog/skus', {
25
+ params: { query: options },
26
+ }));
25
27
  }
26
28
  /**
27
29
  * Get details for a specific product
@@ -30,19 +32,13 @@ class CatalogClient extends client_1.StorefrontAPIClient {
30
32
  * @param options - Optional query parameters
31
33
  * @returns Promise with product details
32
34
  */
33
- async getProductDetail(productId, options) {
34
- return this.executeRequest(async () => {
35
- const { data, error } = await this.client.GET("/catalog/products/{product_id}", {
36
- params: {
37
- path: { product_id: productId },
38
- query: options,
39
- },
40
- });
41
- if (error) {
42
- this.handleError(error);
43
- }
44
- return data?.content;
45
- });
35
+ async getProductDetail(pathParams, queryParams) {
36
+ return this.executeRequest(() => this.client.GET('/catalog/products/{product_id}', {
37
+ params: {
38
+ path: pathParams,
39
+ query: queryParams,
40
+ },
41
+ }));
46
42
  }
47
43
  /**
48
44
  * List variants for a specific product
@@ -51,19 +47,13 @@ class CatalogClient extends client_1.StorefrontAPIClient {
51
47
  * @param options - Optional query parameters
52
48
  * @returns Promise with variants
53
49
  */
54
- async listProductVariants(productId, options) {
55
- return this.executeRequest(async () => {
56
- const { data, error } = await this.client.GET("/catalog/products/{product_id}/variants", {
57
- params: {
58
- path: { product_id: productId },
59
- query: options,
60
- },
61
- });
62
- if (error) {
63
- this.handleError(error);
64
- }
65
- return data?.content;
66
- });
50
+ async listProductVariants(pathParams, queryParams) {
51
+ return this.executeRequest(() => this.client.GET("/catalog/products/{product_id}/variants", {
52
+ params: {
53
+ path: pathParams,
54
+ query: queryParams,
55
+ },
56
+ }));
67
57
  }
68
58
  /**
69
59
  * Get details for a specific variant
@@ -73,22 +63,13 @@ class CatalogClient extends client_1.StorefrontAPIClient {
73
63
  * @param options - Optional query parameters
74
64
  * @returns Promise with variant details
75
65
  */
76
- async getVariantDetail(productId, variantId, options) {
77
- return this.executeRequest(async () => {
78
- const { data, error } = await this.client.GET("/catalog/products/{product_id}/variants/{variant_id}", {
79
- params: {
80
- path: {
81
- product_id: productId,
82
- variant_id: variantId,
83
- },
84
- query: options,
85
- },
86
- });
87
- if (error) {
88
- this.handleError(error);
89
- }
90
- return data?.content;
91
- });
66
+ async getVariantDetail(pathParams, queryParams) {
67
+ return this.executeRequest(() => this.client.GET("/catalog/products/{product_id}/variants/{variant_id}", {
68
+ params: {
69
+ path: pathParams,
70
+ query: queryParams,
71
+ },
72
+ }));
92
73
  }
93
74
  /**
94
75
  * List all categories
@@ -97,15 +78,9 @@ class CatalogClient extends client_1.StorefrontAPIClient {
97
78
  * @returns Promise with categories and pagination info
98
79
  */
99
80
  async listCategories(options) {
100
- return this.executeRequest(async () => {
101
- const { data, error } = await this.client.GET("/catalog/categories", {
102
- params: { query: options },
103
- });
104
- if (error) {
105
- this.handleError(error);
106
- }
107
- return data?.content;
108
- });
81
+ return this.executeRequest(() => this.client.GET("/catalog/categories", {
82
+ params: { query: options },
83
+ }));
109
84
  }
110
85
  /**
111
86
  * List reviews for a specific product
@@ -114,19 +89,13 @@ class CatalogClient extends client_1.StorefrontAPIClient {
114
89
  * @param options - Optional query parameters
115
90
  * @returns Promise with reviews and pagination info
116
91
  */
117
- async listProductReviews(productId, options) {
118
- return this.executeRequest(async () => {
119
- const { data, error } = await this.client.GET("/catalog/products/{product_id}/reviews", {
120
- params: {
121
- path: { product_id: productId },
122
- query: options,
123
- },
124
- });
125
- if (error) {
126
- this.handleError(error);
127
- }
128
- return data?.content;
129
- });
92
+ async listProductReviews(pathParams, queryParams) {
93
+ return this.executeRequest(() => this.client.GET("/catalog/products/{product_id}/reviews", {
94
+ params: {
95
+ path: pathParams,
96
+ query: queryParams,
97
+ },
98
+ }));
130
99
  }
131
100
  /**
132
101
  * Create a review for a specific product
@@ -135,56 +104,78 @@ class CatalogClient extends client_1.StorefrontAPIClient {
135
104
  * @param reviewData - The review data
136
105
  * @returns Promise that resolves when the review is created
137
106
  */
138
- async createProductReview(productId, reviewData) {
139
- // Note: In a real implementation, you would need to handle multipart/form-data
140
- // This would require FormData and may need additional handling
141
- return this.executeRequest(async () => {
142
- const { error } = await this.client.POST("/catalog/products/{product_id}/reviews", {
143
- params: {
144
- path: { product_id: productId },
145
- },
146
- body: reviewData,
147
- // This is simplified as we're not properly handling multipart/form-data
148
- });
149
- if (error) {
150
- this.handleError(error);
107
+ async createProductReview(pathParams, formData) {
108
+ return this.executeRequest(() => this.client.POST("/catalog/products/{product_id}/reviews", {
109
+ params: {
110
+ path: pathParams,
111
+ },
112
+ body: formData,
113
+ bodySerializer: (body) => {
114
+ const fd = new FormData();
115
+ for (const [key, value] of Object.entries(body)) {
116
+ if (value !== undefined && value !== null) {
117
+ // Handle File objects directly
118
+ if (value instanceof File || value instanceof Blob) {
119
+ fd.append(key, value);
120
+ }
121
+ else {
122
+ // Convert other values to string
123
+ fd.append(key, String(value));
124
+ }
125
+ }
126
+ }
127
+ return fd;
151
128
  }
152
- });
129
+ }));
153
130
  }
154
131
  /**
155
132
  * Search for products
156
133
  *
157
134
  * @param searchData - The search parameters
158
- * @returns Promise with search results
135
+ * @returns Promise with search results, facet distribution, facet stats, and pagination
159
136
  */
160
137
  async searchProducts(searchData) {
161
- return this.executeRequest(async () => {
162
- const { data, error } = await this.client.POST("/catalog/products/search", {
163
- body: searchData,
164
- });
165
- if (error) {
166
- this.handleError(error);
167
- }
168
- return data?.content;
169
- });
138
+ return this.executeRequest(() => this.client.POST("/catalog/products/search", {
139
+ body: searchData,
140
+ }));
170
141
  }
171
142
  /**
172
- * Get product details by ID (alternative implementation)
173
- * @param productId - The product ID to retrieve
174
- * @returns Promise with the product details
143
+ * Retrieve cross-sell recommendations for a specific product
144
+ *
145
+ * @param options - Optional query parameters
146
+ * @returns Promise with cross-sell recommendations with pagination
175
147
  */
176
- async getProduct(productId) {
177
- return this.executeRequest(async () => {
178
- const { data, error } = await this.client.GET("/catalog/products/{product_id}", {
179
- params: {
180
- path: { product_id: productId },
181
- },
182
- });
183
- if (error) {
184
- this.handleError(error);
185
- }
186
- return data?.content;
187
- });
148
+ async listCrossSellProducts(options) {
149
+ return this.executeRequest(() => this.client.GET("/catalog/products/cross-sell", {
150
+ params: {
151
+ query: options,
152
+ },
153
+ }));
154
+ }
155
+ /**
156
+ * Retrieve up-sell recommendations for a specific product
157
+ *
158
+ * @param options - Optional query parameters
159
+ * @returns Promise with up-sell recommendations with pagination
160
+ */
161
+ async listUpSellProducts(options) {
162
+ return this.executeRequest(() => this.client.GET("/catalog/products/up-sell", {
163
+ params: {
164
+ query: options,
165
+ },
166
+ }));
167
+ }
168
+ /**
169
+ * Retrieve related products for a specific product
170
+ *
171
+ * @param options - Optional query parameters
172
+ * @returns Promise with related products with pagination
173
+ */
174
+ async listSimilarProducts(options) {
175
+ return this.executeRequest(() => this.client.GET("/catalog/products/similar", {
176
+ params: {
177
+ query: options,
178
+ },
179
+ }));
188
180
  }
189
181
  }
190
- exports.CatalogClient = CatalogClient;
@@ -1,4 +1,7 @@
1
1
  import createClient from "openapi-fetch";
2
+ import type { paths } from "../types/storefront";
3
+ import { ApiErrorResponse, ApiResult } from "../types/storefront-api-types";
4
+ import { type TokenStorage } from "./middleware";
2
5
  /**
3
6
  * Available API environments
4
7
  */
@@ -12,7 +15,6 @@ export declare enum Environment {
12
15
  */
13
16
  Production = "production"
14
17
  }
15
- import type { paths } from "../types/storefront";
16
18
  /**
17
19
  * Configuration options for the StorefrontAPI client
18
20
  */
@@ -30,7 +32,7 @@ export interface StorefrontAPIConfig {
30
32
  */
31
33
  baseUrl?: string;
32
34
  /**
33
- * Optional authentication token
35
+ * Optional authentication token (for manual token management)
34
36
  */
35
37
  token?: string;
36
38
  /**
@@ -42,46 +44,37 @@ export interface StorefrontAPIConfig {
42
44
  * Optional timeout in milliseconds
43
45
  */
44
46
  timeout?: number;
47
+ /**
48
+ * Optional token storage for automatic token management
49
+ * If provided, enables automatic token refresh and management via middleware
50
+ */
51
+ tokenStorage?: TokenStorage;
52
+ /**
53
+ * Callback when tokens are updated (login/refresh)
54
+ */
55
+ onTokensUpdated?: (accessToken: string, refreshToken: string) => void;
56
+ /**
57
+ * Callback when tokens are cleared (logout/error)
58
+ */
59
+ onTokensCleared?: () => void;
45
60
  }
46
- /**
47
- * Error response from the API
48
- */
49
- export type ApiErrorResponse = {
50
- message?: string;
51
- success: boolean;
52
- code?: string;
53
- error?: Record<string, any>;
54
- };
55
61
  /**
56
62
  * Base API client for Storefront API
57
63
  */
58
64
  export declare class StorefrontAPIClient {
59
65
  protected client: ReturnType<typeof createClient<paths>>;
60
66
  protected config: StorefrontAPIConfig;
61
- private headers;
62
67
  private readonly baseUrl;
63
- private isRefreshing;
64
- private static sharedConfigs;
65
68
  /**
66
69
  * Create a new StorefrontAPIClient
67
70
  *
68
71
  * @param config - Configuration for the API client
69
- *
70
- * @remarks
71
- * This client implements a token refresh mechanism that will:
72
- * 1. Automatically retry requests that fail with a 401 error
73
- * 2. Refresh the token before retrying the request
74
- * 3. If the token refresh fails, the original error will be thrown
75
- *
76
- * This behavior is inherited by all client classes that extend StorefrontAPIClient.
77
- *
78
- * When using the AuthClient, tokens can be stored persistently in:
79
- * - Memory (default) - Tokens are lost when the page refreshes or app restarts
80
- * - Browser localStorage - Tokens persist across page refreshes
81
- * - Cookies - Tokens persist across page refreshes and can be read server-side
82
- * - Next.js cookies API - For server-side components
83
72
  */
84
73
  constructor(config: StorefrontAPIConfig);
74
+ /**
75
+ * Set up timeout middleware
76
+ */
77
+ private setupTimeoutMiddleware;
85
78
  /**
86
79
  * Constructs the base URL from the configuration
87
80
  *
@@ -97,20 +90,23 @@ export declare class StorefrontAPIClient {
97
90
  getBaseUrl(): string;
98
91
  /**
99
92
  * Get the authorization header value
93
+ * If using token storage, gets the current token from storage
94
+ * Otherwise returns the manual token
100
95
  *
101
96
  * @returns The Authorization header value or empty string if no token is set
102
97
  */
103
- getAuthorizationHeader(): string;
98
+ getAuthorizationHeader(): Promise<string>;
104
99
  /**
105
100
  * Set the authentication token
101
+ * If using token storage, stores the token; otherwise sets manual token
106
102
  *
107
103
  * @param token - The authentication token
108
104
  */
109
- setToken(token: string): void;
105
+ setToken(token: string): Promise<void>;
110
106
  /**
111
107
  * Clear the authentication token
112
108
  */
113
- clearToken(): void;
109
+ clearToken(): Promise<void>;
114
110
  /**
115
111
  * Set the X-Api-Key header
116
112
  *
@@ -129,19 +125,18 @@ export declare class StorefrontAPIClient {
129
125
  */
130
126
  protected handleError(error: any): Promise<never>;
131
127
  /**
132
- * Attempt to refresh the token
133
- * This is a placeholder method that will be overridden by AuthClient
134
- *
135
- * @returns Promise that resolves to true if token was refreshed, false otherwise
136
- */
137
- protected attemptTokenRefresh(): Promise<boolean>;
138
- /**
139
- * Execute a request with automatic token refresh handling
140
- * For AuthClient, this will attempt to refresh the token and retry once on 401 errors
141
- * Base implementation just executes the request
128
+ * Execute a request and handle the response
142
129
  *
143
- * @param requestFn - Function that executes the API request
130
+ * @param apiCall - Function that executes the API request
144
131
  * @returns Promise with the API response
145
132
  */
146
- protected executeRequest<T>(requestFn: () => Promise<T>): Promise<T>;
133
+ protected executeRequest<T>(apiCall: () => Promise<{
134
+ data?: {
135
+ message?: string;
136
+ success?: boolean;
137
+ content?: T;
138
+ };
139
+ error?: ApiErrorResponse;
140
+ response: Response;
141
+ }>): Promise<ApiResult<T>>;
147
142
  }