@kasuvia/sdk 0.0.1

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 (73) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +112 -0
  3. package/dist/index.d.mts +1891 -0
  4. package/dist/index.d.ts +1891 -0
  5. package/dist/index.js +3540 -0
  6. package/dist/index.js.map +1 -0
  7. package/dist/index.mjs +3314 -0
  8. package/dist/index.mjs.map +1 -0
  9. package/package.json +59 -0
  10. package/src/client/authClient.ts +135 -0
  11. package/src/client/graphqlClient.ts +53 -0
  12. package/src/client/httpClient.ts +298 -0
  13. package/src/config/index.ts +102 -0
  14. package/src/graphql/collections.graphql.ts +56 -0
  15. package/src/graphql/index.ts +7 -0
  16. package/src/graphql/products.graphql.ts +710 -0
  17. package/src/graphql/wishlist.graphql.ts +33 -0
  18. package/src/hooks/index.ts +26 -0
  19. package/src/hooks/use-auth.ts +182 -0
  20. package/src/hooks/use-bespoke-availability.ts +20 -0
  21. package/src/hooks/use-cart.ts +207 -0
  22. package/src/hooks/use-cms.ts +165 -0
  23. package/src/hooks/use-collections.ts +40 -0
  24. package/src/hooks/use-consultation-stream.ts +141 -0
  25. package/src/hooks/use-consultations.ts +76 -0
  26. package/src/hooks/use-countries.ts +24 -0
  27. package/src/hooks/use-currencies.ts +27 -0
  28. package/src/hooks/use-google-translate.ts +164 -0
  29. package/src/hooks/use-is-mounted.ts +9 -0
  30. package/src/hooks/use-languages.ts +33 -0
  31. package/src/hooks/use-order-stream.ts +195 -0
  32. package/src/hooks/use-orders.ts +64 -0
  33. package/src/hooks/use-payment.ts +68 -0
  34. package/src/hooks/use-products.ts +113 -0
  35. package/src/hooks/use-service-booking.ts +118 -0
  36. package/src/hooks/use-states.ts +28 -0
  37. package/src/hooks/use-wishlist.ts +121 -0
  38. package/src/index.ts +65 -0
  39. package/src/services/app.service.ts +17 -0
  40. package/src/services/auth.service.ts +332 -0
  41. package/src/services/bespoke.service.ts +17 -0
  42. package/src/services/cart.service.ts +245 -0
  43. package/src/services/cms.service.ts +112 -0
  44. package/src/services/collection.service.ts +77 -0
  45. package/src/services/config.service.ts +42 -0
  46. package/src/services/consultation.service.ts +51 -0
  47. package/src/services/index.ts +21 -0
  48. package/src/services/logistics.service.ts +95 -0
  49. package/src/services/notifications.service.ts +50 -0
  50. package/src/services/order.service.ts +169 -0
  51. package/src/services/payment.service.ts +127 -0
  52. package/src/services/product.service.ts +678 -0
  53. package/src/services/service-booking.service.ts +86 -0
  54. package/src/services/wishlist.service.ts +84 -0
  55. package/src/types/auth/index.ts +126 -0
  56. package/src/types/bespoke/index.ts +39 -0
  57. package/src/types/business/index.ts +6 -0
  58. package/src/types/cms/index.ts +77 -0
  59. package/src/types/consultations/index.ts +79 -0
  60. package/src/types/index.ts +27 -0
  61. package/src/types/media/index.ts +41 -0
  62. package/src/types/payments/index.ts +120 -0
  63. package/src/types/services/index.ts +80 -0
  64. package/src/types/store/index.ts +282 -0
  65. package/src/types/store/shipping.ts +38 -0
  66. package/src/types/ui/index.ts +32 -0
  67. package/src/utils/cache.ts +33 -0
  68. package/src/utils/checkout.ts +39 -0
  69. package/src/utils/customer.ts +20 -0
  70. package/src/utils/error-handler.ts +14 -0
  71. package/src/utils/index.ts +10 -0
  72. package/src/utils/logger.ts +79 -0
  73. package/src/utils/sanitize-url.ts +55 -0
