@kasuvia/sdk 0.0.2 → 0.0.5

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.
Files changed (77) hide show
  1. package/dist/hooks/index.d.mts +430 -0
  2. package/dist/hooks/index.d.ts +430 -0
  3. package/dist/hooks/index.js +3073 -0
  4. package/dist/hooks/index.js.map +1 -0
  5. package/dist/hooks/index.mjs +2962 -0
  6. package/dist/hooks/index.mjs.map +1 -0
  7. package/dist/index-CxNLI4nw.d.ts +786 -0
  8. package/dist/index-CzVMyUs4.d.mts +492 -0
  9. package/dist/index-CzVMyUs4.d.ts +492 -0
  10. package/dist/index-Dowl5224.d.mts +786 -0
  11. package/dist/index.d.mts +48 -1739
  12. package/dist/index.d.ts +48 -1739
  13. package/dist/index.js +1544 -2359
  14. package/dist/index.js.map +1 -1
  15. package/dist/index.mjs +1527 -2258
  16. package/dist/index.mjs.map +1 -1
  17. package/dist/sdk-context-BuarJbeb.d.ts +75 -0
  18. package/dist/sdk-context-Db8kf1Tv.d.mts +75 -0
  19. package/dist/services/index.d.mts +2 -0
  20. package/dist/services/index.d.ts +2 -0
  21. package/dist/services/index.js +2369 -0
  22. package/dist/services/index.js.map +1 -0
  23. package/dist/services/index.mjs +2252 -0
  24. package/dist/services/index.mjs.map +1 -0
  25. package/package.json +11 -2
  26. package/src/config/index.ts +10 -91
  27. package/src/constants.ts +13 -0
  28. package/src/context/sdk-context.tsx +70 -0
  29. package/src/graphql/collections.graphql.ts +2 -10
  30. package/src/graphql/products.graphql.ts +215 -65
  31. package/src/graphql/wishlist.graphql.ts +7 -6
  32. package/src/hooks/index.ts +2 -0
  33. package/src/hooks/use-auth.ts +82 -158
  34. package/src/hooks/use-bespoke-availability.ts +25 -8
  35. package/src/hooks/use-cart.ts +222 -119
  36. package/src/hooks/use-cms.ts +179 -86
  37. package/src/hooks/use-collections.ts +52 -15
  38. package/src/hooks/use-consultation-stream.ts +4 -3
  39. package/src/hooks/use-consultations.ts +120 -51
  40. package/src/hooks/use-countries.ts +35 -13
  41. package/src/hooks/use-currencies.ts +26 -13
  42. package/src/hooks/use-google-translate.ts +22 -8
  43. package/src/hooks/use-languages.ts +40 -20
  44. package/src/hooks/use-mobile.ts +23 -0
  45. package/src/hooks/use-order-stream.ts +9 -5
  46. package/src/hooks/use-orders.ts +99 -44
  47. package/src/hooks/use-payment.ts +108 -40
  48. package/src/hooks/use-products.ts +251 -53
  49. package/src/hooks/use-service-booking.ts +152 -90
  50. package/src/hooks/use-states.ts +35 -15
  51. package/src/hooks/use-wishlist.ts +92 -91
  52. package/src/index.ts +26 -30
  53. package/src/services/auth.service.ts +209 -167
  54. package/src/services/bespoke.service.ts +12 -4
  55. package/src/services/cart.service.ts +172 -70
  56. package/src/services/cms.service.ts +70 -35
  57. package/src/services/collection.service.ts +22 -5
  58. package/src/services/config.service.ts +34 -14
  59. package/src/services/consultation.service.ts +72 -18
  60. package/src/services/logistics.service.ts +35 -11
  61. package/src/services/notifications.service.ts +27 -12
  62. package/src/services/order.service.ts +74 -15
  63. package/src/services/payment.service.ts +86 -31
  64. package/src/services/product.service.ts +279 -39
  65. package/src/services/service-booking.service.ts +98 -26
  66. package/src/services/wishlist.service.ts +69 -25
  67. package/src/types/auth/index.ts +6 -4
  68. package/src/types/business/index.ts +7 -2
  69. package/src/types/payments/index.ts +3 -3
  70. package/src/types/services/index.ts +2 -5
  71. package/src/types/store/index.ts +38 -3
  72. package/src/utils/error-handler.ts +10 -5
  73. package/src/utils/storage.ts +48 -26
  74. package/src/utils/validators.ts +85 -0
  75. package/src/client/authClient.ts +0 -135
  76. package/src/client/graphqlClient.ts +0 -53
  77. package/src/client/httpClient.ts +0 -298
