@commercengine/storefront-sdk 0.3.8 → 0.3.10
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 +43 -1
- package/dist/index.js +29 -1
- package/dist/lib/cart.d.ts +4 -4
- package/dist/lib/cart.js +10 -4
- package/dist/lib/catalog.d.ts +30 -26
- package/dist/lib/catalog.js +55 -34
- package/dist/lib/client.d.ts +8 -0
- package/dist/lib/client.js +65 -5
- package/dist/lib/logger-utils.d.ts +88 -0
- package/dist/lib/logger-utils.js +211 -0
- package/dist/types/storefront-api-types.d.ts +14 -5
- package/dist/types/storefront.d.ts +162 -29
- package/package.json +1 -1
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import type { Middleware } from "openapi-fetch";
|
|
2
|
+
/**
|
|
3
|
+
* Debug logger function interface
|
|
4
|
+
*/
|
|
5
|
+
export interface DebugLoggerFn {
|
|
6
|
+
(level: "info" | "warn" | "error", message: string, data?: any): void;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Response utilities for debugging and working with Response objects
|
|
10
|
+
*/
|
|
11
|
+
export declare class ResponseUtils {
|
|
12
|
+
/**
|
|
13
|
+
* Get response headers as a plain object
|
|
14
|
+
*/
|
|
15
|
+
static getHeaders(response: Response): Record<string, string>;
|
|
16
|
+
/**
|
|
17
|
+
* Get specific header value
|
|
18
|
+
*/
|
|
19
|
+
static getHeader(response: Response, name: string): string | null;
|
|
20
|
+
/**
|
|
21
|
+
* Check if response was successful
|
|
22
|
+
*/
|
|
23
|
+
static isSuccess(response: Response): boolean;
|
|
24
|
+
/**
|
|
25
|
+
* Get response metadata
|
|
26
|
+
*/
|
|
27
|
+
static getMetadata(response: Response): {
|
|
28
|
+
status: number;
|
|
29
|
+
statusText: string;
|
|
30
|
+
ok: boolean;
|
|
31
|
+
url: string;
|
|
32
|
+
redirected: boolean;
|
|
33
|
+
type: ResponseType;
|
|
34
|
+
headers: {
|
|
35
|
+
[k: string]: string;
|
|
36
|
+
};
|
|
37
|
+
};
|
|
38
|
+
/**
|
|
39
|
+
* Clone and read response as text (useful for debugging)
|
|
40
|
+
* Note: This can only be called once per response
|
|
41
|
+
*/
|
|
42
|
+
static getText(response: Response): Promise<string>;
|
|
43
|
+
/**
|
|
44
|
+
* Clone and read response as JSON (useful for debugging)
|
|
45
|
+
* Note: This can only be called once per response
|
|
46
|
+
*/
|
|
47
|
+
static getJSON(response: Response): Promise<any>;
|
|
48
|
+
/**
|
|
49
|
+
* Format response information for debugging
|
|
50
|
+
*/
|
|
51
|
+
static format(response: Response): string;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Debug logging utilities
|
|
55
|
+
*/
|
|
56
|
+
export declare class DebugLogger {
|
|
57
|
+
private logger;
|
|
58
|
+
private responseTextCache;
|
|
59
|
+
constructor(logger?: DebugLoggerFn);
|
|
60
|
+
/**
|
|
61
|
+
* Log debug information about API request
|
|
62
|
+
*/
|
|
63
|
+
logRequest(request: Request, requestBody?: any): void;
|
|
64
|
+
/**
|
|
65
|
+
* Log debug information about API response
|
|
66
|
+
*/
|
|
67
|
+
logResponse(response: Response, responseBody?: any): Promise<void>;
|
|
68
|
+
/**
|
|
69
|
+
* Log error information
|
|
70
|
+
*/
|
|
71
|
+
logError(message: string, error: any): void;
|
|
72
|
+
/**
|
|
73
|
+
* Get cached response text for a URL (if available)
|
|
74
|
+
*/
|
|
75
|
+
getCachedResponseText(url: string): string | null;
|
|
76
|
+
/**
|
|
77
|
+
* Clear cached response texts
|
|
78
|
+
*/
|
|
79
|
+
clearCache(): void;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Extract request body for logging
|
|
83
|
+
*/
|
|
84
|
+
export declare function extractRequestBody(request: Request): Promise<any>;
|
|
85
|
+
/**
|
|
86
|
+
* Create debug middleware for openapi-fetch (internal use)
|
|
87
|
+
*/
|
|
88
|
+
export declare function createDebugMiddleware(logger?: DebugLoggerFn): Middleware;
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Response utilities for debugging and working with Response objects
|
|
3
|
+
*/
|
|
4
|
+
export class ResponseUtils {
|
|
5
|
+
/**
|
|
6
|
+
* Get response headers as a plain object
|
|
7
|
+
*/
|
|
8
|
+
static getHeaders(response) {
|
|
9
|
+
return Object.fromEntries(response.headers.entries());
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Get specific header value
|
|
13
|
+
*/
|
|
14
|
+
static getHeader(response, name) {
|
|
15
|
+
return response.headers.get(name);
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Check if response was successful
|
|
19
|
+
*/
|
|
20
|
+
static isSuccess(response) {
|
|
21
|
+
return response.ok;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Get response metadata
|
|
25
|
+
*/
|
|
26
|
+
static getMetadata(response) {
|
|
27
|
+
return {
|
|
28
|
+
status: response.status,
|
|
29
|
+
statusText: response.statusText,
|
|
30
|
+
ok: response.ok,
|
|
31
|
+
url: response.url,
|
|
32
|
+
redirected: response.redirected,
|
|
33
|
+
type: response.type,
|
|
34
|
+
headers: Object.fromEntries(response.headers.entries()),
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Clone and read response as text (useful for debugging)
|
|
39
|
+
* Note: This can only be called once per response
|
|
40
|
+
*/
|
|
41
|
+
static async getText(response) {
|
|
42
|
+
const cloned = response.clone();
|
|
43
|
+
return await cloned.text();
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Clone and read response as JSON (useful for debugging)
|
|
47
|
+
* Note: This can only be called once per response
|
|
48
|
+
*/
|
|
49
|
+
static async getJSON(response) {
|
|
50
|
+
const cloned = response.clone();
|
|
51
|
+
return await cloned.json();
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Format response information for debugging
|
|
55
|
+
*/
|
|
56
|
+
static format(response) {
|
|
57
|
+
const metadata = this.getMetadata(response);
|
|
58
|
+
return `${metadata.status} ${metadata.statusText} - ${metadata.url}`;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Debug logging utilities
|
|
63
|
+
*/
|
|
64
|
+
export class DebugLogger {
|
|
65
|
+
logger;
|
|
66
|
+
responseTextCache = new Map();
|
|
67
|
+
constructor(logger) {
|
|
68
|
+
this.logger =
|
|
69
|
+
logger ||
|
|
70
|
+
((level, message, data) => {
|
|
71
|
+
console.log(`[${level.toUpperCase()}]`, message);
|
|
72
|
+
if (data)
|
|
73
|
+
console.log(data);
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Log debug information about API request
|
|
78
|
+
*/
|
|
79
|
+
logRequest(request, requestBody) {
|
|
80
|
+
this.logger("info", "API Request Debug Info", {
|
|
81
|
+
method: request.method,
|
|
82
|
+
url: request.url,
|
|
83
|
+
headers: Object.fromEntries(request.headers.entries()),
|
|
84
|
+
body: requestBody,
|
|
85
|
+
timestamp: new Date().toISOString(),
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Log debug information about API response
|
|
90
|
+
*/
|
|
91
|
+
async logResponse(response, responseBody) {
|
|
92
|
+
// Cache response text for later use by ResponseUtils
|
|
93
|
+
if (responseBody && typeof responseBody === "string") {
|
|
94
|
+
this.responseTextCache.set(response.url, responseBody);
|
|
95
|
+
}
|
|
96
|
+
// Log response metadata
|
|
97
|
+
this.logger("info", "API Response Debug Info", {
|
|
98
|
+
url: response.url,
|
|
99
|
+
status: response.status,
|
|
100
|
+
statusText: response.statusText,
|
|
101
|
+
ok: response.ok,
|
|
102
|
+
headers: Object.fromEntries(response.headers.entries()),
|
|
103
|
+
redirected: response.redirected,
|
|
104
|
+
type: response.type,
|
|
105
|
+
timestamp: new Date().toISOString(),
|
|
106
|
+
});
|
|
107
|
+
// Log response body if available
|
|
108
|
+
if (responseBody) {
|
|
109
|
+
this.logger("info", "API Response Data", {
|
|
110
|
+
data: responseBody,
|
|
111
|
+
contentType: response.headers.get("content-type"),
|
|
112
|
+
contentLength: response.headers.get("content-length"),
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Log error information
|
|
118
|
+
*/
|
|
119
|
+
logError(message, error) {
|
|
120
|
+
this.logger("error", message, error);
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Get cached response text for a URL (if available)
|
|
124
|
+
*/
|
|
125
|
+
getCachedResponseText(url) {
|
|
126
|
+
return this.responseTextCache.get(url) || null;
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Clear cached response texts
|
|
130
|
+
*/
|
|
131
|
+
clearCache() {
|
|
132
|
+
this.responseTextCache.clear();
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Extract request body for logging
|
|
137
|
+
*/
|
|
138
|
+
export async function extractRequestBody(request) {
|
|
139
|
+
if (request.method === "GET" || request.method === "HEAD") {
|
|
140
|
+
return null;
|
|
141
|
+
}
|
|
142
|
+
try {
|
|
143
|
+
const clonedRequest = request.clone();
|
|
144
|
+
const contentType = request.headers.get("content-type")?.toLowerCase();
|
|
145
|
+
if (contentType?.startsWith("application/json")) {
|
|
146
|
+
return await clonedRequest.json();
|
|
147
|
+
}
|
|
148
|
+
else if (contentType?.startsWith("multipart/form-data")) {
|
|
149
|
+
return "[FormData - cannot display]";
|
|
150
|
+
}
|
|
151
|
+
else if (contentType?.startsWith("text/")) {
|
|
152
|
+
return await clonedRequest.text();
|
|
153
|
+
}
|
|
154
|
+
return "[Request body - unknown format]";
|
|
155
|
+
}
|
|
156
|
+
catch (error) {
|
|
157
|
+
return "[Request body unavailable]";
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Create debug middleware for openapi-fetch (internal use)
|
|
162
|
+
*/
|
|
163
|
+
export function createDebugMiddleware(logger) {
|
|
164
|
+
const debugLogger = new DebugLogger(logger);
|
|
165
|
+
return {
|
|
166
|
+
async onRequest({ request }) {
|
|
167
|
+
// Log request information
|
|
168
|
+
const requestBody = await extractRequestBody(request);
|
|
169
|
+
debugLogger.logRequest(request, requestBody);
|
|
170
|
+
return request;
|
|
171
|
+
},
|
|
172
|
+
async onResponse({ response }) {
|
|
173
|
+
// Clone response to read body without consuming it
|
|
174
|
+
const cloned = response.clone();
|
|
175
|
+
let responseBody = null;
|
|
176
|
+
try {
|
|
177
|
+
const contentType = response.headers.get("content-type")?.toLowerCase();
|
|
178
|
+
if (contentType?.startsWith("application/json")) {
|
|
179
|
+
responseBody = await cloned.json();
|
|
180
|
+
}
|
|
181
|
+
else if (contentType?.startsWith("text/")) {
|
|
182
|
+
responseBody = await cloned.text();
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
catch (error) {
|
|
186
|
+
// Ignore body reading errors
|
|
187
|
+
}
|
|
188
|
+
// Log response information
|
|
189
|
+
await debugLogger.logResponse(response, responseBody);
|
|
190
|
+
return response;
|
|
191
|
+
},
|
|
192
|
+
async onError({ error, request }) {
|
|
193
|
+
// Log error information with request context
|
|
194
|
+
debugLogger.logError("API Request Failed", {
|
|
195
|
+
error: {
|
|
196
|
+
name: error instanceof Error ? error.name : "Unknown",
|
|
197
|
+
message: error instanceof Error ? error.message : String(error),
|
|
198
|
+
stack: error instanceof Error ? error.stack : undefined,
|
|
199
|
+
},
|
|
200
|
+
request: {
|
|
201
|
+
method: request.method,
|
|
202
|
+
url: request.url,
|
|
203
|
+
headers: Object.fromEntries(request.headers.entries()),
|
|
204
|
+
},
|
|
205
|
+
timestamp: new Date().toISOString(),
|
|
206
|
+
});
|
|
207
|
+
// Re-throw the error to maintain normal error handling
|
|
208
|
+
throw error;
|
|
209
|
+
},
|
|
210
|
+
};
|
|
211
|
+
}
|
|
@@ -2,9 +2,11 @@ import type { paths } from './storefront';
|
|
|
2
2
|
export type ApiResult<T> = {
|
|
3
3
|
data: T;
|
|
4
4
|
error: null;
|
|
5
|
+
response: Response;
|
|
5
6
|
} | {
|
|
6
7
|
data: null;
|
|
7
8
|
error: ApiErrorResponse;
|
|
9
|
+
response: Response;
|
|
8
10
|
};
|
|
9
11
|
export type ApiErrorResponse = {
|
|
10
12
|
success?: boolean;
|
|
@@ -15,21 +17,23 @@ export type ApiErrorResponse = {
|
|
|
15
17
|
export type ListProductsResponse = paths['/catalog/products']['get']['responses'][200]['content']['application/json'];
|
|
16
18
|
export type ListProductsContent = ListProductsResponse['content'];
|
|
17
19
|
export type ListProductsQuery = paths['/catalog/products']['get']['parameters']['query'];
|
|
20
|
+
export type ListProductsHeaderParams = paths['/catalog/products']['get']['parameters']['header'];
|
|
18
21
|
export type ListSkusResponse = paths['/catalog/skus']['get']['responses'][200]['content']['application/json'];
|
|
19
22
|
export type ListSkusContent = ListSkusResponse['content'];
|
|
20
23
|
export type ListSkusQuery = paths['/catalog/skus']['get']['parameters']['query'];
|
|
21
|
-
export type
|
|
24
|
+
export type ListSkusHeaderParams = paths['/catalog/skus']['get']['parameters']['header'];
|
|
25
|
+
export type GetProductDetailResponse = paths['/catalog/products/{product_id_or_slug}']['get']['responses'][200]['content']['application/json'];
|
|
22
26
|
export type GetProductDetailContent = GetProductDetailResponse['content'];
|
|
23
|
-
export type
|
|
24
|
-
export type
|
|
27
|
+
export type GetProductDetailPathParams = paths['/catalog/products/{product_id_or_slug}']['get']['parameters']['path'];
|
|
28
|
+
export type GetProductDetailHeaderParams = paths['/catalog/products/{product_id_or_slug}']['get']['parameters']['header'];
|
|
25
29
|
export type ListProductVariantsResponse = paths['/catalog/products/{product_id}/variants']['get']['responses'][200]['content']['application/json'];
|
|
26
30
|
export type ListProductVariantsContent = ListProductVariantsResponse['content'];
|
|
27
|
-
export type ListProductVariantsQuery = paths['/catalog/products/{product_id}/variants']['get']['parameters']['query'];
|
|
28
31
|
export type ListProductVariantsPathParams = paths['/catalog/products/{product_id}/variants']['get']['parameters']['path'];
|
|
32
|
+
export type ListProductVariantsHeaderParams = paths['/catalog/products/{product_id}/variants']['get']['parameters']['header'];
|
|
29
33
|
export type GetVariantDetailResponse = paths['/catalog/products/{product_id}/variants/{variant_id}']['get']['responses'][200]['content']['application/json'];
|
|
30
34
|
export type GetVariantDetailContent = GetVariantDetailResponse['content'];
|
|
31
|
-
export type GetVariantDetailQuery = paths['/catalog/products/{product_id}/variants/{variant_id}']['get']['parameters']['query'];
|
|
32
35
|
export type GetVariantDetailPathParams = paths['/catalog/products/{product_id}/variants/{variant_id}']['get']['parameters']['path'];
|
|
36
|
+
export type GetVariantDetailHeaderParams = paths['/catalog/products/{product_id}/variants/{variant_id}']['get']['parameters']['header'];
|
|
33
37
|
export type ListCategoriesResponse = paths['/catalog/categories']['get']['responses'][200]['content']['application/json'];
|
|
34
38
|
export type ListCategoriesContent = ListCategoriesResponse['content'];
|
|
35
39
|
export type ListCategoriesQuery = paths['/catalog/categories']['get']['parameters']['query'];
|
|
@@ -43,12 +47,15 @@ export type CreateProductReviewFormData = NonNullable<paths['/catalog/products/{
|
|
|
43
47
|
export type ListSimilarProductsResponse = paths['/catalog/products/similar']['get']['responses'][200]['content']['application/json'];
|
|
44
48
|
export type ListSimilarProductsContent = ListSimilarProductsResponse['content'];
|
|
45
49
|
export type ListSimilarProductsQuery = paths['/catalog/products/similar']['get']['parameters']['query'];
|
|
50
|
+
export type ListSimilarProductsHeaderParams = paths['/catalog/products/similar']['get']['parameters']['header'];
|
|
46
51
|
export type ListUpsellProductsResponse = paths['/catalog/products/up-sell']['get']['responses'][200]['content']['application/json'];
|
|
47
52
|
export type ListUpsellProductsContent = ListUpsellProductsResponse['content'];
|
|
48
53
|
export type ListUpsellProductsQuery = paths['/catalog/products/up-sell']['get']['parameters']['query'];
|
|
54
|
+
export type ListUpsellProductsHeaderParams = paths['/catalog/products/up-sell']['get']['parameters']['header'];
|
|
49
55
|
export type ListCrosssellProductsResponse = paths['/catalog/products/cross-sell']['get']['responses'][200]['content']['application/json'];
|
|
50
56
|
export type ListCrosssellProductsContent = ListCrosssellProductsResponse['content'];
|
|
51
57
|
export type ListCrosssellProductsQuery = paths['/catalog/products/cross-sell']['get']['parameters']['query'];
|
|
58
|
+
export type ListCrosssellProductsHeaderParams = paths['/catalog/products/cross-sell']['get']['parameters']['header'];
|
|
52
59
|
export type SearchProductsResponse = paths['/catalog/products/search']['post']['responses'][200]['content']['application/json'];
|
|
53
60
|
export type SearchProductsContent = SearchProductsResponse['content'];
|
|
54
61
|
export type SearchProductsBody = NonNullable<paths['/catalog/products/search']['post']['requestBody']>['content']['application/json'];
|
|
@@ -151,6 +158,8 @@ export type DeleteAddressResponse = paths['/customers/{user_id}/addresses/{addre
|
|
|
151
158
|
export type DeleteAddressPathParams = paths['/customers/{user_id}/addresses/{address_id}']['delete']['parameters']['path'];
|
|
152
159
|
export type ListKycDocumentResponse = paths['/store/kyc-document']['get']['responses'][200]['content']['application/json'];
|
|
153
160
|
export type ListKycDocumentContent = ListKycDocumentResponse['content'];
|
|
161
|
+
export type GetConfigResponse = paths['/store/config']['get']['responses'][200]['content']['application/json'];
|
|
162
|
+
export type GetConfigContent = GetConfigResponse['content'];
|
|
154
163
|
export type ListDocumentsResponse = paths['/customers/{id}/documents']['get']['responses'][200]['content']['application/json'];
|
|
155
164
|
export type ListDocumentsContent = ListDocumentsResponse['content'];
|
|
156
165
|
export type ListDocumentsPathParams = paths['/customers/{id}/documents']['get']['parameters']['path'];
|