package/dist/index.mjs ADDED
@@ -0,0 +1,3314 @@
1
+ // src/utils/cache.ts
2
+ var CACHE_TIERS = {
3
+ none: { staleTime: 0, gcTime: 0 },
4
+ infinity: { staleTime: Infinity, gcTime: 0 },
5
+ low: { staleTime: 1e3 * 30, gcTime: 1e3 * 60 },
6
+ // 30s / 1m
7
+ medium: { staleTime: 1e3 * 60 * 5, gcTime: 1e3 * 60 * 10 },
8
+ // 5m / 10m
9
+ high: { staleTime: 1e3 * 60 * 30, gcTime: 1e3 * 60 * 60 }
10
+ // 30m / 1h
11
+ };
12
+ var isDevelopment = true;
13
+ function setEnvironmentMode(development) {
14
+ isDevelopment = development;
15
+ }
16
+ var getCacheTier = (tier) => {
17
+ if (isDevelopment) return CACHE_TIERS.none;
18
+ return CACHE_TIERS[tier];
19
+ };
20
+
21
+ // src/utils/logger.ts
22
+ var isDevelopment2 = true;
23
+ function setLoggerEnvironmentMode(development) {
24
+ isDevelopment2 = development;
25
+ }
26
+ var logger = {
27
+ log: (...args) => {
28
+ if (isDevelopment2) {
29
+ console.log(...args);
30
+ }
31
+ },
32
+ warn: (...args) => {
33
+ if (isDevelopment2) {
34
+ console.warn(...args);
35
+ }
36
+ },
37
+ /**
38
+ * Logs a warning to the console in development only.
39
+ * Alias for warn() for Python logging compatibility.
40
+ * In production, this is a no-op.
41
+ */
42
+ warning: (...args) => {
43
+ if (isDevelopment2) {
44
+ console.warn(...args);
45
+ }
46
+ },
47
+ error: (...args) => {
48
+ if (isDevelopment2) {
49
+ console.error(...args);
50
+ }
51
+ },
52
+ info: (...args) => {
53
+ if (isDevelopment2) {
54
+ console.info(...args);
55
+ }
56
+ },
57
+ createScope: (scope) => ({
58
+ log: (...args) => {
59
+ if (isDevelopment2) {
60
+ console.log(`[${scope}]`, ...args);
61
+ }
62
+ },
63
+ warn: (...args) => {
64
+ if (isDevelopment2) {
65
+ console.warn(`[${scope}]`, ...args);
66
+ }
67
+ },
68
+ warning: (...args) => {
69
+ if (isDevelopment2) {
70
+ console.warn(`[${scope}]`, ...args);
71
+ }
72
+ },
73
+ error: (...args) => {
74
+ if (isDevelopment2) {
75
+ console.error(`[${scope}]`, ...args);
76
+ }
77
+ },
78
+ info: (...args) => {
79
+ if (isDevelopment2) {
80
+ console.info(`[${scope}]`, ...args);
81
+ }
82
+ }
83
+ })
84
+ };
85
+
86
+ // src/utils/sanitize-url.ts
87
+ var InvalidBaseURLError = class extends Error {
88
+ constructor(message) {
89
+ super(message);
90
+ this.name = "InvalidBaseURLError";
91
+ }
92
+ };
93
+ var ALLOWED_SCHEMES = /* @__PURE__ */ new Set(["http:", "https:", "ws:", "wss:"]);
94
+ function sanitizeBaseUrl(url, name = "URL") {
95
+ if (url == null) {
96
+ throw new InvalidBaseURLError(`${name} is not set`);
97
+ }
98
+ const cleaned0 = url.trim();
99
+ if (!cleaned0) {
100
+ throw new InvalidBaseURLError(`${name} is empty`);
101
+ }
102
+ const cleaned = cleaned0.replace(/\/+$/, "");
103
+ let parsed;
104
+ try {
105
+ parsed = new URL(cleaned);
106
+ } catch {
107
+ throw new InvalidBaseURLError(
108
+ `${name} must start with http://, https://, ws://, or wss://, got: ${url}`
109
+ );
110
+ }
111
+ if (!ALLOWED_SCHEMES.has(parsed.protocol)) {
112
+ throw new InvalidBaseURLError(
113
+ `${name} must start with http://, https://, ws://, or wss://, got: ${url}`
114
+ );
115
+ }
116
+ if (!parsed.hostname) {
117
+ throw new InvalidBaseURLError(`${name} is missing a host: ${url}`);
118
+ }
119
+ if (parsed.search || parsed.hash) {
120
+ throw new InvalidBaseURLError(
121
+ `${name} should not contain a query or fragment: ${url}`
122
+ );
123
+ }
124
+ return cleaned;
125
+ }
126
+
127
+ // src/utils/customer.ts
128
+ function buildFullName(firstname, lastname) {
129
+ const name = [firstname, lastname].filter(Boolean).join(" ").trim();
130
+ return name || void 0;
131
+ }
132
+ function splitFullName(fullName) {
133
+ if (!fullName?.trim()) return { firstname: "", lastname: "" };
134
+ const parts = fullName.trim().split(/\s+/);
135
+ return {
136
+ firstname: parts[0] ?? "",
137
+ lastname: parts.slice(1).join(" ")
138
+ };
139
+ }
140
+ function getCustomerDisplayName(user) {
141
+ const fromParts = buildFullName(user.firstname, user.lastname);
142
+ return fromParts || user.full_name || user.email.split("@")[0];
143
+ }
144
+
145
+ // src/utils/checkout.ts
146
+ function buildDeliveryAddress(customer, location) {
147
+ return {
148
+ first_name: customer.first_name,
149
+ last_name: customer.last_name,
150
+ phone: customer.phone,
151
+ ...location
152
+ };
153
+ }
154
+ function getCheckoutCustomerName(customer) {
155
+ return buildFullName(customer.first_name, customer.last_name) ?? customer.email.split("@")[0];
156
+ }
157
+ function enrichCompletedOrder(order, options) {
158
+ const customerName = getCheckoutCustomerName(options.customer);
159
+ return {
160
+ ...order,
161
+ customerName: order.customerName || customerName,
162
+ customerEmail: order.customerEmail || options.customer.email,
163
+ shippingAddress: order.shippingAddress ?? (options.productType === "physical" && options.location ? buildDeliveryAddress(options.customer, options.location) : void 0),
164
+ bespokeBrief: order.bespokeBrief ?? options.bespokeBrief
165
+ };
166
+ }
167
+
168
+ // src/utils/error-handler.ts
169
+ import axios from "axios";
170
+ function getErrorMessage(error, fallback = "Something went wrong") {
171
+ if (axios.isAxiosError(error)) {
172
+ return error.response?.data?.detail || error.response?.data?.message || error.message || fallback;
173
+ }
174
+ if (error instanceof Error) {
175
+ return error.message;
176
+ }
177
+ return fallback;
178
+ }
179
+
180
+ // src/config/index.ts
181
+ var runtimeConfig = null;
182
+ var BACKEND_URLS = {
183
+ auth: "https://127.0.0.1:8000/api/v1",
184
+ store: "https://127.0.0.1:8001/api/v1",
185
+ payment: "https://127.0.0.1:8002/api/v1",
186
+ notifications: "https://127.0.0.1:8007/api/v1",
187
+ cms: "https://127.0.0.1:8003/api/v1"
188
+ };
189
+ function initSdk(config) {
190
+ runtimeConfig = {
191
+ businessId: config.businessId,
192
+ storefrontApiKey: config.storefrontApiKey
193
+ };
194
+ const isDevelopment3 = typeof window === "undefined" && globalThis.process?.env?.NODE_ENV === "development";
195
+ setEnvironmentMode(isDevelopment3);
196
+ setLoggerEnvironmentMode(isDevelopment3);
197
+ logger.log("SDK initialized with businessId:", config.businessId);
198
+ }
199
+ function getRuntimeConfig() {
200
+ if (!runtimeConfig) {
201
+ throw new Error("SDK not initialized. Call initSdk() before using SDK functions.");
202
+ }
203
+ return runtimeConfig;
204
+ }
205
+ function getBackendUrl(service) {
206
+ return BACKEND_URLS[service];
207
+ }
208
+ function isInitialized() {
209
+ return runtimeConfig !== null;
210
+ }
211
+ function resetConfig() {
212
+ runtimeConfig = null;
213
+ }
214
+
215
+ // src/client/httpClient.ts
216
+ import axios3 from "axios";
217
+
218
+ // src/client/authClient.ts
219
+ import axios2 from "axios";
220
+ var _accessToken = null;
221
+ var _isRefreshing = false;
222
+ var _pendingQueue = [];
223
+ function getStorageKey() {
224
+ if (!isInitialized()) return "kasuvia-sf-anon-refresh";
225
+ const config = getRuntimeConfig();
226
+ return `kasuvia-sf-${config.businessId}-refresh`;
227
+ }
228
+ function drainQueue(error, newToken = null) {
229
+ _pendingQueue.forEach(({ resolve, reject }) => {
230
+ if (newToken) resolve(newToken);
231
+ else reject(error);
232
+ });
233
+ _pendingQueue = [];
234
+ }
235
+ var tokenStore = {
236
+ getAccessToken: () => _accessToken,
237
+ setAccessToken: (token) => {
238
+ _accessToken = token;
239
+ },
240
+ getRefreshToken: () => {
241
+ if (typeof window === "undefined") return null;
242
+ const key = getStorageKey();
243
+ return localStorage.getItem(key) || sessionStorage.getItem(key);
244
+ },
245
+ setRefreshToken: (token, remember = true) => {
246
+ if (typeof window === "undefined") return;
247
+ const key = getStorageKey();
248
+ localStorage.removeItem(key);
249
+ sessionStorage.removeItem(key);
250
+ if (token) {
251
+ const store = remember ? localStorage : sessionStorage;
252
+ store.setItem(key, token);
253
+ }
254
+ },
255
+ clearAll: () => {
256
+ _accessToken = null;
257
+ if (typeof window !== "undefined") {
258
+ const key = getStorageKey();
259
+ localStorage.removeItem(key);
260
+ sessionStorage.removeItem(key);
261
+ }
262
+ },
263
+ hasSession: () => {
264
+ if (typeof window === "undefined") return false;
265
+ const key = getStorageKey();
266
+ return !!(localStorage.getItem(key) || sessionStorage.getItem(key));
267
+ },
268
+ isPersistent: () => {
269
+ if (typeof window === "undefined") return true;
270
+ const key = getStorageKey();
271
+ return !!localStorage.getItem(key);
272
+ }
273
+ };
274
+ var refreshAxios = axios2.create({
275
+ baseURL: getBackendUrl("auth"),
276
+ headers: {
277
+ "Content-Type": "application/json",
278
+ Accept: "application/json"
279
+ },
280
+ withCredentials: true,
281
+ timeout: 3e4
282
+ });
283
+ async function refreshToken() {
284
+ if (_isRefreshing) {
285
+ return new Promise((resolve, reject) => {
286
+ _pendingQueue.push({ resolve, reject });
287
+ });
288
+ }
289
+ _isRefreshing = true;
290
+ const refresh = tokenStore.getRefreshToken();
291
+ if (!refresh) {
292
+ _isRefreshing = false;
293
+ tokenStore.clearAll();
294
+ throw new Error("[kasuvia SDK] No refresh token available");
295
+ }
296
+ try {
297
+ const { data } = await refreshAxios.post("/auth/token/refresh/", { refresh });
298
+ const newAccess = data.access;
299
+ tokenStore.setAccessToken(newAccess);
300
+ if (data.refresh) {
301
+ tokenStore.setRefreshToken(data.refresh, tokenStore.isPersistent());
302
+ }
303
+ drainQueue(null, newAccess);
304
+ return newAccess;
305
+ } catch (err) {
306
+ drainQueue(err);
307
+ tokenStore.clearAll();
308
+ throw err;
309
+ } finally {
310
+ _isRefreshing = false;
311
+ }
312
+ }
313
+
314
+ // src/client/httpClient.ts
315
+ var _guestSessionId = null;
316
+ function getOrCreateGuestSessionId() {
317
+ if (_guestSessionId) return _guestSessionId;
318
+ const storageKey = isInitialized() ? `kasuvia-guest-${getRuntimeConfig().businessId}` : "kasuvia-guest-anon";
319
+ if (typeof window !== "undefined") {
320
+ _guestSessionId = sessionStorage.getItem(storageKey) || crypto.randomUUID();
321
+ sessionStorage.setItem(storageKey, _guestSessionId);
322
+ } else {
323
+ _guestSessionId = crypto.randomUUID();
324
+ }
325
+ return _guestSessionId;
326
+ }
327
+ function getGuestSessionId() {
328
+ if (!_guestSessionId && typeof window !== "undefined") {
329
+ const storageKey = isInitialized() ? `kasuvia-guest-${getRuntimeConfig().businessId}` : "kasuvia-guest-anon";
330
+ _guestSessionId = sessionStorage.getItem(storageKey);
331
+ }
332
+ return _guestSessionId;
333
+ }
334
+ function clearGuestSessionId() {
335
+ _guestSessionId = null;
336
+ if (typeof window !== "undefined") {
337
+ const storageKey = isInitialized() ? `kasuvia-guest-${getRuntimeConfig().businessId}` : "kasuvia-guest-anon";
338
+ sessionStorage.removeItem(storageKey);
339
+ }
340
+ }
341
+ var storeManagementAxios = axios3.create({
342
+ baseURL: getBackendUrl("store"),
343
+ headers: {
344
+ "Content-Type": "application/json",
345
+ Accept: "application/json"
346
+ },
347
+ timeout: 3e4
348
+ });
349
+ storeManagementAxios.interceptors.request.use((cfg) => {
350
+ const config = getRuntimeConfig();
351
+ const token = tokenStore.getAccessToken();
352
+ if (token) {
353
+ cfg.headers = cfg.headers ?? {};
354
+ cfg.headers["Authorization"] = `Bearer ${token}`;
355
+ }
356
+ cfg.headers = cfg.headers ?? {};
357
+ cfg.headers["X-Storefront-Key"] = config.storefrontApiKey;
358
+ cfg.headers["X-Business-ID"] = config.businessId;
359
+ if (!token) {
360
+ const sid = getOrCreateGuestSessionId();
361
+ if (sid) cfg.headers["X-Guest-Session"] = sid;
362
+ }
363
+ return cfg;
364
+ });
365
+ storeManagementAxios.interceptors.response.use(
366
+ (res) => res,
367
+ async (err) => {
368
+ const originalRequest = err.config;
369
+ if (!originalRequest) return Promise.reject(err);
370
+ const status = err.response?.status;
371
+ const isUnauthorized = status === 401;
372
+ const isRefreshEndpoint = originalRequest.url?.includes("/auth/token/refresh/");
373
+ const alreadyRetried = originalRequest._retry === true;
374
+ if (isUnauthorized && isRefreshEndpoint) {
375
+ tokenStore.clearAll();
376
+ return Promise.reject(err);
377
+ }
378
+ if (!isUnauthorized || alreadyRetried) return Promise.reject(err);
379
+ try {
380
+ const newToken = await refreshToken();
381
+ originalRequest._retry = true;
382
+ if (originalRequest.headers) {
383
+ originalRequest.headers["Authorization"] = `Bearer ${newToken}`;
384
+ }
385
+ return storeManagementAxios(originalRequest);
386
+ } catch (refreshErr) {
387
+ tokenStore.clearAll();
388
+ return Promise.reject(refreshErr);
389
+ }
390
+ }
391
+ );
392
+ var publicStoreAxios = axios3.create({
393
+ baseURL: getBackendUrl("store"),
394
+ headers: {
395
+ "Content-Type": "application/json",
396
+ Accept: "application/json"
397
+ },
398
+ timeout: 3e4
399
+ });
400
+ publicStoreAxios.interceptors.request.use((cfg) => {
401
+ const config = getRuntimeConfig();
402
+ cfg.headers = cfg.headers ?? {};
403
+ cfg.headers["X-Storefront-Key"] = config.storefrontApiKey;
404
+ cfg.headers["X-Business-ID"] = config.businessId;
405
+ return cfg;
406
+ });
407
+ publicStoreAxios.interceptors.response.use(
408
+ (res) => res,
409
+ (err) => Promise.reject(err)
410
+ );
411
+ var authAxios = axios3.create({
412
+ baseURL: getBackendUrl("auth"),
413
+ headers: {
414
+ "Content-Type": "application/json",
415
+ Accept: "application/json"
416
+ },
417
+ withCredentials: true,
418
+ timeout: 3e4
419
+ });
420
+ authAxios.interceptors.request.use((cfg) => {
421
+ const config = getRuntimeConfig();
422
+ const token = tokenStore.getAccessToken();
423
+ if (token) {
424
+ cfg.headers = cfg.headers ?? {};
425
+ cfg.headers["Authorization"] = `Bearer ${token}`;
426
+ }
427
+ cfg.headers = cfg.headers ?? {};
428
+ cfg.headers["X-Storefront-Key"] = config.storefrontApiKey;
429
+ cfg.headers["X-Business-ID"] = config.businessId;
430
+ return cfg;
431
+ });
432
+ authAxios.interceptors.response.use(
433
+ (res) => res,
434
+ async (err) => {
435
+ const originalRequest = err.config;
436
+ if (!originalRequest) return Promise.reject(err);
437
+ const status = err.response?.status;
438
+ const isUnauthorized = status === 401;
439
+ const isRefreshEndpoint = originalRequest.url?.includes("/auth/token/refresh/");
440
+ const alreadyRetried = originalRequest._retry === true;
441
+ if (isUnauthorized && isRefreshEndpoint) {
442
+ tokenStore.clearAll();
443
+ return Promise.reject(err);
444
+ }
445
+ if (!isUnauthorized || alreadyRetried) return Promise.reject(err);
446
+ try {
447
+ const newToken = await refreshToken();
448
+ originalRequest._retry = true;
449
+ if (originalRequest.headers) {
450
+ originalRequest.headers["Authorization"] = `Bearer ${newToken}`;
451
+ }
452
+ return authAxios(originalRequest);
453
+ } catch (refreshErr) {
454
+ tokenStore.clearAll();
455
+ return Promise.reject(refreshErr);
456
+ }
457
+ }
458
+ );
459
+ var paymentAxios = axios3.create({
460
+ baseURL: getBackendUrl("payment"),
461
+ headers: {
462
+ "Content-Type": "application/json",
463
+ Accept: "application/json"
464
+ },
465
+ timeout: 3e4
466
+ });
467
+ paymentAxios.interceptors.request.use((cfg) => {
468
+ const config = getRuntimeConfig();
469
+ cfg.headers = cfg.headers ?? {};
470
+ cfg.headers["X-Storefront-Key"] = config.storefrontApiKey;
471
+ cfg.headers["X-Business-ID"] = config.businessId;
472
+ return cfg;
473
+ });
474
+ paymentAxios.interceptors.response.use(
475
+ (res) => res,
476
+ (err) => Promise.reject(err)
477
+ );
478
+ var notificationsAxios = axios3.create({
479
+ baseURL: getBackendUrl("notifications"),
480
+ headers: {
481
+ "Content-Type": "application/json",
482
+ Accept: "application/json"
483
+ },
484
+ timeout: 3e4
485
+ });
486
+ notificationsAxios.interceptors.response.use(
487
+ (res) => res,
488
+ (err) => Promise.reject(err)
489
+ );
490
+ var cmsAxios = axios3.create({
491
+ baseURL: getBackendUrl("cms"),
492
+ headers: {
493
+ "Content-Type": "application/json",
494
+ Accept: "application/json"
495
+ },
496
+ timeout: 3e4
497
+ });
498
+ cmsAxios.interceptors.request.use((cfg) => {
499
+ const config = getRuntimeConfig();
500
+ cfg.headers = cfg.headers ?? {};
501
+ cfg.headers["X-Storefront-Key"] = config.storefrontApiKey;
502
+ cfg.headers["X-Business-ID"] = config.businessId;
503
+ return cfg;
504
+ });
505
+ cmsAxios.interceptors.response.use(
506
+ (res) => res,
507
+ (err) => Promise.reject(err)
508
+ );
509
+ var refreshAxios2 = axios3.create({
510
+ baseURL: getBackendUrl("auth"),
511
+ headers: {
512
+ "Content-Type": "application/json",
513
+ Accept: "application/json"
514
+ },
515
+ withCredentials: true,
516
+ timeout: 3e4
517
+ });
518
+ function configureHttpClients() {
519
+ if (!isInitialized()) return;
520
+ const storeUrl = getBackendUrl("store");
521
+ const authUrl = getBackendUrl("auth");
522
+ const paymentUrl = getBackendUrl("payment");
523
+ const notificationsUrl = getBackendUrl("notifications");
524
+ const cmsUrl = getBackendUrl("cms");
525
+ storeManagementAxios.defaults.baseURL = storeUrl;
526
+ publicStoreAxios.defaults.baseURL = storeUrl;
527
+ authAxios.defaults.baseURL = authUrl;
528
+ paymentAxios.defaults.baseURL = paymentUrl;
529
+ notificationsAxios.defaults.baseURL = notificationsUrl;
530
+ cmsAxios.defaults.baseURL = cmsUrl;
531
+ refreshAxios2.defaults.baseURL = authUrl;
532
+ }
533
+
534
+ // src/client/graphqlClient.ts
535
+ import { GraphQLClient } from "graphql-request";
536
+ var GRAPHQL_URL = `${getBackendUrl("store")}/graphql`;
537
+ function buildHeaders() {
538
+ const headers = {
539
+ "Content-Type": "application/json",
540
+ Accept: "application/json"
541
+ };
542
+ if (isInitialized()) {
543
+ const config = getRuntimeConfig();
544
+ headers["X-Storefront-Key"] = config.storefrontApiKey;
545
+ headers["X-Business-ID"] = config.businessId;
546
+ }
547
+ const token = tokenStore.getAccessToken();
548
+ if (token) headers["Authorization"] = `Bearer ${token}`;
549
+ return headers;
550
+ }
551
+ function getGraphQLClient() {
552
+ return new GraphQLClient(GRAPHQL_URL, { headers: buildHeaders() });
553
+ }
554
+ function resetGraphQLClient() {
555
+ }
556
+
557
+ // src/services/cart.service.ts
558
+ function parseItems(items) {
559
+ return items.map((item) => ({
560
+ ...item,
561
+ variant_attributes: item.variant_attributes && typeof item.variant_attributes === "string" ? JSON.parse(item.variant_attributes) : item.variant_attributes
562
+ }));
563
+ }
564
+ async function getGuestCart() {
565
+ const sid = getGuestSessionId();
566
+ if (!sid) return [];
567
+ try {
568
+ const { data } = await storeManagementAxios.get("cart/", {
569
+ headers: { "X-Guest-Session": sid }
570
+ });
571
+ return parseItems(data.items || []);
572
+ } catch {
573
+ return [];
574
+ }
575
+ }
576
+ async function addToGuestCart(item) {
577
+ const sid = getOrCreateGuestSessionId();
578
+ if (!sid) return [];
579
+ const payload = {
580
+ product_id: item.product_id,
581
+ product_slug: item.product_slug,
582
+ product_name: item.product_name,
583
+ image: item.image,
584
+ variant_id: item.variant_id,
585
+ variant_attributes: typeof item.variant_attributes === "string" ? item.variant_attributes : JSON.stringify(item.variant_attributes),
586
+ unit_price: item.unit_price,
587
+ quantity: item.quantity,
588
+ custom_measurements: item.custom_measurements,
589
+ is_bespoke: item.is_bespoke
590
+ };
591
+ const { data } = await storeManagementAxios.post("cart/", payload, {
592
+ headers: { "X-Guest-Session": sid }
593
+ });
594
+ return parseItems(data.items || []);
595
+ }
596
+ async function updateGuestCartItemQuantity(itemId, quantity) {
597
+ const sid = getGuestSessionId();
598
+ if (!sid) return [];
599
+ const { data } = await storeManagementAxios.patch(
600
+ `cart/${itemId}`,
601
+ { quantity },
602
+ { headers: { "X-Guest-Session": sid } }
603
+ );
604
+ return parseItems(data.items || []);
605
+ }
606
+ async function removeFromGuestCart(itemId) {
607
+ const sid = getGuestSessionId();
608
+ if (!sid) return [];
609
+ await storeManagementAxios.delete(`cart/${itemId}`, {
610
+ headers: { "X-Guest-Session": sid }
611
+ });
612
+ return getGuestCart();
613
+ }
614
+ async function clearGuestCart() {
615
+ const sid = getGuestSessionId();
616
+ if (!sid) return;
617
+ await storeManagementAxios.delete("cart/clear", {
618
+ headers: { "X-Guest-Session": sid }
619
+ });
620
+ }
621
+ async function getCart() {
622
+ const { data } = await storeManagementAxios.get("cart/");
623
+ const parsedItems = parseItems(data.items || []);
624
+ return { ...data, items: parsedItems };
625
+ }
626
+ async function addToCart(item) {
627
+ const { data } = await storeManagementAxios.post("cart/", item);
628
+ const parsedItems = parseItems(data.items || []);
629
+ return { ...data, items: parsedItems };
630
+ }
631
+ async function updateCartItem(itemId, quantity) {
632
+ const { data } = await storeManagementAxios.patch(
633
+ `cart/${itemId}`,
634
+ { quantity }
635
+ );
636
+ const parsedItems = parseItems(data.items || []);
637
+ return { ...data, items: parsedItems };
638
+ }
639
+ async function removeFromCart(itemId) {
640
+ await storeManagementAxios.delete(`cart/${itemId}`);
641
+ return getCart();
642
+ }
643
+ async function clearCart() {
644
+ await storeManagementAxios.delete("cart/clear");
645
+ }
646
+ async function mergeGuestCart() {
647
+ const sid = getGuestSessionId();
648
+ const guestItems = sid ? await getGuestCart() : [];
649
+ if (guestItems.length === 0) {
650
+ return getCart();
651
+ }
652
+ const payloadItems = guestItems.map((item) => ({
653
+ product_id: item.product_id,
654
+ product_slug: item.product_slug,
655
+ product_name: item.product_name,
656
+ image: item.image,
657
+ variant_id: item.variant_id,
658
+ variant_attributes: typeof item.variant_attributes === "string" ? item.variant_attributes : JSON.stringify(item.variant_attributes ?? {}),
659
+ unit_price: item.unit_price,
660
+ quantity: item.quantity,
661
+ custom_measurements: typeof item.custom_measurements === "string" ? item.custom_measurements : JSON.stringify(item.custom_measurements ?? {}),
662
+ is_bespoke: item.is_bespoke
663
+ }));
664
+ const { data } = await storeManagementAxios.post(
665
+ "cart/merge",
666
+ { items: payloadItems },
667
+ sid ? { headers: { "X-Guest-Session": sid } } : {}
668
+ );
669
+ clearGuestSessionId();
670
+ return { ...data, items: parseItems(data.items || []) };
671
+ }
672
+ async function mergeGuestCartIfPresent() {
673
+ try {
674
+ const guestItems = await getGuestCart();
675
+ if (guestItems.length === 0) return;
676
+ await mergeGuestCart();
677
+ } catch (error) {
678
+ console.warn("[Cart] Failed to merge guest cart:", error);
679
+ }
680
+ }
681
+ function getGuestCartCount() {
682
+ return 0;
683
+ }
684
+ function getGuestCartSubtotal() {
685
+ return 0;
686
+ }
687
+ function getGuestCartProductType() {
688
+ return "physical";
689
+ }
690
+
691
+ // src/services/order.service.ts
692
+ function deriveCustomerName(raw) {
693
+ if (raw.customer_name) return raw.customer_name;
694
+ if (raw.guest_name) return raw.guest_name;
695
+ const addr = typeof raw.shipping_address === "object" && raw.shipping_address !== null ? raw.shipping_address : null;
696
+ if (addr) {
697
+ const full = `${addr.first_name ?? ""} ${addr.last_name ?? ""}`.trim();
698
+ if (full) return full;
699
+ }
700
+ const email = raw.guest_email ?? raw.customer_email ?? "";
701
+ if (email) return email.split("@")[0];
702
+ return "";
703
+ }
704
+ function normaliseStorefrontOrder(raw) {
705
+ const items = (raw.items ?? []).map((item) => ({
706
+ id: item.id,
707
+ productName: item.product_name ?? item.productName ?? "",
708
+ image: item.image ?? "",
709
+ quantity: item.quantity ?? 1,
710
+ price: item.unit_price ?? item.price ?? 0
711
+ }));
712
+ const addr = typeof raw.shipping_address === "object" && raw.shipping_address !== null ? raw.shipping_address : null;
713
+ return {
714
+ id: raw.id,
715
+ display_id: raw.display_id,
716
+ items,
717
+ total: raw.total_amount ?? raw.total ?? 0,
718
+ status: raw.status,
719
+ customerEmail: raw.guest_email ?? raw.customer_email ?? "",
720
+ customerName: deriveCustomerName(raw),
721
+ createdAt: raw.created_at ? new Date(raw.created_at).getTime() : Date.now(),
722
+ updatedAt: raw.updated_at ? new Date(raw.updated_at).getTime() : Date.now(),
723
+ deliveryMethod: raw.delivery_method,
724
+ trackingNumber: raw.tracking_number,
725
+ deliveryAddress: typeof raw.shipping_address === "string" ? raw.shipping_address : addr ? `${addr.street}, ${addr.city}, ${addr.state}, ${addr.country}` : void 0,
726
+ shippingAddress: addr ? {
727
+ first_name: addr.first_name ?? "",
728
+ last_name: addr.last_name ?? "",
729
+ phone: addr.phone ?? "",
730
+ street: addr.street ?? "",
731
+ city: addr.city ?? "",
732
+ state: addr.state ?? "",
733
+ lga: addr.lga ?? "",
734
+ country: addr.country ?? "",
735
+ postal: addr.postal ?? ""
736
+ } : void 0,
737
+ cancellationReason: raw.cancellation_reason,
738
+ hasBespoke: raw.product_type === "bespoke",
739
+ bespokeStage: raw.bespoke_stage,
740
+ bespokeBrief: raw.bespoke_brief,
741
+ deliveryStatus: raw.delivery_status,
742
+ carrierName: raw.carrier_name,
743
+ terminalShipmentId: raw.terminal_shipment_id,
744
+ guestToken: raw.guest_token,
745
+ guestEmail: raw.guest_email,
746
+ guestPhone: raw.guest_phone,
747
+ guestName: raw.guest_name
748
+ };
749
+ }
750
+ async function createOrder(payload) {
751
+ const { data } = await storeManagementAxios.post("orders/storefront", payload);
752
+ return normaliseStorefrontOrder(data);
753
+ }
754
+ async function findOrder(params) {
755
+ const { data } = await publicStoreAxios.get("orders/find/", { params });
756
+ return normaliseStorefrontOrder(data);
757
+ }
758
+ async function findOrderByToken(token) {
759
+ const { data } = await publicStoreAxios.get("orders/find/", {
760
+ params: { guest_token: token }
761
+ });
762
+ return normaliseStorefrontOrder(data);
763
+ }
764
+ async function getOrders(params) {
765
+ const { data } = await storeManagementAxios.get("orders/", { params });
766
+ const items = Array.isArray(data) ? data : data.items ?? [];
767
+ return items.map(normaliseStorefrontOrder);
768
+ }
769
+ async function cancelOrder(orderId, reason) {
770
+ const { data } = await storeManagementAxios.post(`orders/${orderId}/cancel/`, { reason });
771
+ return normaliseStorefrontOrder(data);
772
+ }
773
+ async function trackOrder(orderId, token) {
774
+ const { data } = await publicStoreAxios.get(`orders/track/${orderId}`, {
775
+ params: token ? { token } : void 0
776
+ });
777
+ return normaliseStorefrontOrder(data);
778
+ }
779
+
780
+ // src/services/auth.service.ts
781
+ async function loginCustomer(payload) {
782
+ const config = getRuntimeConfig();
783
+ const { data } = await authAxios.post("/auth/login/customer/", {
784
+ ...payload,
785
+ tenant_id: config.businessId
786
+ });
787
+ tokenStore.setAccessToken(data.access);
788
+ tokenStore.setRefreshToken(data.refresh);
789
+ resetGraphQLClient();
790
+ await mergeGuestCartIfPresent();
791
+ return data;
792
+ }
793
+ async function registerCustomer(payload) {
794
+ const config = getRuntimeConfig();
795
+ const { data } = await authAxios.post("/auth/register/customer/", {
796
+ ...payload,
797
+ tenant_id: config.businessId
798
+ });
799
+ tokenStore.setAccessToken(data.access);
800
+ tokenStore.setRefreshToken(data.refresh);
801
+ resetGraphQLClient();
802
+ await mergeGuestCartIfPresent();
803
+ return data;
804
+ }
805
+ async function refreshToken2(refresh) {
806
+ const { data } = await refreshAxios2.post("/auth/token/refresh/", { refresh });
807
+ return data;
808
+ }
809
+ async function logout() {
810
+ const refresh = tokenStore.getRefreshToken();
811
+ const payload = refresh ? { refresh } : {};
812
+ try {
813
+ await authAxios.post("/auth/logout/", payload);
814
+ } catch {
815
+ } finally {
816
+ tokenStore.clearAll();
817
+ resetGraphQLClient();
818
+ }
819
+ }
820
+ async function verifySocialToken(provider, token) {
821
+ const config = getRuntimeConfig();
822
+ const { data } = await authAxios.post(
823
+ `/auth/social/verify/${provider}/`,
824
+ {
825
+ id_token: token,
826
+ storefront_key: config.storefrontApiKey
827
+ }
828
+ );
829
+ tokenStore.setAccessToken(data.access);
830
+ tokenStore.setRefreshToken(data.refresh);
831
+ resetGraphQLClient();
832
+ return data;
833
+ }
834
+ function parseJwtPayload(token) {
835
+ try {
836
+ return JSON.parse(atob(token.split(".")[1].replace(/-/g, "+").replace(/_/g, "/")));
837
+ } catch {
838
+ return {};
839
+ }
840
+ }
841
+ function resolveProvider(data) {
842
+ if (data.is_google_auth_enabled) return "google";
843
+ if (data.is_facebook_auth_enabled) return "facebook";
844
+ return "email";
845
+ }
846
+ function resolveAvatar(profilePicture) {
847
+ if (!profilePicture) return null;
848
+ if (typeof profilePicture === "string") return profilePicture;
849
+ if (typeof profilePicture === "object" && profilePicture !== null && "url" in profilePicture) {
850
+ const url = profilePicture.url;
851
+ return typeof url === "string" ? url : null;
852
+ }
853
+ return null;
854
+ }
855
+ function mapAuthUserToCustomer(data, provider) {
856
+ const firstname = data.profile?.firstname?.trim() || void 0;
857
+ const lastname = data.profile?.lastname?.trim() || void 0;
858
+ const phone = data.profile?.phone?.trim() || void 0;
859
+ return {
860
+ id: String(data.id),
861
+ email: data.email,
862
+ firstname,
863
+ lastname,
864
+ phone,
865
+ full_name: buildFullName2(firstname, lastname),
866
+ avatar: resolveAvatar(data.profile?.profile_picture),
867
+ provider: provider ?? resolveProvider(data)
868
+ };
869
+ }
870
+ function buildCustomerFromClaims(claims) {
871
+ const provider = claims.is_google_auth_enabled ? "google" : claims.is_facebook_auth_enabled ? "facebook" : "email";
872
+ const jwtFullName = String(claims.full_name ?? claims.name ?? "").trim() || void 0;
873
+ const { firstname: splitFirst, lastname: splitLast } = splitFullName2(jwtFullName);
874
+ return {
875
+ id: String(claims.user_id ?? claims.sub ?? ""),
876
+ email: String(claims.email ?? ""),
877
+ firstname: splitFirst || void 0,
878
+ lastname: splitLast || void 0,
879
+ phone: String(claims.phone ?? "").trim() || void 0,
880
+ full_name: jwtFullName,
881
+ avatar: claims.avatar,
882
+ provider
883
+ };
884
+ }
885
+ async function getMe() {
886
+ const { data } = await authAxios.get("/auth/profile/");
887
+ return mapAuthUserToCustomer(data);
888
+ }
889
+ async function getAuthUser() {
890
+ const { data } = await authAxios.get("/auth/profile/");
891
+ return data;
892
+ }
893
+ async function updateProfile(payload) {
894
+ const { data } = await authAxios.put("/auth/profile/", payload);
895
+ return mapAuthUserToCustomer(data);
896
+ }
897
+ var refreshPromise = null;
898
+ function classifyError(error) {
899
+ const err = error;
900
+ const isNetworkError = !!(!err.response && (err.code === "ECONNABORTED" || err.code === "ERR_NETWORK" || err.message?.includes("Network Error")));
901
+ const isAuthError = !!(err.response?.status === 401 || err.response?.status === 403);
902
+ const isBlacklistedError = !!(err.response?.data?.detail === "Token is blacklisted" || err.message === "Token is blacklisted");
903
+ return { isNetworkError, isAuthError, isBlacklistedError };
904
+ }
905
+ async function retryWithBackoff(fn, maxRetries = 2, baseDelay = 1e3) {
906
+ let lastError;
907
+ for (let attempt = 0; attempt <= maxRetries; attempt++) {
908
+ try {
909
+ return await fn();
910
+ } catch (error) {
911
+ lastError = error;
912
+ const { isNetworkError, isAuthError } = classifyError(error);
913
+ if (!isNetworkError || isAuthError) {
914
+ throw error;
915
+ }
916
+ if (attempt === maxRetries) {
917
+ throw error;
918
+ }
919
+ const delay = baseDelay * Math.pow(2, attempt);
920
+ await new Promise((resolve) => setTimeout(resolve, delay));
921
+ }
922
+ }
923
+ throw lastError;
924
+ }
925
+ async function silentRefresh() {
926
+ const refresh = tokenStore.getRefreshToken();
927
+ if (!refresh) return null;
928
+ if (refreshPromise) return refreshPromise;
929
+ refreshPromise = (async () => {
930
+ try {
931
+ const tokens = await retryWithBackoff(() => refreshToken2(refresh), 2, 1e3);
932
+ tokenStore.setAccessToken(tokens.access);
933
+ if (tokens.refresh) tokenStore.setRefreshToken(tokens.refresh, tokenStore.isPersistent());
934
+ const claims = parseJwtPayload(tokens.access);
935
+ const user = buildCustomerFromClaims(claims);
936
+ return { user, provider: user.provider };
937
+ } catch (error) {
938
+ const { isNetworkError, isAuthError, isBlacklistedError } = classifyError(error);
939
+ if (isNetworkError) {
940
+ logger.warn("[silentRefresh] Network error during token refresh (offline/CORS), clearing session:", error);
941
+ } else if (isBlacklistedError) {
942
+ logger.log("[silentRefresh] Token was blacklisted (likely from logout), clearing session");
943
+ } else if (isAuthError) {
944
+ logger.log("[silentRefresh] Token refresh failed with auth error (expired/invalid), clearing session");
945
+ } else {
946
+ logger.error("[silentRefresh] Unexpected error during token refresh, clearing session:", error);
947
+ }
948
+ tokenStore.clearAll();
949
+ return null;
950
+ } finally {
951
+ refreshPromise = null;
952
+ }
953
+ })();
954
+ return refreshPromise;
955
+ }
956
+ function storeTokens(access, refresh, remember = true) {
957
+ tokenStore.setAccessToken(access);
958
+ tokenStore.setRefreshToken(refresh, remember);
959
+ }
960
+ function buildFullName2(firstname, lastname) {
961
+ if (firstname && lastname) return `${firstname} ${lastname}`;
962
+ return firstname || lastname || "";
963
+ }
964
+ function splitFullName2(fullName) {
965
+ if (!fullName) return { firstname: "", lastname: "" };
966
+ const parts = fullName.trim().split(/\s+/);
967
+ if (parts.length === 1) {
968
+ return { firstname: parts[0], lastname: "" };
969
+ }
970
+ return {
971
+ firstname: parts[0],
972
+ lastname: parts.slice(1).join(" ")
973
+ };
974
+ }
975
+
976
+ // src/services/product.service.ts
977
+ var GET_STOREFRONT_PRODUCTS = `
978
+ query GetStorefrontProducts($page: Int!, $pageSize: Int!, $collectionSlug: String, $search: String) {
979
+ storefront_products(page: $page, pageSize: $pageSize, collectionSlug: $collectionSlug, search: $search) {
980
+ items {
981
+ id
982
+ business_id
983
+ name
984
+ slug
985
+ description
986
+ brand
987
+ product_type
988
+ requires_shipping
989
+ is_consumable
990
+ is_bespoke
991
+ base_price
992
+ currency
993
+ images { url alt id }
994
+ tags
995
+ custom_fields { label unit required }
996
+ is_published
997
+ is_featured
998
+ is_popular
999
+ is_new
1000
+ is_temporary
1001
+ digital_file_key
1002
+ download_limit
1003
+ download_expires_at
1004
+ weight_kg
1005
+ length_cm
1006
+ width_cm
1007
+ height_cm
1008
+ created_at
1009
+ updated_at
1010
+ variants {
1011
+ id
1012
+ product_id
1013
+ sku
1014
+ attributes
1015
+ price
1016
+ images { url alt id }
1017
+ weight_kg
1018
+ is_active
1019
+ inventory {
1020
+ id
1021
+ product_id
1022
+ variant_id
1023
+ quantity
1024
+ reserved
1025
+ reorder_point
1026
+ reorder_quantity
1027
+ track_quantity
1028
+ allow_backorder
1029
+ available
1030
+ is_in_stock
1031
+ is_low_stock
1032
+ updated_at
1033
+ }
1034
+ created_at
1035
+ updated_at
1036
+ }
1037
+ collections {
1038
+ id
1039
+ business_id
1040
+ name
1041
+ slug
1042
+ description
1043
+ image { url alt id }
1044
+ collection_type
1045
+ rules
1046
+ status
1047
+ sort_order
1048
+ created_at
1049
+ updated_at
1050
+ }
1051
+ }
1052
+ total
1053
+ page
1054
+ page_size
1055
+ total_pages
1056
+ }
1057
+ }
1058
+ `;
1059
+ var GET_STOREFRONT_PRODUCT_BY_SLUG = `
1060
+ query GetStorefrontProductBySlug($slug: String!) {
1061
+ storefront_product_by_slug(slug: $slug) {
1062
+ id
1063
+ business_id
1064
+ name
1065
+ slug
1066
+ description
1067
+ brand
1068
+ product_type
1069
+ requires_shipping
1070
+ is_consumable
1071
+ is_bespoke
1072
+ base_price
1073
+ currency
1074
+ images { url alt id }
1075
+ tags
1076
+ custom_fields { label unit required }
1077
+ is_published
1078
+ is_featured
1079
+ is_popular
1080
+ is_new
1081
+ is_temporary
1082
+ digital_file_key
1083
+ download_limit
1084
+ download_expires_at
1085
+ weight_kg
1086
+ length_cm
1087
+ width_cm
1088
+ height_cm
1089
+ created_at
1090
+ updated_at
1091
+ variants {
1092
+ id
1093
+ product_id
1094
+ sku
1095
+ attributes
1096
+ price
1097
+ images { url alt id }
1098
+ weight_kg
1099
+ is_active
1100
+ inventory {
1101
+ id
1102
+ product_id
1103
+ variant_id
1104
+ quantity
1105
+ reserved
1106
+ reorder_point
1107
+ reorder_quantity
1108
+ track_quantity
1109
+ allow_backorder
1110
+ available
1111
+ is_in_stock
1112
+ is_low_stock
1113
+ updated_at
1114
+ }
1115
+ created_at
1116
+ updated_at
1117
+ }
1118
+ collections {
1119
+ id
1120
+ business_id
1121
+ name
1122
+ slug
1123
+ description
1124
+ image { url alt id }
1125
+ collection_type
1126
+ rules
1127
+ status
1128
+ sort_order
1129
+ created_at
1130
+ updated_at
1131
+ }
1132
+ }
1133
+ }
1134
+ `;
1135
+ var GET_STOREFRONT_LATEST = `
1136
+ query GetStorefrontLatest($page: Int!, $pageSize: Int!) {
1137
+ storefront_latest(page: $page, pageSize: $pageSize) {
1138
+ items {
1139
+ id
1140
+ business_id
1141
+ name
1142
+ slug
1143
+ description
1144
+ brand
1145
+ product_type
1146
+ requires_shipping
1147
+ is_consumable
1148
+ is_bespoke
1149
+ base_price
1150
+ currency
1151
+ images { url alt id }
1152
+ tags
1153
+ custom_fields { label unit required }
1154
+ is_published
1155
+ is_featured
1156
+ is_popular
1157
+ is_new
1158
+ is_temporary
1159
+ digital_file_key
1160
+ download_limit
1161
+ download_expires_at
1162
+ weight_kg
1163
+ length_cm
1164
+ width_cm
1165
+ height_cm
1166
+ created_at
1167
+ updated_at
1168
+ variants {
1169
+ id
1170
+ product_id
1171
+ sku
1172
+ attributes
1173
+ price
1174
+ images { url alt id }
1175
+ weight_kg
1176
+ is_active
1177
+ inventory {
1178
+ id
1179
+ product_id
1180
+ variant_id
1181
+ quantity
1182
+ reserved
1183
+ reorder_point
1184
+ reorder_quantity
1185
+ track_quantity
1186
+ allow_backorder
1187
+ available
1188
+ is_in_stock
1189
+ is_low_stock
1190
+ updated_at
1191
+ }
1192
+ created_at
1193
+ updated_at
1194
+ }
1195
+ collections {
1196
+ id
1197
+ business_id
1198
+ name
1199
+ slug
1200
+ description
1201
+ image { url alt id }
1202
+ collection_type
1203
+ rules
1204
+ status
1205
+ sort_order
1206
+ created_at
1207
+ updated_at
1208
+ }
1209
+ }
1210
+ total
1211
+ page
1212
+ page_size
1213
+ total_pages
1214
+ }
1215
+ }
1216
+ `;
1217
+ var GET_STOREFRONT_POPULAR = `
1218
+ query GetStorefrontPopular($page: Int!, $pageSize: Int!) {
1219
+ storefront_popular(page: $page, pageSize: $pageSize) {
1220
+ items {
1221
+ id
1222
+ business_id
1223
+ name
1224
+ slug
1225
+ description
1226
+ brand
1227
+ product_type
1228
+ requires_shipping
1229
+ is_consumable
1230
+ is_bespoke
1231
+ base_price
1232
+ currency
1233
+ images { url alt id }
1234
+ tags
1235
+ custom_fields { label unit required }
1236
+ is_published
1237
+ is_featured
1238
+ is_popular
1239
+ is_new
1240
+ is_temporary
1241
+ digital_file_key
1242
+ download_limit
1243
+ download_expires_at
1244
+ weight_kg
1245
+ length_cm
1246
+ width_cm
1247
+ height_cm
1248
+ created_at
1249
+ updated_at
1250
+ variants {
1251
+ id
1252
+ product_id
1253
+ sku
1254
+ attributes
1255
+ price
1256
+ images { url alt id }
1257
+ weight_kg
1258
+ is_active
1259
+ inventory {
1260
+ id
1261
+ product_id
1262
+ variant_id
1263
+ quantity
1264
+ reserved
1265
+ reorder_point
1266
+ reorder_quantity
1267
+ track_quantity
1268
+ allow_backorder
1269
+ available
1270
+ is_in_stock
1271
+ is_low_stock
1272
+ updated_at
1273
+ }
1274
+ created_at
1275
+ updated_at
1276
+ }
1277
+ collections {
1278
+ id
1279
+ business_id
1280
+ name
1281
+ slug
1282
+ description
1283
+ image { url alt id }
1284
+ collection_type
1285
+ rules
1286
+ status
1287
+ sort_order
1288
+ created_at
1289
+ updated_at
1290
+ }
1291
+ }
1292
+ total
1293
+ page
1294
+ page_size
1295
+ total_pages
1296
+ }
1297
+ }
1298
+ `;
1299
+ var GET_STOREFRONT_FEATURED = `
1300
+ query GetStorefrontFeatured($page: Int!, $pageSize: Int!) {
1301
+ storefront_featured(page: $page, pageSize: $pageSize) {
1302
+ items {
1303
+ id
1304
+ business_id
1305
+ name
1306
+ slug
1307
+ description
1308
+ brand
1309
+ product_type
1310
+ requires_shipping
1311
+ is_consumable
1312
+ is_bespoke
1313
+ base_price
1314
+ currency
1315
+ images { url alt id }
1316
+ tags
1317
+ custom_fields { label unit required }
1318
+ is_published
1319
+ is_featured
1320
+ is_popular
1321
+ is_new
1322
+ is_temporary
1323
+ digital_file_key
1324
+ download_limit
1325
+ download_expires_at
1326
+ weight_kg
1327
+ length_cm
1328
+ width_cm
1329
+ height_cm
1330
+ created_at
1331
+ updated_at
1332
+ variants {
1333
+ id
1334
+ product_id
1335
+ sku
1336
+ attributes
1337
+ price
1338
+ images { url alt id }
1339
+ weight_kg
1340
+ is_active
1341
+ inventory {
1342
+ id
1343
+ product_id
1344
+ variant_id
1345
+ quantity
1346
+ reserved
1347
+ reorder_point
1348
+ reorder_quantity
1349
+ track_quantity
1350
+ allow_backorder
1351
+ available
1352
+ is_in_stock
1353
+ is_low_stock
1354
+ updated_at
1355
+ }
1356
+ created_at
1357
+ updated_at
1358
+ }
1359
+ collections {
1360
+ id
1361
+ business_id
1362
+ name
1363
+ slug
1364
+ description
1365
+ image { url alt id }
1366
+ collection_type
1367
+ rules
1368
+ status
1369
+ sort_order
1370
+ created_at
1371
+ updated_at
1372
+ }
1373
+ }
1374
+ total
1375
+ page
1376
+ page_size
1377
+ total_pages
1378
+ }
1379
+ }
1380
+ `;
1381
+ var GET_STOREFRONT_NEW = `
1382
+ query GetStorefrontNew($page: Int!, $pageSize: Int!) {
1383
+ storefront_new(page: $page, pageSize: $pageSize) {
1384
+ items {
1385
+ id
1386
+ business_id
1387
+ name
1388
+ slug
1389
+ description
1390
+ brand
1391
+ product_type
1392
+ requires_shipping
1393
+ is_consumable
1394
+ is_bespoke
1395
+ base_price
1396
+ currency
1397
+ images { url alt id }
1398
+ tags
1399
+ custom_fields { label unit required }
1400
+ is_published
1401
+ is_featured
1402
+ is_popular
1403
+ is_new
1404
+ is_temporary
1405
+ digital_file_key
1406
+ download_limit
1407
+ download_expires_at
1408
+ weight_kg
1409
+ length_cm
1410
+ width_cm
1411
+ height_cm
1412
+ created_at
1413
+ updated_at
1414
+ variants {
1415
+ id
1416
+ product_id
1417
+ sku
1418
+ attributes
1419
+ price
1420
+ images { url alt id }
1421
+ weight_kg
1422
+ is_active
1423
+ inventory {
1424
+ id
1425
+ product_id
1426
+ variant_id
1427
+ quantity
1428
+ reserved
1429
+ reorder_point
1430
+ reorder_quantity
1431
+ track_quantity
1432
+ allow_backorder
1433
+ available
1434
+ is_in_stock
1435
+ is_low_stock
1436
+ updated_at
1437
+ }
1438
+ created_at
1439
+ updated_at
1440
+ }
1441
+ collections {
1442
+ id
1443
+ business_id
1444
+ name
1445
+ slug
1446
+ description
1447
+ image { url alt id }
1448
+ collection_type
1449
+ rules
1450
+ status
1451
+ sort_order
1452
+ created_at
1453
+ updated_at
1454
+ }
1455
+ }
1456
+ total
1457
+ page
1458
+ page_size
1459
+ total_pages
1460
+ }
1461
+ }
1462
+ `;
1463
+ var GET_STOREFRONT_RECOMMENDED = `
1464
+ query GetStorefrontRecommended($page: Int!, $pageSize: Int!, $excludeProductId: String) {
1465
+ storefront_recommended(page: $page, pageSize: $pageSize, excludeProductId: $excludeProductId) {
1466
+ items {
1467
+ id
1468
+ business_id
1469
+ name
1470
+ slug
1471
+ description
1472
+ brand
1473
+ product_type
1474
+ requires_shipping
1475
+ is_consumable
1476
+ is_bespoke
1477
+ base_price
1478
+ currency
1479
+ images { url alt id }
1480
+ tags
1481
+ custom_fields { label unit required }
1482
+ is_published
1483
+ is_featured
1484
+ is_popular
1485
+ is_new
1486
+ is_temporary
1487
+ digital_file_key
1488
+ download_limit
1489
+ download_expires_at
1490
+ weight_kg
1491
+ length_cm
1492
+ width_cm
1493
+ height_cm
1494
+ created_at
1495
+ updated_at
1496
+ variants {
1497
+ id
1498
+ product_id
1499
+ sku
1500
+ attributes
1501
+ price
1502
+ images { url alt id }
1503
+ weight_kg
1504
+ is_active
1505
+ inventory {
1506
+ id
1507
+ product_id
1508
+ variant_id
1509
+ quantity
1510
+ reserved
1511
+ reorder_point
1512
+ reorder_quantity
1513
+ track_quantity
1514
+ allow_backorder
1515
+ available
1516
+ is_in_stock
1517
+ is_low_stock
1518
+ updated_at
1519
+ }
1520
+ created_at
1521
+ updated_at
1522
+ }
1523
+ collections {
1524
+ id
1525
+ business_id
1526
+ name
1527
+ slug
1528
+ description
1529
+ image { url alt id }
1530
+ collection_type
1531
+ rules
1532
+ status
1533
+ sort_order
1534
+ created_at
1535
+ updated_at
1536
+ }
1537
+ }
1538
+ total
1539
+ page
1540
+ page_size
1541
+ total_pages
1542
+ }
1543
+ }
1544
+ `;
1545
+ async function getStorefrontProducts(params) {
1546
+ const client = getGraphQLClient();
1547
+ const variables = {
1548
+ page: params?.page || 1,
1549
+ pageSize: params?.pageSize || 20,
1550
+ collectionSlug: params?.collectionSlug,
1551
+ search: params?.search
1552
+ };
1553
+ const data = await client.request(GET_STOREFRONT_PRODUCTS, variables);
1554
+ return data.storefront_products;
1555
+ }
1556
+ async function getStorefrontProductBySlug(slug) {
1557
+ const client = getGraphQLClient();
1558
+ const data = await client.request(GET_STOREFRONT_PRODUCT_BY_SLUG, { slug });
1559
+ return data.storefront_product_by_slug;
1560
+ }
1561
+ async function getLatestProducts(params) {
1562
+ const client = getGraphQLClient();
1563
+ const variables = {
1564
+ page: params?.page || 1,
1565
+ pageSize: params?.pageSize || 4
1566
+ };
1567
+ const data = await client.request(GET_STOREFRONT_LATEST, variables);
1568
+ return data.storefront_latest;
1569
+ }
1570
+ async function getPopularProducts(params) {
1571
+ const client = getGraphQLClient();
1572
+ const variables = {
1573
+ page: params?.page || 1,
1574
+ pageSize: params?.pageSize || 4
1575
+ };
1576
+ const data = await client.request(GET_STOREFRONT_POPULAR, variables);
1577
+ return data.storefront_popular;
1578
+ }
1579
+ async function getFeaturedProducts(params) {
1580
+ const client = getGraphQLClient();
1581
+ const variables = {
1582
+ page: params?.page || 1,
1583
+ pageSize: params?.pageSize || 4
1584
+ };
1585
+ const data = await client.request(GET_STOREFRONT_FEATURED, variables);
1586
+ return data.storefront_featured;
1587
+ }
1588
+ async function getNewProducts(params) {
1589
+ const client = getGraphQLClient();
1590
+ const variables = {
1591
+ page: params?.page || 1,
1592
+ pageSize: params?.pageSize || 4
1593
+ };
1594
+ const data = await client.request(GET_STOREFRONT_NEW, variables);
1595
+ return data.storefront_new;
1596
+ }
1597
+ async function getRecommendedProducts(params) {
1598
+ const client = getGraphQLClient();
1599
+ const variables = {
1600
+ page: params?.page || 1,
1601
+ pageSize: params?.pageSize || 4,
1602
+ excludeProductId: params?.excludeProductId
1603
+ };
1604
+ const data = await client.request(GET_STOREFRONT_RECOMMENDED, variables);
1605
+ return data.storefront_recommended;
1606
+ }
1607
+
1608
+ // src/services/collection.service.ts
1609
+ var GET_STOREFRONT_COLLECTIONS = `
1610
+ query GetStorefrontCollections($page: Int!, $pageSize: Int!) {
1611
+ storefront_collections(page: $page, pageSize: $pageSize) {
1612
+ items {
1613
+ id
1614
+ business_id
1615
+ name
1616
+ slug
1617
+ description
1618
+ image { url alt id }
1619
+ collection_type
1620
+ rules
1621
+ status
1622
+ sort_order
1623
+ created_at
1624
+ updated_at
1625
+ }
1626
+ total
1627
+ page
1628
+ page_size
1629
+ total_pages
1630
+ }
1631
+ }
1632
+ `;
1633
+ var GET_STOREFRONT_COLLECTION_BY_SLUG = `
1634
+ query GetStorefrontCollectionBySlug($slug: String!) {
1635
+ storefront_collection_by_slug(slug: $slug) {
1636
+ id
1637
+ business_id
1638
+ name
1639
+ slug
1640
+ description
1641
+ image { url alt id }
1642
+ collection_type
1643
+ rules
1644
+ status
1645
+ sort_order
1646
+ created_at
1647
+ updated_at
1648
+ }
1649
+ }
1650
+ `;
1651
+ async function getStorefrontCollections(params) {
1652
+ const client = getGraphQLClient();
1653
+ const variables = {
1654
+ page: params?.page || 1,
1655
+ pageSize: params?.pageSize || 20
1656
+ };
1657
+ const data = await client.request(GET_STOREFRONT_COLLECTIONS, variables);
1658
+ return data.storefront_collections;
1659
+ }
1660
+ async function getStorefrontCollectionBySlug(slug) {
1661
+ const client = getGraphQLClient();
1662
+ const data = await client.request(GET_STOREFRONT_COLLECTION_BY_SLUG, { slug });
1663
+ return data.storefront_collection_by_slug;
1664
+ }
1665
+
1666
+ // src/services/wishlist.service.ts
1667
+ var GET_WISHLIST = `
1668
+ query GetWishlist($page: Int!, $pageSize: Int!) {
1669
+ wishlist(page: $page, pageSize: $pageSize) {
1670
+ items {
1671
+ id
1672
+ product_id
1673
+ notes
1674
+ created_at
1675
+ product_name
1676
+ product_slug
1677
+ product_price
1678
+ product_image
1679
+ }
1680
+ total
1681
+ page
1682
+ page_size
1683
+ total_pages
1684
+ }
1685
+ }
1686
+ `;
1687
+ var CHECK_IN_WISHLIST = `
1688
+ query CheckInWishlist($productId: String!) {
1689
+ check_in_wishlist(productId: $productId) {
1690
+ in_wishlist
1691
+ }
1692
+ }
1693
+ `;
1694
+ async function getWishlist(params) {
1695
+ const client = getGraphQLClient();
1696
+ const variables = {
1697
+ page: params?.page || 1,
1698
+ pageSize: params?.pageSize || 20
1699
+ };
1700
+ const data = await client.request(GET_WISHLIST, variables);
1701
+ return data.wishlist;
1702
+ }
1703
+ async function checkInWishlist(productId) {
1704
+ const client = getGraphQLClient();
1705
+ const data = await client.request(CHECK_IN_WISHLIST, { productId });
1706
+ return data.check_in_wishlist;
1707
+ }
1708
+ async function addToWishlist(productId, notes) {
1709
+ const { data } = await storeManagementAxios.post("wishlist/", {
1710
+ product_id: productId,
1711
+ notes: notes || void 0
1712
+ });
1713
+ return data;
1714
+ }
1715
+ async function removeFromWishlist(itemId) {
1716
+ await storeManagementAxios.delete(`wishlist/${itemId}`);
1717
+ }
1718
+ async function removeProductFromWishlist(productId) {
1719
+ await storeManagementAxios.delete(`wishlist/product/${productId}`);
1720
+ }
1721
+
1722
+ // src/services/payment.service.ts
1723
+ async function createDedicatedAccount(request) {
1724
+ const isValidUUID = (str) => {
1725
+ const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
1726
+ return uuidRegex.test(str);
1727
+ };
1728
+ const { data } = await paymentAxios.post(
1729
+ "payments/dedicated-account",
1730
+ {
1731
+ order_id: request.order_id && isValidUUID(request.order_id) ? request.order_id : void 0,
1732
+ amount: request.amount,
1733
+ customer_email: request.customer_email,
1734
+ customer_name: request.customer_name,
1735
+ currency: request.currency,
1736
+ idempotency_key: request.idempotency_key
1737
+ }
1738
+ );
1739
+ return data;
1740
+ }
1741
+ async function initiatePayment(request) {
1742
+ const isValidUUID = (str) => {
1743
+ const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
1744
+ return uuidRegex.test(str);
1745
+ };
1746
+ const validOrderId = request.order_id && isValidUUID(request.order_id) ? request.order_id : void 0;
1747
+ const { data } = await paymentAxios.post("payments/storefront/initiate", {
1748
+ amount: request.amount,
1749
+ currency: request.currency,
1750
+ order_id: validOrderId,
1751
+ quote_id: request.quote_id,
1752
+ metadata_json: {
1753
+ customer_email: request.customer_email,
1754
+ customer_name: request.customer_name ?? "",
1755
+ order_id: validOrderId,
1756
+ ...request.metadata ?? {}
1757
+ },
1758
+ idempotency_key: request.idempotency_key
1759
+ });
1760
+ return {
1761
+ id: data.id,
1762
+ gateway_ref: data.gateway_ref,
1763
+ gateway: data.gateway,
1764
+ status: data.status,
1765
+ checkout_url: data.metadata_json?.checkout_url ?? ""
1766
+ };
1767
+ }
1768
+ async function requestQuote(amount) {
1769
+ const { data } = await paymentAxios.post("payments/quote", { amount });
1770
+ return data;
1771
+ }
1772
+ async function verifyTransaction(reference) {
1773
+ const { data } = await paymentAxios.post(
1774
+ `payments/verify/${reference}`
1775
+ );
1776
+ return data;
1777
+ }
1778
+ async function getTransactionStatus(transactionId) {
1779
+ const { data } = await paymentAxios.get(
1780
+ `payments/transactions/${transactionId}`
1781
+ );
1782
+ return data;
1783
+ }
1784
+ var paymentService = {
1785
+ createDedicatedAccount,
1786
+ initiatePayment,
1787
+ requestQuote,
1788
+ verifyTransaction,
1789
+ getTransactionStatus
1790
+ };
1791
+
1792
+ // src/services/consultation.service.ts
1793
+ async function createConsultation(payload) {
1794
+ const { data } = await storeManagementAxios.post("social/consultations/", payload);
1795
+ return data;
1796
+ }
1797
+ async function getConsultations() {
1798
+ const { data } = await storeManagementAxios.get("social/consultations/");
1799
+ return data;
1800
+ }
1801
+ async function getConsultation(id) {
1802
+ const { data } = await storeManagementAxios.get(`social/consultations/${id}`);
1803
+ return data;
1804
+ }
1805
+ async function sendMessage(id, payload) {
1806
+ await storeManagementAxios.post(`social/consultations/${id}/messages`, payload);
1807
+ }
1808
+ async function acceptQuote(id, payload) {
1809
+ const { data } = await storeManagementAxios.post(`social/consultations/${id}/accept-quote`, payload);
1810
+ return data;
1811
+ }
1812
+ async function rejectQuote(id, reason) {
1813
+ const { data } = await storeManagementAxios.post(`social/consultations/${id}/reject-quote`, { reason });
1814
+ return data;
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(payload) {
1827
+ const { data } = await storeManagementAxios.post(
1828
+ "logistics/shipping/rates",
1829
+ payload
1830
+ );
1831
+ return data;
1832
+ }
1833
+ async function getSellerShippingAddress() {
1834
+ const { data } = await storeManagementAxios.get("logistics/shipping-address");
1835
+ return data;
1836
+ }
1837
+ async function validateShippingAddress(payload) {
1838
+ const { data } = await storeManagementAxios.post("logistics/shipping-address/validate", payload);
1839
+ return data;
1840
+ }
1841
+ var logisticsService = {
1842
+ getShippingRates,
1843
+ getSellerShippingAddress,
1844
+ validateShippingAddress
1845
+ };
1846
+
1847
+ // src/services/bespoke.service.ts
1848
+ async function checkAvailability(product_id) {
1849
+ const { data } = await storeManagementAxios.get(`bespoke/availability/${product_id}`);
1850
+ return data;
1851
+ }
1852
+ var bespokeService = {
1853
+ checkAvailability
1854
+ };
1855
+
1856
+ // src/services/service-booking.service.ts
1857
+ async function getAvailableSlots(product_id, date_from, date_to) {
1858
+ const { data } = await storeManagementAxios.get(
1859
+ `service/available-slots/${product_id}`,
1860
+ { params: { date_from, date_to } }
1861
+ );
1862
+ return data;
1863
+ }
1864
+ async function bookAppointment(payload) {
1865
+ const { data } = await storeManagementAxios.post("service/appointments/", payload);
1866
+ return data;
1867
+ }
1868
+ async function getAppointments() {
1869
+ const { data } = await storeManagementAxios.get("service/bookings/my");
1870
+ return data;
1871
+ }
1872
+ async function getAppointment(id) {
1873
+ const { data } = await storeManagementAxios.get(`service/bookings/${id}`);
1874
+ return data;
1875
+ }
1876
+ async function cancelAppointment(id) {
1877
+ await storeManagementAxios.delete(`service/bookings/${id}`);
1878
+ }
1879
+ async function getDeliverables(order_id) {
1880
+ const { data } = await storeManagementAxios.get(`service/projects/${order_id}/deliverables/`);
1881
+ return data;
1882
+ }
1883
+ async function approveDeliverable(order_id, deliverable_id) {
1884
+ const { data } = await storeManagementAxios.post(
1885
+ `service/projects/${order_id}/deliverables/${deliverable_id}/approve`,
1886
+ { approved: true }
1887
+ );
1888
+ return data;
1889
+ }
1890
+ async function requestRevision(order_id, deliverable_id, feedback) {
1891
+ const { data } = await storeManagementAxios.post(
1892
+ `service/projects/${order_id}/deliverables/${deliverable_id}/revision`,
1893
+ { approved: false, feedback }
1894
+ );
1895
+ return data;
1896
+ }
1897
+ var serviceBookingService = {
1898
+ getAvailableSlots,
1899
+ bookAppointment,
1900
+ getAppointments,
1901
+ getAppointment,
1902
+ cancelAppointment,
1903
+ getDeliverables,
1904
+ approveDeliverable,
1905
+ requestRevision
1906
+ };
1907
+
1908
+ // src/services/notifications.service.ts
1909
+ async function sendContactEmail(payload) {
1910
+ const { data } = await notificationsAxios.post(
1911
+ "contact/send-contact-email",
1912
+ payload
1913
+ );
1914
+ return data;
1915
+ }
1916
+ async function sendContactConfirmation(payload) {
1917
+ const { data } = await notificationsAxios.post(
1918
+ "contact/send-contact-confirmation",
1919
+ payload
1920
+ );
1921
+ return data;
1922
+ }
1923
+ var notificationsService = {
1924
+ sendContactEmail,
1925
+ sendContactConfirmation
1926
+ };
1927
+
1928
+ // src/services/app.service.ts
1929
+ async function googleTranslate(text, target, source = "en") {
1930
+ if (!text || target === source) return text;
1931
+ try {
1932
+ const url = `https://translate.googleapis.com/translate_a/single?client=gtx&sl=${source}&tl=${target}&dt=t&q=${encodeURIComponent(text)}`;
1933
+ const res = await fetch(url);
1934
+ const data = await res.json();
1935
+ return (data?.[0] || []).map((s) => s[0]).join("");
1936
+ } catch {
1937
+ return text;
1938
+ }
1939
+ }
1940
+
1941
+ // src/services/config.service.ts
1942
+ async function getSupportedLanguages() {
1943
+ const { data } = await paymentAxios.get("/config/supported-languages");
1944
+ return data;
1945
+ }
1946
+ async function getSupportedCurrencies() {
1947
+ const { data } = await paymentAxios.get("/config/supported-currencies");
1948
+ return data;
1949
+ }
1950
+ async function getBusinessConfig() {
1951
+ const { data } = await publicStoreAxios.get("business/profile");
1952
+ return data;
1953
+ }
1954
+ var configService = {
1955
+ getSupportedLanguages,
1956
+ getSupportedCurrencies,
1957
+ getBusinessConfig
1958
+ };
1959
+
1960
+ // src/services/cms.service.ts
1961
+ async function listCmsEntries(modelSlug, params) {
1962
+ const config = getRuntimeConfig();
1963
+ const { businessId } = config;
1964
+ const response = await cmsAxios.get(
1965
+ `/sdk/${businessId}/${modelSlug}/entries`,
1966
+ {
1967
+ params: {
1968
+ page: params?.page || 1,
1969
+ page_size: params?.page_size || 50
1970
+ }
1971
+ }
1972
+ );
1973
+ return response.data;
1974
+ }
1975
+ async function getCmsEntry(modelSlug, entryId) {
1976
+ const config = getRuntimeConfig();
1977
+ const { businessId } = config;
1978
+ const response = await cmsAxios.get(
1979
+ `/sdk/${businessId}/${modelSlug}/entries/${entryId}`
1980
+ );
1981
+ return response.data;
1982
+ }
1983
+ async function createCmsEntry(modelSlug, params) {
1984
+ const config = getRuntimeConfig();
1985
+ const { businessId } = config;
1986
+ const response = await cmsAxios.post(
1987
+ `/sdk/${businessId}/${modelSlug}/entries`,
1988
+ params
1989
+ );
1990
+ return response.data;
1991
+ }
1992
+ async function updateCmsEntry(modelSlug, entryId, params) {
1993
+ const config = getRuntimeConfig();
1994
+ const { businessId } = config;
1995
+ const response = await cmsAxios.put(
1996
+ `/sdk/${businessId}/${modelSlug}/entries/${entryId}`,
1997
+ params
1998
+ );
1999
+ return response.data;
2000
+ }
2001
+ async function deleteCmsEntry(modelSlug, entryId) {
2002
+ const config = getRuntimeConfig();
2003
+ const { businessId } = config;
2004
+ await cmsAxios.delete(
2005
+ `/sdk/${businessId}/${modelSlug}/entries/${entryId}`
2006
+ );
2007
+ }
2008
+
2009
+ // src/hooks/use-cart.ts
2010
+ import React, { useContext, useState } from "react";
2011
+ import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query";
2012
+ import axios4 from "axios";
2013
+ var CartCtx = React.createContext ? React.createContext(null) : null;
2014
+ function CartProvider({ children }) {
2015
+ const [isOpen, setIsOpen] = useState(false);
2016
+ if (!CartCtx) return children;
2017
+ return React.createElement(CartCtx.Provider, { value: { isOpen, setOpen: setIsOpen } }, children);
2018
+ }
2019
+ function useCart() {
2020
+ const queryClient = useQueryClient();
2021
+ const context = CartCtx ? useContext(CartCtx) : null;
2022
+ const isOpen = context ? context.isOpen : false;
2023
+ const setOpen = context ? context.setOpen : () => {
2024
+ };
2025
+ const [productTypeMismatch, setProductTypeMismatch] = useState(null);
2026
+ const cartQuery = useQuery({
2027
+ queryKey: ["cart"],
2028
+ queryFn: getCart,
2029
+ enabled: isInitialized()
2030
+ });
2031
+ const addToCartMutation = useMutation({
2032
+ mutationFn: addToCart,
2033
+ onSuccess: () => {
2034
+ setProductTypeMismatch(null);
2035
+ queryClient.invalidateQueries({ queryKey: ["cart"] });
2036
+ },
2037
+ onError: (error) => {
2038
+ if (axios4.isAxiosError(error) && error.response?.status === 409) {
2039
+ const responseData = error.response?.data;
2040
+ const errorDetail = responseData?.detail;
2041
+ if (errorDetail?.code === "CART_PRODUCT_TYPE_MISMATCH") {
2042
+ setProductTypeMismatch({
2043
+ message: errorDetail.message ?? "Your cart contains incompatible items.",
2044
+ existing_type: errorDetail.existing_type ?? "physical",
2045
+ new_type: errorDetail.new_type ?? "physical"
2046
+ });
2047
+ }
2048
+ }
2049
+ }
2050
+ });
2051
+ const updateCartItemMutation = useMutation({
2052
+ mutationFn: ({ itemId, quantity }) => updateCartItem(itemId, quantity),
2053
+ onSuccess: () => {
2054
+ queryClient.invalidateQueries({ queryKey: ["cart"] });
2055
+ }
2056
+ });
2057
+ const removeFromCartMutation = useMutation({
2058
+ mutationFn: removeFromCart,
2059
+ onSuccess: () => {
2060
+ queryClient.invalidateQueries({ queryKey: ["cart"] });
2061
+ }
2062
+ });
2063
+ const clearCartMutation = useMutation({
2064
+ mutationFn: clearCart,
2065
+ onSuccess: () => {
2066
+ queryClient.invalidateQueries({ queryKey: ["cart"] });
2067
+ }
2068
+ });
2069
+ const mergeGuestCartMutation = useMutation({
2070
+ mutationFn: mergeGuestCartIfPresent,
2071
+ onSuccess: () => {
2072
+ queryClient.invalidateQueries({ queryKey: ["cart"] });
2073
+ }
2074
+ });
2075
+ const addItem = (product, variantId, quantity = 1, customMeasurements) => {
2076
+ const variant = variantId ? product.variants.find((v) => v.id === variantId) : void 0;
2077
+ return addToCartMutation.mutate({
2078
+ product_id: product.id,
2079
+ product_slug: product.slug,
2080
+ product_name: product.name,
2081
+ image: product.images[0]?.url,
2082
+ variant_id: variantId,
2083
+ variant_attributes: variant?.attributes ? JSON.stringify(variant.attributes) : void 0,
2084
+ unit_price: variant?.price ?? product.base_price,
2085
+ quantity,
2086
+ custom_measurements: customMeasurements ? JSON.stringify(customMeasurements) : void 0,
2087
+ is_bespoke: product.is_bespoke
2088
+ });
2089
+ };
2090
+ const items = cartQuery.data?.items || [];
2091
+ const subtotal = cartQuery.data?.subtotal || 0;
2092
+ const count = items.reduce((total, item) => total + item.quantity, 0);
2093
+ const updateQty = (itemId, quantity) => {
2094
+ updateCartItemMutation.mutate({ itemId, quantity });
2095
+ };
2096
+ const removeItem = (itemId) => {
2097
+ removeFromCartMutation.mutate(itemId);
2098
+ };
2099
+ const handleClearCartAndAdd = () => {
2100
+ clearCartMutation.mutate();
2101
+ setProductTypeMismatch(null);
2102
+ };
2103
+ const handleKeepCurrentCart = () => {
2104
+ setProductTypeMismatch(null);
2105
+ };
2106
+ return {
2107
+ cart: cartQuery.data,
2108
+ items,
2109
+ count,
2110
+ isOpen,
2111
+ setOpen,
2112
+ isLoading: cartQuery.isLoading,
2113
+ error: cartQuery.error,
2114
+ addToCart: addToCartMutation.mutate,
2115
+ updateCartItem: updateCartItemMutation.mutate,
2116
+ removeFromCart: removeFromCartMutation.mutate,
2117
+ clearCart: clearCartMutation.mutate,
2118
+ clear: clearCartMutation.mutate,
2119
+ // Alias for storefront compatibility
2120
+ mergeGuestCart: mergeGuestCartMutation.mutate,
2121
+ addItem,
2122
+ updateQty,
2123
+ removeItem,
2124
+ subtotal,
2125
+ productTypeMismatch,
2126
+ handleClearCartAndAdd,
2127
+ handleKeepCurrentCart
2128
+ };
2129
+ }
2130
+
2131
+ // src/hooks/use-orders.ts
2132
+ import { useQuery as useQuery2, useMutation as useMutation2, useQueryClient as useQueryClient2 } from "@tanstack/react-query";
2133
+ function useOrders(params) {
2134
+ return useQuery2({
2135
+ queryKey: ["orders", params],
2136
+ queryFn: () => getOrders(params)
2137
+ });
2138
+ }
2139
+ function useOrdersList(params) {
2140
+ return useOrders(params);
2141
+ }
2142
+ function useFindOrder(params) {
2143
+ return useQuery2({
2144
+ queryKey: ["order", params],
2145
+ queryFn: () => findOrder(params),
2146
+ enabled: !!params.email && !!params.order_id
2147
+ });
2148
+ }
2149
+ function useOrder(params) {
2150
+ return useFindOrder(params);
2151
+ }
2152
+ function useOrderTracking(orderId, token) {
2153
+ return useQuery2({
2154
+ queryKey: ["order-tracking", orderId, token],
2155
+ queryFn: () => trackOrder(orderId, token),
2156
+ enabled: !!orderId,
2157
+ refetchInterval: 3e4
2158
+ // Refetch every 30 seconds for tracking updates
2159
+ });
2160
+ }
2161
+ function useCreateOrder() {
2162
+ const queryClient = useQueryClient2();
2163
+ return useMutation2({
2164
+ mutationFn: createOrder,
2165
+ onSuccess: () => {
2166
+ queryClient.invalidateQueries({ queryKey: ["orders"] });
2167
+ }
2168
+ });
2169
+ }
2170
+ function useCancelOrder() {
2171
+ const queryClient = useQueryClient2();
2172
+ return useMutation2({
2173
+ mutationFn: ({ orderId, reason }) => cancelOrder(orderId, reason),
2174
+ onSuccess: () => {
2175
+ queryClient.invalidateQueries({ queryKey: ["orders"] });
2176
+ }
2177
+ });
2178
+ }
2179
+
2180
+ // src/hooks/use-auth.ts
2181
+ import React2, { useContext as useContext2, useState as useState2, useEffect, useCallback } from "react";
2182
+ import { useQuery as useQuery3, useMutation as useMutation3, useQueryClient as useQueryClient3 } from "@tanstack/react-query";
2183
+ var AuthCtx = React2.createContext ? React2.createContext(null) : null;
2184
+ function AuthProvider({ children }) {
2185
+ const [customer, setCustomer] = useState2(null);
2186
+ const [isLoading, setIsLoading] = useState2(true);
2187
+ const [isModalOpen, setIsModalOpen] = useState2(false);
2188
+ useEffect(() => {
2189
+ let voided = false;
2190
+ (async () => {
2191
+ setIsLoading(true);
2192
+ try {
2193
+ const result = await silentRefresh();
2194
+ if (!voided && result) {
2195
+ setCustomer(result.user);
2196
+ resetGraphQLClient();
2197
+ }
2198
+ } catch (error) {
2199
+ logger.error("[AuthProvider] Session restore failed:", error);
2200
+ if (!voided) setCustomer(null);
2201
+ } finally {
2202
+ if (!voided) setIsLoading(false);
2203
+ }
2204
+ })();
2205
+ return () => {
2206
+ voided = true;
2207
+ };
2208
+ }, []);
2209
+ const openModal = useCallback(() => setIsModalOpen(true), []);
2210
+ const closeModal = useCallback(() => {
2211
+ setIsModalOpen(false);
2212
+ if (typeof window !== "undefined" && (window.location.hash === "#login" || window.location.hash === "#signup")) {
2213
+ window.history.replaceState(null, "", window.location.pathname + window.location.search);
2214
+ }
2215
+ }, []);
2216
+ useEffect(() => {
2217
+ const handleHash = () => {
2218
+ if (typeof window === "undefined") return;
2219
+ if (window.location.hash === "#login" || window.location.hash === "#signup") {
2220
+ if (!isLoading && customer) {
2221
+ window.history.replaceState(null, "", window.location.pathname + window.location.search);
2222
+ } else if (!isLoading && !customer) {
2223
+ setIsModalOpen(true);
2224
+ }
2225
+ }
2226
+ };
2227
+ handleHash();
2228
+ window.addEventListener("hashchange", handleHash);
2229
+ return () => window.removeEventListener("hashchange", handleHash);
2230
+ }, [customer, isLoading]);
2231
+ useEffect(() => {
2232
+ resetGraphQLClient();
2233
+ }, [customer]);
2234
+ const handleLogout = useCallback(async () => {
2235
+ await logout();
2236
+ setCustomer(null);
2237
+ setIsModalOpen(false);
2238
+ resetGraphQLClient();
2239
+ }, []);
2240
+ const value = {
2241
+ customer,
2242
+ isLoading,
2243
+ isModalOpen,
2244
+ openModal,
2245
+ closeModal,
2246
+ setCustomer,
2247
+ logout: handleLogout
2248
+ };
2249
+ if (!AuthCtx) return children;
2250
+ return React2.createElement(AuthCtx.Provider, { value }, children);
2251
+ }
2252
+ function useAuthUser() {
2253
+ return useQuery3({
2254
+ queryKey: ["auth-user"],
2255
+ queryFn: getAuthUser,
2256
+ enabled: !!tokenStore.getAccessToken()
2257
+ });
2258
+ }
2259
+ function useLogin() {
2260
+ const queryClient = useQueryClient3();
2261
+ return useMutation3({
2262
+ mutationFn: loginCustomer,
2263
+ onSuccess: () => {
2264
+ queryClient.invalidateQueries({ queryKey: ["auth-user"] });
2265
+ queryClient.invalidateQueries({ queryKey: ["cart"] });
2266
+ }
2267
+ });
2268
+ }
2269
+ function useRegister() {
2270
+ const queryClient = useQueryClient3();
2271
+ return useMutation3({
2272
+ mutationFn: registerCustomer,
2273
+ onSuccess: () => {
2274
+ queryClient.invalidateQueries({ queryKey: ["auth-user"] });
2275
+ queryClient.invalidateQueries({ queryKey: ["cart"] });
2276
+ }
2277
+ });
2278
+ }
2279
+ function useUpdateProfile() {
2280
+ const queryClient = useQueryClient3();
2281
+ return useMutation3({
2282
+ mutationFn: updateProfile,
2283
+ onSuccess: () => {
2284
+ queryClient.invalidateQueries({ queryKey: ["auth-user"] });
2285
+ }
2286
+ });
2287
+ }
2288
+ function useLogout() {
2289
+ const queryClient = useQueryClient3();
2290
+ return useMutation3({
2291
+ mutationFn: logout,
2292
+ onSuccess: () => {
2293
+ queryClient.clear();
2294
+ }
2295
+ });
2296
+ }
2297
+ function useAuth() {
2298
+ const context = AuthCtx ? useContext2(AuthCtx) : null;
2299
+ if (context) return context;
2300
+ const authUserQuery = useAuthUser();
2301
+ const logoutMutation = useLogout();
2302
+ return {
2303
+ customer: authUserQuery.data,
2304
+ isLoading: authUserQuery.isLoading,
2305
+ isModalOpen: false,
2306
+ openModal: () => {
2307
+ },
2308
+ closeModal: () => {
2309
+ },
2310
+ setCustomer: () => {
2311
+ },
2312
+ logout: async () => {
2313
+ await logoutMutation.mutateAsync();
2314
+ }
2315
+ };
2316
+ }
2317
+
2318
+ // src/hooks/use-countries.ts
2319
+ import { useQuery as useQuery4 } from "@tanstack/react-query";
2320
+ async function getCountries() {
2321
+ const { data } = await authAxios.get("auth/countries/");
2322
+ return data;
2323
+ }
2324
+ function useCountries() {
2325
+ return useQuery4({
2326
+ queryKey: ["countries"],
2327
+ queryFn: () => getCountries(),
2328
+ retry: 1,
2329
+ refetchOnWindowFocus: false,
2330
+ refetchOnReconnect: false,
2331
+ staleTime: 24 * 60 * 60 * 1e3
2332
+ // 24 hours
2333
+ });
2334
+ }
2335
+
2336
+ // src/hooks/use-states.ts
2337
+ import { useQuery as useQuery5 } from "@tanstack/react-query";
2338
+ async function getStates(countryIso) {
2339
+ if (!countryIso) return [];
2340
+ const { data } = await authAxios.get("auth/countries/", {
2341
+ params: { iso: countryIso }
2342
+ });
2343
+ return data;
2344
+ }
2345
+ function useStates(countryIso) {
2346
+ return useQuery5({
2347
+ queryKey: ["states", countryIso],
2348
+ queryFn: () => getStates(countryIso),
2349
+ enabled: !!countryIso,
2350
+ retry: 1,
2351
+ refetchOnWindowFocus: false,
2352
+ refetchOnReconnect: false,
2353
+ staleTime: 24 * 60 * 60 * 1e3
2354
+ // 24 hours
2355
+ });
2356
+ }
2357
+
2358
+ // src/hooks/use-languages.ts
2359
+ import { useQuery as useQuery6 } from "@tanstack/react-query";
2360
+ async function getSupportedLanguagesList() {
2361
+ const data = await getSupportedLanguages();
2362
+ return data.languages.map((language) => ({
2363
+ code: language.code,
2364
+ appCode: language.code,
2365
+ label: language.label,
2366
+ native: language.label,
2367
+ flag: language.flag
2368
+ }));
2369
+ }
2370
+ function useSupportedLanguages() {
2371
+ return useQuery6({
2372
+ queryKey: ["supported-languages"],
2373
+ queryFn: () => getSupportedLanguagesList(),
2374
+ enabled: isInitialized(),
2375
+ retry: 1,
2376
+ ...getCacheTier("high")
2377
+ });
2378
+ }
2379
+
2380
+ // src/hooks/use-currencies.ts
2381
+ import { useQuery as useQuery7 } from "@tanstack/react-query";
2382
+ async function getSupportedCurrenciesList() {
2383
+ const data = await getSupportedCurrencies();
2384
+ return data.currencies || [];
2385
+ }
2386
+ function useCurrencies() {
2387
+ return useQuery7({
2388
+ queryKey: ["supported-currencies"],
2389
+ queryFn: () => getSupportedCurrenciesList(),
2390
+ enabled: isInitialized(),
2391
+ retry: 1,
2392
+ ...getCacheTier("high")
2393
+ });
2394
+ }
2395
+
2396
+ // src/hooks/use-bespoke-availability.ts
2397
+ import { useQuery as useQuery8 } from "@tanstack/react-query";
2398
+ function useBespokeAvailability(product_id) {
2399
+ return useQuery8({
2400
+ queryKey: ["bespoke-availability", product_id],
2401
+ queryFn: () => bespokeService.checkAvailability(product_id),
2402
+ enabled: !!product_id,
2403
+ retry: false
2404
+ // Don't retry if no config exists (returns 404)
2405
+ });
2406
+ }
2407
+
2408
+ // src/hooks/use-collections.ts
2409
+ import { useQuery as useQuery9 } from "@tanstack/react-query";
2410
+ var collectionKeys = {
2411
+ all: ["core", "collections"],
2412
+ list: (params) => ["core", "collections", "list", params ?? {}],
2413
+ slug: (slug) => ["core", "collections", "slug", slug]
2414
+ };
2415
+ function useStorefrontCollections(params) {
2416
+ return useQuery9({
2417
+ queryKey: collectionKeys.list(params),
2418
+ queryFn: () => getStorefrontCollections(params),
2419
+ // medium — collections change infrequently
2420
+ ...getCacheTier("medium")
2421
+ });
2422
+ }
2423
+ function useStorefrontCollection(slug) {
2424
+ return useQuery9({
2425
+ queryKey: collectionKeys.slug(slug),
2426
+ queryFn: () => getStorefrontCollectionBySlug(slug),
2427
+ // medium — collection details change infrequently
2428
+ ...getCacheTier("medium"),
2429
+ enabled: !!slug
2430
+ });
2431
+ }
2432
+
2433
+ // src/hooks/use-products.ts
2434
+ import { useQuery as useQuery10 } from "@tanstack/react-query";
2435
+ var productKeys = {
2436
+ all: ["products"],
2437
+ list: (params) => [...productKeys.all, "list", params],
2438
+ detail: (slug) => [...productKeys.all, "detail", slug],
2439
+ recommended: (params) => [...productKeys.all, "recommended", params],
2440
+ latest: (params) => [...productKeys.all, "latest", params],
2441
+ popular: (params) => [...productKeys.all, "popular", params],
2442
+ featured: (params) => [...productKeys.all, "featured", params],
2443
+ new: (params) => [...productKeys.all, "new", params]
2444
+ };
2445
+ function useLatestProducts(params) {
2446
+ return useQuery10({
2447
+ queryKey: productKeys.latest(params),
2448
+ queryFn: () => getLatestProducts(params),
2449
+ // medium — latest products change infrequently
2450
+ ...getCacheTier("medium")
2451
+ });
2452
+ }
2453
+ function usePopularProducts(params) {
2454
+ return useQuery10({
2455
+ queryKey: productKeys.popular(params),
2456
+ queryFn: () => getPopularProducts(params),
2457
+ // medium — popular products change infrequently
2458
+ ...getCacheTier("medium")
2459
+ });
2460
+ }
2461
+ function useFeaturedProducts(params) {
2462
+ return useQuery10({
2463
+ queryKey: productKeys.featured(params),
2464
+ queryFn: () => getFeaturedProducts(params),
2465
+ // medium — featured products change infrequently
2466
+ ...getCacheTier("medium")
2467
+ });
2468
+ }
2469
+ function useNewProducts(params) {
2470
+ return useQuery10({
2471
+ queryKey: productKeys.new(params),
2472
+ queryFn: () => getNewProducts(params),
2473
+ // medium — new products change infrequently
2474
+ ...getCacheTier("medium")
2475
+ });
2476
+ }
2477
+ function useStorefrontProducts(params) {
2478
+ return useQuery10({
2479
+ queryKey: productKeys.list(params),
2480
+ queryFn: () => getStorefrontProducts(params),
2481
+ // medium — product catalog changes infrequently
2482
+ ...getCacheTier("medium")
2483
+ });
2484
+ }
2485
+ function useProduct(slug) {
2486
+ return useQuery10({
2487
+ queryKey: productKeys.detail(slug),
2488
+ queryFn: () => getStorefrontProductBySlug(slug),
2489
+ // medium — product details change infrequently
2490
+ ...getCacheTier("medium"),
2491
+ enabled: !!slug
2492
+ });
2493
+ }
2494
+ function useRecommendedProducts(params) {
2495
+ return useQuery10({
2496
+ queryKey: productKeys.recommended(params),
2497
+ queryFn: () => getRecommendedProducts(params),
2498
+ // medium — recommendations change infrequently
2499
+ ...getCacheTier("medium")
2500
+ });
2501
+ }
2502
+
2503
+ // src/hooks/use-wishlist.ts
2504
+ import { useQuery as useQuery11, useMutation as useMutation4, useQueryClient as useQueryClient4 } from "@tanstack/react-query";
2505
+ var wishlistKeys = {
2506
+ all: ["wishlist"],
2507
+ list: () => [...wishlistKeys.all, "list"],
2508
+ check: (productId) => [...wishlistKeys.all, "check", productId]
2509
+ };
2510
+ function useWishlist(params) {
2511
+ return useQuery11({
2512
+ queryKey: [...wishlistKeys.list(), params],
2513
+ queryFn: () => getWishlist(params),
2514
+ // medium — wishlist changes infrequently
2515
+ ...getCacheTier("medium")
2516
+ });
2517
+ }
2518
+ function useCheckInWishlist(productId) {
2519
+ return useQuery11({
2520
+ queryKey: wishlistKeys.check(productId),
2521
+ queryFn: () => checkInWishlist(productId),
2522
+ // low — wishlist check changes frequently
2523
+ ...getCacheTier("low"),
2524
+ enabled: !!productId
2525
+ });
2526
+ }
2527
+ function useAddToWishlist() {
2528
+ const queryClient = useQueryClient4();
2529
+ return useMutation4({
2530
+ mutationFn: ({ productId, notes }) => {
2531
+ return addToWishlist(productId, notes);
2532
+ },
2533
+ onSuccess: () => {
2534
+ queryClient.invalidateQueries({ queryKey: wishlistKeys.all });
2535
+ queryClient.invalidateQueries({ queryKey: ["wishlist", "check"] });
2536
+ }
2537
+ });
2538
+ }
2539
+ function useRemoveFromWishlist() {
2540
+ const queryClient = useQueryClient4();
2541
+ return useMutation4({
2542
+ mutationFn: (itemId) => {
2543
+ return removeFromWishlist(itemId);
2544
+ },
2545
+ onSuccess: () => {
2546
+ queryClient.invalidateQueries({ queryKey: wishlistKeys.all });
2547
+ queryClient.invalidateQueries({ queryKey: ["wishlist", "check"] });
2548
+ }
2549
+ });
2550
+ }
2551
+ function useRemoveProductFromWishlist() {
2552
+ const queryClient = useQueryClient4();
2553
+ return useMutation4({
2554
+ mutationFn: (productId) => {
2555
+ return removeProductFromWishlist(productId);
2556
+ },
2557
+ onSuccess: () => {
2558
+ queryClient.invalidateQueries({ queryKey: wishlistKeys.all });
2559
+ queryClient.invalidateQueries({ queryKey: ["wishlist", "check"] });
2560
+ }
2561
+ });
2562
+ }
2563
+ function useWishlistCount() {
2564
+ const backendQuery = useQuery11({
2565
+ queryKey: wishlistKeys.list(),
2566
+ queryFn: () => getWishlist(),
2567
+ // low — wishlist count changes frequently
2568
+ ...getCacheTier("low"),
2569
+ select: (data) => data.total
2570
+ });
2571
+ return backendQuery;
2572
+ }
2573
+
2574
+ // src/hooks/use-service-booking.ts
2575
+ import { useQuery as useQuery12, useMutation as useMutation5, useQueryClient as useQueryClient5 } from "@tanstack/react-query";
2576
+ function useAvailableSlots(product_id, date_from, date_to) {
2577
+ return useQuery12({
2578
+ queryKey: ["available-slots", product_id, date_from, date_to],
2579
+ queryFn: () => serviceBookingService.getAvailableSlots(product_id, date_from, date_to),
2580
+ enabled: !!product_id && !!date_from && !!date_to
2581
+ });
2582
+ }
2583
+ function useBookAppointment() {
2584
+ const queryClient = useQueryClient5();
2585
+ return useMutation5({
2586
+ mutationFn: serviceBookingService.bookAppointment,
2587
+ onSuccess: () => {
2588
+ queryClient.invalidateQueries({ queryKey: ["appointments"] });
2589
+ }
2590
+ });
2591
+ }
2592
+ function useAppointments() {
2593
+ return useQuery12({
2594
+ queryKey: ["appointments"],
2595
+ queryFn: serviceBookingService.getAppointments
2596
+ });
2597
+ }
2598
+ function useAppointment(id) {
2599
+ return useQuery12({
2600
+ queryKey: ["appointment", id],
2601
+ queryFn: () => serviceBookingService.getAppointment(id),
2602
+ enabled: !!id
2603
+ });
2604
+ }
2605
+ function useCancelAppointment() {
2606
+ const queryClient = useQueryClient5();
2607
+ return useMutation5({
2608
+ mutationFn: (id) => serviceBookingService.cancelAppointment(id),
2609
+ onSuccess: () => {
2610
+ queryClient.invalidateQueries({ queryKey: ["appointments"] });
2611
+ }
2612
+ });
2613
+ }
2614
+ function useDeliverables(order_id) {
2615
+ return useQuery12({
2616
+ queryKey: ["deliverables", order_id],
2617
+ queryFn: () => serviceBookingService.getDeliverables(order_id),
2618
+ enabled: !!order_id
2619
+ });
2620
+ }
2621
+ function useApproveDeliverable(order_id, deliverable_id) {
2622
+ const queryClient = useQueryClient5();
2623
+ return useMutation5({
2624
+ mutationFn: () => serviceBookingService.approveDeliverable(order_id, deliverable_id),
2625
+ onSuccess: () => {
2626
+ queryClient.invalidateQueries({ queryKey: ["deliverables", order_id] });
2627
+ }
2628
+ });
2629
+ }
2630
+ function useRequestRevision(order_id, deliverable_id) {
2631
+ const queryClient = useQueryClient5();
2632
+ return useMutation5({
2633
+ mutationFn: (feedback) => serviceBookingService.requestRevision(order_id, deliverable_id, feedback),
2634
+ onSuccess: () => {
2635
+ queryClient.invalidateQueries({ queryKey: ["deliverables", order_id] });
2636
+ }
2637
+ });
2638
+ }
2639
+
2640
+ // src/hooks/use-consultations.ts
2641
+ import { useQuery as useQuery13, useMutation as useMutation6, useQueryClient as useQueryClient6 } from "@tanstack/react-query";
2642
+ function useConsultations() {
2643
+ return useQuery13({
2644
+ queryKey: ["consultations"],
2645
+ queryFn: () => consultationService.getConsultations()
2646
+ });
2647
+ }
2648
+ function useConsultation(id) {
2649
+ return useQuery13({
2650
+ queryKey: ["consultation", id],
2651
+ queryFn: () => consultationService.getConsultation(id),
2652
+ enabled: !!id
2653
+ });
2654
+ }
2655
+ function useCreateConsultation() {
2656
+ const queryClient = useQueryClient6();
2657
+ return useMutation6({
2658
+ mutationFn: (payload) => consultationService.createConsultation(payload),
2659
+ onSuccess: () => {
2660
+ queryClient.invalidateQueries({ queryKey: ["consultations"] });
2661
+ }
2662
+ });
2663
+ }
2664
+ function useSendMessage(consultationId) {
2665
+ const queryClient = useQueryClient6();
2666
+ return useMutation6({
2667
+ mutationFn: (payload) => consultationService.sendMessage(consultationId, payload),
2668
+ onSuccess: () => {
2669
+ queryClient.invalidateQueries({ queryKey: ["consultation", consultationId] });
2670
+ }
2671
+ });
2672
+ }
2673
+ function useAcceptQuote(consultationId) {
2674
+ const queryClient = useQueryClient6();
2675
+ return useMutation6({
2676
+ mutationFn: (payload) => consultationService.acceptQuote(consultationId, payload),
2677
+ onSuccess: () => {
2678
+ queryClient.invalidateQueries({ queryKey: ["consultation", consultationId] });
2679
+ }
2680
+ });
2681
+ }
2682
+ function useRejectQuote(consultationId) {
2683
+ const queryClient = useQueryClient6();
2684
+ return useMutation6({
2685
+ mutationFn: (reason) => consultationService.rejectQuote(consultationId, reason),
2686
+ onSuccess: () => {
2687
+ queryClient.invalidateQueries({ queryKey: ["consultation", consultationId] });
2688
+ }
2689
+ });
2690
+ }
2691
+
2692
+ // src/hooks/use-consultation-stream.ts
2693
+ import { useEffect as useEffect2, useRef, useState as useState3 } from "react";
2694
+ import { fetchEventSource } from "@microsoft/fetch-event-source";
2695
+ function useConsultationStream({
2696
+ consultationId,
2697
+ onMessage,
2698
+ onQuote,
2699
+ onStatusChange,
2700
+ onError
2701
+ }) {
2702
+ const abortControllerRef = useRef(null);
2703
+ const [isConnected, setIsConnected] = useState3(false);
2704
+ const [lastEvent, setLastEvent] = useState3(null);
2705
+ useEffect2(() => {
2706
+ if (!consultationId) {
2707
+ return;
2708
+ }
2709
+ const abortController = new AbortController();
2710
+ abortControllerRef.current = abortController;
2711
+ const paymentUrl = getBackendUrl("payment");
2712
+ const streamUrl = `${paymentUrl}/events/stream/consultation/${consultationId}`;
2713
+ fetchEventSource(streamUrl, {
2714
+ method: "GET",
2715
+ signal: abortController.signal,
2716
+ onmessage: (event) => {
2717
+ try {
2718
+ if (!event.data || event.data.trim() === "") {
2719
+ return;
2720
+ }
2721
+ const data = JSON.parse(event.data);
2722
+ logger.log("[ConsultationStream] Received event:", data);
2723
+ setLastEvent(data);
2724
+ if (data.event === "consultation.message") {
2725
+ logger.log("[ConsultationStream] Message detected, calling onMessage");
2726
+ if (onMessage) {
2727
+ onMessage(data);
2728
+ }
2729
+ }
2730
+ if (data.event === "consultation.quote") {
2731
+ logger.log("[ConsultationStream] Quote detected, calling onQuote");
2732
+ if (onQuote) {
2733
+ onQuote(data);
2734
+ }
2735
+ }
2736
+ if (data.event === "consultation.status") {
2737
+ logger.log("[ConsultationStream] Status change detected, calling onStatusChange");
2738
+ if (onStatusChange) {
2739
+ onStatusChange(data);
2740
+ }
2741
+ }
2742
+ } catch (error) {
2743
+ logger.error("[ConsultationStream] Error parsing event:", error);
2744
+ }
2745
+ },
2746
+ onerror: (error) => {
2747
+ if (abortController.signal.aborted) {
2748
+ logger.log("[ConsultationStream] Connection closed via AbortController");
2749
+ return;
2750
+ }
2751
+ logger.error("[ConsultationStream] Connection error:", error);
2752
+ setIsConnected(false);
2753
+ if (onError) {
2754
+ onError(error);
2755
+ }
2756
+ },
2757
+ onopen: async (response) => {
2758
+ if (response.ok && response.headers.get("content-type")?.includes("text/event-stream")) {
2759
+ logger.log("[ConsultationStream] Connection established for consultation:", consultationId);
2760
+ setIsConnected(true);
2761
+ return;
2762
+ }
2763
+ throw new Error(`Unexpected response: ${response.status}`);
2764
+ }
2765
+ }).catch((error) => {
2766
+ if (abortController.signal.aborted || error.name === "AbortError") {
2767
+ return;
2768
+ }
2769
+ logger.error("[ConsultationStream] fetchEventSource failed:", error);
2770
+ });
2771
+ return () => {
2772
+ abortController.abort();
2773
+ setIsConnected(false);
2774
+ };
2775
+ }, [consultationId, onMessage, onQuote, onStatusChange, onError]);
2776
+ return { isConnected, lastEvent };
2777
+ }
2778
+
2779
+ // src/hooks/use-order-stream.ts
2780
+ import { useEffect as useEffect3, useRef as useRef2 } from "react";
2781
+ import { fetchEventSource as fetchEventSource2 } from "@microsoft/fetch-event-source";
2782
+ function useOrderStream({
2783
+ orderId,
2784
+ onPaymentComplete,
2785
+ onDigitalReady,
2786
+ onBespokeUpdate,
2787
+ onConsultationUpdate,
2788
+ onServiceBookingUpdate,
2789
+ onError
2790
+ }) {
2791
+ const abortControllerRef = useRef2(null);
2792
+ useEffect3(() => {
2793
+ if (!orderId) {
2794
+ return;
2795
+ }
2796
+ const abortController = new AbortController();
2797
+ abortControllerRef.current = abortController;
2798
+ const paymentUrl = getBackendUrl("payment");
2799
+ const streamUrl = `${paymentUrl}/events/stream/order/${encodeURIComponent(orderId)}`;
2800
+ fetchEventSource2(streamUrl, {
2801
+ method: "GET",
2802
+ signal: abortController.signal,
2803
+ onmessage: (event) => {
2804
+ try {
2805
+ if (!event.data || event.data.trim() === "") {
2806
+ return;
2807
+ }
2808
+ const data = JSON.parse(event.data);
2809
+ logger.log("[OrderStream] Received event:", data);
2810
+ if (data.event === "payment.success") {
2811
+ logger.log("[OrderStream] Payment success detected, calling onPaymentComplete");
2812
+ if (onPaymentComplete) {
2813
+ onPaymentComplete(data);
2814
+ }
2815
+ abortController.abort();
2816
+ }
2817
+ if (data.event === "digital.ready") {
2818
+ logger.log("[OrderStream] Digital delivery ready detected, calling onDigitalReady");
2819
+ if (onDigitalReady) {
2820
+ onDigitalReady(data);
2821
+ }
2822
+ }
2823
+ if (data.event === "bespoke.update") {
2824
+ logger.log("[OrderStream] Bespoke update detected, calling onBespokeUpdate");
2825
+ if (onBespokeUpdate) {
2826
+ onBespokeUpdate(data);
2827
+ }
2828
+ }
2829
+ if (data.event === "consultation.update") {
2830
+ logger.log("[OrderStream] Consultation update detected, calling onConsultationUpdate");
2831
+ if (onConsultationUpdate) {
2832
+ onConsultationUpdate(data);
2833
+ }
2834
+ }
2835
+ if (data.event === "service_booking.update") {
2836
+ logger.log("[OrderStream] Service booking update detected, calling onServiceBookingUpdate");
2837
+ if (onServiceBookingUpdate) {
2838
+ onServiceBookingUpdate(data);
2839
+ }
2840
+ }
2841
+ } catch (error) {
2842
+ logger.error("[OrderStream] Error parsing event:", error);
2843
+ }
2844
+ },
2845
+ onerror: (error) => {
2846
+ if (abortController.signal.aborted) {
2847
+ logger.log("[OrderStream] Connection closed via AbortController");
2848
+ return;
2849
+ }
2850
+ if (error.message?.includes("404") || error.message?.includes("Not Found")) {
2851
+ logger.warn("[OrderStream] Stream endpoint unavailable for order:", orderId);
2852
+ return;
2853
+ }
2854
+ logger.error("[OrderStream] Connection error:", error);
2855
+ if (onError) {
2856
+ onError(error);
2857
+ }
2858
+ },
2859
+ onopen: async (response) => {
2860
+ if (response.ok && response.headers.get("content-type")?.includes("text/event-stream")) {
2861
+ logger.log("[OrderStream] Connection established for order:", orderId);
2862
+ return;
2863
+ }
2864
+ if (response.status === 404) {
2865
+ logger.warn("[OrderStream] Stream endpoint unavailable for order:", orderId);
2866
+ return;
2867
+ }
2868
+ throw new Error(`Unexpected response: ${response.status}`);
2869
+ }
2870
+ }).catch((error) => {
2871
+ if (abortController.signal.aborted || error.name === "AbortError") {
2872
+ return;
2873
+ }
2874
+ logger.error("[OrderStream] fetchEventSource failed:", error);
2875
+ });
2876
+ return () => {
2877
+ abortController.abort();
2878
+ };
2879
+ }, [orderId, onPaymentComplete, onDigitalReady, onBespokeUpdate, onConsultationUpdate, onServiceBookingUpdate, onError]);
2880
+ return null;
2881
+ }
2882
+
2883
+ // src/hooks/use-is-mounted.ts
2884
+ import { useEffect as useEffect4, useState as useState4 } from "react";
2885
+ function useIsMounted() {
2886
+ const [mounted, setMounted] = useState4(false);
2887
+ useEffect4(() => {
2888
+ setMounted(true);
2889
+ }, []);
2890
+ return mounted;
2891
+ }
2892
+
2893
+ // src/hooks/use-google-translate.ts
2894
+ import { useEffect as useEffect5, useCallback as useCallback2, useState as useState5, useRef as useRef3 } from "react";
2895
+ var SCRIPT_ID = "google-translate-script";
2896
+ var ELEMENT_ID = "google_translate_element";
2897
+ function fireChange(googleCode) {
2898
+ const combo = document.querySelector(".goog-te-combo");
2899
+ if (combo) {
2900
+ combo.value = googleCode;
2901
+ combo.dispatchEvent(new Event("change"));
2902
+ return true;
2903
+ }
2904
+ return false;
2905
+ }
2906
+ function useGoogleTranslate(appLang) {
2907
+ const [isLoaded, setIsLoaded] = useState5(false);
2908
+ const initRef = useRef3(false);
2909
+ const { data: supportedLangs = [] } = useSupportedLanguages();
2910
+ const clearCookies = useCallback2(() => {
2911
+ if (typeof window === "undefined") return;
2912
+ const domains = [
2913
+ window.location.hostname,
2914
+ "." + window.location.hostname,
2915
+ "." + window.location.hostname.split(".").slice(-2).join(".")
2916
+ ];
2917
+ const path = "/";
2918
+ document.cookie = `googtrans=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=${path};`;
2919
+ domains.forEach((domain) => {
2920
+ document.cookie = `googtrans=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=${path}; domain=${domain};`;
2921
+ });
2922
+ }, []);
2923
+ const resetToEnglish = useCallback2(() => {
2924
+ if (typeof window === "undefined") return;
2925
+ const googtrans = document.cookie.split("; ").find((row) => row.startsWith("googtrans="))?.split("=")[1];
2926
+ const domains = [
2927
+ window.location.hostname,
2928
+ "." + window.location.hostname,
2929
+ window.location.hostname.split(".").slice(-2).join("."),
2930
+ "." + window.location.hostname.split(".").slice(-2).join(".")
2931
+ ];
2932
+ const clear = (name) => {
2933
+ document.cookie = `${name}=; Path=/; Expires=Thu, 01 Jan 1970 00:00:01 GMT;`;
2934
+ domains.forEach((d) => {
2935
+ document.cookie = `${name}=; Path=/; Domain=${d}; Expires=Thu, 01 Jan 1970 00:00:01 GMT;`;
2936
+ });
2937
+ };
2938
+ clear("googtrans");
2939
+ if (googtrans || document.documentElement.classList.contains("translated-ltr") || document.querySelector(".goog-te-banner-frame")) {
2940
+ window.location.reload();
2941
+ return;
2942
+ }
2943
+ document.body.style.top = "0";
2944
+ document.documentElement.classList.remove("translated-ltr", "translated-rtl");
2945
+ const container = document.getElementById(":1.container");
2946
+ if (container) container.style.display = "none";
2947
+ }, []);
2948
+ const changeLanguage = useCallback2((nextAppCode) => {
2949
+ if (nextAppCode === "en") {
2950
+ resetToEnglish();
2951
+ return;
2952
+ }
2953
+ const googleCode = nextAppCode;
2954
+ const container = document.getElementById(":1.container");
2955
+ if (container) container.style.display = "block";
2956
+ let tries = 0;
2957
+ const tick = () => {
2958
+ if (fireChange(googleCode)) return;
2959
+ if (tries++ < 30) setTimeout(tick, 200);
2960
+ };
2961
+ tick();
2962
+ }, [resetToEnglish]);
2963
+ useEffect5(() => {
2964
+ if (typeof window === "undefined") return;
2965
+ if (appLang === "en" && !initRef.current) return;
2966
+ if (initRef.current) return;
2967
+ if (supportedLangs.length === 0) return;
2968
+ initRef.current = true;
2969
+ if (!document.getElementById(ELEMENT_ID)) {
2970
+ const host = document.createElement("div");
2971
+ host.id = ELEMENT_ID;
2972
+ host.style.display = "none";
2973
+ document.body.appendChild(host);
2974
+ }
2975
+ const includedLanguages = supportedLangs.map((l) => l.code).join(",");
2976
+ window.googleTranslateElementInit = () => {
2977
+ if (window.google?.translate?.TranslateElement) {
2978
+ new window.google.translate.TranslateElement(
2979
+ { pageLanguage: "en", includedLanguages, autoDisplay: false },
2980
+ ELEMENT_ID
2981
+ );
2982
+ setIsLoaded(true);
2983
+ }
2984
+ };
2985
+ if (!document.getElementById(SCRIPT_ID)) {
2986
+ const script = document.createElement("script");
2987
+ script.id = SCRIPT_ID;
2988
+ script.src = "//translate.google.com/translate_a/element.js?cb=googleTranslateElementInit";
2989
+ script.async = true;
2990
+ document.body.appendChild(script);
2991
+ } else {
2992
+ if (window.google?.translate) window.googleTranslateElementInit?.();
2993
+ }
2994
+ }, [appLang, supportedLangs]);
2995
+ useEffect5(() => {
2996
+ if (isLoaded || appLang === "en" && initRef.current) {
2997
+ changeLanguage(appLang);
2998
+ }
2999
+ }, [appLang, isLoaded, changeLanguage]);
3000
+ return { isLoaded };
3001
+ }
3002
+
3003
+ // src/hooks/use-payment.ts
3004
+ import { useQuery as useQuery14, useMutation as useMutation7, useQueryClient as useQueryClient7 } from "@tanstack/react-query";
3005
+ function useCreateDVA() {
3006
+ const queryClient = useQueryClient7();
3007
+ return useMutation7({
3008
+ mutationFn: (request) => paymentService.createDedicatedAccount(request),
3009
+ onSuccess: () => {
3010
+ queryClient.invalidateQueries({ queryKey: ["payment"] });
3011
+ }
3012
+ });
3013
+ }
3014
+ function useInitiatePayment() {
3015
+ return useMutation7({
3016
+ mutationFn: (request) => paymentService.initiatePayment(request)
3017
+ });
3018
+ }
3019
+ function useVerifyTransaction() {
3020
+ return useMutation7({
3021
+ mutationFn: (reference) => paymentService.verifyTransaction(reference)
3022
+ });
3023
+ }
3024
+ function useTransactionStatus(transactionId, enabled = false) {
3025
+ return useQuery14({
3026
+ queryKey: ["transaction", "status", transactionId],
3027
+ queryFn: () => paymentService.getTransactionStatus(transactionId),
3028
+ enabled: isInitialized() && enabled,
3029
+ ...getCacheTier("none"),
3030
+ refetchInterval: 3e3
3031
+ // Poll every 3 seconds
3032
+ });
3033
+ }
3034
+ function usePollTransactionStatus(reference, enabled = false) {
3035
+ return useQuery14({
3036
+ queryKey: ["transaction", "poll", reference],
3037
+ queryFn: () => paymentService.verifyTransaction(reference),
3038
+ enabled: isInitialized() && enabled,
3039
+ ...getCacheTier("none"),
3040
+ refetchInterval: 2e3,
3041
+ // Poll every 2 seconds
3042
+ retry: 10
3043
+ // Retry up to 10 times
3044
+ });
3045
+ }
3046
+
3047
+ // src/hooks/use-cms.ts
3048
+ import { useQuery as useQuery15, useMutation as useMutation8, useQueryClient as useQueryClient8 } from "@tanstack/react-query";
3049
+ function useCmsEntries(modelSlug, params) {
3050
+ const query = useQuery15({
3051
+ queryKey: ["cms-entries", modelSlug, params],
3052
+ queryFn: () => listCmsEntries(modelSlug, params),
3053
+ enabled: isInitialized() && !!modelSlug
3054
+ });
3055
+ return {
3056
+ entries: query.data?.entries || [],
3057
+ total: query.data?.total || 0,
3058
+ page: query.data?.page || 1,
3059
+ page_size: query.data?.page_size || 50,
3060
+ isLoading: query.isLoading,
3061
+ error: query.error,
3062
+ refetch: query.refetch
3063
+ };
3064
+ }
3065
+ function useCmsEntry(modelSlug, entryId) {
3066
+ const query = useQuery15({
3067
+ queryKey: ["cms-entry", modelSlug, entryId],
3068
+ queryFn: () => getCmsEntry(modelSlug, entryId),
3069
+ enabled: isInitialized() && !!modelSlug && !!entryId
3070
+ });
3071
+ return {
3072
+ entry: query.data,
3073
+ isLoading: query.isLoading,
3074
+ error: query.error,
3075
+ refetch: query.refetch
3076
+ };
3077
+ }
3078
+ function useCreateCmsEntry(modelSlug) {
3079
+ const queryClient = useQueryClient8();
3080
+ const mutation = useMutation8({
3081
+ mutationFn: (params) => createCmsEntry(modelSlug, params),
3082
+ onSuccess: () => {
3083
+ queryClient.invalidateQueries({ queryKey: ["cms-entries", modelSlug] });
3084
+ }
3085
+ });
3086
+ return {
3087
+ createEntry: mutation.mutate,
3088
+ isLoading: mutation.isPending,
3089
+ error: mutation.error
3090
+ };
3091
+ }
3092
+ function useUpdateCmsEntry(modelSlug) {
3093
+ const queryClient = useQueryClient8();
3094
+ const mutation = useMutation8({
3095
+ mutationFn: ({ entryId, params }) => updateCmsEntry(modelSlug, entryId, params),
3096
+ onSuccess: () => {
3097
+ queryClient.invalidateQueries({ queryKey: ["cms-entries", modelSlug] });
3098
+ queryClient.invalidateQueries({ queryKey: ["cms-entry", modelSlug] });
3099
+ }
3100
+ });
3101
+ return {
3102
+ updateEntry: (entryId, params) => mutation.mutate({ entryId, params }),
3103
+ isLoading: mutation.isPending,
3104
+ error: mutation.error
3105
+ };
3106
+ }
3107
+ function useDeleteCmsEntry(modelSlug) {
3108
+ const queryClient = useQueryClient8();
3109
+ const mutation = useMutation8({
3110
+ mutationFn: (entryId) => deleteCmsEntry(modelSlug, entryId),
3111
+ onSuccess: () => {
3112
+ queryClient.invalidateQueries({ queryKey: ["cms-entries", modelSlug] });
3113
+ queryClient.invalidateQueries({ queryKey: ["cms-entry", modelSlug] });
3114
+ }
3115
+ });
3116
+ return {
3117
+ deleteEntry: mutation.mutate,
3118
+ isLoading: mutation.isPending,
3119
+ error: mutation.error
3120
+ };
3121
+ }
3122
+ export {
3123
+ AuthCtx,
3124
+ AuthProvider,
3125
+ CartCtx,
3126
+ CartProvider,
3127
+ InvalidBaseURLError,
3128
+ acceptQuote,
3129
+ addToCart,
3130
+ addToGuestCart,
3131
+ addToWishlist,
3132
+ approveDeliverable,
3133
+ authAxios,
3134
+ bespokeService,
3135
+ bookAppointment,
3136
+ buildDeliveryAddress,
3137
+ buildFullName,
3138
+ cancelAppointment,
3139
+ cancelOrder,
3140
+ checkAvailability,
3141
+ checkInWishlist,
3142
+ clearCart,
3143
+ clearGuestCart,
3144
+ clearGuestSessionId,
3145
+ cmsAxios,
3146
+ collectionKeys,
3147
+ configService,
3148
+ configureHttpClients,
3149
+ consultationService,
3150
+ createCmsEntry,
3151
+ createConsultation,
3152
+ createDedicatedAccount,
3153
+ createOrder,
3154
+ deleteCmsEntry,
3155
+ enrichCompletedOrder,
3156
+ findOrder,
3157
+ findOrderByToken,
3158
+ getAppointment,
3159
+ getAppointments,
3160
+ getAuthUser,
3161
+ getAvailableSlots,
3162
+ getBackendUrl,
3163
+ getBusinessConfig,
3164
+ getCacheTier,
3165
+ getCart,
3166
+ getCheckoutCustomerName,
3167
+ getCmsEntry,
3168
+ getConsultation,
3169
+ getConsultations,
3170
+ getCountries,
3171
+ getCustomerDisplayName,
3172
+ getDeliverables,
3173
+ getErrorMessage,
3174
+ getFeaturedProducts,
3175
+ getGraphQLClient,
3176
+ getGuestCart,
3177
+ getGuestCartCount,
3178
+ getGuestCartProductType,
3179
+ getGuestCartSubtotal,
3180
+ getGuestSessionId,
3181
+ getLatestProducts,
3182
+ getMe,
3183
+ getNewProducts,
3184
+ getOrCreateGuestSessionId,
3185
+ getOrders,
3186
+ getPopularProducts,
3187
+ getRecommendedProducts,
3188
+ getRuntimeConfig,
3189
+ getSellerShippingAddress,
3190
+ getShippingRates,
3191
+ getStates,
3192
+ getStorefrontCollectionBySlug,
3193
+ getStorefrontCollections,
3194
+ getStorefrontProductBySlug,
3195
+ getStorefrontProducts,
3196
+ getSupportedCurrencies,
3197
+ getSupportedCurrenciesList,
3198
+ getSupportedLanguages,
3199
+ getSupportedLanguagesList,
3200
+ getTransactionStatus,
3201
+ getWishlist,
3202
+ googleTranslate,
3203
+ initSdk,
3204
+ initiatePayment,
3205
+ isInitialized,
3206
+ listCmsEntries,
3207
+ logger,
3208
+ loginCustomer,
3209
+ logisticsService,
3210
+ logout,
3211
+ mapAuthUserToCustomer,
3212
+ mergeGuestCart,
3213
+ mergeGuestCartIfPresent,
3214
+ notificationsService,
3215
+ paymentAxios,
3216
+ paymentService,
3217
+ productKeys,
3218
+ publicStoreAxios,
3219
+ refreshToken,
3220
+ registerCustomer,
3221
+ rejectQuote,
3222
+ removeFromCart,
3223
+ removeFromGuestCart,
3224
+ removeFromWishlist,
3225
+ removeProductFromWishlist,
3226
+ requestQuote,
3227
+ requestRevision,
3228
+ resetConfig,
3229
+ resetGraphQLClient,
3230
+ sanitizeBaseUrl,
3231
+ sendContactConfirmation,
3232
+ sendContactEmail,
3233
+ sendMessage,
3234
+ serviceBookingService,
3235
+ setEnvironmentMode,
3236
+ setLoggerEnvironmentMode,
3237
+ silentRefresh,
3238
+ splitFullName,
3239
+ storeManagementAxios,
3240
+ storeTokens,
3241
+ tokenStore,
3242
+ trackOrder,
3243
+ updateCartItem,
3244
+ updateCmsEntry,
3245
+ updateGuestCartItemQuantity,
3246
+ updateProfile,
3247
+ useAcceptQuote,
3248
+ useAddToWishlist,
3249
+ useAppointment,
3250
+ useAppointments,
3251
+ useApproveDeliverable,
3252
+ useAuth,
3253
+ useAuthUser,
3254
+ useAvailableSlots,
3255
+ useBespokeAvailability,
3256
+ useBookAppointment,
3257
+ useCancelAppointment,
3258
+ useCancelOrder,
3259
+ useCart,
3260
+ useCheckInWishlist,
3261
+ useCmsEntries,
3262
+ useCmsEntry,
3263
+ useConsultation,
3264
+ useConsultationStream,
3265
+ useConsultations,
3266
+ useCountries,
3267
+ useCreateCmsEntry,
3268
+ useCreateConsultation,
3269
+ useCreateDVA,
3270
+ useCreateOrder,
3271
+ useCurrencies,
3272
+ useDeleteCmsEntry,
3273
+ useDeliverables,
3274
+ useFeaturedProducts,
3275
+ useFindOrder,
3276
+ useGoogleTranslate,
3277
+ useInitiatePayment,
3278
+ useIsMounted,
3279
+ useLatestProducts,
3280
+ useLogin,
3281
+ useLogout,
3282
+ useNewProducts,
3283
+ useOrder,
3284
+ useOrderStream,
3285
+ useOrderTracking,
3286
+ useOrders,
3287
+ useOrdersList,
3288
+ usePollTransactionStatus,
3289
+ usePopularProducts,
3290
+ useProduct,
3291
+ useRecommendedProducts,
3292
+ useRegister,
3293
+ useRejectQuote,
3294
+ useRemoveFromWishlist,
3295
+ useRemoveProductFromWishlist,
3296
+ useRequestRevision,
3297
+ useSendMessage,
3298
+ useStates,
3299
+ useStorefrontCollection,
3300
+ useStorefrontCollections,
3301
+ useStorefrontProducts,
3302
+ useSupportedLanguages,
3303
+ useTransactionStatus,
3304
+ useUpdateCmsEntry,
3305
+ useUpdateProfile,
3306
+ useVerifyTransaction,
3307
+ useWishlist,
3308
+ useWishlistCount,
3309
+ validateShippingAddress,
3310
+ verifySocialToken,
3311
+ verifyTransaction,
3312
+ wishlistKeys
3313
+ };
3314
+ //# sourceMappingURL=index.mjs.map