@@ -0,0 +1,2252 @@
1
+ // src/services/cart.service.ts
2
+ function parseItems(items) {
3
+ return items.map((item) => ({
4
+ ...item,
5
+ variant_attributes: item.variant_attributes && typeof item.variant_attributes === "string" ? JSON.parse(item.variant_attributes) : item.variant_attributes
6
+ }));
7
+ }
8
+ async function getGuestCart(config, guestSessionId) {
9
+ if (!guestSessionId) return [];
10
+ try {
11
+ const response = await fetch(`${config.backendUrls.store}/cart/`, {
12
+ headers: {
13
+ "X-Storefront-Key": config.storefrontApiKey,
14
+ "X-Business-ID": config.businessId,
15
+ "X-Guest-Session": guestSessionId
16
+ }
17
+ });
18
+ if (!response.ok) return [];
19
+ const data = await response.json();
20
+ return parseItems(data.items || []);
21
+ } catch {
22
+ return [];
23
+ }
24
+ }
25
+ async function addToGuestCart(config, guestSessionId, item) {
26
+ if (!guestSessionId) return [];
27
+ const payload = {
28
+ product_id: item.product_id,
29
+ product_slug: item.product_slug,
30
+ product_name: item.product_name,
31
+ image: item.image,
32
+ variant_id: item.variant_id,
33
+ variant_attributes: typeof item.variant_attributes === "string" ? item.variant_attributes : JSON.stringify(item.variant_attributes),
34
+ unit_price: item.unit_price,
35
+ quantity: item.quantity,
36
+ custom_measurements: item.custom_measurements,
37
+ is_bespoke: item.is_bespoke
38
+ };
39
+ const response = await fetch(`${config.backendUrls.store}/cart/`, {
40
+ method: "POST",
41
+ headers: {
42
+ "Content-Type": "application/json",
43
+ "X-Storefront-Key": config.storefrontApiKey,
44
+ "X-Business-ID": config.businessId,
45
+ "X-Guest-Session": guestSessionId
46
+ },
47
+ body: JSON.stringify(payload)
48
+ });
49
+ if (!response.ok) return [];
50
+ const data = await response.json();
51
+ return parseItems(data.items || []);
52
+ }
53
+ async function updateGuestCartItemQuantity(config, guestSessionId, itemId, quantity) {
54
+ if (!guestSessionId) return [];
55
+ const response = await fetch(`${config.backendUrls.store}/cart/${itemId}`, {
56
+ method: "PATCH",
57
+ headers: {
58
+ "Content-Type": "application/json",
59
+ "X-Storefront-Key": config.storefrontApiKey,
60
+ "X-Business-ID": config.businessId,
61
+ "X-Guest-Session": guestSessionId
62
+ },
63
+ body: JSON.stringify({ quantity })
64
+ });
65
+ if (!response.ok) return [];
66
+ const data = await response.json();
67
+ return parseItems(data.items || []);
68
+ }
69
+ async function removeFromGuestCart(config, guestSessionId, itemId) {
70
+ if (!guestSessionId) return [];
71
+ await fetch(`${config.backendUrls.store}/cart/${itemId}`, {
72
+ method: "DELETE",
73
+ headers: {
74
+ "X-Storefront-Key": config.storefrontApiKey,
75
+ "X-Business-ID": config.businessId,
76
+ "X-Guest-Session": guestSessionId
77
+ }
78
+ });
79
+ return getGuestCart(config, guestSessionId);
80
+ }
81
+ async function clearGuestCart(config, guestSessionId) {
82
+ if (!guestSessionId) return;
83
+ await fetch(`${config.backendUrls.store}/cart/clear`, {
84
+ method: "DELETE",
85
+ headers: {
86
+ "X-Storefront-Key": config.storefrontApiKey,
87
+ "X-Business-ID": config.businessId,
88
+ "X-Guest-Session": guestSessionId
89
+ }
90
+ });
91
+ }
92
+ async function getCart(config, accessToken) {
93
+ if (!accessToken) {
94
+ return { id: "", items: [], subtotal: 0, total: 0, product_type: "physical" };
95
+ }
96
+ const response = await fetch(`${config.backendUrls.store}/cart/`, {
97
+ headers: {
98
+ "Authorization": `Bearer ${accessToken}`,
99
+ "X-Storefront-Key": config.storefrontApiKey,
100
+ "X-Business-ID": config.businessId
101
+ }
102
+ });
103
+ if (!response.ok) throw new Error("Failed to fetch cart");
104
+ const data = await response.json();
105
+ const parsedItems = parseItems(data.items || []);
106
+ return { ...data, items: parsedItems };
107
+ }
108
+ async function addToCart(config, accessToken, item) {
109
+ const response = await fetch(`${config.backendUrls.store}/cart/`, {
110
+ method: "POST",
111
+ headers: {
112
+ "Content-Type": "application/json",
113
+ "Authorization": `Bearer ${accessToken}`,
114
+ "X-Storefront-Key": config.storefrontApiKey,
115
+ "X-Business-ID": config.businessId
116
+ },
117
+ body: JSON.stringify(item)
118
+ });
119
+ if (!response.ok) throw new Error("Failed to add to cart");
120
+ const data = await response.json();
121
+ const parsedItems = parseItems(data.items || []);
122
+ return { ...data, items: parsedItems };
123
+ }
124
+ async function updateCartItem(config, accessToken, itemId, quantity) {
125
+ const response = await fetch(`${config.backendUrls.store}/cart/${itemId}`, {
126
+ method: "PATCH",
127
+ headers: {
128
+ "Content-Type": "application/json",
129
+ "Authorization": `Bearer ${accessToken}`,
130
+ "X-Storefront-Key": config.storefrontApiKey,
131
+ "X-Business-ID": config.businessId
132
+ },
133
+ body: JSON.stringify({ quantity })
134
+ });
135
+ if (!response.ok) throw new Error("Failed to update cart item");
136
+ const data = await response.json();
137
+ const parsedItems = parseItems(data.items || []);
138
+ return { ...data, items: parsedItems };
139
+ }
140
+ async function removeFromCart(config, accessToken, itemId) {
141
+ await fetch(`${config.backendUrls.store}/cart/${itemId}`, {
142
+ method: "DELETE",
143
+ headers: {
144
+ "Authorization": `Bearer ${accessToken}`,
145
+ "X-Storefront-Key": config.storefrontApiKey,
146
+ "X-Business-ID": config.businessId
147
+ }
148
+ });
149
+ return getCart(config, accessToken);
150
+ }
151
+ async function clearCart(config, accessToken) {
152
+ await fetch(`${config.backendUrls.store}/cart/clear`, {
153
+ method: "DELETE",
154
+ headers: {
155
+ "Authorization": `Bearer ${accessToken}`,
156
+ "X-Storefront-Key": config.storefrontApiKey,
157
+ "X-Business-ID": config.businessId
158
+ }
159
+ });
160
+ }
161
+ async function mergeGuestCart(config, accessToken, guestSessionId) {
162
+ const guestItems = guestSessionId ? await getGuestCart(config, guestSessionId) : [];
163
+ if (guestItems.length === 0) {
164
+ return getCart(config, accessToken);
165
+ }
166
+ const payloadItems = guestItems.map((item) => ({
167
+ product_id: item.product_id,
168
+ product_slug: item.product_slug,
169
+ product_name: item.product_name,
170
+ image: item.image,
171
+ variant_id: item.variant_id,
172
+ variant_attributes: typeof item.variant_attributes === "string" ? item.variant_attributes : JSON.stringify(item.variant_attributes ?? {}),
173
+ unit_price: item.unit_price,
174
+ quantity: item.quantity,
175
+ custom_measurements: typeof item.custom_measurements === "string" ? item.custom_measurements : JSON.stringify(item.custom_measurements ?? {}),
176
+ is_bespoke: item.is_bespoke
177
+ }));
178
+ const headers = {
179
+ "Content-Type": "application/json",
180
+ "Authorization": `Bearer ${accessToken}`,
181
+ "X-Storefront-Key": config.storefrontApiKey,
182
+ "X-Business-ID": config.businessId
183
+ };
184
+ if (guestSessionId) {
185
+ headers["X-Guest-Session"] = guestSessionId;
186
+ }
187
+ const response = await fetch(`${config.backendUrls.store}/cart/merge`, {
188
+ method: "POST",
189
+ headers,
190
+ body: JSON.stringify({ items: payloadItems })
191
+ });
192
+ if (!response.ok) throw new Error("Failed to merge guest cart");
193
+ const data = await response.json();
194
+ return { ...data, items: parseItems(data.items || []) };
195
+ }
196
+ async function mergeGuestCartIfPresent(config, accessToken, guestSessionId) {
197
+ try {
198
+ const guestItems = await getGuestCart(config, guestSessionId);
199
+ if (guestItems.length === 0) return;
200
+ await mergeGuestCart(config, accessToken, guestSessionId);
201
+ } catch (error) {
202
+ console.warn("[Cart] Failed to merge guest cart:", error);
203
+ }
204
+ }
205
+ function getGuestCartCount() {
206
+ return 0;
207
+ }
208
+ function getGuestCartSubtotal() {
209
+ return 0;
210
+ }
211
+ function getGuestCartProductType() {
212
+ return "physical";
213
+ }
214
+
215
+ // src/services/order.service.ts
216
+ function deriveCustomerName(raw) {
217
+ if (raw.customer_name) return raw.customer_name;
218
+ if (raw.guest_name) return raw.guest_name;
219
+ const addr = typeof raw.shipping_address === "object" && raw.shipping_address !== null ? raw.shipping_address : null;
220
+ if (addr) {
221
+ const full = `${addr.first_name ?? ""} ${addr.last_name ?? ""}`.trim();
222
+ if (full) return full;
223
+ }
224
+ const email = raw.guest_email ?? raw.customer_email ?? "";
225
+ if (email) return email.split("@")[0];
226
+ return "";
227
+ }
228
+ function normaliseStorefrontOrder(raw) {
229
+ const items = (raw.items ?? []).map((item) => ({
230
+ id: item.id,
231
+ productName: item.product_name ?? item.productName ?? "",
232
+ image: item.image ?? "",
233
+ quantity: item.quantity ?? 1,
234
+ price: item.unit_price ?? item.price ?? 0
235
+ }));
236
+ const addr = typeof raw.shipping_address === "object" && raw.shipping_address !== null ? raw.shipping_address : null;
237
+ return {
238
+ id: raw.id,
239
+ display_id: raw.display_id,
240
+ items,
241
+ total: raw.total_amount ?? raw.total ?? 0,
242
+ status: raw.status,
243
+ customerEmail: raw.guest_email ?? raw.customer_email ?? "",
244
+ customerName: deriveCustomerName(raw),
245
+ createdAt: raw.created_at ? new Date(raw.created_at).getTime() : Date.now(),
246
+ updatedAt: raw.updated_at ? new Date(raw.updated_at).getTime() : Date.now(),
247
+ deliveryMethod: raw.delivery_method,
248
+ trackingNumber: raw.tracking_number,
249
+ deliveryAddress: typeof raw.shipping_address === "string" ? raw.shipping_address : addr ? `${addr.street}, ${addr.city}, ${addr.state}, ${addr.country}` : void 0,
250
+ shippingAddress: addr ? {
251
+ first_name: addr.first_name ?? "",
252
+ last_name: addr.last_name ?? "",
253
+ phone: addr.phone ?? "",
254
+ street: addr.street ?? "",
255
+ city: addr.city ?? "",
256
+ state: addr.state ?? "",
257
+ lga: addr.lga ?? "",
258
+ country: addr.country ?? "",
259
+ postal: addr.postal ?? ""
260
+ } : void 0,
261
+ cancellationReason: raw.cancellation_reason,
262
+ hasBespoke: raw.product_type === "bespoke",
263
+ bespokeStage: raw.bespoke_stage,
264
+ bespokeBrief: raw.bespoke_brief,
265
+ deliveryStatus: raw.delivery_status,
266
+ carrierName: raw.carrier_name,
267
+ terminalShipmentId: raw.terminal_shipment_id,
268
+ guestToken: raw.guest_token,
269
+ guestEmail: raw.guest_email,
270
+ guestPhone: raw.guest_phone,
271
+ guestName: raw.guest_name
272
+ };
273
+ }
274
+ async function createOrder(config, accessToken, payload) {
275
+ const response = await fetch(`${config.backendUrls.store}/orders/storefront`, {
276
+ method: "POST",
277
+ headers: {
278
+ "Content-Type": "application/json",
279
+ "Authorization": `Bearer ${accessToken}`,
280
+ "X-Storefront-Key": config.storefrontApiKey,
281
+ "X-Business-ID": config.businessId
282
+ },
283
+ body: JSON.stringify(payload)
284
+ });
285
+ if (!response.ok) throw new Error("Failed to create order");
286
+ const data = await response.json();
287
+ return normaliseStorefrontOrder(data);
288
+ }
289
+ async function findOrder(config, params) {
290
+ const queryParams = new URLSearchParams();
291
+ if (params.email) queryParams.set("email", params.email);
292
+ if (params.order_id) queryParams.set("order_id", params.order_id);
293
+ if (params.guest_token) queryParams.set("guest_token", params.guest_token);
294
+ const response = await fetch(`${config.backendUrls.store}/orders/find/?${queryParams.toString()}`, {
295
+ headers: {
296
+ "X-Storefront-Key": config.storefrontApiKey,
297
+ "X-Business-ID": config.businessId
298
+ }
299
+ });
300
+ if (!response.ok) throw new Error("Failed to find order");
301
+ const data = await response.json();
302
+ return normaliseStorefrontOrder(data);
303
+ }
304
+ async function findOrderByToken(config, token) {
305
+ const response = await fetch(`${config.backendUrls.store}/orders/find/?guest_token=${token}`, {
306
+ headers: {
307
+ "X-Storefront-Key": config.storefrontApiKey,
308
+ "X-Business-ID": config.businessId
309
+ }
310
+ });
311
+ if (!response.ok) throw new Error("Failed to find order by token");
312
+ const data = await response.json();
313
+ return normaliseStorefrontOrder(data);
314
+ }
315
+ async function getOrders(config, accessToken, params) {
316
+ const queryParams = new URLSearchParams();
317
+ if (params?.email) queryParams.set("email", params.email);
318
+ if (params?.page) queryParams.set("page", params.page.toString());
319
+ if (params?.page_size) queryParams.set("page_size", params.page_size.toString());
320
+ const response = await fetch(`${config.backendUrls.store}/orders/?${queryParams.toString()}`, {
321
+ headers: {
322
+ "Authorization": `Bearer ${accessToken}`,
323
+ "X-Storefront-Key": config.storefrontApiKey,
324
+ "X-Business-ID": config.businessId
325
+ }
326
+ });
327
+ if (!response.ok) throw new Error("Failed to get orders");
328
+ const data = await response.json();
329
+ const items = Array.isArray(data) ? data : data.items ?? [];
330
+ return items.map(normaliseStorefrontOrder);
331
+ }
332
+ async function cancelOrder(config, accessToken, orderId, reason) {
333
+ const response = await fetch(`${config.backendUrls.store}/orders/${orderId}/cancel/`, {
334
+ method: "POST",
335
+ headers: {
336
+ "Content-Type": "application/json",
337
+ "Authorization": `Bearer ${accessToken}`,
338
+ "X-Storefront-Key": config.storefrontApiKey,
339
+ "X-Business-ID": config.businessId
340
+ },
341
+ body: JSON.stringify({ reason })
342
+ });
343
+ if (!response.ok) throw new Error("Failed to cancel order");
344
+ const data = await response.json();
345
+ return normaliseStorefrontOrder(data);
346
+ }
347
+ async function trackOrder(config, orderId, token) {
348
+ const queryParams = token ? `?token=${token}` : "";
349
+ const response = await fetch(`${config.backendUrls.store}/orders/track/${orderId}${queryParams}`, {
350
+ headers: {
351
+ "X-Storefront-Key": config.storefrontApiKey,
352
+ "X-Business-ID": config.businessId
353
+ }
354
+ });
355
+ if (!response.ok) throw new Error("Failed to track order");
356
+ const data = await response.json();
357
+ return normaliseStorefrontOrder(data);
358
+ }
359
+
360
+ // src/constants.ts
361
+ var STORAGE_KEYS = {
362
+ ACCESS_TOKEN: "kasuvia_access_token",
363
+ REFRESH_TOKEN: "kasuvia_refresh_token",
364
+ CHECKOUT_STATE: "kasuvia_checkout_state",
365
+ ORDERS_LINKED: "kasuvia_orders_linked",
366
+ STOREFRONT_STATE: "storefront_state_v3"
367
+ };
368
+
369
+ // src/services/auth.service.ts
370
+ async function loginCustomer(config, payload) {
371
+ const response = await fetch(`${config.backendUrls.auth}/auth/login/customer/`, {
372
+ method: "POST",
373
+ headers: {
374
+ "Content-Type": "application/json",
375
+ "X-Storefront-Key": config.storefrontApiKey,
376
+ "X-Business-ID": config.businessId
377
+ },
378
+ body: JSON.stringify({
379
+ ...payload,
380
+ tenant_id: config.businessId
381
+ })
382
+ });
383
+ if (!response.ok) {
384
+ throw new Error("Login failed");
385
+ }
386
+ const data = await response.json();
387
+ return data;
388
+ }
389
+ async function registerCustomer(config, payload) {
390
+ const response = await fetch(`${config.backendUrls.auth}/auth/register/customer/`, {
391
+ method: "POST",
392
+ headers: {
393
+ "Content-Type": "application/json",
394
+ "X-Storefront-Key": config.storefrontApiKey,
395
+ "X-Business-ID": config.businessId
396
+ },
397
+ body: JSON.stringify({
398
+ ...payload,
399
+ tenant_id: config.businessId
400
+ })
401
+ });
402
+ if (!response.ok) {
403
+ throw new Error("Registration failed");
404
+ }
405
+ const data = await response.json();
406
+ return data;
407
+ }
408
+ async function refreshToken(config, refresh) {
409
+ const response = await fetch(`${config.backendUrls.auth}/auth/token/refresh/`, {
410
+ method: "POST",
411
+ headers: {
412
+ "Content-Type": "application/json"
413
+ },
414
+ body: JSON.stringify({ refresh })
415
+ });
416
+ if (!response.ok) {
417
+ throw new Error("Token refresh failed");
418
+ }
419
+ const data = await response.json();
420
+ return data;
421
+ }
422
+ async function logout(config, refresh) {
423
+ const payload = refresh ? { refresh } : {};
424
+ try {
425
+ await fetch(`${config.backendUrls.auth}/auth/logout/`, {
426
+ method: "POST",
427
+ headers: {
428
+ "Content-Type": "application/json"
429
+ },
430
+ body: JSON.stringify(payload)
431
+ });
432
+ } catch {
433
+ }
434
+ }
435
+ async function verifySocialToken(config, provider, token) {
436
+ const response = await fetch(`${config.backendUrls.auth}/auth/social/verify/${provider}/`, {
437
+ method: "POST",
438
+ headers: {
439
+ "Content-Type": "application/json"
440
+ },
441
+ body: JSON.stringify({
442
+ id_token: token,
443
+ storefront_key: config.storefrontApiKey
444
+ })
445
+ });
446
+ if (!response.ok) {
447
+ throw new Error("Social token verification failed");
448
+ }
449
+ const data = await response.json();
450
+ return data;
451
+ }
452
+ function parseJwtPayload(token) {
453
+ try {
454
+ return JSON.parse(atob(token.split(".")[1].replace(/-/g, "+").replace(/_/g, "/")));
455
+ } catch {
456
+ return {};
457
+ }
458
+ }
459
+ function resolveProvider(data) {
460
+ if (data.is_google_auth_enabled) return "google";
461
+ if (data.is_facebook_auth_enabled) return "facebook";
462
+ return "email";
463
+ }
464
+ function resolveAvatar(profilePicture) {
465
+ if (!profilePicture) return null;
466
+ if (typeof profilePicture === "string") return profilePicture;
467
+ if (typeof profilePicture === "object" && profilePicture !== null && "url" in profilePicture) {
468
+ const url = profilePicture.url;
469
+ return typeof url === "string" ? url : null;
470
+ }
471
+ return null;
472
+ }
473
+ function mapAuthUserToCustomer(data, provider) {
474
+ const firstname = data.profile?.firstname?.trim() || void 0;
475
+ const lastname = data.profile?.lastname?.trim() || void 0;
476
+ const phone = data.profile?.phone?.trim() || void 0;
477
+ return {
478
+ id: String(data.id),
479
+ email: data.email,
480
+ firstname,
481
+ lastname,
482
+ phone,
483
+ full_name: buildFullName(firstname, lastname),
484
+ avatar: resolveAvatar(data.profile?.profile_picture),
485
+ provider: provider ?? resolveProvider(data)
486
+ };
487
+ }
488
+ function buildCustomerFromClaims(claims) {
489
+ const provider = claims.is_google_auth_enabled ? "google" : claims.is_facebook_auth_enabled ? "facebook" : "email";
490
+ const jwtFullName = String(claims.full_name ?? claims.name ?? "").trim() || void 0;
491
+ const { firstname: splitFirst, lastname: splitLast } = splitFullName(jwtFullName);
492
+ return {
493
+ id: String(claims.user_id ?? claims.sub ?? ""),
494
+ email: String(claims.email ?? ""),
495
+ firstname: splitFirst || void 0,
496
+ lastname: splitLast || void 0,
497
+ phone: String(claims.phone ?? "").trim() || void 0,
498
+ full_name: jwtFullName,
499
+ avatar: claims.avatar,
500
+ provider
501
+ };
502
+ }
503
+ async function getMe(config, accessToken) {
504
+ if (!config || !accessToken) {
505
+ const response2 = await fetch("/api/auth/me", { credentials: "include" });
506
+ if (!response2.ok) throw new Error("Failed to fetch profile");
507
+ const data2 = await response2.json();
508
+ return data2.user;
509
+ }
510
+ const response = await fetch(`${config.backendUrls.auth}/auth/profile/`, {
511
+ headers: {
512
+ "Authorization": `Bearer ${accessToken}`
513
+ }
514
+ });
515
+ if (!response.ok) {
516
+ throw new Error("Failed to fetch profile");
517
+ }
518
+ const data = await response.json();
519
+ return mapAuthUserToCustomer(data);
520
+ }
521
+ async function getAuthUser(config, accessToken) {
522
+ if (!config || !accessToken) {
523
+ const response2 = await fetch("/api/auth/me", { credentials: "include" });
524
+ if (!response2.ok) throw new Error("Failed to fetch auth user");
525
+ const data2 = await response2.json();
526
+ return data2.user;
527
+ }
528
+ const response = await fetch(`${config.backendUrls.auth}/auth/profile/`, {
529
+ headers: {
530
+ "Authorization": `Bearer ${accessToken}`
531
+ }
532
+ });
533
+ if (!response.ok) {
534
+ throw new Error("Failed to fetch auth user");
535
+ }
536
+ const data = await response.json();
537
+ return data;
538
+ }
539
+ async function updateProfile(configOrPayload, accessTokenOrPayload, payloadParam) {
540
+ const isArg1Config = typeof configOrPayload === "object" && configOrPayload !== null && "businessId" in configOrPayload;
541
+ if (!isArg1Config) {
542
+ const payload2 = configOrPayload;
543
+ const response2 = await fetch("/api/auth/profile", {
544
+ method: "PUT",
545
+ headers: { "Content-Type": "application/json" },
546
+ credentials: "include",
547
+ body: JSON.stringify(payload2)
548
+ });
549
+ if (!response2.ok) throw new Error("Failed to update profile");
550
+ return response2.json();
551
+ }
552
+ const config = configOrPayload;
553
+ const accessToken = accessTokenOrPayload;
554
+ const payload = payloadParam;
555
+ const response = await fetch(`${config.backendUrls.auth}/auth/profile/`, {
556
+ method: "PUT",
557
+ headers: {
558
+ "Content-Type": "application/json",
559
+ "Authorization": `Bearer ${accessToken}`
560
+ },
561
+ body: JSON.stringify(payload)
562
+ });
563
+ if (!response.ok) {
564
+ throw new Error("Failed to update profile");
565
+ }
566
+ const data = await response.json();
567
+ return mapAuthUserToCustomer(data);
568
+ }
569
+ async function silentRefresh(config, refresh) {
570
+ try {
571
+ const data = await refreshToken(config, refresh);
572
+ if (!data.access || !data.refresh) {
573
+ return null;
574
+ }
575
+ const claims = parseJwtPayload(data.access);
576
+ const user = buildCustomerFromClaims(claims);
577
+ const provider = user.provider;
578
+ return { user, provider, newAccessToken: data.access, newRefreshToken: data.refresh };
579
+ } catch {
580
+ return null;
581
+ }
582
+ }
583
+ function buildFullName(firstname, lastname) {
584
+ if (firstname && lastname) return `${firstname} ${lastname}`;
585
+ return firstname || lastname || "";
586
+ }
587
+ function splitFullName(fullName) {
588
+ if (!fullName) return { firstname: "", lastname: "" };
589
+ const parts = fullName.trim().split(/\s+/);
590
+ if (parts.length === 1) {
591
+ return { firstname: parts[0], lastname: "" };
592
+ }
593
+ return {
594
+ firstname: parts[0],
595
+ lastname: parts.slice(1).join(" ")
596
+ };
597
+ }
598
+ function storeTokens(accessToken, refreshToken2) {
599
+ if (typeof window !== "undefined") {
600
+ localStorage.setItem(STORAGE_KEYS.ACCESS_TOKEN, accessToken);
601
+ localStorage.setItem(STORAGE_KEYS.REFRESH_TOKEN, refreshToken2);
602
+ }
603
+ }
604
+ function clearTokens() {
605
+ if (typeof window !== "undefined") {
606
+ localStorage.removeItem(STORAGE_KEYS.ACCESS_TOKEN);
607
+ localStorage.removeItem(STORAGE_KEYS.REFRESH_TOKEN);
608
+ }
609
+ }
610
+ function getStoredTokens() {
611
+ if (typeof window === "undefined") {
612
+ return { accessToken: null, refreshToken: null };
613
+ }
614
+ return {
615
+ accessToken: localStorage.getItem(STORAGE_KEYS.ACCESS_TOKEN),
616
+ refreshToken: localStorage.getItem(STORAGE_KEYS.REFRESH_TOKEN)
617
+ };
618
+ }
619
+
620
+ // src/services/product.service.ts
621
+ import { GraphQLClient } from "graphql-request";
622
+ function createGraphQLClient(config) {
623
+ const headers = {
624
+ "Content-Type": "application/json",
625
+ "Accept": "application/json",
626
+ "X-Storefront-Key": config.storefrontApiKey,
627
+ "X-Business-ID": config.businessId
628
+ };
629
+ return new GraphQLClient(`${config.backendUrls.store}/graphql`, { headers });
630
+ }
631
+ var GET_STOREFRONT_PRODUCTS = `
632
+ query GetStorefrontProducts($page: Int!, $pageSize: Int!, $collectionSlug: String, $search: String) {
633
+ storefront_products(page: $page, pageSize: $pageSize, collectionSlug: $collectionSlug, search: $search) {
634
+ items {
635
+ id
636
+ business_id
637
+ name
638
+ slug
639
+ description
640
+ brand
641
+ product_type
642
+ requires_shipping
643
+ is_consumable
644
+ is_bespoke
645
+ base_price
646
+ currency
647
+ images
648
+ tags
649
+ custom_fields { label unit required }
650
+ is_published
651
+ is_featured
652
+ is_popular
653
+ is_new
654
+ is_temporary
655
+ digital_file_key
656
+ download_limit
657
+ download_expires_at
658
+ weight_kg
659
+ length_cm
660
+ width_cm
661
+ height_cm
662
+ created_at
663
+ updated_at
664
+ variants {
665
+ id
666
+ product_id
667
+ sku
668
+ attributes
669
+ price
670
+ images
671
+ weight_kg
672
+ is_active
673
+ inventory {
674
+ id
675
+ product_id
676
+ variant_id
677
+ quantity
678
+ reserved
679
+ reorder_point
680
+ reorder_quantity
681
+ track_quantity
682
+ allow_backorder
683
+ available
684
+ is_in_stock
685
+ is_low_stock
686
+ updated_at
687
+ }
688
+ created_at
689
+ updated_at
690
+ }
691
+ collections {
692
+ id
693
+ business_id
694
+ name
695
+ slug
696
+ description
697
+ image
698
+ collection_type
699
+ rules
700
+ status
701
+ sort_order
702
+ created_at
703
+ updated_at
704
+ }
705
+ }
706
+ total
707
+ page
708
+ page_size
709
+ total_pages
710
+ }
711
+ }
712
+ `;
713
+ var GET_STOREFRONT_PRODUCT_BY_SLUG = `
714
+ query GetStorefrontProductBySlug($slug: String!) {
715
+ storefront_product_by_slug(slug: $slug) {
716
+ id
717
+ business_id
718
+ name
719
+ slug
720
+ description
721
+ brand
722
+ product_type
723
+ requires_shipping
724
+ is_consumable
725
+ is_bespoke
726
+ base_price
727
+ currency
728
+ images
729
+ tags
730
+ custom_fields { label unit required }
731
+ is_published
732
+ is_featured
733
+ is_popular
734
+ is_new
735
+ is_temporary
736
+ digital_file_key
737
+ download_limit
738
+ download_expires_at
739
+ weight_kg
740
+ length_cm
741
+ width_cm
742
+ height_cm
743
+ created_at
744
+ updated_at
745
+ variants {
746
+ id
747
+ product_id
748
+ sku
749
+ attributes
750
+ price
751
+ images
752
+ weight_kg
753
+ is_active
754
+ inventory {
755
+ id
756
+ product_id
757
+ variant_id
758
+ quantity
759
+ reserved
760
+ reorder_point
761
+ reorder_quantity
762
+ track_quantity
763
+ allow_backorder
764
+ available
765
+ is_in_stock
766
+ is_low_stock
767
+ updated_at
768
+ }
769
+ created_at
770
+ updated_at
771
+ }
772
+ collections {
773
+ id
774
+ business_id
775
+ name
776
+ slug
777
+ description
778
+ image
779
+ collection_type
780
+ rules
781
+ status
782
+ sort_order
783
+ created_at
784
+ updated_at
785
+ }
786
+ }
787
+ }
788
+ `;
789
+ var GET_STOREFRONT_LATEST = `
790
+ query GetStorefrontLatest($page: Int!, $pageSize: Int!) {
791
+ storefront_latest(page: $page, pageSize: $pageSize) {
792
+ items {
793
+ id
794
+ business_id
795
+ name
796
+ slug
797
+ description
798
+ brand
799
+ product_type
800
+ requires_shipping
801
+ is_consumable
802
+ is_bespoke
803
+ base_price
804
+ currency
805
+ images
806
+ tags
807
+ custom_fields { label unit required }
808
+ is_published
809
+ is_featured
810
+ is_popular
811
+ is_new
812
+ is_temporary
813
+ digital_file_key
814
+ download_limit
815
+ download_expires_at
816
+ weight_kg
817
+ length_cm
818
+ width_cm
819
+ height_cm
820
+ created_at
821
+ updated_at
822
+ variants {
823
+ id
824
+ product_id
825
+ sku
826
+ attributes
827
+ price
828
+ images
829
+ weight_kg
830
+ is_active
831
+ inventory {
832
+ id
833
+ product_id
834
+ variant_id
835
+ quantity
836
+ reserved
837
+ reorder_point
838
+ reorder_quantity
839
+ track_quantity
840
+ allow_backorder
841
+ available
842
+ is_in_stock
843
+ is_low_stock
844
+ updated_at
845
+ }
846
+ created_at
847
+ updated_at
848
+ }
849
+ collections {
850
+ id
851
+ business_id
852
+ name
853
+ slug
854
+ description
855
+ image
856
+ collection_type
857
+ rules
858
+ status
859
+ sort_order
860
+ created_at
861
+ updated_at
862
+ }
863
+ }
864
+ total
865
+ page
866
+ page_size
867
+ total_pages
868
+ }
869
+ }
870
+ `;
871
+ var GET_STOREFRONT_POPULAR = `
872
+ query GetStorefrontPopular($page: Int!, $pageSize: Int!) {
873
+ storefront_popular(page: $page, pageSize: $pageSize) {
874
+ items {
875
+ id
876
+ business_id
877
+ name
878
+ slug
879
+ description
880
+ brand
881
+ product_type
882
+ requires_shipping
883
+ is_consumable
884
+ is_bespoke
885
+ base_price
886
+ currency
887
+ images
888
+ tags
889
+ custom_fields { label unit required }
890
+ is_published
891
+ is_featured
892
+ is_popular
893
+ is_new
894
+ is_temporary
895
+ digital_file_key
896
+ download_limit
897
+ download_expires_at
898
+ weight_kg
899
+ length_cm
900
+ width_cm
901
+ height_cm
902
+ created_at
903
+ updated_at
904
+ variants {
905
+ id
906
+ product_id
907
+ sku
908
+ attributes
909
+ price
910
+ images
911
+ weight_kg
912
+ is_active
913
+ inventory {
914
+ id
915
+ product_id
916
+ variant_id
917
+ quantity
918
+ reserved
919
+ reorder_point
920
+ reorder_quantity
921
+ track_quantity
922
+ allow_backorder
923
+ available
924
+ is_in_stock
925
+ is_low_stock
926
+ updated_at
927
+ }
928
+ created_at
929
+ updated_at
930
+ }
931
+ collections {
932
+ id
933
+ business_id
934
+ name
935
+ slug
936
+ description
937
+ image
938
+ collection_type
939
+ rules
940
+ status
941
+ sort_order
942
+ created_at
943
+ updated_at
944
+ }
945
+ }
946
+ total
947
+ page
948
+ page_size
949
+ total_pages
950
+ }
951
+ }
952
+ `;
953
+ var GET_STOREFRONT_FEATURED = `
954
+ query GetStorefrontFeatured($page: Int!, $pageSize: Int!) {
955
+ storefront_featured(page: $page, pageSize: $pageSize) {
956
+ items {
957
+ id
958
+ business_id
959
+ name
960
+ slug
961
+ description
962
+ brand
963
+ product_type
964
+ requires_shipping
965
+ is_consumable
966
+ is_bespoke
967
+ base_price
968
+ currency
969
+ images
970
+ tags
971
+ custom_fields { label unit required }
972
+ is_published
973
+ is_featured
974
+ is_popular
975
+ is_new
976
+ is_temporary
977
+ digital_file_key
978
+ download_limit
979
+ download_expires_at
980
+ weight_kg
981
+ length_cm
982
+ width_cm
983
+ height_cm
984
+ created_at
985
+ updated_at
986
+ variants {
987
+ id
988
+ product_id
989
+ sku
990
+ attributes
991
+ price
992
+ images
993
+ weight_kg
994
+ is_active
995
+ inventory {
996
+ id
997
+ product_id
998
+ variant_id
999
+ quantity
1000
+ reserved
1001
+ reorder_point
1002
+ reorder_quantity
1003
+ track_quantity
1004
+ allow_backorder
1005
+ available
1006
+ is_in_stock
1007
+ is_low_stock
1008
+ updated_at
1009
+ }
1010
+ created_at
1011
+ updated_at
1012
+ }
1013
+ collections {
1014
+ id
1015
+ business_id
1016
+ name
1017
+ slug
1018
+ description
1019
+ image
1020
+ collection_type
1021
+ rules
1022
+ status
1023
+ sort_order
1024
+ created_at
1025
+ updated_at
1026
+ }
1027
+ }
1028
+ total
1029
+ page
1030
+ page_size
1031
+ total_pages
1032
+ }
1033
+ }
1034
+ `;
1035
+ var GET_STOREFRONT_NEW = `
1036
+ query GetStorefrontNew($page: Int!, $pageSize: Int!) {
1037
+ storefront_new(page: $page, pageSize: $pageSize) {
1038
+ items {
1039
+ id
1040
+ business_id
1041
+ name
1042
+ slug
1043
+ description
1044
+ brand
1045
+ product_type
1046
+ requires_shipping
1047
+ is_consumable
1048
+ is_bespoke
1049
+ base_price
1050
+ currency
1051
+ sale_price
1052
+ sale_start
1053
+ sale_end
1054
+ images
1055
+ tags
1056
+ custom_fields { label unit required }
1057
+ is_published
1058
+ is_featured
1059
+ is_popular
1060
+ is_new
1061
+ is_temporary
1062
+ digital_file_key
1063
+ download_limit
1064
+ download_expires_at
1065
+ weight_kg
1066
+ length_cm
1067
+ width_cm
1068
+ height_cm
1069
+ created_at
1070
+ updated_at
1071
+ variants {
1072
+ id
1073
+ product_id
1074
+ sku
1075
+ attributes
1076
+ price
1077
+ images
1078
+ weight_kg
1079
+ is_active
1080
+ inventory {
1081
+ id
1082
+ product_id
1083
+ variant_id
1084
+ quantity
1085
+ reserved
1086
+ reorder_point
1087
+ reorder_quantity
1088
+ track_quantity
1089
+ allow_backorder
1090
+ available
1091
+ is_in_stock
1092
+ is_low_stock
1093
+ updated_at
1094
+ }
1095
+ created_at
1096
+ updated_at
1097
+ }
1098
+ collections {
1099
+ id
1100
+ business_id
1101
+ name
1102
+ slug
1103
+ description
1104
+ image
1105
+ collection_type
1106
+ rules
1107
+ status
1108
+ sort_order
1109
+ created_at
1110
+ updated_at
1111
+ }
1112
+ }
1113
+ total
1114
+ page
1115
+ page_size
1116
+ total_pages
1117
+ }
1118
+ }
1119
+ `;
1120
+ var GET_STOREFRONT_ON_SALE = `
1121
+ query GetStorefrontOnSale($page: Int!, $pageSize: Int!) {
1122
+ storefront_on_sale(page: $page, pageSize: $pageSize) {
1123
+ items {
1124
+ id
1125
+ business_id
1126
+ name
1127
+ slug
1128
+ description
1129
+ brand
1130
+ product_type
1131
+ requires_shipping
1132
+ is_consumable
1133
+ is_bespoke
1134
+ base_price
1135
+ currency
1136
+ sale_price
1137
+ sale_start
1138
+ sale_end
1139
+ images
1140
+ tags
1141
+ custom_fields { label unit required }
1142
+ is_published
1143
+ is_featured
1144
+ is_popular
1145
+ is_new
1146
+ is_temporary
1147
+ digital_file_key
1148
+ download_limit
1149
+ download_expires_at
1150
+ weight_kg
1151
+ length_cm
1152
+ width_cm
1153
+ height_cm
1154
+ created_at
1155
+ updated_at
1156
+ variants {
1157
+ id
1158
+ product_id
1159
+ sku
1160
+ attributes
1161
+ price
1162
+ images
1163
+ weight_kg
1164
+ is_active
1165
+ inventory {
1166
+ id
1167
+ product_id
1168
+ variant_id
1169
+ quantity
1170
+ reserved
1171
+ reorder_point
1172
+ reorder_quantity
1173
+ track_quantity
1174
+ allow_backorder
1175
+ available
1176
+ is_in_stock
1177
+ is_low_stock
1178
+ updated_at
1179
+ }
1180
+ created_at
1181
+ updated_at
1182
+ }
1183
+ collections {
1184
+ id
1185
+ business_id
1186
+ name
1187
+ slug
1188
+ description
1189
+ image
1190
+ collection_type
1191
+ rules
1192
+ status
1193
+ sort_order
1194
+ created_at
1195
+ updated_at
1196
+ }
1197
+ }
1198
+ total
1199
+ page
1200
+ page_size
1201
+ total_pages
1202
+ }
1203
+ }
1204
+ `;
1205
+ var GET_STOREFRONT_LOW_STOCK = `
1206
+ query GetStorefrontLowStock($page: Int!, $pageSize: Int!) {
1207
+ storefront_low_stock(page: $page, pageSize: $pageSize) {
1208
+ items {
1209
+ id
1210
+ business_id
1211
+ name
1212
+ slug
1213
+ description
1214
+ brand
1215
+ product_type
1216
+ requires_shipping
1217
+ is_consumable
1218
+ is_bespoke
1219
+ base_price
1220
+ currency
1221
+ sale_price
1222
+ sale_start
1223
+ sale_end
1224
+ images
1225
+ tags
1226
+ custom_fields { label unit required }
1227
+ is_published
1228
+ is_featured
1229
+ is_popular
1230
+ is_new
1231
+ is_temporary
1232
+ digital_file_key
1233
+ download_limit
1234
+ download_expires_at
1235
+ weight_kg
1236
+ length_cm
1237
+ width_cm
1238
+ height_cm
1239
+ created_at
1240
+ updated_at
1241
+ variants {
1242
+ id
1243
+ product_id
1244
+ sku
1245
+ attributes
1246
+ price
1247
+ images
1248
+ weight_kg
1249
+ is_active
1250
+ inventory {
1251
+ id
1252
+ product_id
1253
+ variant_id
1254
+ quantity
1255
+ reserved
1256
+ reorder_point
1257
+ reorder_quantity
1258
+ track_quantity
1259
+ allow_backorder
1260
+ available
1261
+ is_in_stock
1262
+ is_low_stock
1263
+ updated_at
1264
+ }
1265
+ created_at
1266
+ updated_at
1267
+ }
1268
+ collections {
1269
+ id
1270
+ business_id
1271
+ name
1272
+ slug
1273
+ description
1274
+ image
1275
+ collection_type
1276
+ rules
1277
+ status
1278
+ sort_order
1279
+ created_at
1280
+ updated_at
1281
+ }
1282
+ }
1283
+ total
1284
+ page
1285
+ page_size
1286
+ total_pages
1287
+ }
1288
+ }
1289
+ `;
1290
+ var GET_STOREFRONT_RECOMMENDED = `
1291
+ query GetStorefrontRecommended($page: Int!, $pageSize: Int!, $excludeProductId: String) {
1292
+ storefront_recommended(page: $page, pageSize: $pageSize, excludeProductId: $excludeProductId) {
1293
+ items {
1294
+ id
1295
+ business_id
1296
+ name
1297
+ slug
1298
+ description
1299
+ brand
1300
+ product_type
1301
+ requires_shipping
1302
+ is_consumable
1303
+ is_bespoke
1304
+ base_price
1305
+ currency
1306
+ images
1307
+ tags
1308
+ custom_fields { label unit required }
1309
+ is_published
1310
+ is_featured
1311
+ is_popular
1312
+ is_new
1313
+ is_temporary
1314
+ digital_file_key
1315
+ download_limit
1316
+ download_expires_at
1317
+ weight_kg
1318
+ length_cm
1319
+ width_cm
1320
+ height_cm
1321
+ created_at
1322
+ updated_at
1323
+ variants {
1324
+ id
1325
+ product_id
1326
+ sku
1327
+ attributes
1328
+ price
1329
+ images
1330
+ weight_kg
1331
+ is_active
1332
+ inventory {
1333
+ id
1334
+ product_id
1335
+ variant_id
1336
+ quantity
1337
+ reserved
1338
+ reorder_point
1339
+ reorder_quantity
1340
+ track_quantity
1341
+ allow_backorder
1342
+ available
1343
+ is_in_stock
1344
+ is_low_stock
1345
+ updated_at
1346
+ }
1347
+ created_at
1348
+ updated_at
1349
+ }
1350
+ collections {
1351
+ id
1352
+ business_id
1353
+ name
1354
+ slug
1355
+ description
1356
+ image
1357
+ collection_type
1358
+ rules
1359
+ status
1360
+ sort_order
1361
+ created_at
1362
+ updated_at
1363
+ }
1364
+ }
1365
+ total
1366
+ page
1367
+ page_size
1368
+ total_pages
1369
+ }
1370
+ }
1371
+ `;
1372
+ async function getStorefrontProducts(config, params) {
1373
+ const client = createGraphQLClient(config);
1374
+ const variables = {
1375
+ page: params?.page || 1,
1376
+ pageSize: params?.pageSize || 20,
1377
+ collectionSlug: params?.collectionSlug,
1378
+ search: params?.search
1379
+ };
1380
+ const data = await client.request(GET_STOREFRONT_PRODUCTS, variables);
1381
+ return data.storefront_products;
1382
+ }
1383
+ async function getStorefrontProductBySlug(config, slug) {
1384
+ const client = createGraphQLClient(config);
1385
+ const data = await client.request(GET_STOREFRONT_PRODUCT_BY_SLUG, { slug });
1386
+ return data.storefront_product_by_slug;
1387
+ }
1388
+ async function getLatestProducts(config, params) {
1389
+ const client = createGraphQLClient(config);
1390
+ const variables = {
1391
+ page: params?.page || 1,
1392
+ pageSize: params?.pageSize || 4
1393
+ };
1394
+ const data = await client.request(GET_STOREFRONT_LATEST, variables);
1395
+ return data.storefront_latest;
1396
+ }
1397
+ async function getPopularProducts(config, params) {
1398
+ const client = createGraphQLClient(config);
1399
+ const variables = {
1400
+ page: params?.page || 1,
1401
+ pageSize: params?.pageSize || 4
1402
+ };
1403
+ const data = await client.request(GET_STOREFRONT_POPULAR, variables);
1404
+ return data.storefront_popular;
1405
+ }
1406
+ async function getFeaturedProducts(config, params) {
1407
+ const client = createGraphQLClient(config);
1408
+ const variables = {
1409
+ page: params?.page || 1,
1410
+ pageSize: params?.pageSize || 4
1411
+ };
1412
+ const data = await client.request(GET_STOREFRONT_FEATURED, variables);
1413
+ return data.storefront_featured;
1414
+ }
1415
+ async function getNewProducts(config, params) {
1416
+ const client = createGraphQLClient(config);
1417
+ const variables = {
1418
+ page: params?.page || 1,
1419
+ pageSize: params?.pageSize || 4
1420
+ };
1421
+ const data = await client.request(GET_STOREFRONT_NEW, variables);
1422
+ return data.storefront_new;
1423
+ }
1424
+ async function getOnSaleProducts(config, params) {
1425
+ const client = createGraphQLClient(config);
1426
+ const variables = {
1427
+ page: params?.page || 1,
1428
+ pageSize: params?.pageSize || 4
1429
+ };
1430
+ const data = await client.request(GET_STOREFRONT_ON_SALE, variables);
1431
+ return data.storefront_on_sale;
1432
+ }
1433
+ async function getLowStockProducts(config, params) {
1434
+ const client = createGraphQLClient(config);
1435
+ const variables = {
1436
+ page: params?.page || 1,
1437
+ pageSize: params?.pageSize || 4
1438
+ };
1439
+ const data = await client.request(GET_STOREFRONT_LOW_STOCK, variables);
1440
+ return data.storefront_low_stock;
1441
+ }
1442
+ async function getRecommendedProducts(config, params) {
1443
+ const client = createGraphQLClient(config);
1444
+ const variables = {
1445
+ page: params?.page || 1,
1446
+ pageSize: params?.pageSize || 4,
1447
+ excludeProductId: params?.excludeProductId
1448
+ };
1449
+ const data = await client.request(GET_STOREFRONT_RECOMMENDED, variables);
1450
+ return data.storefront_recommended;
1451
+ }
1452
+
1453
+ // src/services/collection.service.ts
1454
+ import { GraphQLClient as GraphQLClient2 } from "graphql-request";
1455
+ var GET_STOREFRONT_COLLECTIONS = `
1456
+ query GetStorefrontCollections($page: Int!, $pageSize: Int!) {
1457
+ storefront_collections(page: $page, pageSize: $pageSize) {
1458
+ items {
1459
+ id
1460
+ business_id
1461
+ name
1462
+ slug
1463
+ description
1464
+ image
1465
+ collection_type
1466
+ rules
1467
+ status
1468
+ sort_order
1469
+ created_at
1470
+ updated_at
1471
+ }
1472
+ total
1473
+ page
1474
+ page_size
1475
+ total_pages
1476
+ }
1477
+ }
1478
+ `;
1479
+ var GET_STOREFRONT_COLLECTION_BY_SLUG = `
1480
+ query GetStorefrontCollectionBySlug($slug: String!) {
1481
+ storefront_collection_by_slug(slug: $slug) {
1482
+ id
1483
+ business_id
1484
+ name
1485
+ slug
1486
+ description
1487
+ image
1488
+ collection_type
1489
+ rules
1490
+ status
1491
+ sort_order
1492
+ created_at
1493
+ updated_at
1494
+ }
1495
+ }
1496
+ `;
1497
+ function createGraphQLClient2(config) {
1498
+ const headers = {
1499
+ "Content-Type": "application/json",
1500
+ "Accept": "application/json",
1501
+ "X-Storefront-Key": config.storefrontApiKey,
1502
+ "X-Business-ID": config.businessId
1503
+ };
1504
+ return new GraphQLClient2(`${config.backendUrls.store}/graphql`, { headers });
1505
+ }
1506
+ async function getStorefrontCollections(config, params) {
1507
+ const client = createGraphQLClient2(config);
1508
+ const variables = {
1509
+ page: params?.page || 1,
1510
+ pageSize: params?.pageSize || 20
1511
+ };
1512
+ const data = await client.request(GET_STOREFRONT_COLLECTIONS, variables);
1513
+ return data.storefront_collections;
1514
+ }
1515
+ async function getStorefrontCollectionBySlug(config, slug) {
1516
+ const client = createGraphQLClient2(config);
1517
+ const data = await client.request(GET_STOREFRONT_COLLECTION_BY_SLUG, { slug });
1518
+ return data.storefront_collection_by_slug;
1519
+ }
1520
+
1521
+ // src/services/wishlist.service.ts
1522
+ import { GraphQLClient as GraphQLClient3 } from "graphql-request";
1523
+ var GET_STOREFRONT_WISHLIST = `
1524
+ query GetStorefrontWishlist($page: Int!, $pageSize: Int!) {
1525
+ storefront_wishlist(page: $page, pageSize: $pageSize) {
1526
+ items {
1527
+ id
1528
+ product_id
1529
+ notes
1530
+ created_at
1531
+ product_name
1532
+ product_slug
1533
+ product_price
1534
+ currency
1535
+ product_image
1536
+ }
1537
+ total
1538
+ page
1539
+ page_size
1540
+ total_pages
1541
+ }
1542
+ }
1543
+ `;
1544
+ var CHECK_IN_STOREFRONT_WISHLIST = `
1545
+ query CheckInStorefrontWishlist($productId: String!) {
1546
+ check_in_storefront_wishlist(productId: $productId) {
1547
+ in_wishlist
1548
+ }
1549
+ }
1550
+ `;
1551
+ function createGraphQLClient3(config, accessToken) {
1552
+ const headers = {
1553
+ "Content-Type": "application/json",
1554
+ "Accept": "application/json",
1555
+ "X-Storefront-Key": config.storefrontApiKey,
1556
+ "X-Business-ID": config.businessId
1557
+ };
1558
+ if (accessToken) {
1559
+ headers["Authorization"] = `Bearer ${accessToken}`;
1560
+ }
1561
+ return new GraphQLClient3(`${config.backendUrls.store}/graphql`, { headers });
1562
+ }
1563
+ async function getWishlist(config, accessToken, params) {
1564
+ const client = createGraphQLClient3(config, accessToken);
1565
+ const variables = {
1566
+ page: params?.page || 1,
1567
+ pageSize: params?.pageSize || 20
1568
+ };
1569
+ const data = await client.request(GET_STOREFRONT_WISHLIST, variables);
1570
+ return data.storefront_wishlist;
1571
+ }
1572
+ async function checkInWishlist(config, accessToken, productId) {
1573
+ const client = createGraphQLClient3(config, accessToken);
1574
+ const data = await client.request(CHECK_IN_STOREFRONT_WISHLIST, { productId });
1575
+ return data.check_in_storefront_wishlist;
1576
+ }
1577
+ async function addToWishlist(config, accessToken, productId, notes) {
1578
+ const response = await fetch(`${config.backendUrls.store}/wishlist/`, {
1579
+ method: "POST",
1580
+ headers: {
1581
+ "Content-Type": "application/json",
1582
+ "Authorization": `Bearer ${accessToken}`,
1583
+ "X-Storefront-Key": config.storefrontApiKey,
1584
+ "X-Business-ID": config.businessId
1585
+ },
1586
+ body: JSON.stringify({
1587
+ product_id: productId,
1588
+ notes: notes || void 0
1589
+ })
1590
+ });
1591
+ if (!response.ok) throw new Error("Failed to add to wishlist");
1592
+ return response.json();
1593
+ }
1594
+ async function removeFromWishlist(config, accessToken, itemId) {
1595
+ const response = await fetch(`${config.backendUrls.store}/wishlist/${itemId}`, {
1596
+ method: "DELETE",
1597
+ headers: {
1598
+ "Authorization": `Bearer ${accessToken}`,
1599
+ "X-Storefront-Key": config.storefrontApiKey,
1600
+ "X-Business-ID": config.businessId
1601
+ }
1602
+ });
1603
+ if (!response.ok) throw new Error("Failed to remove from wishlist");
1604
+ }
1605
+ async function removeProductFromWishlist(config, accessToken, productId) {
1606
+ const response = await fetch(`${config.backendUrls.store}/wishlist/product/${productId}`, {
1607
+ method: "DELETE",
1608
+ headers: {
1609
+ "Authorization": `Bearer ${accessToken}`,
1610
+ "X-Storefront-Key": config.storefrontApiKey,
1611
+ "X-Business-ID": config.businessId
1612
+ }
1613
+ });
1614
+ if (!response.ok) throw new Error("Failed to remove product from wishlist");
1615
+ }
1616
+
1617
+ // src/services/payment.service.ts
1618
+ async function createDedicatedAccount(config, accessToken, request) {
1619
+ const isValidUUID = (str) => {
1620
+ const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
1621
+ return uuidRegex.test(str);
1622
+ };
1623
+ const response = await fetch(`${config.backendUrls.payment}/payments/dedicated-account`, {
1624
+ method: "POST",
1625
+ headers: {
1626
+ "Content-Type": "application/json",
1627
+ "Authorization": `Bearer ${accessToken}`,
1628
+ "X-Storefront-Key": config.storefrontApiKey,
1629
+ "X-Business-ID": config.businessId
1630
+ },
1631
+ body: JSON.stringify({
1632
+ order_id: request.order_id && isValidUUID(request.order_id) ? request.order_id : void 0,
1633
+ amount: request.amount,
1634
+ customer_email: request.customer_email,
1635
+ customer_name: request.customer_name,
1636
+ currency: request.currency,
1637
+ idempotency_key: request.idempotency_key
1638
+ })
1639
+ });
1640
+ if (!response.ok) throw new Error("Failed to create dedicated account");
1641
+ const data = await response.json();
1642
+ return data;
1643
+ }
1644
+ async function initiatePayment(config, accessToken, request) {
1645
+ const isValidUUID = (str) => {
1646
+ const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
1647
+ return uuidRegex.test(str);
1648
+ };
1649
+ const validOrderId = request.order_id && isValidUUID(request.order_id) ? request.order_id : void 0;
1650
+ const response = await fetch(`${config.backendUrls.payment}/payments/storefront/initiate`, {
1651
+ method: "POST",
1652
+ headers: {
1653
+ "Content-Type": "application/json",
1654
+ "Authorization": `Bearer ${accessToken}`,
1655
+ "X-Storefront-Key": config.storefrontApiKey,
1656
+ "X-Business-ID": config.businessId
1657
+ },
1658
+ body: JSON.stringify({
1659
+ amount: request.amount,
1660
+ currency: request.currency,
1661
+ order_id: validOrderId,
1662
+ quote_id: request.quote_id,
1663
+ metadata_json: {
1664
+ customer_email: request.customer_email,
1665
+ customer_name: request.customer_name ?? "",
1666
+ order_id: validOrderId,
1667
+ ...request.metadata ?? {}
1668
+ },
1669
+ idempotency_key: request.idempotency_key
1670
+ })
1671
+ });
1672
+ if (!response.ok) throw new Error("Failed to initiate payment");
1673
+ const data = await response.json();
1674
+ return {
1675
+ id: data.id,
1676
+ gateway_ref: data.gateway_ref,
1677
+ gateway: data.gateway,
1678
+ status: data.status,
1679
+ checkout_url: data.metadata_json?.checkout_url ?? ""
1680
+ };
1681
+ }
1682
+ async function requestQuote(config, amount) {
1683
+ const response = await fetch(`${config.backendUrls.payment}/payments/quote`, {
1684
+ method: "POST",
1685
+ headers: {
1686
+ "Content-Type": "application/json",
1687
+ "X-Storefront-Key": config.storefrontApiKey,
1688
+ "X-Business-ID": config.businessId
1689
+ },
1690
+ body: JSON.stringify({ amount })
1691
+ });
1692
+ if (!response.ok) throw new Error("Failed to request quote");
1693
+ const data = await response.json();
1694
+ return data;
1695
+ }
1696
+ async function verifyTransaction(configOrReference, reference) {
1697
+ if (typeof configOrReference === "string") {
1698
+ const ref2 = configOrReference;
1699
+ const response2 = await fetch(`/api/payments/verify/${ref2}`, {
1700
+ method: "POST",
1701
+ headers: { "Content-Type": "application/json" }
1702
+ });
1703
+ if (!response2.ok) throw new Error("Failed to verify transaction");
1704
+ return response2.json();
1705
+ }
1706
+ const config = configOrReference;
1707
+ const ref = reference || "";
1708
+ const response = await fetch(`${config.backendUrls.payment}/payments/verify/${ref}`, {
1709
+ method: "POST",
1710
+ headers: {
1711
+ "Content-Type": "application/json",
1712
+ "X-Storefront-Key": config.storefrontApiKey,
1713
+ "X-Business-ID": config.businessId
1714
+ }
1715
+ });
1716
+ if (!response.ok) throw new Error("Failed to verify transaction");
1717
+ const data = await response.json();
1718
+ return data;
1719
+ }
1720
+ async function getTransactionStatus(config, transactionId) {
1721
+ const response = await fetch(`${config.backendUrls.payment}/payments/transactions/${transactionId}`, {
1722
+ headers: {
1723
+ "X-Storefront-Key": config.storefrontApiKey,
1724
+ "X-Business-ID": config.businessId
1725
+ }
1726
+ });
1727
+ if (!response.ok) throw new Error("Failed to get transaction status");
1728
+ const data = await response.json();
1729
+ return data;
1730
+ }
1731
+ var paymentService = {
1732
+ createDedicatedAccount,
1733
+ initiatePayment,
1734
+ requestQuote,
1735
+ verifyTransaction,
1736
+ getTransactionStatus
1737
+ };
1738
+
1739
+ // src/services/consultation.service.ts
1740
+ async function createConsultation(config, accessToken, payload) {
1741
+ const response = await fetch(`${config.backendUrls.store}/social/consultations/`, {
1742
+ method: "POST",
1743
+ headers: {
1744
+ "Content-Type": "application/json",
1745
+ "Authorization": `Bearer ${accessToken}`,
1746
+ "X-Storefront-Key": config.storefrontApiKey,
1747
+ "X-Business-ID": config.businessId
1748
+ },
1749
+ body: JSON.stringify(payload)
1750
+ });
1751
+ if (!response.ok) throw new Error("Failed to create consultation");
1752
+ return response.json();
1753
+ }
1754
+ async function getConsultations(config, accessToken) {
1755
+ const response = await fetch(`${config.backendUrls.store}/social/consultations/`, {
1756
+ headers: {
1757
+ "Authorization": `Bearer ${accessToken}`,
1758
+ "X-Storefront-Key": config.storefrontApiKey,
1759
+ "X-Business-ID": config.businessId
1760
+ }
1761
+ });
1762
+ if (!response.ok) throw new Error("Failed to get consultations");
1763
+ return response.json();
1764
+ }
1765
+ async function getConsultation(config, accessToken, id) {
1766
+ const response = await fetch(`${config.backendUrls.store}/social/consultations/${id}`, {
1767
+ headers: {
1768
+ "Authorization": `Bearer ${accessToken}`,
1769
+ "X-Storefront-Key": config.storefrontApiKey,
1770
+ "X-Business-ID": config.businessId
1771
+ }
1772
+ });
1773
+ if (!response.ok) throw new Error("Failed to get consultation");
1774
+ return response.json();
1775
+ }
1776
+ async function sendMessage(config, accessToken, id, payload) {
1777
+ await fetch(`${config.backendUrls.store}/social/consultations/${id}/messages`, {
1778
+ method: "POST",
1779
+ headers: {
1780
+ "Content-Type": "application/json",
1781
+ "Authorization": `Bearer ${accessToken}`,
1782
+ "X-Storefront-Key": config.storefrontApiKey,
1783
+ "X-Business-ID": config.businessId
1784
+ },
1785
+ body: JSON.stringify(payload)
1786
+ });
1787
+ }
1788
+ async function acceptQuote(config, accessToken, id, payload) {
1789
+ const response = await fetch(`${config.backendUrls.store}/social/consultations/${id}/accept-quote`, {
1790
+ method: "POST",
1791
+ headers: {
1792
+ "Content-Type": "application/json",
1793
+ "Authorization": `Bearer ${accessToken}`,
1794
+ "X-Storefront-Key": config.storefrontApiKey,
1795
+ "X-Business-ID": config.businessId
1796
+ },
1797
+ body: JSON.stringify(payload)
1798
+ });
1799
+ if (!response.ok) throw new Error("Failed to accept quote");
1800
+ return response.json();
1801
+ }
1802
+ async function rejectQuote(config, accessToken, id, reason) {
1803
+ const response = await fetch(`${config.backendUrls.store}/social/consultations/${id}/reject-quote`, {
1804
+ method: "POST",
1805
+ headers: {
1806
+ "Content-Type": "application/json",
1807
+ "Authorization": `Bearer ${accessToken}`,
1808
+ "X-Storefront-Key": config.storefrontApiKey,
1809
+ "X-Business-ID": config.businessId
1810
+ },
1811
+ body: JSON.stringify({ reason })
1812
+ });
1813
+ if (!response.ok) throw new Error("Failed to reject quote");
1814
+ return response.json();
1815
+ }
1816
+ var consultationService = {
1817
+ createConsultation,
1818
+ getConsultations,
1819
+ getConsultation,
1820
+ sendMessage,
1821
+ acceptQuote,
1822
+ rejectQuote
1823
+ };
1824
+
1825
+ // src/services/logistics.service.ts
1826
+ async function getShippingRates(config, payload) {
1827
+ const response = await fetch(`${config.backendUrls.store}/logistics/shipping/rates`, {
1828
+ method: "POST",
1829
+ headers: {
1830
+ "Content-Type": "application/json",
1831
+ "X-Storefront-Key": config.storefrontApiKey,
1832
+ "X-Business-ID": config.businessId
1833
+ },
1834
+ body: JSON.stringify(payload)
1835
+ });
1836
+ if (!response.ok) throw new Error("Failed to get shipping rates");
1837
+ return response.json();
1838
+ }
1839
+ async function getSellerShippingAddress(config) {
1840
+ const response = await fetch(`${config.backendUrls.store}/logistics/shipping-address`, {
1841
+ headers: {
1842
+ "X-Storefront-Key": config.storefrontApiKey,
1843
+ "X-Business-ID": config.businessId
1844
+ }
1845
+ });
1846
+ if (!response.ok) throw new Error("Failed to get seller shipping address");
1847
+ return response.json();
1848
+ }
1849
+ async function validateShippingAddress(config, payload) {
1850
+ const response = await fetch(`${config.backendUrls.store}/logistics/shipping-address/validate`, {
1851
+ method: "POST",
1852
+ headers: {
1853
+ "Content-Type": "application/json",
1854
+ "X-Storefront-Key": config.storefrontApiKey,
1855
+ "X-Business-ID": config.businessId
1856
+ },
1857
+ body: JSON.stringify(payload)
1858
+ });
1859
+ if (!response.ok) throw new Error("Failed to validate shipping address");
1860
+ return response.json();
1861
+ }
1862
+ var logisticsService = {
1863
+ getShippingRates,
1864
+ getSellerShippingAddress,
1865
+ validateShippingAddress
1866
+ };
1867
+
1868
+ // src/services/bespoke.service.ts
1869
+ async function checkAvailability(config, product_id) {
1870
+ const response = await fetch(`${config.backendUrls.store}/bespoke/availability/${product_id}`, {
1871
+ headers: {
1872
+ "X-Storefront-Key": config.storefrontApiKey,
1873
+ "X-Business-ID": config.businessId
1874
+ }
1875
+ });
1876
+ if (!response.ok) throw new Error("Failed to check bespoke availability");
1877
+ return response.json();
1878
+ }
1879
+ var bespokeService = {
1880
+ checkAvailability
1881
+ };
1882
+
1883
+ // src/services/service-booking.service.ts
1884
+ async function getAvailableSlots(config, product_id, date_from, date_to) {
1885
+ const response = await fetch(
1886
+ `${config.backendUrls.store}/service/available-slots/${product_id}?date_from=${date_from}&date_to=${date_to}`,
1887
+ {
1888
+ headers: {
1889
+ "X-Storefront-Key": config.storefrontApiKey,
1890
+ "X-Business-ID": config.businessId
1891
+ }
1892
+ }
1893
+ );
1894
+ if (!response.ok) throw new Error("Failed to get available slots");
1895
+ return response.json();
1896
+ }
1897
+ async function bookAppointment(config, accessToken, payload) {
1898
+ const response = await fetch(`${config.backendUrls.store}/service/appointments/`, {
1899
+ method: "POST",
1900
+ headers: {
1901
+ "Content-Type": "application/json",
1902
+ "Authorization": `Bearer ${accessToken}`,
1903
+ "X-Storefront-Key": config.storefrontApiKey,
1904
+ "X-Business-ID": config.businessId
1905
+ },
1906
+ body: JSON.stringify(payload)
1907
+ });
1908
+ if (!response.ok) throw new Error("Failed to book appointment");
1909
+ return response.json();
1910
+ }
1911
+ async function getAppointments(config, accessToken) {
1912
+ const response = await fetch(`${config.backendUrls.store}/service/bookings/my`, {
1913
+ headers: {
1914
+ "Authorization": `Bearer ${accessToken}`,
1915
+ "X-Storefront-Key": config.storefrontApiKey,
1916
+ "X-Business-ID": config.businessId
1917
+ }
1918
+ });
1919
+ if (!response.ok) throw new Error("Failed to get appointments");
1920
+ return response.json();
1921
+ }
1922
+ async function getAppointment(config, accessToken, id) {
1923
+ const response = await fetch(`${config.backendUrls.store}/service/bookings/${id}`, {
1924
+ headers: {
1925
+ "Authorization": `Bearer ${accessToken}`,
1926
+ "X-Storefront-Key": config.storefrontApiKey,
1927
+ "X-Business-ID": config.businessId
1928
+ }
1929
+ });
1930
+ if (!response.ok) throw new Error("Failed to get appointment");
1931
+ return response.json();
1932
+ }
1933
+ async function cancelAppointment(config, accessToken, id) {
1934
+ await fetch(`${config.backendUrls.store}/service/bookings/${id}`, {
1935
+ method: "DELETE",
1936
+ headers: {
1937
+ "Authorization": `Bearer ${accessToken}`,
1938
+ "X-Storefront-Key": config.storefrontApiKey,
1939
+ "X-Business-ID": config.businessId
1940
+ }
1941
+ });
1942
+ }
1943
+ async function getDeliverables(config, accessToken, order_id) {
1944
+ const response = await fetch(`${config.backendUrls.store}/service/projects/${order_id}/deliverables/`, {
1945
+ headers: {
1946
+ "Authorization": `Bearer ${accessToken}`,
1947
+ "X-Storefront-Key": config.storefrontApiKey,
1948
+ "X-Business-ID": config.businessId
1949
+ }
1950
+ });
1951
+ if (!response.ok) throw new Error("Failed to get deliverables");
1952
+ return response.json();
1953
+ }
1954
+ async function approveDeliverable(config, accessToken, order_id, deliverable_id) {
1955
+ const response = await fetch(
1956
+ `${config.backendUrls.store}/service/projects/${order_id}/deliverables/${deliverable_id}/approve`,
1957
+ {
1958
+ method: "POST",
1959
+ headers: {
1960
+ "Content-Type": "application/json",
1961
+ "Authorization": `Bearer ${accessToken}`,
1962
+ "X-Storefront-Key": config.storefrontApiKey,
1963
+ "X-Business-ID": config.businessId
1964
+ },
1965
+ body: JSON.stringify({ approved: true })
1966
+ }
1967
+ );
1968
+ if (!response.ok) throw new Error("Failed to approve deliverable");
1969
+ return response.json();
1970
+ }
1971
+ async function requestRevision(config, accessToken, order_id, deliverable_id, feedback) {
1972
+ const response = await fetch(
1973
+ `${config.backendUrls.store}/service/projects/${order_id}/deliverables/${deliverable_id}/revision`,
1974
+ {
1975
+ method: "POST",
1976
+ headers: {
1977
+ "Content-Type": "application/json",
1978
+ "Authorization": `Bearer ${accessToken}`,
1979
+ "X-Storefront-Key": config.storefrontApiKey,
1980
+ "X-Business-ID": config.businessId
1981
+ },
1982
+ body: JSON.stringify({ approved: false, feedback })
1983
+ }
1984
+ );
1985
+ if (!response.ok) throw new Error("Failed to request revision");
1986
+ return response.json();
1987
+ }
1988
+ var serviceBookingService = {
1989
+ getAvailableSlots,
1990
+ bookAppointment,
1991
+ getAppointments,
1992
+ getAppointment,
1993
+ cancelAppointment,
1994
+ getDeliverables,
1995
+ approveDeliverable,
1996
+ requestRevision
1997
+ };
1998
+
1999
+ // src/services/notifications.service.ts
2000
+ async function sendContactEmail(config, payload) {
2001
+ const response = await fetch(`${config.backendUrls.notifications}/contact/send-contact-email`, {
2002
+ method: "POST",
2003
+ headers: {
2004
+ "Content-Type": "application/json",
2005
+ "X-Storefront-Key": config.storefrontApiKey,
2006
+ "X-Business-ID": config.businessId
2007
+ },
2008
+ body: JSON.stringify(payload)
2009
+ });
2010
+ if (!response.ok) throw new Error("Failed to send contact email");
2011
+ return response.json();
2012
+ }
2013
+ async function sendContactConfirmation(config, payload) {
2014
+ const response = await fetch(`${config.backendUrls.notifications}/contact/send-contact-confirmation`, {
2015
+ method: "POST",
2016
+ headers: {
2017
+ "Content-Type": "application/json",
2018
+ "X-Storefront-Key": config.storefrontApiKey,
2019
+ "X-Business-ID": config.businessId
2020
+ },
2021
+ body: JSON.stringify(payload)
2022
+ });
2023
+ if (!response.ok) throw new Error("Failed to send contact confirmation");
2024
+ return response.json();
2025
+ }
2026
+ var notificationsService = {
2027
+ sendContactEmail,
2028
+ sendContactConfirmation
2029
+ };
2030
+
2031
+ // src/services/app.service.ts
2032
+ async function googleTranslate(text, target, source = "en") {
2033
+ if (!text || target === source) return text;
2034
+ try {
2035
+ const url = `https://translate.googleapis.com/translate_a/single?client=gtx&sl=${source}&tl=${target}&dt=t&q=${encodeURIComponent(text)}`;
2036
+ const res = await fetch(url);
2037
+ const data = await res.json();
2038
+ return (data?.[0] || []).map((s) => s[0]).join("");
2039
+ } catch {
2040
+ return text;
2041
+ }
2042
+ }
2043
+
2044
+ // src/services/config.service.ts
2045
+ async function getSupportedLanguages(config) {
2046
+ const response = await fetch(`${config.backendUrls.payment}/config/supported-languages`, {
2047
+ headers: {
2048
+ "X-Storefront-Key": config.storefrontApiKey,
2049
+ "X-Business-ID": config.businessId
2050
+ }
2051
+ });
2052
+ if (!response.ok) throw new Error("Failed to get supported languages");
2053
+ return response.json();
2054
+ }
2055
+ async function getSupportedCurrencies(config) {
2056
+ const response = await fetch(`${config.backendUrls.payment}/config/supported-currencies`, {
2057
+ headers: {
2058
+ "X-Storefront-Key": config.storefrontApiKey,
2059
+ "X-Business-ID": config.businessId
2060
+ }
2061
+ });
2062
+ if (!response.ok) throw new Error("Failed to get supported currencies");
2063
+ return response.json();
2064
+ }
2065
+ async function getBusinessConfig(config) {
2066
+ const response = await fetch(`${config.backendUrls.auth}/internal/businesses/${config.businessId}/`, {
2067
+ headers: {
2068
+ "X-Storefront-Key": config.storefrontApiKey,
2069
+ "X-Business-ID": config.businessId
2070
+ }
2071
+ });
2072
+ if (!response.ok) throw new Error("Failed to get business config");
2073
+ return response.json();
2074
+ }
2075
+ var configService = {
2076
+ getSupportedLanguages,
2077
+ getSupportedCurrencies,
2078
+ getBusinessConfig
2079
+ };
2080
+
2081
+ // src/services/cms.service.ts
2082
+ async function listCmsEntries(config, modelSlug, params) {
2083
+ const queryParams = new URLSearchParams();
2084
+ queryParams.set("page", (params?.page || 1).toString());
2085
+ queryParams.set("page_size", (params?.page_size || 50).toString());
2086
+ const response = await fetch(
2087
+ `${config.backendUrls.cms}/sdk/${config.businessId}/${modelSlug}/entries?${queryParams.toString()}`,
2088
+ {
2089
+ headers: {
2090
+ "X-Storefront-Key": config.storefrontApiKey,
2091
+ "X-Business-ID": config.businessId
2092
+ }
2093
+ }
2094
+ );
2095
+ if (!response.ok) throw new Error("Failed to list CMS entries");
2096
+ return response.json();
2097
+ }
2098
+ async function getCmsEntry(config, modelSlug, entryId) {
2099
+ const response = await fetch(
2100
+ `${config.backendUrls.cms}/sdk/${config.businessId}/${modelSlug}/entries/${entryId}`,
2101
+ {
2102
+ headers: {
2103
+ "X-Storefront-Key": config.storefrontApiKey,
2104
+ "X-Business-ID": config.businessId
2105
+ }
2106
+ }
2107
+ );
2108
+ if (!response.ok) throw new Error("Failed to get CMS entry");
2109
+ return response.json();
2110
+ }
2111
+ async function createCmsEntry(config, accessToken, modelSlug, params) {
2112
+ const response = await fetch(
2113
+ `${config.backendUrls.cms}/sdk/${config.businessId}/${modelSlug}/entries`,
2114
+ {
2115
+ method: "POST",
2116
+ headers: {
2117
+ "Content-Type": "application/json",
2118
+ "Authorization": `Bearer ${accessToken}`,
2119
+ "X-Storefront-Key": config.storefrontApiKey,
2120
+ "X-Business-ID": config.businessId
2121
+ },
2122
+ body: JSON.stringify(params)
2123
+ }
2124
+ );
2125
+ if (!response.ok) throw new Error("Failed to create CMS entry");
2126
+ return response.json();
2127
+ }
2128
+ async function updateCmsEntry(config, accessToken, modelSlug, entryId, params) {
2129
+ const response = await fetch(
2130
+ `${config.backendUrls.cms}/sdk/${config.businessId}/${modelSlug}/entries/${entryId}`,
2131
+ {
2132
+ method: "PUT",
2133
+ headers: {
2134
+ "Content-Type": "application/json",
2135
+ "Authorization": `Bearer ${accessToken}`,
2136
+ "X-Storefront-Key": config.storefrontApiKey,
2137
+ "X-Business-ID": config.businessId
2138
+ },
2139
+ body: JSON.stringify(params)
2140
+ }
2141
+ );
2142
+ if (!response.ok) throw new Error("Failed to update CMS entry");
2143
+ return response.json();
2144
+ }
2145
+ async function deleteCmsEntry(config, accessToken, modelSlug, entryId) {
2146
+ const response = await fetch(
2147
+ `${config.backendUrls.cms}/sdk/${config.businessId}/${modelSlug}/entries/${entryId}`,
2148
+ {
2149
+ method: "DELETE",
2150
+ headers: {
2151
+ "Authorization": `Bearer ${accessToken}`,
2152
+ "X-Storefront-Key": config.storefrontApiKey,
2153
+ "X-Business-ID": config.businessId
2154
+ }
2155
+ }
2156
+ );
2157
+ if (!response.ok) throw new Error("Failed to delete CMS entry");
2158
+ }
2159
+ export {
2160
+ acceptQuote,
2161
+ addToCart,
2162
+ addToGuestCart,
2163
+ addToWishlist,
2164
+ approveDeliverable,
2165
+ bespokeService,
2166
+ bookAppointment,
2167
+ cancelAppointment,
2168
+ cancelOrder,
2169
+ checkAvailability,
2170
+ checkInWishlist,
2171
+ clearCart,
2172
+ clearGuestCart,
2173
+ clearTokens,
2174
+ configService,
2175
+ consultationService,
2176
+ createCmsEntry,
2177
+ createConsultation,
2178
+ createDedicatedAccount,
2179
+ createOrder,
2180
+ deleteCmsEntry,
2181
+ findOrder,
2182
+ findOrderByToken,
2183
+ getAppointment,
2184
+ getAppointments,
2185
+ getAuthUser,
2186
+ getAvailableSlots,
2187
+ getBusinessConfig,
2188
+ getCart,
2189
+ getCmsEntry,
2190
+ getConsultation,
2191
+ getConsultations,
2192
+ getDeliverables,
2193
+ getFeaturedProducts,
2194
+ getGuestCart,
2195
+ getGuestCartCount,
2196
+ getGuestCartProductType,
2197
+ getGuestCartSubtotal,
2198
+ getLatestProducts,
2199
+ getLowStockProducts,
2200
+ getMe,
2201
+ getNewProducts,
2202
+ getOnSaleProducts,
2203
+ getOrders,
2204
+ getPopularProducts,
2205
+ getRecommendedProducts,
2206
+ getSellerShippingAddress,
2207
+ getShippingRates,
2208
+ getStoredTokens,
2209
+ getStorefrontCollectionBySlug,
2210
+ getStorefrontCollections,
2211
+ getStorefrontProductBySlug,
2212
+ getStorefrontProducts,
2213
+ getSupportedCurrencies,
2214
+ getSupportedLanguages,
2215
+ getTransactionStatus,
2216
+ getWishlist,
2217
+ googleTranslate,
2218
+ initiatePayment,
2219
+ listCmsEntries,
2220
+ loginCustomer,
2221
+ logisticsService,
2222
+ logout,
2223
+ mapAuthUserToCustomer,
2224
+ mergeGuestCart,
2225
+ mergeGuestCartIfPresent,
2226
+ notificationsService,
2227
+ paymentService,
2228
+ refreshToken,
2229
+ registerCustomer,
2230
+ rejectQuote,
2231
+ removeFromCart,
2232
+ removeFromGuestCart,
2233
+ removeFromWishlist,
2234
+ removeProductFromWishlist,
2235
+ requestQuote,
2236
+ requestRevision,
2237
+ sendContactConfirmation,
2238
+ sendContactEmail,
2239
+ sendMessage,
2240
+ serviceBookingService,
2241
+ silentRefresh,
2242
+ storeTokens,
2243
+ trackOrder,
2244
+ updateCartItem,
2245
+ updateCmsEntry,
2246
+ updateGuestCartItemQuantity,
2247
+ updateProfile,
2248
+ validateShippingAddress,
2249
+ verifySocialToken,
2250
+ verifyTransaction
2251
+ };
2252
+ //# sourceMappingURL=index.mjs.map