@commercengine/storefront-sdk 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +111 -0
- package/dist/index.d.ts +80 -0
- package/dist/index.js +75 -0
- package/dist/lib/auth.d.ts +261 -0
- package/dist/lib/auth.js +679 -0
- package/dist/lib/cart.d.ts +114 -0
- package/dist/lib/cart.js +209 -0
- package/dist/lib/catalog.d.ts +130 -0
- package/dist/lib/catalog.js +176 -0
- package/dist/lib/client.d.ts +146 -0
- package/dist/lib/client.js +239 -0
- package/dist/types/storefront.d.ts +7588 -0
- package/package.json +44 -0
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import createClient from "openapi-fetch";
|
|
2
|
+
/**
|
|
3
|
+
* Available API environments
|
|
4
|
+
*/
|
|
5
|
+
export declare enum Environment {
|
|
6
|
+
/**
|
|
7
|
+
* Staging environment
|
|
8
|
+
*/
|
|
9
|
+
Staging = "staging",
|
|
10
|
+
/**
|
|
11
|
+
* Production environment
|
|
12
|
+
*/
|
|
13
|
+
Production = "production"
|
|
14
|
+
}
|
|
15
|
+
import type { paths } from "../types/storefront";
|
|
16
|
+
/**
|
|
17
|
+
* Configuration options for the StorefrontAPI client
|
|
18
|
+
*/
|
|
19
|
+
export interface StorefrontAPIConfig {
|
|
20
|
+
/**
|
|
21
|
+
* The store ID to use for API requests
|
|
22
|
+
*/
|
|
23
|
+
storeId: string;
|
|
24
|
+
/**
|
|
25
|
+
* The environment to use (staging or production)
|
|
26
|
+
*/
|
|
27
|
+
environment?: Environment;
|
|
28
|
+
/**
|
|
29
|
+
* Custom base URL (overrides environment-based URL if provided)
|
|
30
|
+
*/
|
|
31
|
+
baseUrl?: string;
|
|
32
|
+
/**
|
|
33
|
+
* Optional authentication token
|
|
34
|
+
*/
|
|
35
|
+
token?: string;
|
|
36
|
+
/**
|
|
37
|
+
* X-Api-Key for anonymous authentication endpoints
|
|
38
|
+
* Required for initial authentication
|
|
39
|
+
*/
|
|
40
|
+
apiKey?: string;
|
|
41
|
+
/**
|
|
42
|
+
* Optional timeout in milliseconds
|
|
43
|
+
*/
|
|
44
|
+
timeout?: number;
|
|
45
|
+
}
|
|
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
|
+
/**
|
|
56
|
+
* Base API client for Storefront API
|
|
57
|
+
*/
|
|
58
|
+
export declare class StorefrontAPIClient {
|
|
59
|
+
protected client: ReturnType<typeof createClient<paths>>;
|
|
60
|
+
protected config: StorefrontAPIConfig;
|
|
61
|
+
private headers;
|
|
62
|
+
private readonly baseUrl;
|
|
63
|
+
private isRefreshing;
|
|
64
|
+
/**
|
|
65
|
+
* Create a new StorefrontAPIClient
|
|
66
|
+
*
|
|
67
|
+
* @param config - Configuration for the API client
|
|
68
|
+
*
|
|
69
|
+
* @remarks
|
|
70
|
+
* This client implements a token refresh mechanism that will:
|
|
71
|
+
* 1. Automatically retry requests that fail with a 401 error
|
|
72
|
+
* 2. Refresh the token before retrying the request
|
|
73
|
+
* 3. If the token refresh fails, the original error will be thrown
|
|
74
|
+
*
|
|
75
|
+
* This behavior is inherited by all client classes that extend StorefrontAPIClient.
|
|
76
|
+
*
|
|
77
|
+
* When using the AuthClient, tokens can be stored persistently in:
|
|
78
|
+
* - Memory (default) - Tokens are lost when the page refreshes or app restarts
|
|
79
|
+
* - Browser localStorage - Tokens persist across page refreshes
|
|
80
|
+
* - Cookies - Tokens persist across page refreshes and can be read server-side
|
|
81
|
+
* - Next.js cookies API - For server-side components
|
|
82
|
+
*/
|
|
83
|
+
constructor(config: StorefrontAPIConfig);
|
|
84
|
+
/**
|
|
85
|
+
* Constructs the base URL from the configuration
|
|
86
|
+
*
|
|
87
|
+
* @param config - The client configuration
|
|
88
|
+
* @returns The constructed base URL
|
|
89
|
+
*/
|
|
90
|
+
private getBaseUrlFromConfig;
|
|
91
|
+
/**
|
|
92
|
+
* Get the base URL of the API
|
|
93
|
+
*
|
|
94
|
+
* @returns The base URL of the API
|
|
95
|
+
*/
|
|
96
|
+
getBaseUrl(): string;
|
|
97
|
+
/**
|
|
98
|
+
* Get the authorization header value
|
|
99
|
+
*
|
|
100
|
+
* @returns The Authorization header value or empty string if no token is set
|
|
101
|
+
*/
|
|
102
|
+
getAuthorizationHeader(): string;
|
|
103
|
+
/**
|
|
104
|
+
* Set the authentication token
|
|
105
|
+
*
|
|
106
|
+
* @param token - The authentication token
|
|
107
|
+
*/
|
|
108
|
+
setToken(token: string): void;
|
|
109
|
+
/**
|
|
110
|
+
* Clear the authentication token
|
|
111
|
+
*/
|
|
112
|
+
clearToken(): void;
|
|
113
|
+
/**
|
|
114
|
+
* Set the X-Api-Key header
|
|
115
|
+
*
|
|
116
|
+
* @param apiKey - The API key to set
|
|
117
|
+
*/
|
|
118
|
+
setApiKey(apiKey: string): void;
|
|
119
|
+
/**
|
|
120
|
+
* Clear the X-Api-Key header
|
|
121
|
+
*/
|
|
122
|
+
clearApiKey(): void;
|
|
123
|
+
/**
|
|
124
|
+
* Handle API errors
|
|
125
|
+
*
|
|
126
|
+
* @param error - Error object from OpenAPI-Fetch
|
|
127
|
+
* @throws Rethrows the error with additional context
|
|
128
|
+
*/
|
|
129
|
+
protected handleError(error: any): Promise<never>;
|
|
130
|
+
/**
|
|
131
|
+
* Attempt to refresh the token
|
|
132
|
+
* This is a placeholder method that will be overridden by AuthClient
|
|
133
|
+
*
|
|
134
|
+
* @returns Promise that resolves to true if token was refreshed, false otherwise
|
|
135
|
+
*/
|
|
136
|
+
protected attemptTokenRefresh(): Promise<boolean>;
|
|
137
|
+
/**
|
|
138
|
+
* Execute a request with automatic token refresh handling
|
|
139
|
+
* For AuthClient, this will attempt to refresh the token and retry once on 401 errors
|
|
140
|
+
* Base implementation just executes the request
|
|
141
|
+
*
|
|
142
|
+
* @param requestFn - Function that executes the API request
|
|
143
|
+
* @returns Promise with the API response
|
|
144
|
+
*/
|
|
145
|
+
protected executeRequest<T>(requestFn: () => Promise<T>): Promise<T>;
|
|
146
|
+
}
|
|
@@ -0,0 +1,239 @@
|
|
|
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"));
|
|
8
|
+
/**
|
|
9
|
+
* Available API environments
|
|
10
|
+
*/
|
|
11
|
+
var Environment;
|
|
12
|
+
(function (Environment) {
|
|
13
|
+
/**
|
|
14
|
+
* Staging environment
|
|
15
|
+
*/
|
|
16
|
+
Environment["Staging"] = "staging";
|
|
17
|
+
/**
|
|
18
|
+
* Production environment
|
|
19
|
+
*/
|
|
20
|
+
Environment["Production"] = "production";
|
|
21
|
+
})(Environment || (exports.Environment = Environment = {}));
|
|
22
|
+
/**
|
|
23
|
+
* Base API client for Storefront API
|
|
24
|
+
*/
|
|
25
|
+
class StorefrontAPIClient {
|
|
26
|
+
/**
|
|
27
|
+
* Create a new StorefrontAPIClient
|
|
28
|
+
*
|
|
29
|
+
* @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
|
+
*/
|
|
45
|
+
constructor(config) {
|
|
46
|
+
this.isRefreshing = false;
|
|
47
|
+
this.config = config;
|
|
48
|
+
this.headers = {
|
|
49
|
+
"Content-Type": "application/json",
|
|
50
|
+
};
|
|
51
|
+
if (config.token) {
|
|
52
|
+
this.headers["Authorization"] = `Bearer ${config.token}`;
|
|
53
|
+
}
|
|
54
|
+
if (config.apiKey) {
|
|
55
|
+
this.headers["X-Api-Key"] = config.apiKey;
|
|
56
|
+
}
|
|
57
|
+
// Determine base URL from environment or use custom URL if provided
|
|
58
|
+
this.baseUrl = this.getBaseUrlFromConfig(config);
|
|
59
|
+
this.client = (0, openapi_fetch_1.default)({
|
|
60
|
+
baseUrl: this.baseUrl,
|
|
61
|
+
fetch: (input, init) => {
|
|
62
|
+
// Add timeout if configured
|
|
63
|
+
const timeoutSignal = config.timeout
|
|
64
|
+
? AbortSignal.timeout(config.timeout)
|
|
65
|
+
: undefined;
|
|
66
|
+
// Merge headers
|
|
67
|
+
const headers = {
|
|
68
|
+
...this.headers,
|
|
69
|
+
...(init?.headers || {}),
|
|
70
|
+
};
|
|
71
|
+
return fetch(input, {
|
|
72
|
+
...init,
|
|
73
|
+
headers,
|
|
74
|
+
signal: timeoutSignal || init?.signal,
|
|
75
|
+
});
|
|
76
|
+
},
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Constructs the base URL from the configuration
|
|
81
|
+
*
|
|
82
|
+
* @param config - The client configuration
|
|
83
|
+
* @returns The constructed base URL
|
|
84
|
+
*/
|
|
85
|
+
getBaseUrlFromConfig(config) {
|
|
86
|
+
// If explicit baseUrl is provided, use it
|
|
87
|
+
if (config.baseUrl) {
|
|
88
|
+
return config.baseUrl;
|
|
89
|
+
}
|
|
90
|
+
// Otherwise construct URL based on environment and storeId
|
|
91
|
+
const env = config.environment || Environment.Production;
|
|
92
|
+
switch (env) {
|
|
93
|
+
case Environment.Staging:
|
|
94
|
+
return `https://staging.api.commercengine.io/api/v1/${config.storeId}/storefront`;
|
|
95
|
+
case Environment.Production:
|
|
96
|
+
default:
|
|
97
|
+
return `https://prod.api.commercengine.io/api/v1/${config.storeId}/storefront`;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Get the base URL of the API
|
|
102
|
+
*
|
|
103
|
+
* @returns The base URL of the API
|
|
104
|
+
*/
|
|
105
|
+
getBaseUrl() {
|
|
106
|
+
return this.baseUrl;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Get the authorization header value
|
|
110
|
+
*
|
|
111
|
+
* @returns The Authorization header value or empty string if no token is set
|
|
112
|
+
*/
|
|
113
|
+
getAuthorizationHeader() {
|
|
114
|
+
return this.config.token ? `Bearer ${this.config.token}` : "";
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Set the authentication token
|
|
118
|
+
*
|
|
119
|
+
* @param token - The authentication token
|
|
120
|
+
*/
|
|
121
|
+
setToken(token) {
|
|
122
|
+
this.config.token = token;
|
|
123
|
+
this.headers["Authorization"] = `Bearer ${token}`;
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Clear the authentication token
|
|
127
|
+
*/
|
|
128
|
+
clearToken() {
|
|
129
|
+
this.config.token = undefined;
|
|
130
|
+
delete this.headers["Authorization"];
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Set the X-Api-Key header
|
|
134
|
+
*
|
|
135
|
+
* @param apiKey - The API key to set
|
|
136
|
+
*/
|
|
137
|
+
setApiKey(apiKey) {
|
|
138
|
+
this.config.apiKey = apiKey;
|
|
139
|
+
this.headers["X-Api-Key"] = apiKey;
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Clear the X-Api-Key header
|
|
143
|
+
*/
|
|
144
|
+
clearApiKey() {
|
|
145
|
+
this.config.apiKey = undefined;
|
|
146
|
+
delete this.headers["X-Api-Key"];
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Handle API errors
|
|
150
|
+
*
|
|
151
|
+
* @param error - Error object from OpenAPI-Fetch
|
|
152
|
+
* @throws Rethrows the error with additional context
|
|
153
|
+
*/
|
|
154
|
+
async handleError(error) {
|
|
155
|
+
// Extract status code and error data from OpenAPI-Fetch error response
|
|
156
|
+
const statusCode = error.status || (error.response?.status ? error.response.status : 500);
|
|
157
|
+
const errorData = error.data ||
|
|
158
|
+
error.response?.data || { message: error.message || "Unknown error" };
|
|
159
|
+
// If we have a 401 error and we're not already in a refresh operation,
|
|
160
|
+
// attempt to refresh the token
|
|
161
|
+
if (statusCode === 401 && !this.isRefreshing) {
|
|
162
|
+
try {
|
|
163
|
+
this.isRefreshing = true;
|
|
164
|
+
const refreshed = await this.attemptTokenRefresh();
|
|
165
|
+
if (refreshed) {
|
|
166
|
+
// Token refreshed successfully - no need to throw error
|
|
167
|
+
// The calling method should retry the request
|
|
168
|
+
this.isRefreshing = false;
|
|
169
|
+
throw new Error("Token refreshed, please retry the request");
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
catch (refreshError) {
|
|
173
|
+
// If refresh fails, continue to throw the original error
|
|
174
|
+
}
|
|
175
|
+
finally {
|
|
176
|
+
this.isRefreshing = false;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
if (statusCode === 401) {
|
|
180
|
+
throw new Error("Unauthorized: Please check your authentication token");
|
|
181
|
+
}
|
|
182
|
+
else if (statusCode === 404) {
|
|
183
|
+
throw new Error("Resource not found");
|
|
184
|
+
}
|
|
185
|
+
else if (errorData?.message) {
|
|
186
|
+
throw new Error(`API Error (${statusCode}): ${errorData.message}`);
|
|
187
|
+
}
|
|
188
|
+
else {
|
|
189
|
+
throw new Error(`API Error (${statusCode})`);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Attempt to refresh the token
|
|
194
|
+
* This is a placeholder method that will be overridden by AuthClient
|
|
195
|
+
*
|
|
196
|
+
* @returns Promise that resolves to true if token was refreshed, false otherwise
|
|
197
|
+
*/
|
|
198
|
+
async attemptTokenRefresh() {
|
|
199
|
+
// Base implementation does nothing
|
|
200
|
+
// Will be overridden by AuthClient
|
|
201
|
+
return false;
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* Execute a request with automatic token refresh handling
|
|
205
|
+
* For AuthClient, this will attempt to refresh the token and retry once on 401 errors
|
|
206
|
+
* Base implementation just executes the request
|
|
207
|
+
*
|
|
208
|
+
* @param requestFn - Function that executes the API request
|
|
209
|
+
* @returns Promise with the API response
|
|
210
|
+
*/
|
|
211
|
+
async executeRequest(requestFn) {
|
|
212
|
+
try {
|
|
213
|
+
return await requestFn();
|
|
214
|
+
}
|
|
215
|
+
catch (error) {
|
|
216
|
+
// Handle 401 errors by attempting to refresh token
|
|
217
|
+
if (error &&
|
|
218
|
+
typeof error === "object" &&
|
|
219
|
+
"status" in error &&
|
|
220
|
+
error.status === 401) {
|
|
221
|
+
// Attempt to refresh the token
|
|
222
|
+
const refreshed = await this.attemptTokenRefresh();
|
|
223
|
+
if (refreshed) {
|
|
224
|
+
// If token was refreshed, retry the request once
|
|
225
|
+
return await requestFn();
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
// Check if the error is from handleError and is the special refresh token message
|
|
229
|
+
if (error instanceof Error &&
|
|
230
|
+
error.message === "Token refreshed, please retry the request") {
|
|
231
|
+
// If token was refreshed, retry the request once
|
|
232
|
+
return await requestFn();
|
|
233
|
+
}
|
|
234
|
+
// Otherwise, throw the error to be handled by the caller
|
|
235
|
+
throw error;
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
exports.StorefrontAPIClient = StorefrontAPIClient;
|