@commercengine/storefront-sdk 0.3.0 → 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,14 +1,9 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.StorefrontAPIClient = exports.Environment = void 0;
7
- const openapi_fetch_1 = __importDefault(require("openapi-fetch"));
1
+ import createClient from "openapi-fetch";
2
+ import { createDefaultAuthMiddleware } from "./middleware";
8
3
  /**
9
4
  * Available API environments
10
5
  */
11
- var Environment;
6
+ export var Environment;
12
7
  (function (Environment) {
13
8
  /**
14
9
  * Staging environment
@@ -18,87 +13,62 @@ var Environment;
18
13
  * Production environment
19
14
  */
20
15
  Environment["Production"] = "production";
21
- })(Environment || (exports.Environment = Environment = {}));
16
+ })(Environment || (Environment = {}));
22
17
  /**
23
18
  * Base API client for Storefront API
24
19
  */
25
- class StorefrontAPIClient {
20
+ export class StorefrontAPIClient {
21
+ client;
22
+ config;
23
+ baseUrl;
26
24
  /**
27
25
  * Create a new StorefrontAPIClient
28
26
  *
29
27
  * @param config - Configuration for the API client
30
- *
31
- * @remarks
32
- * This client implements a token refresh mechanism that will:
33
- * 1. Automatically retry requests that fail with a 401 error
34
- * 2. Refresh the token before retrying the request
35
- * 3. If the token refresh fails, the original error will be thrown
36
- *
37
- * This behavior is inherited by all client classes that extend StorefrontAPIClient.
38
- *
39
- * When using the AuthClient, tokens can be stored persistently in:
40
- * - Memory (default) - Tokens are lost when the page refreshes or app restarts
41
- * - Browser localStorage - Tokens persist across page refreshes
42
- * - Cookies - Tokens persist across page refreshes and can be read server-side
43
- * - Next.js cookies API - For server-side components
44
28
  */
45
29
  constructor(config) {
46
- this.isRefreshing = false;
47
- // Use shared config reference for the same storeId to ensure all clients use the same config
48
- const storeKey = config.storeId + (config.baseUrl || config.environment || "");
49
- if (!StorefrontAPIClient.sharedConfigs.has(storeKey)) {
50
- StorefrontAPIClient.sharedConfigs.set(storeKey, { ...config });
51
- }
52
- // Use the shared config reference
53
- this.config = StorefrontAPIClient.sharedConfigs.get(storeKey);
54
- // Copy non-shared values from the provided config
55
- if (config.token && !this.config.token) {
56
- this.config.token = config.token;
57
- }
58
- if (config.apiKey && !this.config.apiKey) {
59
- this.config.apiKey = config.apiKey;
60
- }
61
- this.headers = {
62
- "Content-Type": "application/json",
63
- };
64
- if (this.config.token) {
65
- this.headers["Authorization"] = `Bearer ${this.config.token}`;
66
- }
67
- if (this.config.apiKey) {
68
- this.headers["X-Api-Key"] = this.config.apiKey;
69
- }
30
+ this.config = { ...config };
70
31
  // Determine base URL from environment or use custom URL if provided
71
32
  this.baseUrl = this.getBaseUrlFromConfig(this.config);
72
- this.client = (0, openapi_fetch_1.default)({
33
+ this.client = createClient({
73
34
  baseUrl: this.baseUrl,
74
- fetch: (input, init) => {
75
- // Add timeout if configured
76
- const timeoutSignal = this.config.timeout
77
- ? AbortSignal.timeout(this.config.timeout)
78
- : undefined;
79
- // Always check for the most current token and API key before each request
80
- if (this.config.token) {
81
- this.headers["Authorization"] = `Bearer ${this.config.token}`;
82
- }
83
- else {
84
- delete this.headers["Authorization"];
85
- }
86
- if (this.config.apiKey) {
87
- this.headers["X-Api-Key"] = this.config.apiKey;
88
- }
89
- else {
90
- delete this.headers["X-Api-Key"];
35
+ });
36
+ // Set up auth middleware if token storage is provided
37
+ if (this.config.tokenStorage) {
38
+ const authMiddleware = createDefaultAuthMiddleware({
39
+ apiKey: this.config.apiKey,
40
+ baseUrl: this.baseUrl,
41
+ tokenStorage: this.config.tokenStorage,
42
+ onTokensUpdated: this.config.onTokensUpdated,
43
+ onTokensCleared: this.config.onTokensCleared,
44
+ });
45
+ this.client.use(authMiddleware);
46
+ }
47
+ // Set up timeout middleware if configured
48
+ if (this.config.timeout) {
49
+ this.setupTimeoutMiddleware();
50
+ }
51
+ }
52
+ /**
53
+ * Set up timeout middleware
54
+ */
55
+ setupTimeoutMiddleware() {
56
+ this.client.use({
57
+ onRequest: async ({ request }) => {
58
+ // Add timeout signal
59
+ const controller = new AbortController();
60
+ const timeoutId = setTimeout(() => controller.abort(), this.config.timeout);
61
+ // Merge with existing signal if present
62
+ if (request.signal) {
63
+ request.signal.addEventListener('abort', () => controller.abort());
91
64
  }
92
- // Merge headers
93
- const headers = {
94
- ...this.headers,
95
- ...(init?.headers || {}),
96
- };
97
- return fetch(input, {
98
- ...init,
99
- headers,
100
- signal: timeoutSignal || init?.signal,
65
+ // Create new request with timeout signal
66
+ const newRequest = new Request(request, {
67
+ signal: controller.signal,
101
68
  });
69
+ // Clean up timeout when request completes
70
+ controller.signal.addEventListener('abort', () => clearTimeout(timeoutId));
71
+ return newRequest;
102
72
  },
103
73
  });
104
74
  }
@@ -133,27 +103,42 @@ class StorefrontAPIClient {
133
103
  }
134
104
  /**
135
105
  * Get the authorization header value
106
+ * If using token storage, gets the current token from storage
107
+ * Otherwise returns the manual token
136
108
  *
137
109
  * @returns The Authorization header value or empty string if no token is set
138
110
  */
139
- getAuthorizationHeader() {
111
+ async getAuthorizationHeader() {
112
+ if (this.config.tokenStorage) {
113
+ const token = await this.config.tokenStorage.getAccessToken();
114
+ return token ? `Bearer ${token}` : "";
115
+ }
140
116
  return this.config.token ? `Bearer ${this.config.token}` : "";
141
117
  }
142
118
  /**
143
119
  * Set the authentication token
120
+ * If using token storage, stores the token; otherwise sets manual token
144
121
  *
145
122
  * @param token - The authentication token
146
123
  */
147
- setToken(token) {
148
- this.config.token = token;
149
- this.headers["Authorization"] = `Bearer ${token}`;
124
+ async setToken(token) {
125
+ if (this.config.tokenStorage) {
126
+ await this.config.tokenStorage.setAccessToken(token);
127
+ }
128
+ else {
129
+ this.config.token = token;
130
+ }
150
131
  }
151
132
  /**
152
133
  * Clear the authentication token
153
134
  */
154
- clearToken() {
155
- this.config.token = undefined;
156
- delete this.headers["Authorization"];
135
+ async clearToken() {
136
+ if (this.config.tokenStorage) {
137
+ await this.config.tokenStorage.clearTokens();
138
+ }
139
+ else {
140
+ this.config.token = undefined;
141
+ }
157
142
  }
158
143
  /**
159
144
  * Set the X-Api-Key header
@@ -162,14 +147,12 @@ class StorefrontAPIClient {
162
147
  */
163
148
  setApiKey(apiKey) {
164
149
  this.config.apiKey = apiKey;
165
- this.headers["X-Api-Key"] = apiKey;
166
150
  }
167
151
  /**
168
152
  * Clear the X-Api-Key header
169
153
  */
170
154
  clearApiKey() {
171
155
  this.config.apiKey = undefined;
172
- delete this.headers["X-Api-Key"];
173
156
  }
174
157
  /**
175
158
  * Handle API errors
@@ -182,26 +165,6 @@ class StorefrontAPIClient {
182
165
  const statusCode = error.status || (error.response?.status ? error.response.status : 500);
183
166
  const errorData = error.data ||
184
167
  error.response?.data || { message: error.message || "Unknown error" };
185
- // If we have a 401 error and we're not already in a refresh operation,
186
- // attempt to refresh the token
187
- if (statusCode === 401 && !this.isRefreshing) {
188
- try {
189
- this.isRefreshing = true;
190
- const refreshed = await this.attemptTokenRefresh();
191
- if (refreshed) {
192
- // Token refreshed successfully - no need to throw error
193
- // The calling method should retry the request
194
- this.isRefreshing = false;
195
- throw new Error("Token refreshed, please retry the request");
196
- }
197
- }
198
- catch (refreshError) {
199
- // If refresh fails, continue to throw the original error
200
- }
201
- finally {
202
- this.isRefreshing = false;
203
- }
204
- }
205
168
  if (statusCode === 401) {
206
169
  throw new Error("Unauthorized: Please check your authentication token");
207
170
  }
@@ -216,52 +179,32 @@ class StorefrontAPIClient {
216
179
  }
217
180
  }
218
181
  /**
219
- * Attempt to refresh the token
220
- * This is a placeholder method that will be overridden by AuthClient
221
- *
222
- * @returns Promise that resolves to true if token was refreshed, false otherwise
223
- */
224
- async attemptTokenRefresh() {
225
- // Base implementation does nothing
226
- // Will be overridden by AuthClient
227
- return false;
228
- }
229
- /**
230
- * Execute a request with automatic token refresh handling
231
- * For AuthClient, this will attempt to refresh the token and retry once on 401 errors
232
- * Base implementation just executes the request
182
+ * Execute a request and handle the response
233
183
  *
234
- * @param requestFn - Function that executes the API request
184
+ * @param apiCall - Function that executes the API request
235
185
  * @returns Promise with the API response
236
186
  */
237
- async executeRequest(requestFn) {
187
+ async executeRequest(apiCall) {
238
188
  try {
239
- return await requestFn();
240
- }
241
- catch (error) {
242
- // Handle 401 errors by attempting to refresh token
243
- if (error &&
244
- typeof error === "object" &&
245
- "status" in error &&
246
- error.status === 401) {
247
- // Attempt to refresh the token
248
- const refreshed = await this.attemptTokenRefresh();
249
- if (refreshed) {
250
- // If token was refreshed, retry the request once
251
- return await requestFn();
252
- }
189
+ const { data, error } = await apiCall();
190
+ // openapi-fetch returns error for 4xx/5xx, data for 2xx
191
+ if (error) {
192
+ return { data: null, error };
253
193
  }
254
- // Check if the error is from handleError and is the special refresh token message
255
- if (error instanceof Error &&
256
- error.message === "Token refreshed, please retry the request") {
257
- // If token was refreshed, retry the request once
258
- return await requestFn();
259
- }
260
- // Otherwise, throw the error to be handled by the caller
261
- throw error;
194
+ // data will be defined for 2xx responses
195
+ return { data: data, error: null };
196
+ }
197
+ catch (err) {
198
+ // This handles network errors or other unexpected errors
199
+ return {
200
+ data: null,
201
+ error: {
202
+ success: false,
203
+ code: 'NETWORK_ERROR',
204
+ message: 'Network error occurred',
205
+ error: err,
206
+ },
207
+ };
262
208
  }
263
209
  }
264
210
  }
265
- exports.StorefrontAPIClient = StorefrontAPIClient;
266
- // Shared static reference for configs by storeId to ensure all clients use the same config
267
- StorefrontAPIClient.sharedConfigs = new Map();
@@ -0,0 +1,91 @@
1
+ import { CreateAddressBody, CreateAddressContent, CreateAddressPathParams, CreateCustomerContent, DeleteAddressPathParams, DeleteAddressResponse, GetAddressDetailContent, GetAddressDetailPathParams, GetCustomerDetailContent, GetCustomerDetailPathParams, GetLoyaltyDetailsContent, GetLoyaltyDetailsPathParams, ListAddressesContent, ListAddressesPathParams, ListLoyaltyActivitiesContent, ListLoyaltyActivitiesPathParams, ListUserReviewsContent, ListUserReviewsPathParams, UpdateAddressDetailBody, UpdateAddressDetailContent, UpdateAddressDetailPathParams, UpdateCustomerBody, UpdateCustomerContent, UpdateCustomerPathParams } from "../types/storefront-api-types";
2
+ import { CreateCustomerBody } from "../types/storefront-api-types";
3
+ import { ApiResult } from "../types/storefront-api-types";
4
+ import { StorefrontAPIClient } from "./client";
5
+ import { StorefrontAPIConfig } from "./client";
6
+ /**
7
+ * Client for interacting with customer endpoints
8
+ */
9
+ export declare class CustomerClient extends StorefrontAPIClient {
10
+ constructor(config: StorefrontAPIConfig);
11
+ /**
12
+ * Create a customer
13
+ *
14
+ * @param body - Customer creation body
15
+ * @returns Promise with customer details
16
+ */
17
+ createCustomer(body: CreateCustomerBody): Promise<ApiResult<CreateCustomerContent>>;
18
+ /**
19
+ * Get customer details
20
+ *
21
+ * @param pathParams - Path parameters
22
+ * @returns Promise with customer details
23
+ */
24
+ getCustomer(pathParams: GetCustomerDetailPathParams): Promise<ApiResult<GetCustomerDetailContent>>;
25
+ /**
26
+ * Update a customer
27
+ *
28
+ * @param pathParams - Path parameters
29
+ * @param body - Customer update body
30
+ * @returns Promise with customer details
31
+ */
32
+ updateCustomer(pathParams: UpdateCustomerPathParams, body: UpdateCustomerBody): Promise<ApiResult<UpdateCustomerContent>>;
33
+ /**
34
+ * Get all saved addresses for a customer
35
+ *
36
+ * @param pathParams - Path parameters
37
+ * @returns Promise with addresses
38
+ */
39
+ listAddresses(pathParams: ListAddressesPathParams): Promise<ApiResult<ListAddressesContent>>;
40
+ /**
41
+ * Create a new address for a customer
42
+ *
43
+ * @param pathParams - Path parameters
44
+ * @param body - Address creation body
45
+ * @returns Promise with address details
46
+ */
47
+ createAddress(pathParams: CreateAddressPathParams, body: CreateAddressBody): Promise<ApiResult<CreateAddressContent>>;
48
+ /**
49
+ * Get an address for a customer
50
+ *
51
+ * @param pathParams - Path parameters
52
+ * @returns Promise with address details
53
+ */
54
+ getAddress(pathParams: GetAddressDetailPathParams): Promise<ApiResult<GetAddressDetailContent>>;
55
+ /**
56
+ * Update an address for a customer
57
+ *
58
+ * @param pathParams - Path parameters
59
+ * @param body - Address update body
60
+ * @returns Promise with address details
61
+ */
62
+ updateAddress(pathParams: UpdateAddressDetailPathParams, body: UpdateAddressDetailBody): Promise<ApiResult<UpdateAddressDetailContent>>;
63
+ /**
64
+ * Delete an address for a customer
65
+ *
66
+ * @param pathParams - Path parameters
67
+ * @returns Promise with address details
68
+ */
69
+ deleteAddress(pathParams: DeleteAddressPathParams): Promise<ApiResult<DeleteAddressResponse>>;
70
+ /**
71
+ * Get customer loyalty details
72
+ *
73
+ * @param pathParams - Path parameters
74
+ * @returns Promise with loyalty details
75
+ */
76
+ getLoyaltyDetails(pathParams: GetLoyaltyDetailsPathParams): Promise<ApiResult<GetLoyaltyDetailsContent>>;
77
+ /**
78
+ * List all loyalty points activity for a customer
79
+ *
80
+ * @param pathParams - Path parameters
81
+ * @returns Promise with loyalty points activity
82
+ */
83
+ listLoyaltyPointsActivity(pathParams: ListLoyaltyActivitiesPathParams): Promise<ApiResult<ListLoyaltyActivitiesContent>>;
84
+ /**
85
+ * List all reviews left by a customer
86
+ *
87
+ * @param pathParams - Path parameters
88
+ * @returns Promise with reviews
89
+ */
90
+ listCustomerReviews(pathParams: ListUserReviewsPathParams): Promise<ApiResult<ListUserReviewsContent>>;
91
+ }
@@ -0,0 +1,156 @@
1
+ import { StorefrontAPIClient } from "./client";
2
+ /**
3
+ * Client for interacting with customer endpoints
4
+ */
5
+ export class CustomerClient extends StorefrontAPIClient {
6
+ constructor(config) {
7
+ super(config);
8
+ }
9
+ /**
10
+ * Create a customer
11
+ *
12
+ * @param body - Customer creation body
13
+ * @returns Promise with customer details
14
+ */
15
+ async createCustomer(body) {
16
+ return this.executeRequest(() => this.client.POST("/customers", {
17
+ body: body,
18
+ }));
19
+ }
20
+ /**
21
+ * Get customer details
22
+ *
23
+ * @param pathParams - Path parameters
24
+ * @returns Promise with customer details
25
+ */
26
+ async getCustomer(pathParams) {
27
+ return this.executeRequest(() => this.client.GET("/customers/{id}", {
28
+ params: {
29
+ path: pathParams,
30
+ },
31
+ }));
32
+ }
33
+ /**
34
+ * Update a customer
35
+ *
36
+ * @param pathParams - Path parameters
37
+ * @param body - Customer update body
38
+ * @returns Promise with customer details
39
+ */
40
+ async updateCustomer(pathParams, body) {
41
+ return this.executeRequest(() => this.client.PUT("/customers/{id}", {
42
+ params: {
43
+ path: pathParams,
44
+ },
45
+ body: body,
46
+ }));
47
+ }
48
+ /**
49
+ * Get all saved addresses for a customer
50
+ *
51
+ * @param pathParams - Path parameters
52
+ * @returns Promise with addresses
53
+ */
54
+ async listAddresses(pathParams) {
55
+ return this.executeRequest(() => this.client.GET("/customers/{user_id}/addresses", {
56
+ params: {
57
+ path: pathParams,
58
+ },
59
+ }));
60
+ }
61
+ /**
62
+ * Create a new address for a customer
63
+ *
64
+ * @param pathParams - Path parameters
65
+ * @param body - Address creation body
66
+ * @returns Promise with address details
67
+ */
68
+ async createAddress(pathParams, body) {
69
+ return this.executeRequest(() => this.client.POST("/customers/{user_id}/addresses", {
70
+ params: {
71
+ path: pathParams,
72
+ },
73
+ body: body,
74
+ }));
75
+ }
76
+ /**
77
+ * Get an address for a customer
78
+ *
79
+ * @param pathParams - Path parameters
80
+ * @returns Promise with address details
81
+ */
82
+ async getAddress(pathParams) {
83
+ return this.executeRequest(() => this.client.GET("/customers/{user_id}/addresses/{address_id}", {
84
+ params: {
85
+ path: pathParams,
86
+ },
87
+ }));
88
+ }
89
+ /**
90
+ * Update an address for a customer
91
+ *
92
+ * @param pathParams - Path parameters
93
+ * @param body - Address update body
94
+ * @returns Promise with address details
95
+ */
96
+ async updateAddress(pathParams, body) {
97
+ return this.executeRequest(() => this.client.PUT("/customers/{user_id}/addresses/{address_id}", {
98
+ params: {
99
+ path: pathParams,
100
+ },
101
+ body: body,
102
+ }));
103
+ }
104
+ /**
105
+ * Delete an address for a customer
106
+ *
107
+ * @param pathParams - Path parameters
108
+ * @returns Promise with address details
109
+ */
110
+ async deleteAddress(pathParams) {
111
+ return this.executeRequest(() => this.client.DELETE("/customers/{user_id}/addresses/{address_id}", {
112
+ params: {
113
+ path: pathParams,
114
+ },
115
+ }));
116
+ }
117
+ /**
118
+ * Get customer loyalty details
119
+ *
120
+ * @param pathParams - Path parameters
121
+ * @returns Promise with loyalty details
122
+ */
123
+ async getLoyaltyDetails(pathParams) {
124
+ return this.executeRequest(() => this.client.GET("/customers/{user_id}/loyalty", {
125
+ params: {
126
+ path: pathParams,
127
+ },
128
+ }));
129
+ }
130
+ /**
131
+ * List all loyalty points activity for a customer
132
+ *
133
+ * @param pathParams - Path parameters
134
+ * @returns Promise with loyalty points activity
135
+ */
136
+ async listLoyaltyPointsActivity(pathParams) {
137
+ return this.executeRequest(() => this.client.GET("/customers/{user_id}/loyalty-points-activity", {
138
+ params: {
139
+ path: pathParams,
140
+ },
141
+ }));
142
+ }
143
+ /**
144
+ * List all reviews left by a customer
145
+ *
146
+ * @param pathParams - Path parameters
147
+ * @returns Promise with reviews
148
+ */
149
+ async listCustomerReviews(pathParams) {
150
+ return this.executeRequest(() => this.client.GET("/customers/{user_id}/reviews", {
151
+ params: {
152
+ path: pathParams,
153
+ },
154
+ }));
155
+ }
156
+ }
@@ -0,0 +1,28 @@
1
+ import { ApiResult, ListCountriesContent, ListCountryPincodesContent, ListCountryPincodesPathParams, ListCountryStatesContent, ListCountryStatesPathParams } from "../types/storefront-api-types";
2
+ import { StorefrontAPIClient, StorefrontAPIConfig } from "./client";
3
+ /**
4
+ * Client for interacting with helper endpoints
5
+ */
6
+ export declare class HelpersClient extends StorefrontAPIClient {
7
+ constructor(config: StorefrontAPIConfig);
8
+ /**
9
+ * Get a list of countries
10
+ *
11
+ * @returns Promise with countries
12
+ */
13
+ listCountries(): Promise<ApiResult<ListCountriesContent>>;
14
+ /**
15
+ * - Get a list of states for a country
16
+ *
17
+ * @param pathParams - Path parameters
18
+ * @returns Promise with states
19
+ */
20
+ listCountryStates(pathParams: ListCountryStatesPathParams): Promise<ApiResult<ListCountryStatesContent>>;
21
+ /**
22
+ * Get pincodes for a country
23
+ *
24
+ * @param pathParams - Path parameters
25
+ * @returns Promise with pincodes
26
+ */
27
+ listCountryPincodes(pathParams: ListCountryPincodesPathParams): Promise<ApiResult<ListCountryPincodesContent>>;
28
+ }
@@ -0,0 +1,43 @@
1
+ import { StorefrontAPIClient } from "./client";
2
+ /**
3
+ * Client for interacting with helper endpoints
4
+ */
5
+ export class HelpersClient extends StorefrontAPIClient {
6
+ constructor(config) {
7
+ super(config);
8
+ }
9
+ /**
10
+ * Get a list of countries
11
+ *
12
+ * @returns Promise with countries
13
+ */
14
+ async listCountries() {
15
+ return this.executeRequest(() => this.client.GET("/common/countries", {}));
16
+ }
17
+ /**
18
+ * - Get a list of states for a country
19
+ *
20
+ * @param pathParams - Path parameters
21
+ * @returns Promise with states
22
+ */
23
+ async listCountryStates(pathParams) {
24
+ return this.executeRequest(() => this.client.GET("/common/countries/{country_iso_code}/states", {
25
+ params: {
26
+ path: pathParams,
27
+ },
28
+ }));
29
+ }
30
+ /**
31
+ * Get pincodes for a country
32
+ *
33
+ * @param pathParams - Path parameters
34
+ * @returns Promise with pincodes
35
+ */
36
+ async listCountryPincodes(pathParams) {
37
+ return this.executeRequest(() => this.client.GET("/common/countries/{country_iso_code}/pincodes", {
38
+ params: {
39
+ path: pathParams,
40
+ },
41
+ }));
42
+ }
43
+ }