@o2vend/theme-cli 1.0.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.

Potentially problematic release.


This version of @o2vend/theme-cli might be problematic. Click here for more details.

@@ -0,0 +1,339 @@
1
+ /**
2
+ * O2VEND API Client
3
+ * Standalone implementation - copied and adapted from webstore solution
4
+ * Update manually when webstore solution changes
5
+ *
6
+ * Source: o2vend-webstore/services/o2vend-api-client.js
7
+ */
8
+
9
+ const axios = require('axios');
10
+ const NodeCache = require('node-cache');
11
+ const crypto = require('crypto');
12
+
13
+ /**
14
+ * O2VEND Storefront API Client
15
+ * Handles all API communication with the O2VEND Storefront API
16
+ *
17
+ * Note: The API returns all field names in lowercase (camelCase), not PascalCase.
18
+ */
19
+ class O2VendApiClient {
20
+ constructor(tenantId, apiKey, baseUrl = null, checkoutSignature = null) {
21
+ this.tenantId = tenantId;
22
+ this.apiKey = apiKey;
23
+ this.baseUrl = baseUrl || process.env.O2VEND_API_BASE_URL;
24
+ this.timeout = parseInt(process.env.O2VEND_API_TIMEOUT) || 10000;
25
+ this.checkoutSignature = checkoutSignature;
26
+
27
+ // Initialize cache with 5 minute TTL
28
+ this.cache = new NodeCache({
29
+ stdTTL: 300, // 5 minutes
30
+ checkperiod: 60 // Check for expired keys every minute
31
+ });
32
+
33
+ // Create axios instance with default config
34
+ this.client = axios.create({
35
+ baseURL: this.baseUrl && this.baseUrl.endsWith('/') ? this.baseUrl.slice(0, -1) : this.baseUrl,
36
+ timeout: this.timeout,
37
+ headers: {
38
+ 'X-O2VEND-SHOPFRONT-API-KEY': this.apiKey,
39
+ 'Content-Type': 'application/json',
40
+ 'User-Agent': 'O2VEND-Theme-CLI/1.0'
41
+ }
42
+ });
43
+
44
+ // Setup interceptors
45
+ this.setupInterceptors();
46
+ }
47
+
48
+ /**
49
+ * Normalize object keys from PascalCase to camelCase recursively
50
+ * @param {*} obj - Object to normalize
51
+ * @returns {*} Object with normalized keys
52
+ */
53
+ normalizeKeys(obj) {
54
+ if (obj === null || obj === undefined) {
55
+ return obj;
56
+ }
57
+
58
+ if (Array.isArray(obj)) {
59
+ return obj.map(item => this.normalizeKeys(item));
60
+ }
61
+
62
+ if (typeof obj === 'object') {
63
+ const normalized = {};
64
+ for (const key in obj) {
65
+ if (obj.hasOwnProperty(key)) {
66
+ const normalizedKey = key.charAt(0).toLowerCase() + key.slice(1);
67
+ normalized[normalizedKey] = this.normalizeKeys(obj[key]);
68
+ }
69
+ }
70
+ return normalized;
71
+ }
72
+
73
+ return obj;
74
+ }
75
+
76
+ /**
77
+ * Setup axios interceptors for logging and error handling
78
+ */
79
+ setupInterceptors() {
80
+ // Request interceptor
81
+ this.client.interceptors.request.use(
82
+ (config) => {
83
+ return config;
84
+ },
85
+ (error) => {
86
+ console.error('[O2VEND API] Request error:', error.message);
87
+ return Promise.reject(error);
88
+ }
89
+ );
90
+
91
+ // Response interceptor - normalize all response data
92
+ this.client.interceptors.response.use(
93
+ (response) => {
94
+ if (response.data) {
95
+ response.data = this.normalizeKeys(response.data);
96
+ }
97
+ return response;
98
+ },
99
+ (error) => {
100
+ if (error.response) {
101
+ const status = error.response.status;
102
+ if (status === 404 && process.env.DEBUG_API_ERRORS !== 'true') {
103
+ // Don't log 404s unless debug mode
104
+ } else {
105
+ console.error(`[O2VEND API] Response error: ${status}`, error.message);
106
+ }
107
+ } else if (error.request) {
108
+ console.error('[O2VEND API] Network error: Unable to reach API');
109
+ }
110
+ return Promise.reject(error);
111
+ }
112
+ );
113
+ }
114
+
115
+ /**
116
+ * Generic GET request with caching
117
+ * @param {string} endpoint - API endpoint
118
+ * @param {Object} params - Query parameters
119
+ * @param {boolean} useCache - Whether to use cache (default: false)
120
+ * @returns {Promise<Object>} API response data
121
+ */
122
+ async get(endpoint, params = {}, useCache = false) {
123
+ const cacheKey = `${endpoint}-${JSON.stringify(params)}`;
124
+
125
+ if (useCache && this.cache.has(cacheKey)) {
126
+ return this.cache.get(cacheKey);
127
+ }
128
+
129
+ try {
130
+ const response = await this.client.get(endpoint, { params });
131
+ const data = response.data;
132
+
133
+ if (useCache) {
134
+ this.cache.set(cacheKey, data);
135
+ }
136
+
137
+ return data;
138
+ } catch (error) {
139
+ console.error(`[O2VEND API] GET ${endpoint} failed:`, error.message);
140
+ throw error;
141
+ }
142
+ }
143
+
144
+ /**
145
+ * Generic POST request
146
+ * @param {string} endpoint - API endpoint
147
+ * @param {Object} data - Request body
148
+ * @param {Object} config - Additional axios config
149
+ * @returns {Promise<Object>} API response data
150
+ */
151
+ async post(endpoint, data = {}, config = {}) {
152
+ try {
153
+ const response = await this.client.post(endpoint, data, config);
154
+ return response.data;
155
+ } catch (error) {
156
+ console.error(`[O2VEND API] POST ${endpoint} failed:`, error.message);
157
+ throw error;
158
+ }
159
+ }
160
+
161
+ /**
162
+ * Generic PUT request
163
+ * @param {string} endpoint - API endpoint
164
+ * @param {Object} data - Request body
165
+ * @param {Object} config - Additional axios config
166
+ * @returns {Promise<Object>} API response data
167
+ */
168
+ async put(endpoint, data = {}, config = {}) {
169
+ try {
170
+ const response = await this.client.put(endpoint, data, config);
171
+ return response.data;
172
+ } catch (error) {
173
+ console.error(`[O2VEND API] PUT ${endpoint} failed:`, error.message);
174
+ throw error;
175
+ }
176
+ }
177
+
178
+ /**
179
+ * Generic DELETE request
180
+ * @param {string} endpoint - API endpoint
181
+ * @param {Object} config - Additional axios config
182
+ * @returns {Promise<Object>} API response data
183
+ */
184
+ async delete(endpoint, config = {}) {
185
+ try {
186
+ const response = await this.client.delete(endpoint, config);
187
+ return response.data;
188
+ } catch (error) {
189
+ console.error(`[O2VEND API] DELETE ${endpoint} failed:`, error.message);
190
+ throw error;
191
+ }
192
+ }
193
+
194
+ // ==================== CORE ENDPOINTS ====================
195
+
196
+ /**
197
+ * Get store information
198
+ * @param {boolean} useCache - Whether to use cache
199
+ * @returns {Promise<Object>} Store information
200
+ */
201
+ async getStoreInfo(useCache = false) {
202
+ return this.get('/shopfront/api/v2/storeinfo', {}, useCache);
203
+ }
204
+
205
+ /**
206
+ * Get store settings
207
+ * @param {boolean} useCache - Whether to use cache
208
+ * @returns {Promise<Object>} Store settings
209
+ */
210
+ async getSettings(useCache = false) {
211
+ return this.get('/shopfront/api/v2/settings', {}, useCache);
212
+ }
213
+
214
+ // ==================== PRODUCT ENDPOINTS ====================
215
+
216
+ /**
217
+ * Get products
218
+ * @param {Object} productQueryRequest - Query parameters
219
+ * @returns {Promise<Object>} Products response
220
+ */
221
+ async getProducts(productQueryRequest = {}) {
222
+ return this.post('/shopfront/api/v2/products', productQueryRequest);
223
+ }
224
+
225
+ /**
226
+ * Get product by ID
227
+ * @param {string} id - Product ID
228
+ * @param {boolean} useCache - Whether to use cache
229
+ * @returns {Promise<Object>} Product data
230
+ */
231
+ async getProductById(id, useCache = false) {
232
+ return this.get(`/shopfront/api/v2/products/${id}`, {}, useCache);
233
+ }
234
+
235
+ /**
236
+ * Search products
237
+ * @param {Object} searchRequest - Search parameters
238
+ * @returns {Promise<Object>} Search results
239
+ */
240
+ async searchProducts(searchRequest = {}) {
241
+ return this.post('/shopfront/api/v2/products/search', searchRequest);
242
+ }
243
+
244
+ // ==================== CATEGORY ENDPOINTS ====================
245
+
246
+ /**
247
+ * Get categories
248
+ * @param {Object} categoryQueryRequest - Query parameters
249
+ * @returns {Promise<Object>} Categories response
250
+ */
251
+ async getCategories(categoryQueryRequest = {}) {
252
+ return this.post('/shopfront/api/v2/categories', categoryQueryRequest);
253
+ }
254
+
255
+ // ==================== BRAND ENDPOINTS ====================
256
+
257
+ /**
258
+ * Get brands
259
+ * @param {Object} brandQueryRequest - Query parameters
260
+ * @returns {Promise<Object>} Brands response
261
+ */
262
+ async getBrands(brandQueryRequest = {}) {
263
+ return this.post('/shopfront/api/v2/brands', brandQueryRequest);
264
+ }
265
+
266
+ // ==================== WIDGET ENDPOINTS ====================
267
+
268
+ /**
269
+ * Get widgets
270
+ * @param {Object} params - Widget query parameters (section, pageId, etc.)
271
+ * @returns {Promise<Object>} Widgets response
272
+ */
273
+ async getWidgets(params = {}) {
274
+ return this.post('/shopfront/api/v2/widgets', params);
275
+ }
276
+
277
+ /**
278
+ * Get widgets by section
279
+ * @param {string} pageId - Page ID (optional)
280
+ * @param {string} section - Section name
281
+ * @returns {Promise<Array>} Widgets array
282
+ */
283
+ async getWidgetsBySection(pageId, section) {
284
+ const params = {
285
+ section,
286
+ status: 'active'
287
+ };
288
+ if (pageId) {
289
+ params.pageId = pageId;
290
+ }
291
+
292
+ const response = await this.getWidgets(params);
293
+ return response.widgets || response.data || [];
294
+ }
295
+
296
+ // ==================== CART ENDPOINTS ====================
297
+
298
+ /**
299
+ * Get cart
300
+ * @param {string} cartId - Cart ID
301
+ * @returns {Promise<Object>} Cart data
302
+ */
303
+ async getCart(cartId) {
304
+ return this.get(`/shopfront/api/v2/cart/${cartId}`);
305
+ }
306
+
307
+ /**
308
+ * Add item to cart
309
+ * @param {string} cartId - Cart ID
310
+ * @param {Object} item - Cart item
311
+ * @returns {Promise<Object>} Updated cart
312
+ */
313
+ async addToCart(cartId, item) {
314
+ return this.post(`/shopfront/api/v2/cart/${cartId}/items`, item);
315
+ }
316
+
317
+ /**
318
+ * Update cart item
319
+ * @param {string} cartId - Cart ID
320
+ * @param {string} itemId - Item ID
321
+ * @param {Object} update - Update data
322
+ * @returns {Promise<Object>} Updated cart
323
+ */
324
+ async updateCartItem(cartId, itemId, update) {
325
+ return this.put(`/shopfront/api/v2/cart/${cartId}/items/${itemId}`, update);
326
+ }
327
+
328
+ /**
329
+ * Remove cart item
330
+ * @param {string} cartId - Cart ID
331
+ * @param {string} itemId - Item ID
332
+ * @returns {Promise<Object>} Updated cart
333
+ */
334
+ async removeCartItem(cartId, itemId) {
335
+ return this.delete(`/shopfront/api/v2/cart/${cartId}/items/${itemId}`);
336
+ }
337
+ }
338
+
339
+ module.exports = O2VendApiClient;