@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.
@@ -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 GetProductDetailResponse = paths['/catalog/products/{product_id}']['get']['responses'][200]['content']['application/json'];
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 GetProductDetailQuery = paths['/catalog/products/{product_id}']['get']['parameters']['query'];
24
- export type GetProductDetailPathParams = paths['/catalog/products/{product_id}']['get']['parameters']['path'];
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'];